Skip to content

fix(desktop): Stop parks the queue instead of firing the next queued prompt - #68725

Merged
OutThisLife merged 1 commit into
NousResearch:mainfrom
SHL0MS:fix/desktop-stop-parks-queue
Jul 21, 2026
Merged

fix(desktop): Stop parks the queue instead of firing the next queued prompt#68725
OutThisLife merged 1 commit into
NousResearch:mainfrom
SHL0MS:fix/desktop-stop-parks-queue

Conversation

@SHL0MS

@SHL0MS SHL0MS commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

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 userInterruptedRef latch (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:

  • Explicit halts park the queue before interrupting. That covers the Stop button, Esc in the composer, Esc with chat focus, the hover Stop on a streaming user message, and the assistant-ui runtime cancel. Parked queues are skipped by both drain paths (the mounted ChatBar drainer and the background drainer for unfocused sessions).
  • Queue-advancing interrupts unpark first. sendQueuedNow keeps 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

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • apps/desktop/src/store/composer-queue.ts: new $parkedQueueSessions atom plus parkQueuedPrompts / unparkQueuedPrompts / isQueueParked. shouldAutoDrain gains an optional parked gate. Enqueueing unparks, emptying a queue drops its park, and migrateQueuedPrompts carries the park to the new key.
  • apps/desktop/src/app/chat/composer/hooks/use-composer-queue.ts: auto-drain effect and autoDrainNext honor the park; a successful drain unparks; sendQueuedNow unparks before interrupting; hook exposes queueParked.
  • apps/desktop/src/app/chat/composer/index.tsx: haltRun wrapper parks then cancels, wired to the Stop button branch of the submit engine, composer Esc, and the chat-focus Esc hook. QueuePanel gets parked + 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.
  • i18n: queuedPaused, queueResume, queueResumeTip added to types.ts and all four locales.
  • Tests: store contract (park bookkeeping, shouldAutoDrain, migration) in composer-queue.test.ts; hook wiring (park held at the Stop settle, resume, send-now unpark + settle drain) in a new use-composer-queue.test.tsx; background-drainer park skip in use-background-queue-drain.test.tsx.
  • Docs: one line in website/docs/user-guide/desktop.md.

How to Test

  1. Start a long turn ("count to 200 slowly"), type two follow-ups and press Enter on each so they queue, then press Stop.
  2. Before: the turn stops and the first queued prompt fires immediately. After: the session goes idle, the queue panel expands showing "2 Queued — paused", and nothing sends.
  3. Click Resume (or press Enter on the empty composer): the queue flows again in order.
  4. Queue an entry mid-turn and click its send arrow: the running turn interrupts and that entry fires on settle, same as before this PR (the fix(desktop): reliable composer message queue #40221 case).
  5. Renderer checks: 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

  • 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 the desktop renderer suite (npx vitest run --project ui) and all tests pass; pytest N/A, no Python changes
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 26.5

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A (no config changes)
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A (renderer-only)
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

…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.
@alt-glitch alt-glitch added type/bug Something isn't working comp/desktop Electron desktop app (apps/desktop/*) P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Jul 21, 2026
@OutThisLife
OutThisLife merged commit 11ae6bf into NousResearch:main Jul 21, 2026
33 checks passed
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) 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.

3 participants