release: 0.5.1 — first-class llm= selector + 5 LLM providers#69
Merged
Conversation
Add ``llm=`` as a first-class selector on ``phone.agent()`` mirroring the
STT/TTS pattern. Five LLM provider classes ship with env-var fallback:
```python
from getpatter import Patter, Twilio, DeepgramSTT, AnthropicLLM, ElevenLabsTTS
phone = Patter(carrier=Twilio(), phone_number="+15550001234")
agent = phone.agent(
stt=DeepgramSTT(),
llm=AnthropicLLM(), # ANTHROPIC_API_KEY from env
tts=ElevenLabsTTS(voice_id="rachel"),
system_prompt="You are helpful.",
)
await phone.serve(agent)
```
TypeScript mirror identical (`new AnthropicLLM()`, etc.).
## What's new
- ``getpatter.llm.{openai,anthropic,groq,cerebras,google}.LLM`` namespaced
classes (Python and TypeScript).
- Flat re-exports: ``OpenAILLM``, ``AnthropicLLM``, ``GroqLLM``,
``CerebrasLLM``, ``GoogleLLM``.
- Env-var fallback on each: ``OPENAI_API_KEY``, ``ANTHROPIC_API_KEY``,
``GROQ_API_KEY``, ``CEREBRAS_API_KEY``, ``GEMINI_API_KEY`` →
``GOOGLE_API_KEY``.
- Tool-calling works across all five — each adapter normalizes
vendor-specific formats to Patter's unified chunk protocol.
- Docs: ``docs/python-sdk/llm.mdx`` + ``typescript-sdk/llm.mdx`` refreshed
with real provider catalog; ``concepts.mdx`` pipeline example now uses
``llm=AnthropicLLM()``; reference tables and agent pages updated.
## Semantics
- ``llm=`` + ``on_message`` are mutually exclusive — conflict raises at
``serve()`` time with a clear error.
- ``engine=`` + ``llm=`` → one-time warning logged, ``llm=`` ignored
(the engine handles the LLM internally).
- Default OpenAI LLMLoop still auto-constructs when ``llm=`` is absent
and ``openai_key`` is present — no break from 0.5.0.
## Test counts
- Python: 1327 → **1350 passed** (+23 new in ``tests/unit/test_llm_api.py``),
8 skipped, 0 failures.
- TypeScript: 1013 → **1042 passed** across 61 files (+29 new in
``tests/unit/llm-api.test.ts``); ``tsc --noEmit`` clean.
## Version
``0.5.0`` → ``0.5.1`` (feature add, backward-compatible — old
``on_message`` pipeline keeps working).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
The base Python CI matrix installs ``getpatter[local,dev]`` only — no ``anthropic`` or ``google-genai``. Five tests in ``test_llm_api.py`` instantiate ``AnthropicLLM()`` / ``GoogleLLM()`` which triggers the underlying provider's lazy vendor import and raises ``RuntimeError``. Add ``pytest.mark.skipif(importlib.util.find_spec(...) is None)`` guards so the base matrix skips Anthropic + Google instantiation cases and the ``python-all-extras`` job (which installs everything) keeps exercising them end-to-end. Local run with extras installed: 23/23 passed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`importlib.util.find_spec('google.genai')` raises ModuleNotFoundError
when the parent `google` namespace doesn't exist at all (instead of
returning None). The base CI matrix has no `google` installed, so
test collection blew up before any test ran. Wrap in try/except.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0.5.1 shipped a broken ESM dist because tsup was bundling
``cloudflared`` into ``dist/index.mjs``. ``cloudflared`` is CJS and
calls ``require("path")`` at runtime — inside an ESM bundle that
resolves to "Dynamic require of 'path' is not supported" and the
tunnel startup crashes on every ``serve({ tunnel: true })``.
Fix: add ``sdk-ts/tsup.config.ts`` marking ``cloudflared`` and
``@ngrok/ngrok`` as external. Now the dist contains a literal
``await import("cloudflared")`` that resolves from the consumer's
``node_modules/`` at runtime, not a bundled copy.
Verified in ``dist/chunk-*.mjs`` (ESM) and ``dist/index.js`` (CJS):
``await import("cloudflared")`` appears as a plain reference; the
``tunnel-*.mjs`` chunk shrank from kilobytes to 142 bytes.
``cloudflared`` is already in ``optionalDependencies`` so users who
don't use ``tunnel: true`` aren't forced to install it; users who do
get it auto-installed by ``npm install getpatter``.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Before: INFO emitted on every WebSocket open, DTMF, STT final, duplicate
transcript drop, hallucination filter, barge-in, guardrail trigger, AI
adapter connect, pipeline-mode setup, LLM-loop active, Deepgram/Twilio
cost query, transfer, hangup — dozens of lines per call.
After: exactly **two INFO lines per call**. Everything else is
``logger.debug(...)`` (Python) / ``getLogger().debug(...)`` (TypeScript)
and invisible unless the user wires a debug-level logger.
### Call started
```
Call started: CAxxx... (Twilio, engine=openai_realtime, +15550001 → +15550002)
```
### Call ended
```
Call ended: CAxxx... (42.3s, 8 turns, cost=$0.0127, p95=612ms)
```
Cost and latency come from the already-finalized ``CallMetrics`` /
``CallMetricsAccumulator.endCall()`` — no extra computation.
Logger ``.debug`` is a no-op in the default logger implementation, so
existing integrations that replace ``getLogger()`` still receive every
event for debugging/analytics. ``on_call_start`` / ``on_call_end`` /
``on_metrics`` / ``on_transcript`` callbacks continue to fire — this
patch only touches the stdout/stderr noise.
### Files touched
- ``sdk-py/getpatter/handlers/{twilio_handler,telnyx_handler,stream_handler}.py``
- ``sdk-ts/src/stream-handler.ts``
### Validation
- Python: 1350 passed / 8 skipped (unchanged vs before)
- TypeScript: 1042 passed / 61 files (unchanged); ``tsc --noEmit`` clean
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Parity gap with sdk-py: when ``phone.agent({ llm: new AnthropicLLM() })``
is called without an ``engine`` (or without explicit ``provider``), the
TypeScript client left ``agent.provider`` undefined so downstream metrics
labelled the call as ``openai_realtime``. Python normalises to
``"pipeline"`` in the same case.
Fix: mirror the Python ``else if (stt || tts || llm): provider='pipeline'``
branch in ``client.ts`` ``agent()``. Pure label-level fix — the LLMLoop
construction that actually picks the provider was already correct.
1042 vitest + tsc clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
llm=as a first-class selector onphone.agent(), mirroring thestt=/tts=pattern shipped in 0.5.0. Five LLM provider classes with env-var fallback ship in both SDKs:TypeScript mirror uses the same names with
new AnthropicLLM()etc.What's new
getpatter.llm.{openai,anthropic,groq,cerebras,google}.LLMnamespaced classes (Python + TS)OpenAILLM,AnthropicLLM,GroqLLM,CerebrasLLM,GoogleLLMOPENAI_API_KEY,ANTHROPIC_API_KEY,GROQ_API_KEY,CEREBRAS_API_KEY,GEMINI_API_KEY→GOOGLE_API_KEY)docs/{python,typescript}-sdk/llm.mdxfull rewrites,concepts.mdxpipeline example updated, reference tables + agent pages updated, CHANGELOG entry addedSemantics
llm=+on_messageare mutually exclusive — conflict raises a clear error atserve()timeengine=+llm=→ one-time log warning,llm=is ignored (the engine handles its own LLM)llm=is absent andopenai_keyis present → no break from 0.5.0Test plan
tests/unit/test_llm_api.py), 8 skipped, 0 failurestests/unit/llm-api.test.ts);tsc --noEmitcleanllm=AnthropicLLM()smoke tested under-W error::DeprecationWarning(Python) and viatsx(TypeScript)engine + llm→ agent builds, warning logged oncellm + on_message→ raises at serve/handler initVersion
0.5.0→0.5.1— patch bump because the feature is additive and backward-compatible. Existing code usingon_messagekeeps working.🤖 Generated with Claude Code