Skip to content
4 min read · 707 words

Tools

A Tool is a validated callable capability the agent can offer to the model. It pairs a name and a description the model reads with an input schema that validates the model's arguments and a handler that produces the result. The shape exists because the two contracts that have to agree about a tool — what the model is told it accepts and what the handler is actually willing to run — were drawn from the same schema, so they cannot drift.

A single source of truth is not decorative

It is what stops the model from being told one contract while the handler enforces another. Every tool-call bug that starts with "the model passed something we didn't expect" is, somewhere underneath, two definitions of the same thing that were allowed to disagree. Tool does not let them disagree.

What a Tool is

A Tool is built out of three things the model sees (name, description, input schema) and one thing the model never sees (the handler). The handler may return string, Uint8Array, Media, or Media[] — the choice between the artifact-handle silo and the native-render silo is the most consequential decision in writing a tool.

→ Continue reading: What a Tool is

Where the handler normally runs: inside the executor, on the same iteration the model proposed the call

By convention, a tool's handler is invoked by the LLM executor during the same iteration that proposed it. When the model returns a tool call on iteration N, the executor should call tool.executor(ctx)(args), capture the result, persist the completed ToolCall record via ctx.storeToolCall(...), and only then return. Iteration N+1's model call can then see the result in ctx.turnToolCalls. That round trip — model proposes → executor invokes handler → executor persists → next iteration sees result — is what makes the dispatch loop useful.

Implication: pipeline middleware reacts to completed ToolCall records (counting, repetition detection, post-hoc safety, audit logging). It does not re-run handlers. Run a handler from turnOutputPipeline and the model never saw the result. Run it from dispatchOutputPipeline after the executor already did and you double-fire the side effect.

ToolRegistry

A ToolRegistry is a name-keyed collection of Tool instances. It owns one collision policy, one lifecycle hook, and the per-turn scoping that keeps middleware edits from leaking into the runner's baseline.

→ Continue reading: ToolRegistry

Collision policy

register and merge collide on names for different reasons and therefore take different defaults: register fails loud on clashes, merge consults the incoming tool's onCollision.

→ Continue reading: Collision policy

Per-turn lifecycle

The registry the runner hands a turn is built fresh from config.tools. Anything middleware does to it is scoped to that turn; the runner's baseline never mutates.

→ Continue reading: Per-turn lifecycle

bindContext and ephemeral pruning

ToolRegistry.bindContext wires an ack handler that prunes ephemeral: true tools when the dispatch completes successfully — the canonical case is the artifact-query tools forged by SpooledArtifact.forgeTools.

→ Continue reading: bindContext and ephemeral pruning

describe() and provider tool definitions

Tool.describe is the plain-object form the executor reads when it has to render the tool into provider wire shape: name, description, and the result of schema.describe() on the input schema.

→ Continue reading: describe() and provider tool definitions

Trust on the tool, not on the battery

trusted: true on a Tool flips the executor's render envelope for string / Uint8Array / artifact results. It does not propagate to Media results — Media.trustTier is the source of truth there.

→ Continue reading: Trust on the tool, not on the battery

Safety, authorisation, and human approval

The ADK cannot make your tools safe. What it gives you is the primitive every defence attaches to — gates — and the rule that gates belong inside the handler, not in middleware downstream.

→ Continue reading: Safety, authorisation, and human approval

Advanced details

You can write basic tools without this section. Read it before you debug checksum mismatches, artifactConstructor cycles, or the first time someone asks why Media does not go through the artifact wrap site.

→ Continue reading: Advanced details