Skip to content

fix: preserve native compaction with safe summary fallback - #2303

Open
Rat0323 wants to merge 2 commits into
BigPizzaV3:mainfrom
Rat0323:fix/openai-identity-compaction-v2
Open

Rat0323 wants to merge 2 commits into
BigPizzaV3:mainfrom
Rat0323:fix/openai-identity-compaction-v2

Conversation

@Rat0323

@Rat0323 Rat0323 commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

背景

这条改动只处理 OpenAI 会话身份走本地代理的 remote compaction v2。纯官登直接访问官方,默认纯 API 使用本地压缩,都不经过这里。

本 PR 已 rebase 到当前 main,并按 #2301 的实现收缩为增量改动:不再替换 #2301 的原生 Responses 透传路线,只补上它目前缺少的安全降级和原生历史保护。

保留的 #2301 行为

  • Responses 原生 compaction 继续透传,encrypted_content 和未知字段不重写。
  • 保留完整 SSE 事件序列:response.created → response.output_item.added → response.output_item.done → response.completed。
  • 继续使用合法的 cmp_ compaction item ID。
  • 保留 data-only SSE、无增量摘要流和完整正文事件的兼容处理。
  • 继续转发 X-Codex-Beta-Features。
  • 保留 channel protection / cooldown 逻辑。

本 PR 新增的行为

  • compaction_trigger 不要求位于 input 末尾,任意位置都能识别。
  • Responses 上游第一次请求先原样携带 compaction_trigger 进行原生探测。
  • 上游返回恰好一个带 encrypted_content 的 compaction item 时原样透传;客户端要求流式而上游返回 JSON 时,会渲染为完整 SSE 事件序列。
  • 只有以下两种情况才降级为普通摘要:
    • 上游用 400/422 明确表示不认识该输入项;
    • 上游请求成功但没有可用 compaction item。
  • 401、403、429、5xx、上游失败事件,以及没有 response.completed 的截断流,不降级、不摘要重试。
  • 历史里已有原生 encrypted compaction、当前上游却不支持 v2 时,返回 Responses 400 compaction_incompatible,而不是笼统 502,也不会把 opaque state 降级成明文摘要。
  • Chat Completions 上游遇到原生 compaction 历史时直接拒绝,不把原生 checkpoint 假装成普通文本。

测试时序修复

测试服务器现在会按 Content-Length 读完整请求,并显式等待预期的第二次连接,不再使用 200ms 的短超时窗口,因此不会在并发负载下提前 drop listener。

Base 分支 CI 修复

当前 main 上 App.tsx 里 metadataImportPreview / setMetadataImportPreview 重复声明,导致所有 PR 的 TypeScript/Vite 构建失败。本 PR 用独立提交删除遗留的 dead useState,用于解除 base 分支 CI 阻塞。

验证

  • cargo test -p codex-plus-core --test protocol_proxy:139 passed
  • 默认并发连续运行 5 次:每次 139 passed
  • cargo test -p codex-plus-core:通过
  • GitHub CI:Windows artifacts、macOS x64、macOS arm64 全部通过

@Rat0323 Rat0323 changed the title fix: 官方会话身份下保留原生 v2 压缩,并为第三方补齐缺失的 compaction 项 fix: 完整适配代理路径的 remote compaction v2 Sep 26, 2026
@Rat0323 Rat0323 changed the title fix: 完整适配代理路径的 remote compaction v2 fix: 完善代理侧 remote compaction v2 原生透传与兼容回退 Sep 26, 2026
@Rat0323 Rat0323 changed the title fix: 完善代理侧 remote compaction v2 原生透传与兼容回退 fix: 完整实现 remote compaction v2 代理协议契约 Sep 26, 2026
@BigPizzaV3

Copy link
Copy Markdown
Owner

审查了。产品逻辑有价值,但当前版本不能合 —— 它给 CI 引入了一个确定性的测试失败。

阻断:并发跑该测试 5 次,5 次失败

我在 rebase 到 main 的独立 worktree 里实测:

单线程 (--test-threads=1):143 passed / 0 failed
并发(默认)      :连续 5 次全部失败

失败的用例是 compaction_v2_request_routes_to_summary_endpoint_and_flags_response(tests/protocol_proxy.rs:489):

供应商「compact」请求上游失败,endpoint: http://127.0.0.1:63511/v1/responses
  1: error sending request for url (...)

作为对照,main 并发跑 3 次全部通过(124 passed)。所以这不是仓库既有的 flake,是本 PR 引入的。

成因

本 PR 把该测试的服务端 accept 改成了带超时的形式:

let accepted = if index == 0 {
    Some(listener.accept().await.unwrap())
} else {
    tokio::time::timeout(Duration::from_millis(200), listener.accept())  // ← 200ms
        .await.ok().and_then(Result::ok)
};
let Some((mut stream, _)) = accepted else { break; };   // 超时即退出,listener 被 drop

并发跑时进程被其它测试拖慢,第二次连接赶不上 200ms 窗口,listener 提前 drop,代理的第二次请求就 Connection refused。第一次连接仍是无限等待,所以单线程下必然通过。

这不是产品逻辑问题(否则单线程也该失败),是测试时序假设过紧。建议把第二次 accept 的超时放宽(或改成与第一次同样的无限等待 + 整体测试超时),再跑并发验证。

产品逻辑部分:认可,但要注意与 #2301 的关系

你的实现提供了 main 目前确实缺少的场景:

  • native_checkpoint_cannot_be_downgraded_to_chat_text —— 拒绝把原生 checkpoint 降级成 chat 文本
  • native_compaction_history_returns_responses_error_without_summary_retry —— 历史含原生压缩而上游不支持 v2 时,返回 Responses 错误而非笼统 502
  • 400/422 判定上游不认识该输入项后降级为摘要

这两个测试名我在 main 上搜不到,说明是新增覆盖。

但请注意:#2301 已经合入 main(1b74e13d),它走的是另一条设计路线 —— 用单一的 UpstreamProxyResponse.compaction: bool 标记「仅 Chat Completions 走合成摘要,原生 Responses 保持透传」,而不是你这里的 native_compaction_passthrough 字段 + 计数校验 + 多分支降级。

两套设计目标相关但实现不同,直接合会有大量重叠。建议先 rebase 到当前 main,把只剩你才有的那部分(上面两个场景 + 400/422 降级)单独整理出来,避免整份替换掉已合入的原生透传实现。

如果你认为 #2301 的路线有它没覆盖的缺陷,欢迎在 rebase 后指出具体场景,我们再决定是否要替换。

@Rat0323
Rat0323 force-pushed the fix/openai-identity-compaction-v2 branch from 5759a68 to 7d9f01a Compare September 30, 2026 11:10
@Rat0323
Rat0323 force-pushed the fix/openai-identity-compaction-v2 branch from 7d9f01a to 211108f Compare September 30, 2026 11:14
@Rat0323 Rat0323 changed the title fix: 完整实现 remote compaction v2 代理协议契约 fix: preserve native compaction with safe summary fallback Sep 30, 2026
@Rat0323

Rat0323 commented Sep 30, 2026

Copy link
Copy Markdown
Contributor Author

感谢 review,已按你的建议处理。

这版已经 rebase 到当前 main,不再替换 #2301 的原生透传实现,而是保留它已有的原生 Responses passthrough、完整输出事件、cmp_ ID、无增量流兼容、beta header 和 channel protection,只叠加本 PR 独有的部分:

  • 400/422 表示不认识 compaction_trigger 时,降级为普通摘要;
  • 成功但没有可用 compaction item 时,降级为普通摘要;
  • 原生 encrypted compaction 历史不能降级成 chat 文本;
  • 历史含原生 compaction 而当前上游不支持 v2 时,返回明确的 Responses compaction_incompatible 错误;
  • 401/403/429/5xx、真实失败事件和截断流不重试。

你指出的测试时序问题也已修复:fake server 现在会读完整请求,并显式等待预期的第二次连接,不再使用 200ms 短窗口。

验证结果:

  • cargo test -p codex-plus-core --test protocol_proxy:139 passed
  • 默认并发连续跑 5 次:全部通过
  • cargo test -p codex-plus-core:通过
  • Windows / macOS x64 / macOS arm64 CI 全部通过

另外,当前 main 的 App.tsx 有 metadataImportPreview 重复声明,导致所有 PR CI 都会在 TypeScript/Vite 阶段失败;本 PR 用独立提交删除了这份 dead useState,用于解除 base 分支构建阻塞。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants