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

shadcn/ui · all subjects

helper utilities

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

assistant() options

assistant() options: id (string, use a specific message ID), metadata (METADATA, set metadata for this message).

Writer.tool() method

Use writer.tool() to add a tool call and return a handle tracking the tool lifecycle. Signature: tool(name, options?). Returns a handle with methods: sleep(delayMs), output(value), error(errorText?), denied(). The tool can finish with output(), error(), or denied(). Tool options: toolCallId, title, toolMetadata, providerExecuted, input, output, errorText, dynamic, needsApproval, approvalId.

@shadcn/helpers/ai-sdk overview

@shadcn/helpers/ai-sdk lets you write an AI conversation in code and stream it through useChat with no model, API route, network request, or API key. Because the conversation streams through the real useChat lifecycle, components behave exactly as they would in production. It supports every part type the AI SDK does: reasoning, tools, data, files, sources, and custom parts. Tool calls can also pause for real user input, including approvals.

createChat basic usage

Import createChat from @shadcn/helpers/ai-sdk. Chain .user() and .assistant() calls to build a conversation. Pass chat.get(0) as initial messages and chat.transport() as transport to useChat. Use chat.next(messages) to find the next predefined user message after the messages already shown.

User messages in createChat

Use user() to add a user message. Pass text as the first argument. Optionally pass a second argument with id and metadata properties. User messages can include files via a files option containing an array of FilePayload objects with mediaType (required), url (required), filename (optional), type (optional, defaults to 'file'), and providerMetadata (optional).

Assistant messages in createChat

Use assistant() to add an assistant message. Pass a string to create one text part, an array of AI SDK message parts, or a callback receiving { writer } to script multiple parts. Optionally pass a second argument with id and metadata properties. When assistant() is called after a paused tool turn, it becomes a continuation and the callback receives { writer, toolCall, toolCalls, messages }.

Writer.text() method

Use writer.text() to add a text part to an assistant message. Each call creates a separate text part. Text streams word by word by default. Options: mode ('stream' or 'instant'), delayMs (override transport delay), id (stable part identifier). Calling text() without content uses 'Summarize the uploaded receipt.'

Writer.reasoning() method

Use writer.reasoning() to add a reasoning part to an assistant message. Reasoning uses the same id, delayMs, and mode options as text. Calling reasoning() without content uses 'I need to inspect the available context before answering.'

Tool calls with dynamic:true

Pass dynamic: true to writer.tool() to create an AI SDK dynamic-tool part instead of a typed tool-<name> part.

Tool typing in createChat

Type the tool name, input, and output by passing a UIMessage type parameter to createChat. Define the message type once with the same type parameter as useChat and use it for both. Example: type ChatMessage = UIMessage<unknown, Record<string, never>, Tools> where Tools defines tool shapes with input and output properties.

Human in the Loop: paused tool calls

Leave a tool call unresolved to pause the turn. The input streams, the turn finishes, and the part stays in 'input-available' state until the client supplies output with addToolOutput. This is for client-executed tools where the user provides the result.

Human in the Loop: approval-gated tools

Pass needsApproval: true to writer.tool() to pause behind the user's decision. The output property then means 'stream this after approval' instead of 'resolve immediately'. Denial streams tool-output-denied automatically. errorText with needsApproval scripts a tool that fails after approval. Calling output(), error(), or denied() on a needsApproval handle throws; the user's decision resolves it.

Continuation turns in createChat

A callback turn scripted immediately after a paused turn becomes a continuation. It does not materialize when the script is built. It runs when the follow-up request arrives, and its context includes: name (tool name), toolCallId (paused call ID), input (tool input), output (user-submitted output or gated output after approval), approved (true when user approved, approval calls only), denied (true when user denied, approval calls only). Continuation context also includes messages (live transcript) and toolCalls (every paused call when a turn has more than one). Continuations must stay pure; regenerating re-resolves them against the current transcript.

Client wiring for Human in the Loop

Use addToolOutput to submit a client-executed tool's output with { tool, toolCallId, output }. Use addToolApprovalResponse to answer an approval with { id, approved }. Import lastAssistantMessageIsCompleteWithToolCalls and lastAssistantMessageIsCompleteWithApprovalResponses from 'ai' and pass them to sendAutomaticallyWhen to let useChat send follow-up requests automatically. The continuation streams as a new step of the paused assistant message; the client merges its parts instead of adding a new message.

Writer.data() method

Use writer.data() to add a typed data-* part. Pass an object with type (required), id (optional), data (required value), and transient (optional boolean). Send the same type and id again to update the part in place. Set transient: true for updates that stream to the client but do not remain in the final message.

Writer.file() method

Use writer.file() to add a file to an assistant message. Options: mediaType (optional), url (optional), filename (optional), providerMetadata (optional). These methods provide sample defaults for omitted fields.

Writer.reasoningFile() method

Use writer.reasoningFile() to add a file attached to a reasoning part. Options: mediaType (optional), url (optional), filename (optional), providerMetadata (optional).

