Client transport API

Open in

The client transport subscribes to an Ably channel, decodes incoming messages through a codec, and builds a conversation tree. It provides views for paginated, branch-aware access to the conversation, and methods for cancellation and turn tracking.

Import from the core entry point:

JavaScript

1

import { createClientTransport } from '@ably/ai-transport'

Or use the Vercel entry point which pre-binds the codec.

createClientTransport

Factory function that creates a ClientTransport instance.

JavaScript

1

function createClientTransport(options: ClientTransportOptions): ClientTransport

ClientTransportOptions

PropertyRequiredTypeDescription
channelrequiredAbly.RealtimeChannelThe Ably channel for the session.
codecrequiredCodec<TEvent, TMessage>Codec for encoding and decoding messages. See Codec API.
clientIdoptionalstringThe client ID for this transport instance. Used for scoping cancel signals and identifying user messages.
apioptionalstringURL of the API endpoint to send user messages to. Defaults to "/api/chat".
headersoptionalRecord<string, string> | (() => Record<string, string>)Additional HTTP headers to include in API requests. Use the function form for dynamic values such as auth tokens.
bodyoptionalRecord<string, unknown> | (() => Record<string, unknown>)Additional fields to merge into the API request body. Use the function form for dynamic values.
credentialsoptionalRequestCredentialsCredentials mode for the fetch request ('include', 'same-origin', 'omit').
fetchoptionaltypeof globalThis.fetchCustom fetch implementation. Defaults to globalThis.fetch.
messagesoptionalTMessage[]Initial messages to seed the conversation tree with. Forms a linear chain.
loggeroptionalLoggerLogger instance for debug output.

ClientTransport

The ClientTransport object returned by the factory.

tree

The underlying conversation tree. The tree contains every message received on the channel, organized into branches.

JavaScript

1

const tree = transport.tree

view

The default View for the transport. Created automatically when the transport is instantiated.

JavaScript

1

const view = transport.view

createView

Create an additional View of the conversation tree. Each view maintains its own branch selection and pagination state.

JavaScript

1

function createView(): View<TEvent, TMessage>

Use multiple views when you need different perspectives on the same conversation, for example a main chat panel and a sidebar showing an alternative branch.

cancel

Publish a cancel signal on the channel. The optional filter scopes which turns are cancelled.

JavaScript

1

function cancel(filter?: CancelFilter): Promise<void>
Filter propertyTypeEffect
owntrueCancel all turns started by this client (default).
turnIdstringCancel one specific turn.
clientIdstringCancel all turns by a specific client.
alltrueCancel all active turns on the channel.

When called with no argument, cancel() defaults to { own: true }.

waitForTurn

Wait for active turns matching the given filter to complete. Returns a promise that resolves when all matching turns have ended. Resolves immediately if no matching turns are active. Defaults to { own: true }.

JavaScript

1

function waitForTurn(filter?: CancelFilter): Promise<void>

on('error')

Subscribe to transport-level errors.

JavaScript

1

2

3

transport.on('error', (error: ErrorInfo) => {
  console.error('Transport error:', error)
})

close

Close the transport and release resources. Optionally cancel active turns before closing.

JavaScript

1

function close(options?: CloseOptions): Promise<void>

View

A View is a paginated, branch-aware projection of the conversation tree. It tracks which branch is selected at each fork point and supports lazy loading of older messages.

getMessages

Return the visible domain messages along the selected branch.

JavaScript

1

function getMessages(): TMessage[]

flattenNodes

Return the visible nodes along the selected branch, filtered by the pagination window. Each node wraps the domain message with tree metadata.

JavaScript

1

function flattenNodes(): MessageNode<TMessage>[]

hasOlder

Whether there are older messages that can be loaded or revealed.

JavaScript

1

function hasOlder(): boolean

send

Send one or more user messages and start a new turn. Messages are optimistically inserted into the tree. The parent is auto-computed from the view's selected branch unless overridden in options. Returns an ActiveTurn handle for the server's response stream.

JavaScript

1

function send(messages: TMessage | TMessage[], options?: SendOptions): Promise<ActiveTurn<TEvent>>

regenerate

Regenerate an assistant message. Creates a new turn that forks the target message with no new user messages. Automatically computes forkOf, parent, and truncated history from the view's branch.

JavaScript

1

function regenerate(messageId: string, options?: SendOptions): Promise<ActiveTurn<TEvent>>

edit

