toToolLoopAgent
Turns a WebAgent into an AI SDK ToolLoopAgent for one request: the model (whose key lives on the server), the page's live tools and the agent's instructions exist together only there.
Turns a WebAgent into an AI SDK ToolLoopAgent for one request: the model (whose key lives on the server), the page’s live tools and the agent’s instructions exist together only there. createChatHandler does this for every POST; reach for these functions to run a WebAgent inside your own AI SDK code, or to inspect the settings the handler builds.
Import
import {
toToolLoopAgent,
toToolLoopAgentSettings,
toToolSet,
} from "@webmcp-agents/chat/server";
import type {
ToToolLoopAgentOptions,
WebAgentSettings,
} from "@webmcp-agents/chat/server";
Example
Build the agent for the shopper with the tools a page sent, and run it once. The model is one step per request: a tool call comes back for the browser to run.
import {
resolveModel,
toToolLoopAgent,
} from "@webmcp-agents/chat/server";
import type { ToolDescriptor } from "@webmcp-agents/chat";
import { shopper } from "@/agents";
// What a page sent with its request: the tools it has right now.
const pageTools: ToolDescriptor[] = [
{
name: "get_cart",
description: "Read the cart: its lines and total.",
inputSchema: { type: "object", properties: {} },
},
];
const { model } = await resolveModel(
"anthropic/claude-opus-5-5",
process.env,
);
// An AI SDK ToolLoopAgent: the shopper's instructions, its tool
// subset, and one model step (the browser runs the tools).
const loop = toToolLoopAgent(shopper, {
model,
tools: pageTools,
path: "/cart",
});
const result = await loop.generate({ prompt: "What is in my cart?" });
console.log(result.text);
To tune the agent the handler builds instead (telemetry, prepareStep, middleware), pass prepareAgent to createChatHandler.
Options
toToolLoopAgent(agent, options) and toToolLoopAgentSettings(agent, options) take the agent (or undefined for the plain assistant) and a ToToolLoopAgentOptions.
| Name | Type | Default | Description |
|---|---|---|---|
agent |
WebAgent | undefined |
required | The agent from defineWebAgent, or undefined for the plain assistant: the base prompt, every page tool, no delegation note. |
model |
LanguageModel |
required | The resolved model: see resolveModel. |
tools |
readonly ToolDescriptor[] |
required | The page’s tools right now, as the request carried them. selectTools(agent, tools) is applied: the agent’s filter, plus its delegate tools. |
path |
string |
not set | The page’s same-origin path, for the “The user is on the page …” line. |
base |
string |
DEFAULT_SYSTEM_PROMPT |
The base system prompt: see buildSystemPrompt. |
extraInstructions |
string |
not set | Appended after the instructions, for example a tool-budget note (the handler passes one once the step budget is spent). |
maxOutputTokens |
number |
not set | Output token cap per step, passed through. |
providerOptions |
AI SDK providerOptions |
not set | Passed through: see providerOptionsFor. |
stopWhen |
AI SDK stopWhen |
stepCountIs(1) |
When the loop stops. One model step per request, because the browser runs the tools in between. |
toolSet |
ToolSet |
not set | Replaces the tool set entirely (the handler passes {} once the step budget is spent). |
Returns
toToolLoopAgentSettingsreturnsWebAgentSettings:{ id: agent?.id, model, instructions, tools, stopWhen, maxOutputTokens, providerOptions }.instructionsisbuildSystemPrompt(base, path, agent?.instructions, agent has sub-agents)plusextraInstructions;toolsistoToolSet(selectTools(agent, tools)).toToolLoopAgentreturnsnew ToolLoopAgent(settings).toToolSet(tools)returns the page’s tools as an AI SDK tool set withoutexecute(the browser runs them), with control characters stripped from descriptions and$schemaand$idremoved from schemas.
Notes
- In the normal flow nobody constructs the
ToolLoopAgentthemselves:defineWebAgentis the definition andcreateChatHandlerthe runtime. This is the seam between the two. - Because tools have no
execute, a call ends the step; the browser runs the tool and posts the result with the next request. ToolDescriptoris exported from@webmcp-agents/chat, not from/server.
See also
- Define an agent, the page that teaches agents
defineWebAgentcreateChatHandlerand itsprepareAgentoptionbuildSystemPrompt