Bound the agent loop
Use ToolLoopAgent and give it a stopWhen it will hit.
AI SDK docsai-sdk.dev
This default is a safety measure to prevent runaway loops that could result in excessive API calls and costs.
From ai-sdk and the Building Agents docs.
A model that keeps searching
Press Run agent, then untick the box and run again.
No step limitBad
0 stepsIdle
Tokens 0Cost $0.00
stopWhen: isLoopFinished()BoundedGood
0 stepsIdle
Tokens 0Cost $0.00
stopWhen: [isStepCount(8), hasToolCall('done')]import { ToolLoopAgent, isStepCount, hasToolCall, tool } from 'ai';
import { z } from 'zod';
export const researchAgent = new ToolLoopAgent({
model: 'anthropic/claude-sonnet-5',
instructions: 'Research the question. Call done when you can answer.',
tools: {
search: tool({
description: 'Search the web',
inputSchema: z.object({ query: z.string() }),
execute: async ({ query }) => searchWeb(query),
}),
done: tool({
description: 'Call once you can answer',
inputSchema: z.object({ answer: z.string() }),
execute: async ({ answer }) => answer,
}),
},
stopWhen: [isStepCount(8), hasToolCall('done')],
});
const { text, steps } = await researchAgent.generate({ prompt });
Why it matters, pros and cons
Why it matters
Every step is a paid model call on a growing context. A loop with no cap costs whatever the model decides.
Pros
- Worst-case cost is known before the run.
hasToolCall('done')ends the run as soon as it can.- The agent owns the loop: no hand-rolled while.
Cons
- Too low a cap cuts off honest long tasks.
- Hitting the cap is not an answer; check the last step.
isLoopFinished()only when a person can stop it.