☰
opencodex 的 Claude Code 入站加固实战:思考签名往返、错误分类对齐与发布门控(Phase 4)
2026/9/25 2:45:27 网站建设 项目流程

【免费下载链接】opencodex

Universal 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
点击查看免费下载

/v1/messages入站通道让 Claude Code 与 Codex 共享同一套 provider 栈(OAuth 池、路由、密钥故障转移、视觉/联网 sidecar),而本篇所基于的 040_phase4_hardening.md 正是该系列的收尾加固与发布阶段:关闭前三个 Phase 遗留的协议保真差距、为入站流量打上可观测性标签、弃用历史代理 ccs-wrapper 并完成一次带文档/变更日志的发布。读完本文,你将掌握 opencodex 在 Claude Code 入向上如何处理思考块签名往返、如何把上游错误映射为 Anthropic 错误分类法、如何验证取消/心跳/非流式等协议边界,以及整个加固周期的测试门控与发布纪律。

一、Phase 4 在整个 Claude Code inbound 单元中的定位

本系列(见 000_plan.md)按四个 PABCD 周期推进,每个周期一份 P 文档:

Phase主题工作类
Phase 1核心入站/v1/messages+count_tokens(010_phase1_core_inbound.md)C3
Phase 2ocx claude启动器 + 网关模型发现/别名C2-C3
Phase 3GUI "Claude Code" 区块 + docs-site/README(多语言)C2
Phase 4加固(思考回放、错误对齐、协议边界、可观测性)+ ccs-wrapper 弃用 + 发布C3-C4

Phase 4 的 Objective 一句话概括:关闭 Phase 1-3 延期的保真缺口,把新暴露面在可观测性中打标签,弃用 ccs-wrapper,并携带文档/变更日志发布一个版本。它的五个 Workstream 分别是:思考往返策略、错误形状对齐、协议边界、可观测性与文档真实性、弃用与发布——本文按此骨架展开。

二、Workstream 1:思考(thinking)往返策略与 ocxr1 签名信封

2.1 问题背景

Phase 1 落地后,思考(thinking)流被无签名地转发给 Claude Code;当 Claude Code 把上一轮的thinking/redacted_thinking块回放给入站时,这些块被直接丢弃。这在多数路由场景下是可接受的(Claude Code 客户端本身不做签名密码学校验),但对 Anthropic 系(anthropic-family)路由 provider 而言,带签名的思考回放是硬性协议要求:Anthropic 要求上一轮助手消息的 thinking/redacted_thinking 块必须带原签名逐字回放,否则会收到400 Expected "thinking" or "redacted_thinking", but found "tool_use"。

2.2 复用 ocxr1 reasoning-envelope 机制

040 给出的加固方向是:当 ROUTED provider 属于 anthropic-family 时,复用现有 reasoning-envelope.ts 的ocxr1信封机制与 bridge 签名捕获能力,让带签名的思考以与 Codex 回放相同的方式存活于 Claude Code 回放。

ocxr1信封的核心设计(源码级证据):

  • 前缀常量OCX_REASONING_PREFIX = "ocxr1:"(reasoning-envelope.ts);
  • 信封体为ocxr1:+ base64(JSON),JSON 内可携带四个字段(ReasoningEnvelope 定义):
    • sig:Anthropic 思考块签名(signature_delta捕获值);
    • red:原始redacted_thinking块数据负载(保序);
    • txt:被隐藏的思考文本——签名签署的就是这段原文,即使可见摘要被抑制,回放仍需要它;
    • krc:Kiro 系模型的 KMS 加密推理 blob(reasoningContentEvent),对代理不透明,但与签名一样需跨轮往返;
  • encodeReasoningEnvelope(L41)与decodeReasoningEnvelope(L97)都在 TranslatorBudget 预算约束下工作,防止不可信的 base64 载荷造成内存膨胀;解码器对非ocxr1:前缀的 OpenAI 原生加密 blob 原样放行。

2.3 决策门:demonstrate-or-document,拒绝投机建设

040 明确规定了一个决策门:只有当真实故障被演示(工具调用回合在回放时出现 400)才构建 Anthropic-family 签名回放;否则就把"回放思考丢弃"记录为预期行为(intended policy)。这是整个 Workstream 1 的风险控制核心——签名回放可能膨胀,必须时间盒化。

从 050_close.md 的处置记录看,最终落地的是 v1 策略:

  • 出站:为 thinking 块先发thinking_delta,再在content_block_stop前发一个合成signature_delta(CCR 先例,E6 证据:Claude Code 接受合成签名、不做客户端密码学校验);
  • 入站:回放的 thinking/redacted_thinking 块仍被丢弃;
  • Anthropic-family 签名回放未构建——040 的决策门保持成立。

