opencodex PR #46 深度解析:native passthrough SSE 的 usage 终结记录修复与脏树安全 Cherry-Pick 实践
【免费下载链接】opencodexUniversal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code项目地址: https://gitcode.com/gh_mirrors/ope/opencodex
导读:本文围绕 opencodex 仓库 devlog 中记录的 PR #46 合并计划 展开,剖析
fix(logs): finalize native passthrough SSE usage这一修复如何让原生透传(native passthrough)SSE 响应在缺少 Codex pool terminal recorder 的情况下依然能正确终结/api/logs与/api/usage,并完整还原一次"脏工作树 + 并发编辑"场景下的安全 cherry-pick 操作流程,以及一次 stash 误操作事故的完整恢复过程。读完本文,你将掌握 opencodex 中 terminal outcome 记录的门控逻辑、对应回归测试的验证方式,以及一套可复用的 Git 事故恢复方法论。
一、背景:为什么 native passthrough SSE 需要单独的 usage 终结修复
opencodex 作为 Universal provider proxy(为 OpenAI Codex 与 Claude Code 提供统一代理),在将上游 Responses API 的 SSE 流透传给客户端时,需要把流的最终状态(completed/failed/incomplete)回写进请求日志与用量统计。
在修复之前,native passthrough 路径的终结记录存在一个缺口:只有当terminalBodyWillRecord && recordTerminalOutcomes同时成立时,透传流的终态才会被记录。而terminalBodyWillRecord的定义(见 passthrough-delivery.ts)为:
const terminalRecorder = recordTerminalOutcome ? (status: ResponsesTerminalStatus, httpStatusOverride?: number): void => { if (terminalOutcomeRecorded) return; terminalOutcomeRecorded = true; recordTerminalOutcome(status, httpStatusOverride); } : undefined; const terminalBodyWillRecord = !!terminalRecorder && upstreamResponse.ok && isEventStream;它依赖terminalRecorder存在(即 Codex forward pool 的终端 outcome 记录器被挂载)。一旦请求没有经过 Codex pool 认证/记录链路(例如直接使用自定义 provider、openai-responsesadapter 单测等场景),terminalRecorder为空,整条终结记录链路就被静默跳过——请求日志/api/logs缺少 terminalStatus、usageStatus,/api/usage无法累加 token。这正是 devlog 中 issue_044_request-log-native-passthrough-gap 所追踪的缺口。
从源码结构看,该缺口与recordTerminalOutcomes的语义紧密相关:它在 core-options.ts 中定义为可选开关,默认在 response-effects.ts 中被解释为options.recordTerminalOutcomes !== false(即默认开启),而在 websocket-handler.ts 中则显式传入recordTerminalOutcomes: false——说明不同传输路径对终结记录的门控策略并不一致。
二、PR #46 核心变更:放宽门控 + 可选链
PR #46(单提交a0db10b,作者0disoft <rodisoft1@gmail.com>)对服务端入口(原计划中的src/server.ts,当前仓库该文件已重构拆分至 src/server/ 目录)做了最小改动(+2/-3):
- 门控条件放宽:将 native-passthrough 终结记录的判定从
terminalBodyWillRecord && recordTerminalOutcomes收窄为仅依赖recordTerminalOutcomes。含义是:只要请求上下文允许记录终端结果,即使没有 Codex pool 提供的terminalRecorder,也要让流正常终结/api/logs与 usage 统计。 - 可选链调用:对
terminalRecorder?.(status)使用 optional chaining,保证terminalRecorder为空时调用安全、不抛异常。
这一变更在 passthrough-delivery.ts 的 eager relay 分支中落地为reportNativeTerminal:
const reportNativeTerminal = recordTerminalOutcomes ? (status: ResponsesTerminalStatus, httpStatusOverride?: number) => { terminalRecorder?.(status, httpStatusOverride); if (status === "failed" || status === "incomplete") { const quotaFailureMessage = [httpStatusOverride, logCtx.terminalHttpStatus] .find(value => value === 429 || value === 402); if (!isFixedCodexAccount(admissionState.authCtx) && quotaFailureMessage !== undefined) { recordSubagentQuotaFailureForThreadSpawn(/* ... */); } } options.onNativePassthroughTerminal?.(status); } : undefined;可以看到,terminalRecorder?.(...)的调用已被可选链保护;即使记录器缺失,onNativePassthroughTerminal等副作用仍可执行,同时failed/incomplete状态下的 429/402 配额失败判定(recordSubagentQuotaFailureForThreadSpawn)也保留了下来。同样的terminalRecorder生命周期管理还出现在 core-combo.ts(声明)、core-combo.ts(通过setTerminalOutcomeRecorder注入)等路径中,PR #46 正是把"必须由 pool 提供 recorder"这一隐含前提从 native passthrough 路径上移除。
三、回归测试:一个 18 tokens 的 SSE 用例验证两个 API
PR #46 同步新增了 +81 行回归测试(位于 tests/server/server-auth.test.ts),用例名直接点明意图:"native passthrough SSE records completed usage without pool terminal tracking"(无 pool 终端跟踪时,native passthrough SSE 仍记录完成态用量)。
测试的搭建与断言逻辑:
- 构造上游 SSE:用
Bun.serve起一个本地上游,返回text/event-stream,内容仅含一个response.completed事件:
event: response.completed data: {"type":"response.completed","response":{"status":"completed","model":"gpt-5.5","usage":{"input_tokens":11,"output_tokens":7,"input_tokens_details":{"cached_tokens":3},"output_tokens_details":{"reasoning_tokens":2}}}}配置 opencodex:以
openai-responsesadapter、baseUrl指向该上游、allowPrivateNetwork: true、默认模型gpt-5.5启动服务,并 POST/v1/responses(stream: true)完成一次真实透传。断言
/api/logs:日志尾部记录应为status: 200、terminalStatus: "completed"、closeReason: "terminal"、usageStatus: "reported"、totalTokens: 18,且 usage 细分被正确解析(inputTokens: 11、outputTokens: 7、cachedInputTokens: 3、reasoningOutputTokens: 2)。断言
/api/usage:/api/usage?range=all&surface=codex返回requests: 1、reportedRequests: 1、totalTokens: 18,模型维度provider: "test-openai"、model: "gpt-5.5"累计一致;同时surface=claude的请求数为 0,确认统计归属 surface 隔离正确。
这个用例的验证价值在于:它完全绕开了 Codex pool 认证链路,直接证明透传流的终态记录不依赖terminalRecorder——即 PR #46 修复的目标场景。
四、脏树安全的 Cherry-Pick:隔离并发工作再合并
合并计划中最大的操作风险是:目标分支feat/kiro-on-dev工作树并不干净——一个并发 agent 正在编辑src/adapters/base.ts(+4 行)与src/adapters/kiro.ts(+8 行),这些未提交修改绝对不能被破坏。而git cherry-pick在脏工作树下会直接拒绝执行。
计划的解决策略(三步法):
- 隔离:
git stash push -- src/adapters/base.ts src/adapters/kiro.ts,只把并发 agent 的两个文件暂存起来(push -- <paths>形式只影响指定路径,这是与普通git stash的关键区别)。 - 合并:在干净工作树上
git cherry-pick a0db10b,自动保留原作者0disoft的署名(cherry-pick 天然保留 author,无需额外配置)。 - 恢复:
git stash pop还原并发工作,并确认 base.ts / kiro.ts 的编辑原样保留。
操作前提是文件无重叠:PR #46 只触及src/server.ts(+2/-3)与tests/server-auth.test.ts(+81),与并发 agent 的 base.ts / kiro.ts 编辑互不相交,因此 stash 隔离 + cherry-pick + pop 可以安全执行。
五、事故复盘:一条错误 flag 引发的 stash 误弹与恢复
计划执行中发生了一起值得记录的事故:执行者使用了一个格式错误的 flaggit stash push -u=false,导致后续出现一次杂散的git stash pop,误把一条无关的历史 stash(google-antigravity WIP)应用进了工作树,产生 7 个文件的 UU(unmerged)冲突。
恢复过程分为两步:
- 回滚冲突文件:对这 7 个 google-antigravity 文件执行
git checkout HEAD --恢复。由于这些内容仍安全保存在对应的 stash(stash@{0})中,回滚没有造成数据损失。 - 清理泄漏的未跟踪文件:误弹还带出了 2 个原本不应存在的未跟踪文件(
src/oauth/google-antigravity.ts、tests/google-antigravity.test.ts),将其移除并备份至/tmp/pr46_leaked_files,同时保留在 stash@{0} 中作为兜底。
最终确认:并发 agent 的工作零丢失——base.ts / kiro.ts 的编辑经 stash pop 以 3-way 自动合并干净恢复,无冲突。
这条事故给 Git 操作带来的实践要点:
git stash push的-u/--include-untracked是布尔开关,不要写成-u=false这种带值的错误形式,否则该 flag 可能被解析为其他含义,导致 push 行为与预期不符;- 在存在多个 stash 的环境中执行
git stash pop前,先git stash list确认目标; - 误弹造成的冲突文件可通过
git checkout HEAD -- <files>快速还原,只要对应 stash 未删除,数据就仍在恢复范围内; - 对泄漏的未跟踪文件,先备份再清理,保留一条可回退路径。
六、验证与验收结果
合并完成后按计划执行了完整验证:
- 测试:
bun test tests/server/server-auth.test.ts tests/request-log.test.ts tests/passthrough-abort.test.ts→57 pass / 0 fail,其中包含 PR #46 新增的 native-passthrough usage 用例; - 类型检查:
bun x tsc --noEmit→exit 0(合并提交与并发工作树叠加状态下均通过); - 提交审计:
git show确认 cherry-pick 产物只包含 server.ts 与测试文件,author 为0disoft;git status确认 pop 后 base.ts / kiro.ts 仍处于已修改状态(并发工作完好)。
最终 cherry-pick 落为提交2481c80,且与原计划中的并发编辑位置(server.ts:112/591/909)相比,PR #46 的改动点位于 server.ts:529,改动位置同样不相交,进一步降低了冲突概率。修复合并后,按计划在 issue #44 上同步了合并结果。
七、总结:一次"修复 + 流程"双重价值的技术合并
从技术层面看,PR #46 用两行门控调整解决了 native passthrough SSE 的用量统计缺口:把"是否有 pool recorder"与"是否记录终态"解耦,让透传流在任何认证形态下都能正确终结/api/logs与/api/usage,并以一个 18 tokens 的端到端用例锁定行为,后续还可在 server-auth.test.ts 中找到"caller abort 不惩罚 pool"(L4215)与"upstream reset 记录 502 并惩罚 pool"(L4256)等相邻回归用例,共同构成 native passthrough 终结语义的完整防线。
从工程流程层面看,这份 devlog 同时示范了多 agent 并发开发下的安全合并范式:路径级 stash 隔离 → cherry-pick → pop 还原,以及一次 stash 误操作从冲突到零丢失恢复的完整闭环。对于任何维护多人/多 agent 共享工作树、且需要保留外部贡献者署名的开源项目,这套操作流程都具备直接的可复制价值。
延伸阅读:感兴趣可继续查看 passthrough-delivery.ts(native passthrough 完整传输与终结逻辑)、core-options.ts(recordTerminalOutcomes开关定义)、response-effects.ts(默认值解释),以及 issue_044_request-log-native-passthrough-gap 中对该缺口的前置追踪。
【免费下载链接】opencodexUniversal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code项目地址: https://gitcode.com/gh_mirrors/ope/opencodex
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考