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
Tools let your agent perform actions during a call — look up customer data, book appointments, process payments, and more. Tools are defined as webhooks that the SDK calls when the AI model invokes them.Defining Tools
Each tool requires aname, description, parameters (JSON Schema), and webhookUrl:
ToolDefinition Interface
Every tool must have either a
webhookUrl or a handler. Providing neither raises an error.Webhook Payload
When the AI model invokes a tool, the SDK sends a POST request to thewebhookUrl with the following JSON body:
attempt field is a 1-based retry counter (1 on the first try, up to 3).
Your webhook must return a JSON response. The response text is fed back to the AI model as the tool result.
Webhook Behavior
| Setting | Value |
|---|---|
| HTTP method | POST |
| Content type | application/json |
| Timeout | 10 seconds |
| Max response size | 1 MB |
| Retries | 3 attempts with exponential backoff |
LLM Loop Limits
When using the built-in LLM loop (pipeline mode without anonMessage handler), the following safety limits apply:
| Setting | Value |
|---|---|
| Max iterations | 10 (tool-call round-trips before the loop stops) |
| LLM request timeout | 30 seconds (AbortSignal.timeout) |
SSRF Protection
All webhook URLs are validated before requests are sent. The following are blocked:- Private IP ranges:
127.x.x.x,10.x.x.x,172.16-31.x.x,192.168.x.x - Link-local addresses:
169.254.x.x - Loopback:
localhost,::1 - Cloud metadata endpoints:
metadata.google.internal - Non-HTTP schemes (only
http:andhttps:are allowed)
System Tools
Two tools are automatically injected into every agent. You do not need to define them:transfer_call
Transfers the current call to another phone number. The AI model invokes this when the caller asks to speak to a human or be transferred.end_call
Ends the current call. The AI model invokes this when the conversation is complete or the caller says goodbye.In-Process Handlers
Instead of webhook URLs, you can pass a function that runs in-process:args— The arguments extracted by the AIcontext— Call metadata (callId,caller,callee)
Validation
Thephone.agent() method validates tools at creation time:
toolsmust be an array- Each tool must have a
namefield - Each tool must have either a
webhookUrlorhandlerfield
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 throw ToolSchemaError immediately, naming the offending tool.
The validator checks:
- The root must be
type: "object". propertiesmust be an object map of field name to JSON Schema.requiredmust be an array 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 per-call runtime overhead.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 function* 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 return value (or final yield { result: "..." }) becomes the function-call result the model sees.
Plain
async 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 a tool lets you set a single filler line the agent will speak if the tool hasn’t returned within a grace window (default 1500 ms). 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 function* handler with a first yield { progress: "..." }.Retries & circuit breaker
Both handler and webhook tool calls go through the same execution policy:-
Retries: up to 3 total attempts (default
maxRetries: 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.
DefaultToolExecutor 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 — throwing
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.

