Skip to content

Releases: PatterAI/Patter

v0.6.2 — GA Realtime adapter + 14-bug fix wave + dashboard hardening

25 May 10:22
5db6779

Choose a tag to compare

Bundled fix wave validated live via PSTN against the inbound and outbound OpenAI Realtime paths. New OpenAIRealtime2 engine + adapter (Python parity with TS) speaks the GA Realtime API (gpt-realtime-2), with bidirectional mulaw 8 kHz ↔ PCM 24 kHz transcoding for Twilio / Telnyx.

Highlights

  • New OpenAIRealtime2 engine + OpenAIRealtime2Adapter (Python parity with TS) — speaks the GA session.update shape (session.type = "realtime", nested audio.{input,output}, output_modalities), with bidirectional mulaw ↔ PCM 24 kHz transcoding.
  • Inbound caller/callee via TwiML <Parameter> — Twilio strips URL query params before the WS handshake, so caller/callee now travel as <Parameter> children of <Stream>. Inbound calls in the dashboard now show the correct numbers.
  • Whisper hallucination filter on the Realtime transcript_input event — drops "Thank you for watching.", "[music]", and 13 other YouTube-caption fallbacks that Whisper emits on silence/echo, eliminating phantom user turns.
  • Deferred response.create with new request_response() method — turn_detection.create_response: false + interrupt_response: false so Patter drives the assistant turn ONLY after the hallucination filter accepts the user transcript.
  • VAD threshold raised 0.1 → 0.5 on the GA Realtime path — kills the phantom barge-in loop where carrier-loopback echo of the agent's own audio tripped server VAD.