不过,入站翻译器已经预埋了 ocxr1 的处理路径:在 inbound.ts 的thinking块翻译中,若收到的 signature 以ocxr1:开头,会先尝试decodeReasoningEnvelope解码——解码失败抛AnthropicRequestError("malformed ocxr1 reasoning signature");若信封内携带了sig(即试图把 OpenCodex 的推理连续性伪装成 Anthropic 签名)则直接拒绝,防止跨协议的签名伪造;普通(非信封)签名则会被重新包进{sig}信封随推理项继续跨轮往返。出站侧在 outbound.ts 的思考块闭合逻辑中,优先使用捕获到的真实签名,否则退化为ocxr1:{txt}兜底信封。

三、Workstream 2:错误形状对齐(error-shape parity)

3.1 Anthropic 错误分类表

040 要求把上游/OpenAI 错误类型映射为 Anthropic 错误分类法(invalid_request_error、authentication_error、permission_error、not_found_error、rate_limit_error、api_error、overloaded_error),并在 429/529 上保留Retry-After,表驱动、按状态逐一测试。该工作在实际实现中被提前到 Phase 1(010 修正第 4 条),并在 outbound.ts 的anthropicErrorType(status)中落地为完整官方表:

HTTP 状态Anthropic 错误类型
400invalid_request_error
401authentication_error
402billing_error
403permission_error
404not_found_error
409conflict_error
413request_too_large
429rate_limit_error
504timeout_error
529overloaded_error
其余 5xx / 其余 4xxapi_error/invalid_request_error

anthropicErrorBody(status, message, type?, code?)统一产出{type:"error", error:{type, message, code?}}形状(L73-L75),anthropicErrorResponse将其包装为标准 JSON Response(L77-L82)。

3.2 瞬时 5xx 重分类为 529 overloaded_error

这是最容易踩坑的一处:Anthropic SDK 客户端对api_error(5xx 兜底)会直接判定致命错误,而对overloaded_error(529)会启用内置退避重试。因此 outbound 状态机(L397-L435)对上游派生的瞬时状态(isTransientUpstreamStatus判定,见 upstream-retry.ts)强制映射为overloaded_error,而代理内部异常保持api_error——确定性 bug 不能被伪装成可重试错误。

同样的原则贯穿整个入站错误链路(claude-messages.ts):

  • 非 2xx 响应先解析上游 body 文本提取真实 message,再重塑为 Anthropic 信封;
  • Retry-After解析链:上游头 →resolveClientRetryAfter→ 兜底"2"(瞬时 5xx 或可重试 429 且上游未带头时);
  • 瞬时 5xx 出站状态改写为529,请求日志保留上游真实状态码(日志=上游真相,客户端=重试信号);
  • 显式Retry-After: "0"会被保留(合法的即时重试指令,优于兜底"2")。

对应测试见 claude-529-mapping.test.ts,且 050 处置表确认"错误分类法 + retry-after 透传 + Anthropic 形状的 auth/origin 拒绝"全部在 WP2 交付。

3.3 auth/origin 拒绝也使用 Anthropic 形状

requireApiAuth/origin 拒绝在/v1/messages*路由上从第一天起就复用这套错误信封(010 修正第 4 条)。一个具体例子:claudeCode.enabled: false时返回403 permission_error(claude-messages.ts);Desktop 模型映射不可用返回503 api_error带Retry-After: 1(L122-L126)。

四、Workstream 3:协议边界(protocol edges)

4.1anthropic-beta头与?beta=true:忽略安全

Claude Code 会向POST /v1/messages?beta=true发请求,并携带anthropic-beta(CSV 值)与anthropic-version(当前2023-06-01)头。040 要求确认这些可安全忽略:路由按url.pathname匹配(查询串被忽略,证据 G9);anthropic-version与anthropic-beta按原样转发/接受,beta 值视为开放列表(G12);未知 beta 请求仅在首次出现时记录一次。x-api-key准入与 CORS allow-headers 中也加入了X-Api-Key, Anthropic-Version, Anthropic-Beta(010 修正第 9 条)。

4.2count_tokens保真:估计值 vs provider 报告值

入站count_tokens走字符估计路径:estimateTokens 基于charsPerToken(modelId)(按模型分档的字符/Token 比率)。040 要求对比估计值与 provider 报告的input_tokens,若漂移 >2x 则调整charsPerToken选择。

