Interrupt can merge queued follow-up input with later composer text into a single next-turn message
Summary
Queued follow-up input can be merged with later composer text after an interrupt, and the next turn is then persisted as a single user message.
I am not reporting only a historical log reconstruction here. I reproduced this locally against codex-cli 0.142.0 on Windows 11 using a live interactive codex session, and then verified the resulting history and rollout files on disk.
The confusing part is that two distinct user intents become one next-turn message:
- a follow-up that was explicitly queued while a turn was running
- additional text typed later into the composer before interrupting that running turn
After Esc interrupts the running turn, pressing Enter submits both as one merged message.
Environment
- Codex CLI:
0.142.0 - Platform: Windows 11
- Shell host: PowerShell 7 terminal environment
- Working directory during repro:
E:\Zero_Base\sumi_os - Reproduced on: June 23, 2026
Reproduction
I was able to reproduce this with a live interactive session:
- Launch
codex --no-alt-screen. - Submit a long-running prompt, for example a prompt that makes Codex run:
pwsh -NoProfile -Command Start-Sleep -Seconds 60
- While that turn is still running, type a follow-up marker and press
Tabso it becomes queued. - Without submitting, type additional text into the composer.
- Press
Escto interrupt the running turn. - Press
Enteronce after the interrupt restore.
Actual Behavior
The queued follow-up and the later composer text are merged into a single next-turn user message.
In my live repro, the next persisted user message became:
FOLLOWUP_mixq_20260623_1
IMPL_mixq_20260623_1
This was persisted as one message in both local history and rollout state, even though those two pieces of text were entered in different phases:
- the first line was explicitly queued during the running turn
- the second line was typed later into the composer before the interrupt-driven resubmission
Expected Behavior
One of these should happen instead:
- queued follow-up input and later post-interrupt composer text should remain distinct
- the UI should explicitly show that they are about to be merged before submission
- persisted telemetry should record enough queue / restore metadata to make the merge unambiguous during later debugging
Why This Looks Real Rather Than User Confusion
The persisted sequence in the live repro matched the behavior I saw:
- the first turn started
- the first user message was persisted
- the turn was persisted as
turn_abortedwith reasoninterrupted - the next turn started
- the next user message was persisted as the merged follow-up plus later draft
So this is not just a UI impression. The merged next-turn message shows up in durable local history.
Relevant Source Paths
The current local source also appears consistent with the observed behavior:
tui/src/chatwidget/input_flow.rs- running or not-yet-configured input is queued in
queued_user_messages tui/src/chatwidget/input_restore.rson_interrupted_turn()restores queued messages into the composer- queued messages are merged with the current composer state instead of being kept as a separate submission boundary
There are already tests around the individual pieces of this behavior, for example:
- startup queued input submission
- interrupt restoring queued messages into the composer
- interrupt prepending queued messages before existing composer text
The issue is the combined outcome: distinct user intents can collapse into one next-turn message.
Notes
- I also hit a local
rusty_v8Windows symlink privilege problem when trying to run the Rust test target directly, so my strongest evidence here is the live interactive repro plus the persisted rollout/history verification. - I think there may be two related concerns:
- the product behavior itself
- observability, because the persisted rollout does not seem to expose a first-class
queued_inputmarker that explains this merge directly
2 Comments
I pushed a candidate fix branch for this issue:
starSumi:fix/issue-29629-interrupt-draft-boundaries6c38d269c2The fix keeps a newer in-progress composer draft in place when
Escinterrupts a turn that already has explicit queued follow-up input, and lets that queued follow-up start the next turn directly instead of merging both intents into one restored message.Validation run locally:
cargo fmt --allgit diff --checkcargo test -p codex-tui interrupt_starts_next_queued_turn_and_preserves_existing_composer_metadata -- --exactI also resolved the earlier local Windows symlink privilege blocker by enabling Developer Mode, but the clean-branch targeted test still did not finish within my local execution window, so I am not claiming a full test pass here.
I tried to open a PR from the fork, but GitHub returned:
GraphQL: starSumi does not have the correct permissions to execute CreatePullRequest (createPullRequest)I refreshed this against current
mainand pushed a current-main candidate branch:starSumi:fix/issue-29629-current-main67c4e26532bdd282f3bbThe old branch I mentioned earlier is now stale against
main, so I re-applied the idea on a clean worktree. The current-main patch keeps the existing restore behavior for non-manual-interrupt cases, but changes theEscinterrupt path when both of these are true:In that case, the queued follow-up starts the next turn and the newer draft remains in the composer, instead of collapsing both user intents into one restored draft.
Validation I was able to run locally:
cargo fmt --all -- --checkpassedgit diff --checkpassedI also attempted the focused test:
cargo test -p codex-tui interrupt_starts_next_queued_turn_and_preserves_existing_composer_metadata -- --exactbut I am not claiming a test pass: on this Windows machine the Rust build did not complete within my local execution window after dependency compilation/resource issues. I am sharing this as current-main analysis and a concrete fix direction, not as a merge-ready PR.
I also noticed
docs/contributing.mdnow says external PRs are by invitation only, so I am not opening another PR unless a maintainer explicitly asks for one. The branch is available if it is useful for maintainers to inspect or cherry-pick.