How is abort instant if it talks to provider?

HEAD
c55ae2ffix(coding-agent): display path of sibling dependent extensions (#6964)
This post might have stale content, as HEAD is 32 commits ahead.

how is abort instant? if presumably, it's talking to the provider server?

Avatar of anthropic/claude-opus-4.7
Claude Opus 4.7
commented

Good — I now have a complete picture. Let me give a well-grounded answer.

##Why abort feels instant

Abort is instant on the client side — it doesn't need the provider server to acknowledge or respond. Here's the flow:

###1. The Agent owns an AbortController

In packages/agent/src/agent.ts, every run creates a fresh AbortController (line 476):

const abortController = new AbortController();
// ...
this.activeRun = { promise, resolve: resolvePromise, abortController };

The public abort() method just fires it (line 312):

abort(): void {
    this.activeRun?.abortController.abort();
}

Calling .abort() on an AbortController is a synchronous, local, in-process operation — it flips a boolean and dispatches an "abort" event on the signal. Nothing hits the network.

###2. The signal is threaded everywhere

The controller's signal is passed into executor(abortController.signal) (line 488), which in turn passes it to runAgentLoop(..., signal, streamFunction). It reaches the provider request options (e.g. in packages/ai/src/api/anthropic-messages.ts):

const requestOptions = {
    ...(options?.signal ? { signal: options.signal } : {}),
    // ...
};

###3. Two things happen "instantly" from the user's perspective

(a) The fetch/HTTP layer: Node's fetch/SDKs honor AbortSignal — when aborted, they immediately reject the pending promise and tear down the socket locally. There's no round-trip; the client just drops the connection (sends TCP RST/FIN eventually, but doesn't wait on it).

(b) The SSE consumer loop: The stream reader checks signal.aborted on every iteration (anthropic-messages.ts:395):

while (true) {
    if (signal?.aborted) {
        throw new Error("Request was aborted");
    }
    // ...
}

So even any bytes already buffered are discarded on the next tick.

###4. The UI reflects it immediately

In interactive-mode.ts, pressing Esc during streaming calls this.agent.abort() (line 3968), and the stop reason gets flipped to "aborted" (see anthropic-messages.ts:751output.stopReason = options?.signal?.aborted ? "aborted" : "error"), which the UI renders as "Operation aborted" (line 2957).

###TL;DR

Abort doesn't "talk to" the provider — it's a purely local signal that (1) rejects the in-flight HTTP promise, (2) short-circuits the SSE read loop, and (3) marks the message as aborted, all synchronously in the client. The server keeps generating for a bit until it notices the closed connection, but the user doesn't have to wait for that.


END OF POST

How is abort instant if it talks to provider? — earendil-works/pi