# Cancellation Your users can stop an agent mid-response without breaking the session. AI Transport sends cancel as a signal on the channel, so other turns continue and the session stays open. Cancellation is a turn-level operation. The client publishes a cancel signal on the Ably channel; the server matches it against active turns and fires their abort signals. Unlike closing an HTTP connection, cancellation is an explicit signal: the session remains intact, other turns continue, and both sides handle cleanup gracefully. A minimal cancel: #### Javascript ``` await transport.cancel(); ``` ## How it works Sessions are bidirectional, so a cancel is just a signal on the channel. The client publishes a cancel message with a filter specifying which turns to cancel. The server's transport matches the filter against active turns and fires their abort signals. The LLM stream stops, the turn ends with reason `'cancelled'`, and every subscriber receives the lifecycle update. ### Javascript ``` // Client: cancel the current turn await turn.cancel(); // Server: abort signal fires automatically const result = streamText({ abortSignal: turn.abortSignal, }); ``` ## Cancel filters Cancel signals are scoped. You control which turns are cancelled: | Filter | Effect | Use case | | --- | --- | --- | | `{ own: true }` (default) | Cancel all turns started by this client. | Stop button. | | `{ turnId: 'abc' }` | Cancel one specific turn. | Cancel a specific generation. | | `{ clientId: 'user-1' }` | Cancel all turns by a specific client. | Admin cancellation. | | `{ all: true }` | Cancel all turns on the channel. | Emergency stop. | ### Javascript ``` // Cancel your own turns (default) await transport.cancel(); // Cancel a specific turn await transport.cancel({ turnId: activeTurn.turnId }); // Cancel all turns on the channel await transport.cancel({ all: true }); ``` ## Server-side handling ### Abort signal Every turn exposes an `abortSignal` that fires when the turn is cancelled. Pass it to your LLM call: #### Javascript ``` const turn = transport.newTurn({ turnId, clientId }); await turn.start(); const result = streamText({ model: anthropic('claude-sonnet-4-20250514'), messages: history, abortSignal: turn.abortSignal, }); const { reason } = await turn.streamResponse(result.toUIMessageStream()); await turn.end(reason); ``` `reason` is `'cancelled'` when the abort fires. ### Authorise the cancel The `onCancel` hook authorises or rejects cancel requests: #### Javascript ``` const turn = transport.newTurn({ turnId, clientId, onCancel: async (request) => { const owner = request.turnOwners.get(request.filter.turnId); return owner === request.message.clientId; }, }); ``` The `CancelRequest` includes `message` (the raw cancel message with `clientId`), `filter` (parsed scope), `matchedTurnIds`, and `turnOwners` (map of turn ID to owner client ID). Return `false` to reject. If `onCancel` is not provided, all cancel requests are accepted. ### Hook into the abort The `onAbort` hook runs after the abort signal fires, giving you a chance to publish final events before the stream closes: #### Javascript ``` const turn = transport.newTurn({ turnId, clientId, onAbort: async (write) => { await write({ type: 'text-delta', textDelta: '\n[Response cancelled]' }); }, }); ``` ## Cancel on close When a client transport closes, it optionally cancels its own turns: ### Javascript ``` await transport.close({ cancel: { own: true } }); ``` ## Edge cases and unhappy paths - Cancellation is asynchronous. A few more tokens arrive after `cancel()` returns and before the server's `abortSignal` fires. Render them on the cancelled turn. - The server is responsible for honouring the abort signal. A tool invocation that does not check the signal continues to run until it completes. - Cancel signals from a client without the channel [publish capability](https://ably.com/docs/auth/capabilities.md?source=llms.txt#capability-operations) will silently fail. Verify capabilities on the [authentication](https://ably.com/docs/ai-transport/concepts/authentication.md?source=llms.txt) endpoint. - An `onCancel` that returns `false` does not notify the requesting client. Surface the rejection through your own application protocol if the user needs to know. - A cancel sent before the turn starts is delivered to the channel and accumulated; the server applies it as soon as the turn is created. ## FAQ ### Why use cancel signals instead of closing the connection? Closing the connection disconnects a client from the session. The session and connection are distinct and not coupled. A cancel signal notifies the agent to stop the stream but leaves the session intact, so the next message starts a new turn immediately, on every connected device. See [reconnection and recovery](https://ably.com/docs/ai-transport/features/reconnection-and-recovery.md?source=llms.txt) for how clients that disconnect mid-stream can reconnect and resume. ### Can a user on another device cancel my turn? Yes, if your `onCancel` hook authorises it. The default accepts all cancel requests. See the authorisation pattern above to scope it to the turn owner. ### What happens if multiple cancel signals match the same turn? The turn cancels once. Subsequent matching signals are no-ops; the abort signal does not refire. ### How do I tell a cancelled turn apart from one that finished normally? `turn.end(reason)` reports the reason on the channel. Clients receive it through the view's turn-end event. The reason is `'cancelled'` for a cancel and `'complete'` for a normal finish. ### Does cancel cost a message? The cancel signal is a published message on the channel. See [pricing](https://ably.com/docs/platform/pricing.md?source=llms.txt) for current rates. ## Related features - [Interruption](https://ably.com/docs/ai-transport/features/interruption.md?source=llms.txt): cancel and immediately send a new message. - [Concurrent turns](https://ably.com/docs/ai-transport/features/concurrent-turns.md?source=llms.txt): multiple turns with independent cancel handles. - [Token streaming](https://ably.com/docs/ai-transport/features/token-streaming.md?source=llms.txt): what gets cancelled when the abort fires. ## Related Topics - [Token streaming](https://ably.com/docs/ai-transport/features/token-streaming.md?source=llms.txt): Stream AI-generated tokens to clients in realtime using AI Transport, with support for message-per-response and message-per-token patterns. - [Reconnection and recovery](https://ably.com/docs/ai-transport/features/reconnection-and-recovery.md?source=llms.txt): AI Transport streams survive connection drops automatically. Clients reconnect and resume from where they left off with no lost tokens. - [Multi-device sessions](https://ably.com/docs/ai-transport/features/multi-device.md?source=llms.txt): Share AI conversations across tabs, phones, and laptops with Ably AI Transport. All devices see the same session in real time. - [History and replay](https://ably.com/docs/ai-transport/features/history.md?source=llms.txt): Load conversation history from Ably channels with AI Transport. Paginated history, gapless continuity, and scroll-back patterns. - [Conversation branching](https://ably.com/docs/ai-transport/features/branching.md?source=llms.txt): Edit user messages, regenerate AI responses, and navigate branches with Ably AI Transport. The full history is preserved as a tree. - [Interruption](https://ably.com/docs/ai-transport/features/interruption.md?source=llms.txt): Let users interrupt AI agents mid-stream with Ably AI Transport. Cancel-then-send and send-alongside patterns for responsive AI interactions. - [Concurrent turns](https://ably.com/docs/ai-transport/features/concurrent-turns.md?source=llms.txt): Run multiple AI turns simultaneously with Ably AI Transport. Independent streams, scoped cancellation, and multi-agent support. - [Tool calling](https://ably.com/docs/ai-transport/features/tool-calling.md?source=llms.txt): Stream tool invocations and results through Ably AI Transport. Server-executed and client-executed tools with persistent state. - [Human-in-the-loop](https://ably.com/docs/ai-transport/features/human-in-the-loop.md?source=llms.txt): Add human approval gates to AI agent workflows with Ably AI Transport. Approve tool executions and provide input across devices. - [Optimistic updates](https://ably.com/docs/ai-transport/features/optimistic-updates.md?source=llms.txt): User messages appear instantly in Ably AI Transport. Optimistic insertion with automatic reconciliation when the server confirms. - [Agent presence](https://ably.com/docs/ai-transport/features/agent-presence.md?source=llms.txt): Show agent status in your AI application with Ably Presence. Display streaming, thinking, idle, and offline states in real time. - [Push notifications](https://ably.com/docs/ai-transport/features/push-notifications.md?source=llms.txt): Notify users when AI agents complete background tasks with Ably Push Notifications. Reach users even when they're offline. - [Chain of thought](https://ably.com/docs/ai-transport/features/chain-of-thought.md?source=llms.txt): Stream reasoning and thinking content alongside responses with Ably AI Transport. Display chain-of-thought in real time. - [Double texting](https://ably.com/docs/ai-transport/features/double-texting.md?source=llms.txt): Handle users sending multiple messages while the AI is streaming with Ably AI Transport. Queue or run messages concurrently. ## Documentation Index To discover additional Ably documentation: 1. Fetch [llms.txt](https://ably.com/llms.txt?source=llms.txt) for the canonical list of available pages. 2. Identify relevant URLs from that index. 3. Fetch target pages as needed. Avoid using assumed or outdated documentation paths.