Skip to content

Commit

Permalink
docstrings, example agent, cli
Browse files Browse the repository at this point in the history
  • Loading branch information
markokraemer committed Nov 18, 2024
1 parent 5355771 commit b20c074
Show file tree
Hide file tree
Showing 18 changed files with 1,279 additions and 285 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
"""
Interactive web development agent supporting both XML and Standard LLM tool calling.
This agent can:
- Create and modify web projects
- Execute terminal commands
- Handle file operations
- Use either XML or Standard tool calling patterns
"""

import asyncio
import json
from agentpress.thread_manager import ThreadManager
Expand All @@ -8,78 +18,17 @@
from typing import AsyncGenerator
import sys

async def run_agent(thread_id: str, max_iterations: int = 5):
thread_manager = ThreadManager()
state_manager = StateManager()

thread_manager.add_tool(FilesTool)
thread_manager.add_tool(TerminalTool)

async def init():
pass

async def pre_iteration():
files_tool = FilesTool()
await files_tool._init_workspace_state()

async def after_iteration():
custom_message = input("Enter a message to send (or press Enter to use 'Continue!!!' as message): ")

message_content = custom_message if custom_message else """
Continue!!!
"""
await thread_manager.add_message(thread_id, {
"role": "user",
"content": message_content
})

async def finalizer():
pass

await init()

iteration = 0

while iteration < max_iterations:
iteration += 1
await pre_iteration()

# 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>
BASE_SYSTEM_MESSAGE = """
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.
# <str-replace file_path="path/to/file">
# <old_str>text to replace</old_str>
# <new_str>replacement text</new_str>
# </str-replace>
Available tools:
- create_file: Create new files with specified content
- delete_file: Remove existing files
- str_replace: Make precise text replacements in files
- execute_command: Run terminal commands
# <delete-file file_path="path/to/file">
# </delete-file>

system_message = {
"role": "system",
"content": """
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.
RESPONSE FORMAT:
Use XML tags to specify file operations:
<create-file file_path="path/to/file">
file contents here
</create-file>
<str-replace file_path="path/to/file">
<old_str>text to replace</old_str>
<new_str>replacement text</new_str>
</str-replace>
<delete-file file_path="path/to/file">
</delete-file>
RULES:
- All current file contents are available to you in the <current_workspace_state> section
Expand Down Expand Up @@ -117,18 +66,65 @@ async def finalizer():
"content": "<!DOCTYPE html>\\n<html>\\n<head>..."
}
}
Think deeply and step by step.
"""
}
state = await state_manager.export_store()
"""

XML_FORMAT = """
RESPONSE FORMAT:
Use XML tags to specify file operations:
<create-file file_path="path/to/file">
file contents here
</create-file>
<str-replace file_path="path/to/file">
<old_str>text to replace</old_str>
<new_str>replacement text</new_str>
</str-replace>
<delete-file file_path="path/to/file">
</delete-file>
"""

async def run_agent(thread_id: str, use_xml: bool = True, max_iterations: int = 5):
"""Run the development agent with specified configuration."""
thread_manager = ThreadManager()
state_manager = StateManager()

thread_manager.add_tool(FilesTool)
thread_manager.add_tool(TerminalTool)

# Combine base message with XML format if needed
system_message = {
"role": "system",
"content": BASE_SYSTEM_MESSAGE + (XML_FORMAT if use_xml else "")
}

async def pre_iteration():
files_tool = FilesTool()
await files_tool._init_workspace_state()

async def after_iteration():
custom_message = input("\nEnter a message (or press Enter to continue): ")
message_content = custom_message if custom_message else "Continue!!!"
await thread_manager.add_message(thread_id, {
"role": "user",
"content": message_content
})

iteration = 0
while iteration < max_iterations:
iteration += 1
await pre_iteration()

state = await state_manager.export_store()
state_message = {
"role": "user",
"content": f"""
Current development environment workspace state:
<current_workspace_state>
<current_workspace_state>
{json.dumps(state, indent=2)}
</current_workspace_state>
"""
Expand All @@ -137,19 +133,19 @@ async def finalizer():
model_name = "anthropic/claude-3-5-sonnet-latest"

response = await thread_manager.run_thread(
thread_id=thread_id,
system_message=system_message,
model_name=model_name,
temperature=0.1,
max_tokens=8096,
tool_choice="auto",
temporary_message=state_message,
native_tool_calling=False,
xml_tool_calling=True,
stream=True,
execute_tools_on_stream=True,
parallel_tool_execution=True
)
thread_id=thread_id,
system_message=system_message,
model_name=model_name,
temperature=0.1,
max_tokens=8096,
tool_choice="auto",
temporary_message=state_message,
native_tool_calling=not use_xml,
xml_tool_calling=use_xml,
stream=True,
execute_tools_on_stream=True,
parallel_tool_execution=True
)

