ai-sdk-6-skill

Expert guide for Vercel AI SDK 6 - ToolLoopAgent, safety patterns, MCP, RAG, DevTools.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "ai-sdk-6-skill" with this command: npx skills add francostan/ai-sdk-6-skill/francostan-ai-sdk-6-skill-ai-sdk-6-skill

AI SDK 6 Skill

Quick Ref

FunctionWhat
generateTextSingle LLM call (use Output.object() for structured JSON)
streamTextStreaming response
ToolLoopAgentMulti-step agent loop with generate() / stream()
createMCPClientExternal tool servers
rerankRAG relevance scoring

When to Use

  • Building multi-step agents with ToolLoopAgent
  • Adding human-in-the-loop safety with needsApproval
  • Connecting MCP servers or using provider-native tools
  • Implementing RAG with rerank
  • Debugging with DevTools
  • Migrating from AI SDK 5 → 6

Core Patterns

1. ToolLoopAgent

The main primitive for multi-step workflows. Automatically handles the "call model → run tools → append results" loop. Defaults to max 20 steps.

import { ToolLoopAgent, stepCountIs, type InferAgentUIMessage } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';

const agent = new ToolLoopAgent({
  model: anthropic('claude-sonnet-4-5-20250514'),
  instructions: 'You are a helpful assistant.',  // replaces 'system'
  tools: { getWeather, searchDocs, sendEmail },
  activeTools: ['getWeather', 'searchDocs'],  // subset of tools active per step
  stopWhen: stepCountIs(10),
  toolChoice: 'auto',  // or 'required', 'none', { tool: 'name' }
  output: Output.object({ schema: mySchema }),  // optional structured output
  prepareStep: async ({ previousSteps }) => {
    // dynamically adjust tools/instructions per step
    return { activeTools: ['sendEmail'] };
  },
  onStepFinish: ({ step, usage }) => {
    console.log('Step completed:', step.type, usage);
  }
});

// Generate (blocking)
const result = await agent.generate({
  prompt: 'Check weather in SF and email me a summary'
});

// Stream
const stream = agent.stream({ prompt: 'Check weather in SF' });
for await (const chunk of stream) {
  console.log(chunk);
}

// Type export for UI
export type MyAgentUIMessage = InferAgentUIMessage<typeof agent>;

Best practices:

  • Define agents in dedicated modules (agents/support-agent.ts)
  • Export types for UI: export type MyAgentUIMessage = InferAgentUIMessage<typeof myAgent>;
  • Use callOptionsSchema + prepareCall for dynamic context (userId, subscription tier)
  • Use toModelOutput to return rich data to your app but minimal summaries to the LLM (saves tokens)

2. Safety with needsApproval

Block dangerous tools until user explicitly confirms. Essential for destructive operations.

import { tool } from 'ai';
import { z } from 'zod';

const tools = {
  deleteUser: tool({
    description: 'Permanently delete a user account',
    parameters: z.object({ userId: z.string() }),
    needsApproval: true,  // static
    execute: async ({ userId }) => {
      await db.users.delete(userId);
      return { deleted: true };
    }
  }),

  // Dynamic approval based on context
  transferFunds: tool({
    parameters: z.object({ amount: z.number(), to: z.string() }),
    needsApproval: async ({ amount }) => amount > 1000,
    execute: async ({ amount, to }) => { /* ... */ }
  })
};

Two-call approval workflow:

When needsApproval returns true, the agent pauses with tool-approval-request. Your app must:

  1. Show approval UI to user
  2. Re-call agent with tool-approval-response message
// First call - agent requests approval
const result1 = await agent.generate({ prompt: 'Delete user 123' });
// result1.finishReason === 'tool-approval-request'

// After user approves in UI, continue with approval response
const result2 = await agent.generate({
  messages: [
    ...result1.messages,
    { type: 'tool-approval-response', toolCallId: 'xyz', approved: true }
  ]
});

In your UI, check for approval-requested state and show confirmation dialog before proceeding.

3. MCP Integration

Connect to external Model Context Protocol servers for additional tools.