Persistence + dashboard

  • persist default flipped OFF → ON in both SDKs. Calls now survive process restarts by default (path: ~/Library/Application Support/patter on macOS / XDG dir on Linux / %LOCALAPPDATA% on Windows). Migration: pass persist=False for the old ephemeral-RAM-only behaviour.
  • PATTER_LOG_REDACT_PHONE default flipped maskfull so the dashboard UI reveal toggle works (you can't unmask numbers the SDK never knew). Migration: set PATTER_LOG_REDACT_PHONE=mask for setups that ship logs off-host.
  • direction now persisted in metadata.json — fixes outbound calls rendering as inbound (and top-bar showing the callee instead of the Patter number) after restart.
  • aggregates.sdk_version field — SPA top-bar version chip now auto-derives from getpatter.__version__ / package.json#version.
  • Python hydrate() now backfills transcript from sibling transcript.jsonl when metadata.json has no array (TS already did).
  • record_call_end preserves the live turns array + falls back to active/existing transcript when the SDK end-of-call snapshot is empty.
  • Standalone dashboard (patter dashboard) now sees outbound dials in real time via notify_dashboard relay of call_initiated.

Prewarm + adoption hardening

  • Liveness check rewritten to handle the current websockets library (state enum + close_code checks; legacy closed fallback). Pre-fix getattr(ws, "closed", True) defaulted to "dead" on the new client and silently aborted every adoption.
  • Application-level keepalive on the parked GA Realtime WS (session.update every 3 s + WS PING every 4 s) — OpenAI's GA edge closes idle sockets within ~6-7 s.
  • cancel_response is now a no-op when no item is in flight — eliminates response_cancel_not_active ERROR spam on every phantom VAD speech_started.
  • firstMessage no longer truncated by loopback echo VAD — barge-in gate consults _current_response_first_audio_at on the adapter.

TS surface additions

  • Top-level re-exports of OpenAIRealtimeModel, OpenAITranscriptionModel, OpenAIRealtimeAudioFormat, OpenAIVoice, ElevenLabsModel, ElevenLabsOutputFormat, DeepgramModel, CartesiaTTSModel, RimeModel, PricingUnit, PRICING_VERSION, etc. — import { OpenAIRealtimeModel } from "getpatter" now works.
  • engines/openai.ts Realtime.model default flipped gpt-4o-mini-realtime-previewgpt-realtime-mini for parity with Python.

Docs

31 Mintlify pages updated + 2 new pages (docs/python-sdk/providers/openai-realtime-2.mdx, docs/typescript-sdk/providers/openai-realtime-2.mdx).

Breaking changes

Both flips are opt-out with safe defaults; no API removals or renames.

  • persist=None → defaults to ON (persist=False to opt out).
  • PATTER_LOG_REDACT_PHONE → defaults to full (mask to opt back).

PR

#104 — release/0.6.2 → main (squash-merged)

0.6.1 — pipeline robustness + new providers + dashboard SPA

17 May 13:27
02d4d04

Choose a tag to compare

See PR #102 for the full changelog.

Highlights

  • New providers: OpenAIRealtime2 (TS, GA gpt-realtime-2), InworldTTS, SpeechmaticsSTT (TS parity)
  • Pipeline: one-shot barge-in fix, first-message pacing, EOU/metrics alignment
  • Dashboard: rewritten as Vite+React SPA, multi-select delete, dark-mode polish
  • ElevenLabs TTS default flipped to WebSocket (TTFB ~265 ms → ~80-100 ms)
  • Model-aware pricing across STT/TTS/Realtime
  • Observability: OTel spans on Python, no-op stubs on TS

Install

  • Python: pip install getpatter==0.6.1
  • TypeScript: npm install getpatter@0.6.1

Known limitations

  • OpenAIRealtime2 over Twilio: outbound audio works via Patter-side transcoding but GA server_vad is studio-tuned, so pipeline mode (STT+LLM+TTS) is the recommended production path for Twilio in 0.6.1 until OpenAI ships native g711_ulaw on GA.
  • Python parity for OpenAIRealtime2 is a follow-up — TS-only in 0.6.1.

0.6.0 — Refactor wave + Phase 3+4 SDK fixes + Mintlify docs parity

08 May 21:46
2d47d7d

Choose a tag to compare

Major SDK release validated by 9 rounds of agent-to-agent acceptance testing (Phase 3 R1–R4 + Phase 4 R1–R5). Six real SDK bugs found and fixed. PR: #83.

Highlights

Fixed

  • OpenAI Realtime barge-in correctness: cancel_response now caps audio_end_ms by wall-clock elapsed (was byte-counter), eliminating post-barge-in re-greeting and mid-sentence resume. Py + TS parity.
  • Pipeline mode on_transcript fires for assistant turns + tool calls: previously emitted only by Realtime mode. Adds LLMLoop.on_tool_call observer + _emit_assistant_transcript helper. Py + TS parity.
  • AssemblyAI STT (Python): coalesce 20 ms Twilio frames to 60 ms target (above v3 50 ms minimum). Closes parity with TS adapter; new flush_audio() drains tail.
  • getpatter.tts.elevenlabs.TTS facade now forwards language_code / voice_settings / chunk_size (the facade had a narrower signature than the underlying provider — multilingual scenarios crashed). Py + TS parity.
  • Cerebras + Groq LLM pricing — silent under-billing fix: gpt-oss-120b (Cerebras default since 0.5.4) and 5 Groq models all billed $0. Now per-1M-token rates for every enum value. Py + TS parity.
  • Pricing tables now model-aware across STT, TTS, and Realtime: was provider-only, so Deepgram nova-3 multilingual users were billed at nova-3 monolingual rate, gpt-realtime-2 users at gpt-realtime-mini rate (4× under-charge on audio out). New _resolve_provider_rates helper with longest-prefix fallback. Built-in rates for Deepgram, Whisper/Transcribe, ElevenLabs, OpenAI TTS, Cartesia, Rime, LMNT, Inworld, OpenAI Realtime. PRICING_VERSION 2026.2 → 2026.3. Py + TS parity.
  • OpenAI Realtime engine wrapper now forwards reasoning_effort and input_audio_transcription_model (were silently dropped by the high-level wrapper). Py + TS parity.

Changed

  • CircuitBreakerOptions.cooldown_scooldown_ms (Python aligned to TS cooldownMs). Backward-compat shim emits DeprecationWarning. Scheduled removal in v0.7.0.

Added

  • TypeScript manageWebhook opt-out for serve() — closes a hidden footgun for users running behind a router/gateway (Terraform / edge function) whose Twilio voice_url is managed externally. Default true preserves existing behaviour.
  • TypeScript SDK now ships SpeechmaticsSTT (closes long-standing Python-only gap). RT v2 WebSocket protocol direct via ws. 21-test mocked suite.
  • OpenAI Realtime gpt-realtime-2 and gpt-realtime-whisper model IDs with model-aware billing.
  • Python parity for ConversationStateSnapshot, UserState, AgentState, EouTrigger types (catches up to TypeScript).
  • MCP server integration — both SDKs expose mcp_servers config + dedicated docs page.
  • Inworld TTS provider (TTS-2 default, NDJSON streaming).

Repo restructure

  • sdk-py/libraries/python/
  • sdk-ts/libraries/typescript/
  • 33 new Mintlify provider reference pages (full Py↔TS parity across 22 providers)

Validation

  • 9-round agent-to-agent acceptance matrix (Phase 3 + Phase 4)
  • Python: 1707 tests pass, 7 skipped
  • TypeScript: 1381 tests pass (78 files)
  • All 13 CI blocking checks green on PR #83

Install

```sh
pip install --upgrade getpatter==0.6.0
npm install getpatter@0.6.0
```

Full changelog: CHANGELOG.md

0.5.4 — Cerebras default to gpt-oss-120b

27 Apr 18:58

Choose a tag to compare

Hotfix: restores gpt-oss-120b as the default Cerebras model.

Install

```bash
pip install getpatter==0.5.4
npm install getpatter@0.5.4
```

What changed

The 0.5.3 merge inadvertently kept llama3.1-8b as the Cerebras default — a regression of an earlier project decision. Bumping back to gpt-oss-120b for both Python and TypeScript SDKs.

Why gpt-oss-120b is the right default

  • Throughput on Cerebras WSE-3: ~3000 tok/sec, the highest in the catalog.
  • TTS-bottlenecked: voice agents consume LLM output at ~150-300 tok/sec via TTS. Both 8B and 120B models saturate the downstream pipeline, so model size doesn't add realtime latency.
  • No deprecation: while llama3.1-8b retires 2026-05-27 and the preview models (qwen-3-235b-a22b-instruct-2507, zai-glm-4.7) carry no SLA.
  • Quality: 120B parameters give materially better answer quality at no realtime cost.

Override

Other models remain reachable via model=:

```python
from getpatter import CerebrasLLM

agent = CerebrasLLM(model="llama3.1-8b") # smaller, free-tier
agent = CerebrasLLM(model="qwen-3-235b-a22b-instruct-2507") # preview
```

If your tier returns 404 for gpt-oss-120b, the provider's stream() logs a recovery hint listing override candidates.

Compatibility

  • Drop-in replacement for 0.5.3.
  • Python ≥ 3.11, Node ≥ 18.

Full changelog

See the v0.5.3 release notes for the full 0.5.x feature set; 0.5.4 is a single-line default-model change on top.

0.5.3 — latency pass + observability + parity

27 Apr 18:46

Choose a tag to compare

First polishing release of the public SDK. Cost-accuracy, audio-pipeline, and observability hardening across both SDKs, plus opt-in per-call filesystem logging, telephony optimizations, and provider tunings.

Install

```bash
pip install getpatter==0.5.3
npm install getpatter@0.5.3
```

Highlights

Latency

End-to-end P50 (user-stop → first TTS audio byte) reduced by ~1000-2000 ms:

  • STT: Python speech_final parity with TypeScript (Deepgram fast endpointing, ~300-700 ms saved per turn). Default smart_format=False for telephony. Whisper / OpenAITranscribeSTT always flush on close.
  • LLM: Anthropic prompt caching enabled by default (cache_control: ephemeral on system + last tool block). Cerebras hardening: retry + structured outputs + sampling kwargs forwarding. New before_llm / after_llm pipeline hooks for PII redaction, output validation, prompt rewriting.
  • TTS: Cartesia bumped to sonic-3 (~90 ms TTFB). OpenAI TTS chunk size 4096 → 1024. Sentence chunker emits short greetings immediately. New telephony factories (for_twilio() / for_telnyx()) on ElevenLabs, Cartesia, and ConvAI that negotiate carrier-native codecs (ulaw_8000 / 8 kHz PCM) and skip per-chunk SDK transcoding.
  • Realtime: OpenAI Realtime silence_duration_ms 500 → 300.
  • Telephony: Telnyx answer + streaming_start consolidated into a single API call (saves one webhook round-trip). TS Twilio outbound switched from Url: to inline Twiml: (parity with Python adapter, saves another round-trip). stream_track set to inbound_track (halves WS upstream bandwidth). Default ring_timeout lowered from 60 s to 25 s.
  • Infrastructure: notify_dashboard made async + fire-and-forget (avoids 1-3 s stall when dashboard is offline). TS call-log switched to fs.promises to keep ~75 ms of cumulative blocking off the Node main thread.

Providers

  • New first-class OpenAITranscribeSTT for gpt-4o-transcribe / gpt-4o-mini-transcribe.
  • Typed ElevenLabs model literal — eleven_v3 / eleven_flash_v2_5 / eleven_turbo_v2_5 / eleven_multilingual_v2 / eleven_monolingual_v1.
  • Cerebras: response_format (JSON mode + structured outputs), parallel_tool_calls, tool_choice, seed, top_p, frequency_penalty, presence_penalty, stop, User-Agent telemetry, max_completion_tokens, gzip compression on by default in TypeScript (parity with Python).
  • Same OpenAI-spec sampling kwargs lifted to the OpenAILLMProvider parent so every OpenAI-compat client benefits.

Observability

  • LatencyBreakdown extended with endpoint_ms, bargein_ms, tts_total_ms, properly split llm_ttft_ms / llm_total_ms.
  • New aggregate: latency_p90 alongside P50 / P95 / P99.
  • New OTel spans getpatter.endpoint and getpatter.bargein. The pre-existing getpatter.llm span is now actually emitted around the pipeline LLM call.
  • New EventBus event types: transcript_partial, transcript_final, llm_chunk, tts_chunk, tool_call_started.
  • TS span names normalised to getpatter.* everywhere.

Compatibility

  • Python ≥ 3.11.
  • Node ≥ 18.
  • No public-API breaks. Anything that was deprecated in 0.5.x continues to work; the new factories (for_twilio() / for_telnyx()) are opt-in.

Full changelog

See CHANGELOG.md and PR #76.

v0.5.2

23 Apr 13:13
81358ae

Choose a tag to compare

Fixed

  • ElevenLabs default voice: Rachel → Sarah — Rachel (21m00Tcm4TlvDq8ikWAM) is a library voice that free-tier ElevenLabs accounts cannot use via the API, so new ElevenLabsTTS() / ElevenLabsTTS() without an explicit voice_id used to fail on the first synthesis with 402 paid_plan_required. The default is now Sarah (EXAVITQu4vr4xnSDxMaL), a premade voice available to every account.
  • alloy alias now resolves to Sarah for the same reason.
  • rachel alias still resolves to her original ID — pass voice="rachel" explicitly to keep using her (requires a paid ElevenLabs plan).
  • Added sarah alias alongside the existing bella (same voice ID).

Changed (UX)

  • Startup banner now renders at the top of the terminal output (before tunnel / webhook setup logs), with a visually distinct Dashboard section using box-drawing separators.
  • Reduced per-frame log noise during calls: removed WS event:, Telnyx event:, Upgrade request:, WebSocket connected: lines. Only Call started / Call ended remain on the happy path.

Install

pip install --upgrade getpatter==0.5.2
npm install getpatter@0.5.2

Full changelog: v0.5.1...v0.5.2

v0.5.1 — First-class llm= selector + 5 LLM providers

22 Apr 19:59
85e6294

Choose a tag to compare

Patter 0.5.1 adds llm= as a first-class selector on phone.agent(), mirroring the stt= / tts= / engine= pattern shipped in 0.5.0. Five LLM provider classes with env-var fallback ship in both SDKs:

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

phone = Patter(carrier=Twilio(), phone_number="+15550001234")
agent = phone.agent(
    stt=DeepgramSTT(),                    # DEEPGRAM_API_KEY
    llm=AnthropicLLM(),                   # ANTHROPIC_API_KEY
    tts=ElevenLabsTTS(voice_id="rachel"), # ELEVENLABS_API_KEY
    system_prompt="You are helpful.",
)
await phone.serve(agent)

TypeScript mirror uses new AnthropicLLM().

What's new

  • OpenAILLM, AnthropicLLM, GroqLLM, CerebrasLLM, GoogleLLM — namespaced classes (getpatter.llm.{vendor}.LLM in Python, getpatter/llm/{vendor} in TS) plus flat aliases from the package root.
  • Env-var fallback per provider — OPENAI_API_KEY, ANTHROPIC_API_KEY, GROQ_API_KEY, CEREBRAS_API_KEY, GEMINI_API_KEY (falls back to GOOGLE_API_KEY).
  • Tool calling works across all 5 providers — each adapter normalizes vendor-specific tool formats to Patter's unified chunk protocol.
  • llm= and on_message are mutually exclusive — conflict raises a clear error at serve() time; engine + llm logs a one-time warning (engine owns the LLM).
  • Clean logging — two INFO lines per call (start + end):
    • Call started: CAxxx (Twilio, engine=openai_realtime, +15550001 → +15550002)
    • Call ended: CAxxx (42.3s, 8 turns, cost=\$0.0127, p95=612ms)
    • Everything else (STT transcripts, barge-in, hallucination filter, DTMF, per-turn guardrail triggers) demoted to debug.

Fixes

  • TypeScript bundler (critical)tsup was bundling cloudflared into the ESM dist, and since cloudflared is CJS and calls require("path") at runtime, serve({ tunnel: true }) crashed with Dynamic require of "path" is not supported. Fixed by externalizing cloudflared and @ngrok/ngrok in a new tsup.config.ts so they resolve from the consumer's node_modules/ at runtime.
  • CIanthropic / google-genai optional-extras tests now skip gracefully on the base Python matrix (they still run end-to-end in the python-all-extras job).
  • Parityprovider="pipeline" is now derived in the TypeScript client when the user passes only llm= without an engine, matching the Python client.

Install

pip install getpatter                      # 0.5.1
pip install "getpatter[anthropic]"         # + Anthropic adapter
pip install "getpatter[google]"            # + Google Gemini
pip install "getpatter[tunnel]"            # + cloudflared for dev tunnels

npm install getpatter                      # 0.5.1
npm install cloudflared                    # optional, only if using tunnel: true

Validation

  • Python: 1350 pytest passed, 8 skipped, 0 failures (1327 baseline + 23 new in tests/unit/test_llm_api.py)
  • TypeScript: 1042 vitest passed across 61 files, tsc --noEmit clean (1013 baseline + 29 new in tests/unit/llm-api.test.ts)
  • 4-line pipeline-mode quickstart with llm=AnthropicLLM() verified in both SDKs

Unchanged

  • Default OpenAI LLMLoop still auto-constructs when llm= is absent and openai_key is present — zero break from 0.5.0.
  • on_message callback still works for custom LLM logic (multi-model routing, local llama.cpp, etc.). Mutually exclusive with llm=.

Links

v0.5.0 — Instance-based API refactor

22 Apr 17:19
49d6c11

Choose a tag to compare

Patter 0.5.0 ships a clean, instance-based public API for both the Python and TypeScript SDKs. The Python module is renamed from patter to getpatter so the install name and import name now match across languages: pip install getpatter / from getpatter import ..., npm install getpatter / import { ... } from "getpatter".

The headline quickstart is four lines:

from getpatter import Patter, Twilio, OpenAIRealtime

phone = Patter(carrier=Twilio(), phone_number="+15550001234")
agent = phone.agent(engine=OpenAIRealtime(), system_prompt="You are a receptionist.")
await phone.serve(agent, tunnel=True)

TypeScript mirror:

import { Patter, Twilio, OpenAIRealtime } from "getpatter";

const phone = new Patter({ carrier: new Twilio(), phoneNumber: "+15550001234" });
const agent = phone.agent({ engine: new OpenAIRealtime(), systemPrompt: "You are a receptionist." });
await phone.serve({ agent, tunnel: true });

Set TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, OPENAI_API_KEY in your env and these four lines answer real phone calls.

What's new

  • Carrierspatter.carriers.{twilio,telnyx} with flat Twilio / Telnyx aliases; env fallback on TWILIO_ACCOUNT_SID / TELNYX_API_KEY etc.
  • Enginespatter.engines.{openai,elevenlabs} with flat OpenAIRealtime / ElevenLabsConvAI; env fallback on OPENAI_API_KEY / ELEVENLABS_API_KEY + ELEVENLABS_AGENT_ID.
  • STTDeepgramSTT, WhisperSTT, CartesiaSTT, SonioxSTT, SpeechmaticsSTT (Python-only), AssemblyAISTT. Each reads <VENDOR>_API_KEY when omitted.
  • TTSElevenLabsTTS, OpenAITTS, CartesiaTTS, RimeTTS, LMNTTTS. Same env-fallback pattern.
  • TunnelsCloudflareTunnel(), Static(hostname=...), Ngrok(hostname=...) instances; serve(tunnel=True) kept as the dev alias.
  • Tools + GuardrailsTool / Guardrail classes with tool() / guardrail() factories.
  • Twilio/Telnyx webhook auto-configserve() now sets the Twilio voice_url and associates Telnyx numbers automatically on both SDKs (TS reached parity with Python this release).
  • Docs rewrite — new Core Concepts page explains the five building blocks from scratch; Setting up Patter nav group with one page per component; engines.mdx + tracing.mdx (OpenTelemetry) added.

What's removed

  • Legacy Patter(twilio_sid=, twilio_token=, openai_key=, deepgram_key=, ...) kwargs.
  • Legacy string selectors (stt="deepgram", tts="elevenlabs", provider="openai_realtime").
  • Factory methods Patter.deepgram(), Patter.whisper(), Patter.elevenlabs(), Patter.openai_tts(), Patter.cartesia(), Patter.rime(), Patter.lmnt(), Patter.guardrail(), Patter.tool().
  • Dict-form tool / guardrail definitions (typed instances only).
  • MCP Server dev-tools page (out of scope for now).
  • ~294 lines of deprecation shim from sdk-py/patter/client.py; ~251 lines of shim + provider-resolver.ts from the TS client.

Install

# Python
pip install getpatter              # or pip install "getpatter[tunnel]" for built-in Cloudflare tunnel

# TypeScript
npm install getpatter
npm install cloudflared            # if you want phone.serve(tunnel: true)

Validation

  • Python: 1327 pytest passing, 8 skipped, 0 failures.
  • TypeScript: 1013 vitest passing across 60 files; tsc --noEmit clean.
  • Both 4-line quickstarts smoke-tested under -W error::DeprecationWarning (Python) and via tsx (TypeScript).

Line-count delta vs 0.4.4

247 files changed, 4,810 insertions, 9,766 deletions — net −4,956 lines.

Links

v0.4.4 — 23 bug fixes + SDK parity + live validation

21 Apr 20:10
e9fe209

Choose a tag to compare

Patter SDK 0.4.4

Bug-fix sweep + parity release. 23 distinct bugs discovered during the
acceptance suite are now fixed; Python ↔ TypeScript SDKs realigned; 5 new
live-call scenarios validated end-to-end against real Twilio and Telnyx
numbers.

pip install -U getpatter            # Python
npm install getpatter@0.4.4         # TypeScript

Highlights

  • Telephony stack is now fully reliable on both Twilio and Telnyx —
    fixes land across the webhook layer (Request forward-ref, deps),
    Telnyx Call Control (answer flow, WS shape, wire format, track
    filtering), and Twilio audio (sample-rate, pass-through sender).
  • Pipeline mode (STT + LLM + TTS) is barge-in-capable and filters
    STT hallucinations (you, ., thank you) so the caller never hears
    overlapping turns from a Whisper / Deepgram mis-commit.
  • Dashboard surfaces every outbound call attempt (including
    no-answer / busy / failed) via the new /webhooks/twilio/status
    endpoint and a status column in the UI.
  • Python ↔ TypeScript parity re-verified by the sdk-parity agent.

Fixes

Telephony

  • #08 Twilio webhooks returned 422 on every call — Request import
    lifted to module top.
  • #09 Pinned websockets>=14,<16 to avoid the additional_headers
    crash on 13.x.
  • #10 OpenAI Realtime → Twilio used the wrong sample rate. Realtime
    now runs on g711_ulaw and the audio sender is pass-through on mulaw.
  • #16 Telnyx Call Control rang forever — /webhooks/telnyx/voice now
    POSTs actions/answer + actions/streaming_start.
  • #17 Telnyx WebSocket media events were silently dropped because
    the bridge matched the wrong event names. Now matches
    data.event == "media" with media.payload base64 frames.
  • #18 Telnyx outbound audio was rejected for wire-format mismatch.
    The sender now emits {event:"media", media:{payload:b64}} and
    streaming_start negotiates g711_ulaw.
  • #19 Telnyx stream_track=both_tracks fed the agent's own TTS back
    into its STT. The bridge now filters media.track != "inbound" and
    only forwards the caller leg.

Pipeline

  • #12 Twilio pipeline double-transcoded audio → 0 transcripts. The
    pipeline STT now always runs on linear16@16k; mulaw decode lives in
    on_audio_received.
  • #13 Deepgram endpointing was hard-coded. endpointing_ms and
    utterance_end_ms are now tunable (defaults 150 ms / 1000 ms).
  • #15 PipelineHooks.before_send_to_stt was declared but never
    invoked — the pipeline now runs the hook and honours None/raise
    semantics (drop chunk / fail-open).
  • #20 Barge-in was broken: on_audio_received skipped STT during
    TTS. The pipeline now forwards caller audio to STT during TTS, and
    any transcript-with-text while _is_speaking=True clears the
    telephony buffer and stops the active sentence loop.
  • #22 Whisper on mulaw 8 kHz hallucinated short fillers and
    back-to-back finals triggered overlapping LLM+TTS turns. The STT
    loop now drops:
    • known hallucination fillers (you, ., thank you, yeah, …)
    • finals that duplicate the previous committed text inside 2 s
    • finals that land within 500 ms of the previous turn
  • #23 OpenAI TTS 24 kHz → 16 kHz streaming resample lost samples
    across chunks. Now uses audioop.ratecv with persistent state and a
    carry-byte buffer.

API / ergonomics

  • #01 Scheduler extra is documented (pip install getpatter[scheduling]).
  • #02 Python FallbackLLMProvider.complete_stream now matches the TS
    surface.
  • #03 Scheduler works across event loops (per-loop registry instead
    of a process-global singleton).
  • #04 Python ↔ TS parity gaps closed: auto-detect local mode,
    Patter.deepgram() / Patter.elevenlabs() / Patter.cartesia() /
    Patter.rime() / Patter.lmnt() factories on both sides.
  • #05 FallbackLLMProvider.aclose() + async context manager
    support — background probe timers are drained on shutdown.
  • #11 Patter.elevenlabs(voice="rachel") resolved to a 404 — the
    SDK now maps ~45 common ElevenLabs voice names to their UUIDs.
  • #14 Patter.agent() was silently dropping hooks,
    text_transforms, vad, audio_filter, background_audio,
    barge_in_threshold_ms. All forward to the Agent now.
  • #21 @tool-decorated functions crashed on invocation because the
    executor always called handler(args, ctx) but typed user functions
    take keyword args. The decorator now wraps the function in an async
    adapter that unpacks arguments as kwargs.

