fix(subagent): avoid missing from_legacy call

This commit is contained in:
Chris Alexander
2026-02-17 21:59:02 +00:00
parent 71d90de31b
commit d633ed6e51

View File

@@ -36,6 +36,7 @@ class SubagentManager:
restrict_to_workspace: bool = False,
):
from nanobot.config.schema import ExecToolConfig, WebSearchConfig
self.provider = provider
self.workspace = workspace
self.bus = bus
@@ -63,9 +64,7 @@ class SubagentManager:
display_label = label or task[:30] + ("..." if len(task) > 30 else "")
origin = {"channel": origin_channel, "chat_id": origin_chat_id}
bg_task = asyncio.create_task(
self._run_subagent(task_id, task, display_label, origin)
)
bg_task = asyncio.create_task(self._run_subagent(task_id, task, display_label, origin))
self._running_tasks[task_id] = bg_task
if session_key:
self._session_tasks.setdefault(session_key, set()).add(task_id)
@@ -100,15 +99,17 @@ class SubagentManager:
tools.register(WriteFileTool(workspace=self.workspace, allowed_dir=allowed_dir))
tools.register(EditFileTool(workspace=self.workspace, allowed_dir=allowed_dir))
tools.register(ListDirTool(workspace=self.workspace, allowed_dir=allowed_dir))
tools.register(ExecTool(
working_dir=str(self.workspace),
timeout=self.exec_config.timeout,
restrict_to_workspace=self.restrict_to_workspace,
path_append=self.exec_config.path_append,
))
tools.register(
ExecTool(
working_dir=str(self.workspace),
timeout=self.exec_config.timeout,
restrict_to_workspace=self.restrict_to_workspace,
path_append=self.exec_config.path_append,
)
)
tools.register(WebSearchTool(config=self.web_search_config, proxy=self.web_proxy))
tools.register(WebFetchTool(proxy=self.web_proxy))
system_prompt = self._build_subagent_prompt()
messages: list[dict[str, Any]] = [
{"role": "system", "content": system_prompt},
@@ -145,23 +146,32 @@ class SubagentManager:
}
for tc in response.tool_calls
]
messages.append({
"role": "assistant",
"content": response.content or "",
"tool_calls": tool_call_dicts,
})
messages.append(
{
"role": "assistant",
"content": response.content or "",
"tool_calls": tool_call_dicts,
}
)
# Execute tools
for tool_call in response.tool_calls:
args_str = json.dumps(tool_call.arguments, ensure_ascii=False)
logger.debug("Subagent [{}] executing: {} with arguments: {}", task_id, tool_call.name, args_str)
logger.debug(
"Subagent [{}] executing: {} with arguments: {}",
task_id,
tool_call.name,
args_str,
)
result = await tools.execute(tool_call.name, tool_call.arguments)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": tool_call.name,
"content": result,
})
messages.append(
{
"role": "tool",
"tool_call_id": tool_call.id,
"name": tool_call.name,
"content": result,
}
)
else:
final_result = response.content
break
@@ -207,15 +217,18 @@ Summarize this naturally for the user. Keep it brief (1-2 sentences). Do not men
)
await self.bus.publish_inbound(msg)
logger.debug("Subagent [{}] announced result to {}:{}", task_id, origin['channel'], origin['chat_id'])
logger.debug(
"Subagent [{}] announced result to {}:{}", task_id, origin["channel"], origin["chat_id"]
)
def _build_subagent_prompt(self) -> str:
"""Build a focused system prompt for the subagent."""
from nanobot.agent.context import ContextBuilder
from nanobot.agent.skills import SkillsLoader
time_ctx = ContextBuilder._build_runtime_context(None, None)
parts = [f"""# Subagent
parts = [
f"""# Subagent
{time_ctx}
@@ -223,18 +236,24 @@ You are a subagent spawned by the main agent to complete a specific task.
Stay focused on the assigned task. Your final response will be reported back to the main agent.
## Workspace
{self.workspace}"""]
{self.workspace}"""
]
skills_summary = SkillsLoader(self.workspace).build_skills_summary()
if skills_summary:
parts.append(f"## Skills\n\nRead SKILL.md with read_file to use a skill.\n\n{skills_summary}")
parts.append(
f"## Skills\n\nRead SKILL.md with read_file to use a skill.\n\n{skills_summary}"
)
return "\n\n".join(parts)
async def cancel_by_session(self, session_key: str) -> int:
"""Cancel all subagents for the given session. Returns count cancelled."""
tasks = [self._running_tasks[tid] for tid in self._session_tasks.get(session_key, [])
if tid in self._running_tasks and not self._running_tasks[tid].done()]
tasks = [
self._running_tasks[tid]
for tid in self._session_tasks.get(session_key, [])
if tid in self._running_tasks and not self._running_tasks[tid].done()
]
for t in tasks:
t.cancel()
if tasks: