Interruption is the most human act in conversation. People cut each other off constantly, benignly, productively — I've heard enough, that reminds me, no, wait, I meant the other one — and a conversation without it isn't polite, it's a sequence of voicemails. Software has historically taken the voicemail position: while output is in progress, input is an error. The button greys out. The spinner spins. Please wait.
An assistant you talk to — by voice, or in the rapid half-sentences of real chat — cannot take that position, because its output is long. A streamed answer runs for seconds to minutes; a spoken one longer. If the only legal move during that window is waiting, then every misunderstanding runs to completion, every wrong direction is fully explored at your expense, and the product feels like exactly what it is: a request/response system wearing a conversational costume. So this phase's work was to make interruption a first-class input — and the first discovery is that "interruption" is not one thing. It is three, with three different meanings, and conflating them is how interruption UX goes wrong.
Stop: "that's enough"
The plainest interruption gets the plainest control: while the agent streams, the Send button becomes a Stop button — same slot, same footprint, nothing shifts — and tapping it ends the turn. The semantics took more care than the button.
Stopping is a decision, not a failure. Whatever text already streamed stays in the thread as a completed message — nothing is rolled back, nothing turns red, no error bubble apologises. The user chose to end it; the record reflects a choice, not a malfunction. The stop is real, not cosmetic. An aborted browser request only ends the local view; the model would keep generating — and billing — into a connection nobody is listening to. So Stop is an explicit endpoint call that reaches the pod and aborts the in-flight model stream itself. And the abort has a defined granularity — cooperative cancellation: the signal is checked between loop iterations and before each tool call, never inside a tool's I/O. Token streaming halts almost instantly; a tool already executing runs to completion and its effect persists. That last rule is the honest answer to "what happens to a half-finished turn": the words stop where they stopped, and the actions that had already happened, happened. An interruption model that pretended to un-send an email would be lying about the arrow of time.
The counterpart rule surprised people we showed it to, and we defend it: closing the tab does not stop the turn. Leaving is not interrupting. Navigate away, refresh, lose the connection — the work continues server-side, completes, and is waiting in history when you return. Only the explicit act cancels. The alternative — inferring "stop" from a disconnect — punishes every flaky network and every accidental tab close with silently discarded work, and conflates the person who left with the person who objected. Those are different people.
Barge-in: "my turn now"
Voice raises the stakes, because a speaking assistant occupies the very channel you would object through. Here the borrowed vocabulary of telephony is exact: barge-in, the caller speaking over the prompt, is the universal signal for I've heard enough and want to respond — and a voice interface without it is a hold-music loop.
So playback yields to intent, everywhere intent shows up. Sending a new message cancels the current read-aloud mid-word — you have moved on, and the audio should too. A floating "stop reading" control appears only while speech is in progress, thumb-reachable, ending the audio without disabling read-aloud. Each message carries its own read control for stopping one utterance rather than the feature.
And one deliberate non-cancellation carries the design's judgment: the system's own follow-up messages — a clarify echo, a folder-read confirmation — do not barge in on the answer being read. Machinery messages are not the user's intent, and an assistant that cut off its own answer because its own plumbing spoke would be interrupting you to hear itself. Barge-in triggers on human acts only.
Changed my mind: the third kind
The third interruption is the richest: the user isn't rejecting the output, they are revising the input. "Pull the Q3 numbers" — "actually just EMEA" — "and compare to Q2" is one thought sent in three pieces, and classical turn-locking answers the first fragment alone while the rest bounces off a disabled composer. At this entry's date we could name the problem precisely and had settled the invariant any solution must keep: no message a user sends is ever silently dropped — grouping may flex, timing may flex, existence never does. The old single-slot queue violated exactly that, keeping only the last message sent during a stream, which is the worst possible semantics: an interruption model that loses interruptions.
The full answer — folding rapid messages into one settled thought, superseding a turn made stale by a correction — was designed but not yet built here, and the hard half was clear in advance: safely aborting a turn that may be mid-tool. Cancelling stale words is free; cancelling stale work requires knowing which tools are past the point of no return, which is an audit, not a feature flag. We refused to ship the elegant version before that audit existed.
What transfers
Give each interruption gesture defined semantics and implement the definitions, because "stop", "my turn", and "let me revise that" are different speech acts and a single cancel button flattens them into noise. Separate leaving from objecting — never infer intent from a disconnect. Put abort points at explicit safe positions in the loop and never inside a side-effect, then tell the truth about what a half-finished turn is: words stop, completed effects stand. Keep partials as first-class history rather than something to hide. And when the output channel is audio, make everything yield to genuine human intent and nothing yield to your own machinery — an assistant that talks over you is annoying, but one that interrupts itself is worse, because it teaches you that interruptions don't mean anything.
Postscript, August 2026. The third kind grew its machinery in stages, each honouring the never-drop invariant. Rapid messages now coalesce client-side into a single settled thought — a short settle window, one growing bubble, one answer to the whole burst — with a subtlety that only surfaced in use: a message carrying its own context (fresh files, a different quoted passage) is sealed out of the open burst rather than folded, because a fold that keeps only the latest attachments silently drops the earlier ones, and that is the forbidden failure wearing a convenience. Dictation joined the barge-in family: starting to speak now hushes the read-aloud in the same gesture, completing the telephony metaphor. And a stopped read now stays stopped for the whole of that message — the reply's continued streaming no longer restarts it, a regression fixed twice before it was pinned. Playback gained pause-and-resume in place. And server-side supersede — cancelling a stale in-flight turn on a corrective message — remains where this entry left it: designed, wanted, and gated on the safe-abort audit of which tools can be stopped and which have already touched the world. We still think refusing to guess about that boundary is the feature.