02.3 工具执行与状态传播
关注源码
src/services/tools/toolOrchestration.tssrc/services/tools/StreamingToolExecutor.tssrc/services/tools/toolExecution.tssrc/state/AppStateStore.tssrc/state/onChangeAppState.ts
工具执行的三层结构
1. toolExecution.ts 负责单次工具调用生命周期
单次 tool use 内部会处理:
- 输入校验
- hooks
- permission decision
- telemetry span
- progress message
- tool result block 规范化
- 持久化与 budget 裁剪
它是真正的“工具调用内核”。
2. toolOrchestration.ts 负责批次编排
这一层按 isConcurrencySafe() 把工具调用分批:
- 可并发读类工具可以一批执行
- 非并发安全工具串行执行
- 并发批次里的 context modifier 延后统一提交
这个策略的重点不是极致性能,而是避免共享状态竞争。
3. StreamingToolExecutor.ts 负责边流边执行
当模型边生成边产出 tool use 时,StreamingToolExecutor 可以:
- 尽早启动已到达的工具
- 维持结果按原始顺序输出
- 在 streaming fallback、兄弟工具错误、用户中断时生成 synthetic error blocks
这是流式体验和执行安全之间的折中层。
AppState 承载什么
AppStateStore.ts 显示,前台状态至少包括这些域:
tasksmcppluginsnotificationselicitationtodospromptSuggestion/speculation- permission / footer / panel / teammate 视图
它不是一个轻量的“组件状态容器”,而是交互式会话的运行时镜像。
状态传播路径
一轮工具调用通常会经历:
- query loop 发现 tool use
toolExecution.ts做 permission/hooks/check- 结果写回消息流
- 可能更新
ToolUseContext - 可能更新
AppState onChangeAppState.ts将关键变更同步到 settings / CCR / SDK metadata
其中最重要的不是 UI 更新,而是“工具执行可以反向改写运行时”。
为什么 onChangeAppState 很重要
它把多个散落的状态副作用集中到了一个 choke point,例如:
- permission mode 改变后通知 CCR
- model 改变后写回 settings
- settings.env 变化后重新应用环境变量
这避免了每个交互入口都各自记一份同步逻辑。
设计上的关键点
1. 工具执行不是黑盒 RPC
它是由 hooks、permissions、telemetry、storage、UI 共同参与的有状态生命周期。
2. 并发策略偏保守
默认不并发,只有明确声明安全才批处理。对代码代理来说,这个选择比“理论吞吐更高”更合理。
3. 状态和副作用被分层
- 工具执行内核处理单次生命周期
- 编排层处理批次和顺序
AppState承载前台会话状态onChangeAppState负责系统级同步