ToolLoopAgent class purpose and features
ToolLoopAgent is the recommended class for building agents with the AI SDK. It handles three core components: LLMs that process input and decide actions, tools that extend capabilities beyond text generation, and a loop that orchestrates execution through context management and stopping conditions. The ToolLoopAgent automatically manages loops and message arrays, improves reusability by defining agents once for use throughout applications, and simplifies maintenance with a single place to update agent configuration.
ToolLoopAgent constructor parameters
ToolLoopAgent constructor takes a configuration object with: model (the language model to use), and tools (an object mapping tool names to tool definitions created with the tool() function).
Tool definition with tool() function
Tools are created using the tool() function and require: description (string describing what the tool does), inputSchema (a Zod schema defining the tool's input parameters), and execute (an async function that runs the tool with the validated inputs).
ToolLoopAgent.generate() method
The ToolLoopAgent.generate() method takes a configuration object with a prompt property (string containing the agent task). It returns a result object with two properties: text (the agent's final answer) and steps (the steps taken by the agent to accomplish the task).
Agent runtime and tool context management
Agents use runtimeContext as shared runtime state that flows through the agent loop and is available in prepareStep and lifecycle callbacks. It can be updated between steps. Use toolsContext for per-tool values such as API keys or scoped permissions; each tool receives only its own typed context based on its contextSchema.
HarnessAgent class for preconfigured harnesses
HarnessAgent is used when you want to run a preconfigured established harness, such as Claude Code, Codex, or Pi, instead of building the loop yourself around a language model. Harnesses are a separate abstraction from providers and models, but stream into AI SDK-compatible result and UI primitives.
Terminal UI for ToolLoopAgent development
The @ai-sdk/tui package provides a runAgentTUI() function to run a ToolLoopAgent in an interactive terminal UI. It is useful for local agent development, demos, and internal tools, providing prompt input, streamed responses, tool cards, reasoning sections, scrolling, and tool approval prompts without building a custom interface.
When to use core functions instead of ToolLoopAgent
Use core functions (generateText, streamText) instead of ToolLoopAgent when you need explicit control over each step for complex structured workflows. Use structured workflow patterns combining conditional statements, standard functions, error handling, and explicit control flow when you need reliable, repeatable outcomes with explicit control flow.
ToolLoopAgent weather agent example
```ts
import { ToolLoopAgent, tool } from 'ai';
__PROVIDER_IMPORT__;
import { z } from 'zod';
const weatherAgent = new ToolLoopAgent({
model: __MODEL__,
tools: {
weather: tool({
description: 'Get the weather in a location (in Fahrenheit)',
inputSchema: z.object({
location: z.string().describe('The location to get the weather for'),
}),
execute: async ({ location }) => ({
location,
temperature: 72 + Math.floor(Math.random() * 21) - 10,
}),
}),
convertFahrenheitToCelsius: tool({
description: 'Convert temperature from Fahrenheit to Celsius',
inputSchema: z.object({
temperature: z.number().describe('Temperature in Fahrenheit'),
}),
execute: async ({ temperature }) => {
const celsius = Math.round((temperature - 32) * (5 / 9));
return { celsius };
},
}),
},
});
const result = await weatherAgent.generate({
prompt: 'What is the weather in San Francisco in celsius?',
});
console.log(result.text); // agent's final answer
console.log(result.steps); // steps taken by the agent
```
This example shows how to create a ToolLoopAgent with multiple tools that the agent orchestrates to convert weather data from Fahrenheit to Celsius.
runAgentTUI terminal UI example
```ts
import { runAgentTUI } from '@ai-sdk/tui';
await runAgentTUI({
title: 'Weather Agent',
agent: weatherAgent,
});
```
This example shows how to run a ToolLoopAgent in an interactive terminal UI.
Call options definition and purpose
Call options allow you to pass type-safe structured inputs to agents to dynamically modify agent behavior based on runtime inputs. Use cases include adding dynamic context (injecting retrieved documents, user preferences, or session data), selecting models dynamically based on request complexity, configuring tools per request, and customizing provider options like reasoning effort or temperature.
Call options implementation steps
Define call options in three steps: (1) Define the schema specifying what inputs you accept using callOptionsSchema with Zod validation. (2) Configure with prepareCall function to use those inputs to modify agent settings. (3) Pass options at runtime by providing the options parameter when calling generate() or stream().
callOptionsSchema with Zod type safety
The callOptionsSchema property on ToolLoopAgent accepts a Zod schema that defines the structure of options. Once defined, the options parameter becomes required and type-checked when calling generate() or stream(). TypeScript will error if options are not provided or contain incorrect types.
prepareCall function signature and behavior
The prepareCall function receives an object with options and other settings via destructuring. It returns modified agent settings. When returning, spread the settings and return only the settings you want to change: return { ...settings, modifiedProperty: newValue }. The prepareCall function can be async, enabling fetching data before configuring the agent.
Dynamic model selection via call options
Use prepareCall to select different models based on options at runtime. Example: set model to 'openai/gpt-4o-mini' for simple complexity and 'openai/o1-mini' for complex complexity based on options.complexity enum value.
Dynamic tool configuration with call options
Configure tools dynamically in prepareCall by modifying the tools object. Example: pass userLocation with city and region to web search tools based on userCity and userRegion options.
Provider-specific options in prepareCall
Set provider-specific options via the providerOptions property in prepareCall. Example: configure OpenAI reasoningEffort dynamically by returning { ...settings, providerOptions: { openai: { reasoningEffort: options.taskDifficulty } } }.
Async prepareCall for RAG pattern
The prepareCall function can be async to fetch relevant documents before configuring the agent. Use vector search or similar retrieval methods to fetch context documents based on options, then inject them into the instructions property for retrieval-augmented generation.
Combining multiple modifications in prepareCall
prepareCall can modify multiple agent settings simultaneously: model selection, activeTools filtering, instructions content, and any other agent setting. Return a single object with all desired modifications to handle complex scenarios like role-based access and urgency levels.
Pass call options through createAgentUIStreamResponse
When using createAgentUIStreamResponse in API routes, pass call options via the options parameter: createAgentUIStreamResponse({ agent: myAgent, messages, options: { userId, accountType } }). The options are passed through to the agent's prepareCall function.
Basic call options example structure
Example ToolLoopAgent with call options for user context: callOptionsSchema defines userId (string) and accountType (enum: 'free', 'pro', 'enterprise'). In prepareCall, access options.accountType and options.userId to modify instructions. Call with generate({ prompt: '...', options: { userId: 'user_123', accountType: 'free' } }).