Skip to content

feat(core): 新增 opt-in「prompt 前缀稳定层」——剥离 resize notice 并规范 system 块序 - #2449

Open
GGGBB wants to merge 1 commit into
BigPizzaV3:mainfrom
GGGBB:codex/prompt-prefix-stabilizer
Open

GGGBB wants to merge 1 commit into
BigPizzaV3:mainfrom
GGGBB:codex/prompt-prefix-stabilizer

Conversation

@GGGBB

@GGGBB GGGBB commented Oct 10, 2026 •

Copy link
Copy Markdown

独立性声明:本分支不含 #2425(该 PR 已关闭),encrypted_content 透传实现与其测试已全部摘除,本 PR 只含「prompt 前缀稳定层」一个主题。已 rebase 至重写后的最新 main(f6092f29,v1.8.0 线),原 15 个提交压为单提交,diff 集中于 protocol_proxy.rs / settings.rs 及新增模块 compaction_align.rs / compaction_tools.rs / prefix_divergence.rs,全部行为由 stabilizePromptPrefix opt-in 开关控制,关闭时逐字节不变(快照测试守住)。

背景与取证见 issue #2448:codex 客户端每轮把注入块重写进历史早段(resize notice、apps_instructions、collaboration_mode、turn_aborted、open_page 等),token 前缀在 ~30060/31508 确定性分叉,深缓存无法复用,最坏一次截图轮重算 202982 token、prefill 约 5.6 分钟。

设计与开关

  • 开关 stabilizePromptPrefix:RelayProfile(settings.json relayProfiles)上的 per-profile 布尔,默认关;serde 与 standardOpenaiProtocol 同策略(关闭时字段不序列化),旧 profile 反序列化默认 false。profile 每请求实时读取,不改生成的 codex config.toml;关闭时转发行为逐字节不变。
  • 剥离(strip):从 system/user/developer/tool 各角色消息文本删除成对的 image_resize_notice 块:整条消息被块消耗则整条删除;带 tool_calls 的骨架消息保留、内容清空;非成对残留三态归零并记 protocol_diagnostic 日志。执行点在配对/relocate 等所有规范化步骤之前。
  • 规范序(normalize-order):system 内容切顶层块(XML 风格具名块 + 普通文本段)后重排:文本段保持到达相对序在前,具名块按块名字典序钉尾。排序键不含到达位置本身,稳定排序保同档——同块集合、任意到达顺序输出逐字节一致,且幂等。空白处理按语义分桶:切分含具名块时文本段空白属"块间分隔"归一(直接全透传会与 join 分隔叠加增长);无具名块的纯文本段空白属块体本身,逐字节透传。
  • 轮次标记:user 收尾的请求把最后一条 user 消息钉 <current_user_turn>,工具/assistant 收尾的请求只做幂等解包——上下文重建时旧问题不再被回放成最新指令(串线根治)。
  • 易变块治理:附件轮样板归一为常量替身、open_page 块内容钉定、codex_apps_client_time_context 时区锚块同名折叠(dedup-last)、system 区 turn_aborted 摘除改挂末条 user 前(该块语义即"紧邻下一轮的一次性提示")。
  • 压缩轮:普通轮按 prompt_cache_key 缓存 tools 序列化,压缩轮(含 514-msg 流式自动压缩路径,按指令签名检出)回填同一 tools Value 并搬离 system 区摘要指令复制件;缓存有防毒化门,压缩轮的 tools: [] 永不写回。
  • 历史回放:新增 web_search_call 分支(codex 客户端执行后 item 无 content,原 _ 兜底整项静默丢弃):回放为 assistant tool_call + tool 结果,query/sources 存在则透传,被剥离时如实告知,杜绝多 Agent 会话失忆重搜与空 FINAL。
  • 探针:同会话「转换后 system 块序列 + tools」前缀指纹逐轮记录,已见指纹集合模式(容量 6,LRU)消除多 Agent 共键乒乓误报;新指纹即报分叉并 dump 分叉点 ±240B,基线全文落诊断日志私有目录并强制 0600。

测试

  • 稳定层新增单元/集成/serde 测试约 40 项:剥离三形态、异序同输出、幂等、关闭路径逐字节快照、开关注销到上游原始 HTTP body、契约不变式(工具收尾零标记、纯文本段空白逐字节透传、块注入/撤除不扰动 system 头部字节、压缩轮 tools 防毒化、探针共键静默)等。
  • rebase 到 main 后本机全量 cargo test -p codex-plus-core --no-fail-fast 1866 passed / 0 failed(此前分支上的 5 个环境性失败在新 base 上全部不再复现);manager 前端 npm test、tsc --noEmit、assemble-native-browser-inspector --check 均通过。

实测(本机替换部署)

  • 压缩轮全程 25.9s(修复前同规模冷 prefill ~5.7 分钟,约 13 倍),压缩后新历史纯追加恢复 99%+;
  • turn_aborted 摘除后重启首个请求 93.2% 深命中(修复前 17%),探针基线跨重启逐字节一致(-223B 与分叉增量逐字节吻合);
  • 截图轮从"每轮全量重算"恢复为秒回;同块集合两种到达顺序的上游 prompt 逐字节一致;
  • 探针上线后未再见头部前缀突变;基线文件以 0600 落私有目录,/tmp 零残留。

已知限制

某个历史文本段在后续轮次整体缺失时,其后的文本段会前移导致局部分叉——本层不解决;已定案的轮变源不受影响。environment 的 subagents 清单是 user 轮内自由文本,规范化会伤及历史文本,不在本层范围。被中断轮的 assistant/tool 条目重放尾部差异导致的重启后历史最尾 ~9K token 一次性重算(~14s,不随历史长度增长)亦不在本层范围。

维护者 Request changes 三条(均已包含在 squash 内)

  1. [P1] 轮次标记误钉:mark_current_user_turn 改为仅 user 收尾时钉定,工具收尾只做幂等解包直接返回;契约测试守住"工具收尾请求输出零标记"。
  2. [P1/P2] 基线落 world-writable /tmp:dump_baseline_file 迁入诊断日志私有目录,OpenOptions.mode(0o600) 创建、覆写前再收紧权限;部署回归实测 /tmp 零残留。
  3. [P2] 规范序 .trim() 契约违背:改为语义分桶(见"设计与开关"节),契约测试覆盖"纯文本段空白逐字节透传 + 具名块路径幂等"。

@BigPizzaV3 BigPizzaV3 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论:Request changes。

发现三处需要先处理的问题:

[P1] mark_current_user_turn 无条件把最后一条 user 消息标成当前轮。如果请求以 assistant/tool 结果结束(例如等待工具结果后的继续请求),最后一条 user 其实是历史问题,模型会被错误提示为“当前问题”。位置:crates/codex-plus-core/src/protocol_proxy.rs:4697-4711。请只在请求确实以新的 user 输入结束时加标记。

[P1/P2] prefix_divergence::dump_baseline_file 把完整的 system/tools 前缀写入 /tmp,而 divergence 事件还会记录旧、新文本片段。这里可能包含用户提示、工具定义和工作区信息。位置:crates/codex-plus-core/src/prefix_divergence.rs:171-175。请改为只记录长度、hash 和经过明确脱敏的短摘要,或至少使用私有权限文件。

[P2] order_system_chunks_stably 对每个普通块调用 .trim(),会改变普通 system 文本的首尾空白,违背“非易变内容逐字节不变”的 opt-in 契约。位置:crates/codex-plus-core/src/protocol_proxy.rs:4610。请只规范块间分隔,不裁剪块体本身。

@BigPizzaV3

Copy link
Copy Markdown
Owner

当前 PR 与 main 存在合并冲突,且没有可用的最新 CI 结果。请先 rebase/解决冲突,再补跑 Windows artifacts 和 macOS DMG CI。

@GGGBB
GGGBB force-pushed the codex/prompt-prefix-stabilizer branch 2 times, most recently from ea796b1 to 3d10622 Compare October 12, 2026 19:55
@GGGBB

GGGBB commented Oct 12, 2026

Copy link
Copy Markdown
Author

