new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

AI SDK · Cookbook · all subjects

streaming & ui patterns

25 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

WorkflowChatTransport POST endpoint with headers

```ts import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow'; import { createUIMessageStreamResponse, type UIMessage } from 'ai'; import { start } from 'workflow/api'; import { chat } from '@/workflow/agent-chat'; export async function POST(request: Request) { const { messages }: { messages: UIMessage[] } = await request.json(); const run = await start(chat, [messages]); return createUIMessageStreamResponse({ stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()), headers: { 'x-workflow-run-id': run.runId, }, }); } ``` POST endpoint must return x-workflow-run-id header for reconnection support.

WorkflowAgent API route setup

```ts import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow'; import { createUIMessageStreamResponse, type UIMessage } from 'ai'; import { start } from 'workflow/api'; import { chat } from '@/workflow/agent-chat'; export async function POST(request: Request) { const { messages }: { messages: UIMessage[] } = await request.json(); const run = await start(chat, [messages]); return createUIMessageStreamResponse({ stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()), }); } ``` This example shows the API route that starts the workflow and transforms the stream for the client.

ModelCallStreamPart and UI conversion in WorkflowAgent

WorkflowAgent writes raw ModelCallStreamPart chunks to the writable stream. Use createModelCallToUIChunkTransform() from @ai-sdk/workflow to convert ModelCallStreamPart to UIMessageChunk at the response boundary. Wrap with createUIMessageStreamResponse() to send to client.

WorkflowChatTransport for resumable streaming

WorkflowChatTransport is a ChatTransport implementation that handles workflow interruptions automatically. It detects when a stream ends without a finish event and reconnects to resume. Requires POST endpoint returning x-workflow-run-id response header and GET endpoint at {api}/{runId}/stream for reconnection.

WorkflowChatTransport implementation

```tsx 'use client'; import { useChat } from '@ai-sdk/react'; import { WorkflowChatTransport } from '@ai-sdk/workflow'; import { useMemo } from 'react'; export default function Chat() { const transport = useMemo( () => new WorkflowChatTransport({ api: '/api/chat', maxConsecutiveErrors: 5, initialStartIndex: -50, }), [], ); const { messages, sendMessage } = useChat({ transport }); } ``` Shows how to use WorkflowChatTransport with useChat. initialStartIndex: -50 means on refresh, fetch last 50 chunks.

WorkflowChatTransport GET endpoint for stream reconnection

```ts import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow'; import type { NextRequest } from 'next/server'; import { getRun } from 'workflow/api'; export async function GET( request: NextRequest, { params }: { params: Promise<{ runId: string }> }, ) { const { runId } = await params; const startIndex = Number( new URL(request.url).searchParams.get('startIndex') ?? '0', ); const run = await getRun(runId); const readable = run .getReadable({ startIndex }) .pipeThrough(createModelCallToUIChunkTransform()); return new Response(readable, { headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive', 'x-workflow-run-id': runId, }, }); } ``` Endpoint at {api}/{runId}/stream for resuming interrupted streams. Supports startIndex query parameter.

generateText error handling code example

