-
-
Notifications
You must be signed in to change notification settings - Fork 109
docs(ai-vue): add docs for ai-vue #126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,280 @@ | ||||||||||
| --- | ||||||||||
| title: TanStack AI Vue API | ||||||||||
| slug: /api/ai-vue | ||||||||||
| --- | ||||||||||
|
|
||||||||||
| Vue hooks for TanStack AI, providing convenient Vue bindings for the headless client. | ||||||||||
|
|
||||||||||
| ## Installation | ||||||||||
|
|
||||||||||
| ```bash | ||||||||||
| npm install @tanstack/ai-vue | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| ## `useChat(options?)` | ||||||||||
|
|
||||||||||
| Main composable for managing chat state in Vue with full 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"; | ||||||||||
| // see more in https://tanstack.com/ai/latest/docs/guides/client-tools#defining-client-tools | ||||||||||
| import { updateUIDef } from "@/tools/definitions"; | ||||||||||
|
|
||||||||||
| const notification = ref<string | null>(null); | ||||||||||
|
|
||||||||||
| // Create client tool implementations, | ||||||||||
| const updateUI = updateUIDef.client((input) => { | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure what is the purpose of this tool. Maybe it makes sense in @AlemTuzlak Was original |
||||||||||
| notification.value = input.message; | ||||||||||
| return { success: true }; | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| // Create typed tools array (no 'as const' needed!) | ||||||||||
| 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); | ||||||||||
| </script> | ||||||||||
|
|
||||||||||
| <template> | ||||||||||
| <div><!-- Chat UI with typed messages --></div> | ||||||||||
| </template> | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| ### Options | ||||||||||
|
|
||||||||||
| Extends `ChatClientOptions` from `@tanstack/ai-client`: | ||||||||||
|
|
||||||||||
| - `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 | ||||||||||
| - `onResponse?` - Callback when response is received | ||||||||||
| - `onChunk?` - Callback when stream chunk is received | ||||||||||
| - `onFinish?` - Callback when response finishes | ||||||||||
| - `onError?` - Callback when error occurs | ||||||||||
| - `streamProcessor?` - Stream processing configuration | ||||||||||
|
|
||||||||||
| **Note:** Client tools are now automatically executed - no `onToolCall` callback needed! | ||||||||||
|
|
||||||||||
| ### Returns | ||||||||||
|
|
||||||||||
| ```typescript | ||||||||||
| interface UseChatReturn { | ||||||||||
| messages: DeepReadonly<ShallowRef<Array<UIMessage>>>; | ||||||||||
| sendMessage: (content: string) => 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>>; | ||||||||||
| setMessages: (messages: UIMessage[]) => void; | ||||||||||
| clear: () => void; | ||||||||||
| } | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| ## 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 = (e: Event) => { | ||||||||||
| const val = input.value.trim() | ||||||||||
| if (((val ?? '') !== '') && !isLoading) { | ||||||||||
| sendMessage(input.value); | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we would need |
||||||||||
| input.value = ''; | ||||||||||
| } | ||||||||||
|
Comment on lines
+127
to
+132
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix ref access and simplify condition. The condition on line 129 should use Additionally, the condition on line 128 has unnecessary nested parentheses. π Proposed fix const handleSubmit = (e: Event) => {
const val = input.value.trim()
- if (((val ?? '') !== '') && !isLoading) {
+ if (val !== '' && !isLoading.value) {
sendMessage(input.value);
input.value = '';
}
};π€ Prompt for AI Agents |
||||||||||
| }; | ||||||||||
| </script> | ||||||||||
| <template> | ||||||||||
| <div> | ||||||||||
| <div v-for="message in messages" :key="message.id"> | ||||||||||
| <strong>{{ message.role }}</strong> | ||||||||||
| <div v-for="part in message.parts" :key="part.id"> | ||||||||||
| <span v-if="part.type === 'text'">{{ part.content }}</span> | ||||||||||
| <div v-else-if="part.type === 'thinking'" class="text-sm text-gray-500 italic"> π Thinking: {{ part.content }}</div> | ||||||||||
| <!-- you can custom more parts --> | ||||||||||
| </div> | ||||||||||
| </div> | ||||||||||
| <form @submit.prevent="handleSubmit"> | ||||||||||
| <input v-model="input" :disabled="isLoading"/> | ||||||||||
| <button type="submit" :disabled="isLoading"> | ||||||||||
| Send | ||||||||||
| </button> | ||||||||||
| </form> | ||||||||||
| <div> | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix closing tag syntax error. Line 151 has a syntax error - it should be a closing π Proposed fix </form>
- <div>
+ </div>
</template>π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||
| </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" > | ||||||||||
| <template v-for="part in message.parts" > | ||||||||||
| <div v-if="part.type === 'tool-call' && part.state === 'approval-requested' && part.approval" :key="part.id"> | ||||||||||
| <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 "@/tools/definitions"; | ||||||||||
|
|
||||||||||
| const notification = ref<{message: string; type: 'success' | 'error'}>(null); | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure what for
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix type definition to include null. The ref is initialized with π Proposed fix-const notification = ref<{message: string; type: 'success' | 'error'}>(null);
+const notification = ref<{message: string; type: 'success' | 'error'} | null>(null);π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||
|
|
||||||||||
| 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" > | ||||||||||
| <template v-for="part in message.parts" > | ||||||||||
| <div v-if="part.type === 'tool-call' && part.name === 'updateUI'" :key="part.id"> | ||||||||||
| <p>Tool executed: {{ part.name }}</p> | ||||||||||
| </div> | ||||||||||
| </template> | ||||||||||
| </template> | ||||||||||
| </div> | ||||||||||
| </template> | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| ## `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 | ||||||||||
|
|
||||||||||
| 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](../getting-started/quick-start) - Learn the basics | ||||||||||
| - [Tools Guide](../guides/tools) - Learn about the isomorphic tool system | ||||||||||
| - [Client Tools](../guides/client-tools) - Learn about client-side tools | ||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This tool def seems to be buried in one of the other pages, maybe in-lining it would be wise?
Or at least a link to this tool definition?
@AlemTuzlak