# 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.