mirror of https://github.com/kortix-ai/suna.git
proper xml schema result adding as user message, xml schema example
This commit is contained in:
parent
320dabb99d
commit
53557718e4
|
@ -7,16 +7,11 @@ from tools.terminal_tool import TerminalTool
|
||||||
import logging
|
import logging
|
||||||
from typing import AsyncGenerator
|
from typing import AsyncGenerator
|
||||||
import sys
|
import sys
|
||||||
from agentpress.xml_tool_parser import XMLToolParser
|
|
||||||
from agentpress.xml_tool_executor import XMLToolExecutor
|
|
||||||
from agentpress.xml_results_adder import XMLResultsAdder
|
|
||||||
|
|
||||||
async def run_agent(thread_id: str, max_iterations: int = 5):
|
async def run_agent(thread_id: str, max_iterations: int = 5):
|
||||||
# Initialize managers and tools
|
|
||||||
thread_manager = ThreadManager()
|
thread_manager = ThreadManager()
|
||||||
state_manager = StateManager()
|
state_manager = StateManager()
|
||||||
|
|
||||||
# Initialize tools
|
|
||||||
thread_manager.add_tool(FilesTool)
|
thread_manager.add_tool(FilesTool)
|
||||||
thread_manager.add_tool(TerminalTool)
|
thread_manager.add_tool(TerminalTool)
|
||||||
|
|
||||||
|
@ -24,12 +19,10 @@ async def run_agent(thread_id: str, max_iterations: int = 5):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def pre_iteration():
|
async def pre_iteration():
|
||||||
# Update files state
|
|
||||||
files_tool = FilesTool()
|
files_tool = FilesTool()
|
||||||
await files_tool._init_workspace_state()
|
await files_tool._init_workspace_state()
|
||||||
|
|
||||||
async def after_iteration():
|
async def after_iteration():
|
||||||
# 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): ")
|
custom_message = input("Enter a message to send (or press Enter to use 'Continue!!!' as message): ")
|
||||||
|
|
||||||
message_content = custom_message if custom_message else """
|
message_content = custom_message if custom_message else """
|
||||||
|
@ -151,8 +144,8 @@ Current development environment workspace state:
|
||||||
max_tokens=8096,
|
max_tokens=8096,
|
||||||
tool_choice="auto",
|
tool_choice="auto",
|
||||||
temporary_message=state_message,
|
temporary_message=state_message,
|
||||||
native_tool_calling=True,
|
native_tool_calling=False,
|
||||||
xml_tool_calling=False,
|
xml_tool_calling=True,
|
||||||
stream=True,
|
stream=True,
|
||||||
execute_tools_on_stream=True,
|
execute_tools_on_stream=True,
|
||||||
parallel_tool_execution=True
|
parallel_tool_execution=True
|
||||||
|
|
|
@ -138,7 +138,11 @@ class FilesTool(Tool):
|
||||||
{"param_name": "file_path", "node_type": "attribute", "path": "."},
|
{"param_name": "file_path", "node_type": "attribute", "path": "."},
|
||||||
{"param_name": "file_contents", "node_type": "content", "path": "."}
|
{"param_name": "file_contents", "node_type": "content", "path": "."}
|
||||||
],
|
],
|
||||||
description="Create a new file with the provided contents"
|
example='''
|
||||||
|
<create-file file_path="path/to/file">
|
||||||
|
File contents go here
|
||||||
|
</create-file>
|
||||||
|
'''
|
||||||
)
|
)
|
||||||
async def create_file(self, file_path: str, file_contents: str) -> ToolResult:
|
async def create_file(self, file_path: str, file_contents: str) -> ToolResult:
|
||||||
try:
|
try:
|
||||||
|
@ -177,7 +181,10 @@ class FilesTool(Tool):
|
||||||
mappings=[
|
mappings=[
|
||||||
{"param_name": "file_path", "node_type": "attribute", "path": "."}
|
{"param_name": "file_path", "node_type": "attribute", "path": "."}
|
||||||
],
|
],
|
||||||
description="Delete a file at the given path"
|
example='''
|
||||||
|
<delete-file file_path="path/to/file">
|
||||||
|
</delete-file>
|
||||||
|
'''
|
||||||
)
|
)
|
||||||
async def delete_file(self, file_path: str) -> ToolResult:
|
async def delete_file(self, file_path: str) -> ToolResult:
|
||||||
try:
|
try:
|
||||||
|
@ -221,7 +228,12 @@ class FilesTool(Tool):
|
||||||
{"param_name": "old_str", "node_type": "element", "path": "old_str"},
|
{"param_name": "old_str", "node_type": "element", "path": "old_str"},
|
||||||
{"param_name": "new_str", "node_type": "element", "path": "new_str"}
|
{"param_name": "new_str", "node_type": "element", "path": "new_str"}
|
||||||
],
|
],
|
||||||
description="Replace text in a file"
|
example='''
|
||||||
|
<str-replace file_path="path/to/file">
|
||||||
|
<old_str>text to replace</old_str>
|
||||||
|
<new_str>replacement text</new_str>
|
||||||
|
</str-replace>
|
||||||
|
'''
|
||||||
)
|
)
|
||||||
async def str_replace(self, file_path: str, old_str: str, new_str: str) -> ToolResult:
|
async def str_replace(self, file_path: str, old_str: str, new_str: str) -> ToolResult:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -46,7 +46,11 @@ class TerminalTool(Tool):
|
||||||
mappings=[
|
mappings=[
|
||||||
{"param_name": "command", "node_type": "content", "path": "."}
|
{"param_name": "command", "node_type": "content", "path": "."}
|
||||||
],
|
],
|
||||||
description="Execute a shell command in the workspace directory"
|
example='''
|
||||||
|
<execute-command>
|
||||||
|
npm install package-name
|
||||||
|
</execute-command>
|
||||||
|
'''
|
||||||
)
|
)
|
||||||
async def execute_command(self, command: str) -> ToolResult:
|
async def execute_command(self, command: str) -> ToolResult:
|
||||||
original_dir = os.getcwd()
|
original_dir = os.getcwd()
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
<!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 class="header">
|
|
||||||
<nav class="nav">
|
|
||||||
<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="#about">About</a></li>
|
|
||||||
<li><a href="#contact">Contact</a></li>
|
|
||||||
</ul>
|
|
||||||
<button class="mobile-nav-toggle" aria-label="Menu">
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
<span></span>
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<section id="home" class="hero">
|
|
||||||
<div class="hero-content">
|
|
||||||
<h1>Welcome to the Future</h1>
|
|
||||||
<p>Transform your digital presence with our innovative solutions</p>
|
|
||||||
<div class="cta-group">
|
|
||||||
<button class="cta-button primary">Get Started</button>
|
|
||||||
<button class="cta-button secondary">Learn More</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="hero-shape"></div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="features" class="features">
|
|
||||||
<h2>Our Features</h2>
|
|
||||||
<div class="features-grid">
|
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">🚀</div>
|
|
||||||
<h3>Fast Performance</h3>
|
|
||||||
<p>Lightning-quick load times and smooth interactions</p>
|
|
||||||
</div>
|
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">🎨</div>
|
|
||||||
<h3>Beautiful Design</h3>
|
|
||||||
<p>Stunning visuals that capture attention</p>
|
|
||||||
</div>
|
|
||||||
<div class="feature-card">
|
|
||||||
<div class="feature-icon">📱</div>
|
|
||||||
<h3>Responsive</h3>
|
|
||||||
<p>Perfect display on all devices</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="about" class="about">
|
|
||||||
<div class="about-content">
|
|
||||||
<h2>About Us</h2>
|
|
||||||
<p>We're dedicated to creating exceptional digital experiences that drive results.</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="contact" class="contact">
|
|
||||||
<h2>Get in Touch</h2>
|
|
||||||
<form class="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 class="footer">
|
|
||||||
<p>© 2024 Brand. All rights reserved.</p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="script.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,61 +0,0 @@
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const mobileNavToggle = document.querySelector('.mobile-nav-toggle');
|
|
||||||
const navLinks = document.querySelector('.nav-links');
|
|
||||||
const header = document.querySelector('.header');
|
|
||||||
let lastScroll = 0;
|
|
||||||
|
|
||||||
mobileNavToggle.addEventListener('click', () => {
|
|
||||||
navLinks.classList.toggle('active');
|
|
||||||
const spans = mobileNavToggle.querySelectorAll('span');
|
|
||||||
spans[0].style.transform = navLinks.classList.contains('active') ? 'rotate(45deg) translate(8px, 8px)' : '';
|
|
||||||
spans[1].style.opacity = navLinks.classList.contains('active') ? '0' : '1';
|
|
||||||
spans[2].style.transform = navLinks.classList.contains('active') ? 'rotate(-45deg) translate(7px, -7px)' : '';
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener('scroll', () => {
|
|
||||||
const currentScroll = window.pageYOffset;
|
|
||||||
|
|
||||||
if (currentScroll <= 0) {
|
|
||||||
header.style.transform = 'translateY(0)';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentScroll > lastScroll && !header.classList.contains('scroll-down')) {
|
|
||||||
header.style.transform = 'translateY(-100%)';
|
|
||||||
} else if (currentScroll < lastScroll && header.classList.contains('scroll-down')) {
|
|
||||||
header.style.transform = 'translateY(0)';
|
|
||||||
}
|
|
||||||
|
|
||||||
lastScroll = currentScroll;
|
|
||||||
});
|
|
||||||
|
|
||||||
const observerOptions = {
|
|
||||||
threshold: 0.1,
|
|
||||||
rootMargin: '0px 0px -50px 0px'
|
|
||||||
};
|
|
||||||
|
|
||||||
const observer = new IntersectionObserver((entries) => {
|
|
||||||
entries.forEach(entry => {
|
|
||||||
if (entry.isIntersecting) {
|
|
||||||
entry.target.style.opacity = '1';
|
|
||||||
entry.target.style.transform = 'translateY(0)';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, observerOptions);
|
|
||||||
|
|
||||||
document.querySelectorAll('section').forEach(section => {
|
|
||||||
section.style.opacity = '0';
|
|
||||||
section.style.transform = 'translateY(20px)';
|
|
||||||
section.style.transition = 'opacity 0.6s ease-out, transform 0.6s ease-out';
|
|
||||||
observer.observe(section);
|
|
||||||
});
|
|
||||||
|
|
||||||
const form = document.querySelector('.contact-form');
|
|
||||||
form.addEventListener('submit', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const formData = new FormData(form);
|
|
||||||
const data = Object.fromEntries(formData);
|
|
||||||
console.log('Form submitted:', data);
|
|
||||||
form.reset();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,343 +0,0 @@
|
||||||
:root {
|
|
||||||
--primary-color: #6366f1;
|
|
||||||
--secondary-color: #4f46e5;
|
|
||||||
--text-color: #18181b;
|
|
||||||
--light-text: #71717a;
|
|
||||||
--background: #ffffff;
|
|
||||||
--glass-bg: rgba(255, 255, 255, 0.7);
|
|
||||||
--glass-border: rgba(255, 255, 255, 0.3);
|
|
||||||
--section-padding: 5rem 2rem;
|
|
||||||
--gradient-1: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
|
|
||||||
--gradient-2: linear-gradient(135deg, #c084fc 0%, #a855f7 100%);
|
|
||||||
--shadow-1: 0 10px 30px -10px rgba(99, 102, 241, 0.2);
|
|
||||||
--shadow-2: 0 20px 40px -15px rgba(99, 102, 241, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
||||||
line-height: 1.6;
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
background: var(--glass-bg);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
border-bottom: 1px solid var(--glass-border);
|
|
||||||
box-shadow: var(--shadow-1);
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-links {
|
|
||||||
display: flex;
|
|
||||||
gap: 2rem;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-links a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: var(--text-color);
|
|
||||||
font-weight: 500;
|
|
||||||
transition: color 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-links a:hover {
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-nav-toggle {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero {
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
background: var(--gradient-1);
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: var(--section-padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
width: 150%;
|
|
||||||
height: 150%;
|
|
||||||
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 60%);
|
|
||||||
animation: rotate 20s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotate {
|
|
||||||
from { transform: rotate(0deg); }
|
|
||||||
to { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero-content {
|
|
||||||
max-width: 800px;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
background: var(--glass-bg);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
padding: 3rem;
|
|
||||||
border-radius: 1rem;
|
|
||||||
border: 1px solid var(--glass-border);
|
|
||||||
box-shadow: var(--shadow-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero h1 {
|
|
||||||
font-size: 3.5rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero p {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
color: var(--light-text);
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cta-group {
|
|
||||||
display: flex;
|
|
||||||
gap: 1rem;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cta-button {
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cta-button::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
background: rgba(255, 255, 255, 0.2);
|
|
||||||
border-radius: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
transition: width 0.6s ease, height 0.6s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cta-button:hover::before {
|
|
||||||
width: 300%;
|
|
||||||
height: 300%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cta-button.primary {
|
|
||||||
background: var(--gradient-1);
|
|
||||||
color: white;
|
|
||||||
box-shadow: var(--shadow-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cta-button.secondary {
|
|
||||||
background: var(--glass-bg);
|
|
||||||
color: var(--primary-color);
|
|
||||||
border: 1px solid var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cta-button:hover {
|
|
||||||
background: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.features {
|
|
||||||
padding: var(--section-padding);
|
|
||||||
background: var(--background);
|
|
||||||
}
|
|
||||||
|
|
||||||
.features h2 {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
font-size: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.features-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
||||||
gap: 2rem;
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-card {
|
|
||||||
padding: 2rem;
|
|
||||||
text-align: center;
|
|
||||||
background: var(--glass-bg);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
border: 1px solid var(--glass-border);
|
|
||||||
border-radius: 1rem;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
box-shadow: var(--shadow-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-card:hover {
|
|
||||||
transform: translateY(-5px) scale(1.02);
|
|
||||||
box-shadow: var(--shadow-2);
|
|
||||||
background: var(--gradient-2);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-icon {
|
|
||||||
font-size: 2.5rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.about {
|
|
||||||
padding: var(--section-padding);
|
|
||||||
background: #f3f4f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.about-content {
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 0 auto;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.about h2 {
|
|
||||||
font-size: 2.5rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact {
|
|
||||||
padding: var(--section-padding);
|
|
||||||
background: var(--background);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact h2 {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
font-size: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-form {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-form input,
|
|
||||||
.contact-form textarea {
|
|
||||||
padding: 1rem;
|
|
||||||
background: var(--glass-bg);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
border: 1px solid var(--glass-border);
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-form input:focus,
|
|
||||||
.contact-form textarea:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: var(--primary-color);
|
|
||||||
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-form textarea {
|
|
||||||
height: 150px;
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-form button {
|
|
||||||
padding: 1rem;
|
|
||||||
background: var(--primary-color);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-form button:hover {
|
|
||||||
background: var(--secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
padding: 2rem;
|
|
||||||
text-align: center;
|
|
||||||
background: #f3f4f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.nav-links {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background: var(--background);
|
|
||||||
padding: 1rem;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-links.active {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-nav-toggle {
|
|
||||||
display: block;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-nav-toggle span {
|
|
||||||
display: block;
|
|
||||||
width: 25px;
|
|
||||||
height: 3px;
|
|
||||||
background: var(--text-color);
|
|
||||||
margin: 5px 0;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero h1 {
|
|
||||||
font-size: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.features-grid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,13 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import uuid
|
||||||
from typing import List, Dict, Any, Optional, Type, Union, AsyncGenerator
|
from typing import List, Dict, Any, Optional, Type, Union, AsyncGenerator
|
||||||
from agentpress.llm import make_llm_api_call
|
from agentpress.llm import make_llm_api_call
|
||||||
from agentpress.tool import Tool, ToolResult
|
from agentpress.tool import Tool, ToolResult
|
||||||
from agentpress.tool_registry import ToolRegistry
|
from agentpress.tool_registry import ToolRegistry
|
||||||
from agentpress.llm_response_processor import LLMResponseProcessor
|
from agentpress.llm_response_processor import LLMResponseProcessor
|
||||||
from agentpress.base_processors import ToolParserBase, ToolExecutorBase, ResultsAdderBase
|
from agentpress.base_processors import ToolParserBase, ToolExecutorBase, ResultsAdderBase
|
||||||
import uuid
|
|
||||||
|
|
||||||
from agentpress.xml_tool_parser import XMLToolParser
|
from agentpress.xml_tool_parser import XMLToolParser
|
||||||
from agentpress.xml_tool_executor import XMLToolExecutor
|
from agentpress.xml_tool_executor import XMLToolExecutor
|
||||||
|
|
|
@ -26,7 +26,7 @@ class XMLTagSchema:
|
||||||
"""Schema for XML tool tags with improved node mapping"""
|
"""Schema for XML tool tags with improved node mapping"""
|
||||||
tag_name: str # Root tag name (e.g. "str-replace")
|
tag_name: str # Root tag name (e.g. "str-replace")
|
||||||
mappings: List[XMLNodeMapping] = field(default_factory=list)
|
mappings: List[XMLNodeMapping] = field(default_factory=list)
|
||||||
description: Optional[str] = None
|
example: Optional[str] = None # Changed from description to example
|
||||||
|
|
||||||
def add_mapping(self, param_name: str, node_type: str = "element", path: str = ".") -> None:
|
def add_mapping(self, param_name: str, node_type: str = "element", path: str = ".") -> None:
|
||||||
"""Add a new node mapping"""
|
"""Add a new node mapping"""
|
||||||
|
@ -97,7 +97,7 @@ def openapi_schema(schema: Dict[str, Any]):
|
||||||
def xml_schema(
|
def xml_schema(
|
||||||
tag_name: str,
|
tag_name: str,
|
||||||
mappings: List[Dict[str, str]] = None,
|
mappings: List[Dict[str, str]] = None,
|
||||||
description: str = None
|
example: str = None # Changed from description to example
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Decorator for XML schema tools with improved node mapping.
|
Decorator for XML schema tools with improved node mapping.
|
||||||
|
@ -108,7 +108,7 @@ def xml_schema(
|
||||||
- param_name: Name of the function parameter
|
- param_name: Name of the function parameter
|
||||||
- node_type: "element", "attribute", or "content"
|
- node_type: "element", "attribute", or "content"
|
||||||
- path: Path to the node (default "." for root)
|
- path: Path to the node (default "." for root)
|
||||||
description: Optional description of the tool
|
example: Optional example showing how to use the XML tag
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@xml_schema(
|
@xml_schema(
|
||||||
|
@ -118,11 +118,16 @@ def xml_schema(
|
||||||
{"param_name": "old_str", "node_type": "element", "path": "old_str"},
|
{"param_name": "old_str", "node_type": "element", "path": "old_str"},
|
||||||
{"param_name": "new_str", "node_type": "element", "path": "new_str"}
|
{"param_name": "new_str", "node_type": "element", "path": "new_str"}
|
||||||
],
|
],
|
||||||
description="Replace text in a file"
|
example='''
|
||||||
|
<str-replace file_path="path/to/file">
|
||||||
|
<old_str>text to replace</old_str>
|
||||||
|
<new_str>replacement text</new_str>
|
||||||
|
</str-replace>
|
||||||
|
'''
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
xml_schema = XMLTagSchema(tag_name=tag_name, description=description)
|
xml_schema = XMLTagSchema(tag_name=tag_name, example=example)
|
||||||
|
|
||||||
# Add mappings
|
# Add mappings
|
||||||
if mappings:
|
if mappings:
|
||||||
|
|
|
@ -129,3 +129,16 @@ class ToolRegistry:
|
||||||
for tool_info in self.tools.values()
|
for tool_info in self.tools.values()
|
||||||
if tool_info['schema'].schema_type == SchemaType.OPENAPI
|
if tool_info['schema'].schema_type == SchemaType.OPENAPI
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def get_xml_examples(self) -> Dict[str, str]:
|
||||||
|
"""Get all XML tag examples from registered tools.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, str]: Dictionary mapping tag names to their examples
|
||||||
|
"""
|
||||||
|
examples = {}
|
||||||
|
for tool_info in self.xml_tools.values():
|
||||||
|
schema = tool_info['schema']
|
||||||
|
if schema.xml_schema and schema.xml_schema.example:
|
||||||
|
examples[schema.xml_schema.tag_name] = schema.xml_schema.example
|
||||||
|
return examples
|
||||||
|
|
|
@ -11,68 +11,65 @@ class XMLResultsAdder(ResultsAdderBase):
|
||||||
|
|
||||||
def __init__(self, thread_manager):
|
def __init__(self, thread_manager):
|
||||||
super().__init__(thread_manager)
|
super().__init__(thread_manager)
|
||||||
self.pending_tool_results = {}
|
self.message_added = False
|
||||||
|
|
||||||
def _format_xml_response(self, content: str, tool_calls: Optional[List[Dict[str, Any]]] = None) -> str:
|
|
||||||
"""Format the response content with XML tool results."""
|
|
||||||
response_parts = []
|
|
||||||
|
|
||||||
# Add any non-XML content first
|
|
||||||
non_xml_content = []
|
|
||||||
lines = content.split('\n')
|
|
||||||
for line in lines:
|
|
||||||
if not (line.strip().startswith('<') and line.strip().endswith('>')):
|
|
||||||
non_xml_content.append(line)
|
|
||||||
if non_xml_content:
|
|
||||||
response_parts.append('\n'.join(non_xml_content))
|
|
||||||
|
|
||||||
# Add XML blocks with their results
|
|
||||||
if tool_calls:
|
|
||||||
for tool_call in tool_calls:
|
|
||||||
tool_id = tool_call['id']
|
|
||||||
if tool_id in self.pending_tool_results:
|
|
||||||
result = self.pending_tool_results[tool_id]
|
|
||||||
response_parts.append(
|
|
||||||
f"<tool-result id='{tool_id}'>\n"
|
|
||||||
f"{result}\n"
|
|
||||||
f"</tool-result>"
|
|
||||||
)
|
|
||||||
|
|
||||||
return '\n\n'.join(response_parts)
|
|
||||||
|
|
||||||
async def add_initial_response(self, thread_id: str, content: str, tool_calls: Optional[List[Dict[str, Any]]] = None):
|
async def add_initial_response(self, thread_id: str, content: str, tool_calls: Optional[List[Dict[str, Any]]] = None):
|
||||||
"""Add initial response with XML formatting."""
|
"""Add initial response without modifications."""
|
||||||
formatted_content = self._format_xml_response(content, tool_calls)
|
|
||||||
message = {
|
message = {
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"content": formatted_content
|
"content": content
|
||||||
}
|
}
|
||||||
await self.add_message(thread_id, message)
|
await self.add_message(thread_id, message)
|
||||||
self.message_added = True
|
self.message_added = True
|
||||||
|
|
||||||
async def update_response(self, thread_id: str, content: str, tool_calls: Optional[List[Dict[str, Any]]] = None):
|
async def update_response(self, thread_id: str, content: str, tool_calls: Optional[List[Dict[str, Any]]] = None):
|
||||||
"""Update response with XML formatting."""
|
"""Update response without modifications."""
|
||||||
if not self.message_added:
|
if not self.message_added:
|
||||||
await self.add_initial_response(thread_id, content, tool_calls)
|
await self.add_initial_response(thread_id, content, tool_calls)
|
||||||
return
|
return
|
||||||
|
|
||||||
formatted_content = self._format_xml_response(content, tool_calls)
|
|
||||||
message = {
|
message = {
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"content": formatted_content
|
"content": content
|
||||||
}
|
}
|
||||||
await self.update_message(thread_id, message)
|
await self.update_message(thread_id, message)
|
||||||
|
|
||||||
async def add_tool_result(self, thread_id: str, result: Dict[str, Any]):
|
async def add_tool_result(self, thread_id: str, result: Dict[str, Any]):
|
||||||
"""Store tool result for inclusion in the XML response."""
|
"""Add tool result as a user message."""
|
||||||
tool_call_id = result['tool_call_id']
|
try:
|
||||||
self.pending_tool_results[tool_call_id] = result['content']
|
# Get the original tool call to find the root tag
|
||||||
|
messages = await self.list_messages(thread_id)
|
||||||
|
assistant_msg = next((msg for msg in reversed(messages)
|
||||||
|
if msg['role'] == 'assistant'), None)
|
||||||
|
|
||||||
# Update the message to include the new result
|
if assistant_msg:
|
||||||
messages = await self.list_messages(thread_id)
|
content = assistant_msg['content']
|
||||||
for msg in reversed(messages):
|
# Find the opening XML tag for this tool call
|
||||||
if msg['role'] == 'assistant':
|
tool_start = content.find(f'<{result["name"]}')
|
||||||
content = msg['content']
|
if tool_start >= 0:
|
||||||
tool_calls = msg.get('tool_calls', [])
|
tag_end = content.find('>', tool_start)
|
||||||
await self.update_response(thread_id, content, tool_calls)
|
if tag_end >= 0:
|
||||||
break
|
root_tag = content[tool_start:tag_end + 1]
|
||||||
|
# Create a simple reference message as user role
|
||||||
|
result_message = {
|
||||||
|
"role": "user",
|
||||||
|
"content": f"Result for {root_tag}\n{result['content']}"
|
||||||
|
}
|
||||||
|
await self.add_message(thread_id, result_message)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Fallback if we can't find the root tag
|
||||||
|
result_message = {
|
||||||
|
"role": "user",
|
||||||
|
"content": f"Result for {result['name']}:\n{result['content']}"
|
||||||
|
}
|
||||||
|
await self.add_message(thread_id, result_message)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error adding tool result: {e}")
|
||||||
|
# Ensure the result is still added even if there's an error
|
||||||
|
result_message = {
|
||||||
|
"role": "user",
|
||||||
|
"content": f"Result for {result['name']}:\n{result['content']}"
|
||||||
|
}
|
||||||
|
await self.add_message(thread_id, result_message)
|
Loading…
Reference in New Issue