实际实现已对最大的失真源做了修正:estimateClaudeRequestTokens 对协议内容位置(消息 content 块、tool_result.content嵌套块)中的 base64 附件(image/document)按有界逐附件估算——能嗅探图片尺寸时按max(256, ceil(w*h/750))(Anthropic 图片计价约 pixels/750),否则按解码字节数/512,下限 256。原因写在注释里:一张 2MB 截图约 270 万 base64 字符,若按纯字符/Token 比率计算会虚报成几十万 Token(真实成本约 1.6k),直接击穿 >2x 漂移上界。tool_use.input与工具 schema 中的 attachment 形状 JSON 不在此列——那些字节会被序列化进 function_call 参数/工具定义发给路由 provider,必须继续按文本计数。

4.3 取消传播:客户端断开 → 上游中止

040 要求客户端断开必须通过 SSE 变换传播为内部请求中止,并验证中途杀流不泄漏上游连接。实现证据:入站以abortSignal: req.signal传入handleResponses(claude-messages.ts);outbound SSE 变换器的cancel(reason)钩子(outbound.ts)置cancelled = true、释放所有 retained 预算与 thinking 缓冲、清理 ping 定时器,并向上游reader.cancel(reason)传播。050 处置记录确认"取消通过abortSignal: req.signal+ streamcancel()传播"已交付。

4.4 Stall 行为:心跳 → ping,维持 Claude Code 的空闲计时器

桥接心跳转换为 Anthropicping事件,防止 Claude Code 的空闲超时误杀长思考回合。具体机制:

  • outbound 变换器内置pingIntervalMs(默认 20000,outbound.ts),定时发射 transport-onlyping;
  • 语义帧(message_start → content_block_* → message_delta → message_stop)中允许ping出现在任意位置(包括 message_start 之前)——证据 G 系列已钉死这一契约;
  • response.heartbeat帧直接转发为ping(L451-L452)。

040 的验证手段是人工 60s stall fixture:在 60 秒无输出的上游上确认 ping 持续、Claude Code 不判定空闲超时。

4.5 非流式原生透传边界:决策与实现

040 提出问题:claude inbound → 原生 gpt 模型、stream:false的边缘——支持还是显式 400 带指引?最终决策是支持(050:non-stream native passthrough JSON fallback — all shipped)。实现分两层:

  • 路由 provider:routed adapters 不支持非流式内部回合,因此内部回放总是stream:true,非流式客户端通过collectAnthropicMessage把翻译后的 Anthropic SSE 折叠为 message JSON(outbound.ts,语义帧聚合、error 帧权威优先、tool 参数 JSON 拼接后解析);
  • 原生 Anthropic 透传:当 Claude Code 以订阅模式只设ANTHROPIC_BASE_URL、携带真实 claude.ai OAuth Bearer,且请求的是无别名/无 modelMap 认领的真 claude/anthropic 模型时,请求逐字转发到 api.anthropic.com(claude-messages.ts),beta/思考签名/计费身份保持原生。

另外注意 EOF 边界:上游在 terminal 帧前关闭流被判定为截断而非成功,变换器以502+overloaded_error的 Anthropic 错误帧 fail-closed(L830-L834),让客户端可以重试——这正是 040 要求的"协议正确性优先于礼貌关闭"的取舍。

五、Workstream 4:可观测性与文档真实性

5.1surface="claude"请求日志标签

040 要求/v1/messages的请求日志行打标签(如surface="claude"),使 Logs/Usage 可过滤。源码中该标签已实现:logCtx.surface = "claude"(claude-messages.ts),且当请求命中 Desktop 3P 别名时进一步细分为claude-desktop(L732-L735)。请求日志走常规 deferred-log 路径,model/provider 在路由后填充。040 中的"GUI Logs 增加过滤 chip(仅当 trivial 才做)"被记录为 follow-up、不阻塞发布。

5.2 docs-site troubleshooting 用真实错误文本

040 要求 troubleshooting 章节使用来自 Workstream 2 的真实错误文本。落地成果位于 docs-site/src/content/docs/guides/claude-code.md,涵盖:Did 0 searches(web_search_call 翻译成 server_tool_use 对)、sidecar 未激活(needsReauth排查)、connectors 禁用(shell 中误设ANTHROPIC_API_KEY)、/model选择器不显示模型(CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1与 gateway-models.json 缓存)、端口变更后环境陈旧、200k 上下文天花板与[1m]变体、bundled-skill 高 Token 占用(claudeCode.blockedSkills默认["claude-api"])、子代理路由到错误模型(<!-- ocx-route: -->指令)等。该文档同时同步翻译到 fr/ja/ko/ru/tr/zh-cn/zh-tw 七个语言目录。

六、Workstream 5:弃用与发布(C4 care)

6.1 ccs-wrapper 弃用

