Docs
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
Neon
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
Neon
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
Class References
Function References
Interface References
Type Alias References
Variable References
API

@tanstack/ai-vue

Vue composables for TanStack AI, providing convenient Vue 3 bindings for the headless client.

Installation

sh
npm install @tanstack/ai-vue

useChat(options?)

Main composable for managing chat state in Vue with full type safety.

typescript
import { useChat, fetchServerSentEvents } from "@tanstack/ai-vue";
import {
  clientTools,
  createChatClientOptions,
  type InferChatMessages,
} from "@tanstack/ai-client";

// In <script setup>
const updateUI = updateUIDef.client((input) => {
  notification.value = input.message;
  return { success: true };
});

const tools = clientTools(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)
  • initialMessages? - Initial messages array
  • id? - Unique identifier for this chat instance
  • body? - Additional body parameters to send (reactive -- changes are synced automatically via watch)
  • 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
  • onCustomEvent? - Callback for custom stream events
  • streamProcessor? - Stream processing configuration

Note: Client tools are now automatically executed - no onToolCall callback needed!

Returns

typescript
interface UseChatReturn {
  messages: DeepReadonly<ShallowRef<UIMessage[]>>;
  sendMessage: (content: string | MultimodalContent) => 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>>;
  setMessages: (messages: UIMessage[]) => void;
  clear: () => void;
}

Note: Reactive state (messages, isLoading, error, status, isSubscribed, connectionStatus, sessionGenerating) is wrapped in DeepReadonly<ShallowRef<T>>. Access values with .value (e.g., messages.value). Cleanup is automatic via onScopeDispose.

Connection Adapters

Re-exported from @tanstack/ai-client for convenience:

typescript
import {
  fetchServerSentEvents,
  fetchHttpStream,
  stream,
  type ConnectionAdapter,
} from "@tanstack/ai-vue";

Example: Basic Chat

vue
<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.value" :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.value" />
      <button type="submit" :disabled="isLoading.value">Send</button>
    </form>
  </div>
</template>

Example: Tool Approval

vue
<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.value" :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

vue
<script setup lang="ts">
import { ref } from "vue";
import { useChat, fetchServerSentEvents } from "@tanstack/ai-vue";
import {
  clientTools,
  createChatClientOptions,
  type InferChatMessages,
} from "@tanstack/ai-client";
import { updateUIDef, saveToStorageDef } from "./tool-definitions";

const notification = ref(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 = clientTools(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.value" :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.

typescript
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?, id?, body?, onResult?, onError?, onProgress?, onChunk?

Returns: generate, result, isLoading, error, status, stop, reset -- 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).

typescript
import {
  clientTools,
  createChatClientOptions,
  type InferChatMessages,
} from "@tanstack/ai-client";

// Create typed tools array (no 'as const' needed!)
const tools = clientTools(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> - Chat client options
  • 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