OpenCode:工具调用为何有自己的状态?
源码范围:官方仓库
anomalyco/opencode@18ef3cc7c5a25b82114c953a80ccc09f4988f74e,仅核对本页涉及的packages/opencode/src/session路径。本文是静态源码阅读,不是运行实测。
核心问题
Agent 的一次工具调用并非只有“模型要求调用”和“工具返回”两个瞬间。OpenCode 在 assistant message 下维护 ToolPart:输入相关流事件可先建立 pending;收到完整 tool-call 时转为 running;匹配且处于 running 的调用收到成功或错误结果时,分别成为 completed 或 error。清理阶段也会把仍未收束的调用记为中断 error,这是另一条路径;不能把所有 tool-error 概括为无条件更新。创建 · 运行 · 收束 · 清理
这给阅读运行轨迹提供了一个比“Agent 正在忙”更细的单位:每个工具调用通过 callID 对应一个 part,并保留输入、输出或错误与起止时间。它和 Session 层的 busy / retry / idle 是两个不同的观察层,后者由 SessionStatus 发布状态事件。ToolPart 状态 · SessionStatus
一次执行如何接上这条状态机
SessionPrompt.prompt() 记录用户消息后进入 loop();runLoop() 读取会话消息、选择 agent/model、解析可用工具,再把消息与工具交给 SessionProcessor.process()。入口 · 循环 · 处理器调用
SessionTools.resolve() 组装工具;在工具执行包装层,tool.execute.before 插件钩子、真实 item.execute、tool.execute.after 按此顺序出现。工具执行结果随后作为流事件进入处理器的 tool-result 分支,收束 ToolPart。这个描述限于已读到的工具注册与处理器代码,不代表所有 provider 都以完全相同的事件时序实现。工具包装 · 结果事件
这篇没有证明什么
- 没有启动 OpenCode、抓取真实事件日志或做中断/重试故障注入;图中状态转换是代码分支,不是实测轨迹。
- 没有审计所有 provider、MCP 工具和插件实现;不推断所有调用都必经相同细节。
- 本图不讲持久化数据库、上下文压缩、子 Agent 或完整插件/Skill 体系;它们需要独立章节及证据。
下一步宜以一次真实工具调用的事件日志核对 pending → running → completed/error 的可见顺序,再单独绘制会话级 busy/retry/idle 与调用级状态的关系。
图的文字说明 · opencode-tool-state
图从上向下读一条工具调用,以 callID 为线索:输入相关流事件可让 SessionProcessor.ensureToolCall 创建或复用 ToolPart.pending;完整 tool-call 事件把它推进至 running;匹配且处于 running 的调用收到成功 tool-result 时进入 completed,收到错误结果或 tool-error 时进入 error。右侧虚线表示清理阶段可把未收束的 pending 直接标为 error;尚未收束的 running 也可由清理进入 error,并写入 interrupted: true。因此不能断言所有错误都经过正常的结果事件,也不能断言每个错误事件都更新了一个 part。completed 与 error 是两个终点,不是串行步骤。每个状态变更通过会话服务更新 part。
底部单独标出 session 层 busy / retry / idle:它是 SessionStatus 发布的状态,不表示三个必经步骤,也不能把 idle 当成某个 ToolPart 的完成状态。retry 来自模型流处理外层的 SessionRetry.policy:只有策略判为可重试且未超过次数上限时才发布,带尝试次数与下次尝试时间;单个 ToolPart 进入 error 不自动触发这个状态。工具执行包装中的 tool.execute.before → item.execute → tool.execute.after 放在图下作为代码路径说明,不画成另一条 ToolPart 状态箭头。完整证据定位 · 重试策略源码
图是固定源码版本 18ef3cc7c5a25b82114c953a80ccc09f4988f74e 的静态机制图;未运行真实请求、未覆盖 provider 差异、中断恢复和持久化故障。视觉布局故意采用状态机而非 Pi 的分区卡片:此图回答“一个对象如何变状态”,不是“系统有哪些层”。
在线预览稿:书稿仍在校稿,系统篇以文内固定源码版本为准;静态阅读不等于运行验收。