000_plan.md 已把 ccs-wrapper 定性为"前身而非基础":单文件 FastAPI 包装、模型别名过时、thinking 路由假流、当前未运行。040 要求在其 README 加横幅"superseded by opencodexocx claude"+ 指针,且不修改该仓库代码。按 050 记录,该弃用横幅因目标仓库不在本次单元范围内而被标记为 out of scope(separate repo, when touched next)。

6.2 发布流程

040 钉死的发布纪律:

  • 版本号 bump + CHANGELOG/release notes,遵循仓库约定release: vX.Y.Z提交;
  • 按 scripts/release.ts 的发布流执行 npm publish;
  • 干净 shell 上对npm i -g路径做冒烟。

scripts/release.ts 的用法签名(源码注释):bun scripts/release.ts <version> [--tag latest|preview] [--publish];版本 bump 提交/推送是真实的,Release workflow 的 publish 步骤默认 dry-run;--bump minor可从 tags + npm channels 解析下一个版本。发布前测试门包含npm pack与 bin smoke(040 测试计划第 4 条)。

七、测试计划与 Gate 标准(C 门)

040 为整个加固周期定义了明确的 C 门测试矩阵:

  1. 错误映射表测试:每一行分类法 +Retry-After透传;
  2. 取消测试:中止于流中段,断言上游中止 + 日志 finalize;
  3. Stall/ping fixture 测试:人工 60s 停顿 + 心跳;
  4. beta-header ignore 测试;
  5. 全量套件 + typecheck + GUI/docs 构建;发布前npm pack+ bin smoke。

Gate 标准三条(任何一条不满足不得退出):

  1. 所有 workstream 决策(尤其 Workstream 1 与 3 的非流式原生边界)带着证据而非假设记录在案;
  2. 全新 full-gate 运行绿色;发布产物核验;ccs-wrapper 横幅在其自有仓库提交;
  3. 发布后冒烟:干净机器/profile 上npm i -g @bitkyc08/opencodex && ocx claude完成一次路由回合。

050 记录的 gate 实证(2026-07-11 全新运行):bun test ./tests/2126 pass / 3 skip / 1 fail(该失败为 install-scripts 测试因 shell 无 node 的既有环境问题,分支改动前同样失败);bun x tsc --noEmitclean;GUI 与 docs-site build clean;Playwright 视觉 QA(含 ko 本地化、Claude ON 开关往返、9 条诚实 display_name 的别名列表)与 e2e 流式回合(mock openai-chat 上游 →/v1/messages?beta=true→ Anthropic SSE 序列断言)均通过。

八、风险与时间盒

040 明确列出两项风险,并给出对应纪律:

  • 签名回放可能膨胀(Workstream 1):时间盒化——demonstrate-or-document,不投机建设。这正是最终选择合成签名 v1 策略、把 signed replay 留到真实故障被演示的原因;
  • 发布 + 协议边界同周期过宽:若 Workstream 1-3 产生大 diff,按blast-radius 规则把发布拆成独立 mini-cycle。

九、落地结果与后续(来自 050 处置记录)

各 Workstream 最终状态(050_close.md):

Workstream状态
1. 思考往返v1 策略交付(合成signature_delta出站 + 回放思考丢弃);Anthropic-family 签名回放未构建——决策门保持
2. 错误对齐WP2 交付(分类法 + retry-after + Anthropic 形状 auth/origin 拒绝)
3. 协议边界?beta=true路径匹配、心跳→ping、EOF 无 terminal fail-closed、取消传播、非流式 JSON 回退全部交付
4. 可观测性日志行走常规 deferred-log 路径;surface="claude"标签 + Logs 过滤 chip 记为 follow-up
5. ccs-wrapper 横幅 + 发布按目标 out of scope(ccs-wrapper 仓库排除、未要求发布)

已登记的 follow-up(非阻塞):surface="claude"请求日志标签 + GUI Logs 过滤 chip;ocxr1 信封驱动的 Anthropic-family 签名回放(仅当真实回放失败被演示);count_tokens与 provider 报告input_tokens的实时漂移检查;ccs-wrapper 弃用横幅(下次触碰时)。同时,真实 Claude Code CLI 冒烟发现的三个线上 bug(role:"system"折叠为 instructions、max_output_tokens等采样参数在 openai-responses 路由上的剥离、占位 Bearer 不转发而注入主 codex 登录态)均已修复并留有回归测试。

至此,opencodex 的 Claude Code 入向通道完成了从"能用"到"协议保真、错误可诊断、发布可复现"的完整加固闭环——这正是 040 作为 C3-C4 发布面文档交付的核心价值。

【免费下载链接】opencodex

Universal 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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询