105 lines
3.4 KiB
Python
105 lines
3.4 KiB
Python
"""
|
|
tools/subagent_tool.py — Sub-agent creation and synchronous execution.
|
|
|
|
Only available when the parent agent has can_create_subagents=True.
|
|
Creates a child agent in the DB (with parent_agent_id set) and runs it
|
|
synchronously, returning the result and token counts.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from .base import BaseTool, ToolResult
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SubagentTool(BaseTool):
|
|
name = "subagent"
|
|
description = (
|
|
"Create and run a sub-agent synchronously. "
|
|
"Use this to delegate a well-defined sub-task to a focused agent. "
|
|
"The sub-agent runs to completion and returns its result. "
|
|
"Operation: create_and_run(name, prompt, model=None)"
|
|
)
|
|
input_schema = {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"description": "Short name for the sub-agent",
|
|
},
|
|
"prompt": {
|
|
"type": "string",
|
|
"description": "The task prompt for the sub-agent",
|
|
},
|
|
"model": {
|
|
"type": "string",
|
|
"description": "Model override for the sub-agent (optional)",
|
|
},
|
|
},
|
|
"required": ["name", "prompt"],
|
|
}
|
|
requires_confirmation = False
|
|
allowed_in_scheduled_tasks = False
|
|
|
|
def __init__(self, parent_agent_id: str, parent_model: str) -> None:
|
|
self._parent_agent_id = parent_agent_id
|
|
self._parent_model = parent_model
|
|
|
|
async def execute(
|
|
self,
|
|
name: str,
|
|
prompt: str,
|
|
model: str = "",
|
|
**kwargs,
|
|
) -> ToolResult:
|
|
from ..agents import tasks as agent_store
|
|
from ..agents.runner import agent_runner
|
|
|
|
resolved_model = model or self._parent_model
|
|
|
|
try:
|
|
# Create sub-agent in DB
|
|
sub = agent_store.create_agent(
|
|
name=name,
|
|
prompt=prompt,
|
|
model=resolved_model,
|
|
parent_agent_id=self._parent_agent_id,
|
|
created_by=self._parent_agent_id,
|
|
enabled=True,
|
|
)
|
|
sub_id = sub["id"]
|
|
|
|
# Run it now and wait for completion
|
|
run = await agent_runner.run_agent_now(sub_id)
|
|
run_id = run["id"]
|
|
|
|
# Wait for the asyncio task to finish (run_agent_now creates the task)
|
|
import asyncio
|
|
task = agent_runner._running.get(run_id)
|
|
if task:
|
|
await task
|
|
|
|
# Fetch final run record
|
|
final = agent_store.get_run(run_id)
|
|
if not final:
|
|
return ToolResult(success=False, error="Sub-agent run record not found")
|
|
|
|
return ToolResult(
|
|
success=final["status"] == "success",
|
|
data={
|
|
"run_id": run_id,
|
|
"agent_id": sub_id,
|
|
"status": final["status"],
|
|
"result": final.get("result") or "",
|
|
"input_tokens": final.get("input_tokens", 0),
|
|
"output_tokens": final.get("output_tokens", 0),
|
|
},
|
|
error=final.get("error") if final["status"] != "success" else None,
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"[subagent] Error running sub-agent: {e}")
|
|
return ToolResult(success=False, error=f"Sub-agent error: {e}")
|