ChatTransport

The Vercel entry point pre-binds the UIMessageCodec and exposes a ChatTransport adapter that satisfies the contract Vercel AI SDK's useChat hook expects. Use these factories whenever you build a chat UI on top of useChat so you do not have to wire the codec yourself.

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

import * as Ably from 'ably';
import { createClientSession, createChatTransport } from '@ably/ai-transport/vercel';

const ably = new Ably.Realtime({ authUrl: '/api/auth/token' });

const session = createClientSession({
  client: ably,
  channelName: 'conversation-42',
});

await session.connect();

const chatTransport = createChatTransport(session);

React-side wiring (ChatTransportProvider, useChatTransport, useMessageSync) lives at @ably/ai-transport/vercel/react.

Create a Vercel client session

function createClientSession(options: VercelClientSessionOptions): ClientSession<VercelInput, VercelOutput, VercelProjection, UIMessage>

A pre-bound version of the core createClientSession with codec: UIMessageCodec already supplied. The api default is set on createChatTransport, not here.

JavaScript

1

2

3

4

5

6

7

8

9

import * as Ably from 'ably';
import { createClientSession } from '@ably/ai-transport/vercel';

const ably = new Ably.Realtime({ authUrl: '/api/auth/token' });

const session = createClientSession({
  client: ably,
  channelName: 'conversation-42',
});

Parameters

clientrequiredAbly.Realtime
The Ably Realtime client. The caller owns its lifecycle. The session's identity is read from this client's auth.clientId at publish time and stamped on everything it publishes.
channelNamerequiredString
The channel to subscribe to and publish cancel signals on.
channelModesoptionalAbly.ChannelMode[]
Extra channel modes to request on top of the modes AI Transport always needs. Pass OBJECT_MODES to use Ably LiveObjects.
historyPageSizeoptionalNumber
Wire-message limit fetched per channel-history round trip when paging older history. Defaults to 100.
loggeroptionalLogger
Logger instance for diagnostic output.

Returns

ClientSession<VercelInput, VercelOutput, VercelProjection, UIMessage>. A client session whose codec is pre-bound to UIMessageCodec.

Create a Vercel agent session

function createAgentSession(options: VercelAgentSessionOptions): AgentSession<VercelOutput, VercelProjection, UIMessage>

A pre-bound version of the core createAgentSession with codec: UIMessageCodec already supplied. Construct one inside your HTTP handler when the request arrives.

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

import * as Ably from 'ably';
import { Invocation } from '@ably/ai-transport';
import { createAgentSession } from '@ably/ai-transport/vercel';

const ably = new Ably.Realtime({ key: process.env.ABLY_API_KEY });

const invocation = Invocation.fromJSON(await req.json());

const session = createAgentSession({
  client: ably,
  channelName: invocation.sessionName,
});

Parameters

clientrequiredAbly.Realtime
The Ably Realtime client. The caller owns its lifecycle.
channelNamerequiredString
The channel to publish to.
channelModesoptionalAbly.ChannelMode[]
Extra channel modes to request on top of the modes AI Transport always needs. Pass OBJECT_MODES to use Ably LiveObjects.
historyPageSizeoptionalNumber
Wire-message limit fetched per channel-history round trip, used by every run.view pagination on this session. Defaults to 100.
loggeroptionalLogger
Logger instance for diagnostic output.

Subscribe to non-fatal session-level errors with session.on('error') rather than a constructor option.

Returns

AgentSession<VercelOutput, VercelProjection, UIMessage>. An agent session whose codec is pre-bound to UIMessageCodec.

Create a chat transport

function createChatTransport(session: ClientSession<VercelInput, VercelOutput, VercelProjection, UIMessage>, chatOptions?: ChatTransportOptions): ChatTransport

Wrap a ClientSession in a ChatTransport adapter that satisfies Vercel AI SDK's useChat transport option. The adapter maps useChat's sendMessages and reconnectToStream contract onto the session's view.send, view.regenerate, and tool-resolution paths.

JavaScript

1

2

3

4

5

6

7

8

9

10

import { useChat } from '@ai-sdk/react';
import { createChatTransport } from '@ably/ai-transport/vercel';

const chatTransport = createChatTransport(session, {
  prepareSendMessagesRequest: ({ history }) => ({
    body: { history },
  }),
});

const chat = useChat({ transport: chatTransport });

Parameters

sessionrequiredClientSession<VercelInput, VercelOutput, VercelProjection, UIMessage>
The core client session to wrap.
chatOptionsoptionalChatTransportOptions
Hooks for customising request construction.

Returns

ChatTransport. The adapter to pass to useChat's transport option.

ChatTransport

The transport adapter returned by createChatTransport. Structurally compatible with the AI SDK's internal ChatTransport<UIMessage> interface, extended with close(), streaming, and onStreamingChange for coordinating with useMessageSync.

Properties

sendMessages(options) => Promise<ReadableStream<UIMessageChunk>>
Send messages and return a ReadableStream of UIMessageChunk events.
reconnectToStream(options) => Promise<ReadableStream<UIMessageChunk> | null>
Reconnect to an existing streaming response. Returns null because observer mode handles in-progress streams automatically.
close() => Promise<void>
Close the underlying transport, releasing all resources.
streamingBoolean
Whether an own-run stream is currently being consumed by useChat.
onStreamingChange(callback: (streaming: boolean) => void) => () => void
Subscribe to streaming state changes. Used by useMessageSync to gate setMessages calls during active streams.

Example

End-to-end client-side wiring: open a session, wrap it in a chat transport, and hand it to useChat.

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

import * as Ably from 'ably';
import { useChat } from '@ai-sdk/react';
import { createClientSession, createChatTransport } from '@ably/ai-transport/vercel';

const ably = new Ably.Realtime({ authUrl: '/api/auth/token' });

const session = createClientSession({
  client: ably,
  channelName: 'conversation-42',
});

await session.connect();

const chatTransport = createChatTransport(session, {
  prepareSendMessagesRequest: ({ history, messages }) => ({
    body: { history, messages },
  }),
});

function Chat() {
  const { messages, sendMessage } = useChat({ transport: chatTransport });
  return (
    <>
      {messages.map((m) => (
        <Message key={m.id} message={m} />
      ))}
      <Composer onSubmit={(text) => sendMessage({ role: 'user', parts: [{ type: 'text', text }] })} />
    </>
  );
}