ai-sdk

作者: openai

Vercel AI SDK 專家指導。用於建構 AI 驅動功能時使用——聊天介面、文字生成、結構化輸出、工具呼叫、代理、MCP……

npx skills add https://github.com/openai/plugins --skill ai-sdk

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: generateObject() removal, streamObject() removal, result.files for image generation, Output.object() for structured streaming, ToolLoopAgent class (not Agent), useChat transport 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.

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)

  • ai@^6.0.0 is the umbrella package for AI SDK v6 (latest: 6.0.83).
  • @ai-sdk/react is ^3.0.x in v6 projects (NOT ^6.0.0).
  • @ai-sdk/gateway is ^3.x in v6 projects (NOT ^1.x).
  • In createUIMessageStream, write with stream.writer.write(...) (NOT stream.write(...)).
  • useChat no longer supports body or onResponse; configure behavior through transport.
  • UI tool parts are typed as tool-<toolName> (for example tool-weather), not tool-invocation.
  • DynamicToolCall does not provide typed .args; cast via unknown first.
  • TypedToolResult exposes .output (NOT .result).
  • The agent class is ToolLoopAgent (NOT AgentAgent is just an interface).
  • Constructor uses instructions (NOT system).
  • Agent methods are agent.generate() and agent.stream() (NOT agent.generateText() or agent.streamText()).
  • AI Gateway does not support embeddings; use @ai-sdk/openai directly for openai.embedding(...).
  • useChat() with no transport defaults to DefaultChatTransport({ api: '/api/chat' }) — explicit transport only needed for custom endpoints or DirectChatTransport.
  • Default stopWhen for ToolLoopAgent is stepCountIs(20), not stepCountIs(1) — override if you need fewer steps.
  • strict: true on tools is opt-in per tool, not global — only set on tools with provider-compatible schemas.
  • For agent API routes, use createAgentUIStreamResponse({ agent, uiMessages }) instead of manual streamText + toUIMessageStreamResponse().
  • @ai-sdk/azure now uses the Responses API by default — use azure.chat() for the previous Chat Completions API behavior.
  • @ai-sdk/azure uses azure (not openai) as the key for providerMetadata and providerOptions.
  • @ai-sdk/google-vertex uses vertex (not google) as the key for providerMetadata and providerOptions.
  • @ai-sdk/anthropic supports native structured outputs via structuredOutputMode option (Anthropic Sonnet 4.5+).

Installation

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)

@ai-sdk/react is a separate package — it is NOT included in the ai package. For v6 projects, install @ai-sdk/react@^3.0.x alongside ai@^6.0.0.

If you install @ai-sdk/gateway directly, use @ai-sdk/gateway@^3.x (NOT ^1.x).

Only install a direct provider SDK (e.g., @ai-sdk/anthropic) if you need provider-specific features not exposed through the gateway.

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:

NeedHow
Text generation / chatgenerateText() or streamText() with model: "openai/gpt-5.4"
Image generationgenerateText() with model: "google/gemini-3.1-flash-image-preview" — images in result.files. Always use this model, never older gemini-2.x models
Structured JSON outputgenerateText() with output: Output.object({ schema })
Tool calling / agentsgenerateText() with tools: { ... } or ToolLoopAgent
Embeddingsembed() / embedMany() with @ai-sdk/openai

If the product needs generated images (portraits, posters, cover art, illustrations, comics, diagrams), use generateText with an image model — do NOT use placeholder images or skip image generation.

Setup for AI Projects

For the smoothest experience, link to a Vercel project so AI Gateway credentials are auto-provisioned via OIDC:

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 components

This gives you AI Gateway access with OIDC authentication, cost tracking, failover, and observability — no manual API keys needed.

OIDC is the default auth: vercel env pull provisions a VERCEL_OIDC_TOKEN (short-lived JWT, ~24h). The @ai-sdk/gateway reads it automatically via @vercel/oidc. On Vercel deployments, tokens auto-refresh. For local dev, re-run vercel env pull when the token expires. No AI_GATEWAY_API_KEY or provider-specific keys needed.

Global Provider System (AI Gateway — Default)

In AI SDK 6, pass a "provider/model" string to the model parameter — it automatically routes through the Vercel AI Gateway:

import { generateText } from "ai";

const { text } = await generateText({
  model: "openai/gpt-5.4", // plain string — routes through AI Gateway automatically
  prompt: "Hello!",
});

