After this topic
You will have a Route Handler that is the Tool Calling lab: streamText, a Zod tool, a step cap, the same UI stream as chat. You will know what the model sees (the schema) and what it never sees (execute).
Route handler
Same stream as chat — the new part is the tools map and a step cap.
This is the same pattern as the Tool Calling lab. inputSchema uses Zod directly — the SDK validates arguments before execute runs. If the model invents a field, you never hit your function with garbage (or you fail closed — better than a wrong city in production).
stopWhen: stepCountIs(5) allows up to five model steps (tool rounds plus the final answer). Tune n to the task: weather-and-compare might need three; a research agent might need more, with a higher bill.
toUIMessageStreamResponse() is the same last line as streaming chat. Tool calls show up as parts on the assistant message. The client does not need a second API.
Files
- 01
tools is a map of functions the model may call
Each tool has a description (when to use it), inputSchema (arguments), and execute (your code). The model never sees execute — only the schema.
- 02
stopWhen caps the loop
stepCountIs(5) allows up to five model steps. Without a cap, a confused model can call tools forever and run up cost.
- 03
Same stream as Day 3 chat
toUIMessageStreamResponse() still feeds useChat. Tool calls appear as parts on the message, not as a separate API.
What runs on which machine
The model, in a datacenter, emits a tool name and JSON arguments. Your Route Handler, on Vercel, runs execute. The browser never runs the tool. That split is the same as the chat key: side effects belong on the server.
Weather in this snippet is fake data so the lesson does not need a third-party key. In a product, execute hits your API, your database, or a vendor. Same shape. Real consequences.
Trade-offs
Too few steps and the task stops mid-way (one city, no comparison). Too many and a stuck model burns tokens. Start small, log steps, raise n when you see real multi-call tasks.
Use generateText with tools when you are debugging — you get the full step list in one object. Use streamText for the chat UI.
When the same agent must run from a route, a cron, and a job, look at ToolLoopAgent in the official agents docs. For this lesson, one Route Handler is the right size.
- Cap the loop (stopWhen) — always
- Descriptions and schemas decide whether tools get called correctly (next day)
- Destructive execute belongs behind approval
Further reading
The official Building Agents guide covers ToolLoopAgent when you want a shared agent object across routes and jobs. The catalog Tool Calling lab is this route with a UI.
Related patterns
Docs
Official API reference for this chapter.
Common questions
- What is “The tool loop in a route”?
- Match the Tool Calling lab: streamText, Zod tool schemas, and stopWhen in one API route.
- What will I be able to do after this lesson?
- You will have a Route Handler that is the Tool Calling lab: streamText, a Zod tool, a step cap, the same UI stream as chat. You will know what the model sees (the schema) and what it never sees (execute).
- How long does this lesson take?
- About 16 minutes of reading. It is a free chapter in the AI SDK Patterns TypeScript course.
- When should I not use this?
- Too few steps and the task stops mid-way (one city, no comparison). Too many and a stuck model burns tokens. Start small, log steps, raise n when you see real multi-call tasks.
Written by Akash Panchal·Updated August 29, 2026