Repository navigation
Description
Problem (one or two sentences)
While a task is running, every message I send is queued and only read later — sometimes minutes later, after the model has finished thinking in a direction my message already overrode. The only way to make the model stop right now is the Stop button, but Stop ends the task (status: "interrupted") and does not send any message.
Context (who is affected and when)
Anyone who steers a task mid-flight: "actually, skip that and do X", correcting a wrong turn, or answering what the model is currently reasoning about. Today the cost is the model's entire remaining generation — minutes on long thinking/tool chains — plus the tokens spent on work the user already decided against. The longer the model runs, the more this bites.
Desired behavior (conceptual, not technical)
A new action — call it Interrupt & send:
- While the model is generating, I type a message and trigger "Interrupt & send" (a button next to the queue button; a keyboard shortcut would be nice).
- The in-flight model request stops immediately, and what it has already produced stays in the conversation with its cost recorded (Stop does this part today).
- The task does NOT end: it stays active, the model immediately reads my message, and the same task continues based on it.
- The plain Stop button keeps working exactly as it does today.
- The action is only offered when it is safe to interrupt — e.g., while the model is just generating, not mid-way through writing a file or running a command.
Constraints / preferences
- No data loss: the partial output, its cost, and anything already queued must not be silently dropped.
- No behavior changes for what exists: queueing while streaming, the Stop button, and queue draining at prompts all stay as-is.
- Keyboard accessible, and must not slow down normal sending.
- Exact UI is open for design: dedicated button, modifier key (e.g., Alt+Enter), or a "send now" action on individual queued messages.
Request checklist
- I've searched existing Issues and Discussions for duplicates
- This describes a specific problem with clear context and impact
Acceptance criteria
- Given a task is streaming, when I "Interrupt & send" a message, then the in-flight request stops within about a second, the partial output remains in history with its cost and a cancel reason, my message is in the conversation, and the task continues with status active.
- But the task is not marked "interrupted" and I do not have to reopen it.
- Given messages were already queued, when I interrupt & send, then [OPEN — community decision] only my message / my message plus the existing queue in order is delivered, with stable ordering and no duplicates.
- Given the model is mid-tool (writing a file / running a command), when [per the safety decision below], then the action is either unavailable or handles the partial side effects safely.
- A plain Stop still ends the task exactly as today; existing queue behavior is unchanged.
Proposed approach (plain language)
Stop already has the machinery to abort an in-flight model request while preserving the partial response and its cost; today that machinery is coupled to "end the task and mark it interrupted". A variant that interrupts only the current request, hands my message to the model, and resumes the normal task loop would close the gap. The message queue already exists (edit/delete, drain at prompts), so after the interrupt the feature just needs to deliver my message (and possibly the queue) into the resumed loop.
Trade-offs / risks
- Interrupting mid-tool: partial side effects (a half-written file, a running command) may have already happened. Options: offer only between model turns (safe, simple), or offer anytime and rely on the existing partial-write revert machinery.
- Races: double-clicks, or the turn finishing at the same instant — the action must be idempotent, never send the message twice, and never lose it.
- The queue is in-memory today; an extension reload mid-interrupt would lose queued messages (existing behavior, likely out of scope).
- Scope: VS Code webview first; CLI parity can be a follow-up.
Open questions for the community
- Where is it "safe" to interrupt — only while the model is generating, or also between tool calls?
- After the interrupt, what gets delivered: only my message, or mine plus the existing queue (in order)?
- UI: dedicated button, modifier key, or per-queued-message action?
- Keep the interrupted partial turn in history (my vote: yes — it is transparent about what the model thought and how much it cost), or discard it?
- Should the CLI get the same feature in v1, or webview only?
Related work — and how this differs
- [ENHANCEMENT] Add queue and steer delivery modes for running conversations #133 (open) proposes queue vs steer delivery modes. Steer delivers input "on the next opportunity after a tool call sequence is complete" — i.e., at API/tool boundaries. This request complements it: it covers the case steer does not, where the model is in the middle of a long pure generation with no upcoming boundary for minutes. The user wants the current request to stop now and the message read now, with the task continuing rather than ending. If the community prefers, this could be implemented as a third delivery mode (e.g.,
interrupt) inside [ENHANCEMENT] Add queue and steer delivery modes for running conversations #133's design, or kept as a standalone feature building on the same queue infrastructure. - Task Queue - Wait for Current Task Completion Before Submitting New Instructions #1054 (open) asks for a sequential "queue mode" so new instructions never interrupt a running task; this request is orthogonal (it adds an intentional, immediate interruption path).
Technical context (for maintainers — verified against current code, optional reading)
- Queue path: the webview routes sends into
queueMessagewhenever the task is streaming/blocked (webview-ui/src/components/chat/ChatView.tsx:659–677);queueMessage→webviewMessageHandler.ts:3753→Task.messageQueueService(src/core/message-queue/MessageQueueService.ts— in-memory, not persisted, cleared on task dispose; rendered bywebview-ui/src/components/chat/QueuedMessages.tsx). - The queue is drained today only at pending asks (
src/core/task/Task.ts:1299–1503,command_outputexcluded), after context condensing (Task.ts:1816), and viaprocessQueuedMessages()(Task.ts:5105). Nothing drains it while the model is purely generating — that is the gap. - Stop path to reuse:
ClineProvider.cancelTask()(src/core/webview/ClineProvider.ts:3497) callsTask.cancelCurrentRequest()(aborts the in-flightAbortController,Task.ts:2448) andTask.abortTask()(Task.ts:2467), which marks the task abandoned and persists history as "interrupted". The partial-turn finalization — finalizing the partial message, recording cost +cancelReasonon theapi_req_startedmessage, saving to disk — lives inabortStream()(Task.ts:2960) and is already independent of ending the task. - Sketch: a request-scoped interrupt that reuses
abortStream()finalization without theabandoned/interruptedside effects, then delivers the message via the existingsubmitUserMessage()(Task.ts:1641) / queue drain, and lets the main loop (Task.ts:2709) continue. The loop treatsthis.abortas the only stop condition and discriminates abort errors by message suffix (Task.ts:411–425), so an interrupted request must surface to the loop as a normal completed turn, not an error. ClineApiReqCancelReasonis"streaming_failed" | "user_cancelled"(packages/types/src/vscode-extension-host.ts:930); a third value would let telemetry/cost UI distinguish "interrupt & send" from Stop.
This issue was prepared with agentic AI assistance; every code reference was verified against the current codebase.
Activity
philbb commentedon Sep 4, 2026
My first instinct would be to not allow interrupting tools without explicit permission from the user. This is to avoid cases like file operations being interrupted destructively. Any thoughts?
philbb commentedon Sep 4, 2026
We also need a visual language to clearly let the user know what is happening.
For example a simple click on the (blue) stop button could queue an interruption after the next tool call, with a small message in italics saying so. Maybe then the stop button could turn red and a second click (on the red button) could force an immediate stop.
Please comment on whether you think this would be a good idea
WebMad commentedon Sep 29, 2026
Now that we have a steer queue, the current behavior makes sense for ZooCode. I think users expect queued messages to be sent only when the next turn is safe for processing a new message.
I think we should add an Interrupt & Send Now button next to the main Send button and also next to each queued message.
We should also add controls for changing the priority of queued messages:
thigger commentedon Nov 10, 2026
I had a try with hermes agent the other day, which seems to work like this by default and the model handled it surprisingly well