diff --git a/backend/agent/api.py b/backend/agent/api.py
index 412fdc8b..52f036f7 100644
--- a/backend/agent/api.py
+++ b/backend/agent/api.py
@@ -512,6 +512,9 @@ async def run_agent_background(agent_run_id: str, thread_id: str, instance_id: s
agent_gen = run_agent(thread_id, stream=True,
thread_manager=thread_manager)
+ # Collect all responses to save to database
+ all_responses = []
+
async for response in agent_gen:
# Check if stop signal received
if stop_signal_received:
@@ -521,12 +524,13 @@ async def run_agent_background(agent_run_id: str, thread_id: str, instance_id: s
# Store response in memory
if agent_run_id in active_agent_runs:
active_agent_runs[agent_run_id].append(response)
+ all_responses.append(response)
total_responses += 1
- # Periodically log progress for long-running agents
- if total_responses % 100 == 0:
- duration = (datetime.now(timezone.utc) - start_time).total_seconds()
- logger.info(f"Agent run {agent_run_id} still running after {duration:.1f}s, processed {total_responses} responses (instance: {instance_id})")
+ # # Periodically log progress for long-running agents
+ # if total_responses % 100 == 0:
+ # duration = (datetime.now(timezone.utc) - start_time).total_seconds()
+ # logger.info(f"Agent run {agent_run_id} still running after {duration:.1f}s, processed {total_responses} responses (instance: {instance_id})")
# Signal all done if we weren't stopped
if not stop_signal_received:
@@ -535,11 +539,13 @@ async def run_agent_background(agent_run_id: str, thread_id: str, instance_id: s
# Add completion message to the stream
if agent_run_id in active_agent_runs:
- active_agent_runs[agent_run_id].append({
+ completion_message = {
"type": "status",
"status": "completed",
"message": "Agent run completed successfully"
- })
+ }
+ active_agent_runs[agent_run_id].append(completion_message)
+ all_responses.append(completion_message)
# Update the agent run status in the database
completion_timestamp = datetime.now(timezone.utc).isoformat()
@@ -549,7 +555,8 @@ async def run_agent_background(agent_run_id: str, thread_id: str, instance_id: s
try:
update_result = await client.table('agent_runs').update({
"status": "completed",
- "completed_at": completion_timestamp
+ "completed_at": completion_timestamp,
+ "responses": json.dumps(all_responses)
}).eq("id", agent_run_id).execute()
if hasattr(update_result, 'data') and update_result.data:
@@ -597,11 +604,16 @@ async def run_agent_background(agent_run_id: str, thread_id: str, instance_id: s
# Add error message to the stream
if agent_run_id in active_agent_runs:
- active_agent_runs[agent_run_id].append({
+ error_response = {
"type": "status",
"status": "error",
"message": error_message
- })
+ }
+ active_agent_runs[agent_run_id].append(error_response)
+ if 'all_responses' in locals():
+ all_responses.append(error_response)
+ else:
+ all_responses = [error_response] # Initialize if not exists
# Update the agent run with the error - with retry
completion_timestamp = datetime.now(timezone.utc).isoformat()
@@ -611,7 +623,8 @@ async def run_agent_background(agent_run_id: str, thread_id: str, instance_id: s
update_result = await client.table('agent_runs').update({
"status": "failed",
"error": f"{error_message}\n{traceback_str}",
- "completed_at": completion_timestamp
+ "completed_at": completion_timestamp,
+ "responses": json.dumps(all_responses if 'all_responses' in locals() else [])
}).eq("id", agent_run_id).execute()
if hasattr(update_result, 'data') and update_result.data:
@@ -667,6 +680,4 @@ async def run_agent_background(agent_run_id: str, thread_id: str, instance_id: s
except Exception as e:
logger.warning(f"Error deleting active run key: {str(e)}")
- logger.info(f"Agent run background task fully completed for: {agent_run_id} (instance: {instance_id})")
-
-
+ logger.info(f"Agent run background task fully completed for: {agent_run_id} (instance: {instance_id})")
\ No newline at end of file
diff --git a/backend/agent/tools/coder/files_tool.py b/backend/agent/coder/files_tool.py
similarity index 100%
rename from backend/agent/tools/coder/files_tool.py
rename to backend/agent/coder/files_tool.py
diff --git a/backend/agent/coder/prompt.py b/backend/agent/coder/prompt.py
new file mode 100644
index 00000000..41fd600a
--- /dev/null
+++ b/backend/agent/coder/prompt.py
@@ -0,0 +1,100 @@
+'''
+Agent prompt configuration with instructions for XML-based tool usage.
+This defines the system prompt that instructs the agent how to properly use the XML tool syntax.
+'''
+
+SYSTEM_PROMPT = '''
+You are an AI agent specialized in helping users with coding tasks and web development projects.
+
+# XML-BASED TOOLS GUIDE
+
+You have access to several tools to help with files, searching code, and executing commands. These tools must be used with specific XML syntax.
+
+## File Operations
+
+### Reading Files
+To read a file, use the `read_file` tag:
+```
+
+
+```
+
+### Writing Files
+To create or overwrite a file, use the `write_to_file` tag:
+```
+
+Your file content here
+
+```
+
+### Replacing Content in Files
+To modify parts of a file, use the `replace_in_file` tag with search/replace blocks:
+```
+
+<<<<<<< SEARCH
+[exact content to find]
+=======
+[new content to replace with]
+>>>>>>> REPLACE
+
+```
+
+### Deleting Files
+To delete a file, use the `delete_file` tag:
+```
+
+
+```
+
+## Searching and Code Navigation
+
+### Listing Directory Contents
+To list the contents of a directory, use the `list_dir` tag:
+```
+
+
+```
+
+### Searching for Text Pattern
+To search for text patterns in files, use the `grep_search` tag:
+```
+
+
+```
+
+### Finding Files
+To search for files by name, use the `file_search` tag:
+```
+
+
+```
+
+## Terminal Operations
+
+### Executing Commands
+To run a command in the terminal, use the `execute_command` tag:
+```
+
+npm install react
+true
+
+```
+
+# USING TOOLS
+
+1. **Choose the right tool** for each task based on what you're trying to accomplish.
+2. **Use the exact XML syntax** shown in the examples above.
+3. **Provide all required parameters** for each tool.
+4. **Process the results** returned by the tools to inform your next actions.
+5. **Use appropriate tools based on the extent of changes** needed.
+
+When executing commands that might modify the system (installing packages, removing files, etc.), always set `requires_approval` to true.
+
+Always provide clear explanations to the user about what actions you're taking and why.
+'''
+
+def get_system_prompt():
+ '''
+ Returns the system prompt with XML tool usage instructions.
+ '''
+ return SYSTEM_PROMPT
\ No newline at end of file
diff --git a/backend/agent/tools/coder/search_tool.py b/backend/agent/coder/search_tool.py
similarity index 100%
rename from backend/agent/tools/coder/search_tool.py
rename to backend/agent/coder/search_tool.py
diff --git a/backend/agent/tools/coder/terminal_tool.py b/backend/agent/coder/terminal_tool.py
similarity index 100%
rename from backend/agent/tools/coder/terminal_tool.py
rename to backend/agent/coder/terminal_tool.py
diff --git a/backend/agent/prompt.py b/backend/agent/prompt.py
index 41fd600a..599e635c 100644
--- a/backend/agent/prompt.py
+++ b/backend/agent/prompt.py
@@ -1,97 +1,79 @@
-'''
-Agent prompt configuration with instructions for XML-based tool usage.
-This defines the system prompt that instructs the agent how to properly use the XML tool syntax.
-'''
+SYSTEM_PROMPT = """
+You are a powerful general purpose AI assistant capable of helping users with a wide range of tasks. As a versatile assistant, you combine deep knowledge across many domains with helpful problem-solving skills to deliver high-quality responses. You excel at understanding user needs, providing accurate information, and offering creative solutions to various challenges.
-SYSTEM_PROMPT = '''
-You are an AI agent specialized in helping users with coding tasks and web development projects.
+You are capable of:
+1. Information gathering, fact-checking, and documentation
+2. Data processing, analysis, and visualization
+3. Writing multi-chapter articles and in-depth research reports
+4. Creating websites, applications, and tools
+5. Using programming to solve various problems beyond development
+6. Various tasks that can be accomplished using computers and the internet
-# XML-BASED TOOLS GUIDE
+The tasks you handle may include answering questions, performing research, drafting content, explaining complex concepts, or helping with specific technical requirements. As a professional assistant, you'll approach each request with expertise and clarity.
-You have access to several tools to help with files, searching code, and executing commands. These tools must be used with specific XML syntax.
+Your main goal is to follow the USER's instructions at each message, delivering helpful, accurate, and clear responses tailored to their needs.
+FOLLOW THE USER'S QUESTIONS, INSTRUCTIONS AND REQUESTS AT ALL TIMES.
-## File Operations
+Remember:
+1. ALWAYS follow the exact response format shown above
+2. When using str_replace, only include the minimal changes needed
+3. When using full_file_rewrite, include ALL necessary code
+4. Use appropriate tools based on the extent of changes
+5. Focus on providing accurate, helpful information
+6. Consider context and user needs in your responses
+7. Handle ambiguity gracefully by asking clarifying questions when needed
+8. ISSUE ONLY ONE SINGLE XML TOOL CALL AT A TIME - complete one action before proceeding to the next
-### Reading Files
-To read a file, use the `read_file` tag:
-```
-
-
-```
+
+You have access to these tools through XML-based tool calling:
+- create_file: Create new files with specified content
+- delete_file: Remove existing files
+- str_replace: Replace specific text in files
+- full_file_rewrite: Completely rewrite an existing file with new content
+- terminal_tool: Execute shell commands in the workspace directory
+- message_notify_user: Send a message to user without requiring a response. Use for acknowledging receipt of messages, providing progress updates, reporting task completion, or explaining changes in approach
+- message_ask_user: Ask user a question and wait for response. Use for requesting clarification, asking for confirmation, or gathering additional information
+- idle: A special tool to indicate you have completed all tasks and are entering idle state
+
-### Writing Files
-To create or overwrite a file, use the `write_to_file` tag:
-```
-
-Your file content here
-
-```
+
+RESPONSE FORMAT – STRICTLY Output XML tags for tool calling
-### Replacing Content in Files
-To modify parts of a file, use the `replace_in_file` tag with search/replace blocks:
-```
-
-<<<<<<< SEARCH
-[exact content to find]
-=======
-[new content to replace with]
->>>>>>> REPLACE
-
-```
+You must only use ONE tool call at a time. Wait for each action to complete before proceeding to the next one.
-### Deleting Files
-To delete a file, use the `delete_file` tag:
-```
-
-
-```
+
+file contents here
+
-## Searching and Code Navigation
+
+text to replace
+replacement text
+
-### Listing Directory Contents
-To list the contents of a directory, use the `list_dir` tag:
-```
-
-
-```
+
+New file contents go here, replacing all existing content
+
-### Searching for Text Pattern
-To search for text patterns in files, use the `grep_search` tag:
-```
-
-
-```
+
+
-### Finding Files
-To search for files by name, use the `file_search` tag:
-```
-
-
-```
+
+command here
+
-## Terminal Operations
+
+Message text to display to user
+
-### Executing Commands
-To run a command in the terminal, use the `execute_command` tag:
-```
-
-npm install react
-true
-
-```
+
+Question text to present to user
+
-# USING TOOLS
+
-1. **Choose the right tool** for each task based on what you're trying to accomplish.
-2. **Use the exact XML syntax** shown in the examples above.
-3. **Provide all required parameters** for each tool.
-4. **Process the results** returned by the tools to inform your next actions.
-5. **Use appropriate tools based on the extent of changes** needed.
+
-When executing commands that might modify the system (installing packages, removing files, etc.), always set `requires_approval` to true.
-
-Always provide clear explanations to the user about what actions you're taking and why.
-'''
+"""
def get_system_prompt():
'''
diff --git a/backend/agent/run.py b/backend/agent/run.py
index 26cd87b2..672a6329 100644
--- a/backend/agent/run.py
+++ b/backend/agent/run.py
@@ -7,7 +7,7 @@ from agent.tools.terminal_tool import TerminalTool
from agent.tools.wait_tool import WaitTool
# from agent.tools.search_tool import CodeSearchTool
from typing import Optional
-from agent.test_prompt import get_system_prompt
+from agent.prompt import get_system_prompt
from agentpress.response_processor import ProcessorConfig
from dotenv import load_dotenv
@@ -155,4 +155,4 @@ if __name__ == "__main__":
load_dotenv() # Ensure environment variables are loaded
# Run the test function
- asyncio.run(test_agent())
+ asyncio.run(test_agent())
\ No newline at end of file
diff --git a/backend/agent/test_prompt.py b/backend/agent/test_prompt.py
deleted file mode 100644
index c939f0ad..00000000
--- a/backend/agent/test_prompt.py
+++ /dev/null
@@ -1,59 +0,0 @@
-
-SYSTEM_PROMPT = """
-You are a powerful AI web development partner helping users create modern web applications. As an expert web development partner, you combine deep technical expertise with best practices to deliver high-quality, scalable web solutions. You excel at modern web development, creating responsive user interfaces, crafting polished visuals with CSS, and implementing robust functionality with JavaScript.
-
-The task will require modifying or creating web applications, implementing new features, optimizing performance, or simply answering technical questions. As a professional web development assistant, you'll approach each request with the expertise of a senior web developer.
-
-Your main goal is to follow the USER's instructions at each message, delivering high-quality code solutions, thoughtful architectural advice, and clear technical explanations in a non-technical friendly way.
-FOLLOW THE USER'S QUESTIONS, INSTRUCTIONS AND REQUESTS AT ALL TIMES.
-
-Remember:
-1. ALWAYS follow the exact response format shown above
-2. Use CDN links for external libraries (if needed)
-3. When using str_replace, only include the minimal changes needed
-4. When using full_file_rewrite, include ALL necessary code
-5. Use appropriate tools based on the extent of changes
-6. Focus on creating maintainable and scalable web applications
-7. Implement proper error handling and edge cases
-
-
-You have access to these tools:
-- create_file: Create new files with specified content
-- delete_file: Remove existing files
-- str_replace: Replace specific text in files
-- full_file_rewrite: Completely rewrite an existing file with new content
-- terminal_tool: Execute shell commands in the workspace directory
-
-
-
-RESPONSE FORMAT – STRICTLY Output XML tags
-
-
-file contents here
-
-
-
-text to replace
-replacement text
-
-
-
-New file contents go here, replacing all existing content
-
-
-
-
-
-
-command here
-
-
-
-
-"""
-
-def get_system_prompt():
- '''
- Returns the system prompt with XML tool usage instructions.
- '''
- return SYSTEM_PROMPT
\ No newline at end of file
diff --git a/backend/agent/tools/message_tool.py b/backend/agent/tools/message_tool.py
new file mode 100644
index 00000000..69f6208d
--- /dev/null
+++ b/backend/agent/tools/message_tool.py
@@ -0,0 +1,203 @@
+import os
+from typing import List, Optional, Union
+from agentpress.tool import Tool, ToolResult, openapi_schema, xml_schema
+
+class MessageTool(Tool):
+ """Tool for user communication and interaction.
+
+ This tool provides methods for notifying users and asking questions, with support for
+ attachments and user takeover suggestions.
+ """
+
+ def __init__(self):
+ super().__init__()
+
+ @openapi_schema({
+ "type": "function",
+ "function": {
+ "name": "message_notify_user",
+ "description": "Send a message to user without requiring a response. Use for acknowledging receipt of messages, providing progress updates, reporting task completion, or explaining changes in approach.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "text": {
+ "type": "string",
+ "description": "Message text to display to user"
+ },
+ "attachments": {
+ "anyOf": [
+ {"type": "string"},
+ {"items": {"type": "string"}, "type": "array"}
+ ],
+ "description": "(Optional) List of attachments to show to user, can be file paths or URLs"
+ }
+ },
+ "required": ["text"]
+ }
+ }
+ })
+ @xml_schema(
+ tag_name="message-notify-user",
+ mappings=[
+ {"param_name": "text", "node_type": "content", "path": "."},
+ {"param_name": "attachments", "node_type": "attribute", "path": ".", "required": False}
+ ],
+ example='''
+
+ Task completed successfully!
+
+ '''
+ )
+ async def message_notify_user(self, text: str, attachments: Optional[Union[str, List[str]]] = None) -> ToolResult:
+ """Send a notification message to the user without requiring a response.
+
+ Args:
+ text: The message to display to the user
+ attachments: Optional file paths or URLs to attach to the message
+
+ Returns:
+ ToolResult indicating success or failure of the notification
+ """
+ try:
+ # Convert single attachment to list for consistent handling
+ if attachments and isinstance(attachments, str):
+ attachments = [attachments]
+
+ # Format the response message
+ response_text = f"NOTIFICATION: {text}"
+
+ # Add attachments information if present
+ if attachments:
+ attachment_list = "\n- ".join(attachments)
+ response_text += f"\n\nAttachments:\n- {attachment_list}"
+
+ return self.success_response(response_text)
+ except Exception as e:
+ return self.fail_response(f"Error sending notification: {str(e)}")
+
+ @openapi_schema({
+ "type": "function",
+ "function": {
+ "name": "message_ask_user",
+ "description": "Ask user a question and wait for response. Use for requesting clarification, asking for confirmation, or gathering additional information.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "text": {
+ "type": "string",
+ "description": "Question text to present to user"
+ },
+ "attachments": {
+ "anyOf": [
+ {"type": "string"},
+ {"items": {"type": "string"}, "type": "array"}
+ ],
+ "description": "(Optional) List of question-related files or reference materials"
+ },
+ "suggest_user_takeover": {
+ "type": "string",
+ "enum": ["none", "browser"],
+ "description": "(Optional) Suggested operation for user takeover"
+ }
+ },
+ "required": ["text"]
+ }
+ }
+ })
+ @xml_schema(
+ tag_name="message-ask-user",
+ mappings=[
+ {"param_name": "text", "node_type": "content", "path": "."},
+ {"param_name": "attachments", "node_type": "attribute", "path": ".", "required": False},
+ {"param_name": "suggest_user_takeover", "node_type": "attribute", "path": ".", "required": False}
+ ],
+ example='''
+
+ Would you like to continue with this approach?
+
+ '''
+ )
+ async def message_ask_user(self, text: str, attachments: Optional[Union[str, List[str]]] = None,
+ suggest_user_takeover: str = "none") -> ToolResult:
+ """Ask the user a question and wait for a response.
+
+ Args:
+ text: The question to present to the user
+ attachments: Optional file paths or URLs to attach to the question
+ suggest_user_takeover: Optional suggestion for user takeover (none, browser)
+
+ Returns:
+ ToolResult indicating the question was successfully sent
+ """
+ try:
+ # Convert single attachment to list for consistent handling
+ if attachments and isinstance(attachments, str):
+ attachments = [attachments]
+
+ # Format the question message
+ response_text = f"QUESTION: {text}"
+
+ # Add attachments information if present
+ if attachments:
+ attachment_list = "\n- ".join(attachments)
+ response_text += f"\n\nAttachments:\n- {attachment_list}"
+
+ # Add user takeover suggestion if not "none"
+ if suggest_user_takeover and suggest_user_takeover != "none":
+ response_text += f"\n\nSuggested takeover: {suggest_user_takeover}"
+
+ return self.success_response(response_text, requires_response=True)
+ except Exception as e:
+ return self.fail_response(f"Error asking user: {str(e)}")
+
+ @openapi_schema({
+ "type": "function",
+ "function": {
+ "name": "idle",
+ "description": "A special tool to indicate you have completed all tasks and are about to enter idle state.",
+ "parameters": {
+ "type": "object"
+ }
+ }
+ })
+ @xml_schema(
+ tag_name="idle",
+ mappings=[],
+ example='''
+
+ '''
+ )
+ async def idle(self) -> ToolResult:
+ """Indicate that the agent has completed all tasks and is entering idle state.
+
+ Returns:
+ ToolResult indicating successful transition to idle state
+ """
+ try:
+ return self.success_response("Entering idle state")
+ except Exception as e:
+ return self.fail_response(f"Error entering idle state: {str(e)}")
+
+
+if __name__ == "__main__":
+ import asyncio
+
+ async def test_message_tool():
+ message_tool = MessageTool()
+
+ # Test notification
+ notify_result = await message_tool.message_notify_user(
+ "Processing has completed successfully!",
+ attachments=["results.txt", "output.log"]
+ )
+ print("Notification result:", notify_result)
+
+ # Test question
+ ask_result = await message_tool.message_ask_user(
+ "Would you like to proceed with the next phase?",
+ attachments="summary.pdf",
+ suggest_user_takeover="browser"
+ )
+ print("Question result:", ask_result)
+
+ asyncio.run(test_message_tool())
diff --git a/backend/agent/workspace/index.html b/backend/agent/workspace/index.html
new file mode 100644
index 00000000..dd334f3e
--- /dev/null
+++ b/backend/agent/workspace/index.html
@@ -0,0 +1,331 @@
+
+
+
Hello! I'm a passionate web developer with a keen eye for design and a love for creating seamless user experiences. With a background in [Your Background], I bring a unique perspective to every project I work on.
+
I enjoy solving complex problems and turning ideas into reality through clean and efficient code. When I'm not coding, you can find me [Your Hobbies/Interests].