feat(agent): 实现委派工具重构,支持子代理和代理团队模式
- 新增 spawn_subagent 和 spawn_agent_team 工具,替代原有的 spawn 工具 - 重构 DelegationManager 以支持单个子代理和代理团队两种委派模式 - 更新系统提示词中的委派策略说明,明确使用场景和区别 - 添加技能上下文传递功能,确保委派任务遵循指定技能 - 实现代理内部的受控下游委派机制,防止无限嵌套 - 更新工具注册和上下文设置逻辑以适配新架构
This commit is contained in:
@ -19,10 +19,12 @@ from nanobot.agent.run_result import AgentRunResult
|
||||
from nanobot.agent.tools.filesystem import EditFileTool, ListDirTool, ReadFileTool, WriteFileTool
|
||||
from nanobot.agent.tools.registry import ToolRegistry
|
||||
from nanobot.agent.tools.shell import ExecTool
|
||||
from nanobot.agent.tools.spawn import NestedDelegateTool
|
||||
from nanobot.agent.tools.web import WebFetchTool, WebSearchTool
|
||||
from nanobot.providers.base import LLMProvider
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from nanobot.agent.delegation import DelegationManager
|
||||
from nanobot.config.schema import ExecToolConfig
|
||||
|
||||
|
||||
@ -51,6 +53,11 @@ class SubagentManager:
|
||||
self.brave_api_key = brave_api_key
|
||||
self.exec_config = exec_config or ExecToolConfig()
|
||||
self.restrict_to_workspace = restrict_to_workspace
|
||||
self._nested_delegate: DelegationManager | None = None
|
||||
|
||||
def set_nested_delegate(self, manager: "DelegationManager | None") -> None:
|
||||
"""注入 delegated worker 可用的受控下游委派器。"""
|
||||
self._nested_delegate = manager
|
||||
|
||||
async def run_local_task(
|
||||
self,
|
||||
@ -61,14 +68,22 @@ class SubagentManager:
|
||||
system_prompt: str | None = None,
|
||||
model: str | None = None,
|
||||
progress_callback: Callable[..., Awaitable[None]] | None = None,
|
||||
allow_nested_delegation: bool = True,
|
||||
skill_context: str = "",
|
||||
skill_names: list[str] | None = None,
|
||||
) -> AgentRunResult:
|
||||
"""执行一次本地委派任务,并返回结构化结果。"""
|
||||
# 每次任务都新建一套局部工具注册表,避免不同任务之间共享临时状态。
|
||||
tools = self._build_local_tools()
|
||||
tools = self._build_local_tools(
|
||||
allow_nested_delegation=allow_nested_delegation,
|
||||
skill_names=skill_names,
|
||||
)
|
||||
prompt = self._build_subagent_prompt(
|
||||
task,
|
||||
agent_name=agent_name,
|
||||
custom_system_prompt=system_prompt,
|
||||
allow_nested_delegation=allow_nested_delegation,
|
||||
skill_context=skill_context,
|
||||
)
|
||||
# 本地委派不共享主会话历史,只带“专用 system prompt + 当前任务”。
|
||||
messages: list[dict[str, Any]] = [
|
||||
@ -143,7 +158,12 @@ class SubagentManager:
|
||||
summary=final_result,
|
||||
)
|
||||
|
||||
def _build_local_tools(self) -> ToolRegistry:
|
||||
def _build_local_tools(
|
||||
self,
|
||||
*,
|
||||
allow_nested_delegation: bool,
|
||||
skill_names: list[str] | None = None,
|
||||
) -> ToolRegistry:
|
||||
"""构建本地委派可用的受限工具集。"""
|
||||
tools = ToolRegistry()
|
||||
allowed_dir = self.workspace if self.restrict_to_workspace else None
|
||||
@ -175,6 +195,8 @@ class SubagentManager:
|
||||
# 网络能力保持只读:搜索和抓取,不提供消息发送/再次委派等工具。
|
||||
tools.register(WebSearchTool(api_key=self.brave_api_key))
|
||||
tools.register(WebFetchTool())
|
||||
if allow_nested_delegation and self._nested_delegate is not None:
|
||||
tools.register(NestedDelegateTool(manager=self._nested_delegate, default_skills=skill_names))
|
||||
return tools
|
||||
|
||||
@staticmethod
|
||||
@ -201,12 +223,46 @@ class SubagentManager:
|
||||
task: str,
|
||||
agent_name: str = "Local Subagent",
|
||||
custom_system_prompt: str | None = None,
|
||||
allow_nested_delegation: bool = True,
|
||||
skill_context: str = "",
|
||||
) -> str:
|
||||
"""构建子代理专用 system prompt。"""
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)")
|
||||
tz = _time.strftime("%Z") or "UTC"
|
||||
# plugin agent 的自定义系统提示拼到末尾,保留通用约束,再叠加个性化指令。
|
||||
extra = f"\n\n## Agent Instructions\n{custom_system_prompt.strip()}" if custom_system_prompt else ""
|
||||
can_do_lines = [
|
||||
"- Read and write files in the workspace",
|
||||
"- Execute shell commands",
|
||||
"- Search the web and fetch web pages",
|
||||
"- Complete the task thoroughly",
|
||||
]
|
||||
cannot_do_lines = [
|
||||
"- Send messages directly to users (no message tool available)",
|
||||
"- Access the main agent's conversation history",
|
||||
]
|
||||
delegation_section = (
|
||||
"\n## Downstream Delegation\n"
|
||||
"- Do not delegate further. Complete the task yourself with the tools you have."
|
||||
)
|
||||
if allow_nested_delegation and self._nested_delegate is not None:
|
||||
can_do_lines.append(
|
||||
"- Use `delegate_task` for controlled downstream delegation when specialized help is required"
|
||||
)
|
||||
cannot_do_lines.append("- Do not start agent teams or use background delegation tools")
|
||||
nested_summary = self._nested_delegate.build_nested_agents_summary()
|
||||
summary_block = f"\n\n{nested_summary}" if nested_summary else ""
|
||||
delegation_section = (
|
||||
"\n## Downstream Delegation\n"
|
||||
"- Use `delegate_task` only when a specialized downstream worker is actually needed.\n"
|
||||
"- `strategy=\"a2a\"` delegates directly to an available A2A agent.\n"
|
||||
"- `strategy=\"ephemeral_subagent\"` runs a temporary local worker for this task only.\n"
|
||||
"- Never create, register, or persist a new local sub-agent through `subagentctl.py`, `/api/subagents`, or registry edits."
|
||||
f"{summary_block}"
|
||||
)
|
||||
else:
|
||||
cannot_do_lines.append("- Spawn other subagents or downstream workers")
|
||||
skill_section = f"\n## Required Skills\n{skill_context.strip()}" if skill_context.strip() else ""
|
||||
|
||||
return f"""# {agent_name}
|
||||
|
||||
@ -220,17 +276,17 @@ You are a delegated agent spawned by the main agent to complete a specific task.
|
||||
2. Your final response will be reported back to the main agent
|
||||
3. Do not initiate conversations or take on side tasks
|
||||
4. Be concise but informative in your findings
|
||||
5. Do not create or modify persistent local sub-agents unless the task explicitly requires that workflow
|
||||
|
||||
## What You Can Do
|
||||
- Read and write files in the workspace
|
||||
- Execute shell commands
|
||||
- Search the web and fetch web pages
|
||||
- Complete the task thoroughly
|
||||
{chr(10).join(can_do_lines)}
|
||||
|
||||
## What You Cannot Do
|
||||
- Send messages directly to users (no message tool available)
|
||||
- Spawn other subagents
|
||||
- Access the main agent's conversation history
|
||||
{chr(10).join(cannot_do_lines)}
|
||||
|
||||
{delegation_section}
|
||||
|
||||
{skill_section}
|
||||
|
||||
## Workspace
|
||||
Your workspace is at: {self.workspace}
|
||||
|
||||
Reference in New Issue
Block a user