fix(subagent): avoid missing from_legacy call
This commit is contained in:
@@ -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,15 +99,17 @@ 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))
|
||||||
|
|
||||||
system_prompt = self._build_subagent_prompt()
|
system_prompt = self._build_subagent_prompt()
|
||||||
messages: list[dict[str, Any]] = [
|
messages: list[dict[str, Any]] = [
|
||||||
{"role": "system", "content": system_prompt},
|
{"role": "system", "content": system_prompt},
|
||||||
@@ -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,15 +217,18 @@ 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."""
|
||||||
from nanobot.agent.context import ContextBuilder
|
from nanobot.agent.context import ContextBuilder
|
||||||
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:
|
||||||
|
|||||||
Reference in New Issue
Block a user