diff --git a/agent_core/core/prompts/__init__.py b/agent_core/core/prompts/__init__.py
index 78517742..72efe67a 100644
--- a/agent_core/core/prompts/__init__.py
+++ b/agent_core/core/prompts/__init__.py
@@ -81,6 +81,11 @@
LANGUAGE_INSTRUCTION,
)
+# Reasoning prompts
+from agent_core.core.prompts.reasoning import (
+ PROMPT_ENHANCE_REASONING_PROMPT
+)
+
# Routing prompts
from agent_core.core.prompts.routing import (
ROUTE_TO_SESSION_PROMPT,
@@ -130,6 +135,8 @@
"CURRENT_DATETIME_PROMPT",
"AGENT_FILE_SYSTEM_CONTEXT_PROMPT",
"LANGUAGE_INSTRUCTION",
+ # Reasoning prompts
+ "PROMPT_ENHANCE_REASONING_PROMPT",
# Routing prompts
"ROUTE_TO_SESSION_PROMPT",
# GUI prompts
diff --git a/agent_core/core/prompts/reasoning.py b/agent_core/core/prompts/reasoning.py
index f9724d71..ffe4d99c 100644
--- a/agent_core/core/prompts/reasoning.py
+++ b/agent_core/core/prompts/reasoning.py
@@ -6,4 +6,108 @@
Inspired by "Thinking-Claude" repository by richards199999.
"""
-__all__ = []
+PROMPT_ENHANCE_REASONING_PROMPT="""
+You are a prompt enhancer for CraftBot — a proactive autonomous AI agent that
+controls a computer (file system, CLI, browser, MCP tools, external
+integrations, and a task scheduler).
+
+Your output feeds directly into CraftBot's task pipeline. A poorly written
+prompt causes wrong skill selection, wrong action sets, misrouted sessions,
+or the agent executing the wrong thing entirely. Your job is to eliminate
+every source of ambiguity before the agent ever sees the instruction.
+
+
+RULE 1 — PRESERVE INTENT EXACTLY
+Never change, expand, or restrict what the user asked for.
+Clarify; do not invent. If uncertain, keep the original scope.
+
+RULE 2 — NAME THE TARGET EXPLICITLY
+Vague references to apps, files, or services cause the agent to guess wrong.
+- "my emails" → name the email client (Gmail, Outlook, etc.) if known;
+ otherwise write "the default email client or browser"
+- "that file" → name the file or folder path
+- "send a message" → name the platform (Telegram, WhatsApp, Slack, Discord)
+ if implied by context; this prevents wrong platform routing
+- "remind me" → write "create a proactive scheduled task"
+
+RULE 3 — STATE THE DONE-CONDITION
+The agent verifies tasks against a done-condition. If it is missing, the
+agent either over-executes or loops asking for confirmation.
+End every enhanced prompt with what success looks like:
+"...and confirm to me when complete."
+"...and save the result to the workspace folder."
+"...and send me a summary of what was found."
+
+RULE 4 — SIGNAL TASK COMPLEXITY
+CraftBot routes to simple_task (fast, no plan) or complex_task (todos,
+verification, user approval). Use these signals so routing is correct:
+- For quick lookups, checks, or single-step actions: keep the prompt direct
+ and short — this naturally triggers simple_task mode
+- For multi-step work, file changes, or anything needing verification:
+ include the phrase "and verify the result before reporting back to me"
+ — this signals complex_task mode
+
+RULE 5 — HONOUR SCHEDULING SIGNALS
+CraftBot has a built-in proactive scheduler. If the user implies recurrence
+("every day", "each week", "automatically", "whenever X happens"), write
+"Set up a recurring proactive task to..." — this ensures the scheduler
+system is invoked, not a one-off task.
+
+RULE 6 — ELIMINATE PRONOUN AMBIGUITY
+"it", "this", "that", "them", "there" — replace every pronoun with the
+actual noun it refers to, using context from the conversation if available.
+
+RULE 7 — ONE ACTION FRAME
+Do not chain unrelated actions into one prompt. If the user asked for one
+thing, keep it as one thing. Do not add "and also..." unless the user said so.
+
+
+
+Before writing the enhanced prompt, silently work through:
+1. What is the single core intent? (state it in one clause)
+2. What nouns are vague or missing? (app, file, platform, service)
+3. What is the done-condition? (file saved, message sent, result shown)
+4. simple or complex task? (single-shot vs. multi-step + verify)
+5. Any scheduling signal? (one-time vs. recurring)
+6. Any pronouns to replace with actual nouns?
+
+
+
+NEVER do these:
+- Do NOT add scope the user didn't ask for ("...and also back up your files")
+- Do NOT produce bullet lists or numbered steps — output is one prose block
+- Do NOT include preamble ("Here is the improved prompt:", "Enhanced:", etc.)
+- Do NOT wrap the output in quotes
+- Do NOT exceed 4 sentences
+- Do NOT use passive voice — use active imperative verbs
+- Do NOT leave platform names implicit when a platform is involved
+
+
+
+Return ONLY a valid JSON object.
+
+The JSON object must contain exactly one field named "enhanced_prompt". The value of "enhanced_prompt" must be the enhanced prompt as plain prose.
+
+Do not include markdown, code fences, explanations, or any additional fields.
+
+Examples of prompt quality (these are examples only, NOT the required output format):
+
+BAD: "check my emails"
+GOOD: "Open Gmail in the browser, check for unread emails received in the last 24 hours, and send me a plain-text summary of any messages that need a reply or action."
+
+BAD: "remind me about the standup"
+GOOD: "Create a recurring proactive task that sends me a reminder message 5 minutes before my daily standup meeting, using the schedule defined in my calendar or a fixed daily time I confirm."
+
+BAD: "clean it up"
+GOOD: "Open the Downloads folder, identify duplicate files and files not accessed in the last 30 days, list them for my review, and move only the confirmed items to Trash."
+
+Required output example:
+{
+ "enhanced_prompt": "Open the GitHub pull request at https://github.com/CraftOS-dev/CraftBot/pull/346, review the proposed code changes, identify any bugs, design issues, regressions, or opportunities for improvement, and send me a summary of your findings."
+}
+
+"""
+
+__all__ = [
+ "PROMPT_ENHANCE_REASONING_PROMPT"
+]
\ No newline at end of file
diff --git a/app/agent_base.py b/app/agent_base.py
index 0199a095..d93656d0 100644
--- a/app/agent_base.py
+++ b/app/agent_base.py
@@ -111,6 +111,7 @@
get_memory_max_items,
get_memory_prune_target,
)
+from app.i18n import classify_provider_error
from agent_core import profile, profile_loop, OperationCategory
from agent_core import (
# Registries for dependency injection
@@ -2553,6 +2554,15 @@ async def _handle_external_event(self, payload: Dict) -> None:
except Exception as e:
logger.error(f"Error handling external event: {e}", exc_info=True)
+ async def _handle_prompt_enhance(self, user_message: str) -> str:
+ try:
+ from agent_core.core.prompts.reasoning import PROMPT_ENHANCE_REASONING_PROMPT
+ response = await self.llm.generate_response_async(system_prompt=PROMPT_ENHANCE_REASONING_PROMPT, user_prompt=user_message)
+ result = json.loads(response)
+ return result.get('enhanced_prompt', '')
+ except Exception as e:
+ logger.error(f"{classify_provider_error(error=e)}")
+
# =====================================
# Hooks
# =====================================
diff --git a/app/ui_layer/adapters/browser_adapter.py b/app/ui_layer/adapters/browser_adapter.py
index 9a0ff3e7..9636c5bf 100644
--- a/app/ui_layer/adapters/browser_adapter.py
+++ b/app/ui_layer/adapters/browser_adapter.py
@@ -1110,6 +1110,17 @@ async def submit_message(
living_ui_id=living_ui_id,
)
+ async def _handle_enhance_prompt(self, content: str, ws) -> None:
+ """Enhance a user's prompt using the LLM for clarity and precision."""
+ try:
+ enhanced: str = await self._controller.handle_prompt_enhance(
+ user_message=content
+ )
+ await ws.send_json({"type": "prompt_enhanced", "content": enhanced.strip()})
+ return
+ except Exception as e:
+ logger.warning(f"[BROWSER ADAPTER] enhance_prompt failed: {e}")
+
def _handle_task_start(self, event: UIEvent) -> None:
"""Handle task start event with metrics tracking."""
# Call parent implementation
@@ -1485,6 +1496,11 @@ async def _handle_ws_message(self, data: Dict[str, Any], ws=None) -> None:
if command:
await self.submit_message(command)
+ elif msg_type == "enhance_prompt":
+ content = data.get("content", "")
+ if content and ws:
+ await self._handle_enhance_prompt(content, ws)
+
elif msg_type == "chat_history":
before_timestamp = data.get("beforeTimestamp")
limit = data.get("limit", 50)
diff --git a/app/ui_layer/browser/frontend/src/components/Chat/Chat.tsx b/app/ui_layer/browser/frontend/src/components/Chat/Chat.tsx
index 9abe8f3f..10dfcb3d 100644
--- a/app/ui_layer/browser/frontend/src/components/Chat/Chat.tsx
+++ b/app/ui_layer/browser/frontend/src/components/Chat/Chat.tsx
@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect, useLayoutEffect, KeyboardEvent, useCallback, ChangeEvent, useMemo } from 'react'
-import { Send, Paperclip, X, Loader2, File, AlertCircle, Reply, Mic, MicOff, ChevronDown } from 'lucide-react'
+import { Send, Paperclip, X, Loader2, File, AlertCircle, Reply, Mic, MicOff, ChevronDown, Sparkles } from 'lucide-react'
import { useVirtualizer } from '@tanstack/react-virtual'
import { useWebSocket } from '../../contexts/WebSocketContext'
import { useToast } from '../../contexts/ToastContext'
@@ -114,6 +114,9 @@ export function Chat({ livingUIId, placeholder, emptyMessage }: ChatProps) {
loadOlderMessages,
hasMoreMessages,
loadingOlderMessages,
+ enhancedPrompt,
+ enhancePrompt,
+ clearEnhancedPrompt,
} = useWebSocket()
const status = useDerivedAgentStatus({ actions, messages, connected })
@@ -130,6 +133,7 @@ export function Chat({ livingUIId, placeholder, emptyMessage }: ChatProps) {
}, [messages])
const [input, setInput] = useState('')
+ const [enhancing, setEnhancing] = useState(false)
const dispatch = useAppDispatch()
const pendingPrefill = useAppSelector(selectPendingPrefill)
const [pendingAttachments, setPendingAttachments] = useState([])
@@ -301,6 +305,25 @@ export function Chat({ livingUIId, placeholder, emptyMessage }: ChatProps) {
}, 0)
}, [pendingPrefill, dispatch])
+ // Consume enhanced prompt from context when WS response arrives
+ useEffect(() => {
+ if (enhancedPrompt === null) return
+ setInput(enhancedPrompt)
+ setEnhancing(false)
+ clearEnhancedPrompt()
+ inputRef.current?.focus()
+ }, [enhancedPrompt, clearEnhancedPrompt])
+
+ // Reset enhancing spinner if the WebSocket disconnects mid-request
+ useEffect(() => {
+ if (!connected) setEnhancing(false)
+ }, [connected])
+
+ const handleEnhancePrompt = useCallback(() => {
+ if (!input.trim() || enhancing) return
+ setEnhancing(true)
+ enhancePrompt(input.trim())
+ }, [input, enhancing, enhancePrompt])
useEffect(() => {
if (replyTarget) inputRef.current?.focus()
}, [replyTarget])
@@ -733,6 +756,13 @@ export function Chat({ livingUIId, placeholder, emptyMessage }: ChatProps) {