Skip to content
Dashboard
pnpm add ai@latest

Install AI SDK 7

Link to headingDevelop agents

Link to headingReasoning control

agent.ts
import { generateText } from 'ai';
const result = await generateText({
model,
prompt,
reasoning: 'high',
});

Setting reasoning effort with a single option

Link to headingTool context

agent.ts
const agent = new ToolLoopAgent({
model,
tools: {
weather: tool({
description,
inputSchema,
contextSchema: z.object({
apiKey: z.string(),
}),
execute: async (input, { context: { apiKey } }) => {
// ...
},
}),
},
toolsContext: {
weather: { apiKey: process.env.WEATHER_API_KEY! },
},
});

Scoping an API key to the tool that needs it

Link to headingRuntime context

agent.ts
const agent = new ToolLoopAgent({
// setup runtime context
runtimeContext: {
var1: "something",
},
prepareStep: async ({ runtimeContext, steps }) => {
// use runtime context
// return updated runtime context
},
});

Accessing and updating typed variables across steps

Link to headingProvider file uploads

upload.ts
const { providerReference } = await uploadFile({
api: openai.files(),
data: readFileSync('./photo.png'),
filename: 'photo.png',
});
const result = await streamText({
model: openai.responses('gpt-5.5'),
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe what you see in this image.' },
{ type: 'file', mediaType: 'image', data: providerReference },
],
},
],
});

Upload a file once, pass a reference into subsequent model calls

Link to headingProvider skill uploads

upload.ts
const { providerReference } = await uploadSkill({
api: anthropic.skills(),
files: [
{
path: 'my-skill/SKILL.md',
content: readFileSync('./SKILL.md'),
},
],
displayTitle: 'My Skill',
});
const result = await streamText({
model: anthropic('claude-sonnet-4-6'),
tools: {
code_execution: anthropic.tools.codeExecution_20260120(),
},
prompt: 'Use the my-skill skill to complete the task.',
providerOptions: {
anthropic: {
container: {
skills: [{ type: 'custom', providerReference }],
},
} satisfies AnthropicLanguageModelOptions,
},
});

Upload a skill once, reference it across inference calls

Link to headingMCP Apps

An MCP App rendering a dashboard UI inside a sandboxed iframe alongside agent outputAn MCP App rendering a dashboard UI inside a sandboxed iframe alongside agent output
An MCP App rendering its UI alongside the agent
components/chat.tsx
import { experimental_MCPAppRenderer as MCPAppRenderer } from '@ai-sdk/react';
import { isToolUIPart } from 'ai';
{
messages.map(message =>
message.parts.map(part =>
isToolUIPart(part) ? (
<MCPAppRenderer
key={part.toolCallId}
part={part}
sandbox={{ url: '/mcp-app-sandbox', className: 'h-96 w-full' }}
loadResource={app => fetch(`/api/mcp-apps?uri=${app.resourceUri}`)}
handlers={{ allowedTools: ['refreshDashboard'] }}
/>
) : null,
),
);
}

Rendering MCP app UIs alongside model output

Link to headingTUI

An agent running interactively in the terminal UI, showing reasoning steps and tool calls
An agent running in the terminal UI
dev.ts
import { runAgentTUI } from '@ai-sdk/tui';
await runAgentTUI({ agent });

Running an agent in the terminal

Link to headingRun agents

Link to headingTool approvals

agent.ts
const agent = new ToolLoopAgent({
model,
tools: { weather: weatherTool },
toolApproval: {
weather: 'user-approval',
},
});

Requiring user approval before a tool executes

Link to headingWorkflowAgent (Durability)

Link to headingTimeouts

agent.ts
const result = await generateText({
model,
tools: { weather: weatherTool, slowApi: slowApiTool },
timeout: {
totalMs: 60000, // 60 seconds total
stepMs: 10000, // 10 seconds per step
chunkMs: 2000, // abort if no chunk received for 2 seconds
toolMs: 5000, // default for all tools
tools: {
weatherMs: 3000, // 3 seconds for weather tool
slowApiMs: 10000, // 10 seconds for slow API tool
},
},
prompt: 'What is the weather in San Francisco?',
});