No gateway() wrapper needed — plain "provider/model" strings are the simplest approach and are what the official Vercel docs recommend. The gateway() function is an optional explicit wrapper (useful when you need providerOptions.gateway for routing, failover, or tags):

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 provider/model format. Version numbers use dots, not hyphens: anthropic/claude-sonnet-4.6 (not claude-sonnet-4-6). Default to openai/gpt-5.4 or anthropic/claude-sonnet-4.6. Never use outdated models like gpt-4o.

AI Gateway does not support embeddings. Use a direct provider SDK such as @ai-sdk/openai for embeddings.

Direct provider SDKs (@ai-sdk/openai, @ai-sdk/anthropic, etc.) are only needed for provider-specific features not exposed through the gateway (e.g., Anthropic computer use, OpenAI fine-tuned model endpoints).

Core Functions

Text Generation

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

generateObject was removed in AI SDK v6. Use generateText with output: Output.object() instead. Do NOT import generateObject — it does not exist.

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 inputSchema (not parameters) and output/outputSchema (not result), aligned with the MCP specification. Per-tool strict mode ensures providers only generate valid tool calls matching your schema.

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):

import { dynamicTool } from "ai";

const tools = {
  unknownTool: dynamicTool({
    description: "A tool discovered at runtime",
    execute: async (input) => {
      // Handle dynamically
      return { result: "done" };
    },
  }),
};

Agents

The ToolLoopAgent class wraps generateText/streamText with an agentic tool-calling loop. Default stopWhen is stepCountIs(20) (up to 20 tool-calling steps). Agent is an interface — ToolLoopAgent is the concrete implementation.

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:

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/mcp.

Tool Approval (Human-in-the-Loop)

Set needsApproval on any tool to require user confirmation before execution. The tool pauses in approval-requested state until the client responds.

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 useChat:

"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: input-streaminginput-availableapproval-requested (if needsApproval) → output-available | output-error

Embeddings & Reranking

Use a direct provider SDK for embeddings. AI Gateway does not support embedding models.

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 google/gemini-3.1-flash-image-preview model — it is significantly better than older models like gemini-2.0-flash-exp-image-generation or gemini-2.0-flash-001.

Always use google/gemini-3.1-flash-image-preview for image generation. Do NOT use older models (gemini-2.0-*, gemini-2.5-*) — they produce much worse results and some do not support image output at all.

Multimodal LLMs (recommended — use generateText/streamText)

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: google/gemini-3.1-flash-image-preview — fast, high-quality. This is the ONLY recommended model for image generation.

Image-only models (use experimental_generateImage)

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-001, bfl/flux-2-pro, bfl/flux-kontext-max, xai/grok-imagine-image-pro.

Saving generated images

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 **bold**, ## headings, `code`, and ---. There is no "plain text" mode. Every AI-generated string displayed in a browser MUST be rendered through AI Elements.

  • Chat messages: Use AI Elements <Message message={message} /> — handles text, tool calls, code blocks, reasoning, streaming.
  • Any other AI text (streaming panels, workflow events, reports, briefings, narratives, summaries, perspectives): Use <MessageResponse>{text}</MessageResponse> from @/components/ai-elements/message.
  • <MessageResponse> wraps Streamdown with code highlighting, math, mermaid, and CJK plugins — works for any markdown string, including streamed text.
  • Never render AI output as raw {text}, <p>{content}</p>, or <div>{stream}</div> — this always produces ugly unformatted output with visible markdown syntax.
  • 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 uses a transport-based architecture. Three built-in transports:

TransportUse Case
DefaultChatTransportHTTP POST to API routes (default — sends to /api/chat)
DirectChatTransportIn-process agent communication without HTTP (SSR, testing)
TextStreamChatTransportPlain text stream protocol

Default behavior: useChat() with no transport config defaults to DefaultChatTransport({ api: '/api/chat' }).

With AI Elements (Recommended)

"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)

"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 / handleInputChange → manage your own useState
  • body / onResponse options were removed from useChat; use transport to configure requests/responses
  • isLoadingstatus === 'streaming' || status === 'submitted'
  • message.content → iterate message.parts (UIMessage format)

