fix(desktop): Stop parks the queue instead of firing the next queued prompt - #68725
Merged
OutThisLife merged 1 commit intoJul 21, 2026
Merged
Conversation
…prompt Interrupting a busy turn with the Stop button (or Esc) settles the session to idle, and the edge-independent auto-drain immediately submits the head of the composer queue. The user pressed Stop to halt the agent, but it looks like Stop skipped the current turn and kept going — and the queued text is hard to find, since its only surface is the collapsed 'N queued' pill above the composer. The old userInterruptedRef latch (a23728dcc) fixed this but was removed in NousResearch#40221 because it also suppressed the drain that send-now-while-busy depends on. This reintroduces the halt with source awareness instead of a blanket latch: - Explicit halts (Stop button, composer Esc, chat-focus Esc, the streaming message's hover Stop, runtime cancel) park the session's queue before interrupting. Parked queues are skipped by both auto-drain paths (mounted ChatBar + background drainer). - Interrupts that exist to advance the queue (send-now-while-busy) unpark first, so the settle drain they rely on still flows. - The park lifts on any renewed intent: resume, a manual drain (Enter on empty composer or the per-row send arrow), queueing a new prompt, or emptying the queue. It migrates with entries on a runtime re-key and is deliberately not persisted (a fresh process starts unparked). - The queue panel expands on park, switches to 'N Queued — paused' with a pause icon, and grows a Resume action, so the held prompts are visible instead of reading as vanished. Store contract, hook wiring, and background-drain coverage included; docs updated.
This was referenced Jul 21, 2026
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…rks-queue fix(desktop): Stop parks the queue instead of firing the next queued prompt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Pressing Stop while prompts are queued doesn't feel like stopping. The interrupt settles the turn, the auto-drain sees an idle session with a non-empty queue, and the head entry fires immediately. To the user it reads as Stop skipping ahead instead of halting. The queued text is also easy to lose track of, since its only surface is the collapsed "N queued" pill above the composer.
This was fixed once before with a
userInterruptedReflatch (a23728d) and reverted two days later in #40221, because the latch also suppressed the drain that send-now-while-busy depends on: sending a queued entry during a running turn promotes it to the head, interrupts, and relies on the settle drain to fire it.This PR tags the interrupt's intent instead of latching every interrupt:
sendQueuedNowkeeps exactly the behavior fix(desktop): reliable composer message queue #40221 protected: promote, interrupt, drain on settle.A park lifts on any renewed intent: the Resume action in the queue panel, a manual drain (Enter on an empty composer or a row's send arrow), queueing a new prompt, or deleting the last entry. Parks migrate with entries when a session re-keys after compression, and are not persisted to localStorage, so a fresh app launch starts unparked.
The queue panel now telegraphs the state. On park it force-expands, the label switches to "N Queued — paused" with a pause icon, and a Resume button appears. The held prompts sit right above the composer with edit/send/delete still available, instead of reading as vanished.
Related: #55183 tracks the same drain-after-interrupt behavior on the ACP surface, which is server-side and untouched here. #41202 (default-expand while flowing) and #45662 (transcript presence for queued prompts) stay open; this PR only changes expansion on park.
Related Issue
No desktop issue filed for this one; closest open reports are #55183 (same complaint on ACP) and #41202 / #45664 (queue visibility).
Type of Change
Changes Made
apps/desktop/src/store/composer-queue.ts: new$parkedQueueSessionsatom plusparkQueuedPrompts/unparkQueuedPrompts/isQueueParked.shouldAutoDraingains an optionalparkedgate. Enqueueing unparks, emptying a queue drops its park, andmigrateQueuedPromptscarries the park to the new key.apps/desktop/src/app/chat/composer/hooks/use-composer-queue.ts: auto-drain effect andautoDrainNexthonor the park; a successful drain unparks;sendQueuedNowunparks before interrupting; hook exposesqueueParked.apps/desktop/src/app/chat/composer/index.tsx:haltRunwrapper parks then cancels, wired to the Stop button branch of the submit engine, composer Esc, and the chat-focus Esc hook. QueuePanel getsparked+onResume.apps/desktop/src/app/chat/index.tsx: same wrapper for the transcript-side stops (hover Stop on the streaming message, runtime cancel). ChatBar keeps the raw cancel since it wraps internally.apps/desktop/src/app/chat/composer/queue-panel.tsx: paused label, pause icon, Resume action with tooltip; remounts the StatusSection on park so it expands.apps/desktop/src/app/session/hooks/use-background-queue-drain.ts: background drainer skips parked sessions.queuedPaused,queueResume,queueResumeTipadded totypes.tsand all four locales.shouldAutoDrain, migration) incomposer-queue.test.ts; hook wiring (park held at the Stop settle, resume, send-now unpark + settle drain) in a newuse-composer-queue.test.tsx; background-drainer park skip inuse-background-queue-drain.test.tsx.website/docs/user-guide/desktop.md.How to Test
cd apps/desktop && npx tsc -p . --noEmit && npx vitest run --project ui(1723 passed, 208 files) and eslint on the touched files (clean).Checklist
Code
fix(scope):,feat(scope):, etc.)npx vitest run --project ui) and all tests pass;pytestN/A, no Python changesDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/A (no config changes)CONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/A