fix(codex): 远端 compact 密文失败走同一任务换窗 - #3529
Conversation
订阅会话 remote compact 撞 invalid_encrypted_content 时,原样重试必败, 且 HTTP 静默剥推理密文够不到这条路径。把它当成官方 compact 确定性失败, 复用现有 host-controlled rollover:同一条任务交接重建并重放用户消息, 不再要求用户开新任务或 Fork。单独的 invalid_encrypted_content 仍留给 静默剥密文,避免供应商切换被误换窗。 Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
|
| Filename | Overview |
|---|---|
| packages/maker-core/src/agents/shared/remote-compact-encrypted-error.ts | 新增窄范围双条件分类器,避免将单独的密文错误误判为换窗条件。 |
| packages/maker-core/src/agents/codex/translator.ts | 将 error notification 中的 message 与 additionalDetails 联合分类,并复用稳定的 context-overflow reason。 |
| packages/maker-core/src/agents/codex/index.ts | 在权威的 turn.completed 失败路径中同步标记远端 compact 密文错误。 |
| apps/desktop/src/main/maker-ipc/contextOverflowRollover.ts | 将新错误类型接入现有 rollover 检测,同时保留远程会话和副作用相关安全边界。 |
| apps/desktop/src/main/maker-ipc/tests/contextOverflowRollover.test.ts | 覆盖即时恢复、下次发送前重建及单独密文错误不触发换窗的行为。 |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Codex 远端 compact] --> B{错误文本同时包含<br/>remote compact 与<br/>invalid_encrypted_content?}
B -->|否| C[保留原错误处理]
B -->|是| D[标记 context-overflow]
D --> E{本地会话且可安全重放?}
E -->|否| F[Fail closed]
E -->|是| G[关闭旧 native thread]
G --> H[写入上下文交接]
H --> I[重放当前用户消息]
Reviews (1): Last reviewed commit: "fix(codex): 远端 compact 密文失败走同一任务换窗" | Re-trigger Greptile
|
@dashhuang 👋 这个 PR 目前与 请在本地 merge 最新的 |
MagicLizi
left a comment
There was a problem hiding this comment.
独立审查通过:把远端 compact 的 invalid_encrypted_content 接到与满窗相同的 host-controlled 换窗路径,并避开单独的推理密文 400。当前 head 与 origin/main 在 rollover / translator 上有实质冲突,Approve 后仍不能合并。
MagicLizi
left a comment
There was a problem hiding this comment.
独立审查 head a482b7a8d26ddc45585fcad54fdef46cd91c5be5:无 P0,有 1 条 P1,本轮不能合。
packages/maker-core/src/agents/codex/index.ts:10887
CodexAgent 在 translateErrorNotification 之前先走 recordHttpRecoveryIntent。armCodexHttpRecovery 用 INVALID_ENCRYPTED_CONTENT_RE 匹配任意含 invalid_encrypted_content 的文本(包括 Error running remote compact task: … invalid_encrypted_content)。订阅会话有 scoped WS 时会吞掉终态 error、把 thread 标成 HTTP-only 并走 retryTurnViaHttpRecovery,到不了本 PR 在 translator 打上的 context-overflow。HTTP strip 会跳过 compaction blob,这次重投必败。请在 isRemoteCompactEncryptedContentError(message + additionalDetails) 为真时不要 arm HTTP recovery,让现有 overflow 分类和 rollover 落地;并在 websocket body recovery 套件加 remote compact 密文 400 fixture。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
审查结论:Request Changes(P1×2)
-
[P1]
packages/maker-core/src/agents/codex/index.ts:10887—translateErrorNotification/turn.completed打context-overflow之前会先recordHttpRecoveryIntent→armHttpRecoveryForError→armCodexHttpRecovery。host 侧INVALID_ENCRYPTED_CONTENT_RE匹配任意含invalid_encrypted_content的文本,用户截图形态Error running remote compact task: … "code": "invalid_encrypted_content"会命中。订阅会话有 scoped WS 时:终态 error 被吞、thread 标成 HTTP-only、retryTurnViaHttpRecovery重投同一 turn;本 PR 的 overflow 分类和 hosttryRecover到不了。HTTPstripEncryptedContentFromBody会跳过 compaction blob,这次重投必败。这正是 GPT-5.6 Sol 订阅旧任务的目标路径,也违反本 PR 写进maker-core-and-agent-behavior.md的新规则(compact 密文硬失败应直接 host-controlled rollover,不得当推理密文 400 剥密文)。请在isRemoteCompactEncryptedContentError(message + additionalDetails)为真时不要 arm HTTP recovery,并给既有websocket body recovery auto-retry套件加 remote compact 密文 400 fixture,断言不会第二次TurnStart、终态 error 带reason: 'context-overflow'。 -
[P1]
packages/maker-core/src/agents/codex/translator.ts:586— 当前 head 相对origin/main(#3510:classifyCodexError/ Cindy 保底压缩)在translator.ts、codex/index.tsturn.completed、contextOverflowRollover.ts导入上仍有实质冲突。2026-08-27 讨论要求 merge 最新origin/main,未做。请 rebase 到origin/main,把 compact 密文判定放进classifyCodexError(或与其结果 OR),再解 rollover 导入。验证:git merge-tree无 conflict,且 compact 用例与 #3510 oversized 用例都绿。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
独立审查 a482b7a8d26ddc45585fcad54fdef46cd91c5be5 后有 2 条 P1,当前 head 不能合。
-
[P1]
packages/maker-core/src/agents/codex/index.ts:10887:订阅会话的 terminal Codex error 仍先recordHttpRecoveryIntent再translateErrorNotification(turn.completed在index.ts:8830同样)。hostarmCodexHttpRecovery用INVALID_ENCRYPTED_CONTENT_RE,只要文案含invalid_encrypted_content就会命中,包括Error running remote compact task: … "code": "invalid_encrypted_content"。有 scoped WebSocket 时这条会吞掉终态、把 thread 标成 HTTP-only,再retryTurnViaHttpRecovery同 turn。本 PR 的reason: 'context-overflow'和 hosttryRecover在第一次失败走不到;HTTPstripEncryptedContentFromBody剥不掉 compact blob,重试必再 400。这正是 GPT-5.6 Sol 旧任务路径,也和文档新句「compact 密文硬失败必须 host-rollover,不能静默剥密文」矛盾。修复:若isRemoteCompactEncryptedContentError(message + additionalDetails)则不要 arm HTTP recovery;补一条websocket body recovery auto-retryfixture(remote-compact 400),断言没有第二次TurnStart,并出现带reason: 'context-overflow'的终态错误。 -
[P1]
packages/maker-core/src/agents/codex/translator.ts:586:本 head 仍把 overflow 分类内联在isContextOverflowErrorMessage旁边。当前origin/main(含 #3510)已把分类收到classifyCodexError(translator.ts:495),turn.completed消费它;compact 检测不在该 classifier 里,additionalDetails也被明确排除。按现在 main 合入会冲突,并可能丢掉 compact→overflow 接线。描述写「不改 #3510 / 独立合入」,但 #3510 已在 main。修复:rebase 到origin/main,把 compact 检查放进classifyCodexError(或与其结果 OR,且仅此路径吃additionalDetails),并重解 rollover import。验证:与origin/main三方合并干净,compact-cipher 与 #3510 oversized/classify 测试都绿。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
独立审查 a482b7a8d26ddc45585fcad54fdef46cd91c5be5 后无 P0、有 2 条 P1,当前 head 不能合。
-
[P1]
packages/maker-core/src/agents/codex/index.ts:10887— 订阅会话的 terminal Codex error 会先recordHttpRecoveryIntent(turn.completed在同文件:8830同样)。hostarmCodexHttpRecovery走INVALID_ENCRYPTED_CONTENT_RE(packages/anthropic-compat-proxy/src/transform.ts:1242),任意含invalid_encrypted_content的文本都会命中,包括Error running remote compact task: … "code": "invalid_encrypted_content"。有 scoped WebSocket 时:终态被吞、thread 标成 HTTP-only、retryTurnViaHttpRecovery重投同一 turn。本 PR 的reason: 'context-overflow'和 hosttryRecover在第一次失败走不到;HTTPstripEncryptedContentFromBody剥不掉 compact blob,重试必再 400。这正是 GPT-5.6 Sol 订阅旧任务路径,也和文档新句「compact 密文硬失败必须 host-rollover,不能静默剥密文」矛盾。请在isRemoteCompactEncryptedContentError(message + additionalDetails)为真时不要 arm HTTP recovery;给既有websocket body recovery auto-retry套件加 remote-compact 400 fixture,断言没有第二次TurnStart,并出现带reason: 'context-overflow'的终态错误。 -
[P1]
packages/maker-core/src/agents/codex/translator.ts:586— 当前 head 仍把 overflow 分类内联在isContextOverflowErrorMessage旁边。origin/main(含 #3510)已把分类收到classifyCodexError,turn.completed消费它;compact 检测不在该 classifier 里,additionalDetails也被明确排除。按现在 main 合入会冲突(translator.ts、codex/index.ts、contextOverflowRollover.ts等),并可能丢掉 compact→overflow 接线。描述写「不改 #3510 / 独立合入」,但 #3510 已在 main;2026-08-27 讨论也要求 merge 最新origin/main。请 rebase 到origin/main,把 compact 检查放进classifyCodexError(或与其结果 OR,且仅此路径吃additionalDetails),并重解 rollover import。验证:与origin/main三方合并干净,compact-cipher 与 #3510 oversized/classify 测试都绿。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
P1 packages/maker-core/src/agents/codex/index.ts:10887(turn.completed 同文件 :8830 同样)
订阅会话终态错误仍先 recordHttpRecoveryIntent → armCodexHttpRecovery,再才 translateErrorNotification / 打 reason: 'context-overflow'。host 的 INVALID_ENCRYPTED_CONTENT_RE 只要文案含 invalid_encrypted_content 就会命中用户形态 Error running remote compact task: … "code": "invalid_encrypted_content"。有 scoped WebSocket 时终态被吞、thread 标成 HTTP-only,retryTurnViaHttpRecovery 重投同一 turn;本 PR 的 overflow 分类和 host tryRecover 第一次失败走不到。HTTP stripEncryptedContentFromBody 会跳过 compaction blob,重试必再 400。这和本 PR 写进 docs/dev-rules/maker-core-and-agent-behavior.md 的新句(compact 密文硬失败必须 host-rollover,不能当推理密文 400 剥密文)矛盾。
请在 isRemoteCompactEncryptedContentError(message + additionalDetails) 为真时不要 arm HTTP recovery;给既有 websocket body recovery auto-retry 套件加 remote-compact 400 fixture,断言没有第二次 TurnStart,并出现带 reason: 'context-overflow' 的终态错误。
P1 packages/maker-core/src/agents/codex/translator.ts 与 codex/index.ts turn.completed、apps/desktop/src/main/maker-ipc/contextOverflowRollover.ts
当前 head 相对 origin/main 仍有实质冲突(git merge-tree 多文件 changed in both)。main(#3510)已把 overflow 收到 classifyCodexError,且明确不吃 additionalDetails;本 head 仍内联在 isContextOverflowErrorMessage 旁,compact 检测不在 classifier 里。按现在合入会冲突,并可能丢掉 compact→overflow 接线。描述写「不改 #3510 / 独立合入」,但 #3510 已在 main。
请 rebase 到 origin/main,把 compact 检查放进 classifyCodexError(或与其结果 OR,且仅此路径吃 additionalDetails),并重解 rollover import(main 已有 CODEX_HISTORY_OVERSIZED_REASON)。验证:与 origin/main 三方合并干净,compact-cipher 与 #3510 oversized/classify 测试都绿。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
代码重审通过:当前 head 未发现 P0/P1。远端 compact 密文失败走同一任务换窗,未发现安全/正确性问题。
MagicLizi
left a comment
There was a problem hiding this comment.
审查结论:Changes requested(P1×2)
P1 packages/maker-core/src/agents/codex/index.ts:10887 — 订阅会话终态仍先 recordHttpRecoveryIntent(turn.completed 同文件 :8830 同样),再才走到 translateErrorNotification / reason: 'context-overflow'。recordHttpRecoveryIntent → armHttpRecoveryForError 没有排除 isRemoteCompactEncryptedContentError。host armCodexHttpRecovery 用 INVALID_ENCRYPTED_CONTENT_RE,任意含 invalid_encrypted_content 的文本都会命中,包括用户形态 Error running remote compact task: … "code": "invalid_encrypted_content"。有 scoped WebSocket 时终态被吞、thread 标成 HTTP-only、retryTurnViaHttpRecovery 重投同一 turn;本 PR 的 overflow 分类和 host tryRecover 在第一次失败走不到。远端 compact 是 Codex 内部硬失败,HTTP 剥密文跳过 compaction blob,重试必再 400。这和本 PR 写进 docs/dev-rules/maker-core-and-agent-behavior.md 的新句(compact 密文硬失败必须 host-rollover,不能当推理密文 400 剥密文)矛盾。既有 websocket body recovery 套件只覆盖单独密文 400。请在 isRemoteCompactEncryptedContentError(message + additionalDetails) 为真时不要 arm HTTP recovery;给该套件加 remote-compact 400 fixture,断言没有第二次 TurnStart,并出现带 reason: 'context-overflow' 的终态错误。
P1 packages/maker-core/src/agents/codex/translator.ts:586 — 当前 head a482b7a8d26ddc45585fcad54fdef46cd91c5be5 相对 origin/main 仍 CONFLICTING(git merge-tree 在 translator.ts、codex/index.ts turn.completed、contextOverflowRollover.ts 导入处有冲突标记;GitHub mergeable=CONFLICTING)。main(#3510)已把 overflow 收到 classifyCodexError,且明确不吃 additionalDetails;本 head 仍内联在 isContextOverflowErrorMessage 旁并用 additionalDetails 拼 classify 文本。按现在合入会冲突,并可能丢掉 compact→overflow 接线。描述写「不改 #3510 / 独立合入」,但 #3510 已在 main。请 rebase 到 origin/main,把 compact 检查放进 classifyCodexError(或与其结果 OR,且仅此路径吃 additionalDetails),并重解 rollover import。验证:与 origin/main 三方合并干净,compact-cipher 与 #3510 oversized/classify 测试都绿。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
审查结论:Changes requested(P1×2)
P1 packages/maker-core/src/agents/codex/index.ts:10887(turn.completed 同文件约 :8830 同样)— 订阅会话终态仍先 recordHttpRecoveryIntent → armHttpRecoveryForError → host armCodexHttpRecovery,再才 translateErrorNotification / 给 reason: 'context-overflow'。armCodexHttpRecovery 用 INVALID_ENCRYPTED_CONTENT_RE,任意含 invalid_encrypted_content 的文本都会命中,包括用户形态 Error running remote compact task: … "code": "invalid_encrypted_content"。有 scoped WebSocket 时 error notification 直接 return、终态被吞,thread 标成 HTTP-only 后 retryTurnViaHttpRecovery 重投同一 turn;本 PR 的 overflow 分类和 host tryRecover 在第一次失败走不到。请在 isRemoteCompactEncryptedContentError(...) 为真时不要 arm HTTP recovery,并给该套件加 remote-compact 400 fixture,断言没有第二次 TurnStart,并出现带 reason: 'context-overflow' 的终态错误。
P1 packages/maker-core/src/agents/codex/translator.ts:586、packages/maker-core/src/agents/codex/index.ts turn.completed、apps/desktop/src/main/maker-ipc/contextOverflowRollover.ts、docs/dev-rules/maker-core-and-agent-behavior.md — 相对当前 origin/main 实质冲突(#3510 已把 overflow 收到 classifyCodexError,且明确不吃 additionalDetails;本 head 仍内联分类并用 additionalDetails)。规则文档相对 main 会删掉 Cindy 保底压缩整段。请 rebase 到最新 origin/main,把 compact 检查放进 classifyCodexError(或与其结果 OR,且仅此路径吃 additionalDetails),并重解 rollover import。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
审查结论:Request Changes(P1×2)。当前 head a482b7a8d26ddc45585fcad54fdef46cd91c5be5 与 origin/main 已 CONFLICTING,请先 rebase 后再修下面两条。
-
packages/maker-core/src/agents/codex/index.ts:10887
scoped WebSocket 的 error notification 在translateErrorNotification之前调用recordHttpRecoveryIntent;命中则直接return,错误通知被吞掉。armHttpRecoveryForError不排除isRemoteCompactEncryptedContentError,而 hostINVALID_ENCRYPTED_CONTENT_RE会匹配 compact 密文 400(invalid_encrypted_content)。随后turn.completed(约 8830 行)会走 HTTP body recovery,而不是本 PR 要求的同一任务换窗。请在登记 HTTP recovery 前排除 compact 密文失败,让 overflow/rollover 路径先于 proxy 重试。 -
packages/maker-core/src/agents/codex/translator.ts:586
本 head 仍在 translator 内联拼接additionalDetails后调用isRemoteCompactEncryptedContentError。主干(#3510)已把 overflow 分类收进classifyCodexError,且不拼additionalDetails。两边改同一分类面,不 rebase 无法安全合入;合入后 compact 密文是否带CONTEXT_OVERFLOW_REASON也会和主干分叉。请 rebase 到最新 main,把密文失败分类接到classifyCodexError,不要再维护一份并行判定。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
审查结论:changes-requested(P1×2)。当前 head a482b7a8d26ddc45585fcad54fdef46cd91c5be5 不能合。
-
packages/maker-core/src/agents/codex/index.ts:10887— 订阅会话终态 error 在translateErrorNotification之前先recordHttpRecoveryIntent(turn.completed同文件约:8830同样)。armHttpRecoveryForError未排除isRemoteCompactEncryptedContentError;hostarmCodexHttpRecovery用INVALID_ENCRYPTED_CONTENT_RE(packages/anthropic-compat-proxy/src/transform.ts:1242),任意含invalid_encrypted_content的文本都会命中,包括 remote compact 400(Error running remote compact task: … "code": "invalid_encrypted_content")。有 scoped WS 时:error 在:10887return被吞、thread 标成 HTTP-only、retryTurnViaHttpRecovery重投同一 turn;本 PR 打的reason: 'context-overflow'与 hosttryRecover第一次失败走不到。这与本 PR 写入docs/dev-rules/maker-core-and-agent-behavior.md的新句(compact 密文硬失败必须 host-rollover,不得当推理密文 400 剥密文)矛盾。请在isRemoteCompactEncryptedContentError(message + additionalDetails)为真时不要 arm HTTP recovery,并加 remote-compact 400 fixture:断言没有第二次TurnStart,并出现带reason: 'context-overflow'的终态错误。 -
packages/maker-core/src/agents/codex/translator.ts:586— GitHubmergeable=CONFLICTING/mergeStateStatus=DIRTY。当前 head 仍把 overflow 内联在isContextOverflowErrorMessage旁并拼接additionalDetails。origin/main(#3510)已把分类收到classifyCodexError(明确不吃additionalDetails),turn.completed消费它。描述写「不改 #3510 / 独立合入」,但 #3510 已在 main。请 rebase 到最新 main,把 compact 检查放进classifyCodexError(或与其结果 OR,且仅此路径吃additionalDetails),并重解 rollover import。验证:与origin/main三方合并干净,compact-cipher 与 #3510 oversized/classify 测试都绿。
|
@dashhuang 👋 这个 PR 目前与 请在本地 merge 最新的 |
|
@dashhuang 👋 这个 PR 已经有 3 天没有 rebase 了。 为了避免合入后出现 CI 未曾验证过的新问题,请在本地 rebase 最新的 |
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
这次改了什么
摘要
Codex 订阅会话做远端压缩时,如果历史里有解不开的
encrypted_content,上游直接 400:Error running remote compact task+invalid_encrypted_content。这条失败原样重试必败;HTTP 静默剥推理密文也够不到 compact / WebSocket。用户只能开新任务或手动 Fork。本 PR 把它当成官方 compact 的确定性失败,接到现有同一任务换窗(host-controlled rollover):关掉旧 native thread、写交接、重放刚才那句用户消息。新任务不用用户去开,也不走 Fork 并剥离。单独的
invalid_encrypted_content(供应商切换时 HTTP 还能剥推理密文)不会被误判成换窗。设计上接着 #3510 的「官方压不动就同一任务换窗」,但不改 #3510,独立合入。
变更类型
fix缺陷修复feat新功能refactor/perf重构或性能优化docs/test/chore文档与工程维护范围
invalid_encrypted_content,新任务正常。isRemoteCompactEncryptedContentError:必须同时命中remote compact与invalid_encrypted_contentcontext-overflowreasoncontextOverflowRollover把这类错误当成可重建prepareUnhealthySessionUI 变化
contextRebuild分隔样式与chat.errorBanner.contextOverflow文案。怎么验证的
自动验证
pnpm test:unit:related因改了 maker-core 公共导出而拉了全量 desktop。其中 maker-core related 通过。desktop 全量有环境性失败(claudeOrphanReaper、portReclaim、usageHistory、以及若干ioregcollect 失败),与本 diff 无关;#3510 也曾在干净 main 上复现同类基线项。CI 全量pnpm test:unit为准。手工验证
未在安装版 Cindy 上用真实 GPT-5.6 Sol 旧任务复现换窗。分类与 rollover 由单测覆盖用户截图中的文案形态。
未执行的验证
真机:打开已报
Error running remote compact task的旧 Codex 任务,发下一条,确认同一任务交接并继续。device-link / SSH 未手测(SSH 本就拒绝本地换窗)。风险
风险分类
context-overflow换窗;交接会丢掉 native 历史细节,只保留摘要。本轮已有工具副作用时不自动 replay。影响与回滚
提交前检查
git commit -s,见 DCO)