Skip to main content
Agents wrap AI SDK v7 ToolLoopAgent with FrogBot model resolution, request context, access, and hooks. Register code-defined AgentConfig objects in the root configuration.

Define one

Provide a URL-safe slug and instructions. Set model to a provider-prefixed model ID or router alias for a single choice, use the object form for selectable models, or omit it to use ai.defaultModel.

Agent options

Model options

Use model: { default, options } to offer model choices. Omit default to use ai.defaultModel; if neither is set, startup fails. The default is always included first, and duplicate IDs are removed. An empty options: [] offers only the default, as does a string model. A provider’s models list controls what the app can use; an agent’s model.options controls what users can pick for that agent. options: '*' includes every configured chat-capable model:
  • For a built-in provider with a models list, only chat models from that list.
  • For a built-in provider without a models list, every chat model in that provider’s catalog.
  • For a custom provider, entries declared with mode: 'chat'.
  • For configured routers, aliases whose target is chat-capable.
It excludes unconfigured providers and non-chat models such as embeddings, image generation, and dedicated transcription models. Chat models that also accept audio input remain chat-capable. The wildcard does not guarantee that your provider account, region, or credentials can serve every model. For example, this agent offers every configured chat model, including the models from your Bedrock provider’s models list, without copying that list:
For a curated selector, replace '*' with ['bedrock/amazon.nova-lite-v1:0', 'bedrock/us.anthropic.claude-sonnet-4-6']. You do not need to repeat the default in that array. Put a models list on OpenRouter and Vercel AI Gateway provider entries to keep the picker focused. Without a list, '*' includes their entire chat catalogs, which can contain hundreds of models. FrogBot validates the default and every explicit option. Unknown models or IDs outside a provider’s models list fail startup with is not configured; configured non-chat models fail with is not chat-capable. frogbot dev and type generation warn for these model checks instead of throwing. ai.access.generate further filters the choices each user sees and may use, for example through the AI policy plugin. allowModels has been removed. Configs that still set it fail with a message naming the agent and showing the replacement. Migrate model: 'provider/id', allowModels: [...] to model: { default: 'provider/id', options: [...] }. The chat composer shows the active model name and its reasoning level, for example gpt-5 · High. Clicking it opens a reasoning slider for that model, and the trigger reads Select effort; clicking the model name inside switches to the list of allowed models, and the trigger reads Select model. A model without reasoning options opens straight on the list. The slider starts at Default, which leaves the level to the provider, and offers only the options that model supports. The selector is hidden when the agent allows one model and that model has no reasoning options. FrogBot saves the chosen model as a user preference and remembers one reasoning level per model. Switching models restores the level last used with the new model, or Default if it has none; levels never carry over from one model to another. A saved model or level that is no longer allowed or offered falls back to the agent’s default model or to Default. Opening an existing chat starts from the model and level of its latest sent message instead of the saved preference, as long as that model is still allowed.

Use the general preset

general() provides FrogBot’s default general-purpose instructions and the general slug. It sets model: { options: '*' }, offering every configured chat model with ai.defaultModel as the default, subject to ai.access.generate. Configure that default and its provider. The chat composer shows a model picker whenever more than one model is available.
Pass agent fields to override the preset. The general slug is fixed, but options such as tools, profile, and access can be replaced.
Override model to narrow the choices. general({ model: 'openai/gpt-4o-mini' }) offers only that model; an object form can provide a curated options array instead.

Add a profile

Use profile for client-facing agent identity. Each field is optional, but provided values must be non-empty strings.
avatar accepts a URL or app-relative path. It is a plain string rather than an admin component or media-document reference. The chat UI uses name for avatar alt text and renders initials when avatar is omitted. Without a profile, chat messages render as before.

Profile options

Accessible profiles appear in both GET /api/agents and the chat manifest. An agent rejected by its access rule exposes neither its slug nor its profile.

Add tools

Agents accept FrogBot Tool objects, not raw AI SDK tools. FrogBot converts them internally and supplies request, runtime, slug, and run ID context to every execution. To add integration actions, pass individual piece actions or a whole piece instance. To add current web results, use the web search pieces. To give an agent the tools of an MCP server, such as Sidekick’s browser, add an mcpServer().

Tool options

Client tools replace execute with outputSchema and client; see Build a client tool.

Tool context

Attach tools directly to the worker.
Inference runs through the embedded gateway. Each model step can request tools, FrogBot executes them with ToolCtx, and the loop continues until a stop condition matches. Set component to an import-map component reference when a tool needs purpose-built chat UI.
The component receives { part }, including the tool input, output, state, and error details. Tools without component use the generic tool render. frogbot dev updates the import map automatically; build-only workflows must run frogbot generate:importmap before the app build. Components resolve from the selected agent’s effective tools. When an agent tool shadows an inherited root slug, the agent’s component wins and FrogBot logs both definitions during initialization. Omitting component on the shadowing tool intentionally restores the generic render for that agent.

Add skills

Skills keep playbooks and reference material out of the prompt until the agent needs them. Each skill adds a short discovery line to the agent instructions and makes three tools available: list_skills, load_skill, and load_skill_resource.
instructions and resource content accept a string or a function receiving { req, frogbot }. Function content is evaluated only when the agent loads it. Unknown skill and resource names return the available names so the agent can correct its next call. Each resource takes these options: license and compatibility are top-level fields. metadata is a flat string map. The three generated tool slugs are reserved when an agent has skills. inheritTools: false disables root tool inheritance but does not disable that agent’s skill tools. Folder-based source skills are not supported yet. Declare skill content in configuration; a future generated skills map will package folder content without runtime filesystem access.

