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
- ApprovalRequestedStreamChunk
- 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
- StreamChunkType
- ToolCallState
- ToolResultState
Variable References
@tanstack/ai-vue
Vue composables for TanStack AI, providing convenient Vue 3 bindings for the headless client.
For a typed headless chat UI, see Vue Chat UI.
Installation#
npm i @tanstack/ai-vuepnpm add @tanstack/ai-vueyarn add @tanstack/ai-vuebun add @tanstack/ai-vueuseRegisterWebMCPTools(tools, options?)#
Register executable client tools for the current Vue scope. Vue removes them when the scope is disposed.
For a complete setup and behavior guide, see WebMCP Tools.
<script setup lang="ts">
import {
useRegisterWebMCPTools,
type UseRegisterWebMCPToolsOptions,
} from "@tanstack/ai-vue";
import { searchProducts } from "./tools";
const tools = [searchProducts];
const options: UseRegisterWebMCPToolsOptions<typeof tools> = {
onError(error) {
console.error(error);
},
};
useRegisterWebMCPTools(tools, options);
</script>UseRegisterWebMCPToolsOptions<TTools, TContext> contains toolOptions, context, and onError. The composable owns the registration signal.
The context field is required when a tool declares a required runtime context.
usePageWebMCPTools(options?)#
Read the WebMCP tools on the page as client tools. The ref starts empty and updates when the page adds or removes a tool. Pass the ref to useChat as tools.
import { usePageWebMCPTools } from "@tanstack/ai-vue";
export function useSameOriginPageTools() {
return usePageWebMCPTools({
filter: (tool) => tool.origin === location.origin,
});
}filter skips a tool when it returns false. onError gets a failed WebMCP read. For a complete guide, see Page WebMCP Tools in Chat.
createChatHook(options)#
Bind chatOptions once at module scope. Call useChat() in the screen to create the instance. Per-call overrides may set threadId, initialMessages, live, and forwardedProps. They must not change tools, interrupts, or outputSchema.
import { createChatHook, fetchServerSentEvents } from "@tanstack/ai-vue";
const chatOptions = {
connection: fetchServerSentEvents("/api/chat"),
};
const { useChat } = createChatHook(chatOptions);
const chat = useChat({ threadId: "support-1" });useChat(chatOptions) from this package still works when you want to pass the full object at the call site. Rename the bound composable if both are in one file: const { useChat: useSupportChat } = createChatHook(chatOptions).
useChat(options?)#
Main composable for managing chat state in Vue with full type safety.
import { useChat, fetchServerSentEvents } from "@tanstack/ai-vue";
import {
createChatClientOptions,
type InferChatMessages,
} from "@tanstack/ai-client";
import { toolDefinition } from "@tanstack/ai";
import { z } from "zod";
import { ref } from "vue";
const updateUIDef = toolDefinition({
name: "updateUI",
description: "Show a notification in the UI",
inputSchema: z.object({ message: z.string() }),
});
const notification = ref<string | null>(null);
// In <script setup>
const updateUI = updateUIDef.client((input) => {
notification.value = input.message;
return { success: true };
});
const tools = [updateUI];
const chatOptions = createChatClientOptions({
connection: fetchServerSentEvents("/api/chat"),
tools,
});
// Fully typed messages!
type ChatMessages = InferChatMessages<typeof chatOptions>;
const { messages, sendMessage, isLoading, error, addToolApprovalResponse } =
useChat(chatOptions);Options#
Extends ChatClientOptions from @tanstack/ai-client (minus internal state callbacks):
- connection - Connection adapter (required)
- tools? - Array of client tool implementations (with .client() method). Pass a ref or getter to change the tools after the chat is created.
- initialMessages? - Initial messages array
- threadId? - The only identity for this chat. Required when persistence is on. If omitted, minted after mount.
- forwardedProps? - Arbitrary client-controlled JSON forwarded to the server in the AG-UI RunAgentInput.forwardedProps field (reactive -- changes are synced automatically via watch)
- body? - Deprecated. Use forwardedProps instead. Still works for backward compatibility; values are merged into forwardedProps on the wire (reactive)
- byok? - Optional BYOK keyring from defineByok. On each send the client prepares the resolved provider and stamps x-byok-* request headers. Keys never go in the body
- byokProvider? - Optional function that returns the provider slug for this chat. If it returns a slug, only that key is prepared and sent. Otherwise the merged provider from forwardedProps, body, and per-call sendMessage body is used. Later sources win. If no slug resolves, the send throws instead of attaching every stored key
- context? - Typed client-local runtime context passed to client tool implementations (reactive). This value is not serialized to the server
- live? - Enable live subscription mode (auto-subscribes/unsubscribes)
- onResponse? - Callback when response is received
- onChunk? - Callback when stream chunk is received
- onFinish? - Callback when response finishes
- onError? - Callback when error occurs
- onInterruptStateChange? - Callback when interrupt state changes; context source is hydrate for restored state and live for streamed or client-initiated updates
- onCustomEvent? - Callback for custom stream events
- streamProcessor? - Stream processing configuration
Note: Client tools are now automatically executed - no onToolCall callback needed!
Returns#
import type { DeepReadonly, ShallowRef } from "vue";
import type { UIMessage } from "@tanstack/ai-vue";
import type { ModelMessage } from "@tanstack/ai/client";
import type {
MultimodalContent,
ChatClientState,
ConnectionStatus,
SendMessageOptions,
} from "@tanstack/ai-client";
interface UseChatReturn {
messages: Readonly<ShallowRef<ReadonlyArray<UIMessage>>>;
sendMessage: (
content: string | MultimodalContent,
options?: SendMessageOptions,
) => Promise<void>;
append: (message: ModelMessage | UIMessage) => Promise<void>;
addToolResult: (result: {
toolCallId: string;
tool: string;
output: any;
state?: "output-available" | "output-error";
errorText?: string;
}) => Promise<void>;
addToolApprovalResponse: (response: {
id: string;
approved: boolean;
}) => Promise<void>;
reload: () => Promise<void>;
stop: () => void;
isLoading: DeepReadonly<ShallowRef<boolean>>;
error: DeepReadonly<ShallowRef<Error | undefined>>;
status: DeepReadonly<ShallowRef<ChatClientState>>;
isSubscribed: DeepReadonly<ShallowRef<boolean>>;
connectionStatus: DeepReadonly<ShallowRef<ConnectionStatus>>;
sessionGenerating: DeepReadonly<ShallowRef<boolean>>;
isHydrating: DeepReadonly<ShallowRef<boolean>>;
setMessages: (messages: ReadonlyArray<UIMessage>) => void;
clear: () => void;
}Note: Reactive state (messages, isLoading, error, status, isSubscribed, connectionStatus, sessionGenerating, isHydrating) is wrapped in DeepReadonly<ShallowRef<T>>. In <script setup> read the underlying value with .value (e.g., messages.value); in <template> Vue auto-unwraps the ref, so use the bare name (e.g., v-for="m in messages"). Cleanup is automatic via onScopeDispose.
useByok(client)#
Subscribe to a ByokClient snapshot in Vue. The return value is a DeepReadonly<ShallowRef<ByokSnapshot>>.
import { useByok } from "@tanstack/ai-vue";
import { byok } from "./byok";
const snapshot = useByok(byok);
const openai = snapshot.value.status.openai;
const last4 = openai && "masked" in openai ? openai.masked : "No key";snapshot.value has status, locked, and prompt. Call byok.update(provider, value) from your own UI to save a key. See Bring Your Own Key.
Connection Adapters#
Re-exported from @tanstack/ai-client for convenience:
import {
fetchServerSentEvents,
fetchHttpStream,
fetchJson,
stream,
type ConnectionAdapter,
} from "@tanstack/ai-vue";Example: Basic Chat#
<script setup lang="ts">
import { ref } from "vue";
import { useChat, fetchServerSentEvents } from "@tanstack/ai-vue";
const input = ref("");
const { messages, sendMessage, isLoading } = useChat({
connection: fetchServerSentEvents("/api/chat"),
});
const handleSubmit = () => {
if (input.value.trim() && !isLoading.value) {
sendMessage(input.value);
input.value = "";
}
};
</script>
<template>
<div>
<div>
<div v-for="message in messages" :key="message.id">
<strong>{{ message.role }}:</strong>
<template v-for="(part, idx) in message.parts" :key="idx">
<div
v-if="part.type === 'thinking'"
class="text-sm text-gray-500 italic"
>
Thinking: {{ part.content }}
</div>
<span v-else-if="part.type === 'text'">{{ part.content }}</span>
</template>
</div>
</div>
<form @submit.prevent="handleSubmit">
<input v-model="input" :disabled="isLoading" />
<button type="submit" :disabled="isLoading">Send</button>
</form>
</div>
</template>Example: Tool Approval#
<script setup lang="ts">
import { useChat, fetchServerSentEvents } from "@tanstack/ai-vue";
const { messages, sendMessage, addToolApprovalResponse } = useChat({
connection: fetchServerSentEvents("/api/chat"),
});
</script>
<template>
<div>
<template v-for="message in messages" :key="message.id">
<template v-for="part in message.parts" :key="part.id">
<div
v-if="
part.type === 'tool-call' &&
part.state === 'approval-requested' &&
part.approval
"
>
<p>Approve: {{ part.name }}</p>
<button
@click="
addToolApprovalResponse({
id: part.approval!.id,
approved: true,
})
"
>
Approve
</button>
<button
@click="
addToolApprovalResponse({
id: part.approval!.id,
approved: false,
})
"
>
Deny
</button>
</div>
</template>
</template>
</div>
</template>Example: Client Tools with Type Safety#
<script setup lang="ts">
import { ref } from "vue";
import { useChat, fetchServerSentEvents } from "@tanstack/ai-vue";
import {
createChatClientOptions,
type InferChatMessages,
} from "@tanstack/ai-client";
import { toolDefinition } from "@tanstack/ai";
import { z } from "zod";
const updateUIDef = toolDefinition({
name: "updateUI",
description: "Show a notification in the UI",
inputSchema: z.object({ message: z.string(), type: z.string() }),
});
const saveToStorageDef = toolDefinition({
name: "saveToStorage",
description: "Save a value to localStorage",
inputSchema: z.object({ key: z.string(), value: z.string() }),
});
const notification = ref<{ message: string; type: string } | null>(null);
// Create client implementations
const updateUI = updateUIDef.client((input) => {
// input is fully typed!
notification.value = { message: input.message, type: input.type };
return { success: true };
});
const saveToStorage = saveToStorageDef.client((input) => {
localStorage.setItem(input.key, input.value);
return { saved: true };
});
// Create typed tools array (no 'as const' needed!)
const tools = [updateUI, saveToStorage];
const { messages, sendMessage } = useChat({
connection: fetchServerSentEvents("/api/chat"),
tools, // Automatic execution, full type safety
});
</script>
<template>
<div>
<template v-for="message in messages" :key="message.id">
<template v-for="(part, idx) in message.parts" :key="idx">
<div v-if="part.type === 'tool-call' && part.name === 'updateUI'">
Tool executed: {{ part.name }}
</div>
</template>
</template>
</div>
</template>Generation Composables#
Vue composables for one-shot generation tasks (images, speech, transcription, summarization, video). All share the same pattern: provide a connection or fetcher, call generate(), and read reactive state.
useGeneration(options)#
Base composable for custom generation types. All specialized composables below are built on this.
import { useGeneration } from "@tanstack/ai-vue";
import { fetchServerSentEvents } from "@tanstack/ai-client";
const { generate, result, isLoading, error, status, stop, reset } =
useGeneration({
connection: fetchServerSentEvents("/api/generate/custom"),
});Options: connection?, fetcher?, threadId?, body?, onResult?, onError?, onProgress?, onChunk?
Returns: generate, result, isLoading, error, status, stop, reset, runId -- all reactive state is DeepReadonly<ShallowRef<T>>.
useGenerateImage(options)#
Image generation composable. generate() accepts ImageGenerateInput, result is ImageGenerationResult.
useGenerateSpeech(options)#
Text-to-speech composable. generate() accepts SpeechGenerateInput, result is TTSResult.
useTranscription(options)#
Audio transcription composable. generate() accepts TranscriptionGenerateInput, result is TranscriptionResult.
useSummarize(options)#
Text summarization composable. generate() accepts SummarizeGenerateInput, result is SummarizationResult.
useGenerateVideo(options)#
Video generation composable with job polling. Returns additional jobId and videoStatus refs. Accepts extra onJobCreated? and onStatusUpdate? callbacks.
All generation composables automatically clean up via onScopeDispose.
createChatClientOptions(options)#
Helper to create typed chat options (re-exported from @tanstack/ai-client).
import {
createChatClientOptions,
type InferChatMessages,
} from "@tanstack/ai-client";
import { fetchServerSentEvents } from "@tanstack/ai-vue";
import { tool1, tool2 } from "./tools";
// Create typed tools array (no 'as const' needed!)
const tools = [tool1, tool2];
const chatOptions = createChatClientOptions({
connection: fetchServerSentEvents("/api/chat"),
tools,
});
type Messages = InferChatMessages<typeof chatOptions>;Types#
Re-exported from @tanstack/ai-client:
- UIMessage<TTools> - Message type with tool type parameter
- MessagePart<TTools> - Message part with tool type parameter
- TextPart - Text content part
- ThinkingPart - Thinking content part
- ToolCallPart<TTools> - Tool call part (discriminated union)
- ToolResultPart - Tool result part
- ChatClientOptions<TTools, TContext> - Chat client options with typed client runtime context
- ConnectionAdapter - Connection adapter interface
- InferChatMessages<T> - Extract message type from options
- ChatRequestBody - Request body type
- GenerationClientState - Generation lifecycle state
- ImageGenerateInput - Image generation input type
- SpeechGenerateInput - Speech generation input type
- TranscriptionGenerateInput - Transcription input type
- SummarizeGenerateInput - Summarization input type
- VideoGenerateInput - Video generation input type
- VideoGenerateResult - Video generation result type
- VideoStatusInfo - Video job status info
Re-exported from @tanstack/ai:
- toolDefinition() - Create isomorphic tool definition
- ToolDefinitionInstance - Tool definition type
- ClientTool - Client tool type
- ServerTool - Server tool type
Next Steps#
- Getting Started - Learn the basics
- Tools Guide - Learn about the isomorphic tool system
- Client Tools - Learn about client-side tools