Dashboard

  • #06 The dashboard now registers the call as soon as Patter.call()
    fires (before any webhook), and tracks status transitions
    (initiated → ringing → in-progress → completed | no-answer | busy | failed | canceled) via the new /webhooks/twilio/status endpoint.
    UI adds a status column, filter pills, and SSE call_initiated /
    call_status events.

New

  • Patter.call(..., ring_timeout=60) kwarg — maps to Twilio Timeout
    and Telnyx timeout_secs.
  • Agent.barge_in_threshold_ms — disable barge-in (value 0) or tune
    the hang-over window.
  • vad_events on Patter.deepgram() / patter.providers.deepgram().
  • Top-level patter.mix_pcm helper (Python parity with TS).
  • Static TTS factories on the Python Patter class: cartesia,
    rime, lmnt (match TS).
  • GitHub Actions audit.yml workflow: pip-audit + npm audit +
    bandit with SARIF upload on schedule + PR diff.
  • README "Provider Notes" section documenting ElevenLabs free-tier
    voice restriction, Telnyx Outbound Profile requirement, Gemini free
    tier quota, and Whisper hallucination filtering.

Test coverage

Full offline suite now runs 749 Python unit tests + 932 TypeScript
tests
(soak included). Every bug listed above has a regression test:

File Bug Tests
sdk-py/tests/unit/test_pipeline_dedup.py #22 13
sdk-py/tests/unit/test_openai_tts_resample.py #23 7
sdk-py/tests/unit/test_twilio_status_and_ring_timeout.py #6 + ring_timeout 13
sdk-py/tests/unit/test_pipeline_bargein.py #20 7
sdk-py/tests/unit/test_before_send_to_stt_hook.py #15 9
sdk-py/tests/unit/test_telnyx_track_filter.py #19 5

