Initial commit
This commit is contained in:
104
server/tools/subagent_tool.py
Normal file
104
server/tools/subagent_tool.py
Normal file
@@ -0,0 +1,104 @@
|
||||
"""
|
||||
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}")
|
||||
Reference in New Issue
Block a user