Skip to main content

PatterTool

PatterTool exposes a live Patter instance as a single make_phone_call tool that any text-based agent framework can register and dispatch. The agent picks up the phone, Patter runs a short conversation against the caller, and the tool returns a JSON envelope with the call ID, status, transcript, cost, and metrics. This complements the bring-your-own-agent pattern (serve(on_message=...)) with the inverse pattern — phone-as-tool — covering the two realistic migration paths from LiveKit / ElevenLabs ConvAI / Pipecat customers.
PatternWhere the brain livesWhere Patter sitsUse this when…
A — Bring-your-own agent (HTTP/WS endpoint)Customer’s existing servicePatter is STT + LLM proxy + TTSCustomer already runs a voice agent and wants to swap the voice transport but keep their conversation logic. Use serve(on_message='https://...').
B — Phone as a tool (this page)Customer’s text-based agentPatter is a tool the agent callsCustomer’s agent is text-driven but needs to make phone calls during a conversation.

Quickstart

import asyncio
from getpatter import Patter, Twilio, DeepgramSTT, AnthropicLLM, ElevenLabsTTS, PatterTool

phone = Patter(
    carrier=Twilio(),
    phone_number="+15550001234",
    webhook_url="api.example.com",          # stable hostname — not a tunnel
)

tool = PatterTool(
    phone=phone,
    agent={
        "stt": DeepgramSTT(),
        "llm": AnthropicLLM(),
        "tts": ElevenLabsTTS(voice_id="rachel"),
    },
)

async def main():
    await tool.start()                       # boots phone.serve() once (idempotent)

    result = await tool.execute({
        "to": "+15551234567",
        "goal": "Book a haircut for tomorrow at 3 pm.",
    })
    print(result)                            # PatterToolResult
    # → call_id, status, duration_seconds, cost_usd, transcript, metrics

asyncio.run(main())

Schema exporters

PatterTool ships three schema exporters with identical wire shape (parameter JSON-schema + result envelope), so a customer can switch frameworks without re-mapping fields.
tool.openai_schema()      # { "type": "function", "function": { "name", "description", "parameters" } }
tool.anthropic_schema()   # { "name", "description", "input_schema" }
tool.hermes_schema()      # { "name", "description", "parameters" }   # same shape as Anthropic input_schema
For Hermes Agent, there’s a one-line registry helper:
tool.register_hermes(registry, toolset="patter")

Tool arguments (JSON-schema)

Identical across all three exporters:
FieldTypeRequiredNotes
tostringE.164 phone number
goalstringBecomes the in-call agent’s system prompt
first_messagestringFirst thing the agent speaks on answer
max_duration_secintegerHard timeout, default 180, max 1800

Result envelope

@dataclass(frozen=True)
class PatterToolResult:
    call_id: str
    status: str                  # "completed" | "no-answer" | "busy" | "failed" | "timeout"
    duration_seconds: float
    cost_usd: float
    transcript: list[dict]       # [{"role": "agent" | "user", "text": "..."}]
    metrics: dict                # { p95_latency_ms, cost: { stt, tts, llm, telephony } }
When the model framework expects a JSON string (e.g. Hermes), use tool.hermes_handler() — it returns exactly that and wraps errors as {"error": "..."}.

Concurrency & timeouts

  • start() is idempotent — call it from your bootstrap, or let execute() boot it lazily.
  • Concurrent execute() calls are serialised through an asyncio.Lock so the per-call_id Future never races.
  • max_duration_sec is enforced by asyncio.wait_for; on timeout the tool hangs up the call and returns status="timeout".

Production deployment

PatterTool boots phone.serve() once. Make sure the Patter instance was constructed with a stable webhook hostname in webhook_url — never a tunnel — because Twilio/Telnyx need a long-lived HTTPS URL. For local development, use tunnel=True on the Patter constructor and let it spawn a cloudflared. For production deploys (Fly.io / Cloud Run / Fargate behind ALB), set webhook_url to your public hostname and disable the tunnel.

Examples

See examples/integrations/ in the repo:
  • hermes_phone_tool.py — drop-in tools/patter.py for Hermes Agent.
  • openai_assistant_phone_tool.ts — minimal OpenAI Assistants run dispatching the tool.
  • README.md — Pattern A vs Pattern B decision matrix.

What’s next

Tools

In-call tool calling (function calling within a Patter agent).

Agents

Configure the in-call agent that PatterTool wraps.