
Ai Sdk Core
- 64 installs
- 51 repo stars
- Updated November 25, 2025
- ovachiever/droid-tings
Helps with ai & agent building tasks during AI-assisted development.
About
ai-sdk-core is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- ai-sdk-core
- AI & Agent Building
- AI-coding skill
Ai Sdk Core by the numbers
- 64 all-time installs (skills.sh)
- Ranked #6,008 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 27, 2026 (Skillselion catalog sync)
npx skills add https://github.com/ovachiever/droid-tings --skill ai-sdk-coreAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 64 |
|---|---|
| repo stars | ★ 51 |
| Last updated | November 25, 2025 |
| Repository | ovachiever/droid-tings ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
AI SDK Core
Backend AI with Vercel AI SDK v5 and v6 Beta.
Installation:
npm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google zod
# Beta: npm install ai@beta @ai-sdk/openai@beta---
AI SDK 6 Beta (November 2025)
Status: Beta (stable release planned end of 2025) Latest: ai@6.0.0-beta.107 (Nov 22, 2025)
New Features
1. Agent Abstraction Unified interface for building agents with ToolLoopAgent class:
- Full control over execution flow, tool loops, and state management
- Replaces manual tool calling orchestration
2. Tool Execution Approval (Human-in-the-Loop) Request user confirmation before executing tools:
- Static approval: Always ask for specific tools
- Dynamic approval: Conditional based on tool inputs
- Native human-in-the-loop pattern
3. Reranking Support Improve search relevance by reordering documents:
- Supported providers: Cohere, Amazon Bedrock, Together.ai
- Specialized reranking models for RAG workflows
4. Structured Output (Stable) Combine multi-step tool calling with structured data generation:
- Multiple output strategies: objects, arrays, choices, text formats
- Now stable and production-ready in v6
5. Call Options Dynamic runtime configuration:
- Type-safe parameter passing
- RAG integration, model selection, tool customization
- Provider-specific settings adjustments
6. Image Editing (Coming Soon) Native support for image transformation workflows.
Migration from v5
Unlike v4→v5, v6 has minimal breaking changes:
- Powered by v3 Language Model Specification
- Most users require no code changes
- Agent abstraction is additive (opt-in)
Install Beta:
npm install ai@beta @ai-sdk/openai@beta @ai-sdk/react@betaOfficial Docs: https://ai-sdk.dev/docs/announcing-ai-sdk-6-beta
---
Latest AI Models (2025)
OpenAI
GPT-5 (Aug 7, 2025):
- 45% less hallucination than GPT-4o
- State-of-the-art in math, coding, visual perception, health
- Available in ChatGPT, API, GitHub Models, Microsoft Copilot
GPT-5.1 (Nov 13, 2025):
- Improved speed and efficiency over GPT-5
- Available in API platform
import { openai } from '@ai-sdk/openai';
const gpt5 = openai('gpt-5');
const gpt51 = openai('gpt-5.1');Anthropic
Claude 4 Family (May-Oct 2025):
- Opus 4 (May 22): Best for complex reasoning, $15/$75 per million tokens
- Sonnet 4 (May 22): Balanced performance, $3/$15 per million tokens
- Opus 4.1 (Aug 5): Enhanced agentic tasks, real-world coding
- Sonnet 4.5 (Sept 29): Most capable for coding, agents, computer use
- Haiku 4.5 (Oct 15): Small, fast, low-latency model
import { anthropic } from '@ai-sdk/anthropic';
const sonnet45 = anthropic('claude-sonnet-4-5-20250929'); // Latest
const opus41 = anthropic('claude-opus-4-1-20250805');
const haiku45 = anthropic('claude-haiku-4-5-20251015');Gemini 2.5 Family (Mar-Sept 2025):
- Pro (March 2025): Most intelligent, #1 on LMArena at launch
- Pro Deep Think (May 2025): Enhanced reasoning mode
- Flash (May 2025): Fast, cost-effective
- Flash-Lite (Sept 2025): Updated efficiency
import { google } from '@ai-sdk/google';
const pro = google('gemini-2.5-pro');
const flash = google('gemini-2.5-flash');
const lite = google('gemini-2.5-flash-lite');---
v5 Core Functions (Basics)
generateText() - Text completion with tools streamText() - Real-time streaming generateObject() - Structured output (Zod schemas) streamObject() - Streaming structured data
See official docs for usage: https://ai-sdk.dev/docs/ai-sdk-core
---
Cloudflare Workers Startup Fix
Problem: AI SDK v5 + Zod causes >270ms startup time (exceeds Workers 400ms limit).
Solution:
// ❌ BAD: Top-level imports cause startup overhead
import { createWorkersAI } from 'workers-ai-provider';
const workersai = createWorkersAI({ binding: env.AI });
// ✅ GOOD: Lazy initialization inside handler
app.post('/chat', async (c) => {
const { createWorkersAI } = await import('workers-ai-provider');
const workersai = createWorkersAI({ binding: c.env.AI });
// ...
});Additional:
- Minimize top-level Zod schemas
- Move complex schemas into route handlers
- Monitor startup time with Wrangler
---
v5 Tool Calling Changes
Breaking Changes:
parameters→inputSchema(Zod schema)- Tool properties:
args→input,result→output ToolExecutionErrorremoved (nowtool-errorcontent parts)maxStepsparameter removed → UsestopWhen(stepCountIs(n))
New in v5:
- Dynamic tools (add tools at runtime based on context)
- Agent class (multi-step execution with tools)
---
Critical v4→v5 Migration
AI SDK v5 introduced extensive breaking changes. If migrating from v4, follow this guide.
Breaking Changes Overview
1. Parameter Renames
maxTokens→maxOutputTokensproviderMetadata→providerOptions
2. Tool Definitions
parameters→inputSchema- Tool properties:
args→input,result→output
3. Message Types
CoreMessage→ModelMessageMessage→UIMessageconvertToCoreMessages→convertToModelMessages
4. Tool Error Handling
ToolExecutionErrorclass removed- Now
tool-errorcontent parts - Enables automated retry
5. Multi-Step Execution
maxSteps→stopWhen- Use
stepCountIs()orhasToolCall()
6. Message Structure
- Simple
contentstring →partsarray - Parts: text, file, reasoning, tool-call, tool-result
7. Streaming Architecture
- Single chunk → start/delta/end lifecycle
- Unique IDs for concurrent streams
8. Tool Streaming
- Enabled by default
toolCallStreamingoption removed
9. Package Reorganization
ai/rsc→@ai-sdk/rscai/react→@ai-sdk/reactLangChainAdapter→@ai-sdk/langchain
Migration Examples
Before (v4):
import { generateText } from 'ai';
const result = await generateText({
model: openai.chat('gpt-4'),
maxTokens: 500,
providerMetadata: { openai: { user: 'user-123' } },
tools: {
weather: {
description: 'Get weather',
parameters: z.object({ location: z.string() }),
execute: async (args) => { /* args.location */ },
},
},
maxSteps: 5,
});After (v5):
import { generateText, tool, stopWhen, stepCountIs } from 'ai';
const result = await generateText({
model: openai('gpt-4'),
maxOutputTokens: 500,
providerOptions: { openai: { user: 'user-123' } },
tools: {
weather: tool({
description: 'Get weather',
inputSchema: z.object({ location: z.string() }),
execute: async ({ location }) => { /* input.location */ },
}),
},
stopWhen: stepCountIs(5),
});Migration Checklist
- [ ] Update all
maxTokenstomaxOutputTokens - [ ] Update
providerMetadatatoproviderOptions - [ ] Convert tool
parameterstoinputSchema - [ ] Update tool execute functions:
args→input - [ ] Replace
maxStepswithstopWhen(stepCountIs(n)) - [ ] Update message types:
CoreMessage→ModelMessage - [ ] Remove
ToolExecutionErrorhandling - [ ] Update package imports (
ai/rsc→@ai-sdk/rsc) - [ ] Test streaming behavior (architecture changed)
- [ ] Update TypeScript types
Automated Migration
AI SDK provides a migration tool:
npx ai migrateThis will update most breaking changes automatically. Review changes carefully.
Official Migration Guide: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
---
Top 12 Errors & Solutions
1. AI_APICallError
Cause: API request failed (network, auth, rate limit).
Solution:
import { AI_APICallError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_APICallError) {
console.error('API call failed:', error.message);
console.error('Status code:', error.statusCode);
console.error('Response:', error.responseBody);
// Check common causes
if (error.statusCode === 401) {
// Invalid API key
} else if (error.statusCode === 429) {
// Rate limit - implement backoff
} else if (error.statusCode >= 500) {
// Provider issue - retry
}
}
}Prevention:
- Validate API keys at startup
- Implement retry logic with exponential backoff
- Monitor rate limits
- Handle network errors gracefully
---
2. AI_NoObjectGeneratedError
Cause: Model didn't generate valid object matching schema.
Solution:
import { AI_NoObjectGeneratedError } from 'ai';
try {
const result = await generateObject({
model: openai('gpt-4'),
schema: z.object({ /* complex schema */ }),
prompt: 'Generate data',
});
} catch (error) {
if (error instanceof AI_NoObjectGeneratedError) {
console.error('No valid object generated');
// Solutions:
// 1. Simplify schema
// 2. Add more context to prompt
// 3. Provide examples in prompt
// 4. Try different model (gpt-4 better than gpt-3.5 for complex objects)
}
}Prevention:
- Start with simple schemas, add complexity incrementally
- Include examples in prompt: "Generate a person like: { name: 'Alice', age: 30 }"
- Use GPT-4 for complex structured output
- Test schemas with sample data first
---
3. Worker Startup Limit (270ms+)
Cause: AI SDK v5 + Zod initialization overhead in Cloudflare Workers exceeds startup limits.
Solution:
// BAD: Top-level imports cause startup overhead
import { createWorkersAI } from 'workers-ai-provider';
import { complexSchema } from './schemas';
const workersai = createWorkersAI({ binding: env.AI });
// GOOD: Lazy initialization inside handler
export default {
async fetch(request, env) {
const { createWorkersAI } = await import('workers-ai-provider');
const workersai = createWorkersAI({ binding: env.AI });
// Use workersai here
}
}Prevention:
- Move AI SDK imports inside route handlers
- Minimize top-level Zod schemas
- Monitor Worker startup time (must be <400ms)
- Use Wrangler's startup time reporting
GitHub Issue: Search for "Workers startup limit" in Vercel AI SDK issues
---
4. streamText Fails Silently
Cause: Stream errors can be swallowed by createDataStreamResponse.
Status: ✅ RESOLVED - Fixed in ai@4.1.22 (February 2025)
Solution (Recommended):
// Use the onError callback (added in v4.1.22)
const stream = streamText({
model: openai('gpt-4'),
prompt: 'Hello',
onError({ error }) {
console.error('Stream error:', error);
// Custom error logging and handling
},
});
// Stream safely
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}Alternative (Manual try-catch):
// Fallback if not using onError callback
try {
const stream = streamText({
model: openai('gpt-4'),
prompt: 'Hello',
});
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}
} catch (error) {
console.error('Stream error:', error);
}Prevention:
- Use `onError` callback for proper error capture (recommended)
- Implement server-side error monitoring
- Test stream error handling explicitly
- Always log on server side in production
GitHub Issue: #4726 (RESOLVED)
---
5. AI_LoadAPIKeyError
Cause: Missing or invalid API key.
Solution:
import { AI_LoadAPIKeyError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_LoadAPIKeyError) {
console.error('API key error:', error.message);
// Check:
// 1. .env file exists and loaded
// 2. Correct env variable name (OPENAI_API_KEY)
// 3. Key format is valid (starts with sk-)
}
}Prevention:
- Validate API keys at application startup
- Use environment variable validation (e.g., zod)
- Provide clear error messages in development
- Document required environment variables
---
6. AI_InvalidArgumentError
Cause: Invalid parameters passed to function.
Solution:
import { AI_InvalidArgumentError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
maxOutputTokens: -1, // Invalid!
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_InvalidArgumentError) {
console.error('Invalid argument:', error.message);
// Check parameter types and values
}
}Prevention:
- Use TypeScript for type checking
- Validate inputs before calling AI SDK functions
- Read function signatures carefully
- Check official docs for parameter constraints
---
7. AI_NoContentGeneratedError
Cause: Model generated no content (safety filters, etc.).
Solution:
import { AI_NoContentGeneratedError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Some prompt',
});
} catch (error) {
if (error instanceof AI_NoContentGeneratedError) {
console.error('No content generated');
// Possible causes:
// 1. Safety filters blocked output
// 2. Prompt triggered content policy
// 3. Model configuration issue
// Handle gracefully:
return { text: 'Unable to generate response. Please try different input.' };
}
}Prevention:
- Sanitize user inputs
- Avoid prompts that may trigger safety filters
- Have fallback messaging
- Log occurrences for analysis
---
8. AI_TypeValidationError
Cause: Zod schema validation failed on generated output.
Solution:
import { AI_TypeValidationError } from 'ai';
try {
const result = await generateObject({
model: openai('gpt-4'),
schema: z.object({
age: z.number().min(0).max(120), // Strict validation
}),
prompt: 'Generate person',
});
} catch (error) {
if (error instanceof AI_TypeValidationError) {
console.error('Validation failed:', error.message);
// Solutions:
// 1. Relax schema constraints
// 2. Add more guidance in prompt
// 3. Use .optional() for unreliable fields
}
}Prevention:
- Start with lenient schemas, tighten gradually
- Use
.optional()for fields that may not always be present - Add validation hints in field descriptions
- Test with various prompts
---
9. AI_RetryError
Cause: All retry attempts failed.
Solution:
import { AI_RetryError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Hello',
maxRetries: 3, // Default is 2
});
} catch (error) {
if (error instanceof AI_RetryError) {
console.error('All retries failed');
console.error('Last error:', error.lastError);
// Check root cause:
// - Persistent network issue
// - Provider outage
// - Invalid configuration
}
}Prevention:
- Investigate root cause of failures
- Adjust retry configuration if needed
- Implement circuit breaker pattern for provider outages
- Have fallback providers
---
10. Rate Limiting Errors
Cause: Exceeded provider rate limits (RPM/TPM).
Solution:
// Implement exponential backoff
async function generateWithBackoff(prompt: string, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await generateText({
model: openai('gpt-4'),
prompt,
});
} catch (error) {
if (error instanceof AI_APICallError && error.statusCode === 429) {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
console.log(`Rate limited, waiting ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
throw new Error('Rate limit retries exhausted');
}Prevention:
- Monitor rate limit headers
- Queue requests to stay under limits
- Upgrade provider tier if needed
- Implement request throttling
---
11. TypeScript Performance with Zod
Cause: Complex Zod schemas slow down TypeScript type checking.
Solution:
// Instead of deeply nested schemas at top level:
// const complexSchema = z.object({ /* 100+ fields */ });
// Define inside functions or use type assertions:
function generateData() {
const schema = z.object({ /* complex schema */ });
return generateObject({ model: openai('gpt-4'), schema, prompt: '...' });
}
// Or use z.lazy() for recursive schemas:
type Category = { name: string; subcategories?: Category[] };
const CategorySchema: z.ZodType<Category> = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(CategorySchema).optional(),
})
);Prevention:
- Avoid top-level complex schemas
- Use
z.lazy()for recursive types - Split large schemas into smaller ones
- Use type assertions where appropriate
Official Docs: https://ai-sdk.dev/docs/troubleshooting/common-issues/slow-type-checking
---
12. Invalid JSON Response (Provider-Specific)
Cause: Some models occasionally return invalid JSON.
Solution:
// Use built-in retry and mode selection
const result = await generateObject({
model: openai('gpt-4'),
schema: mySchema,
prompt: 'Generate data',
mode: 'json', // Force JSON mode (supported by GPT-4)
maxRetries: 3, // Retry on invalid JSON
});
// Or catch and retry manually:
try {
const result = await generateObject({
model: openai('gpt-4'),
schema: mySchema,
prompt: 'Generate data',
});
} catch (error) {
// Retry with different model
const result = await generateObject({
model: openai('gpt-4-turbo'),
schema: mySchema,
prompt: 'Generate data',
});
}Prevention:
- Use
mode: 'json'when available - Prefer GPT-4 for structured output
- Implement retry logic
- Validate responses
GitHub Issue: #4302 (Imagen 3.0 Invalid JSON)
---
More Errors: https://ai-sdk.dev/docs/reference/ai-sdk-errors (28 total)
---
When to Use This Skill
Use ai-sdk-core when:
- Building backend AI features (server-side text generation)
- Implementing server-side text generation (Node.js, Workers, Next.js)
- Creating structured AI outputs (JSON, forms, data extraction)
- Building AI agents with tools (multi-step workflows)
- Integrating multiple AI providers (OpenAI, Anthropic, Google, Cloudflare)
- Migrating from AI SDK v4 to v5
- Encountering AI SDK errors (AI_APICallError, AI_NoObjectGeneratedError, etc.)
- Using AI in Cloudflare Workers (with workers-ai-provider)
- Using AI in Next.js Server Components/Actions
- Need consistent API across different LLM providers
Don't use this skill when:
- Building React chat UIs (use ai-sdk-ui skill instead)
- Need frontend hooks like useChat (use ai-sdk-ui skill instead)
- Need advanced topics like embeddings or image generation (check official docs)
- Building native Cloudflare Workers AI apps without multi-provider (use cloudflare-workers-ai skill instead)
- Need Generative UI / RSC (see https://ai-sdk.dev/docs/ai-sdk-rsc)
---
Versions
AI SDK:
- Stable: ai@5.0.98 (Nov 20, 2025)
- Beta: ai@6.0.0-beta.107 (Nov 22, 2025)
- Zod 3.x/4.x both supported (3.23.8 recommended)
Latest Models (2025):
- OpenAI: GPT-5.1, GPT-5, o3
- Anthropic: Claude Sonnet 4.5, Opus 4.1, Haiku 4.5
- Google: Gemini 2.5 Pro/Flash/Lite
Check Latest:
npm view ai version
npm view ai dist-tags # See beta versions---
Official Docs
Core:
- AI SDK 6 Beta: https://ai-sdk.dev/docs/announcing-ai-sdk-6-beta
- AI SDK Core: https://ai-sdk.dev/docs/ai-sdk-core/overview
- v4→v5 Migration: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
- All Errors (28): https://ai-sdk.dev/docs/reference/ai-sdk-errors
- Providers (25+): https://ai-sdk.dev/providers/overview
GitHub:
- Repository: https://github.com/vercel/ai
- Issues: https://github.com/vercel/ai/issues
---
Last Updated: 2025-11-22 Skill Version: 1.2.0 AI SDK: 5.0.98 stable / 6.0.0-beta.107
{
"name": "ai-sdk-core",
"description": "Build backend AI features with Vercel AI SDK v5: text generation, structured output (Zod schemas), tool calling, and agents. Multi-provider support (OpenAI, Anthropic, Google, Cloudflare). Use when: implementing server-side AI, generating text/structured data, building AI agents, streaming responses, or troubleshooting AI_APICallError, AI_NoObjectGeneratedError.",
"version": "1.0.0",
"author": {
"name": "Jeremy Dawes",
"email": "jeremy@jezweb.net"
},
"license": "MIT",
"repository": "https://github.com/jezweb/claude-skills",
"keywords": []
}
AI SDK Core
Backend AI with Vercel AI SDK v5 - text generation, structured output, tools, and agents.
Auto-Trigger Keywords
This skill should be discovered when working with:
Primary Keywords (High Priority)
- ai sdk core, vercel ai sdk, ai sdk v5
- generateText, streamText, generate text ai
- generateObject, streamObject, structured ai output
- ai sdk node, ai sdk server, ai sdk backend
- zod ai schema, zod ai validation
- ai tools calling, ai agent class, agent with tools
- openai sdk, anthropic sdk, google gemini sdk
- multi-provider ai, ai provider switching
Secondary Keywords (Medium Priority)
- ai streaming backend, stream ai responses
- ai server actions, nextjs ai server
- cloudflare workers ai sdk, workers-ai-provider
- ai sdk migration, v4 to v5 migration
- ai chat completion, llm text generation
- ai sdk typescript, typed ai responses
- stopWhen ai sdk, multi-step ai execution
- dynamic tools ai, runtime tools ai
Error Keywords (Discovery on Errors)
- AI_APICallError, ai api call error
- AI_NoObjectGeneratedError, no object generated
- AI_LoadAPIKeyError, ai api key error
- AI_InvalidArgumentError, invalid argument ai
- AI_TypeValidationError, zod validation failed
- AI_RetryError, ai retry failed
- streamText fails silently, stream error swallowed
- worker startup limit ai sdk, 270ms startup
- ai rate limit, rate limiting ai
- maxTokens maxOutputTokens, v5 breaking changes
- providerMetadata providerOptions, tool inputSchema
- ToolExecutionError removed, tool-error parts
Framework Keywords
- nextjs ai sdk, next.js server actions ai
- cloudflare workers ai integration
- node.js ai sdk, nodejs llm
- vercel ai deployment, serverless ai
Provider Keywords
- openai integration, gpt-4 api, chatgpt api
- anthropic claude, claude api integration
- google gemini api, gemini integration
- cloudflare llama, workers ai llm
What This Skill Provides
- 4 Core Functions: generateText, streamText, generateObject, streamObject
- Top 4 Providers: OpenAI, Anthropic, Google, Cloudflare Workers AI
- Tool Calling & Agents: Multi-step execution with tools
- v4→v5 Migration: Complete breaking changes guide
- Top 12 Errors: Common issues with solutions
- 13 Templates: Copy-paste examples
- 5 Reference Docs: Detailed guides
- Production Patterns: Best practices for deployment
Quick Links
- Official Docs: https://ai-sdk.dev/docs
- Migration Guide: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
- Error Reference: https://ai-sdk.dev/docs/reference/ai-sdk-errors
- GitHub: https://github.com/vercel/ai
Installation
npm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google zodUsage
See SKILL.md for comprehensive documentation and examples.
Version
- Skill Version: 1.1.1
- AI SDK Version: 5.0.95+
- Last Updated: 2025-11-19
Recent Updates (v1.1.1 - 2025-11-19)
- Updated Package Versions: AI SDK 5.0.95, @ai-sdk/anthropic 2.0.45, @ai-sdk/openai 2.0.68, @ai-sdk/google 2.0.38
- Updated Template Models: anthropic-setup.ts and openai-setup.ts now use latest model IDs
- Claude: Sonnet 4.5, Opus 4.0, Haiku 4.5 (deprecated Claude 3.x models as commented examples)
- OpenAI: GPT-5.1, GPT-5-Pro, GPT-4.1, o3 reasoning model (previous gen as comments)
- Added Metadata: YAML frontmatter now includes version tracking and last_verified date
- Zod 3.x for Compatibility: Templates use Zod 3.23.8 for maximum compatibility (AI SDK supports both 3.x and 4.x)
Previous Updates (v1.1.0 - 2025-10-29)
- Updated Model Names: Claude 4.x (Sonnet 4.5, Opus 4), GPT-5, Gemini 2.5 models now GA
- Zod 4 Support Documented: AI SDK 5 supports both Zod 3.x and 4.x (4.1.12 latest)
- Issue #4726 Resolved: streamText now has onError callback (fixed in v4.1.22)
- Deprecated Claude 3.x: Anthropic deprecated Claude 3.x models in favor of Claude 4.x family
License
MIT
AI SDK Core - Official Documentation Links
Organized links to official AI SDK and provider documentation.
---
AI SDK Core Documentation
Getting Started
- Introduction: https://ai-sdk.dev/docs/introduction
- AI SDK Core Overview: https://ai-sdk.dev/docs/ai-sdk-core/overview
- Foundations: https://ai-sdk.dev/docs/foundations/overview
Core Functions
- Generating Text: https://ai-sdk.dev/docs/ai-sdk-core/generating-text
- Streaming Text: https://ai-sdk.dev/docs/ai-sdk-core/streaming-text
- Generating Structured Data: https://ai-sdk.dev/docs/ai-sdk-core/generating-structured-data
- Streaming Structured Data: https://ai-sdk.dev/docs/ai-sdk-core/streaming-structured-data
Tool Calling & Agents
- Tools and Tool Calling: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling
- Agents Overview: https://ai-sdk.dev/docs/agents/overview
- Building Agents: https://ai-sdk.dev/docs/agents/building-agents
Advanced Topics (Not Replicated in This Skill)
- Embeddings: https://ai-sdk.dev/docs/ai-sdk-core/embeddings
- Image Generation: https://ai-sdk.dev/docs/ai-sdk-core/generating-images
- Transcription (Audio to Text): https://ai-sdk.dev/docs/ai-sdk-core/generating-transcriptions
- Speech (Text to Audio): https://ai-sdk.dev/docs/ai-sdk-core/generating-speech
- MCP Tools: https://ai-sdk.dev/docs/ai-sdk-core/mcp-tools
- Telemetry: https://ai-sdk.dev/docs/ai-sdk-core/telemetry
- Generative UI (RSC): https://ai-sdk.dev/docs/ai-sdk-rsc
---
Migration & Troubleshooting
- v4 → v5 Migration Guide: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
- All Error Types (28 total): https://ai-sdk.dev/docs/reference/ai-sdk-errors
- Troubleshooting Guide: https://ai-sdk.dev/docs/troubleshooting
- Common Issues: https://ai-sdk.dev/docs/troubleshooting/common-issues
- Slow Type Checking: https://ai-sdk.dev/docs/troubleshooting/common-issues/slow-type-checking
---
Provider Documentation
Provider Overview
- All Providers: https://ai-sdk.dev/providers/overview
- Provider Selection Guide: https://ai-sdk.dev/providers/overview#provider-selection
OpenAI
- OpenAI Provider Docs: https://ai-sdk.dev/providers/ai-sdk-providers/openai
- OpenAI Platform: https://platform.openai.com/
- API Keys: https://platform.openai.com/api-keys
- Rate Limits: https://platform.openai.com/account/rate-limits
- Pricing: https://openai.com/api/pricing/
Anthropic
- Anthropic Provider Docs: https://ai-sdk.dev/providers/ai-sdk-providers/anthropic
- Anthropic Console: https://console.anthropic.com/
- Claude Models: https://docs.anthropic.com/en/docs/models-overview
- Rate Limits: https://docs.anthropic.com/en/api/rate-limits
- Pricing: https://www.anthropic.com/pricing
- Google Provider Docs: https://ai-sdk.dev/providers/ai-sdk-providers/google
- Google AI Studio: https://aistudio.google.com/
- API Keys: https://aistudio.google.com/app/apikey
- Gemini Models: https://ai.google.dev/models/gemini
- Pricing: https://ai.google.dev/pricing
Cloudflare Workers AI
- Workers AI Provider (Community): https://ai-sdk.dev/providers/community-providers/cloudflare-workers-ai
- Cloudflare Workers AI Docs: https://developers.cloudflare.com/workers-ai/
- AI SDK Configuration: https://developers.cloudflare.com/workers-ai/configuration/ai-sdk/
- Available Models: https://developers.cloudflare.com/workers-ai/models/
- GitHub (workers-ai-provider): https://github.com/cloudflare/ai/tree/main/packages/workers-ai-provider
- Pricing: https://developers.cloudflare.com/workers-ai/platform/pricing/
Community Providers
- Community Providers List: https://ai-sdk.dev/providers/community-providers
- Ollama: https://ai-sdk.dev/providers/community-providers/ollama
- FriendliAI: https://ai-sdk.dev/providers/community-providers/friendliai
- LM Studio: https://ai-sdk.dev/providers/community-providers/lmstudio
---
Framework Integration
Next.js
- Next.js App Router Integration: https://ai-sdk.dev/docs/getting-started/nextjs-app-router
- Next.js Pages Router Integration: https://ai-sdk.dev/docs/getting-started/nextjs-pages-router
- Next.js Documentation: https://nextjs.org/docs
Node.js
- Node.js Integration: https://ai-sdk.dev/docs/getting-started/nodejs
Vercel Deployment
- Vercel Functions: https://vercel.com/docs/functions
- Vercel Streaming: https://vercel.com/docs/functions/streaming
- Vercel Environment Variables: https://vercel.com/docs/projects/environment-variables
Cloudflare Workers
- Cloudflare Workers Docs: https://developers.cloudflare.com/workers/
- Wrangler CLI: https://developers.cloudflare.com/workers/wrangler/
- Workers Configuration: https://developers.cloudflare.com/workers/wrangler/configuration/
---
API Reference
- generateText: https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-text
- streamText: https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text
- generateObject: https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-object
- streamObject: https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-object
- Tool: https://ai-sdk.dev/docs/reference/ai-sdk-core/tool
- Agent: https://ai-sdk.dev/docs/reference/ai-sdk-core/agent
---
GitHub & Community
- GitHub Repository: https://github.com/vercel/ai
- GitHub Issues: https://github.com/vercel/ai/issues
- GitHub Discussions: https://github.com/vercel/ai/discussions
- Discord Community: https://discord.gg/vercel
---
Blog Posts & Announcements
- AI SDK 5.0 Release: https://vercel.com/blog/ai-sdk-5
- Vercel AI Blog: https://vercel.com/blog/category/ai
- Engineering Blog (Agents): https://www.anthropic.com/engineering
---
TypeScript & Zod
- Zod Documentation: https://zod.dev/
- TypeScript Handbook: https://www.typescriptlang.org/docs/
---
Complementary Skills
For complete AI SDK coverage, also see:
- ai-sdk-ui skill: Frontend React hooks (useChat, useCompletion, useObject)
- cloudflare-workers-ai skill: Native Cloudflare Workers AI binding (no multi-provider)
---
Quick Navigation
I want to...
Generate text:
- Docs: https://ai-sdk.dev/docs/ai-sdk-core/generating-text
- Template:
templates/generate-text-basic.ts
Stream text:
- Docs: https://ai-sdk.dev/docs/ai-sdk-core/streaming-text
- Template:
templates/stream-text-chat.ts
Generate structured output:
- Docs: https://ai-sdk.dev/docs/ai-sdk-core/generating-structured-data
- Template:
templates/generate-object-zod.ts
Use tools:
- Docs: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling
- Template:
templates/tools-basic.ts
Build an agent:
- Docs: https://ai-sdk.dev/docs/agents/overview
- Template:
templates/agent-with-tools.ts
Migrate from v4:
- Docs: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
- Reference:
references/v5-breaking-changes.md
Fix an error:
- Docs: https://ai-sdk.dev/docs/reference/ai-sdk-errors
- Reference:
references/top-errors.md
Set up a provider:
- Reference:
references/providers-quickstart.md
Deploy to production:
- Reference:
references/production-patterns.md
---
Last Updated: 2025-10-21
AI SDK Core - Production Patterns
Best practices for deploying AI SDK Core in production environments.
---
Performance Optimization
1. Streaming for Long-Form Content
Always use streaming for user-facing long-form content:
// ✅ GOOD: User-facing (better perceived performance)
app.post('/chat', async (req, res) => {
const stream = streamText({
model: openai('gpt-4'),
prompt: req.body.message,
});
return stream.toDataStreamResponse();
});
// ❌ BAD: User waits for entire response
app.post('/chat', async (req, res) => {
const result = await generateText({
model: openai('gpt-4'),
prompt: req.body.message,
});
return res.json({ response: result.text });
});
// ✅ GOOD: Background tasks (no user waiting)
async function processDocument(doc: string) {
const result = await generateText({
model: openai('gpt-4'),
prompt: `Analyze: ${doc}`,
});
await saveToDatabase(result.text);
}2. Set Appropriate maxOutputTokens
// ✅ GOOD: Limit token usage based on use case
const shortSummary = await generateText({
model: openai('gpt-4'),
prompt: 'Summarize in 2 sentences',
maxOutputTokens: 100, // Prevents over-generation
});
const article = await generateText({
model: openai('gpt-4'),
prompt: 'Write article',
maxOutputTokens: 2000, // Appropriate for long-form
});
// ❌ BAD: No limit (can waste tokens/money)
const unlimited = await generateText({
model: openai('gpt-4'),
prompt: 'Write something',
// No maxOutputTokens
});3. Cache Provider Instances
// ✅ GOOD: Reuse provider instances
const gpt4 = openai('gpt-4-turbo');
const claude = anthropic('claude-3-5-sonnet-20241022');
app.post('/chat', async (req, res) => {
const result = await generateText({
model: gpt4, // Reuse
prompt: req.body.message,
});
return res.json({ response: result.text });
});
// ❌ BAD: Create new instance every time
app.post('/chat', async (req, res) => {
const result = await generateText({
model: openai('gpt-4-turbo'), // New instance each call
prompt: req.body.message,
});
});4. Optimize Zod Schemas (Especially in Workers)
// ❌ BAD: Complex schema at top level (slow startup)
const ComplexSchema = z.object({
// 50+ fields with deep nesting
});
// ✅ GOOD: Define schemas inside functions
function generateStructuredData() {
const schema = z.object({
// Schema definition here
});
return generateObject({ model: openai('gpt-4'), schema, prompt: '...' });
}
// ✅ GOOD: Split into smaller reusable schemas
const AddressSchema = z.object({ street: z.string(), city: z.string() });
const PersonSchema = z.object({ name: z.string(), address: AddressSchema });---
Error Handling
1. Wrap All AI Calls in Try-Catch
async function generateSafely(prompt: string) {
try {
const result = await generateText({
model: openai('gpt-4'),
prompt,
});
return { success: true, data: result.text };
} catch (error) {
if (error instanceof AI_APICallError) {
console.error('API call failed:', error.statusCode, error.message);
return { success: false, error: 'AI service temporarily unavailable' };
} else if (error instanceof AI_NoContentGeneratedError) {
console.error('No content generated');
return { success: false, error: 'Unable to generate response' };
} else {
console.error('Unknown error:', error);
return { success: false, error: 'An error occurred' };
}
}
}2. Handle Specific Error Types
import {
AI_APICallError,
AI_NoObjectGeneratedError,
AI_TypeValidationError,
AI_RetryError,
} from 'ai';
async function robustGeneration(prompt: string) {
try {
return await generateText({ model: openai('gpt-4'), prompt });
} catch (error) {
switch (error.constructor) {
case AI_APICallError:
if (error.statusCode === 429) {
// Rate limit - wait and retry
await wait(5000);
return retry();
} else if (error.statusCode >= 500) {
// Provider issue - try fallback
return generateText({ model: anthropic('claude-3-5-sonnet-20241022'), prompt });
}
break;
case AI_RetryError:
// All retries failed - use fallback provider
return generateText({ model: google('gemini-2.5-pro'), prompt });
case AI_NoContentGeneratedError:
// Content filtered - return safe message
return { text: 'Unable to generate response for this input.' };
default:
throw error;
}
}
}3. Implement Retry Logic
async function generateWithRetry(prompt: string, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await generateText({
model: openai('gpt-4'),
prompt,
maxRetries: 2, // Built-in retry
});
} catch (error) {
if (i === maxRetries - 1) throw error; // Last attempt failed
// Exponential backoff
const delay = Math.pow(2, i) * 1000;
console.log(`Retry ${i + 1}/${maxRetries} after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}4. Log Errors Properly
function logAIError(error: any, context: Record<string, any>) {
const errorLog = {
timestamp: new Date().toISOString(),
type: error.constructor.name,
message: error.message,
statusCode: error.statusCode,
responseBody: error.responseBody,
context,
stack: error.stack,
};
// Send to monitoring service (e.g., Sentry, Datadog)
console.error('AI SDK Error:', JSON.stringify(errorLog));
// Track metrics
metrics.increment('ai.error', {
type: error.constructor.name,
statusCode: error.statusCode,
});
}
try {
const result = await generateText({ model: openai('gpt-4'), prompt });
} catch (error) {
logAIError(error, { prompt, model: 'gpt-4' });
throw error;
}---
Cost Optimization
1. Choose Appropriate Models
// Model selection based on task complexity
async function generateWithCostOptimization(prompt: string, complexity: 'simple' | 'medium' | 'complex') {
const models = {
simple: openai('gpt-3.5-turbo'), // $0.50 / 1M tokens
medium: openai('gpt-4-turbo'), // $10 / 1M tokens
complex: openai('gpt-4'), // $30 / 1M tokens
};
return generateText({
model: models[complexity],
prompt,
});
}
// Usage
await generateWithCostOptimization('Translate to Spanish', 'simple');
await generateWithCostOptimization('Analyze sentiment', 'medium');
await generateWithCostOptimization('Complex reasoning task', 'complex');2. Set Token Limits
// Prevent runaway costs
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Write essay',
maxOutputTokens: 500, // Hard limit
});
// Adjust limits per use case
const limits = {
chatMessage: 200,
summary: 300,
article: 2000,
analysis: 1000,
};3. Cache Results
import { LRUCache } from 'lru-cache';
const cache = new LRUCache<string, string>({
max: 1000, // Max 1000 items
ttl: 1000 * 60 * 60, // 1 hour TTL
});
async function generateWithCache(prompt: string) {
const cacheKey = `ai:${hash(prompt)}`;
// Check cache
const cached = cache.get(cacheKey);
if (cached) {
console.log('Cache hit');
return { text: cached, cached: true };
}
// Generate
const result = await generateText({
model: openai('gpt-4'),
prompt,
});
// Store in cache
cache.set(cacheKey, result.text);
return { text: result.text, cached: false };
}4. Monitor Usage
// Track token usage
let totalTokensUsed = 0;
let totalCost = 0;
async function generateWithTracking(prompt: string) {
const result = await generateText({
model: openai('gpt-4'),
prompt,
});
// Track tokens
totalTokensUsed += result.usage.totalTokens;
// Estimate cost (GPT-4: $30/1M tokens)
const cost = (result.usage.totalTokens / 1_000_000) * 30;
totalCost += cost;
console.log(`Tokens: ${result.usage.totalTokens}, Cost: $${cost.toFixed(4)}`);
console.log(`Total tokens: ${totalTokensUsed}, Total cost: $${totalCost.toFixed(2)}`);
return result;
}---
Cloudflare Workers Best Practices
1. Lazy Initialization
// ✅ GOOD: Import inside handler
export default {
async fetch(request, env) {
const { generateText } = await import('ai');
const { createWorkersAI } = await import('workers-ai-provider');
const workersai = createWorkersAI({ binding: env.AI });
const result = await generateText({
model: workersai('@cf/meta/llama-3.1-8b-instruct'),
prompt: 'Hello',
});
return new Response(result.text);
}
};
// ❌ BAD: Top-level imports (startup overhead)
import { generateText } from 'ai';
const workersai = createWorkersAI({ binding: env.AI }); // Runs at startup!2. Monitor Startup Time
# Wrangler reports startup time
npx wrangler deploy
# Output shows:
# Startup Time: 287ms (must be <400ms)3. Handle Streaming Properly
app.post('/chat/stream', async (c) => {
const workersai = createWorkersAI({ binding: c.env.AI });
const stream = streamText({
model: workersai('@cf/meta/llama-3.1-8b-instruct'),
prompt: 'Hello',
});
// Return ReadableStream for Workers
return new Response(stream.toTextStream(), {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
'X-Content-Type-Options': 'nosniff',
},
});
});---
Next.js / Vercel Best Practices
1. Server Actions for Mutations
// app/actions.ts
'use server';
export async function generateContent(input: string) {
const result = await generateText({
model: openai('gpt-4'),
prompt: input,
maxOutputTokens: 500,
});
return result.text;
}
// app/page.tsx (Client Component)
'use client';
import { generateContent } from './actions';
export default function Page() {
const [loading, setLoading] = useState(false);
async function handleSubmit(formData: FormData) {
setLoading(true);
const result = await generateContent(formData.get('input') as string);
setLoading(false);
}
return <form action={handleSubmit}>...</form>;
}2. Server Components for Initial Loads
// app/page.tsx (Server Component)
export default async function Page() {
// Generate on server
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Welcome message',
});
// No loading state needed
return <div>{result.text}</div>;
}3. API Routes for Streaming
// app/api/chat/route.ts
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
export async function POST(request: Request) {
const { messages } = await request.json();
const stream = streamText({
model: openai('gpt-4-turbo'),
messages,
});
return stream.toDataStreamResponse();
}---
Monitoring and Logging
1. Track Key Metrics
// Token usage
metrics.gauge('ai.tokens.total', result.usage.totalTokens);
metrics.gauge('ai.tokens.prompt', result.usage.promptTokens);
metrics.gauge('ai.tokens.completion', result.usage.completionTokens);
// Response time
const startTime = Date.now();
const result = await generateText({ model: openai('gpt-4'), prompt });
metrics.timing('ai.response_time', Date.now() - startTime);
// Error rate
metrics.increment('ai.errors', { type: error.constructor.name });2. Structured Logging
import winston from 'winston';
const logger = winston.createLogger({
format: winston.format.json(),
transports: [new winston.transports.Console()],
});
logger.info('AI generation started', {
model: 'gpt-4',
promptLength: prompt.length,
userId: user.id,
});
const result = await generateText({ model: openai('gpt-4'), prompt });
logger.info('AI generation completed', {
model: 'gpt-4',
tokensUsed: result.usage.totalTokens,
responseLength: result.text.length,
duration: Date.now() - startTime,
});---
Rate Limiting
1. Queue Requests
import PQueue from 'p-queue';
// Limit: 50 requests per minute
const queue = new PQueue({
concurrency: 5,
interval: 60000,
intervalCap: 50,
});
async function generateQueued(prompt: string) {
return queue.add(() =>
generateText({ model: openai('gpt-4'), prompt })
);
}2. Monitor Rate Limits
async function generateWithRateCheck(prompt: string) {
const result = await generateText({
model: openai('gpt-4'),
prompt,
});
// Check rate limit headers (provider-specific)
console.log('Remaining requests:', response.headers['x-ratelimit-remaining']);
console.log('Resets at:', response.headers['x-ratelimit-reset']);
return result;
}---
Security
1. Sanitize User Inputs
function sanitizePrompt(userInput: string): string {
// Remove potential prompt injections
return userInput
.replace(/system:/gi, '')
.replace(/ignore previous/gi, '')
.slice(0, 1000); // Limit length
}
const result = await generateText({
model: openai('gpt-4'),
prompt: sanitizePrompt(req.body.message),
});2. Validate API Keys
// Startup validation
function validateEnv() {
const required = ['OPENAI_API_KEY', 'ANTHROPIC_API_KEY'];
for (const key of required) {
if (!process.env[key]) {
throw new Error(`Missing: ${key}`);
}
if (!process.env[key].match(/^sk-/)) {
throw new Error(`Invalid format: ${key}`);
}
}
}
validateEnv();---
Deployment
See Vercel's official deployment documentation: https://vercel.com/docs/functions
For Cloudflare Workers: https://developers.cloudflare.com/workers/
---
Last Updated: 2025-10-21
AI SDK Core - Providers Quick Start
Quick reference for setting up the top 4 AI providers with AI SDK v5.
---
OpenAI
Package: @ai-sdk/openai Version: 2.0.53+ Maturity: Excellent
Setup
npm install @ai-sdk/openai# .env
OPENAI_API_KEY=sk-...Usage
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
});Available Models
| Model | Use Case | Cost | Speed |
|---|---|---|---|
| gpt-5 | Latest (if available) | High | Medium |
| gpt-4-turbo | Complex reasoning | High | Medium |
| gpt-4 | High quality | High | Slow |
| gpt-3.5-turbo | Simple tasks | Low | Fast |
Common Errors
- 401 Unauthorized: Invalid API key
- 429 Rate Limit: Exceeded RPM/TPM limits
- 500 Server Error: OpenAI service issue
Links
- Docs: https://ai-sdk.dev/providers/ai-sdk-providers/openai
- API Keys: https://platform.openai.com/api-keys
- Rate Limits: https://platform.openai.com/account/rate-limits
---
Anthropic
Package: @ai-sdk/anthropic Version: 2.0.0+ Maturity: Excellent
Setup
npm install @ai-sdk/anthropic# .env
ANTHROPIC_API_KEY=sk-ant-...Usage
import { anthropic } from '@ai-sdk/anthropic';
import { generateText } from 'ai';
const result = await generateText({
model: anthropic('claude-3-5-sonnet-20241022'),
prompt: 'Hello',
});Available Models
| Model | Use Case | Context | Speed |
|---|---|---|---|
| claude-3-5-sonnet-20241022 | Best balance | 200K | Medium |
| claude-3-opus-20240229 | Highest intelligence | 200K | Slow |
| claude-3-haiku-20240307 | Fast and cheap | 200K | Fast |
Common Errors
- authentication_error: Invalid API key
- rate_limit_error: Rate limit exceeded
- overloaded_error: Service overloaded, retry
Links
- Docs: https://ai-sdk.dev/providers/ai-sdk-providers/anthropic
- API Keys: https://console.anthropic.com/
- Model Details: https://docs.anthropic.com/en/docs/models-overview
---
Package: @ai-sdk/google Version: 2.0.0+ Maturity: Excellent
Setup
npm install @ai-sdk/google# .env
GOOGLE_GENERATIVE_AI_API_KEY=...Usage
import { google } from '@ai-sdk/google';
import { generateText } from 'ai';
const result = await generateText({
model: google('gemini-2.5-pro'),
prompt: 'Hello',
});Available Models
| Model | Use Case | Context | Free Tier |
|---|---|---|---|
| gemini-2.5-pro | Complex reasoning | 1M | Generous |
| gemini-2.5-flash | Fast & efficient | 1M | Generous |
| gemini-2.5-flash-lite | Ultra-fast | 1M | Generous |
Common Errors
- SAFETY: Content filtered by safety settings
- QUOTA_EXCEEDED: Rate limit exceeded
- INVALID_ARGUMENT: Invalid parameters
Links
- Docs: https://ai-sdk.dev/providers/ai-sdk-providers/google
- API Keys: https://aistudio.google.com/app/apikey
- Model Details: https://ai.google.dev/models/gemini
---
Cloudflare Workers AI
Package: workers-ai-provider Version: 2.0.0+ Type: Community Provider Maturity: Good
Setup
npm install workers-ai-provider// wrangler.jsonc
{
"ai": {
"binding": "AI"
}
}Usage
import { createWorkersAI } from 'workers-ai-provider';
import { generateText } from 'ai';
// In Cloudflare Worker handler
const workersai = createWorkersAI({ binding: env.AI });
const result = await generateText({
model: workersai('@cf/meta/llama-3.1-8b-instruct'),
prompt: 'Hello',
});Available Models
| Model | Use Case | Notes |
|---|---|---|
| @cf/meta/llama-3.1-8b-instruct | General purpose | Recommended |
| @cf/meta/llama-3.1-70b-instruct | Complex tasks | Slower |
| @cf/mistral/mistral-7b-instruct-v0.1 | Alternative | Good quality |
Common Issues
- Startup Limit: Move imports inside handlers
- 270ms+: Lazy-load AI SDK to avoid startup overhead
Important Notes
1. Startup Optimization Required:
// BAD: Top-level import causes startup overhead
const workersai = createWorkersAI({ binding: env.AI });
// GOOD: Lazy initialization
export default {
async fetch(request, env) {
const workersai = createWorkersAI({ binding: env.AI });
// Use here
}
}2. When to Use:
- Multi-provider scenarios (OpenAI + Workers AI)
- Using AI SDK UI hooks
- Need consistent API across providers
3. When to Use Native Binding:
- Cloudflare-only deployment
- Maximum performance
- See:
cloudflare-workers-aiskill
Links
- Docs: https://ai-sdk.dev/providers/community-providers/cloudflare-workers-ai
- Models: https://developers.cloudflare.com/workers-ai/models/
- GitHub: https://github.com/cloudflare/ai/tree/main/packages/workers-ai-provider
---
Provider Comparison
| Feature | OpenAI | Anthropic | Cloudflare | |
|---|---|---|---|---|
| Quality | Excellent | Excellent | Excellent | Good |
| Speed | Medium | Medium | Fast | Fast |
| Cost | Medium | Medium | Low | Lowest |
| Context | 128K | 200K | 1M | 128K |
| Structured Output | ✅ | ✅ | ✅ | ⚠️ |
| Tool Calling | ✅ | ✅ | ✅ | ⚠️ |
| Streaming | ✅ | ✅ | ✅ | ✅ |
| Free Tier | ❌ | ❌ | ✅ | ✅ |
---
Multi-Provider Setup
import { openai } from '@ai-sdk/openai';
import { anthropic } from '@ai-sdk/anthropic';
import { google } from '@ai-sdk/google';
import { generateText } from 'ai';
// Use different providers for different tasks
const complexTask = await generateText({
model: openai('gpt-4'), // Best reasoning
prompt: 'Complex analysis...',
});
const longContext = await generateText({
model: anthropic('claude-3-5-sonnet-20241022'), // Long context
prompt: 'Document: ' + longDocument,
});
const fastTask = await generateText({
model: google('gemini-2.5-flash'), // Fast and cheap
prompt: 'Quick summary...',
});---
Fallback Pattern
async function generateWithFallback(prompt: string) {
try {
return await generateText({ model: openai('gpt-4'), prompt });
} catch (error) {
console.error('OpenAI failed, trying Anthropic...');
try {
return await generateText({ model: anthropic('claude-3-5-sonnet-20241022'), prompt });
} catch (error2) {
console.error('Anthropic failed, trying Google...');
return await generateText({ model: google('gemini-2.5-pro'), prompt });
}
}
}---
All Providers
AI SDK supports 25+ providers. See full list: https://ai-sdk.dev/providers/overview
Other Official Providers:
- xAI (Grok)
- Mistral
- Azure OpenAI
- Amazon Bedrock
- DeepSeek
- Groq
Community Providers:
- Ollama (local models)
- FriendliAI
- Portkey
- LM Studio
- Baseten
---
Last Updated: 2025-10-21
AI SDK Core - Top 12 Errors & Solutions
Comprehensive guide to the most common AI SDK Core errors with actionable solutions.
---
1. AI_APICallError
Type: Network/API Error Frequency: Very Common Severity: High
Cause
API request to provider failed due to:
- Invalid API key
- Network connectivity issues
- Rate limit exceeded
- Provider service outage
Solution
import { AI_APICallError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_APICallError) {
console.error('API call failed:', error.message);
console.error('Status code:', error.statusCode);
console.error('Response:', error.responseBody);
// Handle specific status codes
if (error.statusCode === 401) {
// Invalid API key
console.error('Check OPENAI_API_KEY environment variable');
} else if (error.statusCode === 429) {
// Rate limit - implement exponential backoff
await wait(Math.pow(2, retryCount) * 1000);
// retry...
} else if (error.statusCode >= 500) {
// Provider issue - retry later
console.error('Provider service issue, retry in 1 minute');
}
}
}Prevention
- Validate API keys at application startup
- Implement retry logic with exponential backoff
- Monitor rate limits via response headers
- Handle network errors gracefully
- Set reasonable timeouts
Resources
- Docs: https://ai-sdk.dev/docs/reference/ai-sdk-errors/ai-api-call-error
---
2. AI_NoObjectGeneratedError
Type: Generation Error Frequency: Common Severity: Medium
Cause
Model didn't generate a valid object matching the Zod schema:
- Schema too complex for model
- Prompt doesn't provide enough context
- Model capabilities exceeded
- Safety filters triggered
Solution
import { AI_NoObjectGeneratedError } from 'ai';
try {
const result = await generateObject({
model: openai('gpt-4'),
schema: z.object({
// Complex schema
name: z.string(),
age: z.number(),
nested: z.object({ /* ... */ }),
}),
prompt: 'Generate a person',
});
} catch (error) {
if (error instanceof AI_NoObjectGeneratedError) {
console.error('No valid object generated');
// Solutions:
// 1. Simplify schema
const simpler = z.object({
name: z.string(),
age: z.number(),
});
// 2. Add more context
const betterPrompt = 'Generate a person profile with name (string) and age (number, 18-80)';
// 3. Try different model
const result2 = await generateObject({
model: openai('gpt-4'), // GPT-4 better than 3.5 for complex objects
schema: simpler,
prompt: betterPrompt,
});
}
}Prevention
- Start with simple schemas, add complexity gradually
- Include examples in prompt:
"Generate like: { name: 'Alice', age: 30 }" - Use GPT-4 or Claude for complex structured output
- Test schemas with sample data first
- Add descriptions to schema fields using
.describe()
Resources
- Docs: https://ai-sdk.dev/docs/reference/ai-sdk-errors/ai-no-object-generated-error
---
3. Worker Startup Limit (270ms+)
Type: Cloudflare Workers Issue Frequency: Common (Workers only) Severity: High (blocks deployment)
Cause
AI SDK v5 + Zod initialization overhead exceeds Cloudflare Workers startup limit (must be <400ms):
- Top-level imports of AI SDK packages
- Complex Zod schemas at module level
- Provider initialization at startup
Solution
// ❌ BAD: Top-level imports cause startup overhead
import { createWorkersAI } from 'workers-ai-provider';
import { generateText } from 'ai';
import { complexSchema } from './schemas'; // Heavy Zod schemas
const workersai = createWorkersAI({ binding: env.AI }); // Runs at startup!
// ✅ GOOD: Lazy initialization inside handler
export default {
async fetch(request, env) {
// Import inside handler
const { createWorkersAI } = await import('workers-ai-provider');
const { generateText } = await import('ai');
const workersai = createWorkersAI({ binding: env.AI });
const result = await generateText({
model: workersai('@cf/meta/llama-3.1-8b-instruct'),
prompt: 'Hello',
});
return new Response(result.text);
}
};Alternative Solution (Move Schemas Inside Routes)
// ❌ BAD: Top-level schema
import { z } from 'zod';
const PersonSchema = z.object({ /* complex schema */ });
// ✅ GOOD: Schema inside handler
export default {
async fetch(request, env) {
const { z } = await import('zod');
const PersonSchema = z.object({ /* complex schema */ });
// Use schema here
}
};Prevention
- Never initialize AI SDK at module top-level in Workers
- Move all imports inside route handlers
- Minimize top-level Zod schemas
- Monitor Worker startup time:
wrangler deployshows startup duration - Target < 270ms startup time to be safe (limit is 400ms)
Resources
- Cloudflare Workers AI Docs: https://developers.cloudflare.com/workers-ai/configuration/ai-sdk/
- GitHub: Search "Workers startup limit" in Vercel AI SDK issues
---
4. streamText Fails Silently
Type: Streaming Error Frequency: Occasional Severity: Medium (hard to debug)
Cause
Stream errors are swallowed by createDataStreamResponse() or framework response handling:
- Error occurs during streaming
- Error handler not set up
- Response already committed
- Client disconnects
Solution
// ✅ GOOD: Add explicit error handling
const stream = streamText({
model: openai('gpt-4'),
prompt: 'Hello',
});
try {
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}
} catch (error) {
// Error may not reach here if stream swallows it
console.error('Stream error:', error);
}
// ✅ BETTER: Always log on server side
console.log('Starting stream...');
const stream = streamText({
model: openai('gpt-4'),
prompt: 'Hello',
});
stream.result.then(
(result) => console.log('Stream success:', result.usage),
(error) => console.error('Stream failed:', error) // This will catch errors!
);
return stream.toDataStreamResponse();Prevention
- Always check server logs for stream errors
- Implement server-side error monitoring (e.g., Sentry)
- Test stream error handling explicitly
- Use
try-catcharound stream consumption - Monitor for unexpected stream terminations
Resources
- GitHub Issue: #4726
---
5. AI_LoadAPIKeyError
Type: Configuration Error Frequency: Very Common (setup) Severity: High (blocks usage)
Cause
API key missing or invalid:
.envfile not loaded- Wrong environment variable name
- API key format invalid
- Environment variable not set in deployment
Solution
import { AI_LoadAPIKeyError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_LoadAPIKeyError) {
console.error('API key error:', error.message);
// Debugging steps:
console.log('OPENAI_API_KEY exists:', !!process.env.OPENAI_API_KEY);
console.log('Key starts with sk-:', process.env.OPENAI_API_KEY?.startsWith('sk-'));
// Common issues:
// 1. .env not loaded → use dotenv or similar
// 2. Wrong variable name → check provider docs
// 3. Key format wrong → verify in provider dashboard
}
}Prevention
// Validate at startup
function validateEnv() {
const required = ['OPENAI_API_KEY', 'ANTHROPIC_API_KEY'];
for (const key of required) {
if (!process.env[key]) {
throw new Error(`Missing required environment variable: ${key}`);
}
}
}
validateEnv();Environment Variable Names
| Provider | Variable Name |
|---|---|
| OpenAI | OPENAI_API_KEY |
| Anthropic | ANTHROPIC_API_KEY |
GOOGLE_GENERATIVE_AI_API_KEY |
Resources
- Docs: https://ai-sdk.dev/docs/reference/ai-sdk-errors/ai-load-api-key-error
---
6. AI_InvalidArgumentError
Type: Validation Error Frequency: Common (development) Severity: Low (easy to fix)
Cause
Invalid parameters passed to AI SDK function:
- Negative
maxOutputTokens - Invalid temperature (must be 0-2)
- Wrong parameter types
- Missing required parameters
Solution
import { AI_InvalidArgumentError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
maxOutputTokens: -1, // ❌ Invalid!
temperature: 3.0, // ❌ Must be 0-2
prompt: 'Hello',
});
} catch (error) {
if (error instanceof AI_InvalidArgumentError) {
console.error('Invalid argument:', error.message);
// Fix: Check parameter types and values
}
}Prevention
- Use TypeScript for compile-time type checking
- Validate inputs before calling AI SDK functions
- Read function signatures carefully
- Check official docs for parameter constraints
- Use IDE autocomplete
Resources
- Docs: https://ai-sdk.dev/docs/reference/ai-sdk-errors/ai-invalid-argument-error
---
7. AI_NoContentGeneratedError
Type: Generation Error Frequency: Occasional Severity: Medium
Cause
Model generated no content:
- Safety filters blocked output
- Prompt triggered content policy
- Model configuration issue
- Empty prompt
Solution
import { AI_NoContentGeneratedError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Some potentially problematic prompt',
});
} catch (error) {
if (error instanceof AI_NoContentGeneratedError) {
console.error('No content generated');
// Return user-friendly message
return {
text: 'Unable to generate response. Please try different input.',
error: true,
};
}
}Prevention
- Sanitize user inputs
- Avoid prompts that may trigger safety filters
- Have fallback messaging
- Log occurrences for analysis
- Test with edge cases
Resources
- Docs: https://ai-sdk.dev/docs/reference/ai-sdk-errors/ai-no-content-generated-error
---
8. AI_TypeValidationError
Type: Validation Error Frequency: Common (with generateObject) Severity: Medium
Cause
Zod schema validation failed on generated output:
- Model output doesn't match schema
- Schema too strict
- Model misunderstood schema
- Invalid JSON generated
Solution
import { AI_TypeValidationError } from 'ai';
try {
const result = await generateObject({
model: openai('gpt-4'),
schema: z.object({
age: z.number().min(0).max(120), // Strict validation
email: z.string().email(), // Strict format
}),
prompt: 'Generate person',
});
} catch (error) {
if (error instanceof AI_TypeValidationError) {
console.error('Validation failed:', error.message);
// Solutions:
// 1. Relax schema
const relaxed = z.object({
age: z.number(), // Remove min/max
email: z.string().optional(), // Make optional
});
// 2. Add guidance in prompt
const better = await generateObject({
model: openai('gpt-4'),
schema: relaxed,
prompt: 'Generate person with age 18-80 and valid email',
});
}
}Prevention
- Start with lenient schemas, tighten gradually
- Use
.optional()for unreliable fields - Add validation hints in field descriptions
- Test with various prompts
- Use mode: 'json' when available
Resources
- Docs: https://ai-sdk.dev/docs/reference/ai-sdk-errors/ai-type-validation-error
---
9. AI_RetryError
Type: Network Error Frequency: Occasional Severity: High
Cause
All retry attempts failed:
- Persistent network issue
- Provider outage
- Invalid configuration
- Unreachable API endpoint
Solution
import { AI_RetryError } from 'ai';
try {
const result = await generateText({
model: openai('gpt-4'),
prompt: 'Hello',
maxRetries: 3, // Default is 2
});
} catch (error) {
if (error instanceof AI_RetryError) {
console.error('All retries failed');
console.error('Last error:', error.lastError);
console.error('Retry count:', error.retryCount);
// Implement circuit breaker
if (isProviderDown()) {
switchToFallbackProvider();
}
}
}Prevention
- Investigate root cause of failures
- Adjust retry configuration if needed
- Implement circuit breaker pattern
- Have fallback providers
- Monitor provider status pages
Resources
- Docs: https://ai-sdk.dev/docs/reference/ai-sdk-errors/ai-retry-error
---
10. Rate Limiting Errors
Type: API Limit Error Frequency: Common (production) Severity: High
Cause
Exceeded provider rate limits:
- RPM (Requests Per Minute) exceeded
- TPM (Tokens Per Minute) exceeded
- Concurrent request limit hit
- Free tier limits reached
Solution
// Implement exponential backoff
async function generateWithBackoff(prompt: string, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await generateText({
model: openai('gpt-4'),
prompt,
});
} catch (error: any) {
if (error.statusCode === 429) {
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s, 8s...
console.log(`Rate limited, waiting ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
throw new Error('Rate limit retries exhausted');
}
// Or use queue
import PQueue from 'p-queue';
const queue = new PQueue({ concurrency: 5, interval: 60000, intervalCap: 50 });
async function generateQueued(prompt: string) {
return queue.add(() => generateText({ model: openai('gpt-4'), prompt }));
}Prevention
- Monitor rate limit headers in responses
- Queue requests to stay under limits
- Upgrade provider tier if needed
- Implement request throttling
- Cache results when possible
Resources
- OpenAI Rate Limits: https://platform.openai.com/account/rate-limits
- Anthropic Rate Limits: https://docs.anthropic.com/en/api/rate-limits
---
11. TypeScript Performance with Zod
Type: Development Issue Frequency: Occasional Severity: Low (annoying)
Cause
Complex Zod schemas slow down TypeScript type checking:
- Deeply nested schemas
- Many union types
- Recursive types
- Top-level complex schemas
Solution
// ❌ BAD: Complex schema at top level
const ComplexSchema = z.object({
// 100+ fields with nested objects...
});
// ✅ GOOD: Define inside function
function generateData() {
const schema = z.object({
// Complex schema here
});
return generateObject({ model: openai('gpt-4'), schema, prompt: '...' });
}
// ✅ GOOD: Use z.lazy() for recursive
type Category = { name: string; subcategories?: Category[] };
const CategorySchema: z.ZodType<Category> = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(CategorySchema).optional(),
})
);
// ✅ GOOD: Split large schemas
const AddressSchema = z.object({ /* ... */ });
const PersonSchema = z.object({
address: AddressSchema, // Reuse smaller schema
});Prevention
- Avoid top-level complex schemas
- Use
z.lazy()for recursive types - Split large schemas into smaller ones
- Use type assertions where appropriate
- Enable
skipLibCheckin tsconfig.json if desperate
Resources
- Troubleshooting: https://ai-sdk.dev/docs/troubleshooting/common-issues/slow-type-checking
---
12. Invalid JSON Response (Provider-Specific)
Type: Provider Issue Frequency: Rare Severity: Medium
Cause
Some models occasionally return invalid JSON:
- Model error
- Provider API issue
- Specific model version bug (e.g., Imagen 3.0)
Solution
// Use built-in retry and mode selection
try {
const result = await generateObject({
model: openai('gpt-4'),
schema: mySchema,
prompt: 'Generate data',
mode: 'json', // Force JSON mode (GPT-4 supports this)
maxRetries: 3, // Retry on invalid JSON
});
} catch (error) {
// Fallback to different model
console.error('GPT-4 failed, trying Claude...');
const result2 = await generateObject({
model: anthropic('claude-3-5-sonnet-20241022'),
schema: mySchema,
prompt: 'Generate data',
});
}Prevention
- Use
mode: 'json'when available - Prefer GPT-4/Claude for structured output
- Implement retry logic
- Validate responses
- Have fallback models
Resources
- GitHub Issue: #4302 (Imagen 3.0 Invalid JSON)
---
For More Errors
See complete error reference (28 total error types): https://ai-sdk.dev/docs/reference/ai-sdk-errors
---
Last Updated: 2025-10-21
AI SDK v4 → v5 Migration Guide
Complete guide to breaking changes from AI SDK v4 to v5.
---
Overview
AI SDK v5 introduced extensive breaking changes to improve consistency, type safety, and functionality. This guide covers all critical changes with before/after examples.
Migration Effort: Medium-High (2-8 hours depending on codebase size)
Automated Migration Available:
npx ai migrate---
Core API Changes
1. Parameter Renames
Change: maxTokens → maxOutputTokens, providerMetadata → providerOptions
Before (v4):
const result = await generateText({
model: openai.chat('gpt-4'),
maxTokens: 500,
providerMetadata: {
openai: { user: 'user-123' }
},
prompt: 'Hello',
});After (v5):
const result = await generateText({
model: openai('gpt-4'),
maxOutputTokens: 500,
providerOptions: {
openai: { user: 'user-123' }
},
prompt: 'Hello',
});Why: maxOutputTokens is clearer that it limits generated tokens, not prompt tokens. providerOptions better reflects that it's for provider-specific configuration.
---
2. Tool Definitions
Change: parameters → inputSchema, tool properties renamed
Before (v4):
const tools = {
weather: {
description: 'Get weather',
parameters: z.object({
location: z.string(),
}),
execute: async (args) => {
return { temp: 72, location: args.location };
},
},
};
// In tool call result:
console.log(toolCall.args); // { location: "SF" }
console.log(toolCall.result); // { temp: 72 }After (v5):
import { tool } from 'ai';
const tools = {
weather: tool({
description: 'Get weather',
inputSchema: z.object({
location: z.string(),
}),
execute: async ({ location }) => {
return { temp: 72, location };
},
}),
};
// In tool call result:
console.log(toolCall.input); // { location: "SF" }
console.log(toolCall.output); // { temp: 72 }Why: inputSchema clarifies it's a Zod schema. input/output are clearer than args/result.
---
3. Message Types
Change: CoreMessage → ModelMessage, Message → UIMessage
Before (v4):
import { CoreMessage, convertToCoreMessages } from 'ai';
const messages: CoreMessage[] = [
{ role: 'user', content: 'Hello' },
];
const converted = convertToCoreMessages(uiMessages);After (v5):
import { ModelMessage, convertToModelMessages } from 'ai';
const messages: ModelMessage[] = [
{ role: 'user', content: 'Hello' },
];
const converted = convertToModelMessages(uiMessages);Why: ModelMessage better reflects that these are messages for the model. UIMessage is for UI hooks.
---
4. Tool Error Handling
Change: ToolExecutionError removed, errors now appear as content parts
Before (v4):
import { ToolExecutionError } from 'ai';
const tools = {
risky: {
execute: async (args) => {
throw new ToolExecutionError({
message: 'API failed',
cause: originalError,
});
},
},
};
// Error would stop executionAfter (v5):
const tools = {
risky: tool({
execute: async (input) => {
// Just throw regular errors
throw new Error('API failed');
},
}),
};
// Error appears as tool-error content part
// Model can see the error and retry or handle itWhy: Enables automated retry in multi-step scenarios. Model can see and respond to errors.
---
5. Multi-Step Execution
Change: maxSteps → stopWhen with conditions
Before (v4):
const result = await generateText({
model: openai.chat('gpt-4'),
tools: { /* ... */ },
maxSteps: 5,
experimental_continueSteps: true,
prompt: 'Complex task',
});After (v5):
import { stopWhen, stepCountIs } from 'ai';
const result = await generateText({
model: openai('gpt-4'),
tools: { /* ... */ },
stopWhen: stepCountIs(5),
prompt: 'Complex task',
});
// Or stop on specific tool:
stopWhen: hasToolCall('finalize')
// Or custom condition:
stopWhen: (step) => step.stepCount > 5 || step.hasToolCall('finish')Why: More flexible control over when multi-step execution stops. experimental_continueSteps no longer needed.
---
6. Message Structure
Change: Simple content string → parts array
Before (v4):
const message = {
role: 'user',
content: 'Hello',
};
// Tool calls embedded in message differentlyAfter (v5):
const message = {
role: 'user',
content: [
{ type: 'text', text: 'Hello' },
],
};
// Tool calls as parts:
const messageWithTool = {
role: 'assistant',
content: [
{ type: 'text', text: 'Let me check...' },
{
type: 'tool-call',
toolCallId: '123',
toolName: 'weather',
args: { location: 'SF' },
},
],
};Part Types:
text: Text contentfile: File attachmentsreasoning: Extended thinking (Claude)tool-call: Tool invocationtool-result: Tool resulttool-error: Tool error (new in v5)
Why: Unified structure for all content types. Enables richer message formats.
---
7. Streaming Architecture
Change: Single chunk format → start/delta/end lifecycle
Before (v4):
stream.on('chunk', (chunk) => {
console.log(chunk.text);
});After (v5):
for await (const part of stream.fullStream) {
if (part.type === 'text-delta') {
console.log(part.textDelta);
} else if (part.type === 'finish') {
console.log('Stream finished:', part.finishReason);
}
}
// Or use simplified textStream:
for await (const text of stream.textStream) {
console.log(text);
}Stream Event Types:
text-delta: Text chunktool-call-delta: Tool call chunktool-result: Tool resultfinish: Stream completeerror: Stream error
Why: Better structure for concurrent streaming and metadata.
---
8. Tool Streaming
Change: Enabled by default
Before (v4):
const result = await generateText({
model: openai.chat('gpt-4'),
tools: { /* ... */ },
toolCallStreaming: true, // Opt-in
});After (v5):
const result = await generateText({
model: openai('gpt-4'),
tools: { /* ... */ },
// Tool streaming enabled by default
});Why: Better UX. Tools stream by default for real-time feedback.
---
9. Package Reorganization
Change: Separate packages for RSC and React
Before (v4):
import { streamUI } from 'ai/rsc';
import { useChat } from 'ai/react';
import { LangChainAdapter } from 'ai';After (v5):
import { streamUI } from '@ai-sdk/rsc';
import { useChat } from '@ai-sdk/react';
import { LangChainAdapter } from '@ai-sdk/langchain';Install:
npm install @ai-sdk/rsc @ai-sdk/react @ai-sdk/langchainWhy: Cleaner package structure. Easier to tree-shake unused functionality.
---
UI Hook Changes (See ai-sdk-ui Skill)
Brief summary (detailed in ai-sdk-ui skill):
1. useChat Input Management: No longer managed by hook 2. useChat Actions: append() → sendMessage() 3. useChat Props: initialMessages → messages (controlled) 4. StreamData Removed: Replaced by message streams
See: ai-sdk-ui skill for complete UI migration guide
---
Provider-Specific Changes
OpenAI
Change: Default API changed
Before (v4):
const model = openai.chat('gpt-4'); // Uses Chat Completions APIAfter (v5):
const model = openai('gpt-4'); // Uses Responses API
// strictSchemas: true → strictJsonSchema: trueWhy: Responses API is newer and has better features.
---
Change: Search grounding moved to tool
Before (v4):
const model = google.generativeAI('gemini-pro', {
googleSearchRetrieval: true,
});After (v5):
import { google, googleSearchRetrieval } from '@ai-sdk/google';
const result = await generateText({
model: google('gemini-pro'),
tools: {
search: googleSearchRetrieval(),
},
prompt: 'Search for...',
});Why: More flexible. Search is now a tool like others.
---
Migration Checklist
- [ ] Update package versions (
ai@^5.0.76,@ai-sdk/openai@^2.0.53, etc.) - [ ] Run automated migration:
npx ai migrate - [ ] Review automated changes
- [ ] Update all
maxTokens→maxOutputTokens - [ ] Update
providerMetadata→providerOptions - [ ] Convert tool
parameters→inputSchema - [ ] Update tool properties:
args→input,result→output - [ ] Replace
maxStepswithstopWhen(stepCountIs(n)) - [ ] Update message types:
CoreMessage→ModelMessage - [ ] Remove
ToolExecutionErrorhandling (just throw errors) - [ ] Update package imports (
ai/rsc→@ai-sdk/rsc) - [ ] Test streaming behavior
- [ ] Update TypeScript types
- [ ] Test tool calling
- [ ] Test multi-step execution
- [ ] Check for message structure changes in your code
- [ ] Update any custom error handling
- [ ] Test with real API calls
---
Common Migration Errors
Error: "maxTokens is not a valid parameter"
Solution: Change to maxOutputTokens
Error: "ToolExecutionError is not exported from 'ai'"
Solution: Remove ToolExecutionError, just throw regular errors
Error: "Cannot find module 'ai/rsc'"
Solution: Install and import from @ai-sdk/rsc
npm install @ai-sdk/rsc
import { streamUI } from '@ai-sdk/rsc';Error: "model.chat is not a function"
Solution: Remove .chat() call
// Before: openai.chat('gpt-4')
// After: openai('gpt-4')Error: "maxSteps is not a valid parameter"
Solution: Use stopWhen(stepCountIs(n))
---
Testing After Migration
// Test basic generation
const test1 = await generateText({
model: openai('gpt-4'),
prompt: 'Hello',
});
console.log('✅ Basic generation:', test1.text);
// Test streaming
const test2 = streamText({
model: openai('gpt-4'),
prompt: 'Hello',
});
for await (const chunk of test2.textStream) {
process.stdout.write(chunk);
}
console.log('\n✅ Streaming works');
// Test structured output
const test3 = await generateObject({
model: openai('gpt-4'),
schema: z.object({ name: z.string() }),
prompt: 'Generate a person',
});
console.log('✅ Structured output:', test3.object);
// Test tools
const test4 = await generateText({
model: openai('gpt-4'),
tools: {
test: tool({
description: 'Test tool',
inputSchema: z.object({ value: z.string() }),
execute: async ({ value }) => ({ result: value }),
}),
},
prompt: 'Use the test tool with value "hello"',
});
console.log('✅ Tools work');---
Resources
- Official Migration Guide: https://ai-sdk.dev/docs/migration-guides/migration-guide-5-0
- Automated Migration:
npx ai migrate - GitHub Discussions: https://github.com/vercel/ai/discussions
- v5 Release Blog: https://vercel.com/blog/ai-sdk-5
---
Last Updated: 2025-10-21
#!/bin/bash
# Check installed AI SDK Core package versions against latest
# Usage: ./scripts/check-versions.sh
echo "==================================="
echo " AI SDK Core - Version Checker"
echo "==================================="
echo ""
packages=(
"ai"
"@ai-sdk/openai"
"@ai-sdk/anthropic"
"@ai-sdk/google"
"workers-ai-provider"
"zod"
)
echo "Checking package versions..."
echo ""
for package in "${packages[@]}"; do
echo "📦 $package"
# Get installed version
installed=$(npm list "$package" --depth=0 2>/dev/null | grep "$package" | awk -F@ '{print $NF}')
if [ -z "$installed" ]; then
echo " ❌ Not installed"
else
echo " ✅ Installed: $installed"
fi
# Get latest version
latest=$(npm view "$package" version 2>/dev/null)
if [ -z "$latest" ]; then
echo " ⚠️ Could not fetch latest version"
else
echo " 📌 Latest: $latest"
# Compare versions
if [ "$installed" = "$latest" ]; then
echo " ✨ Up to date!"
elif [ -n "$installed" ]; then
echo " ⬆️ Update available"
fi
fi
echo ""
done
echo "==================================="
echo " Recommended Versions (AI SDK v5)"
echo "==================================="
echo ""
echo "ai: ^5.0.76"
echo "@ai-sdk/openai: ^2.0.53"
echo "@ai-sdk/anthropic: ^2.0.0"
echo "@ai-sdk/google: ^2.0.0"
echo "workers-ai-provider: ^2.0.0"
echo "zod: ^3.23.8"
echo ""
echo "To update all packages:"
echo "npm install ai@latest @ai-sdk/openai@latest @ai-sdk/anthropic@latest @ai-sdk/google@latest workers-ai-provider@latest zod@latest"
echo ""
// Agent class with multiple tools
// AI SDK Core - Agent class for multi-step execution
import { Agent, tool } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
// Create agent with tools
const weatherAgent = new Agent({
model: anthropic('claude-sonnet-4-5'),
system: 'You are a weather assistant. Always provide temperature in the user\'s preferred unit.',
tools: {
getWeather: tool({
description: 'Get current weather for a location',
inputSchema: z.object({
location: z.string(),
}),
execute: async ({ location }) => {
console.log(`[Tool] Getting weather for ${location}...`);
// Simulate API call
return {
location,
temperature: 72,
condition: 'sunny',
humidity: 65,
unit: 'fahrenheit',
};
},
}),
convertTemp: tool({
description: 'Convert temperature between Fahrenheit and Celsius',
inputSchema: z.object({
fahrenheit: z.number(),
}),
execute: async ({ fahrenheit }) => {
console.log(`[Tool] Converting ${fahrenheit}°F to Celsius...`);
const celsius = Math.round(((fahrenheit - 32) * 5 / 9) * 10) / 10;
return { celsius };
},
}),
getAirQuality: tool({
description: 'Get air quality index for a location',
inputSchema: z.object({
location: z.string(),
}),
execute: async ({ location }) => {
console.log(`[Tool] Getting air quality for ${location}...`);
// Simulate API call
return {
location,
aqi: 42,
level: 'good',
pollutants: {
pm25: 8,
pm10: 15,
o3: 35,
},
};
},
}),
},
});
async function main() {
console.log('Starting agent conversation...\n');
const result = await weatherAgent.run({
messages: [
{
role: 'user',
content: 'What is the weather in San Francisco? Tell me in Celsius and include air quality.',
},
],
});
console.log('\n--- Agent Response ---');
console.log(result.text);
console.log('\n--- Execution Summary ---');
console.log('Total steps:', result.steps);
console.log('Tools used:', result.toolCalls?.map(tc => tc.toolName).join(', ') || 'none');
}
main().catch(console.error);
// Anthropic provider configuration
// AI SDK Core - Anthropic (Claude) setup and usage
import { generateText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
async function main() {
console.log('=== Anthropic (Claude) Provider Setup ===\n');
// Method 1: Use environment variable (recommended)
// ANTHROPIC_API_KEY=sk-ant-...
const model1 = anthropic('claude-sonnet-4-5');
// Method 2: Explicit API key
const model2 = anthropic('claude-sonnet-4-5', {
apiKey: process.env.ANTHROPIC_API_KEY,
});
// Available models (Claude 4.x family - current)
const models = {
sonnet45: anthropic('claude-sonnet-4-5'), // Latest, recommended
opus4: anthropic('claude-opus-4-0'), // Highest intelligence
haiku45: anthropic('claude-haiku-4-5'), // Fastest
};
// Legacy models (Claude 3.x - deprecated, use Claude 4.x instead)
// const legacyModels = {
// sonnet35: anthropic('claude-3-5-sonnet-20241022'),
// opus3: anthropic('claude-3-opus-20240229'),
// haiku3: anthropic('claude-3-haiku-20240307'),
// };
// Example: Generate text with Claude
console.log('Generating text with Claude Sonnet 4.5...\n');
const result = await generateText({
model: models.sonnet45,
prompt: 'Explain what makes Claude different from other AI assistants in 2 sentences.',
maxOutputTokens: 150,
});
console.log('Response:', result.text);
console.log('\nUsage:');
console.log('- Prompt tokens:', result.usage.promptTokens);
console.log('- Completion tokens:', result.usage.completionTokens);
console.log('- Total tokens:', result.usage.totalTokens);
// Example: Long context handling
console.log('\n=== Long Context Example ===\n');
const longContextResult = await generateText({
model: models.sonnet45,
messages: [
{
role: 'user',
content: 'I will give you a long document to analyze. Here it is: ' + 'Lorem ipsum '.repeat(1000),
},
{
role: 'user',
content: 'Now summarize the key points.',
},
],
maxOutputTokens: 200,
});
console.log('Long context summary:', longContextResult.text);
// Model selection guide
console.log('\n=== Model Selection Guide ===');
console.log('- Claude Sonnet 4.5: Latest model, best balance (recommended)');
console.log('- Claude Opus 4.0: Highest intelligence for complex reasoning');
console.log('- Claude Haiku 4.5: Fastest and most cost-effective');
console.log('\nAll Claude 4.x models support extended context windows');
console.log('Note: Claude 3.x models deprecated in 2025, use Claude 4.x instead');
}
main().catch(console.error);
// Cloudflare Workers with workers-ai-provider
// AI SDK Core - Cloudflare Workers AI integration
import { Hono } from 'hono';
import { generateText, streamText } from 'ai';
import { createWorkersAI } from 'workers-ai-provider';
// Environment interface for Workers AI binding
interface Env {
AI: Ai;
}
const app = new Hono<{ Bindings: Env }>();
// Example 1: Basic text generation
app.post('/chat', async (c) => {
// IMPORTANT: Create provider inside handler to avoid startup overhead
const workersai = createWorkersAI({ binding: c.env.AI });
const { message } = await c.req.json();
const result = await generateText({
model: workersai('@cf/meta/llama-3.1-8b-instruct'),
prompt: message,
maxOutputTokens: 500,
});
return c.json({ response: result.text });
});
// Example 2: Streaming response
app.post('/chat/stream', async (c) => {
const workersai = createWorkersAI({ binding: c.env.AI });
const { message } = await c.req.json();
const stream = streamText({
model: workersai('@cf/meta/llama-3.1-8b-instruct'),
prompt: message,
});
// Return stream to client
return stream.toDataStreamResponse();
});
// Example 3: Structured output
app.post('/extract', async (c) => {
const workersai = createWorkersAI({ binding: c.env.AI });
const { generateObject } = await import('ai');
const { z } = await import('zod');
const { text } = await c.req.json();
const result = await generateObject({
model: workersai('@cf/meta/llama-3.1-8b-instruct'),
schema: z.object({
summary: z.string(),
keyPoints: z.array(z.string()),
}),
prompt: `Extract key information from: ${text}`,
});
return c.json(result.object);
});
// Example 4: Health check
app.get('/health', (c) => {
return c.json({ status: 'ok', ai: 'ready' });
});
export default app;
/*
* wrangler.jsonc configuration:
*
* {
* "name": "ai-sdk-worker",
* "compatibility_date": "2025-10-21",
* "main": "src/index.ts",
* "ai": {
* "binding": "AI"
* }
* }
*/
/*
* IMPORTANT NOTES:
*
* 1. Startup Optimization:
* - Move `createWorkersAI` inside handlers (not top-level)
* - Avoid importing complex Zod schemas at top level
* - Monitor startup time (must be <400ms)
*
* 2. Available Models:
* - @cf/meta/llama-3.1-8b-instruct (recommended)
* - @cf/meta/llama-3.1-70b-instruct
* - @cf/mistral/mistral-7b-instruct-v0.1
* - See: https://developers.cloudflare.com/workers-ai/models/
*
* 3. When to use workers-ai-provider:
* - Multi-provider scenarios (OpenAI + Workers AI)
* - Using AI SDK UI hooks
* - Need consistent API across providers
*
* 4. When to use native binding:
* - Cloudflare-only deployment
* - Maximum performance
* - See: cloudflare-workers-ai skill
*
* 5. Testing:
* npx wrangler dev
* curl -X POST http://localhost:8787/chat \
* -H "Content-Type: application/json" \
* -d '{"message": "Hello!"}'
*
* 6. Deployment:
* npx wrangler deploy
*/
// Structured output with Zod schema validation
// AI SDK Core - generateObject() with Zod
import { generateObject } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
// Define Zod schema
const PersonSchema = z.object({
name: z.string().describe('Person full name'),
age: z.number().describe('Person age in years'),
role: z.enum(['engineer', 'designer', 'manager', 'other']).describe('Job role'),
skills: z.array(z.string()).describe('List of technical skills'),
experience: z.object({
years: z.number(),
companies: z.array(z.string()),
}),
});
async function main() {
const result = await generateObject({
model: openai('gpt-4'),
schema: PersonSchema,
prompt: 'Generate a profile for a senior software engineer with 8 years of experience.',
});
console.log('Generated object:');
console.log(JSON.stringify(result.object, null, 2));
// TypeScript knows the exact type
console.log('\nAccessing typed properties:');
console.log('Name:', result.object.name);
console.log('Skills:', result.object.skills.join(', '));
console.log('Years of experience:', result.object.experience.years);
}
main().catch(console.error);
// Simple text generation with OpenAI
// AI SDK Core - generateText() basic example
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
async function main() {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'What is TypeScript? Explain in 2 sentences.',
maxOutputTokens: 100,
temperature: 0.7,
});
console.log('Generated text:', result.text);
console.log('Tokens used:', result.usage.totalTokens);
console.log('Finish reason:', result.finishReason);
}
main().catch(console.error);
// Google provider configuration
// AI SDK Core - Google (Gemini) setup and usage
import { generateText } from 'ai';
import { google } from '@ai-sdk/google';
async function main() {
console.log('=== Google (Gemini) Provider Setup ===\n');
// Method 1: Use environment variable (recommended)
// GOOGLE_GENERATIVE_AI_API_KEY=...
const model1 = google('gemini-2.5-pro');
// Method 2: Explicit API key
const model2 = google('gemini-2.5-pro', {
apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
});
// Available models
const models = {
pro: google('gemini-2.5-pro'), // Best for reasoning
flash: google('gemini-2.5-flash'), // Fast and efficient
flashLite: google('gemini-2.5-flash-lite'), // Ultra-fast (if available)
};
// Example: Generate text with Gemini
console.log('Generating text with Gemini 2.5 Pro...\n');
const result = await generateText({
model: models.pro,
prompt: 'Explain what makes Gemini good at multimodal tasks in 2 sentences.',
maxOutputTokens: 150,
});
console.log('Response:', result.text);
console.log('\nUsage:');
console.log('- Prompt tokens:', result.usage.promptTokens);
console.log('- Completion tokens:', result.usage.completionTokens);
console.log('- Total tokens:', result.usage.totalTokens);
// Example: Structured output with Gemini
console.log('\n=== Structured Output Example ===\n');
const { generateObject } = await import('ai');
const { z } = await import('zod');
const structuredResult = await generateObject({
model: models.pro,
schema: z.object({
title: z.string(),
summary: z.string(),
keyPoints: z.array(z.string()),
}),
prompt: 'Summarize the benefits of using Gemini AI.',
});
console.log('Structured output:');
console.log(JSON.stringify(structuredResult.object, null, 2));
// Error handling example
console.log('\n=== Error Handling ===\n');
try {
const result2 = await generateText({
model: google('gemini-2.5-pro'),
prompt: 'Hello',
});
console.log('Success:', result2.text);
} catch (error: any) {
if (error.message?.includes('SAFETY')) {
console.error('Error: Content filtered by safety settings');
} else if (error.message?.includes('QUOTA_EXCEEDED')) {
console.error('Error: API quota exceeded');
} else {
console.error('Error:', error.message);
}
}
// Model selection guide
console.log('\n=== Model Selection Guide ===');
console.log('- Gemini 2.5 Pro: Best for complex reasoning and analysis');
console.log('- Gemini 2.5 Flash: Fast and cost-effective for most tasks');
console.log('- Gemini 2.5 Flash Lite: Ultra-fast for simple tasks');
console.log('\nGemini has generous free tier limits and excels at multimodal tasks');
}
main().catch(console.error);
// Multi-step execution with stopWhen conditions
// AI SDK Core - Control multi-step workflows
import { generateText, tool, stopWhen, stepCountIs, hasToolCall } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
async function example1_stepCount() {
console.log('=== Example 1: Stop after N steps ===\n');
const result = await generateText({
model: openai('gpt-4'),
tools: {
research: tool({
description: 'Research a topic',
inputSchema: z.object({ topic: z.string() }),
execute: async ({ topic }) => {
console.log(`[Tool] Researching ${topic}...`);
return { info: `Research data about ${topic}` };
},
}),
analyze: tool({
description: 'Analyze research data',
inputSchema: z.object({ data: z.string() }),
execute: async ({ data }) => {
console.log(`[Tool] Analyzing data...`);
return { analysis: `Analysis of ${data}` };
},
}),
},
prompt: 'Research TypeScript and analyze the findings.',
stopWhen: stepCountIs(3), // Stop after 3 steps
});
console.log('\nResult:', result.text);
console.log('Steps taken:', result.steps);
}
async function example2_specificTool() {
console.log('\n=== Example 2: Stop when specific tool called ===\n');
const result = await generateText({
model: openai('gpt-4'),
tools: {
search: tool({
description: 'Search for information',
inputSchema: z.object({ query: z.string() }),
execute: async ({ query }) => {
console.log(`[Tool] Searching for: ${query}`);
return { results: `Search results for ${query}` };
},
}),
summarize: tool({
description: 'Create final summary',
inputSchema: z.object({ content: z.string() }),
execute: async ({ content }) => {
console.log(`[Tool] Creating summary...`);
return { summary: `Summary of ${content}` };
},
}),
},
prompt: 'Search for information about AI and create a summary.',
stopWhen: hasToolCall('summarize'), // Stop when summarize is called
});
console.log('\nResult:', result.text);
console.log('Final tool called:', result.toolCalls?.[result.toolCalls.length - 1]?.toolName);
}
async function example3_customCondition() {
console.log('\n=== Example 3: Custom stop condition ===\n');
const result = await generateText({
model: openai('gpt-4'),
tools: {
calculate: tool({
description: 'Perform calculation',
inputSchema: z.object({ expression: z.string() }),
execute: async ({ expression }) => {
console.log(`[Tool] Calculating: ${expression}`);
return { result: 42 };
},
}),
finish: tool({
description: 'Mark task as complete',
inputSchema: z.object({ status: z.string() }),
execute: async ({ status }) => {
console.log(`[Tool] Finishing with status: ${status}`);
return { done: true };
},
}),
},
prompt: 'Solve a math problem and finish.',
stopWhen: (step) => {
// Stop if:
// - More than 5 steps, OR
// - 'finish' tool was called
return step.stepCount > 5 || step.hasToolCall('finish');
},
});
console.log('\nResult:', result.text);
console.log('Stopped at step:', result.steps);
}
async function main() {
await example1_stepCount();
await example2_specificTool();
await example3_customCondition();
}
main().catch(console.error);
// Next.js Server Action with AI SDK
// AI SDK Core - Server Actions for Next.js App Router
'use server';
import { generateObject, generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
// Example 1: Simple text generation
export async function generateStory(theme: string) {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt: `Write a short story about: ${theme}`,
maxOutputTokens: 500,
});
return result.text;
}
// Example 2: Structured output (recipe generation)
export async function generateRecipe(ingredients: string[]) {
const RecipeSchema = z.object({
name: z.string(),
description: z.string(),
ingredients: z.array(
z.object({
name: z.string(),
amount: z.string(),
})
),
instructions: z.array(z.string()),
cookingTime: z.number().describe('Cooking time in minutes'),
servings: z.number(),
});
const result = await generateObject({
model: openai('gpt-4'),
schema: RecipeSchema,
prompt: `Create a recipe using these ingredients: ${ingredients.join(', ')}`,
});
return result.object;
}
// Example 3: Data extraction
export async function extractContactInfo(text: string) {
const ContactSchema = z.object({
name: z.string().optional(),
email: z.string().email().optional(),
phone: z.string().optional(),
company: z.string().optional(),
});
const result = await generateObject({
model: openai('gpt-4'),
schema: ContactSchema,
prompt: `Extract contact information from this text: ${text}`,
});
return result.object;
}
// Example 4: Error handling in Server Action
export async function generateWithErrorHandling(prompt: string) {
try {
const result = await generateText({
model: openai('gpt-4-turbo'),
prompt,
maxOutputTokens: 200,
});
return { success: true, data: result.text };
} catch (error: any) {
console.error('AI generation error:', error);
return {
success: false,
error: 'Failed to generate response. Please try again.',
};
}
}
/*
* Usage in Client Component:
*
* 'use client';
*
* import { useState } from 'react';
* import { generateStory, generateRecipe } from './actions';
*
* export default function AIForm() {
* const [result, setResult] = useState('');
* const [loading, setLoading] = useState(false);
*
* async function handleGenerateStory(formData: FormData) {
* setLoading(true);
* const theme = formData.get('theme') as string;
* const story = await generateStory(theme);
* setResult(story);
* setLoading(false);
* }
*
* async function handleGenerateRecipe(formData: FormData) {
* setLoading(true);
* const ingredients = (formData.get('ingredients') as string).split(',');
* const recipe = await generateRecipe(ingredients);
* setResult(JSON.stringify(recipe, null, 2));
* setLoading(false);
* }
*
* return (
* <div>
* <form action={handleGenerateStory}>
* <input name="theme" placeholder="Story theme" required />
* <button disabled={loading}>Generate Story</button>
* </form>
*
* <form action={handleGenerateRecipe}>
* <input name="ingredients" placeholder="flour, eggs, sugar" required />
* <button disabled={loading}>Generate Recipe</button>
* </form>
*
* {result && <pre>{result}</pre>}
* </div>
* );
* }
*/
/*
* File Structure:
*
* app/
* ├── actions.ts # This file (Server Actions)
* ├── page.tsx # Client component using actions
* └── api/
* └── chat/
* └── route.ts # Alternative: API Route for streaming
*
* Note: Server Actions are recommended for mutations and non-streaming AI calls.
* For streaming, use API Routes with streamText().toDataStreamResponse()
*/
/*
* Environment Variables (.env.local):
*
* OPENAI_API_KEY=sk-...
* ANTHROPIC_API_KEY=sk-ant-...
* GOOGLE_GENERATIVE_AI_API_KEY=...
*/
// OpenAI provider configuration
// AI SDK Core - OpenAI setup and usage
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
async function main() {
console.log('=== OpenAI Provider Setup ===\n');
// Method 1: Use environment variable (recommended)
// OPENAI_API_KEY=sk-...
const model1 = openai('gpt-4-turbo');
// Method 2: Explicit API key
const model2 = openai('gpt-4', {
apiKey: process.env.OPENAI_API_KEY,
});
// Available models (latest)
const models = {
gpt51: openai('gpt-5.1'), // Latest flagship model (Nov 2025)
gpt5Pro: openai('gpt-5-pro'), // Advanced reasoning
gpt41: openai('gpt-4.1'), // Latest GPT-4 series
o3: openai('o3'), // Reasoning model
gpt4Turbo: openai('gpt-4-turbo'), // Previous generation (still excellent)
gpt35Turbo: openai('gpt-3.5-turbo'), // Fast, cost-effective
};
// Older models (still functional)
// const olderModels = {
// gpt5: openai('gpt-5'), // Superseded by gpt-5.1
// gpt4: openai('gpt-4'), // Use gpt-4-turbo instead
// };
// Example: Generate text with GPT-4
console.log('Generating text with GPT-4 Turbo...\n');
const result = await generateText({
model: models.gpt4Turbo,
prompt: 'Explain the difference between GPT-3.5 and GPT-4 in one sentence.',
maxOutputTokens: 100,
});
console.log('Response:', result.text);
console.log('\nUsage:');
console.log('- Prompt tokens:', result.usage.promptTokens);
console.log('- Completion tokens:', result.usage.completionTokens);
console.log('- Total tokens:', result.usage.totalTokens);
// Example: Error handling
console.log('\n=== Error Handling ===\n');
try {
const result2 = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Hello',
});
console.log('Success:', result2.text);
} catch (error: any) {
if (error.statusCode === 401) {
console.error('Error: Invalid API key');
} else if (error.statusCode === 429) {
console.error('Error: Rate limit exceeded');
} else if (error.statusCode >= 500) {
console.error('Error: OpenAI server issue');
} else {
console.error('Error:', error.message);
}
}
// Model selection guide
console.log('\n=== Model Selection Guide ===');
console.log('- gpt-5.1: Latest flagship model (November 2025)');
console.log('- gpt-5-pro: Advanced reasoning and complex tasks');
console.log('- o3: Specialized reasoning model');
console.log('- gpt-4.1: Latest GPT-4 series, excellent quality');
console.log('- gpt-4-turbo: Previous generation, still very capable');
console.log('- gpt-3.5-turbo: Fast and cost-effective for simple tasks');
}
main().catch(console.error);
{
"name": "ai-sdk-core-example",
"version": "1.0.0",
"type": "module",
"description": "AI SDK Core examples - Backend AI with generateText, streamText, generateObject, and tools",
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"type-check": "tsc --noEmit"
},
"dependencies": {
"ai": "^5.0.95",
"@ai-sdk/openai": "^2.0.68",
"@ai-sdk/anthropic": "^2.0.45",
"@ai-sdk/google": "^2.0.38",
"workers-ai-provider": "^2.0.0",
"zod": "^3.23.8"
},
"devDependencies": {
"@types/node": "^20.11.0",
"tsx": "^4.7.0",
"typescript": "^5.3.3"
},
"keywords": [
"ai",
"ai-sdk",
"vercel",
"openai",
"anthropic",
"google",
"gemini",
"claude",
"gpt-4",
"llm",
"text-generation",
"structured-output",
"zod"
],
"author": "",
"license": "MIT"
}
// Streaming structured output with partial updates
// AI SDK Core - streamObject() with Zod
import { streamObject } from 'ai';
import { google } from '@ai-sdk/google';
import { z } from 'zod';
// Define schema for RPG characters
const CharacterSchema = z.object({
characters: z.array(
z.object({
name: z.string(),
class: z.enum(['warrior', 'mage', 'rogue', 'cleric']),
level: z.number(),
stats: z.object({
hp: z.number(),
mana: z.number(),
strength: z.number(),
intelligence: z.number(),
}),
inventory: z.array(z.string()),
})
),
});
async function main() {
const stream = streamObject({
model: google('gemini-2.5-pro'),
schema: CharacterSchema,
prompt: 'Generate 3 diverse RPG characters with complete stats and starting inventory.',
});
console.log('Streaming structured object (partial updates):');
console.log('---\n');
// Stream partial object updates
for await (const partialObject of stream.partialObjectStream) {
console.clear(); // Clear console for visual effect
console.log('Current partial object:');
console.log(JSON.stringify(partialObject, null, 2));
}
// Get final complete object
const result = await stream.result;
console.log('\n---');
console.log('Final complete object:');
console.log(JSON.stringify(result.object, null, 2));
console.log('\nCharacter count:', result.object.characters.length);
}
main().catch(console.error);
// Streaming chat with messages
// AI SDK Core - streamText() with chat messages
import { streamText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
async function main() {
const stream = streamText({
model: anthropic('claude-sonnet-4-5'),
messages: [
{
role: 'system',
content: 'You are a helpful assistant that writes concise responses.',
},
{
role: 'user',
content: 'Tell me a short story about AI and humanity working together.',
},
],
maxOutputTokens: 500,
});
console.log('Streaming response:');
console.log('---');
// Stream text chunks to console
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}
console.log('\n---');
// Get final result with metadata
const result = await stream.result;
console.log('\nTokens used:', result.usage.totalTokens);
console.log('Finish reason:', result.finishReason);
}
main().catch(console.error);
// Basic tool calling example
// AI SDK Core - Tool calling with generateText()
import { generateText, tool } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
async function main() {
const result = await generateText({
model: openai('gpt-4'),
tools: {
weather: tool({
description: 'Get the current weather for a location',
inputSchema: z.object({
location: z.string().describe('City name, e.g. "San Francisco"'),
unit: z.enum(['celsius', 'fahrenheit']).optional().describe('Temperature unit'),
}),
execute: async ({ location, unit = 'fahrenheit' }) => {
// Simulate API call to weather service
console.log(`[Tool] Fetching weather for ${location}...`);
// In production, call real weather API here
const mockWeather = {
location,
temperature: unit === 'celsius' ? 22 : 72,
condition: 'sunny',
humidity: 65,
unit,
};
return mockWeather;
},
}),
convertTemperature: tool({
description: 'Convert temperature between Celsius and Fahrenheit',
inputSchema: z.object({
value: z.number(),
from: z.enum(['celsius', 'fahrenheit']),
to: z.enum(['celsius', 'fahrenheit']),
}),
execute: async ({ value, from, to }) => {
console.log(`[Tool] Converting ${value}°${from} to ${to}...`);
if (from === to) return { value, unit: to };
let result: number;
if (from === 'celsius' && to === 'fahrenheit') {
result = (value * 9 / 5) + 32;
} else {
result = (value - 32) * 5 / 9;
}
return { value: Math.round(result * 10) / 10, unit: to };
},
}),
},
prompt: 'What is the weather in Tokyo? Please tell me in Celsius.',
maxOutputTokens: 200,
});
console.log('\n--- AI Response ---');
console.log(result.text);
console.log('\n--- Tool Calls ---');
console.log('Number of tool calls:', result.toolCalls?.length || 0);
if (result.toolCalls) {
result.toolCalls.forEach((call, i) => {
console.log(`\n${i + 1}. ${call.toolName}`);
console.log(' Input:', JSON.stringify(call.input));
console.log(' Output:', JSON.stringify(call.output));
});
}
}
main().catch(console.error);