Writer.sourceUrl() method

Use writer.sourceUrl() to add a URL source. Options: sourceId (optional), url (optional), title (optional), providerMetadata (optional).

Writer.sourceDocument() method

Use writer.sourceDocument() to add a document source. Options: sourceId (optional), mediaType (optional), title (optional), filename (optional), providerMetadata (optional).

Writer.stepStart() method

Use writer.stepStart() to add an AI SDK step boundary. Call it multiple times to separate steps within a single assistant message.

Writer.custom() method

Use writer.custom() to add a custom part. Pass a kind in the format {provider}.{provider-type}. Calling custom() without a kind uses 'test.output'.

Writer.sleep() method

Use writer.sleep() to pause between parts of an assistant response before the next writer event.

Writer.error() method

Use writer.error() to emit an error and end the response without a finish chunk. This allows the whole assistant response to fail after other parts have streamed. Optionally pass an error message. Calling error() without a message uses 'An error occurred.'

chat.get() method

Use chat.get() to return messages from the start of the conversation. chat.get() returns every message. chat.get(2) returns the first two messages. chat.get(0) returns an empty initial conversation. get() returns cloned messages and does not change the chat. It stops before the first continuation turn, since a continuation has no message without a live transcript, and throws when count reaches past one or is negative or not an integer.

chat.next() method

Use chat.next() to find the next predefined user message after the messages already shown. Pass a message transcript (not an index). Returns the next user message or null when none remain.

chat.sleep() method

Use chat.sleep() to wait before the next assistant response starts. Timing control reproduces the pace of a real response.

chat.error() method

Use chat.error() to make the whole assistant response fail. The error is emitted without a finish chunk. Optionally pass an error message. Calling error() without a message uses 'An error occurred.'

createChat from existing messages

Pass a messages option to createChat to continue from a saved conversation or fixture. Declare messages as UIMessage[], then pass { messages: savedMessages } to createChat(). Existing IDs, metadata, and parts are preserved.

chat.transport() method

Use chat.transport() to create an AI SDK ChatTransport that you can pass directly to useChat as the transport option. When sendMessage() runs, the transport finds the assistant message that follows the current transcript and streams it through the normal AI SDK chat lifecycle. It uses message IDs first and falls back to matching the role and text of the latest message. Automatic sends after tool results and approval responses resolve the next continuation; only a regeneration replays a turn by its message ID.

transport() options

transport() accepts options: delayMs (number, default 50, delay between text and reasoning deltas, use 0 or undefined to remove it), fallback (string, UIMessagePart[], or callback, default None, response to stream when no predefined assistant response remains).

transport delayMs override

The transport-level delayMs is the default for every streamed text and reasoning part. Override it for one part with writer.text(..., { delayMs }) or writer.reasoning(..., { delayMs }).

transport fallback option

Use fallback in transport() when the conversation has no predefined assistant response left. This keeps a demo usable after its predefined replies are exhausted. A fallback can be a string, an array of AI SDK message parts, or a writer callback. The callback receives ({ writer, messages }) so it can create a response from the current state. Fallback responses stream like assistant responses but are not added to the predefined conversation. Without one, the transport throws 'No assistant response found for this transcript.' when exhausted.

transport abort and reconnect

Calling stop() from useChat aborts the active transport stream. Reconnecting is not supported; reconnectToStream() returns null.

Timing control in AI SDK helper

Use timing methods to reproduce the pace of a real response: chat.sleep(ms) waits before the next assistant response starts, writer.sleep(ms) waits between parts of an assistant response, tool.sleep(ms) waits between a tool's input and its result, transport({ delayMs }) sets the default delay between text and reasoning deltas, writer.text(text, { delayMs }) and writer.reasoning(text, { delayMs }) override that delay for one part, mode: 'instant' sends a whole text or reasoning part in one delta. For fast tests, use chat.transport({ delayMs: 0 }) and instant text.

Metadata and IDs in createChat

Pass metadata on individual messages. Its type is preserved through get(), next(), and the transport. Define a metadata type and pass it as the type parameter to createChat: createChat<UIMessage<Metadata>>. Use chat options to customize ID prefixes and time: messageIdPrefix (string, default 'msg'), toolCallIdPrefix (string, default 'call'), sourceIdPrefix (string, default 'source'), now (Date | string, default '2026-01-01T00:00:00.000Z'). IDs found in messages are reserved, so newly generated IDs continue after the existing transcript.

createChat API reference

function createChat<UI_MESSAGE extends UIMessage = UIMessage>(options?: CreateChatOptions<UI_MESSAGE>): AiSdkChat<UI_MESSAGE>. Type parameter UI_MESSAGE is the UIMessage type for the conversation, same as useChat accepts. Define it once and share it. The message type carries the metadata shape, typed data-* parts, and tool definitions. Example: type ChatMessage = UIMessage<Metadata, DataParts, Tools>.

