UIMessageCodec
UIMessageCodec is the pre-built codec for the Vercel AI SDK. It implements Codec<VercelInput, VercelOutput, VercelProjection, UIMessage> 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 and createAgentSession 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.
1
2
3
4
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 interface for the Vercel TInput, TOutput, TProjection, and TMessage parameters listed below.
init() => VercelProjectionVercelProjection.fold(state, event, meta) => VercelProjectionVercelInput or VercelOutput into the projection.createEncoder(channel, options?) => Encoder<VercelInput, VercelOutput>createDecoder() => Decoder<VercelInput, VercelOutput>getMessages(projection) => CodecMessage<UIMessage>[]{ 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.createUserMessage(message: UIMessage) => VercelInputUIMessage as the UserMessage input variant.createRegenerate(target, parent) => VercelInputRegenerate input targeting an assistant UIMessage.createToolResult(codecMessageId, { toolCallId, output }) => VercelInputToolResult input addressed at the assistant codec-message that contains the tool call.createToolResultError(codecMessageId, { toolCallId, message }) => VercelInputToolResultError input.createToolApprovalResponse(codecMessageId, { toolCallId, approved, reason? }) => VercelInputToolApprovalResponse input.Type parameters
TInputUserMessage<UIMessage> | Regenerate | ToolResult<VercelToolResultPayload> | ToolResultError<VercelToolResultErrorPayload> | ToolApprovalResponse<VercelToolApprovalResponsePayload>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).TOutputAI.UIMessageChunkai-output wire. The codec passes Vercel's UIMessageChunk through unchanged.TProjection{ messages: CodecMessage<UIMessage>[], ... }{ 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.The well-known input variants (UserMessage, Regenerate, ToolResult, ToolResultError, ToolApprovalResponse) are documented on the Codec reference page. 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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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));
});