Tools and function calling
Tools turn the agent from a talking head into a participant. Define a typed function, hand the schema to Saaya, and the agent will call it during a conversation, to look up an order, charge a card, schedule a follow-up, or route a ticket.
Defining a tool
await saaya.agents.update(agent.id, {
tools: [
{
name: "orders.fetch",
description: "Look up an order by id. Returns null if not found.",
input: {
type: "object",
required: ["orderId"],
properties: {
orderId: { type: "string", pattern: "^ord_[a-zA-Z0-9]+$" },
},
},
output: {
type: "object",
properties: {
id: { type: "string" },
status: { type: "string" },
total: { type: "number" },
daysOld: { type: "integer" },
},
},
endpoint: { url: "https://api.acme.com/orders/lookup", method: "POST" },
auth: { type: "bearer", secretRef: "ACME_API_KEY" },
timeoutMs: 4000,
},
],
});How the agent picks a tool
The model sees tool name + description + input schema. The description matters more than you think, write it like a teammate would, including when not to call it ("only call when the user has provided an order id"). Bad descriptions are the single biggest cause of runaway tool calls.
Errors and retries
Tools return one of three shapes: success, retryable error, terminal error. Saaya retries retryable errors up to three times with exponential backoff (250ms, 1s, 4s). Terminal errors surface back to the agent as a message, the model is told the tool failed and asked to recover gracefully.
Idempotency keys
Inspecting tool calls
Every tool invocation is recorded on the session, input, output, duration, retries, final status. Open the Session viewer or pull `session.toolCalls` programmatically to debug. Most "the agent did the wrong thing" tickets resolve here in a minute.