Skip to content
5 changes: 5 additions & 0 deletions .changeset/tall-chairs-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-vue': patch
---

Introduce `useChat()` for Vue
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
},
"packageManager": "pnpm@10.17.0",
"type": "module",
"pnpm": {
"overrides": {
"abbrev": "^3.0.0"
}
},
"scripts": {
"clean": "pnpm --filter \"./packages/**\" run clean",
"test": "pnpm run test:ci",
Expand Down
104 changes: 104 additions & 0 deletions packages/typescript/ai-vue/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<div align="center">
<img src="./media/header_ai.png" >
</div>

<br />

<div align="center">
<a href="https://npmjs.com/package/@tanstack/ai" target="\_parent">
<img alt="" src="https://img.shields.io/npm/dm/@tanstack/ai.svg" />
</a>
<a href="https://github.com/TanStack/ai" target="\_parent">
<img alt="" src="https://img.shields.io/github/stars/TanStack/ai.svg?style=social&label=Star" alt="GitHub stars" />
</a>
<a href="https://bundlephobia.com/result?p=@tanstack/ai@latest" target="\_parent">
<img alt="" src="https://badgen.net/bundlephobia/minzip/@tanstack/ai@latest" />
</a>
</div>

<div align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
</a>
<a href="#badge">
<img src="https://img.shields.io/github/v/release/tanstack/ai" alt="Release"/>
</a>
<a href="https://twitter.com/tan_stack">
<img src="https://img.shields.io/twitter/follow/tan_stack.svg?style=social" alt="Follow @TanStack"/>
</a>
</div>

<div align="center">

### [Become a Sponsor!](https://github.com/sponsors/tannerlinsley/)
</div>

# TanStack AI

A powerful, type-safe AI SDK for building AI-powered applications.

- Provider-agnostic adapters (OpenAI, Anthropic, Gemini, Ollama, etc.)
- Chat completion, streaming, and agent loop strategies
- Headless chat state management with adapters (SSE, HTTP stream, custom)
- Type-safe tools with server/client execution

### <a href="https://tanstack.com/ai">Read the docs →</b></a>

## Get Involved

- We welcome issues and pull requests!
- Participate in [GitHub discussions](https://github.com/TanStack/ai/discussions)
- Chat with the community on [Discord](https://discord.com/invite/WrRKjPJ)
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup instructions

## Partners

<table align="center">
<tr>
<td>
<a href="https://www.coderabbit.ai/?via=tanstack&dub_id=aCcEEdAOqqutX6OS" >
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/coderabbit-dark-CMcuvjEy.svg" height="40" />
<source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/coderabbit-light-DVMJ2jHi.svg" height="40" />
<img src="https://tanstack.com/assets/coderabbit-light-DVMJ2jHi.svg" height="40" alt="CodeRabbit" />
</picture>
</a>
</td>
<td>
<a href="https://www.cloudflare.com?utm_source=tanstack">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/cloudflare-white-DQDB7UaL.svg" height="60" />
<source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/cloudflare-black-CPufaW0B.svg" height="60" />
<img src="https://tanstack.com/assets/cloudflare-black-CPufaW0B.svg" height="60" alt="Cloudflare" />
</picture>
</a>
</td>
</tr>
</table>

<div align="center">
<img src="./media/partner_logo.svg" alt="AI & you?" height="65">
<p>
We're looking for TanStack AI Partners to join our mission! Partner with us to push the boundaries of TanStack AI and build amazing things together.
</p>
<a href="mailto:partners@tanstack.com?subject=TanStack AI Partnership"><b>LET'S CHAT</b></a>
</div>

## Explore the TanStack Ecosystem

- <a href="https://github.com/tanstack/config"><b>TanStack Config</b></a> – Tooling for JS/TS packages
- <a href="https://github.com/tanstack/db"><b>TanStack DB</b></a> – Reactive sync client store
- <a href="https://github.com/tanstack/devtools">TanStack Devtools</a> – Unified devtools panel
- <a href="https://github.com/tanstack/form"><b>TanStack Form</b></a> – Type‑safe form state
- <a href="https://github.com/tanstack/pacer"><b>TanStack Pacer</b></a> – Debouncing, throttling, batching
- <a href="https://github.com/tanstack/query"><b>TanStack Query</b></a> – Async state & caching
- <a href="https://github.com/tanstack/ranger"><b>TanStack Ranger</b></a> – Range & slider primitives
- <a href="https://github.com/tanstack/router"><b>TanStack Router</b></a> – Type‑safe routing, caching & URL state
- <a href="https://github.com/tanstack/router"><b>TanStack Start</b></a> – Full‑stack SSR & streaming
- <a href="https://github.com/tanstack/store"><b>TanStack Store</b></a> – Reactive data store
- <a href="https://github.com/tanstack/table"><b>TanStack Table</b></a> – Headless datagrids
- <a href="https://github.com/tanstack/virtual"><b>TanStack Virtual</b></a> – Virtualized rendering

… and more at <a href="https://tanstack.com"><b>TanStack.com »</b></a>

<!-- USE THE FORCE LUKE -->
61 changes: 61 additions & 0 deletions packages/typescript/ai-vue/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "@tanstack/ai-vue",
"version": "0.0.0",
"description": "Vue hooks for TanStack AI",
"author": "",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/TanStack/ai.git",
"directory": "packages/typescript/ai-vue"
},
"type": "module",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"files": [
"dist",
"src"
],
"scripts": {
"clean": "premove ./build ./dist",
"test:eslint": "eslint ./src",
"test:lib": "vitest run",
"test:lib:dev": "pnpm test:lib --watch",
"test:types": "tsc",
"build": "tsdown"
},
"keywords": [
"ai",
"vue",
"hooks",
"tanstack",
"chat",
"streaming"
],
"dependencies": {
"@tanstack/ai": "workspace:*",
"@tanstack/ai-client": "workspace:*",
"zod": "^4.1.13"
},
"devDependencies": {
"@types/node": "^24.10.1",
"@vitest/coverage-v8": "4.0.14",
"@vue/test-utils": "^2.4.6",
"jsdom": "^27.2.0",
"tsdown": "^0.17.0-beta.6",
"typescript": "5.9.3",
"vitest": "^4.0.14",
"vue": "^3.5.25"
},
"peerDependencies": {
"@tanstack/ai": "workspace:*",
"@tanstack/ai-client": "workspace:*",
"vue": ">=3.5.0"
}
}
18 changes: 18 additions & 0 deletions packages/typescript/ai-vue/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export { useChat } from './use-chat'
export type {
UseChatOptions,
UseChatReturn,
UIMessage,
ChatRequestBody,
} from './types'

// Re-export from ai-client for convenience
export {
fetchServerSentEvents,
fetchHttpStream,
stream,
createChatClientOptions,
type ConnectionAdapter,
type FetchConnectionOptions,
type InferChatMessages,
} from '@tanstack/ai-client'
102 changes: 102 additions & 0 deletions packages/typescript/ai-vue/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import type { DeepReadonly, ShallowRef } from 'vue'
import type { AnyClientTool, ModelMessage } from '@tanstack/ai'
import type {
ChatClientOptions,
ChatRequestBody,
UIMessage,
} from '@tanstack/ai-client'

// Re-export types from ai-client
export type { UIMessage, ChatRequestBody }

/**
* Options for the useChat composable.
*
* This extends ChatClientOptions but omits the state change callbacks that are
* managed internally by Vue refs:
* - `onMessagesChange` - Managed by Vue ref (exposed as `messages`)
* - `onLoadingChange` - Managed by Vue ref (exposed as `isLoading`)
* - `onErrorChange` - Managed by Vue ref (exposed as `error`)
*
* All other callbacks (onResponse, onChunk, onFinish, onError) are
* passed through to the underlying ChatClient and can be used for side effects.
*
* Note: Connection and body changes will recreate the ChatClient instance.
* To update these options, remount the component or use a key prop.
*/
export type UseChatOptions<TTools extends ReadonlyArray<AnyClientTool> = any> =
Omit<
ChatClientOptions<TTools>,
'onMessagesChange' | 'onLoadingChange' | 'onErrorChange'
>

export interface UseChatReturn<
TTools extends ReadonlyArray<AnyClientTool> = any,
> {
/**
* Current messages in the conversation
*/
messages: DeepReadonly<ShallowRef<Array<UIMessage<TTools>>>>

/**
* Send a message and get a response
*/
sendMessage: (content: string) => Promise<void>

/**
* Append a message to the conversation
*/
append: (message: ModelMessage | UIMessage<TTools>) => Promise<void>

/**
* Add the result of a client-side tool execution
*/
addToolResult: (result: {
toolCallId: string
tool: string
output: any
state?: 'output-available' | 'output-error'
errorText?: string
}) => Promise<void>

/**
* Respond to a tool approval request
*/
addToolApprovalResponse: (response: {
id: string // approval.id, not toolCallId
approved: boolean
}) => Promise<void>

/**
* Reload the last assistant message
*/
reload: () => Promise<void>

/**
* Stop the current response generation
*/
stop: () => void

/**
* Whether a response is currently being generated
*/
isLoading: DeepReadonly<ShallowRef<boolean>>

/**
* Current error, if any
*/
error: DeepReadonly<ShallowRef<Error | undefined>>

/**
* Set messages manually
*/
setMessages: (messages: Array<UIMessage<TTools>>) => void

/**
* Clear all messages
*/
clear: () => void
}

// Note: createChatClientOptions and InferChatMessages are now in @tanstack/ai-client
// and re-exported from there for convenience
Loading
Loading