Choose the correct streaming response helper

  • toUIMessageStreamResponse() is for useChat + DefaultChatTransport UIMessage-based chat UIs. Use it when you need tool calls, metadata, reasoning, and other rich message parts.
  • toTextStreamResponse() 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 toUIMessageStreamResponse() + AI Elements instead.
  • Warning: Do not return toUIMessageStreamResponse() to a plain fetch() client unless that client intentionally parses the AI SDK UI message stream protocol.
  • Warning: Do not use toTextStreamResponse() + manual fetch() stream reading as a way to skip AI Elements. If the output goes to a browser, use useChat + <MessageResponse> or <Message>.

Server-side for useChat (API Route)

// 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 ToolLoopAgent and use createAgentUIStreamResponse for the API route:

// 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),
});
// 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 DirectChatTransport on the client to skip the API route entirely.

Server-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 toUIMessageStreamResponse() + AI Elements instead — even for "simple" streaming text panels.

// 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:

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

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

npx @ai-sdk/devtools
# Opens http://localhost:4983 — inspect LLM calls, agents, token usage, timing

Key Patterns

  1. Default to AI Gateway with OIDC — pass "provider/model" strings (e.g., model: "openai/gpt-5.4") to route through the gateway automatically. vercel env pull provisions OIDC tokens. No manual API keys needed. The gateway() wrapper is optional (only needed for providerOptions.gateway).
  2. Set up a Vercel project for AIvercel link → enable AI Gateway at https://vercel.com/{team}/{project}/settingsAI Gatewayvercel env pull to get OIDC credentials. Never manually create .env.local with provider-specific API keys.
  3. Always use AI Elements for any AI text in a browsernpx ai-elements installs production-ready Message, Conversation, and Tool components. Use <Message> for chat and <MessageResponse> for any other AI-generated text (streaming panels, summaries, reports). AI models always produce markdown — there is no scenario where raw {text} rendering is correct. ⤳ skill: ai-elements
  4. Always stream for user-facing AI — use streamText + useChat, not generateText
  5. UIMessage chat UIsuseChat() defaults to DefaultChatTransport({ api: '/api/chat' }). On the server: convertToModelMessages() + toUIMessageStreamResponse(). For no-API-route setups: DirectChatTransport + Agent.
  6. Text-only clients (non-browser)toTextStreamResponse() is only for CLI tools, server pipes, and programmatic consumers. If the text is displayed in a browser, use toUIMessageStreamResponse() + AI Elements
  7. Use structured output for extracting data — generateText with Output.object() and Zod schemas
  8. Use ToolLoopAgent for multi-step reasoning — not manual loops. Default stopWhen is stepCountIs(20). Use createAgentUIStreamResponse for agent API routes.
  9. Use DurableAgent (from Workflow DevKit) for production agents that must survive crashes
  10. Use mcp-to-ai-sdk to generate static tool definitions from MCP servers for security
  11. Use needsApproval for human-in-the-loop — set on any tool to pause execution until user approves; supports conditional approval via async function
  12. Use strict: true per tool — opt-in strict mode ensures providers only generate schema-valid tool calls; set on individual tools, not globally

Common Pitfall: Structured Output Property Name

In v6, generateText with Output.object() returns the parsed result on the output property (NOT object):

// 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 v6

This is one of the most common v5→v6 migration mistakes. The config key is output and the result key is also output.

Migration from AI SDK 5