CreateChatOptions

Options for createChat: messages (UIMessage[], default []), messageIdPrefix (string, default 'msg'), toolCallIdPrefix (string, default 'call'), sourceIdPrefix (string, default 'source'), now (Date | string, default '2026-01-01T00:00:00.000Z'). Start from an existing transcript by passing messages; they are cloned.

AiSdkChat methods

AiSdkChat methods and their signatures: user(text?, options?) returns AiSdkChat, assistant(input?, options?) returns AiSdkChat, sleep(delayMs) returns AiSdkChat, error(errorText?) returns AiSdkChat, get(count?) returns UIMessage[], next(messages) returns UIMessage | null, transport(options?) returns ChatTransport. Every method that adds content returns the same chat for chaining. Calling user() or assistant() without content uses 'Summarize the uploaded receipt.' Calling error() without a message uses 'An error occurred.'

user() options

user() options: id (string, use a specific message ID), metadata (METADATA, set metadata for this message), files (FilePayload[], append file parts after the user text part).

FilePayload type

FilePayload shape for user() files option: type (optional, defaults to 'file'), mediaType (required, string), url (required, string), filename (optional, string), providerMetadata (optional, Record<string, unknown>).

assistant() input options

assistant() input: string (one text part that streams word by word), UIMessagePart[] (static AI SDK parts that stream in their existing order), ({ writer }) => void (synchronous callback for scripting parts, tools, errors, and timing; after a paused turn becomes a continuation and receives toolCall, toolCalls, and messages).

Writer text and reasoning options

Text and reasoning options: id (string, default Generated, use a stable part ID), delayMs (number, default Transport, override the transport delay for this part), mode ('stream' or 'instant', default 'stream', stream word deltas or emit the whole part in one delta).

Writer tool options table

Tool options for writer.tool(): toolCallId (string, use a specific tool call ID), title (string, add a display title to the tool part), toolMetadata (Record<string, unknown>, add provider or application metadata), providerExecuted (boolean, mark the call as executed by the provider), input (TOOLS[NAME]['input'], set the typed tool input), output (TOOLS[NAME]['output'], immediately finish with a typed output; with needsApproval, stream it after approval instead), errorText (string, immediately finish with an error; with needsApproval, stream it after approval instead), dynamic (boolean, emit a dynamic-tool part instead of tool-<name>), needsApproval (boolean, pause the turn behind the user's decision), approvalId (string, use a specific approval ID).

Writer tool handle methods

tool() returns a handle with methods: sleep(delayMs), output(value), error(errorText?), denied(). Use the handle when the tool lifecycle needs events between its input and result. Calling tool.error() without a message uses 'Tool call failed.' The resolution methods throw on a needsApproval call.

Writer data input

writer.data() input structure: type (required, string like 'data-name'), id (optional, string), data (required, value), transient (optional, boolean, default false). Repeating the same type and id replaces the earlier data part. A transient part streams to the client but is not included in the final message returned by get().

Writer file and source options

File and source methods and their options: file() has mediaType?, url?, filename?, providerMetadata?; reasoningFile() has mediaType?, url?, filename?, providerMetadata?; sourceUrl() has sourceId?, url?, title?, providerMetadata?; sourceDocument() has sourceId?, mediaType?, title?, filename?, providerMetadata?. These methods provide sample defaults for omitted fields.

Writer methods list

Writer methods available inside assistant(({ writer }) => {}) and fallback callbacks: text(text?, options?), reasoning(text?, options?), tool(name, options?), data(part), file(options?), reasoningFile(options?), sourceUrl(options?), sourceDocument(options?), stepStart(), custom(kind?), sleep(delayMs), error(errorText?).

Installation of @shadcn/helpers

Install with: npm install @shadcn/helpers. The helper works alongside existing AI SDK setup (ai and @ai-sdk/react). Import helpers from @shadcn/helpers/ai-sdk.

AI SDK helper use cases

The AI SDK helper is useful for: Build components (develop message bubbles, tool cards, and reasoning panels against realistic streaming output without wiring up a model first), Preview and demo (ship reproducible previews, screenshots, and videos that never depend on a live model), Write docs (power documentation examples with conversations that render the same way on every load), Test (assert against a deterministic stream in CI with no network calls, token spend, or flaky model output).

Export types from AI SDK helper

Export types: AiSdkChat (the typed fluent chat returned by createChat()), CreateChatOptions (options accepted by createChat()).

scroll-fade CSS utility

scroll-fade is a CSS utility that adds scroll-aware edge fades to scroll containers. It can be used on MessageScroller, ScrollArea, attachment rows, and any long list to hint at more content without adding overlays or scroll listeners. It ships with shadcn/tailwind.css.

shimmer CSS utility

shimmer is a CSS utility that adds a text shimmer for live status, used for things like 'Thinking…', 'Generating response…', running tools, and streaming markers. It ships with shadcn/tailwind.css.

Give your agent this brain