Harness Engineering

这里的 harness 指 Codex 给模型动作套上的执行外壳。模型可以提出“运行命令、改文件、调用 MCP、请求权限、生成图片、spawn agent”等动作,但每个动作都必须穿过同一套工程边界。

Harness Engineering

工具注册:ToolRegistry

ToolRegistry 位于 codex-rs/core/src/tools/registry.rs。它负责:

  • ToolName 保存 CoreToolRuntime
  • 检查工具是否支持并发。
  • 创建 streamed argument diff consumer。
  • 执行 pre-tool-use hook。
  • 调用真正的 handler。
  • 执行 post-tool-use hook。
  • 发送 tool start/finish lifecycle。
  • 记录工具遥测和 dispatch trace。

CoreToolRuntime 继承 ToolExecutor<ToolInvocation>,但又补充了 Codex 核心需要的能力:hook payload、telemetry tags、argument diff、取消等待策略等。

工具规划:ToolRouter

ToolRouter 把模型输出的 ResponseItem 转成内部 ToolCall,并把 tool call 分发给 registry。它还持有本次 turn 的 model_visible_specs

源码入口:

  • codex-rs/core/src/tools/router.rs
  • codex-rs/core/src/tools/spec_plan.rs

spec_plan.rs 很关键:它不是简单列出所有工具,而是根据 turn context、MCP 工具、deferred MCP 工具、extension tools、dynamic tools、code mode、multi-agent 版本等条件构建“本轮可见工具集”。

执行编排:ToolOrchestrator

ToolOrchestrator 位于 codex-rs/core/src/tools/orchestrator.rs,文件注释已经把流程概括成:

  1. approval
  2. select sandbox
  3. attempt
  4. retry with escalated sandbox strategy on denial

它统一处理:

  • AskForApproval 策略。
  • Guardian 自动 review。
  • PermissionRequest hook。
  • 文件系统 sandbox policy。
  • network sandbox policy。
  • managed network approval。
  • sandbox denied 后是否可升级重试。
  • sandbox outcome 遥测。

这个设计的好处是工具 handler 不需要各自实现审批和沙箱语义,减少安全策略分叉。

并发与取消:ToolCallRuntime

codex-rs/core/src/tools/parallel.rs 负责工具并发:

  • 支持并发的工具走读锁。
  • 不支持并发的工具走写锁。
  • 用户取消时根据工具声明决定是否等待 runtime 清理。
  • 取消后生成模型可见的 aborted tool output。
  • 避免 tool finish 和 abort finish 重复上报。

这让“多个工具并行”和“用户中断”同时可控,而不是散落在每个工具实现里。

Hook 的位置

工具执行路径里有三类 hook 特别重要:

  • PreToolUse:可阻止工具执行,或改写 tool input。
  • PostToolUse:可阻止工具结果返回模型,或替换模型可见反馈。
  • PermissionRequest:可自动允许或拒绝审批请求。

hook 不是 UI 装饰,而是执行 harness 的一部分。

可学习的设计

Codex 的 harness engineering 值得学习的地方在于,它承认模型输出是不可信的执行计划,因此把每个计划都放进一个可审计管道:

  • 模型只提出动作。
  • registry 校验工具名和 payload。
  • hook 可以检查或改写。
  • orchestrator 决定审批和沙箱。
  • runtime 处理并发、取消和结果。
  • event/telemetry 记录全过程。