Skip to content

fix(tui_gateway): stop replaying live-turn user text after redirect - #84589

Closed
StanleyStetson wants to merge 1 commit into
NousResearch:mainfrom
StanleyStetson:fix/84417-prompt-replay-one-commit
Closed

StanleyStetson wants to merge 1 commit into
NousResearch:mainfrom
StanleyStetson:fix/84417-prompt-replay-one-commit

Conversation

@StanleyStetson

Copy link
Copy Markdown
Contributor

What does this PR do?

Stops the tui_gateway server queue from re-firing the live turn's original user prompt P after a mid-turn correction Q (Desktop session.redirect / busy-input interrupt redirect). That re-fire produced a second agent turn and a second active role=user row with the same content (#84417).

Root cause (contract layer): while turn P was live, a text-only self-copy of P could sit in session["queued_prompt"] / queued_prompts (e.g. mid-busy re-submit while redirect was not available; consecutive-text merge could also glue P\n\nQ). Successful redirect/steer of Q did not scrub that self-duplicate, so post-settle _drain_queued_prompt restarted P.

Approach:

  1. Scrub text-only self-duplicates of inflight_turn.user on successful redirect/steer; rewrite merged {P}\n\n{Q}Q only.
  2. Refuse admitting a text-only self-copy of the live user in _enqueue_prompt (scrub first so merge cannot re-glue P+Q).
  3. On compression session rotation, bump _queued_prompt_generation so an in-flight drain claim cannot dispatch with a stale generation. If generation cancels a claim mid-drain, the claimed envelope is restored to the queue (legitimate follow-ups are not dropped).

Scope / residual (honest limits of this PR):

  • Fixes server self-duplicates of the live turn. The independent Desktop client composer queue ($queuedPromptsBySession) is unchanged; a user-queued follow-up can still drain by design.
  • Image-bearing queue envelopes are left alone (chronology/ownership).
  • Verification is production-path unit/integration on gateway helpers (class repro), not a full interactive long-session Desktop compression e2e.

Related Issue

Fixes #84417

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✅ Tests (adding or improving test coverage)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • tui_gateway/server.py_sanitize_queued_entry_vs_inflight_user, _drop_queued_duplicates_of_inflight_user; scrub on successful busy redirect/steer; refuse self-dup in _enqueue_prompt; bump _queued_prompt_generation in _sync_session_key_after_compress on rotation; restore claimed queue envelope when generation cancels mid-drain.
  • tui_gateway/methods_session.py — scrub on successful session.redirect and session.steer (Desktop production path).
  • tests/test_tui_gateway_queue_on_busy.py — redirect scrub, hard-interrupt path, merge rewrite, drain E2E (no second P), enqueue refuse, compress generation bump / no-op, generation-cancel restores claimed head.
  • tests/test_tui_gateway_server.pysession.redirect RPC scrub + build-window queue of Q scrubs stale P.

How to Test

  1. Regression suite:
    scripts/run_tests.sh tests/test_tui_gateway_queue_on_busy.py -q --tb=short
    scripts/run_tests.sh tests/test_tui_gateway_server.py -k "session_redirect" -q --tb=short
    scripts/run_tests.sh tests/tui_gateway/test_protocol.py -k "sync_session_key_after_compress" -q --tb=short
  2. Evidence (local runner): tests/test_tui_gateway_queue_on_busy.py — 25 passed; related session.redirect / compress re-anchor tests passed via scripts/run_tests.sh.
  3. Key cases:
    • successful redirect drops queued self-dup of inflight user (busy-submit + Desktop session.redirect RPC)
    • hard-interrupt + queue of Q scrubs stale P ahead of Q
    • build-window session.redirect enqueue of Q scrubs P
    • after redirect(Q), _drain_queued_prompt does not start a turn with P
    • merged P\n\nQ rewrites to Q-only
    • compress rotation bumps generation; unrelated follow-up text is preserved
    • generation cancel mid-drain does not drop the claimed follow-up (restored to queue)
  4. Class repro (pre/post): P running + queued_prompt=P + redirect(Q) → pre-fix drain re-fired P; post-fix queue scrubbed, drain no-op.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run scripts/run_tests.sh on the affected tests and they pass (project canonical runner)
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Linux (WSL/Ubuntu-class), via scripts/run_tests.sh

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) — pure Python gateway session-dict logic; no OS-specific paths
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tui Terminal UI (ui-tui/ + tui_gateway/) sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 12, 2026
@StanleyStetson
StanleyStetson force-pushed the fix/84417-prompt-replay-one-commit branch from a578f24 to 3219756 Compare August 12, 2026 14:58
A mid-turn correction (Desktop session.redirect / busy-input interrupt redirect)
must not leave a server-queue self-copy of the live inflight user prompt.
Otherwise post-turn _drain_queued_prompt restarts that original text as a
fresh agent turn after Q completes (NousResearch#84417).

Scrub text-only self-duplicates of inflight_turn.user on successful
redirect/steer, refuse admitting them in _enqueue_prompt, rewrite merged
"{P}\n\n{Q}" slots to Q-only, bump _queued_prompt_generation on compression
session rotation, and restore the claimed queue envelope when generation
cancels mid-drain. Stabilize profile-scoped agent-build unit tests under CI load.

Fixes NousResearch#84417
@spfcraze

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Summary:
A queued multi-line follow-up whose first line equals the live prompt is truncated to its later lines when any later redirect scrubs the queue.

Problems:

  • In tui_gateway/server.py, _sanitize_queued_entry_vs_inflight_user iterates for sep in ("\n\n", "\n") (line 7612), treating a single newline as a merge boundary as well. _enqueue_prompt's consecutive-text merge only ever joins with \n\n (line 7579, f"{prev}\n\n{text}"), so the single-newline branch has no merge artifact to catch: it only fires on genuine multi-line user text.
  • A queued follow-up like write a poem\nabout the sea under a live prompt write a poem is rewritten to about the sea on the next successful redirect or steer (each calls _drop_queued_duplicates_of_inflight_user, which runs this sanitize on every queued envelope), dropping the first line the user wrote.

Solution:
Restrict the rewrite to the merge separator _enqueue_prompt actually produces, the double newline, so a legitimate multi-line follow-up is never truncated.

Evidence

no deterministic fact backs this claim — model belief, not executed or read evidence


Checked against 7c39f7d — the tip of fix/84417-prompt-replay-one-commit when this was written — and fa83af3, main at the same moment.

@teknium1

Copy link
Copy Markdown
Collaborator

Thank you for this fix! It was salvaged into #86593 (cherry-picked onto current main with your authorship preserved in the commit history) and is now merged. Closing this PR since the work has landed.

@teknium1 teknium1 closed this Aug 15, 2026
@StanleyStetson
StanleyStetson deleted the fix/84417-prompt-replay-one-commit branch August 15, 2026 08:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: post-compression Desktop session replays an earlier user prompt as a fresh turn

4 participants