Skip to content

Backtrack rewind sets context remaining to 0% and triggers auto-compaction #9601

Open

Description

@yiwenlu66

Summary

After using the TUI backtrack/rewind flow (Esc to open transcript overlay, select a previous user message, Enter to rollback), the context indicator jumps to 0% left and the next turn is auto-compacted, even when the post-rollback thread should be far below the model context window.

Version

  • Repo: openai/codex
  • Commit: 16b9380e99474c87502c22ed99bac497d116e724

Repro

  1. Start a Codex TUI session and exchange a few turns (enough to have non-empty history).
  2. Confirm the bottom-bar context indicator is not near 0% left.
  3. Press Esc twice to open the transcript overlay (backtrack preview).
  4. Use Left to select an earlier user message.
  5. Press Enter to rollback.
  6. Observe the context indicator becomes 0% left and the next user turn triggers an automatic compact.

Expected

  • After rollback, token/context usage reflects the smaller history and the context indicator shows substantial remaining context.
  • Auto-compact should not run unless the post-rollback prompt actually exceeds the auto-compact threshold.

Actual

  • Immediately after rollback, remaining context shows 0% left.
  • A compact runs even when the post-rollback thread should be well below the context window.

Suspected cause

The rollback handler recomputes token usage from a heuristic estimate rather than server-provided token usage:

  • codex-rs/core/src/codex.rs:2522 handlers::thread_rollback(...) calls sess.recompute_token_usage(...).
  • codex-rs/core/src/codex.rs:1626 Session::recompute_token_usage(...) uses ContextManager::estimate_token_count(...).
  • codex-rs/core/src/context_manager/history.rs:87 estimate_token_count(...) estimates by JSON-serializing history items (serde_json::to_string(item)) and then calling byte/token heuristics.

This can drastically overestimate the prompt size (JSON framing overhead, large structured fields, image/base64 fields, etc.), which then drives:

  • The TUI context indicator (codex-rs/tui/src/chatwidget.rs:906 uses info.last_token_usage.percent_of_context_window_remaining(window))
  • The auto-compact guard (token usage estimate feeds get_total_token_usage / auto_compact_token_limit).

Possible fixes

  • After rollback, clear token usage info (emit TokenCount { info: None }) until the next real model response provides accurate counts.
  • Or, compute the estimate from the normalized prompt representation (same normalization used for for_prompt()), and avoid counting JSON framing. If images are present, estimate image token cost instead of base64 length.

Activity

  1. 0xdeafbeef commented on Jan 21, 2026

    @0xdeafbeef

    Same thing if you change model and compact.

    Image
  2. added
    bugSomething isn't working
    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal display
    contextIssues related to context management (including compaction)
    on Jan 21, 2026
  3. sahir2k commented on Jan 22, 2026

    @sahir2k

    facing this as well

  4. swordfish444 commented on Jan 26, 2026

    @swordfish444
    Contributor

    @etraut-openai This looks like the same symptom family as #9417 / #9257 (“context remaining goes to 0% after a history mutation”), just triggered by backtrack/rollback instead of compaction.

    The suspected cause in the report seems plausible: recompute_token_usage estimating from serde_json::to_string(item) will overcount (JSON framing + large structured fields), which can push the indicator to 0% and trip auto-compact.

    A low-risk stopgap could be: after rollback, clear token usage info (treat as unknown) until the next real server-provided token count arrives. That avoids bogus “0% remaining” and unnecessary auto-compaction.

    Longer term, it seems safer to estimate from the normalized prompt representation (what’s actually sent) rather than serialized history structs.

  5. Alek2077 commented on Feb 19, 2026

    @Alek2077

    Facing the same issue. It permanently burns my sessions, some of which are very important.
    So now it's clear the huge disadvantages Codex CLI has over some of the other tools:

    1. No undo/rewind feature on code changes
    2. No proper 'safe' undo on conversation

    These are huge usability features.

  6. miraclebakelaser commented on Feb 20, 2026

    @miraclebakelaser
    Contributor

    This has become a constant issue for me when backtracking. Context frequently gets crushed to 0%.

    Pasting an image into a conversation perpetually poisons, even after compactions. Every single backtrack following an image input will lead to 0% context.

  7. Alek2077 commented on Feb 20, 2026

    @Alek2077

    @miraclebakelaser I managed to change from 0% to 90%+ by messing with model_auto_compact_token_limit in toml.config
    and starting the convo with the flag codex resume --last --autocompact=off
    and codex resume --last -c model_auto_compact_token_limit=10000000,
    but unsure how usable the conversation is anymore. I just started a new convo..

  8. miraclebakelaser commented on Feb 20, 2026

    @miraclebakelaser
    Contributor

    @Alek2077 codex resume --last --autocompact=off doesnt seem like a valid command.
    codex resume --last -c model_auto_compact_token_limit=10000000 doesn't fix the issue for me. The conversation resumes at 0% context.

  9. Alek2077 commented on Feb 20, 2026

    @Alek2077

    @miraclebakelaser My bad, the first one indeed is invalid command, but something did fix it - either increasing the model_auto_compact_token_limit in config.toml, or running directly on the 'resume' command. Try it, try increasing compaction to 300k, that's above the max limit, it might actually prevent compacting completely. Let it run for one turn, see if compaction happens and if not, after Codex does one turn, it might change the percentage.

    but again, these are just workarounds and we do need a proper fix.

  10. runfence commented on Jun 5, 2026

    @runfence

    Same issue. I was around at 80%, asked a few questions, then reverted to 80% point and asked another question which triggered compaction.

  11. moulwyse commented on Sep 9, 2026

    @moulwyse

    The suspected cause in the report points at a failure mode worth naming
    explicitly: the session carries two different token accountings, and only
    one of them is authoritative.

    • estimate_token_count is a local heuristic.
    • Provider-reported usage (input_tokens, output_tokens,
      input_tokens_details.cached_tokens) is what the backend actually
      counted and truncated against.

    Rollback recomputes from the heuristic, so the displayed remaining context
    is not a measurement — it is a re-derivation. That is consistent with
    landing on 0% left for a history the server would have accepted.

    There is a second derivation on the other side of the same ratio. Recent
    CLI versions emit token-usage events with model_context_window: 258400
    while the bundled catalog carries context_window: 272000 — exactly 95%.
    So the indicator is an estimated numerator over a discounted denominator.
    Two independent approximations compound, which matches reports of
    compaction firing well below the real limit.

    Suggested behaviour, in order of preference:

    1. After rollback, do not re-estimate. Carry forward the last
      provider-reported usage associated with the retained prefix.
    2. If no reported usage covers the retained prefix, mark usage as
      unknown rather than 0%, and defer the auto-compaction decision
      until the next model response returns real usage.
    3. Do not let an estimated value trigger an irreversible context
      operation. Compaction is destructive; it should require a reported
      number, not an inferred one.

    If useful, I can contribute a measurement rather than an opinion: the same
    session replayed with rollback, logging estimate_token_count against
    provider-reported input_tokens at each turn, to quantify the drift in
    absolute tokens instead of percent. I maintain an Apache-2.0 tool that
    already records provider-reported usage per call for this kind of
    comparison, so the instrumentation exists. Happy to run it and paste the
    table here if that would help triage.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal displaybugSomething isn't workingcontextIssues related to context management (including compaction)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions