Automatic compaction drops unchanged additionalContext
What issue are you seeing?
Unchanged client-supplied additionalContext disappears after automatic compaction.
Codex retains additionalContext in AdditionalContextStore and normally emits only entries that changed since the prior turn. That deduplication works until compaction replaces model history: the replacement history is built without re-rendering the store's retained values. A subsequent model request therefore lacks still-active application context even though the client did not remove or change it.
In our app-server-backed integration, this caused connected browser-profile context to vanish after compaction. The model then reported that no browser profile was active despite the client having supplied one earlier in the same session.
What steps can reproduce the bug?
The included integration test reproduces this through the real Responses API loop:
- Submit a user turn with application
additionalContext, such asbrowser_access = "profile id: browser-profile-1". - Return a shell tool call with usage high enough to trigger automatic mid-turn compaction.
- Return the compaction summary.
- Inspect the continuation request sent to the model.
Before the fix, the continuation request contains no <browser_access> developer context. The regression assertion fails with an empty list instead of:
<browser_access>profile id: browser-profile-1</browser_access>
The same underlying omission exists when a token-budget rollover starts a replacement context window.
What is the expected behavior?
Every replacement context window should include the current values retained by AdditionalContextStore. Ordinary turns should continue deduplicating unchanged values, but compaction must rebuild active context because it discards the history that previously carried those values.
Additional information
A focused fix and regression test are ready on a branch based directly on current openai/codex main:
- Commit: https://github.com/davidfant/codex/commit/a77285a05
- Branch: https://github.com/davidfant/codex/tree/codex/upstream-preserve-additional-context-compaction
- Compare view: https://github.com/openai/codex/compare/main...davidfant:codex:codex/upstream-preserve-additional-context-compaction
- Downstream merged fix: https://github.com/comp-work/openai-codex/pull/57
The change renders the store's current values into standard local/remote compaction replacement history and token-budget context-window replacement history. It touches four files and preserves normal per-turn deduplication.
Focused validation on current upstream:
env -u CODEX_SANDBOX_NETWORK_DISABLED NEXTEST_RETRIES=0 just test -p codex-core suite::additional_context— 7 passedenv -u CODEX_SANDBOX_NETWORK_DISABLED NEXTEST_RETRIES=0 just test -p codex-core multiple_auto_compact_per_task_runs_after_token_limit_hit token_budget_context_uses_new_window_after_compaction— 2 passedcargo fmt --allgit diff --check
The new E2E failed at the intended post-compaction assertion before the implementation and passed afterward. If a maintainer agrees with the approach and invites the contribution, the clean branch is ready to open as a PR.
1 Comment
Verified this remains reproducible on current
openai/codexmain(9d012ca4) after the recent compaction-hook changes.The failure boundary is replacement history:
AdditionalContextStore::mergeintentionally emits only changed values, but bothbuild_compaction_initial_contextand token-budgetstart_new_context_windowreplace the history without rendering the store's current values. The next model request therefore cannot recover unchanged application context from either the old history or the deduplicating store.I adapted David Fant's prior implementation onto current main, preserved its provenance, and added current regression coverage for both user-visible paths:
Local proof:
just fmtNEXTEST_RETRIES=0 just test -p codex-core --test all suite::additional_context— 7 passedNEXTEST_RETRIES=0 just test -p codex-core --test all token_budget_context_uses_new_window_after_compaction— 2 passedgit diff --checkReviewable hunk: https://github.com/c3mb0/codex/pull/1
Prior implementation credited here: https://github.com/davidfant/codex/commit/a77285a05
I have not opened an upstream PR because external contributions are invitation-only. If this direction fits the owner lab's current architecture and priority, I would be glad to submit the focused branch by invitation.