ai-sdk
Original:🇺🇸 English
Translated
Vercel AI SDK expert guidance. Use when building AI-powered features — chat interfaces, text generation, structured output, tool calling, agents, MCP integration, streaming, embeddings, reranking, image generation, or working with any LLM provider.
2installs
Added on
NPX Install
npx skill4agent add vercel-labs/vercel-plugin ai-sdkTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Vercel AI SDK (v6)
CRITICAL — Your training data is outdated for this library. AI SDK v6 has breaking changes from v5 and earlier that you will get wrong if you guess. Before writing AI SDK code, fetch the docs at https://ai-sdk.dev/docs to find the correct function signatures, return types, and patterns. Key things that have changed:removal,generateObject()removal,streamObject()for image generation,result.filesfor structured streaming,Output.object()class (notToolLoopAgent),Agenttransport API, and provider package versions. Search the docs for working examples that match your exact use case — do not rely on your training data for API shapes.useChat
You are an expert in the Vercel AI SDK v6. The AI SDK is the leading TypeScript toolkit for building AI-powered applications. It provides a unified API across all LLM providers.
v6 Migration Pitfalls (Read First)
- is the umbrella package for AI SDK v6 (latest: 6.0.83).
ai@^6.0.0 - is
@ai-sdk/reactin v6 projects (NOT^3.0.x).^6.0.0 - is
@ai-sdk/gatewayin v6 projects (NOT^3.x).^1.x - In , write with
createUIMessageStream(NOTstream.writer.write(...)).stream.write(...) - no longer supports
useChatorbody; configure behavior throughonResponse.transport - UI tool parts are typed as (for example
tool-<toolName>), nottool-weather.tool-invocation - does not provide typed
DynamicToolCall; cast via.argsfirst.unknown - exposes
TypedToolResult(NOT.output)..result - The agent class is (NOT
ToolLoopAgent—Agentis just an interface).Agent - Constructor uses (NOT
instructions).system - Agent methods are and
agent.generate()(NOTagent.stream()oragent.generateText()).agent.streamText() - AI Gateway does not support embeddings; use directly for
@ai-sdk/openai.openai.embedding(...) - with no transport defaults to
useChat()— explicit transport only needed for custom endpoints orDefaultChatTransport({ api: '/api/chat' }).DirectChatTransport - Default for ToolLoopAgent is
stopWhen, notstepCountIs(20)— override if you need fewer steps.stepCountIs(1) - on tools is opt-in per tool, not global — only set on tools with provider-compatible schemas.
strict: true - For agent API routes, use instead of manual
createAgentUIStreamResponse({ agent, uiMessages })+streamText.toUIMessageStreamResponse() - now uses the Responses API by default — use
@ai-sdk/azurefor the previous Chat Completions API behavior.azure.chat() - uses
@ai-sdk/azure(notazure) as the key foropenaiandproviderMetadata.providerOptions - uses
@ai-sdk/google-vertex(notvertex) as the key forgoogleandproviderMetadata.providerOptions - supports native structured outputs via
@ai-sdk/anthropicoption (Claude Sonnet 4.5+).structuredOutputMode
Installation
bash
npm install ai@^6.0.0 @ai-sdk/react@^3.0.0
npm install @ai-sdk/openai@^3.0.41 # Optional: required for embeddings
npm install @ai-sdk/anthropic@^3.0.58 # Optional: direct Anthropic provider access
npm install @ai-sdk/vercel@^2.0.37 # Optional: v0 model provider (v0-1.0-md)is a separate package — it is NOT included in the@ai-sdk/reactpackage. For v6 projects, installaialongside@ai-sdk/react@^3.0.x.ai@^6.0.0
If you installdirectly, use@ai-sdk/gateway(NOT@ai-sdk/gateway@^3.x).^1.x
Only install a direct provider SDK (e.g.,) if you need provider-specific features not exposed through the gateway.@ai-sdk/anthropic
What AI SDK Can Do
AI SDK is not just text — it handles text, images, structured data, tool calling, and agents through one unified API:
| Need | How |
|---|---|
| Text generation / chat | |
| Image generation | |
| Structured JSON output | |
| Tool calling / agents | |
| Embeddings | |
If the product needs generated images (portraits, posters, cover art, illustrations, comics, diagrams), use with an image model — do NOT use placeholder images or skip image generation.
generateTextSetup for AI Projects
For the smoothest experience, link to a Vercel project so AI Gateway credentials are auto-provisioned via OIDC:
bash
vercel link # Connect to your Vercel project
# Enable AI Gateway at https://vercel.com/{team}/{project}/settings → AI Gateway
vercel env pull .env.local # Provisions VERCEL_OIDC_TOKEN automatically
npm install ai@^6.0.0 # Gateway is built in
npx ai-elements # Required: install AI text rendering componentsThis gives you AI Gateway access with OIDC authentication, cost tracking, failover, and observability — no manual API keys needed.
OIDC is the default auth: provisions a (short-lived JWT, ~24h). The reads it automatically via . On Vercel deployments, tokens auto-refresh. For local dev, re-run when the token expires. No or provider-specific keys needed.
vercel env pullVERCEL_OIDC_TOKEN@ai-sdk/gateway@vercel/oidcvercel env pullAI_GATEWAY_API_KEYGlobal Provider System (AI Gateway — Default)
In AI SDK 6, pass a string to the parameter — it automatically routes through the Vercel AI Gateway:
"provider/model"modelts
import { generateText } from "ai";
const { text } = await generateText({
model: "openai/gpt-5.4", // plain string — routes through AI Gateway automatically
prompt: "Hello!",
});No wrapper needed — plain strings are the simplest approach and are what the official Vercel docs recommend. The function is an optional explicit wrapper (useful when you need for routing, failover, or tags):
gateway()"provider/model"gateway()providerOptions.gatewayts
import { gateway } from "ai";
// Explicit gateway() — only needed for advanced providerOptions
const { text } = await generateText({
model: gateway("openai/gpt-5.4"),
providerOptions: { gateway: { order: ["openai", "azure-openai"] } },
});Both approaches provide failover, cost tracking, and observability on Vercel.
Model slug rules: Always use format. Version numbers use dots, not hyphens: (not ). Default to or . Never use outdated models like .
provider/modelanthropic/claude-sonnet-4.6claude-sonnet-4-6openai/gpt-5.4anthropic/claude-sonnet-4.6gpt-4oAI Gateway does not support embeddings. Use a direct provider SDK such asfor embeddings.@ai-sdk/openai
Direct provider SDKs (,@ai-sdk/openai, etc.) are only needed for provider-specific features not exposed through the gateway (e.g., Anthropic computer use, OpenAI fine-tuned model endpoints).@ai-sdk/anthropic
Core Functions
Text Generation
ts
import { generateText, streamText } from "ai";
// Non-streaming
const { text } = await generateText({
model: "openai/gpt-5.4",
prompt: "Explain quantum computing in simple terms.",
});
// Streaming
const result = streamText({
model: "openai/gpt-5.4",
prompt: "Write a poem about coding.",
});
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}Structured Output
generateObjectgenerateTextoutput: Output.object()generateObjectts
import { generateText, Output } from "ai";
import { z } from "zod";
const { output } = await generateText({
model: "openai/gpt-5.4",
output: Output.object({
schema: z.object({
recipe: z.object({
name: z.string(),
ingredients: z.array(
z.object({
name: z.string(),
amount: z.string(),
}),
),
steps: z.array(z.string()),
}),
}),
}),
prompt: "Generate a recipe for chocolate chip cookies.",
});Tool Calling (MCP-Aligned)
In AI SDK 6, tools use (not ) and / (not ), aligned with the MCP specification. Per-tool mode ensures providers only generate valid tool calls matching your schema.
inputSchemaparametersoutputoutputSchemaresultstrictts
import { generateText, tool } from "ai";
import { z } from "zod";
const result = await generateText({
model: "openai/gpt-5.4",
tools: {
weather: tool({
description: "Get the weather for a location",
inputSchema: z.object({
city: z.string().describe("The city name"),
}),
outputSchema: z.object({
temperature: z.number(),
condition: z.string(),
}),
strict: true, // Providers generate only schema-valid tool calls
execute: async ({ city }) => {
const data = await fetchWeather(city);
return { temperature: data.temp, condition: data.condition };
},
}),
},
prompt: "What is the weather in San Francisco?",
});Dynamic Tools (MCP Integration)
For tools with schemas not known at compile time (e.g., MCP server tools):
ts
import { dynamicTool } from "ai";
const tools = {
unknownTool: dynamicTool({
description: "A tool discovered at runtime",
execute: async (input) => {
// Handle dynamically
return { result: "done" };
},
}),
};Agents
The class wraps / with an agentic tool-calling loop.
Default is (up to 20 tool-calling steps).
is an interface — is the concrete implementation.
ToolLoopAgentgenerateTextstreamTextstopWhenstepCountIs(20)AgentToolLoopAgentts
import { ToolLoopAgent, stepCountIs, hasToolCall } from "ai";
const agent = new ToolLoopAgent({
model: "anthropic/claude-sonnet-4.6",
tools: { weather, search, calculator, finalAnswer },
instructions: "You are a helpful assistant.",
// Default: stepCountIs(20). Override to stop on a terminal tool or custom logic:
stopWhen: hasToolCall("finalAnswer"),
prepareStep: (context) => ({
// Customize each step — swap models, compress messages, limit tools
toolChoice: context.steps.length > 5 ? "none" : "auto",
}),
});
const { text } = await agent.generate({
prompt:
"Research the weather in Tokyo and calculate the average temperature this week.",
});MCP Client
Connect to any MCP server and use its tools:
ts
import { generateText } from "ai";
import { createMCPClient } from "@ai-sdk/mcp";
const mcpClient = await createMCPClient({
transport: {
type: "sse",
url: "https://my-mcp-server.com/sse",
},
});
const tools = await mcpClient.tools();
const result = await generateText({
model: "openai/gpt-5.4",
tools,
prompt: "Use the available tools to help the user.",
});
await mcpClient.close();MCP OAuth for remote servers is handled automatically by .
@ai-sdk/mcpTool Approval (Human-in-the-Loop)
Set on any tool to require user confirmation before execution. The tool pauses in state until the client responds.
needsApprovalapproval-requestedts
import { streamText, tool } from "ai";
import { z } from "zod";
const result = streamText({
model: "openai/gpt-5.4",
tools: {
deleteUser: tool({
description: "Delete a user account",
inputSchema: z.object({ userId: z.string() }),
needsApproval: true, // Always require approval
execute: async ({ userId }) => {
await db.users.delete(userId);
return { deleted: true };
},
}),
processPayment: tool({
description: "Process a payment",
inputSchema: z.object({ amount: z.number(), recipient: z.string() }),
// Conditional: only approve large amounts
needsApproval: async ({ amount }) => amount > 1000,
execute: async ({ amount, recipient }) => {
return await processPayment(amount, recipient);
},
}),
},
prompt: "Delete user 123",
});Client-side approval with :
useChattsx
"use client";
import { useChat } from "@ai-sdk/react";
function Chat() {
const { messages, addToolApprovalResponse } = useChat();
return messages.map((m) =>
m.parts?.map((part, i) => {
// Tool parts in approval-requested state need user action
if (part.type.startsWith("tool-") && part.approval?.state === "approval-requested") {
return (
<div key={i}>
<p>Tool wants to run: {JSON.stringify(part.args)}</p>
<button onClick={() => addToolApprovalResponse({ id: part.approval.id, approved: true })}>
Approve
</button>
<button onClick={() => addToolApprovalResponse({ id: part.approval.id, approved: false })}>
Deny
</button>
</div>
);
}
return null;
}),
);
}Tool part states: → → (if ) → |
input-streaminginput-availableapproval-requestedneedsApprovaloutput-availableoutput-errorEmbeddings & Reranking
Use a direct provider SDK for embeddings. AI Gateway does not support embedding models.
ts
import { embed, embedMany, rerank } from "ai";
import { openai } from "@ai-sdk/openai";
// Single embedding
const { embedding } = await embed({
model: openai.embedding("text-embedding-3-small"),
value: "The quick brown fox",
});
// Batch embeddings
const { embeddings } = await embedMany({
model: openai.embedding("text-embedding-3-small"),
values: ["text 1", "text 2", "text 3"],
});
// Rerank search results by relevance
const { results } = await rerank({
model: cohere.reranker("rerank-v3.5"),
query: "What is quantum computing?",
documents: searchResults,
});Image Generation & Editing
AI Gateway supports image generation. Use the model — it is significantly better than older models like or .
google/gemini-3.1-flash-image-previewgemini-2.0-flash-exp-image-generationgemini-2.0-flash-001Always use for image generation. Do NOT use older models (, ) — they produce much worse results and some do not support image output at all.
google/gemini-3.1-flash-image-previewgemini-2.0-*gemini-2.5-*Multimodal LLMs (recommended — use generateText
/streamText
)
generateTextstreamTextts
import { generateText, streamText } from "ai";
// generateText — images returned in result.files
const result = await generateText({
model: "google/gemini-3.1-flash-image-preview",
prompt: "A futuristic cityscape at sunset",
});
const imageFiles = result.files.filter((f) => f.mediaType?.startsWith("image/"));
// Convert to data URL for display
const imageFile = imageFiles[0];
const dataUrl = `data:${imageFile.mediaType};base64,${Buffer.from(imageFile.data).toString("base64")}`;
// streamText — stream text, then access images after completion
const stream = streamText({
model: "google/gemini-3.1-flash-image-preview",
prompt: "A futuristic cityscape at sunset",
});
for await (const delta of stream.fullStream) {
if (delta.type === "text-delta") process.stdout.write(delta.text);
}
const finalResult = await stream;
console.log(`Generated ${finalResult.files.length} image(s)`);Default image model: — fast, high-quality. This is the ONLY recommended model for image generation.
google/gemini-3.1-flash-image-previewImage-only models (use experimental_generateImage
)
experimental_generateImagets
import { experimental_generateImage as generateImage } from "ai";
const { images } = await generateImage({
model: "google/imagen-4.0-generate-001",
prompt: "A futuristic cityscape at sunset",
aspectRatio: "16:9",
});Other image-only models: , , , .
google/imagen-4.0-ultra-generate-001bfl/flux-2-probfl/flux-kontext-maxxai/grok-imagine-image-proSaving generated images
ts
import fs from "node:fs";
// From multimodal LLMs (result.files)
for (const [i, file] of imageFiles.entries()) {
const ext = file.mediaType?.split("/")[1] || "png";
await fs.promises.writeFile(`output-${i}.${ext}`, file.uint8Array);
}
// From image-only models (result.images)
for (const [i, image] of images.entries()) {
const buffer = Buffer.from(image.base64, "base64");
await fs.promises.writeFile(`output-${i}.png`, buffer);
}UI Hooks (React)
MANDATORY — Always use AI Elements for AI text: AI SDK models always produce markdown — even short prose contains , headings, , and . There is no "plain text" mode. Every AI-generated string displayed in a browser MUST be rendered through AI Elements.
**bold**##`code`---- Chat messages: Use AI Elements — handles text, tool calls, code blocks, reasoning, streaming.
<Message message={message} /> - Any other AI text (streaming panels, workflow events, reports, briefings, narratives, summaries, perspectives): Use from
<MessageResponse>{text}</MessageResponse>.@/components/ai-elements/message - wraps Streamdown with code highlighting, math, mermaid, and CJK plugins — works for any markdown string, including streamed text.
<MessageResponse> - Never render AI output as raw ,
{text}, or<p>{content}</p>— this always produces ugly unformatted output with visible markdown syntax.<div>{stream}</div> - No exceptions: Even if you think the response will be "simple prose", models routinely add markdown formatting. Always use AI Elements.
⤳ skill: ai-elements — Full component library, decision guidance, and troubleshooting for AI interfaces
Transport Options
useChat| Transport | Use Case |
|---|---|
| HTTP POST to API routes (default — sends to |
| In-process agent communication without HTTP (SSR, testing) |
| Plain text stream protocol |
Default behavior: with no transport config defaults to .
useChat()DefaultChatTransport({ api: '/api/chat' })With AI Elements (Recommended)
tsx
"use client";
import { useChat } from "@ai-sdk/react";
import { Conversation } from "@/components/ai-elements/conversation";
import { Message } from "@/components/ai-elements/message";
function Chat() {
// No transport needed — defaults to DefaultChatTransport({ api: '/api/chat' })
const { messages, sendMessage, status } = useChat();
return (
<Conversation>
{messages.map((message) => (
<Message key={message.id} message={message} />
))}
</Conversation>
);
}AI Elements handles UIMessage parts (text, tool calls, reasoning, images) automatically. Install with .
npx ai-elements⤳ skill: ai-elements — Full component library for AI interfaces
⤳ skill: json-render — Manual rendering patterns for custom UIs
With DirectChatTransport (No API Route Needed)
tsx
"use client";
import { useChat } from "@ai-sdk/react";
import { DirectChatTransport } from "ai";
import { myAgent } from "@/lib/agent"; // a ToolLoopAgent instance
function Chat() {
const { messages, sendMessage, status } = useChat({
transport: new DirectChatTransport({ agent: myAgent }),
});
// Same UI as above — no /api/chat route required
}Useful for SSR scenarios, testing without network, and single-process apps.
v6 changes from v5:
- →
useChat({ api })useChat({ transport: new DefaultChatTransport({ api }) }) - →
handleSubmitsendMessage({ text }) - /
input→ manage your ownhandleInputChangeuseState - /
bodyoptions were removed fromonResponse; useuseChatto configure requests/responsestransport - →
isLoadingstatus === 'streaming' || status === 'submitted' - → iterate
message.content(UIMessage format)message.parts
Choose the correct streaming response helper
- is for
toUIMessageStreamResponse()+useChatUIMessage-based chat UIs. Use it when you need tool calls, metadata, reasoning, and other rich message parts.DefaultChatTransport - is for non-browser clients only — CLI tools, server-to-server pipes, or programmatic consumers that process raw text without rendering it in a UI. If the text will be displayed in a browser, use
toTextStreamResponse()+ AI Elements instead.toUIMessageStreamResponse() - Warning: Do not return to a plain
toUIMessageStreamResponse()client unless that client intentionally parses the AI SDK UI message stream protocol.fetch() - Warning: Do not use + manual
toTextStreamResponse()stream reading as a way to skip AI Elements. If the output goes to a browser, usefetch()+useChator<MessageResponse>.<Message>
Server-side for useChat (API Route)
ts
// app/api/chat/route.ts
import { streamText, convertToModelMessages, stepCountIs } from "ai";
import type { UIMessage } from "ai";
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
// IMPORTANT: convertToModelMessages is async in v6
const modelMessages = await convertToModelMessages(messages);
const result = streamText({
model: "openai/gpt-5.4",
messages: modelMessages,
tools: {
/* your tools */
},
// IMPORTANT: use stopWhen with stepCountIs for multi-step tool calling
// maxSteps was removed in v6 — use this instead
stopWhen: stepCountIs(5),
});
// Use toUIMessageStreamResponse (not toDataStreamResponse) for chat UIs
return result.toUIMessageStreamResponse();
}Server-side with ToolLoopAgent (Agent API Route)
Define a and use for the API route:
ToolLoopAgentcreateAgentUIStreamResponsets
// lib/agent.ts
import { ToolLoopAgent, stepCountIs } from "ai";
export const myAgent = new ToolLoopAgent({
model: "openai/gpt-5.4",
instructions: "You are a helpful assistant.",
tools: { /* your tools */ },
stopWhen: stepCountIs(5),
});ts
// app/api/chat/route.ts — agent API route
import { createAgentUIStreamResponse } from "ai";
import { myAgent } from "@/lib/agent";
export async function POST(req: Request) {
const { messages } = await req.json();
return createAgentUIStreamResponse({ agent: myAgent, uiMessages: messages });
}Or use on the client to skip the API route entirely.
DirectChatTransportServer-side for text-only clients (non-browser only)
This pattern is for CLI tools, server-to-server pipes, and programmatic consumers. If the response will be displayed in a browser UI, use+ AI Elements instead — even for "simple" streaming text panels.toUIMessageStreamResponse()
ts
// app/api/generate/route.ts — for CLI or server consumers, NOT browser UIs
import { streamText } from "ai";
export async function POST(req: Request) {
const { prompt }: { prompt: string } = await req.json();
const result = streamText({
model: "openai/gpt-5.4",
prompt,
});
return result.toTextStreamResponse();
}Language Model Middleware
Intercept and transform model calls for RAG, guardrails, logging:
ts
import { wrapLanguageModel } from "ai";
const wrappedModel = wrapLanguageModel({
model: "openai/gpt-5.4",
middleware: {
transformParams: async ({ params }) => {
// Inject RAG context, modify system prompt, etc.
return { ...params, system: params.system + "\n\nContext: ..." };
},
wrapGenerate: async ({ doGenerate }) => {
const result = await doGenerate();
// Post-process, log, validate guardrails
return result;
},
},
});Provider Routing via AI Gateway
ts
import { generateText } from "ai";
import { gateway } from "ai";
const result = await generateText({
model: gateway("anthropic/claude-sonnet-4.6"),
prompt: "Hello!",
providerOptions: {
gateway: {
order: ["bedrock", "anthropic"], // Try Bedrock first
models: ["openai/gpt-5.4"], // Fallback model
only: ["anthropic", "bedrock"], // Restrict providers
user: "user-123", // Usage tracking
tags: ["feature:chat", "env:production"], // Cost attribution
},
},
});DevTools
bash
npx @ai-sdk/devtools
# Opens http://localhost:4983 — inspect LLM calls, agents, token usage, timingKey Patterns
- Default to AI Gateway with OIDC — pass strings (e.g.,
"provider/model") to route through the gateway automatically.model: "openai/gpt-5.4"provisions OIDC tokens. No manual API keys needed. Thevercel env pullwrapper is optional (only needed forgateway()).providerOptions.gateway - Set up a Vercel project for AI — → enable AI Gateway at
vercel link→ AI Gateway →https://vercel.com/{team}/{project}/settingsto get OIDC credentials. Never manually createvercel env pullwith provider-specific API keys..env.local - Always use AI Elements for any AI text in a browser — installs production-ready Message, Conversation, and Tool components. Use
npx ai-elementsfor chat and<Message>for any other AI-generated text (streaming panels, summaries, reports). AI models always produce markdown — there is no scenario where raw<MessageResponse>rendering is correct. ⤳ skill: ai-elements{text} - Always stream for user-facing AI — use +
streamText, notuseChatgenerateText - UIMessage chat UIs — defaults to
useChat(). On the server:DefaultChatTransport({ api: '/api/chat' })+convertToModelMessages(). For no-API-route setups:toUIMessageStreamResponse()+ Agent.DirectChatTransport - Text-only clients (non-browser) — is only for CLI tools, server pipes, and programmatic consumers. If the text is displayed in a browser, use
toTextStreamResponse()+ AI ElementstoUIMessageStreamResponse() - Use structured output for extracting data — with
generateTextand Zod schemasOutput.object() - Use for multi-step reasoning — not manual loops. Default
ToolLoopAgentisstopWhen. UsestepCountIs(20)for agent API routes.createAgentUIStreamResponse - Use DurableAgent (from Workflow DevKit) for production agents that must survive crashes
- Use to generate static tool definitions from MCP servers for security
mcp-to-ai-sdk - Use for human-in-the-loop — set on any tool to pause execution until user approves; supports conditional approval via async function
needsApproval - Use per tool — opt-in strict mode ensures providers only generate schema-valid tool calls; set on individual tools, not globally
strict: true
Common Pitfall: Structured Output Property Name
In v6, with returns the parsed result on the property (NOT ):
generateTextOutput.object()outputobjectts
// CORRECT — v6
const { output } = await generateText({
model: 'openai/gpt-5.4',
output: Output.object({ schema: mySchema }),
prompt: '...',
})
console.log(output) // ✅ parsed object
// WRONG — v5 habit
const { object } = await generateText({ ... }) // ❌ undefined — `object` doesn't exist in v6This is one of the most common v5→v6 migration mistakes. The config key is and the result key is also .
outputoutputMigration from AI SDK 5
Run (or ) to auto-migrate. Preview with . Key changes:
npx @ai-sdk/codemod upgradenpx @ai-sdk/codemod v6npx @ai-sdk/codemod --dry upgrade- /
generateObject→streamObject/generateTextwithstreamTextOutput.object() - →
parametersinputSchema - →
resultoutput - →
maxSteps(importstopWhen: stepCountIs(N)fromstepCountIs)ai - →
CoreMessage(useModelMessage— now async)convertToModelMessages() - →
ToolCallOptionsToolExecutionOptions - →
Experimental_Agent(concrete class;ToolLoopAgentis just an interface)Agent - →
system(oninstructions)ToolLoopAgent - →
agent.generateText()agent.generate() - →
agent.streamText()agent.stream() - →
experimental_createMCPClient(stable)createMCPClient - New: for agent API routes
createAgentUIStreamResponse({ agent, uiMessages }) - New: +
callOptionsSchemafor per-call agent configurationprepareCall - →
useChat({ api })useChat({ transport: new DefaultChatTransport({ api }) }) useChat/bodyoptions removed → configure with transportonResponse- /
handleSubmit→input/ manage own statesendMessage({ text }) - →
toDataStreamResponse()(for chat UIs)toUIMessageStreamResponse() - : use
createUIMessageStream(notstream.writer.write(...))stream.write(...) - text-only clients / text stream protocol →
toTextStreamResponse() - →
message.content(tool parts usemessage.parts, nottool-<toolName>)tool-invocation - UIMessage / ModelMessage types introduced
- is not strongly typed; cast via
DynamicToolCall.argsfirstunknown - →
TypedToolResult.resultTypedToolResult.output - is the umbrella package
ai@^6.0.0 - must be installed separately at
@ai-sdk/react^3.0.x - (if installed directly) is
@ai-sdk/gateway, not^3.x^1.x - New: on tools (boolean or async function) for human-in-the-loop approval
needsApproval - New: per-tool opt-in for strict schema validation
strict: true - New: — connect
DirectChatTransportto an Agent in-process, no API route neededuseChat - New: on
addToolApprovalResponsefor client-side approval UIuseChat - Default changed from
stopWhentostepCountIs(1)forstepCountIs(20)ToolLoopAgent - New: type renamed to
ToolCallOptionsToolExecutionOptions - New: now receives
Tool.toModelOutputobject, not bare({ output })output - New: →
isToolUIPart;isStaticToolUIPart→isToolOrDynamicToolUIPartisToolUIPart - New: →
getToolName;getStaticToolName→getToolOrDynamicToolNamegetToolName - New: defaults to Responses API; use
@ai-sdk/azurefor Chat Completionsazure.chat() - New:
@ai-sdk/anthropicfor native structured outputs (Claude Sonnet 4.5+)structuredOutputMode - New: rewritten —
@ai-sdk/langchain,toBaseMessages(),toUIMessageStream()LangSmithDeploymentTransport - New: Provider-specific tools — Anthropic (memory, code execution), OpenAI (shell, patch), Google (maps, RAG), xAI (search, code)
- finish reason removed → now returned as
unknownother - Warning types consolidated into single type exported from
Warningai