suna/agentpress/examples/example_agent/agent.py

211 lines
7.0 KiB
Python
Raw Normal View History

2024-10-17 19:44:10 +08:00
import asyncio
2024-10-28 05:04:42 +08:00
import json
2024-10-17 19:44:10 +08:00
from agentpress.thread_manager import ThreadManager
from tools.files_tool import FilesTool
2024-10-30 00:21:19 +08:00
from agentpress.state_manager import StateManager
from tools.terminal_tool import TerminalTool
import logging
from typing import AsyncGenerator
import sys
2024-11-18 06:36:37 +08:00
from agentpress.xml_tool_parser import XMLToolParser
from agentpress.xml_tool_executor import XMLToolExecutor
from agentpress.xml_results_adder import XMLResultsAdder
2024-10-10 22:21:39 +08:00
2024-11-02 07:05:29 +08:00
async def run_agent(thread_id: str, max_iterations: int = 5):
2024-11-01 23:09:12 +08:00
# Initialize managers and tools
thread_manager = ThreadManager()
2024-11-02 07:05:29 +08:00
state_manager = StateManager()
2024-11-01 23:09:12 +08:00
2024-11-18 11:21:08 +08:00
# Initialize tools
2024-11-01 23:09:12 +08:00
thread_manager.add_tool(FilesTool)
thread_manager.add_tool(TerminalTool)
2024-10-23 09:42:38 +08:00
async def init():
pass
async def pre_iteration():
2024-10-30 00:21:19 +08:00
# Update files state
files_tool = FilesTool()
await files_tool._init_workspace_state()
2024-10-23 09:42:38 +08:00
async def after_iteration():
2024-11-02 07:05:29 +08:00
# Ask the user for a custom message or use the default
custom_message = input("Enter a message to send (or press Enter to use 'Continue!!!' as message): ")
2024-11-02 11:13:51 +08:00
message_content = custom_message if custom_message else """
Continue!!!
"""
2024-10-30 00:21:19 +08:00
await thread_manager.add_message(thread_id, {
"role": "user",
2024-11-02 07:05:29 +08:00
"content": message_content
2024-10-30 00:21:19 +08:00
})
2024-11-02 11:13:51 +08:00
2024-10-23 09:42:38 +08:00
async def finalizer():
pass
await init()
iteration = 0
2024-11-01 23:09:12 +08:00
2024-10-23 09:42:38 +08:00
while iteration < max_iterations:
iteration += 1
await pre_iteration()
2024-11-18 06:36:37 +08:00
# You are a world-class web developer who can create, edit, and delete files, and execute terminal commands. You write clean, well-structured code.
# RESPONSE FORMAT:
# Use XML tags to specify file operations:
# <create-file file_path="path/to/file">
# file contents here
# </create-file>
2024-11-18 11:21:08 +08:00
# <str-replace file_path="path/to/file">
# <old_str>text to replace</old_str>
# <new_str>replacement text</new_str>
2024-11-18 08:38:31 +08:00
# </str-replace>
2024-11-18 06:36:37 +08:00
# <delete-file file_path="path/to/file">
# </delete-file>
2024-10-28 05:04:42 +08:00
system_message = {
"role": "system",
2024-11-02 11:13:51 +08:00
"content": """
2024-11-03 01:47:24 +08:00
You are a world-class web developer who can create, edit, and delete files, and execute terminal commands. You write clean, well-structured code. Keep iterating on existing files, continue working on this existing codebase - do not omit previous progress; instead, keep iterating.
2024-11-18 11:21:08 +08:00
RESPONSE FORMAT:
2024-11-18 08:38:31 +08:00
Use XML tags to specify file operations:
<create-file file_path="path/to/file">
file contents here
</create-file>
2024-11-18 09:15:34 +08:00
<str-replace file_path="path/to/file">
<old_str>text to replace</old_str>
<new_str>replacement text</new_str>
2024-11-18 08:38:31 +08:00
</str-replace>
<delete-file file_path="path/to/file">
</delete-file>
2024-11-03 01:47:24 +08:00
RULES:
- All current file contents are available to you in the <current_workspace_state> section
2024-11-03 02:09:39 +08:00
- Each file in the workspace state includes its full content
2024-11-03 01:47:24 +08:00
- Use str_replace for precise replacements in files
- NEVER include comments in any code you write - the code should be self-documenting
- Always maintain the full context of files when making changes
- When creating new files, write clean code without any comments or documentation
2024-11-02 11:13:51 +08:00
<available_tools>
2024-11-03 01:47:24 +08:00
[create_file(file_path, file_contents)] - Create new files
[delete_file(file_path)] - Delete existing files
[str_replace(file_path, old_str, new_str)] - Replace specific text in files
[execute_command(command)] - Execute terminal commands
2024-11-02 11:13:51 +08:00
</available_tools>
ALWAYS RESPOND WITH MULTIPLE SIMULTANEOUS ACTIONS:
<thoughts>
[Provide a concise overview of your planned changes and implementations]
</thoughts>
<actions>
[Include multiple tool calls]
</actions>
2024-11-03 01:47:24 +08:00
EDITING GUIDELINES:
2024-11-03 02:09:39 +08:00
1. Review the current file contents in the workspace state
2. Make targeted changes with str_replace
3. Write clean, self-documenting code without comments
4. Use create_file for new files and str_replace for modifications
2024-11-03 01:47:24 +08:00
Example workspace state for a file:
{
"index.html": {
2024-11-03 02:09:39 +08:00
"content": "<!DOCTYPE html>\\n<html>\\n<head>..."
2024-11-03 01:47:24 +08:00
}
}
2024-11-02 11:13:51 +08:00
Think deeply and step by step.
"""
}
state = await state_manager.export_store()
2024-10-23 09:42:38 +08:00
2024-11-02 11:13:51 +08:00
state_message = {
"role": "user",
"content": f"""
Current development environment workspace state:
<current_workspace_state>
{json.dumps(state, indent=2)}
</current_workspace_state>
"""
2024-10-30 00:21:19 +08:00
}
2024-11-02 11:13:51 +08:00
2024-11-18 09:15:34 +08:00
model_name = "anthropic/claude-3-5-sonnet-latest"
2024-10-28 05:04:42 +08:00
2024-10-23 09:42:38 +08:00
response = await thread_manager.run_thread(
thread_id=thread_id,
system_message=system_message,
model_name=model_name,
2024-11-02 11:13:51 +08:00
temperature=0.1,
2024-11-06 20:39:33 +08:00
max_tokens=8096,
2024-10-23 09:42:38 +08:00
tool_choice="auto",
temporary_message=state_message,
2024-11-18 11:21:08 +08:00
native_tool_calling=True,
xml_tool_calling=False,
stream=True,
2024-11-18 11:21:08 +08:00
execute_tools_on_stream=True,
parallel_tool_execution=True
2024-10-23 09:42:38 +08:00
)
2024-11-01 23:09:12 +08:00
if isinstance(response, AsyncGenerator):
print("\n🤖 Assistant is responding:")
try:
async for chunk in response:
if hasattr(chunk.choices[0], 'delta'):
delta = chunk.choices[0].delta
# Handle content streaming - print immediately without buffering
if hasattr(delta, 'content') and delta.content is not None:
print(delta.content, end='', flush=True)
# Handle tool calls - print immediately
if hasattr(delta, 'tool_calls') and delta.tool_calls:
for tool_call in delta.tool_calls:
if tool_call.function:
# Print tool name immediately when received
if tool_call.function.name:
print(f"\n🛠️ Tool Call: {tool_call.function.name}", flush=True)
# Print arguments immediately when received
if tool_call.function.arguments:
print(f" {tool_call.function.arguments}", end='', flush=True)
print("\n✨ Response completed\n")
except Exception as e:
print(f"\n❌ Error processing stream: {e}", file=sys.stderr)
logging.error(f"Error processing stream: {e}")
else:
print("\n❌ Non-streaming response received:", response)
2024-10-23 09:42:38 +08:00
await after_iteration()
await finalizer()
2024-10-17 19:44:10 +08:00
2024-10-17 04:08:46 +08:00
if __name__ == "__main__":
2024-10-23 09:42:38 +08:00
async def main():
2024-11-02 07:05:29 +08:00
thread_manager = ThreadManager()
thread_id = await thread_manager.create_thread()
2024-11-02 11:13:51 +08:00
await thread_manager.add_message(
thread_id,
{
"role": "user",
2024-11-18 06:36:37 +08:00
"content": "Create a modern, responsive landing page with HTML, CSS and JS."
2024-11-02 11:13:51 +08:00
}
)
2024-11-02 07:05:29 +08:00
await run_agent(thread_id)
asyncio.run(main())