import { createMCPClient } from '@ai-sdk/mcp';
import { anthropic } from '@ai-sdk/anthropic';

const mcp = await createMCPClient({
  transport: { type: 'sse', url: 'https://mcp.example.com/sse' }
});

const tools = await mcp.listTools();

// Use in agent
const agent = new ToolLoopAgent({
  model: anthropic('claude-sonnet-4-5-20250514'),
  tools: { ...myTools, ...tools }
});

Notes:

  • Use OAuthClientProvider for authenticated connections
  • Handle elicitation requests when server needs user input
  • Implement reconnection logic for production

4. RAG with Rerank

Two-stage retrieval: fetch broad candidate set, then rerank by relevance.

import { rerank } from 'ai';
import { cohere } from '@ai-sdk/cohere';
// or: import { amazonBedrock } from '@ai-sdk/amazon-bedrock';

// Stage 1: Broad vector search
const candidates = await vectorStore.search(query, { limit: 50 });

// Stage 2: Rerank for relevance
const { ranking, rerankedDocuments, originalDocuments } = await rerank({
  model: cohere.reranking('rerank-v3.5'),
  // or: amazonBedrock.reranking('cohere.rerank-v3-5:0'),
  query,
  documents: candidates,
  topN: 5  // optional: limit results
});

// Use top results in context
const context = rerankedDocuments;

Return structure:

  • ranking - array of { documentIndex, relevanceScore }
  • rerankedDocuments - documents sorted by relevance
  • originalDocuments - original order preserved

This reduces hallucinations and improves response quality vs naive top-k retrieval.

5. Structured Output

Force agent to return typed JSON using Output.object() in generateText:

import { generateText, Output } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';

const { output } = await generateText({
  model: anthropic('claude-sonnet-4-5-20250514'),
  prompt: 'Research our top 3 competitors',
  output: Output.object({
    schema: z.object({
      competitors: z.array(z.object({
        name: z.string(),
        strengths: z.array(z.string()),
        weaknesses: z.array(z.string()),
        marketShare: z.number().optional()
      }))
    })
  })
});

// output is fully typed

Note: generateObject() and streamObject() are deprecated in v6. Use generateText with Output.object() instead.

6. Provider-Native Tools

Use built-in tools when available - they're optimized and don't count against your tool limit:

Anthropic:

  • computer - Browser/desktop automation (beta)
  • memory - Key-value store across conversations
  • code_execution - Sandboxed code analysis

OpenAI:

  • file_search - Search uploaded files
  • code_interpreter - Run Python in sandbox

Google:

  • google_maps - Location grounding
  • vertex_rag_store - Managed RAG

xAI:

  • web_search - Real-time web with image understanding
  • x_search - Search X/Twitter

Workflow Patterns

Orchestrator-Worker

Main agent delegates to specialized sub-agents via tools:

import { anthropic } from '@ai-sdk/anthropic';

const orchestrator = new ToolLoopAgent({
  model: anthropic('claude-sonnet-4-5-20250514'),
  tools: {
    research: tool({
      description: 'Deep research on a topic',
      parameters: z.object({ topic: z.string() }),
      execute: async ({ topic }) => {
        const researcher = new ToolLoopAgent({
          model: anthropic('claude-sonnet-4-5-20250514'),
          tools: { webSearch, readPage, summarize }
        });
        return researcher.generate({ prompt: `Research: ${topic}` });
      }
    }),

    analyze: tool({
      description: 'Analyze data',
      parameters: z.object({ data: z.any() }),
      execute: async ({ data }) => {
        const analyst = new ToolLoopAgent({ /* analyst config */ });
        return analyst.generate({ prompt: `Analyze: ${JSON.stringify(data)}` });
      }
    })
  }
});

Parallel Execution

Run independent agents concurrently:

const [weather, news, stocks] = await Promise.all([
  weatherAgent.generate({ prompt: 'SF weather forecast' }),
  newsAgent.generate({ prompt: 'Top tech news today' }),
  stocksAgent.generate({ prompt: 'AAPL current price and trend' })
]);

// Combine results
const summary = await summaryAgent.generate({
  prompt: `Summarize: ${JSON.stringify({ weather, news, stocks })}`
});

