Tools
Tools let an agent take action mid-call. Two ship built-in (hang up, transfer), and you can register your own that call your own HTTPS endpoints.
How tools work
Mid-call, the agent decides when to invoke a tool based on what the caller said and what your tool's description says it does. For a custom tool, Aethex makes a server-to-server HTTPS call to your endpoint and feeds the response back into the conversation:
The whole loop runs inside the call, with the caller waiting on the line. Keep your endpoint fast: sub-second response is ideal. The agent always gets an answer within 9 seconds, and that limit covers the DNS lookup, the connection and the whole response.
Built-in tools
Every agent gets these two automatically. They are enabled by configuration on the agent (end_call_enabled, transfer_phone_number), not by registering anything.
end_callBuilt-inHang up the call cleanly.
The agent says any closing line, waits a short grace window for goodbye TTS to finish, then disconnects. Cancellable by user barge-in during the grace window.
When to trigger: After the caller confirms they have what they need, after a clear goodbye on either side, or per your Guardrails (e.g. abusive caller).
transfer_to_numberBuilt-inTransfer the call to a human agent.
Dials the number configured on the agent (`transfer_phone_number`, or the `transfer_phone_numbers` fallback list in order) while the caller hears hold audio, briefs whoever answers privately with the agent's summary, then connects them to the caller. With `transfer_mode: conference` on a SIP call the agent stays on the line, silent, recording and transcribing both of them.
When to trigger: For account-specific requests the agent cannot handle (refunds, fraud claims, escalations), or when the caller explicitly asks for a human.
Custom tools
Register your own tool with one POST. The pipeline picks it up on the next call against that agent.
Fields
namestringrequiredIdentifier the LLM uses when it invokes the tool. Lowercase, alphanumeric + underscores. Must not collide with a built-in (
end_call,transfer_to_number,voicemail_detected); collisions are skipped at pipeline build.descriptionstringoptionalPlain-English description of what the tool does and when to use it. The LLM reads this when deciding whether to invoke. Be specific; vague descriptions cause the model to skip the tool.
parameters_schemaobject (JSON Schema)optionalJSON Schema for the arguments the LLM must produce. Standard properties / required shape. Aethex passes these through to the LLM as an OpenAI-style function definition.
endpoint_urlstring (HTTPS)requiredHTTPS endpoint Aethex calls when the LLM invokes the tool. For POST (default): receives a JSON body. For GET: receives LLM arguments as URL query parameters. Must be reachable from our outbound IP range. HTTP (no TLS) is rejected at create time.
http_methodstringoptionalHTTP method used to call your endpoint.
POST(default) sends LLM arguments and context IDs in a JSON body.GETsends LLM arguments as URL query parameters and context IDs asX-Aethex-Agent-Id/X-Aethex-Conversation-Id/X-Aethex-Call-Idrequest headers — no body is sent. Scalar values (string, number, boolean) are stringified directly; non-scalar values (objects, arrays) are JSON-encoded per parameter. Query arguments above 8 KiB total are refused with an error. Any query parameter already in theendpoint_urltakes precedence over a same-named LLM argument.headersobjectoptionalHeaders attached to every outbound request. Use this for bearer auth or routing headers. Stored on our side; redacted from logs.
tool_typestringoptionalCurrently always "function". Reserved for future tool types (data sources, MCP, etc.).
Register a tool
import os, requests
API_KEY = os.environ["AETHEX_API_KEY"]
BASE_URL = "https://api.aethexai.com/api/v1"
AGENT_ID = "ag_..."
resp = requests.post(
f"{BASE_URL}/agents/{AGENT_ID}/tools",
headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
json={
"name": "lookup_order",
"description": (
"Look up the status of a customer order by order ID. "
"Use when the caller asks about an order or shipment they have placed."
),
"parameters_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order ID, alphanumeric. Example: A1B2C3.",
},
},
"required": ["order_id"],
},
"endpoint_url": "https://orders.example.com/aethex/lookup",
"headers": {"Authorization": "Bearer your-shared-secret"},
},
)
resp.raise_for_status()
print(resp.json())Endpoint contract
When the LLM invokes a custom tool, Aethex dispatches to your endpoint_url using the tool's http_method (POST by default). You have 9 seconds to respond, counting the DNS lookup, the connection and the whole response.
POST request (default)
{
"arguments": {
"order_id": "A1B2C3"
},
"agent_id": "ag_...",
"conversation_id": "co_...",
"call_id": "ca_..."
}GET request
For http_method: GET, LLM arguments are appended to the URL as query parameters and the contextual IDs are forwarded as headers. No body is sent. Note: arguments land in your web server's access logs.
GET /aethex/lookup?order_id=A1B2C3&in_stock=true&tags=%5B%22prime%22%5D
Host: orders.example.com
X-Aethex-Agent-Id: ag_...
X-Aethex-Conversation-Id: co_...
X-Aethex-Call-Id: ca_...
(no body)Response
Return a JSON body with whatever the agent should know. Aethex feeds the entire response into the LLM as the tool result, so structure it so the LLM can read it (key/value pairs, plain English fields).
{
"status": "shipped",
"tracking_number": "1Z999AA10123456784",
"estimated_delivery": "Tomorrow, 3 PM"
}Errors
Any 4xx, 5xx, timeout, or network failure is captured as a tool error and surfaced to the LLM as a JSON object like {"error": "<reason>"}. The agent then handles it gracefully (acknowledges the failure, offers to transfer). The call is never killed because your endpoint is down. If a tool fails, it still answers the agent, so the call never stalls waiting on it.
Limits and safety
Per tool invocation, covering the DNS lookup, the connection and the whole response. Not configurable. At that point Aethex stops waiting and closes the request. A GET is reported to the agent as unanswered. A POST may already have reached your endpoint, so the agent is told its outcome is unknown and not to repeat it: make POST handlers finish or roll back on their own if the connection closes. A caller interrupting the agent no longer cancels a POST.
A larger response is returned to the agent as an error, not cut short. Requests ask for an uncompressed response (Accept-Encoding: identity): a gzip or deflate response is still read, and stacked or any other encodings are refused.
Single dispatch per invocation: a request is never sent a second time once your endpoint may have received it, and redirects are not followed. The LLM can retry a failed GET on the next turn; a POST whose outcome is unknown is not to be repeated.
Next
Once your agent has tools, give it grounded knowledge: see Knowledge base for uploading reference documents the agent can pull from at call time.