if isinstance(response, AsyncGenerator):
print("\n🤖 Assistant is responding:")
Expand All @@ -158,19 +154,14 @@ async def finalizer():
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)

Expand All @@ -180,25 +171,45 @@ async def finalizer():
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)
print("\nNon-streaming response received:", response)

await after_iteration()

await finalizer()

if __name__ == "__main__":
async def main():
def main():
"""Main entry point with synchronous setup."""
print("\n🚀 Welcome to AgentPress Web Developer Example!")

project_description = input("What would you like to build? (default: Create a modern, responsive landing page)\n> ")
if not project_description.strip():
project_description = "Create a modern, responsive landing page"

print("\nChoose your agent type:")
print("1. XML-based Tool Calling")
print(" - Structured XML format for tool execution")
print(" - Parses tool calls using XML outputs in the LLM response")

print("\n2. Standard Function Calling")
print(" - Native LLM function calling format")
print(" - JSON-based parameter passing")

use_xml = input("\nSelect tool calling format [1/2] (default: 1): ").strip() != "2"

print(f"\n{'XML-based' if use_xml else 'Standard'} agent will help you build: {project_description}")
print("Use Ctrl+C to stop the agent at any time.")

async def async_main():
thread_manager = ThreadManager()
thread_id = await thread_manager.create_thread()

await thread_manager.add_message(
thread_id,
{
"role": "user",
"content": "Create a modern, responsive landing page with HTML, CSS and JS."
"content": project_description
}
)
)
await run_agent(thread_id, use_xml)

await run_agent(thread_id)

asyncio.run(main())
asyncio.run(async_main())

if __name__ == "__main__":
main()
94 changes: 94 additions & 0 deletions agentpress/agents/simple_web_dev/workspace/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modern Landing Page</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<nav class="navbar">
<div class="logo">Brand</div>
<ul class="nav-links">
<li><a href="#home">Home</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
<div class="hamburger">
<span></span>
<span></span>
<span></span>
</div>
</nav>
</header>

<main>
<section id="home" class="hero">
<div class="hero-content">
<h1>Welcome to the Future</h1>
<p>Experience innovation at its finest</p>
<button class="cta-button">Get Started</button>
</div>
</section>

<section id="testimonials" class="testimonials">
<h2>What Our Clients Say</h2>
<div class="testimonial-grid">
<div class="testimonial-card">
<div class="testimonial-avatar">👤</div>
<p class="testimonial-text">"Amazing service! The team went above and beyond."</p>
<p class="testimonial-author">- John Doe, CEO</p>
</div>
<div class="testimonial-card">
<div class="testimonial-avatar">👤</div>
<p class="testimonial-text">"Incredible results. Would highly recommend!"</p>
<p class="testimonial-author">- Jane Smith, Designer</p>
</div>
<div class="testimonial-card">
<div class="testimonial-avatar">👤</div>
<p class="testimonial-text">"Professional and efficient service."</p>
<p class="testimonial-author">- Mike Johnson, Developer</p>
</div>
</div>
</section>

<section id="features" class="features">
<h2>Our Features</h2>
<div class="feature-grid">
<div class="feature-card">
<div class="feature-icon">🚀</div>
<h3>Fast Performance</h3>
<p>Lightning-quick loading times</p>
</div>
<div class="feature-card">
<div class="feature-icon">🎨</div>
<h3>Beautiful Design</h3>
<p>Stunning visuals and animations</p>
</div>
<div class="feature-card">
<div class="feature-icon">📱</div>
<h3>Responsive</h3>
<p>Works on all devices</p>
</div>
</div>
</section>

<section id="contact" class="contact">
<h2>Contact Us</h2>
<form id="contact-form">
<input type="text" placeholder="Name" required>
<input type="email" placeholder="Email" required>
<textarea placeholder="Message" required></textarea>
<button type="submit">Send Message</button>
</form>
</section>
</main>

<footer>
<p>&copy; 2024 Brand. All rights reserved.</p>
</footer>

<script src="script.js"></script>
</body>
</html>
Loading

0 comments on commit b20c074

Please sign in to comment.