Tools
Tools let the agent call your APIs. A tool is one HTTP request, described in YAML. The filename is the tool key: tools/check_stock.yml becomes check_stock.
Anything that needs branching, a second call, or a derived response is code, and it belongs in the backend the tool already calls — give the agent one endpoint that does the whole job.
Add each tool to agent.tools; creating its file alone does not enable it.
Declarative HTTP tools
Set your backend URL as a workspace secret:
vatio secrets set ACME_API https://api.acme.comCreate tools/check_stock.yml. This example expects the API to return {"data": [{"name": "Picker", "stock": 3}]}:
description: Check product stock.
when_to_use: The visitor asks whether a product is available.
parameters:
type: object
properties:
product: { type: string }
required: [product]
access: public
request:
method: GET
base_url: "$env.ACME_API"
path: /products
requires: [params.product]
query:
name: "$params.product"
respond:
data:
products: "$.data"
message:
when_empty: No products matched that name.
default: "Found {{count}} matching products."Merge this into your existing agent block:
agent:
instructions: Use check_stock to answer questions about product availability.
tools: [check_stock]The request supports GET, POST, PATCH, and DELETE. Supply method, base_url, and path; the base URL must include its scheme and host. headers and query are maps; body is a JSON map used for POST and PATCH.
Placeholders
Values in base_url, path, headers, query, and body support:
| Placeholder | Source |
|---|---|
$params.<name> | Tool arguments |
$env.<KEY> | Workspace secrets |
$auth.subject, $auth.token, $auth.claims.<key> | The tool's authenticated principal |
$contact.name, $contact.email, $contact.phone_number | Contact profile |
A single placeholder keeps its value's type. A placeholder within a string is interpolated. || selects the first non-empty alternative, such as "$params.name || $contact.name".
Required values
Missing values are omitted from the request. List any value the endpoint needs under request.requires, without the $ prefix, to fail before sending an incomplete request. A missing contact phone, email, or name produces missing_contact_phone, missing_contact_email, or missing_contact_name; other paths produce missing_requirement.
Response mapping
respond.data maps output keys to JSON paths: $ is the entire body, $.data is its data field. respond.message can be a literal string or the when_empty / default mapping shown above. {{count}} is the length of the first array in the mapped data. Without an array, when_empty applies when all mapped values are blank.
Omit respond.message to use the API's own message field. HTTP 2xx produces result: "ok"; non-2xx produces result: "error", so return the status that says what happened rather than encoding failures inside a 200.
Tool results
Every tool returns an object with result (ok or error) and a non-empty message. Additional fields, such as data and error_key, are allowed.
{ "result": "ok", "message": "This product is out of stock.", "data": { "stock": 0 } }{ "result": "error", "message": "Stock could not be checked.", "error_key": "backend_unavailable" }Use ok when the operation completed, including an empty result or negative answer. Use error when it could not complete. Invalid results become a platform error. Tool results are visible to the model; never return credentials.
Validate with vatio tools check, deploy with vatio push, and exercise the tool through vatio chat. There is no direct tool-invoke command.
Built-in tools
| Tool | Purpose |
|---|---|
knowledge_lookup | Search the knowledge bases listed in knowledge |
identify_contact | Save a name supplied by the visitor |
request_contact_info | Ask a WhatsApp visitor to share their phone number |
handoff | Hand the conversation to a person — see Human in the loop |
Enable built-in tools through agent.tools just like your own tools. The one exception is handoff, which has no switch of its own: declaring agent.handoff is what attaches it, so an agent can never be able to escalate with nowhere to escalate to. request_contact_info sends a sharing request; the number arrives only if the visitor shares it in a later message. End the turn and retry the dependent operation after that reply.
A tool that reads a signed-in visitor's own records needs access: private and an auth: block.
