Class References
Function References
- text
- textOptions
- combineStrategies
- convertMessagesToModelMessages
- convertZodToJsonSchema
- createReplayStream
- embedding
- generateMessageId
- maxIterations
- messages
- modelMessageToUIMessage
- modelMessagesToUIMessages
- normalizeToUIMessage
- parsePartialJSON
- summarize
- toServerSentEventsStream
- toServerSentEventsResponse
- toolDefinition
- uiMessageToModelMessages
- realtimeToken
- untilFinishReason
Interface References
- AIAdapter
- AIAdapterConfig
- AgentLoopState
- AudioPart
- AudioVisualization
- BaseStreamChunk
- TextCompletionChunk
- TextOptions
- ChunkRecording
- ChunkStrategy
- ClientTool
- ContentPartSource
- ContentStreamChunk
- DefaultMessageMetadataByModality
- DocumentPart
- DoneStreamChunk
- EmbeddingOptions
- EmbeddingResult
- ErrorStreamChunk
- ImagePart
- InternalToolCallState
- JSONParser
- ModelMessage
- ProcessorResult
- ProcessorState
- RealtimeAdapter
- RealtimeClientOptions
- RealtimeConnection
- RealtimeMessage
- RealtimeSessionConfig
- RealtimeToken
- RealtimeTokenAdapter
- RealtimeTokenOptions
- ResponseFormat
- ServerTool
- StreamProcessorEvents
- StreamProcessorHandlers
- StreamProcessorOptions
- SummarizationOptions
- SummarizationResult
- TextPart
- ThinkingPart
- ThinkingStreamChunk
- Tool
- ToolCall
- ToolCallPart
- ToolCallStreamChunk
- ToolConfig
- ToolDefinition
- ToolDefinitionConfig
- ToolDefinitionInstance
- ToolInputAvailableStreamChunk
- ToolResultPart
- ToolResultStreamChunk
- UIMessage
- VideoPart
Type Alias References
- AgentLoopStrategy
- AnyClientTool
- TextStreamOptionsForModel
- TextStreamOptionsUnion
- ConstrainedContent
- ConstrainedModelMessage
- ContentPart
- ContentPartForModalities
- ExtractModalitiesForModel
- ExtractModelsFromAdapter
- InferToolInput
- InferToolName
- InferToolOutput
- MessagePart
- RealtimeEvent
- RealtimeMessagePart
- RealtimeMode
- RealtimeStatus
- ModalitiesArrayToUnion
- Modality
- StreamChunk
- ToolCallState
- ToolResultState
Variable References
@tanstack/ai-react
React hooks for TanStack AI. To build your first chat, start with the Quick Start. For a typed chat layout, see React Chat UI.
Installation#
npm i @tanstack/ai-reactpnpm add @tanstack/ai-reactyarn add @tanstack/ai-reactbun add @tanstack/ai-reactThe package works in React Native and Expo, but only useChat with chat connection adapters is supported there. See Quick Start: React Native.
useChat(options)#
Holds the messages and the run state of one chat, and talks to your server route.
import { useState } from "react";
import { useChat, fetchServerSentEvents } from "@tanstack/ai-react";
export function Chat() {
const [input, setInput] = useState("");
const { messages, sendMessage, isLoading } = useChat({
connection: fetchServerSentEvents("/api/chat"),
threadId: "support-chat",
});
return (
<div>
{messages.map((message) => (
<div key={message.id}>
<strong>{message.role}:</strong>
{message.parts.map((part, idx) =>
part.type === "text" ? <span key={idx}>{part.content}</span> : null,
)}
</div>
))}
<form
onSubmit={(e) => {
e.preventDefault();
if (input.trim() && !isLoading) {
sendMessage(input);
setInput("");
}
}}
>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button type="submit" disabled={isLoading}>
Send
</button>
</form>
</div>
);
}Options#
You must pass threadId. You must also pass connection or fetcher, not both.
| Option | What it does |
|---|---|
| connection | Connection adapter, for example fetchServerSentEvents("/api/chat"). See Transports. |
| fetcher | A function that returns a Response or a stream. Use it with server functions. |
| tools | Client tools from .client(). They run when the model calls them. See Client Tools. |
| threadId | Required. The id of this chat. Use a stable id for each conversation, for example the id from your route. |
| initialMessages | The messages to show first. |
| forwardedProps | JSON sent to the server in the AG-UI forwardedProps field, for example { model: "gpt-6.1-sol" }. |
| persistence | true to load the thread from the server, or a storage adapter. See Chat Persistence. |
| outputSchema | A Standard Schema. Adds typed partial and final to the return value. See Streaming structured output. |
| context | Client-only runtime context for client tools. It is not sent to the server. |
| live | Subscribe on mount and unsubscribe on unmount. |
| queue | What sendMessage does while a run is busy. Default: queue the message. See Queueing. |
| interrupts | Definitions from defineInterrupt(). See Interrupts. |
| subagents | Agents from defineAgent(), for types only. See Subagents. |
| byok, byokProvider | A keyring from defineByok(). See Bring Your Own Key. |
| devtools | Display options for TanStack AI Devtools. |
The hook also takes the ChatClient callbacks (onResponse, onChunk, onFinish, onError, onInterruptStateChange, onCustomEvent) and the other client options. See ChatClient options.
When forwardedProps, tools, context, or queue change, the hook updates the current chat.
Returns#
State values are plain React values. The hook renders again when they change.
| Field | What it is |
|---|---|
| messages | The UIMessage array of the chat. |
| sendMessage(content, options?) | Sends a user message. content is a string or { content, id?, metadata? }. options takes whenBusy and body. |
| isLoading | true while a response streams. |
| error | The last error, or undefined. |
| status | "ready", "submitted", "streaming", or "error". |
| stop() | Stops the current response. |
| reload() | Sends the last user message again. |
| append(message) | Adds a UIMessage or ModelMessage and starts a run. |
| addToolResult(result) | Gives the result of a client tool by hand: { toolCallId, tool, output, state?, errorText? }. |
| setMessages(messages), clear() | Replace or clear the messages. |
| queue, cancelQueued(id) | Messages that wait while a run is busy. See Queueing. |
| runId | The id of the run in flight, or null. |
| interrupts | Pending interrupts. Each item has resolveInterrupt(...). See Interrupts. |
| resolveInterrupts, cancelInterrupts, retryInterrupts, resumeInterruptsUnsafe | Act on all pending interrupts at once. |
| interruptErrors, resuming | Errors from the last resume, and true while a resume runs. |
| isHydrating | true while the chat loads from persistence. |
| hasOlderMessages, loadOlderMessages() | Page in older messages. See Chat Persistence. |
| isSubscribed, connectionStatus, sessionGenerating | State of the live subscription. |
| partial, final | Structured output. Only when you pass outputSchema. |
| subagents | Live child-agent runs. See Subagents. |
Example: tool approval#
A tool with needsApproval: true pauses the run. The pending call shows up in interrupts.
import { toolDefinition } from "@tanstack/ai";
import { useChat, fetchServerSentEvents } from "@tanstack/ai-react";
import { z } from "zod";
const deleteFileTool = toolDefinition({
name: "delete_file",
description: "Delete a file",
needsApproval: true,
inputSchema: z.object({ path: z.string() }),
});
export function ChatWithApproval() {
const { interrupts } = useChat({
connection: fetchServerSentEvents("/api/chat"),
threadId: "support-chat",
tools: [deleteFileTool],
});
return (
<div>
{interrupts.map((interrupt) =>
interrupt.kind === "tool-approval" ? (
<div key={interrupt.id}>
<p>Approve: {interrupt.toolName}</p>
<button onClick={() => interrupt.resolveInterrupt(true)}>
Approve
</button>
<button onClick={() => interrupt.resolveInterrupt(false)}>
Deny
</button>
</div>
) : null,
)}
</div>
);
}See Tool Approval for the server side.
createChatHook(options)#
Binds chat options once at module scope and returns a useChat hook that uses them.
import { createChatHook, fetchServerSentEvents } from "@tanstack/ai-react";
const { useChat: useSupportChat } = createChatHook({
connection: fetchServerSentEvents("/api/chat"),
});
export function SupportScreen() {
const chat = useSupportChat({ threadId: "support-1" });
return <p>{chat.messages.length} messages</p>;
}The bound hook takes these per-call overrides: threadId, initialMessages, live, and forwardedProps. Keep tools, interrupts, and outputSchema on the factory options.
@tanstack/ai-react/ui has its own createChatHook that also returns typed UI components. See React Chat UI.
Generation hooks#
Each hook runs one generation request and keeps its result. See Generation Hooks.
| Hook | generate() input | result |
|---|---|---|
| useGenerateImage | ImageGenerateInput | ImageGenerationResult |
| useGenerateAudio | AudioGenerateInput | AudioGenerationResult |
| useGenerateSpeech | SpeechGenerateInput | TTSResult |
| useTranscription | TranscriptionGenerateInput | TranscriptionResult |
| useSummarize | SummarizeGenerateInput | SummarizationResult |
| useGenerateVideo | VideoGenerateInput | VideoGenerateResult |
| useGeneration | Your own input type | Your own result type |
import { useGenerateImage, fetchServerSentEvents } from "@tanstack/ai-react";
export function ImageButton() {
const image = useGenerateImage({
connection: fetchServerSentEvents("/api/generate/image"),
threadId: "image-studio",
});
return (
<button
disabled={image.isLoading}
onClick={() => image.generate({ prompt: "A mountain at sunset" })}
>
Generate
</button>
);
}Options: threadId (required), connection or fetcher, body, persistence, byok, byokProvider, devtools, onResult, onError, onProgress, onChunk.
Returns: generate(input), result, isLoading, error, status, stop(), reset(), runId.
useGenerateVideo also returns jobId and videoStatus, and takes onJobCreated and onStatusUpdate.
useRealtimeChat(options)#
Runs a voice conversation with a realtime model. Pass getToken and adapter. See Realtime Chat.
import { useRealtimeChat } from "@tanstack/ai-react";
import { openaiRealtime } from "@tanstack/ai-openai";
export function VoiceChat() {
const chat = useRealtimeChat({
getToken: () => fetch("/api/realtime-token").then((r) => r.json()),
adapter: openaiRealtime(),
});
return chat.status === "idle" ? (
<button onClick={() => chat.connect()}>Start</button>
) : (
<button onClick={() => chat.disconnect()}>Stop</button>
);
}Returns status, error, mode, messages, connect(), disconnect(), startListening(), stopListening(), interrupt(), sendText(text), sendImage(data, mimeType), updateSession(config), plus audio levels and frequency data for visualizers.
useAudioRecorder(options?)#
Records audio from the microphone. See Audio Recording.
Returns recording, isRecording, isSupported, start(), stop(), and cancel(). Pass onComplete to transform the recording. Then recording and stop() use the transformed type.
useByok(client)#
Subscribes to a BYOK keyring and returns its snapshot. See Bring Your Own Key.
import { useByok } from "@tanstack/ai-react";
import { byok } from "./byok";
export function KeyStatus() {
const snapshot = useByok(byok);
const openai = snapshot.status.openai;
return <p>{openai && "masked" in openai ? openai.masked : "No key"}</p>;
}The snapshot has status, locked, prompt, and storageError. Save a key from your own UI with byok.update(provider, value).
useMcpAppBridge(options)#
Returns a stable MCP App bridge for one thread. It always calls the latest chat.sendMessage and onLink. Options: threadId, callEndpoint, chat, fetchImpl, onLink. See MCP Apps.
The MCPAppResource component, which renders a ui-resource part, is on the @tanstack/ai-react/mcp-apps subpath.
useRegisterWebMCPTools(tools, options?)#
Exposes client tools to the browser WebMCP API while the component is mounted. See WebMCP Tools.
import { useRegisterWebMCPTools } from "@tanstack/ai-react";
import { searchProducts } from "./tools";
const tools = [searchProducts];
export function ProductsPage() {
useRegisterWebMCPTools(tools, {
onError: (error) => console.error(error),
});
return null;
}Options: toolOptions, context, and onError. context is required when a tool declares a required runtime context. The hook registers the tools again when tools or options change, so keep them stable.
usePageWebMCPTools(options?)#
Reads the WebMCP tools that the page registered, as client tools. The array starts empty and updates when the page adds or removes a tool. Pass it to useChat as tools. See Page WebMCP Tools in Chat.
import { usePageWebMCPTools } from "@tanstack/ai-react";
export function useSameOriginPageTools() {
return usePageWebMCPTools({
filter: (tool) => tool.origin === location.origin,
});
}Options: filter (return false to skip a tool) and onError.
Re-exports from @tanstack/ai-client#
You can import these from @tanstack/ai-react directly. See @tanstack/ai-client for details.
| Group | Exports |
|---|---|
| Connection adapters | fetchServerSentEvents, fetchHttpStream, fetchJson, xhrServerSentEvents, xhrHttpStream, webSocket, stream, rpcStream |
| Typed options | createChatClientOptions, clientTools |
| Persistence | localStoragePersistence, sessionStoragePersistence, indexedDBPersistence |
| Clients | ChatClient, GenerationClient, VideoGenerationClient, RealtimeClient, AudioRecorder, InterruptManager |
| WebMCP and MCP Apps | registerWebMCPTools, getWebMCPTools, subscribeWebMCPTools, createMcpAppBridge |
| Errors | UnsupportedResponseStreamError, StreamTruncatedError, DurableStreamIncompleteError, StreamReconnectLimitError, StorageUnavailableError |
| Stream helpers | StreamProcessor, chunk strategies, parsePartialJSON, message converters |
For React Native or Expo, use an absolute server URL and xhrHttpStream() with a route that returns toHttpResponse(). If the host cannot stream, use fetchJson() with toJsonResponse(). See React Native.
BYOK helpers (defineByok, defaultByokStorage, and more) are on the @tanstack/ai-react/byok subpath.
Types#
| Type | What it is |
|---|---|
| UseChatOptions, UseChatReturn | The options and return value of useChat. |
| UIMessage<TTools> | A chat message with typed parts. |
| InferChatMessages<T> | The message type for a createChatClientOptions result. |
| SendMessageOptions, WhenBusy, QueueOption, QueuedMessage | Send and queue types. |
| DeepPartial<T> | The type of partial while structured output streams. |
| Use<Hook>Options, Use<Hook>Return | Options and return types for the generation, realtime, and recorder hooks. The WebMCP hooks export only an options type. |
Pass a plain tools array to useChat or createChatClientOptions. Tool names, inputs, and outputs stay typed without as const. Import toolDefinition from @tanstack/ai.