Sequential with Context

Process items while accumulating context:

let context = { findings: [] };

for (const company of companies) {
  const result = await agent.generate({
    prompt: `Analyze ${company}. Previous findings: ${JSON.stringify(context.findings)}`,
  });

  context.findings.push({ company, analysis: result.text });
}

Evaluation Loop

Self-correcting agent with quality checks:

let attempts = 0;
let result;

do {
  result = await agent.generate({ prompt: task });
  const evaluation = await evaluator.generate({
    prompt: `Is this output satisfactory? ${result.text}`
  });

  if (evaluation.text.includes('yes')) break;
  attempts++;
} while (attempts < 3);

Debugging & Observability

DevTools

Wrap model with middleware for full trace inspection:

import { devToolsMiddleware } from '@ai-sdk/devtools';
import { anthropic } from '@ai-sdk/anthropic';

const model = devToolsMiddleware(anthropic('claude-sonnet-4-5-20250514'));

// Run DevTools server
// npx @ai-sdk/devtools
// Opens at localhost:4983

DevTools shows: inputs, tool calls, raw provider payloads, token costs.

Token Analytics

const result = await agent.generate({ prompt });

// Cache efficiency
console.log(result.usage.inputTokenDetails);  // { cached: 1000, uncached: 200 }

// Output breakdown
console.log(result.usage.outputTokenDetails);

// Provider-specific stop reason
console.log(result.rawFinishReason);  // 'end_turn', 'tool_use', 'max_tokens', etc.

Common Errors & Fixes

ErrorCauseFix
maxSteps exceededAgent hit step limit without completingIncrease stopWhen: stepCountIs(N) or simplify tool set
Tool schema validationModel sent invalid paramsAdd inputExamples to tool, simplify schema, enable strict: true
MCP connection failedServer unreachable or auth issueCheck URL, verify credentials, add reconnect logic
rawFinishReason: lengthContext window fullTrim conversation history, use toModelOutput for compact summaries
Approval timeoutneedsApproval not handled in UIImplement approval dialog/webhook handler
Tool not calledModel doesn't understand when to use itImprove tool description, add inputExamples

Migration from v5

Run the automated codemod:

npx @ai-sdk/codemod v6

Manual checks needed:

  • Custom middleware implementations (API changed)
  • streamUI usage (evolved for agentic patterns)
  • Any direct provider API calls

Key API changes:

v5v6
system: '...'instructions: '...'
generateObject()generateText() + Output.object()
streamObject()streamText() + Output.object()
convertToCoreMessages()convertToModelMessages() (now async)
usage.totalTokensusage.inputTokens + usage.outputTokens

Structural changes:

  • ToolLoopAgent replaces manual tool loops
  • needsApproval is now built-in (no custom implementation needed)
  • rerank is a first-class function
  • DevTools middleware for debugging

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

openclaw-version-monitor

监控 OpenClaw GitHub 版本更新,获取最新版本发布说明,翻译成中文, 并推送到 Telegram 和 Feishu。用于:(1) 定时检查版本更新 (2) 推送版本更新通知 (3) 生成中文版发布说明

Archived SourceRecently Updated
Coding

ask-claude

Delegate a task to Claude Code CLI and immediately report the result back in chat. Supports persistent sessions with full context memory. Safe execution: no data exfiltration, no external calls, file operations confined to workspace. Use when the user asks to run Claude, delegate a coding task, continue a previous Claude session, or any task benefiting from Claude Code's tools (file editing, code analysis, bash, etc.).

Archived SourceRecently Updated
Coding

ai-dating

This skill enables dating and matchmaking workflows. Use it when a user asks to make friends, find a partner, run matchmaking, or provide dating preferences/profile updates. The skill should execute `dating-cli` commands to complete profile setup, task creation/update, match checking, contact reveal, and review.

Archived SourceRecently Updated
Coding

clawhub-rate-limited-publisher

Queue and publish local skills to ClawHub with a strict 5-per-hour cap using the local clawhub CLI and host scheduler.

Archived SourceRecently Updated