# UIMessageCodec `UIMessageCodec` is the pre-built codec for the Vercel AI SDK. It implements [`Codec`](https://ably.com/docs/ai-transport/api/javascript/core/codec.md) so a session can encode `UIMessageChunk` events out and decode them back into `UIMessage` objects without a custom implementation. You rarely import `UIMessageCodec` directly. The Vercel-pre-bound [`createClientSession`](https://ably.com/docs/ai-transport/api/javascript/vercel/chat-transport.md#create-client-session) and [`createAgentSession`](https://ably.com/docs/ai-transport/api/javascript/vercel/chat-transport.md#create-agent-session) already supply it. Import it explicitly when you build a codec wrapper, run the encoder or decoder outside of a session, or compose `UIMessageCodec` into a different codec. #### Javascript ``` import { UIMessageCodec } from '@ably/ai-transport/vercel'; const decoder = UIMessageCodec.createDecoder(); const projection = UIMessageCodec.init(); ``` ## Properties `UIMessageCodec` is a value, not a type. It satisfies the full [`Codec`](https://ably.com/docs/ai-transport/api/javascript/core/codec.md) interface for the Vercel `TInput`, `TOutput`, `TProjection`, and `TMessage` parameters listed below. | Property | Description | Type | | --- | --- | --- | | init | Build an empty `VercelProjection`. | `() => VercelProjection` | | fold | Fold a `VercelInput` or `VercelOutput` into the projection. | `(state, event, meta) => VercelProjection` | | createEncoder | Create a Vercel encoder bound to the supplied channel writer. | `(channel, options?) => Encoder` | | createDecoder | Create a Vercel decoder for the channel. | `() => Decoder` | | getMessages | Extract `{ codecMessageId, message }` pairs from a `VercelProjection`. The domain `UIMessage.id` is preserved verbatim from the source stream; the SDK keys correlation off the paired `codecMessageId`. | `(projection) => CodecMessage[]` | | createUserMessage | Wrap a `UIMessage` as the `UserMessage` input variant. | `(message: UIMessage) => VercelInput` | | createRegenerate | Build a `Regenerate` input targeting an assistant `UIMessage`. | `(target, parent) => VercelInput` | | createToolResult | Build a `ToolResult` input addressed at the assistant codec-message that contains the tool call. | `(codecMessageId, { toolCallId, output }) => VercelInput` | | createToolResultError | Build a `ToolResultError` input. | `(codecMessageId, { toolCallId, message }) => VercelInput` | | createToolApprovalResponse | Build a `ToolApprovalResponse` input. | `(codecMessageId, { toolCallId, approved, reason? }) => VercelInput` |
## Type parameters | Property | Description | Type | | --- | --- | --- | | TInput | Discriminated union of every record-shape a client publishes on the `ai-input` wire. Composed from the SDK's well-known input variants, with the tool variants parameterised by the Vercel domain payload shapes (`VercelToolResultPayload`, `VercelToolResultErrorPayload`, `VercelToolApprovalResponsePayload`). | `UserMessage \| Regenerate \| ToolResult \| ToolResultError \| ToolApprovalResponse` |
| Property | Description | Type | | --- | --- | --- | | TOutput | Every record-shape the agent publishes on the `ai-output` wire. The codec passes Vercel's `UIMessageChunk` through unchanged. | `AI.UIMessageChunk` |
| Property | Description | Type | | --- | --- | --- | | TProjection | Per-Run projection. Carries the `{ codecMessageId, message }` pair list plus internal stream-tracker state and a high-water-mark serial for idempotency. The SDK does not inspect this shape. Reach for `getMessages` instead. | `{ messages: CodecMessage[], ... }` |
The well-known input variants ([`UserMessage`](https://ably.com/docs/ai-transport/api/javascript/core/codec.md#user-message), [`Regenerate`](https://ably.com/docs/ai-transport/api/javascript/core/codec.md#regenerate), [`ToolResult`](https://ably.com/docs/ai-transport/api/javascript/core/codec.md#tool-result), [`ToolResultError`](https://ably.com/docs/ai-transport/api/javascript/core/codec.md#tool-result-error), [`ToolApprovalResponse`](https://ably.com/docs/ai-transport/api/javascript/core/codec.md#tool-approval-response)) are documented on the [`Codec` reference page](https://ably.com/docs/ai-transport/api/javascript/core/codec.md#input-variants). The Vercel codec layers no extra input variants. ## Example Decode a single Ably message and fold the resulting events into a fresh projection. `ReducerMeta.serial` is required (the reducer uses it as the high-water-mark for idempotency); the `messageId` field is optional and only needed when the codec routes events to an existing message. ### Javascript ``` import { UIMessageCodec } from '@ably/ai-transport/vercel'; const decoder = UIMessageCodec.createDecoder(); let projection = UIMessageCodec.init(); channel.subscribe((message) => { if (!message.serial) return; // live channel-subscribe messages always carry one const { inputs, outputs } = decoder.decode(message); for (const input of inputs) { projection = UIMessageCodec.fold(projection, input, { serial: message.serial }); } for (const output of outputs) { projection = UIMessageCodec.fold(projection, output, { serial: message.serial }); } render(UIMessageCodec.getMessages(projection).map((entry) => entry.message)); }); ``` ## Related Topics - [Chat transport](https://ably.com/docs/ai-transport/api/javascript/vercel/chat-transport.md): API reference for the AI Transport Vercel ChatTransport adapter and the Vercel-bound createClientSession and createAgentSession factories. - [Run outcome](https://ably.com/docs/ai-transport/api/javascript/vercel/run-outcome.md): API reference for vercelRunOutcome, the helper that maps a Vercel streamText finishReason and Run.pipe result to a RunEndReason or a 'suspend' sentinel. ## Documentation Index To discover additional Ably documentation: 1. Fetch [llms.txt](https://ably.com/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.