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