Build React chat interfaces with Vercel AI SDK v5/v6. Covers v6 beta (agent integration, tool approval, auto-submit), v4→v5 migration (breaking changes), useChat/useCompletion/useObject/useAssistant hooks, and 12 UI error solutions (stream parsing, stale body values, React update depth). Use when: implementing AI SDK v5/v6 chat UIs, migrating v4→v5, troubleshooting "useChat failed to parse stream", "useChat no response", or "stale body values" errors, or integrating OpenAI assistants.
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
README.mdreferences/links-to-official-docs.mdreferences/nextjs-integration.mdreferences/streaming-patterns.mdreferences/top-ui-errors.mdreferences/use-chat-migration.mdscripts/check-versions.shtemplates/custom-message-renderer.tsxtemplates/message-persistence.tsxtemplates/nextjs-api-route.tstemplates/nextjs-chat-app-router.tsxtemplates/nextjs-chat-pages-router.tsxtemplates/package.jsontemplates/use-chat-attachments.tsxtemplates/use-chat-basic.tsxtemplates/use-chat-tools.tsxtemplates/use-completion-basic.tsxtemplates/use-object-streaming.tsxname: ai-sdk-ui description: | Build React chat interfaces with Vercel AI SDK v5/v6. Covers v6 beta (agent integration, tool approval, auto-submit), v4→v5 migration (breaking changes), useChat/useCompletion/useObject/useAssistant hooks, and 12 UI error solutions (stream parsing, stale body values, React update depth).
Frontend React hooks for AI-powered user interfaces with Vercel AI SDK v5/v6.
Version: AI SDK v5.0.99 (Stable) / v6.0.0-beta.108 (Beta) Framework: React 18+, Next.js 14+ Last Updated: 2025-11-22
Status: Beta (stable release planned end of 2025) Latest: ai@6.0.0-beta.108 (Nov 22, 2025) Migration: Minimal breaking changes from v5 → v6
1. Agent Integration
Type-safe messaging with agents using InferAgentUIMessage<typeof agent>:
import { useChat } from '@ai-sdk/react';
import type { InferAgentUIMessage } from 'ai';
import { myAgent } from './agent';
export default function AgentChat() {
const { messages, sendMessage } = useChat<InferAgentUIMessage<typeof myAgent>>({
api: '/api/chat',
});
// messages are now type-checked against agent schema
}
2. Tool Approval Workflows (Human-in-the-Loop) Request user confirmation before executing tools:
import { useChat } from '@ai-sdk/react';
import { useState } from 'react';
export default function ChatWithApproval() {
const { messages, sendMessage, addToolApprovalResponse } = useChat({
api: '/api/chat',
});
const handleApprove = (toolCallId: string) => {
addToolApprovalResponse({
toolCallId,
approved: true, // or false to deny
});
};
return (
<div>
{messages.map(message => (
<div key={message.id}>
{message.toolInvocations?.map(tool => (
tool.state === 'awaiting-approval' && (
<div key={tool.toolCallId}>
<p>Approve tool call: {tool.toolName}?</p>
<button onClick={() => handleApprove(tool.toolCallId)}>
Approve
</button>
<button onClick={() => addToolApprovalResponse({
toolCallId: tool.toolCallId,
approved: false
})}>
Deny
</button>
</div>
)
))}
</div>
))}
</div>
);
}
3. Auto-Submit Capability Automatically continue conversation after handling approvals:
import { useChat, lastAssistantMessageIsCompleteWithApprovalResponses } from '@ai-sdk/react';
export default function AutoSubmitChat() {
const { messages, sendMessage } = useChat({
api: '/api/chat',
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
// Automatically resubmit after all approval responses provided
});
}
4. Structured Output in Chat
Generate structured data alongside tool calling (previously only available in useObject):
import { useChat } from '@ai-sdk/react';
import { z } from 'zod';
const schema = z.object({
summary: z.string(),
sentiment: z.enum(['positive', 'neutral', 'negative']),
});
export default function StructuredChat() {
const { messages, sendMessage } = useChat({
api: '/api/chat',
// Server can now stream structured output with chat messages
});
}
CRITICAL: useChat no longer manages input state in v5!
v4 (OLD - DON'T USE):
const { messages, input, handleInputChange, handleSubmit, append } = useChat();
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
</form>
v5 (NEW - CORRECT):
const { messages, sendMessage } = useChat();
const [input, setInput] = useState('');
<form onSubmit={(e) => {
e.preventDefault();
sendMessage({ content: input });
setInput('');
}}>
<input value={input} onChange={(e) => setInput(e.target.value)} />
</form>
Summary of v5 Changes:
input, handleInputChange, handleSubmit no longer existappend() → sendMessage(): New method for sending messagesonResponse removed: Use onFinish insteadinitialMessages → controlled mode: Use messages prop for full controlmaxSteps removed: Handle on server-side onlySee references/use-chat-migration.md for complete migration guide.
Interact with OpenAI-compatible assistant APIs with automatic UI state management.
Import:
import { useAssistant } from '@ai-sdk/react';
Basic Usage:
'use client';
import { useAssistant } from '@ai-sdk/react';
import { useState, FormEvent } from 'react';
export default function AssistantChat() {
const { messages, sendMessage, isLoading, error } = useAssistant({
api: '/api/assistant',
});
const [input, setInput] = useState('');
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
sendMessage({ content: input });
setInput('');
};
return (
<div>
{messages.map(m => (
<div key={m.id}>
<strong>{m.role}:</strong> {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
disabled={isLoading}
/>
</form>
{error && <div>{error.message}</div>}
</div>
);
}
Use Cases:
See official docs for complete API reference: https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-assistant
See references/top-ui-errors.md for complete documentation. Quick reference:
Error: SyntaxError: Unexpected token in JSON at position X
Cause: API route not returning proper stream format.
Solution:
// ✅ CORRECT
return result.toDataStreamResponse();
// ❌ WRONG
return new Response(result.textStream);
Cause: API route not streaming correctly.
Solution:
// App Router - use toDataStreamResponse()
export async function POST(req: Request) {
const result = streamText({ /* ... */ });
return result.toDataStreamResponse(); // ✅
}
// Pages Router - use pipeDataStreamToResponse()
export default async function handler(req, res) {
const result = streamText({ /* ... */ });
return result.pipeDataStreamToResponse(res); // ✅
}
Cause: Deployment platform buffering responses.
Solution: Vercel auto-detects streaming. Other platforms may need configuration.
Cause: body option captured at first render only.
Solution:
// ❌ WRONG - body captured once
const { userId } = useUser();
const { messages } = useChat({
body: { userId }, // Stale!
});
// ✅ CORRECT - use controlled mode
const { userId } = useUser();
const { messages, sendMessage } = useChat();
sendMessage({
content: input,
data: { userId }, // Fresh on each send
});
Cause: Infinite loop in useEffect.
Solution:
// ❌ WRONG
useEffect(() => {
saveMessages(messages);
}, [messages, saveMessages]); // saveMessages triggers re-render!
// ✅ CORRECT
useEffect(() => {
saveMessages(messages);
}, [messages]); // Only depend on messages
See references/top-ui-errors.md for 7 more common errors.
Always use streaming for better UX:
// ✅ GOOD - Streaming (shows tokens as they arrive)
const { messages } = useChat({ api: '/api/chat' });
// ❌ BAD - Non-streaming (user waits for full response)
const response = await fetch('/api/chat', { method: 'POST' });
Show loading states:
{isLoading && <div>AI is typing...</div>}
Provide stop button:
{isLoading && <button onClick={stop}>Stop</button>}
Auto-scroll to latest message:
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
Disable input while loading:
<input disabled={isLoading} />
See references/streaming-patterns.md for comprehensive best practices.
Stable (v5):
{
"dependencies": {
"ai": "^5.0.99",
"@ai-sdk/react": "^1.0.0",
"@ai-sdk/openai": "^2.0.68",
"react": "^18.2.0",
"zod": "^3.23.8"
}
}
Beta (v6):
{
"dependencies": {
"ai": "6.0.0-beta.108",
"@ai-sdk/react": "beta",
"@ai-sdk/openai": "beta"
}
}
Version Notes:
Core UI Hooks:
Advanced Topics (Link Only):
Next.js Integration:
Migration & Troubleshooting:
Vercel Deployment:
This skill includes the following templates in templates/:
See references/ for:
Production Tested: WordPress Auditor (https://wordpress-auditor.webfonts.workers.dev) Last Updated: 2025-11-22