跟着 OpenCode 代码看一次 ToolPart 状态变化
返回 OpenCode 首页 · 固定源码 18ef3cc7
以下伪代码只压缩阅读顺序,不是原项目代码。OpenCode 的实现使用 Effect、流事件和会话服务;这里不把异步事件硬说成单一同步调用栈。
text
SessionPrompt.prompt(input)
保存用户消息 → loop / runLoop
选 agent 和 model → SessionTools.resolve → SessionProcessor.process
处理模型流事件:
tool-input-* → ensureToolCall(callID) → ToolPart.pending
tool-call → updateToolCall(callID) → ToolPart.running
tool-result(success) → completeToolCall(callID) → 若匹配 running part,则 completed
tool-result(error) / tool-error → failToolCall(callID) → 若匹配 running part,则 error
未收束调用 → cleanup() → ToolPart.error (interrupted)prompt()保存用户消息并调用loop()。后者借助SessionRunState.ensureRunning管理同一 session 的运行者;runLoop每轮读取历史和任务,按 agent/model 组装下一次模型请求。prompt · loop · runLoopSessionTools.resolve的工具包装会调用插件前置钩子、实际工具、后置钩子;SessionProcessor.process对llm.stream产生的事件执行handleEvent。这里的前后置钩子属于工具执行包装,并不等于ToolPart的三个状态。工具包装 · 流处理tool-input-start/delta/end都可调用ensureToolCall;该函数按callID复用已有 part,没有时写入pending,并建立callID → partID/messageID/sessionID的临时映射。输入事件 · ensureToolCalltool-call分支同样先确保 part 存在,再把它设为running、写入参数和开始时间。它也检查最近重复调用并可能要求doom_loop许可,所以“收到完整调用就必然成功执行”不是正确结论。tool-call 分支tool-result按结果类型分流;成功结果规范化后交给completeToolCall,为匹配的runningpart 写入completed、输出、元数据、附件及结束时间;错误结果或tool-error交给failToolCall,仅在匹配且仍为running时写error。权限拒绝等错误还可令处理器停止本轮。清理阶段等待未收束调用,仍存在的 part 会写成带interrupted: true的error,不能与正常结果分支混为一谈。结果分支 · 状态写入 · 清理SessionStatus另外维护 session 的当前状态并发布busy/retry/idle事件;进入idle时删除该 session 的状态表项,查询缺项默认返回idle。它不是工具状态机;一个 session 可以处于busy,其内部某个 ToolPart 仍在pending或running。SessionStatus · 处理器 busy/retry
最后一项中“可以”表示两套源码状态模型并存的结构性推断,不是运行时抓到的同时态。有关中断后的孤儿工具调用,runLoop 有显式清理标记检查;本篇不推断其所有边界结果。循环结束检查
在线预览稿:书稿仍在校稿,系统篇以文内固定源码版本为准;静态阅读不等于运行验收。