Run npx @ai-sdk/codemod upgrade (or npx @ai-sdk/codemod v6) to auto-migrate. Preview with npx @ai-sdk/codemod --dry upgrade. Key changes:

  • generateObject / streamObjectgenerateText / streamText with Output.object()
  • parametersinputSchema
  • resultoutput
  • maxStepsstopWhen: stepCountIs(N) (import stepCountIs from ai)
  • CoreMessageModelMessage (use convertToModelMessages() — now async)
  • ToolCallOptionsToolExecutionOptions
  • Experimental_AgentToolLoopAgent (concrete class; Agent is just an interface)
  • systeminstructions (on ToolLoopAgent)
  • agent.generateText()agent.generate()
  • agent.streamText()agent.stream()
  • experimental_createMCPClientcreateMCPClient (stable)
  • New: createAgentUIStreamResponse({ agent, uiMessages }) for agent API routes
  • New: callOptionsSchema + prepareCall for per-call agent configuration
  • useChat({ api })useChat({ transport: new DefaultChatTransport({ api }) })
  • useChat body / onResponse options removed → configure with transport
  • handleSubmit / inputsendMessage({ text }) / manage own state
  • toDataStreamResponse()toUIMessageStreamResponse() (for chat UIs)
  • createUIMessageStream: use stream.writer.write(...) (not stream.write(...))
  • text-only clients / text stream protocol → toTextStreamResponse()
  • message.contentmessage.parts (tool parts use tool-<toolName>, not tool-invocation)
  • UIMessage / ModelMessage types introduced
  • DynamicToolCall.args is not strongly typed; cast via unknown first
  • TypedToolResult.resultTypedToolResult.output
  • ai@^6.0.0 is the umbrella package
  • @ai-sdk/react must be installed separately at ^3.0.x
  • @ai-sdk/gateway (if installed directly) is ^3.x, not ^1.x
  • New: needsApproval on tools (boolean or async function) for human-in-the-loop approval
  • New: strict: true per-tool opt-in for strict schema validation
  • New: DirectChatTransport — connect useChat to an Agent in-process, no API route needed
  • New: addToolApprovalResponse on useChat for client-side approval UI
  • Default stopWhen changed from stepCountIs(1) to stepCountIs(20) for ToolLoopAgent
  • New: ToolCallOptions type renamed to ToolExecutionOptions
  • New: Tool.toModelOutput now receives ({ output }) object, not bare output
  • New: isToolUIPartisStaticToolUIPart; isToolOrDynamicToolUIPartisToolUIPart
  • New: getToolNamegetStaticToolName; getToolOrDynamicToolNamegetToolName
  • New: @ai-sdk/azure defaults to Responses API; use azure.chat() for Chat Completions
  • New: @ai-sdk/anthropic structuredOutputMode for native structured outputs (Anthropic Sonnet 4.5+)
  • New: @ai-sdk/langchain rewritten — toBaseMessages(), toUIMessageStream(), LangSmithDeploymentTransport
  • New: Provider-specific tools — Anthropic (memory, code execution), OpenAI (shell, patch), Google (maps, RAG), xAI (search, code)
  • unknown finish reason removed → now returned as other
  • Warning types consolidated into single Warning type exported from ai

Official Documentation

來自 openai 的更多技能

user-context
openai
載入或管理資料分析插件的持久性來源路由偏好設定、入門邏輯、設定進度以及語義層註冊表。
official
notion-research-documentation
openai
研究Notion內容,並將其整合為結構化的簡報、報告或附有引用的比較分析。透過精準查詢搜尋並擷取Notion頁面,然後按主題組織發現,並附上內文來源引用及參考文獻章節。根據範圍與使用者目標,從四種輸出格式(快速簡報、研究摘要、比較分析、綜合報告)中選擇。使用內建範本建立與更新Notion頁面;直接連結來源,並在新資訊到來時追蹤變更。
official
rcsb-pdb-skill
openai
提交精簡的RCSB PDB請求以獲取核心元數據、Search API查詢及FASTA下載。當用戶需要簡潔的RCSB摘要時使用;保存原始JSON或…
official
pdf
openai
PDF 讀取、建立與驗證,支援視覺化渲染與程式化生成。使用 Poppler(pdftoppm)將 PDF 頁面渲染為 PNG,以便在交付前檢查版面、間距與排版。透過 reportlab 程式化生成 PDF,確保格式可靠;使用 pdfplumber 或 pypdf 提取文字與元資料。執行品質標準:無文字裁切、元素重疊、表格破損或渲染瑕疵;僅使用 ASCII 連字號,引用格式需具可讀性。使用...
official
test-coverage-improver
openai
Improve test coverage in the OpenAI Agents JS monorepo: run `pnpm test:coverage`, inspect coverage artifacts, identify low-coverage files and branches, propose…
official
playwright
openai
終端驅動的瀏覽器自動化,具備元素快照與互動式UI工作流程。透過playwright-cli包裝腳本運作(需npx),支援無頭模式與有頭模式以進行視覺化除錯。核心流程:開啟頁面、擷取快照以取得穩定元素參照、使用參照進行互動、在導航或DOM變更後重新擷取快照。包含表單填寫、點擊、輸入、多分頁管理、螢幕截圖/PDF擷取,以及流程除錯的軌跡記錄。元素參照(例如e3、e15)...
official
ukb-topmed-phewas-skill
openai
接受rsID、GRCh37或GRCh38輸入,解析為所需的GRCh38查詢,以獲取單一變異的簡潔UKB-TOPMed PheWAS摘要。當需要…時使用。
official
code-review-context
openai
模型可見上下文
official