Creating Tools
Define typed tools that agents can call.
Tools expose application-owned behavior to an agent. The model chooses when to call the tool, but your code owns the implementation.
Tool APIs
Use createTool() to define one tool. Use ToolSet to group reusable static tools for sharing, direct calls, and tests. Use ToolRegistry only when an agent needs a mutable or shared runtime tool store.
Minimal Tool
import { createTool } from "@anvia/core";
import { z } from "zod";
export const lookupOrder = createTool({
name: "lookup_order",
description: "Look up an order by order id.",
input: z.object({
orderId: z.string().describe("The order id to inspect."),
}),
output: z.object({
orderId: z.string(),
status: z.string(),
}),
async execute({ orderId }) {
return {
orderId,
status: "shipped",
};
},
});input validates arguments from the model before your handler runs. output validates the value returned by your handler before Anvia sends it back to the model.
Add the Tool to an Agent
const agent = new AgentBuilder("support", model)
.instructions("Use tools when order status is needed.")
.tool(lookupOrder)
.defaultMaxTurns(3)
.build();The turn limit gives the agent room to call the tool and then ask the model for the final answer.
Naming
Use names that describe the action.
| Good | Avoid |
|---|---|
lookup_order | order |
create_refund | refund_tool |
search_docs | search |
Descriptions should explain when to use the tool, not how the tool is implemented.
Read-Only vs Side-Effect Tools
Read-only tools can usually run automatically.
const searchDocs = createTool({
name: "search_docs",
description: "Search public documentation.",
input: z.object({ query: z.string() }),
async execute({ query }) {
return docs.search(query);
},
});Side-effect tools should usually be paired with Human in the Loop approval.
const refundOrder = createTool({
name: "refund_order",
description: "Refund an eligible order.",
input: z.object({ orderId: z.string() }),
output: z.object({ refunded: z.boolean() }),
async execute({ orderId }) {
return refunds.create(orderId);
},
});Keep the tool implementation explicit. Do not rely on the model prompt as the permission boundary.
