|
|
""" |
|
|
Executor Agent for SPARKNET |
|
|
Handles task execution and tool usage |
|
|
""" |
|
|
|
|
|
from typing import Optional, Dict, Any |
|
|
from loguru import logger |
|
|
import json |
|
|
import re |
|
|
|
|
|
from .base_agent import BaseAgent, Task, Message |
|
|
from ..llm.ollama_client import OllamaClient |
|
|
|
|
|
|
|
|
class ExecutorAgent(BaseAgent): |
|
|
"""Agent specialized in executing tasks using available tools.""" |
|
|
|
|
|
def __init__( |
|
|
self, |
|
|
llm_client: OllamaClient, |
|
|
model: str = "llama3.1:8b", |
|
|
temperature: float = 0.5, |
|
|
): |
|
|
system_prompt = """You are an execution agent specialized in completing tasks using available tools. |
|
|
|
|
|
Your role is to: |
|
|
1. Analyze the task requirements |
|
|
2. Select and use appropriate tools |
|
|
3. Execute actions to complete the task |
|
|
4. Report results clearly |
|
|
|
|
|
When you need to use a tool, format your response as: |
|
|
TOOL: tool_name |
|
|
PARAMETERS: { |
|
|
"param1": "value1", |
|
|
"param2": "value2" |
|
|
} |
|
|
|
|
|
After receiving tool results, provide a final answer starting with: |
|
|
RESULT: [your analysis and conclusion] |
|
|
|
|
|
Be precise, focused, and efficient in task completion.""" |
|
|
|
|
|
super().__init__( |
|
|
name="ExecutorAgent", |
|
|
description="Task execution and tool usage agent", |
|
|
llm_client=llm_client, |
|
|
model=model, |
|
|
system_prompt=system_prompt, |
|
|
temperature=temperature, |
|
|
max_tokens=1024, |
|
|
) |
|
|
|
|
|
async def process_task(self, task: Task) -> Task: |
|
|
""" |
|
|
Process and execute a task. |
|
|
|
|
|
Args: |
|
|
task: Task to process |
|
|
|
|
|
Returns: |
|
|
Updated task with results |
|
|
""" |
|
|
logger.info(f"ExecutorAgent processing task: {task.id}") |
|
|
task.status = "in_progress" |
|
|
|
|
|
try: |
|
|
|
|
|
task_message = Message( |
|
|
role="user", |
|
|
content=f"Task: {task.description}\n\nAvailable tools: {', '.join(self.get_available_tools())}", |
|
|
sender="system", |
|
|
) |
|
|
|
|
|
|
|
|
self.clear_history() |
|
|
self.add_message(task_message) |
|
|
|
|
|
|
|
|
max_iterations = 5 |
|
|
iteration = 0 |
|
|
final_result = None |
|
|
|
|
|
while iteration < max_iterations: |
|
|
iteration += 1 |
|
|
logger.debug(f"Iteration {iteration}/{max_iterations}") |
|
|
|
|
|
|
|
|
response = await self.call_llm(messages=self.messages) |
|
|
|
|
|
|
|
|
self.add_message( |
|
|
Message( |
|
|
role="assistant", |
|
|
content=response, |
|
|
sender=self.name, |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
if "TOOL:" in response: |
|
|
tool_result = await self._execute_tool_from_response(response) |
|
|
|
|
|
|
|
|
tool_message = Message( |
|
|
role="user", |
|
|
content=f"Tool execution result:\nSuccess: {tool_result.success}\nOutput: {tool_result.output}\nError: {tool_result.error}", |
|
|
sender="system", |
|
|
) |
|
|
self.add_message(tool_message) |
|
|
|
|
|
|
|
|
if "RESULT:" in response: |
|
|
|
|
|
result_match = re.search(r"RESULT:\s*(.+)", response, re.DOTALL) |
|
|
if result_match: |
|
|
final_result = result_match.group(1).strip() |
|
|
break |
|
|
|
|
|
if final_result: |
|
|
task.result = final_result |
|
|
task.status = "completed" |
|
|
logger.info(f"Task {task.id} completed successfully") |
|
|
else: |
|
|
task.result = "Task processing reached maximum iterations without completion" |
|
|
task.status = "completed" |
|
|
logger.warning(f"Task {task.id} reached max iterations") |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error processing task {task.id}: {e}") |
|
|
task.status = "failed" |
|
|
task.error = str(e) |
|
|
|
|
|
return task |
|
|
|
|
|
async def _execute_tool_from_response(self, response: str) -> Any: |
|
|
""" |
|
|
Parse and execute tool call from agent response. |
|
|
|
|
|
Args: |
|
|
response: Agent response containing tool call |
|
|
|
|
|
Returns: |
|
|
Tool result |
|
|
""" |
|
|
try: |
|
|
|
|
|
tool_match = re.search(r"TOOL:\s*(\w+)", response) |
|
|
if not tool_match: |
|
|
return {"success": False, "error": "Could not parse tool name"} |
|
|
|
|
|
tool_name = tool_match.group(1) |
|
|
|
|
|
|
|
|
params_match = re.search(r"PARAMETERS:\s*(\{[^}]+\})", response, re.DOTALL) |
|
|
if params_match: |
|
|
params_str = params_match.group(1) |
|
|
|
|
|
params_str = params_str.replace("'", '"') |
|
|
params = json.loads(params_str) |
|
|
else: |
|
|
params = {} |
|
|
|
|
|
logger.info(f"Executing tool {tool_name} with params: {params}") |
|
|
|
|
|
|
|
|
result = await self.execute_tool(tool_name, **params) |
|
|
|
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error executing tool from response: {e}") |
|
|
return { |
|
|
"success": False, |
|
|
"error": f"Tool execution error: {str(e)}", |
|
|
} |
|
|
|