问题所在
给 agent 挑一个 runtime,不管是 Claude、Codex 还是别的什么,这个选择就会开始到处泄露。主页上看得到,discovery 结果里看得到,CLI 每条列表都打在最前面。没过多久,大家就开始管你的 agent 叫"那个 Claude 的"和"那个 Codex 的"了。
这不对。调用方根本不在乎底下跑的是什么。他们只关心这个 agent 能不能把活干好。
我们改了什么
现在,runtime 除了 agent 的创建者,其他人都看不到。
对调用方来说,不管走 ah chat、ah call、A2A JSON-RPC 还是 Web UI,Claude-backed 和 Codex-backed 的 agent 长得完全一样。同一套接口,同一种流式格式,同样的 tool 事件。A2A 协议本来就没暴露过 runtime,现在我们也不暴露。
如果你是 agent 的创建者,什么都没变。注册的时候你依然可以挑 runtime:
ah agent quick my-agent --runtime-type codex
ah agent show 也还能看到里面用的是什么。这是你的实现细节,和别人没关系。
怎么做到的
daemon 里每个 runtime 都对应一个 profile:一层薄薄的适配器,知道怎么启动 CLI、传什么参数、怎么解析输出。
Claude Code 吐 stream-json,Codex 吐 JSONL。两边都会被归一化成同一套内部事件:chunk、tool_start、tool_result、done。事件离开 daemon 的时候,谁生产的已经完全不重要了。
接入新 runtime 只需要三样东西:一个 parser,一个 profile,一次注册。系统其余部分(sessions、bridge protocol、A2A、Web UI)压根不知道发生过这件事。
Codex 支持
Codex 现在是一等公民 runtime。底层跑的是 codex exec --json --full-auto,JSONL 输出会被映射成和 Claude 完全一致的事件流。Tool 调用(command_execution、file_edit)也会映射到标准的 tool_start 和 tool_result。
把现有 agent 的 runtime 换掉,调用方完全感知不到:
ah agent update my-agent --runtime-type codex
这带来了什么
一旦 runtime 不再是对外契约的一部分,你就可以真的玩起来了。
同一个 agent,Claude 和 Codex 并行跑,拿你自己的真实流量对比质量,不用再去看别人的 benchmark。便宜的请求走便宜的 runtime,贵的走贵的,调用方完全不用知道。某个 runtime 宕机,切就是了,你的用户依赖的 agent 不会跟着一起挂。
下一个重要的模型早晚会出现。等它来的时候,加进来就行,剩下的代码甚至不会察觉。
