Skip to content

Tools

A tool is a function the model can call. To the model, every tool looks the same: a name, a description and a JSON Schema for its arguments. vRT runs it in one of two places.

Server toolsApp tools (client tools)
RunsIn the agent’s session, on the serverIn the user’s page, app or device
DeclaredIn defineAgent({ tools })By the client when it connects
Use forDatabases, APIs, anything with secretsThe UI, the document, the device itself
Cancelled byIts AbortSignalThe client’s epoch gate and AbortSignal

App tools are offered to the model only when the agent sets clientTools: 'accept'.

Every call gets exactly one result: either { ok: true, output } or a failure with a code:

CodeMeaning
INTERRUPTEDThe call’s turn was interrupted before or while it ran
REJECTEDDeclined, for example by the user or by a beforeToolCall hook
INVALIDThe arguments are not valid for the tool
TIMEOUTNo result arrived in time (clientToolTimeoutMs for app tools)
FAILEDThe tool threw, or the app does not host a tool of that name

A tool that returns nothing answers with output: null.

App tools run one at a time, in arrival order: a call starts only after the previous one has its result. Tools can rely on that ordering, for example when the model applies several edits in sequence.

Every tool receives a context with a signal that aborts when its turn is interrupted, plus callId, turnId and epoch. Check the signal after every await and right before committing:

run: async ({ blockId, text }, { signal, callId, turnId }) => {
const block = await loadBlock(blockId);
if (signal.aborted) return; // interrupted while loading: change nothing
return editor.apply({ blockId, text, operationId: callId, group: turnId });
}

Group effects by turnId to undo a whole turn, and use callId as an idempotency key.

Server tools declare a risk ('low', 'medium' or 'high'), and every call, server or app, passes through the beforeToolCall hook first. The hook can allow it, reject it, or rewrite its arguments, so a high-risk action can wait for a spoken or on-screen confirmation. See Build an agent.

The app can follow every call, server or app, through its lifecycle with tool.stream events, so it can render a preview while the model is still writing the arguments:

PhaseCarriesMeaning
startThe model began a call
arguments-deltadeltaThe next fragment of the arguments’ JSON text
arguments-completeargumentsThe arguments are complete; the call is issued
progressprogressA running server tool reported progress with context.emit()
settledok, codeThe call has its result
cancelledIts turn was interrupted
failedmessageThe model stopped before completing the arguments

Every call starts with start and ends with exactly one of settled, cancelled or failed, unless the session ends first. A model that does not stream arguments goes straight from start to arguments-complete, so show a waiting state there.

Streams are for display only. arguments-complete runs nothing: an app tool still runs only through its run, behind the epoch gate. When the user interrupts, the client cancels every open call of that turn at once, without waiting for the server. A server tool’s result output is not included in tool.stream; settled only says whether it succeeded. Application-provided progress is still application data.

Tool streams need the tool-stream-v1 capability, which the browser client and the TypeScript server both support. With a server that lacks it, the app receives the older tool.preview events instead, and it keeps receiving them alongside tool.stream for compatibility.

On final session close, clear application preview state from the public closed event; the client does not synthesize a terminal event for every open call. A lost connection may still resume the same session. Cancellation is cooperative: checking a signal does not undo a committed effect, and applications own durable idempotency and transaction policies.

tool-stream-v1 remains a draft capability. Supporting its lifecycle does not require a model to emit argument fragments.

parameters is plain JSON Schema, as the model sees it. Server tools can also pass any Standard Schema validator (Zod, Valibot, ArkType) as validate; invalid arguments become an INVALID result without running the tool. App tools validate inside run.