Sessions and turns

Open in

Sessions and turns are the two core concepts in AI Transport. A session is the conversation between agents and clients. A turn is one prompt-response cycle within that conversation.

Sessions

A session is an Ably channel. It represents the ongoing conversation between one or more agents and one or more clients, including its full history. Every participant on the channel sees every message: user prompts, agent responses, cancel signals.

Because a session is a channel rather than a connection, it survives disconnections. If a client drops off, the agent keeps publishing tokens. When the client reconnects, Ably's connection protocol resumes from the last received message. If the client has been offline longer, it loads the conversation from channel history.

Multiple devices can join the same session. Open a second tab, switch to your phone, hand the session to a colleague. They all see the same conversation in real time.

JavaScript

1

2

const channel = ably.channels.get('my-session')
const transport = useClientTransport({ channel, codec: UIMessageCodec })

Turns

Each user prompt to the agent is wrapped as a turn. A turn contains the user's message and the agent's response, with clear start and end boundaries.

Without turns, you'd have a flat stream of tokens with no structure. You couldn't cancel one response without killing the connection or distinguish between two concurrent responses. Turns group tokens into units you can track, cancel, and replay individually.

Server-side lifecycle

On the server, you control the turn lifecycle explicitly:

  1. transport.newTurn({ turnId, clientId }) creates the turn.
  2. turn.addMessages(messages) publishes the user's input to the channel.
  3. turn.streamResponse(stream) pipes LLM tokens through the codec to the channel.
  4. turn.end(reason) marks the turn as complete.

A turn ends with one of three reasons: 'complete', 'cancelled', or 'error'.

Client-side lifecycle

On the client, turns are implicit. Calling view.send(messages) creates a turn and returns an ActiveTurn:

JavaScript

1

2

3

const turn = await view.send([userMessage])
turn.stream   // ReadableStream of decoded events
turn.cancel() // Cancel this turn only

Concurrent turns

Multiple turns can be active at the same time, each with independent streams and cancel handles. See concurrent turns for details.

Cancellation

Cancel signals are scoped to specific turns. Filters can target a single turn by ID, all turns from a specific client, your own turns, or all turns. The server can authorize or reject cancel requests via the onCancel hook. See cancellation for details.