已 rebase 到最新 main 并解决全部冲突(原 15 个提交压为单提交,三条 Request changes 修复均保留,PR 描述已同步改写去掉失效 SHA 引用)。

  • 冲突面:protocol_proxy.rs(上游 +1700 行重构,合成处理:上游的 native compaction 守卫在前,稳定层的 tools 回填/前缀对齐在其后,避免双重 rewrite)、settings.rs(上游已移除的限流字段已同步剔除,保留上游 webSearchHistoryCompat + 本 PR stabilizePromptPrefix)、两个测试文件的调用签名已对齐上游新 API。
  • 本机全量 cargo test -p codex-plus-core --no-fail-fast 1746 passed / 0 failed;manager npm test、tsc --noEmit、inspector --check 全绿。
  • 新提交 3d10622 已推送,PR 状态已从 CONFLICTING 变为可合并;CI run 当前在等待维护者批准(fork 首contributor 的 action_required),麻烦点一下 Approve and run 让 Windows artifacts 和 macOS DMG 跑起来。

@GGGBB
GGGBB force-pushed the codex/prompt-prefix-stabilizer branch from 3d10622 to bccbdd1 Compare October 13, 2026 08:47
@GGGBB

GGGBB commented Oct 13, 2026

Copy link
Copy Markdown
Author

main 前进了 5 个提交后已再次 rebase(新 head bccbdd1,base 45f1c15)。本轮仅一处位置撞车:#2434 的 ensure_web_search_tool_for_history 与本 PR 的 log_compaction_align 插在了同一位置,两个函数均保留;另对齐了上游新增测试的调用签名(stabilizePromptPrefix 传 false,不改变其原意)。

本机全量 cargo test -p codex-plus-core --no-fail-fast 1756 passed / 0 failed。新 head 的 CI run 应该又进了首次贡献者待批准队列,麻烦顺手点一下 Approve and run。

per-profile 开关 stabilizePromptPrefix(serde 与 standardOpenaiProtocol 同策略,
默认关=转发逐字节不变,有快照测试守住)。开启后对发往上游的 body 做:

- 剥离成对 image_resize_notice(整条删除/夹心保留前后文/骨架消息清空内容);
- system 头部块规范序重排(文本段保相对序在前、具名块字典序钉尾;含具名块时
  文本段空白按块间分隔归一,无具名块纯文本段逐字节透传;确定性+幂等);
- 轮次标记 <current_user_turn> 只钉在 user 收尾的请求上,工具收尾只幂等解包;
- 附件轮样板归一 + open_page 块内容钉定;时区锚块同名折叠(dedup-last);
- 压缩轮回填会话 tools(缓存防毒化门:tools:[] 永不写回)+ 前缀对齐
  (514-msg 流式压缩按指令签名检出,搬离 system 区指令复制件);
- system 区 turn_aborted 注入块摘除,改挂末条 user 前(语义即瞬态提示);
- 回放 web_search_call 历史项(query/sources 透传;被剥离时如实告知),
  杜绝多 Agent 会话失忆重搜与空 FINAL;
- 前缀分叉探针(已见指纹集合模式,多 Agent 共键乒乓静默),
  基线落诊断日志私有目录并强制 0600,不再写 world-writable /tmp。

取证背景见 issue BigPizzaV3#2448。本提交为 rebase 到 main@v1.7.7 的 squash(原分支
15 个提交,含维护者三条 Request changes 修复:轮次标记仅 user 收尾钉定、
基线迁私有目录 0600、规范序空白语义分桶)。
全量 cargo test -p codex-plus-core:1746 passed / 0 failed。
@GGGBB
GGGBB force-pushed the codex/prompt-prefix-stabilizer branch from bccbdd1 to ebc5a5e Compare October 14, 2026 03:16
@GGGBB

GGGBB commented Oct 14, 2026

Copy link
Copy Markdown
Author

main 重写并发布 1.8.0 后已跟进 rebase(新 head ebc5a5e2,base f6092f29)。本轮冲突为上游重排的 reasoning 测试与新增测试的调用签名对齐(stabilizePromptPrefix 均传 false,不改变其原意);另外补上了上一版遗漏提交的一处测试调用签名,现已验证提交后的树在零工作区改动下独立编译通过。本机全量 cargo test -p codex-plus-core --no-fail-fast 1866 passed / 0 failed。

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