Edit a user message and regenerate from that point. Creates a new turn that forks the target message with replacement content. Automatically computes forkOf, parent, and history from the view's branch.

JavaScript

1

function edit(messageId: string, newMessages: TMessage | TMessage[], options?: SendOptions): Promise<ActiveTurn<TEvent>>

update

Update an existing message and start a continuation turn. The local tree is updated optimistically, then the events are sent to the server in the POST body. The server publishes them to the channel and streams a continuation response.

JavaScript

1

function update(msgId: string, events: TEvent[], options?: SendOptions): Promise<ActiveTurn<TEvent>>

loadOlder

Load older messages from channel history. Loads from history if the tree does not have enough messages, then advances the pagination window.

JavaScript

1

function loadOlder(limit?: number): Promise<void>

select

Select a sibling at a fork point by index. Updates the view's branch selection. The index is clamped to [0, siblings.length - 1].

JavaScript

1

function select(msgId: string, index: number): void

getSelectedIndex

Get the index of the currently selected sibling at a fork point.

JavaScript

1

function getSelectedIndex(msgId: string): number

getSiblings

Get all messages that are siblings at a given fork point, ordered chronologically by serial.

JavaScript

1

function getSiblings(msgId: string): TMessage[]

hasSiblings

Whether a message has sibling alternatives at its fork point.

JavaScript

1

function hasSiblings(msgId: string): boolean

getNode

Get a node by its message ID, or undefined if not found.

JavaScript

1

function getNode(msgId: string): MessageNode<TMessage> | undefined

getActiveTurnIds

Get active turn IDs for turns with visible messages, grouped by client ID.

JavaScript

1

function getActiveTurnIds(): Map<string, Set<string>>

on

Subscribe to view events. Each handler returns an unsubscribe function.

JavaScript

1

2

3

4

5

6

7

8

// Fired when the visible message list changes (new message, branch switch, window shift)
const unsubscribe = view.on('update', () => { })

// Fired when a raw Ably message arrives for a visible node
view.on('ably-message', (msg: Ably.InboundMessage) => { })

// Fired when a turn starts or ends for a turn with visible messages
view.on('turn', (event: TurnLifecycleEvent) => { })

close

Tear down the view. Unsubscribes from tree events and clears internal state.

JavaScript

1

function close(): void

ActiveTurn

A handle to an active client-side turn, returned by send(), regenerate(), edit(), and update().

PropertyTypeDescription
streamReadableStream<TEvent>The decoded event stream for this turn.
turnIdstringThe unique identifier for this turn.
cancel() => Promise<void>Cancel this specific turn. Publishes a cancel message and closes the local stream.

SendOptions

Per-send options for customizing the HTTP POST and branching metadata.

PropertyRequiredTypeDescription
headersoptionalRecord<string, string>Additional HTTP headers for this request.
bodyoptionalRecord<string, unknown>Additional fields to merge into the request body.
forkOfoptionalstringThe msg-id of the message this send replaces (creates a fork).
parentoptionalstring | nullThe msg-id of the preceding message in the conversation thread. null means the message is a root. If omitted, auto-computed from the last message in the view.

CloseOptions

PropertyTypeDescription
cancelCancelFilterCancel in-progress turns before closing. Publishes a cancel message to the channel.

MessageNode

A node in the conversation tree, representing a single domain message.

PropertyTypeDescription
kind'message'Discriminator identifying this as a message node.
messageTMessageThe domain message.
msgIdstringThe x-ably-msg-id of this node. Primary key in the tree.
parentIdstring | undefinedParent node's msg-id, or undefined for root messages.
forkOfstring | undefinedThe msg-id this node forks from, or undefined if first version.
headersRecord<string, string>Full Ably headers for this message.
serialstring | undefinedAbly serial for ordering. Absent for optimistic messages.

TurnLifecycleEvent

A structured event describing a turn starting or ending.

JavaScript

1

2

3

type TurnLifecycleEvent =
  | { type: 'x-ably-turn-start'; turnId: string; clientId: string }
  | { type: 'x-ably-turn-end'; turnId: string; clientId: string; reason: TurnEndReason }

TurnEndReason

JavaScript

1

type TurnEndReason = 'complete' | 'cancelled' | 'error'

CancelFilter

Filter for cancel operations. At most one field should be set.

PropertyTypeDescription
turnIdstringCancel a specific turn by ID.
ownbooleanCancel all turns belonging to the sender's client ID.
clientIdstringCancel all turns belonging to a specific client ID.
allbooleanCancel all turns on the channel.