File size: 8,943 Bytes
666aab6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | """
Tool Executor β Routes tool calls to the right implementation
Supports: code, shell, file, browser, github, memory, search, test, none
"""
import asyncio
import os
import subprocess
import tempfile
import time
from typing import Any, List, Optional
import structlog
from api.websocket_manager import WebSocketManager
log = structlog.get_logger()
class ToolExecutor:
def __init__(self, ws_manager: WebSocketManager):
self.ws = ws_manager
async def run(
self,
tool: str,
task: str,
goal: str = "",
previous: List = [],
task_id: str = "",
session_id: str = "",
) -> str:
tool = (tool or "none").lower().strip()
dispatch = {
"code": self._tool_code,
"shell": self._tool_shell,
"file": self._tool_file,
"github": self._tool_github,
"memory": self._tool_memory,
"search": self._tool_search,
"test": self._tool_test,
"browser": self._tool_browser,
"none": self._tool_none,
}
fn = dispatch.get(tool, self._tool_none)
return await fn(task=task, goal=goal, previous=previous, task_id=task_id, session_id=session_id)
# βββ Code Tool βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def _tool_code(self, task, goal, previous, task_id, session_id) -> str:
"""Generate code using LLM."""
from core.agent import AgentCore
agent = AgentCore(self.ws)
messages = [
{"role": "system", "content": "You are an expert software engineer. Write clean, production-quality code. Return only the code with minimal explanation."},
{"role": "user", "content": f"Task: {task}\nGoal: {goal}\n\nWrite the code to accomplish this."},
]
result = await agent.llm_stream(messages, task_id=task_id, session_id=session_id)
return result or f"# Code for: {task}"
# βββ Shell Tool ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def _tool_shell(self, task, goal, previous, task_id, session_id) -> str:
"""Execute shell commands safely in a temp workspace."""
# Extract command from task description
from core.agent import AgentCore
agent = AgentCore(self.ws)
messages = [
{"role": "system", "content": "Extract the shell command to run. Return ONLY the command, nothing else."},
{"role": "user", "content": f"Task: {task}"},
]
cmd = await agent.llm_stream(messages, task_id=task_id, session_id=session_id)
cmd = cmd.strip().strip("`").strip()
# Safety: block dangerous commands
blocked = ["rm -rf /", ":(){ :|:& };:", "mkfs", "dd if=", "shutdown", "reboot", "halt"]
for b in blocked:
if b in cmd:
return f"β Blocked dangerous command: {cmd}"
try:
await self.ws.emit(task_id, "step_progress", {
"action": "shell_exec",
"command": cmd[:200],
}, session_id=session_id)
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
cwd="/tmp",
)
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=30)
output = stdout.decode()[:2000] + (stderr.decode()[:500] if stderr else "")
return output or "Command executed (no output)"
except asyncio.TimeoutError:
return "β οΈ Command timed out after 30s"
except Exception as e:
return f"β Shell error: {str(e)}"
# βββ File Tool βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def _tool_file(self, task, goal, previous, task_id, session_id) -> str:
"""Create or modify files."""
from core.agent import AgentCore
agent = AgentCore(self.ws)
messages = [
{"role": "system", "content": "Generate file content. Respond with JSON: {\"filename\": \"...\", \"content\": \"...\"}"},
{"role": "user", "content": f"Task: {task}\nGoal: {goal}"},
]
raw = await agent.llm_stream(messages, task_id=task_id, session_id=session_id)
try:
import json
start = raw.find("{")
end = raw.rfind("}") + 1
data = json.loads(raw[start:end])
filename = data.get("filename", "output.txt")
content = data.get("content", raw)
path = f"/tmp/workspace/{filename}"
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
f.write(content)
await self.ws.emit(task_id, "step_progress", {
"action": "file_written",
"filename": filename,
"size": len(content),
}, session_id=session_id)
return f"β
File written: {filename} ({len(content)} chars)"
except Exception as e:
return f"File task result: {raw[:500]}"
# βββ GitHub Tool βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def _tool_github(self, task, goal, previous, task_id, session_id) -> str:
"""Perform GitHub operations."""
return f"GitHub: {task}\n(Set GITHUB_TOKEN to enable real GitHub operations)"
# βββ Memory Tool βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def _tool_memory(self, task, goal, previous, task_id, session_id) -> str:
"""Save/retrieve from memory."""
from memory.db import save_memory, search_memory
results = await search_memory(task[:50], session_id=session_id)
if results:
return "\n".join([r["content"][:300] for r in results[:3]])
return "No relevant memories found"
# βββ Search Tool βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def _tool_search(self, task, goal, previous, task_id, session_id) -> str:
"""Web search using available APIs."""
return f"Search result for: {task}\n(Integrate search API for real results)"
# βββ Test Tool βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def _tool_test(self, task, goal, previous, task_id, session_id) -> str:
"""Generate and run tests."""
from core.agent import AgentCore
agent = AgentCore(self.ws)
messages = [
{"role": "system", "content": "Write test cases for the given task. Use pytest format."},
{"role": "user", "content": f"Write tests for: {task}\nContext: {goal}"},
]
result = await agent.llm_stream(messages, task_id=task_id, session_id=session_id)
return result or f"# Tests for: {task}"
# βββ Browser Tool ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def _tool_browser(self, task, goal, previous, task_id, session_id) -> str:
"""Browser automation (stub β extend with playwright)."""
return f"Browser task: {task}\n(Install playwright for real browser automation)"
# βββ None Tool βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def _tool_none(self, task, goal, previous, task_id, session_id) -> str:
"""Use LLM directly without tools."""
from core.agent import AgentCore
agent = AgentCore(self.ws)
messages = [
{"role": "system", "content": "You are an expert engineer. Complete the task thoroughly."},
{"role": "user", "content": f"Task: {task}\nGoal context: {goal}"},
]
result = await agent.llm_stream(messages, task_id=task_id, session_id=session_id)
return result or f"Completed: {task}"
|