Metadata-Version: 2.4
Name: pipecat-thunderphone
Version: 0.1.0
Summary: ThunderPhone realtime voice agents as a Pipecat speech-to-speech LLM service
Author-email: ThunderPhone <support@thunderphone.com>
License-Expression: BSD-2-Clause
Project-URL: Homepage, https://thunderphone.com
Project-URL: Documentation, https://thunderphone.com/docs/guides/use-with-pipecat
Project-URL: Source, https://github.com/autophonix/pipecat-thunderphone
Project-URL: Issues, https://github.com/autophonix/pipecat-thunderphone/issues
Project-URL: Changelog, https://github.com/autophonix/pipecat-thunderphone/blob/main/CHANGELOG.md
Keywords: pipecat,voice-ai,realtime,speech-to-speech,thunderphone
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Communications :: Telephony
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pipecat-ai[openai]<2,>=1.8
Requires-Dist: websockets>=13
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
Requires-Dist: pipecat-ai[silero]<2,>=1.8; extra == "dev"
Dynamic: license-file

# pipecat-thunderphone

Run a [ThunderPhone](https://thunderphone.com) voice agent inside a
[Pipecat](https://github.com/pipecat-ai/pipecat) pipeline.

ThunderPhone is a speech-to-speech service in Pipecat terms: audio in, audio
out, with speech recognition, the language model, the voice, turn-taking,
47 languages and function calling handled on ThunderPhone's side. You bring the
transport (Daily, LiveKit, Twilio, a WebRTC page, a phone line) and Pipecat
does the plumbing. Billing is ThunderPhone's per-minute engine rate; there is
no subscription.

```bash
pip install pipecat-thunderphone
```

## Use a saved agent

The agent's prompt, voice, engine, languages, tools, greeting and silence
handling all come from ThunderPhone. The pipeline only moves audio.

```python
from pipecat_thunderphone import ThunderPhoneRealtimeLLMService

llm = ThunderPhoneRealtimeLLMService(agent_id=12)  # reads THUNDERPHONE_API_KEY

context = LLMContext()
aggregators = LLMContextAggregatorPair(context)
pipeline = Pipeline([
    transport.input(),
    aggregators.user(),
    llm,
    aggregators.assistant(),
    transport.output(),
])
```

The saved agent opens the call itself, so the service skips the first
`response.create` Pipecat would normally send. Pass `greet_on_connect=True`
to request an opening response anyway.

## Inline configuration

Instructions and tools come from the Pipecat context, exactly as with the
OpenAI Realtime service. `product` picks the engine and `voice` the voice.

```python
llm = ThunderPhoneRealtimeLLMService(
    api_key="sk_live_...",
    product="bolt",          # spark | bolt | storm
    voice="olivia",
    language="es",
)

async def get_weather(params: FunctionCallParams):
    await params.result_callback({"conditions": "sunny"})

llm.register_function("get_weather", get_weather)

context = LLMContext(
    messages=[{"role": "system", "content": "You are Acme Dental's receptionist."}],
    tools=ToolsSchema(standard_tools=[weather_schema]),
)
```

Inline sessions are client-steered: the agent speaks first because Pipecat
requests a response when the context arrives, and it stays quiet during
silence unless you append a message or request another response.

## What the service handles for you

- The ThunderPhone URL and query (`agent_id`, `product`, `language`,
  `from_number`, `to_number`) and 24 kHz PCM in both directions.
- Secret-key auth (`sk_live_...`); the constructor rejects anything else early.
- Saved-agent sessions: pipeline `instructions`, `tools` and `voice` are
  dropped from `session.update` so they cannot collide with the agent's own
  configuration (the server would reject them).
- ThunderPhone's `call.*` platform events, which Pipecat's parser does not
  know. `call.ended` pushes an `EndWorkerFrame` upstream so the pipeline
  finishes; set `end_task_on_call_ended=False` to handle it yourself. Every
  such event is also delivered to the `on_call_event` handler, and
  `call.ended` to `on_call_ended`.
- Non-fatal `error` events for rejected session fields are logged as
  warnings rather than ending the session.
- `service.call_id` holds the ThunderPhone call id once the session is live,
  for fetching the recording, transcript and grade afterwards via
  `GET /v1/calls/{call_id}`.

## Limits

- Turn detection is server-side and always on. `turn_detection=False`
  (Pipecat-driven turns) is not supported.
- Tools registered on the service run only for inline sessions. A saved agent
  executes its own tools on ThunderPhone.
- `live_transcripts=True` streams caller transcript fragments while the
  caller speaks; it is billed extra per ThunderPhone pricing.
- Video frames are ignored.

## Compatibility

Tested with Pipecat v1.8.1 (requires `pipecat-ai>=1.8`). Python 3.11+.

## About

Built and maintained by [ThunderPhone](https://thunderphone.com) (Autophonix,
Inc.), the company behind the service. Issues and pull requests are welcome in
this repository; ThunderPhone platform questions go to support@thunderphone.com.

## Source

https://github.com/autophonix/pipecat-thunderphone — issues and pull requests welcome.

## Development

```bash
pip install -e ".[dev]"
pytest
```

The tests run against a scripted stand-in for the ThunderPhone realtime
server; inside the ThunderPhone monorepo they also check that every event the
real server emits parses in Pipecat.
