A motivating example: a dice game
Let’s build something concrete. Imagine a game where the agent rolls dice and asks for the player’s name. Two tools, two different styles.plainToolis the simplest factory.executereceives only the validated args — no context object. Use it for pure functions.tool<Deps>is the full-featured factory.executereceives aRunContext<Deps>as its first argument, then the args second. Thectxgives you access to injected dependencies, current token usage, the run ID, and more.- Tools are passed as a plain array. Vibes sends the full list to the model on every turn unless you use
prepareto conditionally exclude a tool (see below).
What the message trace looks like
Under the hood, each turn is a structured conversation. After the run above,result.messages would contain something like this:
execute functions.
tool() — with dependencies
Usetool<TDeps>() whenever your tool needs to call a database, an API client, or any other injected service. The TDeps type parameter tells TypeScript what shape ctx.deps will have.
agent.run("...", { deps: { db: myDb } }). This keeps your tools testable — pass a mock in tests, a real connection in production.
ctx also exposes:
ctx.usage— token counts accumulated so far in this runctx.runId— a unique ID for this run (useful for logging)ctx.toolName— the name of the currently executing toolctx.retryCount— how many times this result has been retriedctx.metadata— per-run metadata supplied by the callerctx.attachMetadata(toolCallId, meta)— attach structured metadata for a tool call that callers can inspect after the run
plainTool() — no context
plainTool() is a convenience wrapper for tools that are pure functions. The execute receives only the validated arguments — there is no RunContext parameter.
plainTool also supports maxRetries and argsValidator. It does not support prepare, requiresApproval, or sequential — those require access to the run context. Use tool() if you need those features.outputTool() — terminal tools
Sometimes you want the model to fill in a structured result and stop.outputTool() creates a tool that ends the run. When the model calls it, the return value becomes the agent’s final output and no further turns occur.
- The output schema is defined inline in the tool’s
parameters. executetypically returnsargsdirectly — the model has already structured the data.outputMode: "tool"tells Vibes to treat the tool call as the output mechanism.
fromSchema() — raw JSON Schema
When you already have a JSON Schema — from an OpenAPI spec, a schema registry, or a third-party library — usefromSchema() to avoid rewriting it in Zod. There is no TypeScript inference for args, so you’ll need to cast.
Tool return types
A tool’sexecute function can return:
For image-returning tools, return a
BinaryContent object:
Conditional availability with prepare
Every tool is sent to the model on every turn by default. Theprepare function lets you change that. It is called once per turn before the tool list is sent. Return null or undefined to exclude the tool from that turn; return the tool definition (or a modified version of it) to include it.
preparereceives theRunContext, giving it access to deps and all run metadata.- Returning
nullhides the tool. The model won’t know it exists for this turn. - Returning
undefined(or the tool definition itself) includes it normally.
prepare to dynamically update the description or parameters based on runtime state:
Argument validation with argsValidator
Zod validates the shape and types of each argument. But sometimes you need cross-field validation — for example, ensuring astart date is before an end date. That’s what argsValidator is for.
- Throwing inside
argsValidatorrejects the call. The error message is sent back to the model without consuming a retry — it’s treated as a validation failure, not an execution failure.
Retries with maxRetries
Tool execution errors are surfaced back to the model by default. If you want Vibes to automatically retry before giving up, setmaxRetries:
maxRetries: 2means up to 3 total attempts (1 initial + 2 retries).- Any thrown error triggers a retry. After all attempts are exhausted, the final error is propagated.
maxRetries on a tool retries the execution. It is independent of result validation retries (configured on the agent via maxRetries).Full options reference
All options accepted bytool():
plainTool() supports name, description, parameters, execute, maxRetries, and argsValidator only.
outputTool() supports name, description, parameters, and execute only.
fromSchema() supports name, description, jsonSchema, execute, and maxRetries only.
Toolsets
Group, filter, and compose tools into reusable collections
Dependencies
Inject runtime context via RunContext deps