Agent tools
Letting an agent call your systems
A tool is a declaration: a name, a description the model reads to decide when to use it, a JSON Schema for the arguments, and a timeout the caller can hear.
The idea
Without tools, an agent can only say what is in its instructions. With tools, it can find things out. You declare what is available; the model decides whether a given sentence calls for one, extracts the arguments from what the caller said, and continues the conversation with the result.
The decision is made from the description you write. That is not a label for humans - it is the instruction the model reasons over. A tool described as "gets data" will be called at random. A tool described as "look up the fulfilment status of an order; use when the caller asks where their order is, whether it shipped, or when it will arrive" gets called when it should.
- Caller says something
- Model selectsfrom your descriptions
- Arguments extractedagainst your JSON Schema
- Your system answersinside the timeout
- Agent repliesin the same turn
The declaration
Tools live on the agent as a list. Each entry has four fields that matter and one that does not:
| Field | Rules | Notes |
|---|---|---|
name | 1–64 chars, A–Z a–z 0–9 _ - | Unique within the agent. Duplicates are rejected. |
description | Required | The selection criterion. Write it as an instruction, not a label. |
parameters | JSON Schema, type: "object" | properties object, required array of strings, additionalProperties boolean. |
responseTimeoutMs | Integer 1000–60000 | Optional. What the caller waits through if your system is slow. |
enabled | Boolean | Turn a tool off without deleting the declaration. |
{
"name": "appointment_check",
"description": "Check which appointment slots are free on a given date. Use when the caller asks for an appointment, asks whether a day is free, or proposes a time.",
"parameters": {
"type": "object",
"properties": {
"date": { "type": "string" }
},
"required": ["date"],
"additionalProperties": false
},
"responseTimeoutMs": 3000,
"enabled": true
}There is no target URL and no HTTP method in the agent's tool object. The declaration says what the tool is, not where it runs. Wiring a declared tool to your endpoint is set up together with the bitpull team, which is why every live-lookup integration on this site carries the Assisted setup status rather than Available. If you are planning a self-serve rollout, plan around that.
Writing a tool that gets called correctly
- One job per tool.
order_statusandproduct_availabilitybeat oneshop_lookupwith amodeparameter. The model chooses between tools far better than it fills in a discriminator. - Say when, not just what. The description is a decision rule. "Use when the caller asks…" is the most valuable phrase in it.
- Set
additionalProperties: false. It stops the model inventing fields your handler then has to ignore. - Require as little as possible. Every required field is something the agent must extract from speech before it can call anything. Phone audio makes that harder than it sounds.
- Return narrow results. Hand back the three fields the agent should say out loud, not the object your API returned. Everything you return is something the agent may read to an unverified caller.
// ✗ Called at random, because the description decides nothing.
{
"name": "crm",
"description": "CRM access",
"parameters": { "type": "object", "properties": { "q": { "type": "string" } } }
}
// ✓ Called when it should be, and only then.
{
"name": "create_crm_contact",
"description": "Store the caller as a new contact in the CRM. Use only after the caller has given a name and an email address and has agreed to be contacted.",
"parameters": {
"type": "object",
"properties": {
"email": { "type": "string" },
"name": { "type": "string" }
},
"required": ["email"],
"additionalProperties": false
},
"responseTimeoutMs": 2500,
"enabled": true
}Timeouts are audible
A tool call happens inside the caller's silence. The timeout can be set as high as sixty seconds, and it almost never should be - nobody waits sixty seconds on a phone call. Treat 1–2 seconds as the target and the timeout as the disaster limit, not the budget.
- Cache anything that changes slower than the conversation.
- Give your handler its own timeout, shorter than the tool's.
- Return a structured failure rather than hanging - the agent can say "I cannot reach that right now", but only if it gets an answer.
- Write the prompt so the agent speaks before it waits.
The voice page covers the rest of the latency budget your tool is spending against.
Safety, briefly
The arguments a tool receives were extracted from something a stranger said out loud. That is user input in the strictest sense.
- Validate server-side. The schema constrains the model, not an attacker who finds your endpoint.
- Read, do not write. Lookups are safe; state changes triggered by an unverified caller are not.
- Return the minimum. An order status, not an order object with an address in it.
- Log every call. Arguments and result. When someone asks what the agent told a customer, this is the answer.
Free developer tools
Different meaning of the word, same section of the site. Four browser tools we built while integrating agents, all free and none requiring an account:
Webhook tester
A throwaway inbox URL that shows headers and body exactly as they arrived. Point the agent webhook at it, press Test, read the truth.
02Widget generator
Assemble the embed snippet attribute by attribute, with a live preview of what the visitor sees.
03Voice latency test
Measure microphone, network and round-trip latency on this connection, against the budget a spoken turn actually has.
04Prompt reviewer
Static review of a voice agent prompt against the things that break real calls - structure, hours, hand-over, limits, AI disclosure.