03.2 子智能体运行时

关注源码

  • src/tools/AgentTool/AgentTool.tsx
  • src/tools/AgentTool/runAgent.ts
  • src/utils/forkedAgent.ts
  • src/utils/agentContext.ts

AgentTool 做的事远超“再起一个模型调用”

AgentTool 要同时处理:

  • 选择 agent definition
  • 解析运行模式与隔离方式
  • 解析允许工具集
  • 创建子上下文
  • 选择同步、后台、worktree、remote 或 teammate 运行
  • 注册任务
  • 汇总结果、更新进度、发通知

所以它本质上是“多智能体运行时的桥接层”。

runAgent() 的核心作用

runAgent.ts 把一个 agent definition 变成可运行回合,主要负责:

  • 解析 agent 专属 system prompt
  • 解析 agent frontmatter 中的 MCP servers
  • 组装 agent 可见 commands / tools
  • 创建专属 transcript subdir
  • 调用通用 query()
  • 记录 sidechain transcript
  • 做 agent 生命周期清理

它并没有复制一套 query 逻辑,而是复用主循环。

forkedAgent.ts 决定了隔离边界

这个文件最关键的设计是“默认隔离,显式共享”。创建 subagent context 时,默认会:

  • clone readFileState
  • clone contentReplacementState
  • 为子 agent 创建自己的 abort controller
  • 让大部分父级 mutation callback 失效
  • 为后台 agent 设置 shouldAvoidPermissionPrompts

只有在显式 opt-in 时,才共享:

  • setAppState
  • setResponseLength
  • 父级 abort controller

这使后台 agent 不容易污染主线程状态。

cache-safe fork 是这层的隐含主线

forkedAgent.ts 里专门定义了 CacheSafeParams,强调以下参数必须与父请求保持一致:

  • systemPrompt
  • userContext
  • systemContext
  • toolUseContext
  • forkContextMessages

说明子智能体系统不是只追求“跑起来”,而是追求:

  • 共享 prompt cache
  • 复用父上下文前缀
  • 降低 fork 成本

agent 身份如何传播

utils/agentContext.ts 使用异步上下文传递 agent identity,而不是把 agent 身份硬塞进单一全局状态。这样可以在:

  • 多个后台 agent 并发
  • 远端与本地 agent 混跑
  • telemetry / hooks / logging 并发

时仍能正确归因。

典型子智能体路径

  1. AgentTool.call() 解析输入和 agent definition。
  2. 根据 run_in_backgroundisolation、team/worktree/remote 选择执行策略。
  3. runAgent() 组装 agent 专属上下文和工具池。
  4. 复用 query() 执行。
  5. 通过任务层或同步结果把输出送回主会话。

这层的设计结论

1. 子智能体不是特判分支,而是主运行时的 fork

这样主线程和子线程共享同一套:

  • prompt 语义
  • 工具契约
  • transcript 结构
  • 统计与 telemetry

2. 隔离边界是按状态能力切的,不只是按进程切

即使仍在同进程内,subagent 也可以通过 ToolUseContext 裁掉写回能力。

3. agent frontmatter 可以扩展平台面

runAgent.ts 支持 agent 自带 MCP server 定义,说明 agent 不只是 prompt 模板,也可以携带执行环境要求。