【免费下载链接】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 中的 010 报告与 000 计划为主线完整还原了上游 PR #93、#94 通过 PABCD 循环 cherry-pick 到dev分支的工程过程在解析器层保持agent_message边界、在 sanitize 层对明文encrypted_content做预解析归一化、将明文 agent 消息规范化为普通用户消息。读完本文你将掌握 opencodex 多智能体sub-agent / 子任务消息在代理转发链路中的底层修复机制、PABCD 评审循环的运作方式以及对应的源码位置与测试验证方法。一、问题背景agent_message为什么会在路由链路上炸开在 opencodex 中多智能体协作依赖 OpenAI Codex 后端的一个私有输入项类型agent_message。它的职责是承载子代理sub-agent产生的回复、父代理派发的任务NEW_TASK以及相关的路由信封元数据。从 src/adapters/routed-agent-messages.ts 的源码注释可以确认关键事实agent_message只存在于 ChatGPT Codex 后端的 schema 中属于私有不公开类型Codex 会把每个子代理回复都重放进历史记录一旦某个线程使用过子代理后续请求体进入被路由的 Responses 目的端例如第三方模型提供商时对方会直接以422 unknown item type agent_message拒绝整个请求体且该线程后续所有轮次都会以同样方式失败。这正是 010_report.md 所记录的两个上游 PR 要解决的核心问题让私有agent_message在到达第三方提供商之前被安全地转换为公开的、可被解析的消息形态。二、两个上游 PR 的职责划分与 union 集成策略PR #93 与 #94 同源于 Wibias 贡献者两者的基线df29afd8恰好等于当前devHEADv2.7.7因此天然具备 cherry-pick 条件。从 000_plan.md 的 Context 一节可以看到两者的分工与重叠提交归属 PR职责fb6bd707#93解析器parser层agent_message边界处理 解析器测试64da27d3#93responses.ts中 sanitize-before-parse 预解析钩子 兼容性测试f29002de#94与64da27d3内容完全相同仅 SHA 不同 —— 被跳过749d3978#94sanitizer 层容器归一化明文agent_message→message、递归计数、额外测试断言评审结论是#93 是超集且结构上更安全的修复解析器级处理#94 的独有增量是 sanitizer 层的容器归一化。两者在responses.ts上有相同的 hunk在测试追加点有近乎相同的测试块因此存在文本冲突预期——但实际 cherry-pick 时被 A-gate 评审纠正了git merge-tree 64da27d3 f29002de 749d3978合并无冲突749d3978只修改现有测试块的注释并追加一条断言。最终集成策略是联合union规则两个机制都保留在responses.tsparser 分支 sanitizer 归一化测试块只保留一份采用 #94 含容器归一化断言的变体。三、PABCD 循环cherry-pick 的完整工程闭环报告的标题即点明本次操作的工作方式PABCD session cli通过cxc orchestrate运行P → A → B → C → D的完整评审-执行-验证循环涉及被签名边attested edges与 agent 门控 CLI。各阶段记录如下A gate评审GO-WITH-FIXESsol-high 评审员代号 Leibniz给出VERDICT GO-WITH-FIXES共 3 个 blockerBlocker 1纠正了原计划中文本冲突的错误预期见上文 merge-tree 验证Blocker 2被延期处理 —— 回归测试直接调用 sanitize-then-parse没有任何测试经过生产链路handleResponses的真实编排顺序详见下文残留风险Blocker 3纳入 000_plan.md即回滚流程规范。B 阶段执行精确提交sol-high 执行者代号 Plato只提交 4 个目标路径涉及的改动工作区中未提交的用户/并行单元文件15 个修改 3 个未跟踪文件被完整保留不做git add -A这是保护脏工作区的关键纪律。C 阶段验证测试与类型检查在全新分支上执行bun test tests/multi-agent-compat.test.ts tests/responses-parser-agent-message.test.ts bun run typecheck结果28 pass / 0 fail / 87 expects基线 26 pass即新增 2 个通过用例typecheck 退出码 0预解析 sanitize 钩子恰好触发一次src/server/responses.ts:442parser 的agent_message分支2 处引用与 sanitizer 归一化3 处引用共存。最终提交3 个提交落在dev上8852e50fPreserve agent_message boundariesPR #93来自fb6bd70750aa116asanitize plaintext encrypted_content before parsePR #93来自64da27d36131577dnormalize plaintext agent messages before parsingPR #94来自749d3978PR #94 的f29002de被跳过它与64da27d3的稳定 patch-id 相同ff961126...由 A-gate 评审通过git showmerge-tree双重验证避免重复落盘。四、源码机制深度解析三层防御如何协同本次修复在源码中形成了解析器边界 → 预解析 sanitize → 适配器归一化三层配合。以下均以当前仓库实际代码为准。4.1 解析器层agent_message作为 user 角色的边界消息核心实现在 src/responses/parser.ts。当输入项type agent_message时通过inputContentParts(agentMessage.content)提取内容保留有内容的部分清空挂起的推理块pendingReasoning.length 0将消息以role: user压入上下文消息列表内容为空时退化为占位文本(sub-agent message received)。该分支的注释解释了设计意图agent_message 是交付给父代理的外部输入必须保留为 user 角色轮次从而保证两侧的签名 Anthropic thinking 块永远不会被合并进同一条被修改的 assistant 响应中。这正是边界保持boundary preservation的含义。同时src/responses/parser.ts 在边界检测逻辑中把agent_message与function_call_output、普通 user/assistant 消息并列用于在previous_response_id续写场景下定位continuationConversationMessageIndex确保后续元数据始终排在对话内容之前。这一点在 tests/responses/responses-parser-agent-message.test.ts 中有完整的回归覆盖输入reasoning → agent_message → reasoning → function_call → function_call_output解析结果必须为[user, assistant, toolResult]三段——agent_message 之前的推理被丢弃边界无后续 assistant 承接之后的推理归属下一条 assistant。4.2 sanitize 层明文encrypted_content的预解析重写第二个修复点聚焦一个隐蔽缺陷子任务负载task payload被插件钩子以明文形式放进encrypted_content槽位如[CXC-LEAF-GUARD]前缀 明文指令。第三方提供商无法解密、无法识别导致空负载。核心函数sanitizeEncryptedContentInPlace位于 src/server/responses/encrypted-payload.ts实现要点迭代式遍历显式栈而非递归调用对 30,000 层深度的输入也不会栈溢出——对应 multi-agent-compat.test.ts 的深度测试用isStructurallyValidFernetTokenencrypted-payload.ts做密钥无关的 Fernet 线格式校验base64url 字母表、版本字节0x80、时间戳 8 字节 IV 16 字节 AES-CBC 密文16 的整数倍 HMAC 32 字节的规范长度。结构合法的后端密文保持逐字节不变pure Fernet slot stays byte-identical测试断言非 Fernet 的明文槽位被拆解为input_text部件encryptedSlotParts容器归一化一旦某个agent_message内部所有密文槽位都被重写为明文且不再残留encrypted_content该消息本身被改写为{ type: message, role: user }并删除id、author、recipient等私有字段encrypted-payload.ts。4.3 预解析钩子挂接点与双触发路径sanitize 被挂在RAW body 解析之前这是保证所有消费者都能看到负载的关键顺序。见 src/server/responses/request-prepare.ts位置在parseRequest(body)之前因此路由/翻译型提供商的解析器和native passthrough_rawBody原样序列化都能读到归一化后的内容首次调用预路由阶段使用preserveUnknownOpaqueSlots: true让编码外观未知的槽位保持不透明等到最终路由确定后再决定剥离或严格分类当最终路由是 Canonical OpenAI 转发提供商时会再次调用request-prepare.ts对非 Fernet 的encrypted_content做最终剥离。4.4 适配器层normalizeRoutedAgentMessages第三道防线在 src/adapters/routed-agent-messages.tsnormalizeRoutedAgentMessages把每个agent_message改写为{ type: message, role: user }并把author/recipient身份拼进input_text前缀Agent message {author:...}。值得注意的是其fail-closed 边界若 content 中包含真正的密文或未知部件类型非input_text/input_image/input_file函数拒绝改写交由加密 v2 任务面的unreadable_encrypted_agent_task与可选的恢复路由处理authMode: forward的提供商则完全不会进入该函数。五、验证体系回归测试如何锁定行为本次修复的验证由两组测试构成均已在当前仓库中落盘5.1 解析器边界测试tests/responses/responses-parser-agent-message.test.ts 验证agent_message 夹在两条 assistant 推理之间时前一段 reasoning 因边界无后续 assistant 承接而被清除agent_message 内容成为唯一的 user 消息后一段 reasoning 与 function_call 归属下一条 assistant 消息Responses 的 item id 不会被复制到thoughtSignatureAntigravity 会拒绝。5.2 sanitize 兼容性测试tests/codex-integration/multi-agent-compat.test.ts 覆盖六类场景明文槽位 → input_text、真密文原样保留[CXC-LEAF-GUARD]前缀场景非数组输入为 no-op返回 0深层嵌套不栈溢出30,000 层嵌套 agent_message 归一化内层重写后外层/内层都变为message/user且 rewrite 计数只计密文重写、不计归一化混合槽位[CXC-LEAF-GUARD]明文 嵌入 Fernet token 时拆成input_textencrypted_content两部分消息仍保持agent_message因为仍有密文残留不可归一化纯 Fernet 槽位逐字节不变。spawn-message delivery测试则完整模拟了handleResponses的顺序先对 RAW input 做 sanitize normalize再 parseRequest验证子代理的 NEW_TASK 任务负载能作为 user 消息交付到路由路径——这直接对应报告中的预解析 sanitize 钩子恰好触发一次。六、残留风险与后续跟进LOOP-UNIT-CHAIN-01 候选报告明确记录了三个残留项均为刻意决策而非遗漏【HighA-gate blocker 2 延期】生产链路集成测试缺口现有回归测试直接调用 sanitize-then-parse没有测试经过handleResponses的真实编排顺序。若未来预解析钩子被移动或移除现有测试仍会通过。处置延期为一个独立工作单元handleResponses路径集成测试需要 config/route mocking并记录在案以防丢失。上游 PR #93/#94 仍处于开放状态尚未决定是否在这些 dev 提交上评论/关闭上游 PR或让贡献者自行 rebase当前未推送。Native-wire 变异风险已接受#94 的归一化会把 passthrough 链路上的agent_message变异为message。该风险在 000_plan.md 的风险笔记中已论证归一化只会在明文驻留routed-parent mint时触发且 #93 的 parser 分支无论路由如何都已覆盖若后端多智能体记账出现回归需要回访复查。此外混合负载的边界行为值得特别注意当一个agent_message同时携带真实 Fernet 密文时parser 通过inputContentParts丢弃密文部件——这是可接受的因为路由提供商本来就无法解密宁缺毋滥。七、工程方法论要点从本次 cherry-pick 可复用的纪律union 集成优于二选一两个修复机制parser 分支 sanitizer 归一化职责互补全部保留冲突预期必须用git merge-tree实证而不是凭直觉。patch-id 去重内容完全相同的提交64da27d3vsf29002de通过稳定 patch-idff961126...识别并跳过避免重复落盘。脏工作区保护cherry-pick 只提交目标路径预检git status --porcelain必须为空失败用git cherry-pick --abort完整回滚用git reset --keep保留未提交改动绝不用reset --hard。已知红测试隔离Cursor MCP live stdio、pool-health、Windows service 等既有环境相关失败不计入本次回归。参考文件索引报告与计划010_report.md、000_plan.md解析器实现src/responses/parser.tssanitize 与密文分类src/server/responses/encrypted-payload.ts预解析钩子src/server/responses/request-prepare.ts适配器归一化src/adapters/routed-agent-messages.ts测试tests/codex-integration/multi-agent-compat.test.ts、tests/responses/responses-parser-agent-message.test.ts赞分享【免费下载链接】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 PR 73 Cherry-Pick 与传输加固Codex/Cursor 桥接层的错误分类与取消语义修复opencodex PR 73 Cherry Pick 与传输加固Codex/Cursor 桥接层的错误分类与取消语义修复 导读 本文基于 opencodexopencodex 跨平台兼容性审计与修复实录Windows 技能消除、spawn 卫生与路径边界全解析opencodex 跨平台兼容性审计与修复实录Windows 技能消除、spawn 卫生与路径边界全解析 本篇技术指南以 opencodex 仓库中 devl如何为已合并的 Ansible 修复创建回移 PRstable 分支 cherry-pick 与 gh pr create 流程如何为已合并的 Ansible 修复创建回移 PRstable 分支 cherry pick 与 gh pr create 流程 当一个 Ansible buDevOps运维配置管理工作流自动化任务调度上一篇rpmdepsearch实战教程3个真实场景解决软件包依赖问题下一篇深入探索libvirt高级功能快照管理、虚拟机迁移与高可用配置完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
