AiCoderClean / brain_server /agents /tool_selector_agent.py
MrA7A1's picture
Initial modernized KAPO runtime upload
06ce7ac verified
Raw History Blame Contribute Delete
4.13 kB
"""Tool selector for remote execution steps."""
import sqlite3
from typing import Any
from api.deps import get_logger, load_config
logger = get_logger("kapo.agent.tool_selector")
class ToolSelectorAgent:
def __init__(self):
self.cfg = load_config()
def _load_catalog(self) -> list[dict[str, Any]]:
tools_db = self.cfg.get("TOOLS_DB_PATH")
if not tools_db or not str(tools_db).endswith(".db"):
return []
try:
conn = sqlite3.connect(str(tools_db))
cur = conn.cursor()
cur.execute(
"""
SELECT tool_name, install_command, path, description, installed
FROM tools
"""
)
rows = cur.fetchall()
conn.close()
except sqlite3.OperationalError:
return []
except Exception:
logger.exception("Tool catalog load failed")
return []
return [
{
"tool_name": row[0],
"install_command": row[1],
"path": row[2],
"description": row[3] or "",
"installed": bool(row[4]),
}
for row in rows
]
def _step_text(self, step: dict[str, Any]) -> str:
for key in ("input", "description", "title", "summary", "task", "prompt"):
value = str(step.get(key, "")).strip()
if value:
return value
return ""
def _fallback_tool(self, tool_hint: str) -> dict[str, Any]:
name = f"fallback_{tool_hint or 'command'}"
return {
"tool_name": name,
"description": "Synthetic fallback tool selected by ToolSelectorAgent",
"path": tool_hint or "",
"installed": True,
}
def _fallback_command(self, step: dict[str, Any], tool_hint: str = "") -> str:
action = str(step.get("action", "")).strip().lower()
step_input = self._step_text(step)
explicit_command = str(step.get("command", "")).strip()
if explicit_command:
return explicit_command
if action == "research":
return f"echo Research task queued: {step_input}".strip()
if action in {"verify", "summarize", "respond", "synthesize"}:
if step_input:
return f"python -c \"print({step_input!r})\""
return "echo Verification requested"
if action in {"execute", "collect_requirements", "analyze", "decompose", "collect_context"}:
return f"python -c \"print({step_input!r})\"" if step_input else "python -c \"print('step received')\""
if tool_hint in {"python", "py"} or not tool_hint:
return f"python -c \"print({step_input!r})\"" if step_input else "python -c \"print('step received')\""
if step_input:
return f"echo {step_input}"
return "echo Step received"
def select_tool(self, step: dict[str, Any]) -> dict[str, Any]:
action = str(step.get("action", "")).strip().lower()
tool_hint = str(step.get("tool_hint", "")).strip().lower()
step_input = self._step_text(step).lower()
catalog = self._load_catalog()
for tool in catalog:
haystack = " ".join([tool["tool_name"], tool["description"], tool["path"] or ""]).lower()
if tool_hint and tool_hint in haystack:
return {"command": tool["path"] or tool["tool_name"], "files": {}, "env": {}, "tool": tool}
if action and action in haystack:
return {"command": tool["path"] or tool["tool_name"], "files": {}, "env": {}, "tool": tool}
if step_input and any(token in haystack for token in step_input.split()[:4]):
return {"command": tool["path"] or tool["tool_name"], "files": {}, "env": {}, "tool": tool}
return {
"command": self._fallback_command(step, tool_hint=tool_hint),
"files": step.get("files", {}),
"env": step.get("env", {}),
"tool": self._fallback_tool(tool_hint or "python"),
}