Configuring total, per-step, and per-tool timeout limits

Link to headingSandbox support

Link to headingIntegrate any agent harness

Link to headingHarnessAgent

agent.ts
const agent = new HarnessAgent({
harness: claudeCode,
sandbox: createVercelSandbox({
runtime: 'node24',
ports: [4000],
}),
instructions:
'You are a careful coding assistant. Prefer small changes and explain tradeoffs.',
skills: [
{
name: 'review-github-pr',
description: 'Review a GitHub pull request. Use when asked to review a pull request.',
content:
'Use the `readGitHubPullRequest` tool to fetch the context about the relevant pull request the user has asked you to review. ' +
'If the pull request refers to an issue, fetch the relevant issue context as well using the `readGitHubIssue` tool.',
},
],
tools: { readGitHubIssue, readGitHubPullRequest },
});

Configuring Claude Code as a HarnessAgent with a sandbox and custom skills

Link to headingObserve agents

Link to headingTelemetry

instrumentation.ts
import { registerTelemetry, generateText } from 'ai';
import { OpenTelemetry } from '@ai-sdk/otel';
registerTelemetry(new OpenTelemetry());
const result = await generateText({
model: "google/gemini-3.5-flash",
prompt: 'Write a short story about a cat.',
telemetry: {
functionId: `story-agent`,
},
});

Registering OpenTelemetry once at application startup

An observed trace of an agent in Langfuse with multiple steps and tool calls

Link to headingNode.js tracing channel

instrumentation.ts
import { tracingChannel } from 'node:diagnostics_channel';
import {
AI_SDK_TELEMETRY_TRACING_CHANNEL,
type TelemetryTracingChannelMessage,
} from 'ai';
tracingChannel(AI_SDK_TELEMETRY_TRACING_CHANNEL).subscribe({
start(message) {
const { type, event } = message as TelemetryTracingChannelMessage;
console.log(`AI SDK ${type} started`, event);
},
asyncEnd(message) {
const { type } = message as TelemetryTracingChannelMessage;
console.log(`AI SDK ${type} completed`);
},
});

Subscribing to AI SDK telemetry events via the Node.js tracing channel

Link to headingPerformance statistics

app.ts
import { streamText } from 'ai';
const result = streamText({
model: 'openai/gpt-5',
prompt: 'Write a short product announcement.',
});
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}
const { performance } = await result.finalStep;
console.log({
responseTimeMs: performance.responseTimeMs,
outputTokensPerSecond: performance.outputTokensPerSecond,
timeToFirstOutputMs: performance.timeToFirstOutputMs,
});

Getting per-step latency and throughput from a streamed response

Link to headingLifecycle events

agent.ts
import { generateText } from 'ai';
const result = await generateText({
model: 'openai/gpt-5',
prompt: 'What is the meaning of life',
runtimeContext: {
userId: 'user_123',
feature: 'launch-copy',
},
onStart({ callId, modelId, runtimeContext }) {
console.log('Request started', {
callId,
modelId,
userId: runtimeContext.userId,
});
},
onEnd({ callId, usage, finishReason }) {
console.log('Request finished', {
callId,
finishReason,
totalTokens: usage.totalTokens,
});
},
});

Observing when a request starts and finishes

Link to headingProvider-agnostic realtime support

components/realtime.tsx
const realtime = experimental_useRealtime({
model: gateway.experimental_realtime('openai/gpt-realtime-2'),
api: {
token: '/api/realtime/setup',
},
onToolCall: async ({ toolCall }) => {
// handle client side or sent server requests
},
});

Connecting to a realtime session from the browser

Link to headingVideo generation

app.ts
import { experimental_generateVideo as generateVideo } from 'ai';
const { videos } = await generateVideo({
model: "google/veo-3.1-generate-001",
prompt: 'A cat walking on a treadmill',
aspectRatio: '16:9',
});

Generating a video with a single API call

Link to headingGetting started

pnpm add ai@latest

Install AI SDK 7

Link to headingContributors

Ready to deploy?