Vercel AI SDK v5 Agent Patterns: stopWhen, prepareStep, and Loop Control
AI SDK 5 ships fully typed chat for React, Svelte, Vue, and Angular plus first-class agent loop primitives. Here are the patterns that matter for shipping in 2026.
TL;DR — Vercel AI SDK 5 (released July 31, 2025) is the TypeScript-first answer to agent loops.
stopWhencontrols when a tool-calling loop ends;prepareStepmutates the next step's settings; the redesigneduseChathook ships modular transports for WebSockets and SSE. The result is the cleanest TS path from prototype to production agent in 2026.
What's actually in AI SDK 5
flowchart TD
Client[MCP client · Claude Desktop] --> MCP[MCP server]
MCP --> Tool1[Tool: Calendar]
MCP --> Tool2[Tool: CRM]
MCP --> Tool3[Tool: KB search]
Tool1 --> SaaS1[(Calendly)]
Tool2 --> SaaS2[(Salesforce)]
Tool3 --> SaaS3[(Notion)]The headline numbers from the v5 release:
- Fully typed chat hook for React, Svelte, Vue, and Angular — same primitives, framework-native bindings.
- Tool improvements — dynamic tools, provider-executed functions, lifecycle hooks, type-safety throughout the tool calling process.
- Modular
useChatwith three extensibility patterns: flexible transports (WebSockets, SSE, custom), client-only support, and end-to-end typed message envelopes. - Agentic control via
stopWhenandprepareStep. - Speech and audio APIs — consistent typed interface across OpenAI, ElevenLabs, DeepGram.
The agent loop, demystified
The classic SDK loop runs generateText (or streamText) with a tools object. The model emits a tool call, the SDK runs the tool, appends the result, runs the model again. Repeat until the model emits text without a tool call — or until you stop it.
stopWhen controls the stop condition. Built-ins:
stepCountIs(20)— stop after 20 steps. Default safety.hasToolCall("submit")— stop when a specific tool is called.isLoopFinished()— never trigger; let the agent run to natural completion.
You can compose them: stopWhen: [stepCountIs(20), hasToolCall("submit")] — stop on whichever fires first.
prepareStep is the per-step config callback. It runs before each step and can:
- Swap the model (cheaper model for the first step, smarter for the second).
- Mutate the messages (truncate history, inject a reminder).
- Change the tool set (different tools available at different steps).
This is your hook for adaptive cost and quality control mid-loop.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
A real production pattern
import { generateText, stepCountIs, hasToolCall } from "ai";
const result = await generateText({
model: openai("gpt-5"),
tools: { lookup, schedule, submit },
messages,
stopWhen: [stepCountIs(15), hasToolCall("submit")],
prepareStep: async ({ stepNumber, messages }) => {
if (stepNumber === 0) {
return { model: openai("gpt-5-mini") }; // cheap first pass
}
if (messages.length > 30) {
return { messages: messages.slice(-20) }; // truncate context
}
return {};
},
});
The first step runs on a cheaper model to triage. Later steps escalate to the bigger model. If history grows beyond 30 messages, we truncate. The loop stops at 15 steps or when submit is called. This pattern can cut your agent's per-conversation cost by 40-60% with no quality drop on common inputs.
useChat redesigned
The new useChat is transport-agnostic. The default is HTTP streaming. You can plug in:
- WebSocket transport — push tokens from a long-lived connection.
- SSE transport — server-sent events for one-way streaming.
- Custom transport — your own protocol (CallSphere's voice agent uses a custom WebRTC-aware transport).
Each transport ships with full typed message envelopes — no any, no string-typing.
How CallSphere uses it
CallSphere's public-facing chat widgets are built on AI SDK 5. The useChat hook in our Next.js 15 App Router pages connects to a Node Edge runtime endpoint that runs the agent loop. stopWhen keeps the loop bounded; prepareStep swaps to a cheaper model for the first triage step.
For our post-call summarization workflow (every voice call ends with a structured summary written to Salesforce / HubSpot), we use generateObject from AI SDK 5 with a Zod schema. The structured output is type-safe end-to-end — the same Zod schema validates on the server and types on the client.
For voice we don't use AI SDK directly — OpenAI Realtime + WebRTC is its own beast — but the non-voice surfaces of CallSphere all run on AI SDK 5.
Pricing: $149 Starter / $499 Growth / $1499 Scale. 14-day trial. 22% affiliate.
Build steps — your first AI SDK 5 agent
npm install ai @ai-sdk/openai zod.- Define tools with
tool({ description, parameters: z.object({...}), execute: async (...) => ... }). - Call
generateText(one-shot) orstreamText(streaming) with your tools. - Add
stopWhento bound the loop. - Add
prepareStepfor per-step control. - On the client, use
useChatto render the streaming response. - Wire OpenInference instrumentation for traces in Phoenix or LangSmith.
Code: typed structured output
import { generateObject } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
const CallSummary = z.object({
disposition: z.enum(["qualified", "not_interested", "callback", "voicemail"]),
next_action: z.string(),
mentioned_competitors: z.array(z.string()),
buying_signals: z.array(z.string()),
follow_up_at: z.coerce.date().nullable(),
});
const { object } = await generateObject({
model: openai("gpt-5"),
schema: CallSummary,
prompt: `Summarize: ${transcript}`,
});
await crm.upsertCall(object); // fully typed
Tool lifecycle hooks — the underused power feature
AI SDK 5 ships per-tool lifecycle hooks: onInputAvailable, onInputStart, onInputDelta. These let you stream UI updates as the model is building the tool call's arguments, before it actually calls the tool.
Practical use: when the model is mid-way through building a "schedule_meeting" tool call, your UI can show "scheduling..." with the partial arguments rendered as placeholders. The user sees progress instead of a blank pause. We use this in the chat widget for any tool that takes more than a couple of seconds.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
const schedule = tool({
parameters: scheduleSchema,
execute: scheduleMeeting,
onInputStart: ({ toolCallId }) => ui.show(toolCallId, "Building meeting..."),
onInputDelta: ({ toolCallId, inputTextDelta }) => ui.update(toolCallId, inputTextDelta),
onInputAvailable: ({ toolCallId, input }) => ui.previewMeeting(toolCallId, input),
});
Provider-executed tools — keeping the loop server-side
A new v5 capability: tools that run on the model provider's side (OpenAI's web search, code interpreter, file search) without round-tripping to your server. webSearch() from @ai-sdk/openai is the most popular — your agent gets web search results without you running a search backend.
For CallSphere this is mostly relevant in our research agents. We let OpenAI's web search hold the search loop while we focus on the synthesis prompt; saves us from operating Brave or SerpAPI integrations.
Streaming UI patterns — partialOutput and beyond
generateObject and streamObject support output: 'partial-object' mode: the schema validates as fields stream in, and your UI gets typed partial objects to render incrementally. Good for forms, tables, structured output that benefits from "showing up as it's generated."
const { partialObjectStream } = await streamObject({
model: openai("gpt-5"),
schema: CallSummary,
output: "partial-object",
prompt: `Summarize: ${transcript}`,
});
for await (const partial of partialObjectStream) {
ui.render(partial);
}
Speech and audio — the v5 sleeper feature
The new speech and audio APIs give you a single typed interface to OpenAI, ElevenLabs, and DeepGram for both TTS and STT. Switching providers is a config change, not a refactor. For non-realtime audio (voicemail transcription, post-call TTS summaries) this is the cleanest abstraction we've seen.
FAQ
AI SDK 5 vs OpenAI Agents SDK (TypeScript)? AI SDK 5 is more ergonomic for chat UI and structured outputs; OpenAI Agents SDK is more opinionated for multi-agent topology. We use both — Agents SDK for orchestration, AI SDK for UI hooks.
Does it support MCP? Yes — experimental_createMCPClient lets you mount MCP servers as tool sources.
What models work? Anything in the AI SDK provider ecosystem — OpenAI, Anthropic, Google, Mistral, Bedrock, Azure, Ollama, OpenRouter, and dozens more.
Is v6 out yet? Vercel announced AI SDK 6 development in 2026; v5 is the production stable line as of May 2026.
Where do I see this on CallSphere? Book a demo and we'll walk through the chat widget code.
Sources
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.