createUIMessageStream

API Reference for createUIMessageStream.

The createUIMessageStream function allows you to create a readable stream for UI messages with advanced features like message merging, error handling, and finish callbacks.

Import

import { createUIMessageStream } from "ai"

Example

const existingMessages: UIMessage[] = [
  /* ... */
];

const stream = createUIMessageStream({
  async execute({ writer }) {
    // Start a text message
    // Note: The id must be consistent across text-start, text-delta, and text-end steps
    // This allows the system to correctly identify they belong to the same text block
    writer.write({
      type: 'text-start',
      id: 'example-text',
    });

    // Write a message chunk
    writer.write({
      type: 'text-delta',
      id: 'example-text',
      delta: 'Hello',
    });

    // End the text message
    writer.write({
      type: 'text-end',
      id: 'example-text',
    });

    // Merge another stream from streamText
    const result = streamText({
      model: "anthropic/claude-sonnet-5.5",
      prompt: 'Write a haiku about AI',
    });

    writer.merge(
      result.toUIMessageStream({
        onFinish: ({ outcome }) => {
          // The composer decides that the model stream outcome is also the
          // aggregate stream outcome.
          writer.setOutcome(outcome);
        },
      }),
    );
  },
  onError: error => `Custom error: ${error.message}`,
  originalMessages: existingMessages,
  onFinish: ({ messages, isContinuation, outcome, responseMessage }) => {
    console.log('Stream finished with messages:', messages);
    console.log('Stream outcome:', outcome.status);
  },
});

setOutcome records the composer's policy without writing a chunk or closing the stream. The first outcome declared through setOutcome is retained, but a fatal execution, merge, error-handling, or downstream processing failure makes the final onFinish outcome failed. Individual error chunks do not change the outcome by themselves. When merging multiple child streams, aggregate their outcomes and call setOutcome once.

API Signature

Parameters

execute:

(options: { writer: UIMessageStreamWriterWithOutcome }) => Promise<void> | void
A function that receives a writer instance and can use it to write UI message chunks to the stream.
UIMessageStreamWriterWithOutcome

write:

(part: UIMessageChunk) => void
Writes a UI message chunk to the stream.

merge:

(stream: ReadableStream<UIMessageChunk>) => void
Merges the contents of another UI message stream into this stream.

setOutcome:

(outcome: UIMessageStreamOutcome) => void
Declares the operation-level outcome of the composed stream. The first outcome declared through this method is retained, while fatal execution, merge, error-handling, or downstream processing failures override declarations. Supported statuses are 'completed', 'failed', 'aborted', and 'unknown'. Declaring an outcome does not write a chunk or close the stream.

onError:

(error: unknown) => string
Error handler that is used by the stream writer for handling errors in merged streams.

onError:

(error: unknown) => string
A function that handles errors and returns an error message string. By default, it returns the error message.

originalMessages:

UIMessage[] | undefined
The original messages. If provided, persistence mode is assumed and a message ID is provided for the response message.

onFinish:

(options: { messages: UIMessage[]; isContinuation: boolean; isAborted: boolean; outcome: UIMessageStreamOutcome; responseMessage: UIMessage; finishReason?: FinishReason }) => PromiseLike<void> | void
A callback function that is called when the stream finishes.
FinishOptions

messages:

UIMessage[]
The updated list of UI messages.

isContinuation:

boolean
Indicates whether the response message is a continuation of the last original message, or if a new message was created.

isAborted:

boolean
Indicates whether the stream was aborted.

outcome:

UIMessageStreamOutcome = { status: 'completed' } | { status: 'failed'; error?: unknown } | { status: 'aborted' } | { status: 'unknown' }
The operation-level outcome of the stream. It reflects the stream owner declaration unless a fatal stream-processing failure occurs, and is separate from model finish reasons and individual error chunks.

responseMessage:

UIMessage
The message that was sent to the client as a response (including the original message if it was extended).

generateId:

IdGenerator | undefined
A function to generate unique IDs for messages. Uses the default ID generator if not provided.

Returns

ReadableStream<UIMessageChunk>

A readable stream that emits UI message chunks. The stream automatically handles error propagation, merging of multiple streams, and proper cleanup when all operations are complete.