Live-call validation on real Twilio + Telnyx numbers, all PASSED:

  • transfer_call auto-injected tool
  • serve(recording=True)
  • Telnyx DTMF (call.dtmf.received)
  • WebSocket drop mid-call + EmbeddedServer.stop() cleanup
  • Full Italian pipeline (Deepgram language="it" + ElevenLabs IT voice)

Breaking changes

None. Every change preserves the existing public API — only additions.

Upgrade notes

  • If you pinned websockets to 13.x in your own environment, bump to
    >=14,<16 to avoid the additional_headers crash.
  • Calls placed with machine_detection=True now require voicemail_message
    to drop a message (previously silently produced empty audio).
  • If you were using conftest monkey-patches to work around #7/#8/#10/
    #12/#13/#16/#17/#18 — they can be removed.

Provider caveats (read before production)

  • ElevenLabs free tier: cannot hit the library voice catalog via API
    (402 Payment Required). Set ELEVENLABS_VOICE_ID to a voice you
    own (cloned or generated) before phone.serve().
  • Telnyx outbound: connections must have an "Outbound Profile"
    attached in the portal or outbound calls return 403 D38.
  • Google Gemini free tier: gemini-2.0-flash has a hard quota=0.
    Enable billing before using Gemini as the LLM.
  • Whisper on mulaw 8 kHz: hallucinates short fillers. The pipeline
    drops them automatically — no action needed.

Full changelog: v0.4.3...v0.4.4
Acceptance suite: https://github.com/PatterAI/patter-sdk-acceptance

v0.4.3

18 Apr 15:24
c473fae

Choose a tag to compare

Patter v0.4.3 — self-contained install.

Packaging

  • pip install getpatter alone is now enough to run the SDK end-to-end. The runtime dependencies previously kept behind the [local] extra — fastapi, uvicorn[standard], twilio, audioop-lts (Python 3.13+), openai, and cryptography — are now part of the base dependencies in sdk-py/pyproject.toml.
  • The [local] extra is preserved as an empty alias, so existing guides, scripts, and templates that call pip install getpatter[local] continue to work unchanged.
  • The TypeScript package already shipped express and ws as runtime dependencies, so no structural change was needed on the npm side beyond the version bump.

Docs

  • Dropped the now-redundant [local] marker from the dashboard install snippet in docs/dev-tools/dashboard.mdx.

Install

pip install getpatter==0.4.3
npm install getpatter@0.4.3

Full changelog: v0.4.2...v0.4.3