Share tools across agents

Add tools to the root configuration to attach them to every agent.
Toolkits can be spread into the same array, such as tools: [...todoTools]. If an agent declares a tool with the same slug, its tool replaces the root tool and FrogBot logs a warning during initialization. Set inheritTools: false when an agent should only use its own tools.
Piece actions and whole piece instances can be supplied directly in root and agent tool lists.

Track chat todos

FrogBot provides write_todos and read_todos as an optional toolkit. write_todos replaces the entire list, and read_todos returns the current chat’s list. Both render a task-list card with pending and completed counts by default.
Attach the toolkit to one agent instead when todos should not be shared across all agent configurations.
Each item has content and a status of pending, in_progress, or completed. Keep one item in_progress at a time. Todos are stored on the current chat, survive continuations, and are deleted with that chat. Chat persistence must be enabled and the tool must run within a persisted agent chat.

Ask the user a question

Add the optional question tool when an agent should pause for a decision instead of guessing. The reply stops at the question and continues in the same message once the user answers.
See Ask the user questions for the answer shape, the headless API, and client tools of your own.

Organize files

Use folders for organization, then import every config explicitly. FrogBot v0 does not scan a directory or load AGENT.md files.
Slugs must be unique and URL-safe. Run pnpm frogbot generate:types to augment GeneratedTypes with configured agent slugs, matching collection typing; each configured model must resolve to a provider enabled under ai.providers.

Invoke locally

Registered instances live at frogbot.agents[slug] and expose generate and stream.
Pass either a prompt or messages. Messages may be AI SDK UIMessage[] or ModelMessage[]; UI messages are converted before inference.
Local calls default to overrideAccess: true. To enforce the configured rule, pass a request and overrideAccess: false.
Local calls are stateless by default. Pass an existing chatId to generate to persist the new user message and assistant response against server-owned history.
Chat persistence accepts prompts or UIMessage[]; it does not accept ModelMessage[]. Local stream() calls remain stateless.

Run options

generate and stream accept these options:

Schedule runs

Add schedule triggers next to the agent that owns the recurring work. Each trigger requires a URL-safe slug, exactly one schedule form, and exactly one of prompt or handler.
every accepts positive whole durations in seconds, minutes, hours, or days when they divide evenly into the corresponding cron field. Use cron for other intervals. Cron expressions use UTC; timezone-specific schedules are not yet supported. A handler receives: FrogBot runs schedules and skips an occurrence while the same trigger already has an active or runnable scheduled job. User-defined jobs, workflows, queues, and automatic runners remain configured alongside FrogBot schedules. Each prompt trigger creates a fresh chat with user: null and persists its user and assistant messages. A handler may invoke the owning agent, another agent, or no agent. Every handler receives { frogbot, agent, req, job }, and req.context contains source, agentSlug, triggerSlug, and jobId. Removing an agent or trigger makes already-queued work for it complete without running.

Invoke over HTTP

Configuring at least one worker mounts two FrogBot endpoints at the root API path. They are served under the normal /api prefix. POST exactly one non-empty prompt or non-empty messages array. Add model to select one of the agent’s allowed models; FrogBot rejects other models with a 403 response. Add reasoning to select one of the options the manifest lists under reasoning for that model, or for the default model when model is omitted; an option the model does not offer returns 400. A request without model uses the agent’s default model. Each user message keeps the model and reasoning option it was sent with, and every turn it starts uses them. Authenticated calls create a chat when chatId is absent. Without an explicit event-stream accept header, the response is { text, usage, finishReason, chatId }.
Request an AI SDK UI stream with Accept: text/event-stream.
Stream responses return the chat ID in the X-FrogBot-Chat-Id header. Continue the conversation by sending that ID with only the next user message.
FrogBot loads stored history, rejects chats owned by another authenticated user, and rejects client-supplied assistant or system messages. Custom access rules can allow anonymous callers to create and continue chats, but those chats are not private to the anonymous caller who created them because there is no anonymous identity to verify. Applications handling sensitive conversations should require authentication. Malformed input returns 400, an unknown slug returns 404, and an aborted request returns a bodyless 499. See Chat persistence for collection customization and durability behavior.

Control access

access receives { req, agent }, where agent is the agent instance being checked, and may return a boolean or promise. Its default is Boolean(req.user).
HTTP POST calls always set overrideAccess: false. The GET endpoint evaluates each worker’s rule and omits denied entries or entries whose rule throws. Custom rules may allow anonymous requests by returning true. Local calls bypass the rule unless you explicitly set overrideAccess: false with a request.

Follow hooks

Worker runs use the five hooks configured under ai.hooks. Every hook receives agent: { slug, runId, chatId? }, plus req and user when available. beforeOperation and afterOperation run once for the whole generate or stream call. Agent HTTP calls use that same lifecycle rather than adding another one. beforeUpstream, afterUpstream, and afterError run around each model’s doGenerate or doStream call, so a tool loop can produce multiple upstream phase pairs. Access is checked before beforeOperation, so denied calls run no hooks. Stream completion, failure, and abort each finalize afterOperation at most once. Tool execution has no separate lifecycle hook in v0. Match ToolCtx.agent.runId with the hook argument’s agent.runId to correlate tool work. See AI hooks for phase arguments, mutation rules, and failure isolation.