Agents
Tools on Agents
Attach tools to agents and control how the model may call them.
Tools let an agent call application-owned behavior. The model chooses the tool and arguments; your code owns validation, permissions, side effects, and returned data.
Add One Tool
import { AgentBuilder, createTool } from "@anvia/core";
import { z } from "zod";
const lookupOrder = createTool({
name: "lookup_order",
description: "Look up an order by order id.",
input: z.object({
orderId: z.string(),
}),
output: z.object({
status: z.string(),
}),
async execute({ orderId }) {
return orders.findById(orderId);
},
});
const agent = new AgentBuilder("support", model)
.instructions("Use tools when order status is needed.")
.tool(lookupOrder)
.defaultMaxTurns(3)
.build();Use clear tool names and descriptions. The model relies on them when deciding whether to call a tool.
Add Multiple Tools
const agent = new AgentBuilder("support", model)
.tools([lookupOrder, createReturnLabel, updateAddress])
.defaultMaxTurns(4)
.build();Keep tools narrow. A focused tool is easier to validate, approve, test, and observe.
Control Tool Choice
const agent = new AgentBuilder("support", model)
.tool(lookupOrder)
.toolChoice("auto")
.build();| Choice | Behavior |
|---|---|
"auto" | The model may call a tool |
"required" | The model should call a tool |
"none" | Tools are available on the agent but disabled for the model call |
{ type: "function", name: "lookup_order" } | Prefer one specific tool |
Provider support for strict tool-choice behavior can vary.
Tool Loop
When the model calls a tool, Anvia:
- validates tool arguments
- calls your tool handler
- appends a tool-result message
- calls the model again
- returns the final assistant answer
Set a low turn limit while building the workflow.
const response = await agent.prompt("Where is order A-100?").maxTurns(3).send();Require Approval
Use hook-based tool approval when a tool should not run until your app approves it.
import { createHook, requireApproval } from "@anvia/core";
const approvalHook = createHook({
onToolCall({ toolName }) {
if (toolName === "refund_order") {
return requireApproval({
reason: "Refunds require staff approval.",
rejectMessage: "Refund was not approved.",
});
}
},
});
const response = await agent
.prompt("Refund order A-100.")
.withHook(approvalHook)
.withToolApprovalHandler(async (approval) => {
const approved = await approvals.waitForDecision(approval);
return {
...approval,
status: approved ? "approved" : "rejected",
resolvedAt: new Date().toISOString(),
};
})
.send();For the full approval flow, read Human in the Loop.
