Documentation Index
Fetch the complete documentation index at: https://patter-06b046ce-feat-observability-otel-attrs-0-6-1.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Tools & Function Calling
Tools let your voice agent perform actions during a conversation — check a database, call an API, transfer a call, or anything else you can expose via a webhook or an in-process handler.Defining Tools
Each tool is a dictionary with the following fields:| Field | Type | Required | Description | |
|---|---|---|---|---|
name | str | Yes | Unique identifier for the tool. | |
description | str | Yes | Natural language description of what the tool does. The AI uses this to decide when to call it. | |
parameters | dict | Yes | JSON Schema defining the tool’s input parameters. | |
webhook_url | str | One of webhook_url or handler | URL that Patter POSTs to when the AI invokes this tool. | |
handler | Callable | One of webhook_url or handler | Async or sync callable `(arguments, context) -> str | dict`. Runs in-process instead of making an HTTP call. |
Every tool must have either a
webhook_url or a handler. Providing neither raises a ValueError.Webhook Request Format
When the AI decides to call a tool, Patter sends an HTTP POST to thewebhook_url with the following JSON body:
| Field | Type | Description |
|---|---|---|
tool | str | The name of the tool being invoked. |
arguments | dict | The arguments extracted by the AI, matching the JSON Schema. |
call_id | str | Unique identifier for the current call. |
caller | str | The caller’s phone number. |
callee | str | The callee’s phone number. |
attempt | int | Attempt number (1, 2, or 3). |
Webhook Response
Your webhook must return valid JSON. The response is passed back to the AI as the tool result:Response Requirements
| Constraint | Value |
|---|---|
| Content type | application/json |
| Max response size | 1 MB |
| Timeout | 10 seconds |
Retry Behavior
If your webhook fails (non-2xx status code or network error), Patter retries automatically. Same exponential-backoff policy applies to in-process handlers — see Retries & circuit breaker below.System Tools
Patter automatically injects two system tools into every agent. You do not need to define these — they are always available.transfer_call
Transfers the current call to another phone number. The AI decides when to trigger this based on the conversation context.| Parameter | Type | Description |
|---|---|---|
number | str | Phone number to transfer to (E.164 format). |
transfer_call with the appropriate number.
end_call
Ends the current call programmatically.| Parameter | Type | Description |
|---|---|---|
reason | str | Reason for ending the call (logged in the transcript). |
Using tool()
Thetool() static method provides a convenient way to create tool definitions:
In-Process Handlers
Instead of webhook URLs, you can pass a Python callable that runs in-process. This is useful for tools that query local databases, call internal APIs, or perform any logic without an external HTTP endpoint.arguments— A dict of the arguments extracted by the AIcontext— A dict with call metadata (call_id,caller,callee)
str or dict. Dict values are serialized to JSON before being passed to the AI.
Tool Design Tips
Write clear descriptions
Write clear descriptions
The AI uses the
description field to decide when to call a tool. Be specific:Use descriptive parameter names
Use descriptive parameter names
Parameter names and descriptions help the AI extract the right values from the conversation:
Keep responses concise
Keep responses concise
The AI processes the full JSON response. Large responses add latency. Return only what the AI needs to continue the conversation.
Schema validation at build time
Patter structurally validates every tool’sparameters schema the moment you call phone.agent(tools=[...]). Typos that previously failed silently mid-call (required: "name" instead of required: ["name"]) now raise ToolSchemaError immediately, naming the offending tool.
The validator checks:
- The root must be
type: "object". propertiesmust be a dict mapping field name to JSON Schema.requiredmust be a list of strings.- Every entry in
requiredmust exist inproperties.
Validation lives in
getpatter.tools.schema_validation and runs once per tool at agent build time. There is no runtime overhead per call.Streaming progress from long-running tools
Realtime mode only. When a tool takes more than a moment to run — a database query, a multi-step API workflow, a file generation — you can write the handler as anasync generator and yield {"progress": "..."} updates while it works. Each progress message is spoken inline by the agent so the caller hears live status instead of dead air.
The generator’s final {"result": "..."} yield becomes the function-call result the model sees.
Plain
async def handlers continue to work unchanged — streaming is purely opt-in by switching to a generator. Pipeline mode silently discards progress yields for now and uses only the final result; Realtime mode is fully supported.Reassurance during long tool calls
Realtime mode only. Even with progress streaming, some tools take a beat before they have anything useful to say. Thereassurance field on Tool lets you set a single filler line the agent will speak if the tool hasn’t returned within a grace window (default 1.5 s). If the tool returns earlier, the timer is cancelled and the line is never spoken.
Pipeline mode silently skips reassurance for now — there is no clean injection point mid-turn. If you need it for a Pipeline agent, prefer an async-generator handler with a first
{"progress": ...} yield.Retries & circuit breaker
Both handler and webhook tool calls go through the same execution policy:-
Retries: up to 3 total attempts (default
MAX_RETRIES = 2). -
Backoff: exponential —
500 ms × 2^attempt, jittered up to ~60 ms, capped at 5 s. -
Failure response: after the last attempt the executor returns a structured JSON error so the model can recover gracefully.
ToolExecutor keeps a per-tool circuit breaker so a flaky downstream doesn’t burn LLM tokens on calls that will keep failing.
State machine
| State | When | Behaviour |
|---|---|---|
CLOSED | Default. | Calls run normally; failures count toward the threshold. |
OPEN | After 5 consecutive failures (default). | Calls short-circuit immediately for 30 s. The model receives {"error": ..., "fallback": true, "circuit_state": "open", "retry_after_ms": ...}. |
HALF_OPEN | First call after the cooldown elapses. | One probe call is allowed. Success transitions to CLOSED; failure trips back to OPEN for another cooldown. |
OPEN the model can recover with a graceful response such as: “I couldn’t reach the booking system right now — can I take your number and call you back?”
Tunables
OpenAI strict mode (opt-in)
Setstrict=True on a tool to constrain the model to emit arguments that exactly match the declared schema — no missing required fields, no extra properties, no type coercion. Recommended for any tool whose handler can’t tolerate malformed arguments (DB writes, payments, transfers).
strict=True, Patter:
- Validates the schema satisfies OpenAI’s strict-mode requirements at agent build time — raising
ToolSchemaErrorwith the offending path on any violation. - Propagates
strict: truein the OpenAI Realtimesession.updatewire payload so the model honours it.
Strict-mode schema rules
| Rule | Why |
|---|---|
Root must be type: "object". | OpenAI function tools require object roots. |
Every nested object must set additionalProperties: False. | Prevents the model from inventing extra keys. |
Every property in properties must also be in required. | Strict mode has no concept of “optional” — use nullable types instead. |
Arrays’ items schema is recursively validated under the same rules. | Same guarantees inside lists. |
strict=False — existing tools keep working with no changes.