import { generateText } from 'ai'; __PROVIDER_IMPORT__; try { const { text } = await generateText({ model: __MODEL__, prompt: 'Write a vegetarian lasagna recipe for 4 people.', }); } catch (error) { // handle error }

Handle regular errors with try/catch in generateText

Regular errors thrown by generateText can be caught using a try/catch block. Wrap the generateText call and any awaited operations in the try block, then handle the error in the catch block.

Handle streaming errors in simple streams with try/catch

When errors occur during streams that do not support error chunks, the error is thrown as a regular error. Use a try/catch block around the stream iteration to catch these errors.

Handle error parts in streamText result

The stream result from streamText supports error parts. Iterate through the stream and check for part.type === 'error' to handle errors that occur during streaming. Also wrap the stream iteration in a try/catch block for errors outside the streaming.

Handle stream abort events with onAbort callback

Use the onAbort callback in streamText to handle stream aborts, such as when a user clicks a stop button. The onAbort callback is called when a stream is aborted via AbortSignal but onEnd is not called. This allows you to perform cleanup operations and update UI state. The callback receives an object with a steps property containing an array of all completed steps before the abort.

Handle abort type in stream iteration

When iterating through the stream from streamText, check for chunk.type === 'abort' to handle abort events directly within the stream processing loop.

streamText simple error handling code example

import { streamText } from 'ai'; __PROVIDER_IMPORT__; try { const { textStream } = streamText({ model: __MODEL__, prompt: 'Write a vegetarian lasagna recipe for 4 people.', }); for await (const textPart of textStream) { process.stdout.write(textPart); } } catch (error) { // handle error }

streamText stream with error parts code example

import { streamText } from 'ai'; __PROVIDER_IMPORT__; try { const { stream } = streamText({ model: __MODEL__, prompt: 'Write a vegetarian lasagna recipe for 4 people.', }); for await (const part of stream) { switch (part.type) { // ... handle other part types case 'error': { const error = part.error; // handle error break; } case 'abort': { // handle stream abort break; } case 'tool-error': { const error = part.error; // handle error break; } } } } catch (error) { // handle error }

streamText onAbort and onEnd callbacks code example

import { streamText } from 'ai'; __PROVIDER_IMPORT__; const { textStream } = streamText({ model: __MODEL__, prompt: 'Write a vegetarian lasagna recipe for 4 people.', onAbort: ({ steps }) => { // Update stored messages or perform cleanup console.log('Stream aborted after', steps.length, 'steps'); }, onEnd: ({ steps, totalUsage }) => { // This is called on normal completion console.log('Stream completed normally'); }, }); for await (const textPart of textStream) { process.stdout.write(textPart); }

streamText stream abort handling in loop code example

import { streamText } from 'ai'; __PROVIDER_IMPORT__; const { stream } = streamText({ model: __MODEL__, prompt: 'Write a vegetarian lasagna recipe for 4 people.', }); for await (const chunk of stream) { switch (chunk.type) { case 'abort': { // Handle abort directly in stream console.log('Stream was aborted'); break; } // ... handle other part types } }

HarnessAgent stream method

Use agent.stream({session, prompt: 'your prompt'}) for incremental output. Returns a result with a stream property that yields parts. Iterate with 'for await (const part of result.stream)' and check if part.type === 'text-delta' to get streamed text via part.text.

Warning indicators in AI SDK

The AI SDK shows warnings in the browser console when unsupported features are used, compatibility issues occur, or the model reports other advisory messages. All warnings start with 'AI SDK Warning:' prefix for easy identification.

Disable all AI SDK warnings globally

Set the global variable 'globalThis.AI_SDK_LOG_WARNINGS = false;' to turn off all warnings in the browser console.

Custom warning handler for AI SDK

Provide a custom warning handler by setting 'globalThis.AI_SDK_LOG_WARNINGS' to a function that receives an object with 'warnings' (array of warnings), 'provider' (provider id), and 'model' (model id) properties. This allows custom handling of warnings instead of console output.

Show generic error messages to users

Display a generic error message to users such as 'Something went wrong.' This is a security best practice to avoid leaking information from the server.

Error object from useChat hook

The useChat hook returns an error object that indicates when an error occurred. This error object can be used to render error messages in the UI, disable the submit button, or show a retry button.

Error handling callback in useChat

Pass an 'onError' callback function as an option to the useChat or useCompletion hooks to process errors. The callback receives an error object as an argument and is invoked when an error occurs during message handling.

Test error injection in route handler

Create test errors by throwing an Error in the route handler (e.g., in app/api/chat/route.ts export async function POST). The thrown error will be captured and handled by the error handling mechanisms.

useChat error recovery with message replacement

When an error occurs and error is not null, use setMessages to replace the failed user message. If the assistant response started streaming before the error, remove both the partial assistant response and its user message by checking if the last message role is 'assistant' and slicing accordingly.

Give your agent this brain