fix(desktop): make Stop button actually interrupt when a turn is queued#37948
Merged
kshitijk4poor merged 1 commit intoJun 3, 2026
Merged
Conversation
rodriguez46p-ui
left a comment
There was a problem hiding this comment.
Hermes hourly review: I read the diff for the composer queue Stop-button regression and did not find a blocking issue. The new pure shouldAutoDrainOnSettle helper captures the important invariant: natural busy→idle completion drains queued work, explicit Stop suppresses exactly one drain while preserving the queue.\n\nI am leaving this as a comment rather than approval because the broader CI matrix was still pending when checked; the already-finished lint/security/e2e checks were passing.
OutThisLife
previously approved these changes
Jun 3, 2026
When a follow-up message is queued during a busy turn, the composer clears and the primary button switches back to the Stop affordance. But clicking Stop ran interruptAndSendNextQueued(), which cancelled the turn and *immediately* re-sent the head of the queue. The auto-drain effect (busy true to false) compounded this: any explicit cancel flipped busy false and re-fired the queue. The net effect was that Stop appeared to never interrupt -- the agent kept running on the queued prompt. Fix: - Stop button (busy + empty composer) now always performs a pure interrupt via onCancel(); it no longer hijacks the queue. - An explicit interrupt latches userInterruptedRef so the busy to false auto-drain skips exactly one drain. Queued turns are preserved and the user resumes them deliberately (Cmd/Ctrl+K, Enter, or the per-row send-now arrow), matching the documented Esc=cancel / Cmd+K=send-next affordances. - Extracted the settle decision into shouldAutoDrainOnSettle() with unit tests covering natural completion vs. explicit interrupt.
9a69103 to
a23728d
Compare
davidgut1982
pushed a commit
to davidgut1982/hermes-agent
that referenced
this pull request
Jun 5, 2026
…stop-button-interrupt fix(desktop): make Stop button actually interrupt when a turn is queued
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.
Summary
On the desktop app (reproduced on macOS), sending a message while the agent is busy queues a follow-up — but then the Stop button never actually interrupts the running turn. Clicking the arrow/Stop button after queuing keeps the agent running on the queued prompt instead of halting.
Root cause
Two cooperating bits of logic in
apps/desktop/src/app/chat/composer/:submitDraftStop branch. When busy with an empty composer (the state right after a follow-up has been queued and the composer cleared), the primary button shows the Stop square. But clicking it raninterruptAndSendNextQueued()— cancel the turn and immediately re-send the head of the queue. So Stop never stopped; it just swapped which prompt the agent was running.Auto-drain on settle. The
busy: true → falseeffect unconditionally re-sent the next queued prompt. Even a pureonCancel()would flipbusyfalse and the queue would auto-fire. The user could never halt while anything was queued.Net effect: the Stop affordance lied — it rendered as a Stop square but behaved as "interrupt, then keep going."
Fix
onCancel(). It no longer hijacks the queue.userInterruptedRefso thebusy → falseauto-drain skips exactly one drain. Queued turns are preserved; the user resumes them deliberately —Cmd/Ctrl+K,Enteron an empty composer, or the per-row "send now" arrow — matching the documented affordances (Esc= cancel run,Cmd+K= send next queued).shouldAutoDrainOnSettle()helper incomposer-queue.tsso the invariant is explicit and testable.interruptAndSendNextQueued.Enterwhile busy and the Stop button now behave identically (both interrupt), which is the intended "cancel run" semantics.Test plan
New unit tests in
composer-queue.test.tscovershouldAutoDrainOnSettle:Manual repro before/after on the desktop composer: