supafone-labs 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. supafone_labs-0.3.0/.gitignore +30 -0
  2. supafone_labs-0.3.0/LICENSE +21 -0
  3. supafone_labs-0.3.0/PKG-INFO +470 -0
  4. supafone_labs-0.3.0/README.md +428 -0
  5. supafone_labs-0.3.0/pyproject.toml +51 -0
  6. supafone_labs-0.3.0/src/supafone_labs/__init__.py +105 -0
  7. supafone_labs-0.3.0/src/supafone_labs/_json.py +28 -0
  8. supafone_labs-0.3.0/src/supafone_labs/config.py +53 -0
  9. supafone_labs-0.3.0/src/supafone_labs/facade.py +489 -0
  10. supafone_labs-0.3.0/src/supafone_labs/llm/__init__.py +16 -0
  11. supafone_labs-0.3.0/src/supafone_labs/llm/base.py +87 -0
  12. supafone_labs-0.3.0/src/supafone_labs/llm/hosted_provider.py +67 -0
  13. supafone_labs-0.3.0/src/supafone_labs/llm/openai_provider.py +41 -0
  14. supafone_labs-0.3.0/src/supafone_labs/llm/registry.py +59 -0
  15. supafone_labs-0.3.0/src/supafone_labs/models.py +121 -0
  16. supafone_labs-0.3.0/src/supafone_labs/oracle/__init__.py +13 -0
  17. supafone_labs-0.3.0/src/supafone_labs/oracle/belief_state.py +73 -0
  18. supafone_labs-0.3.0/src/supafone_labs/oracle/directive.py +204 -0
  19. supafone_labs-0.3.0/src/supafone_labs/oracle/policy.py +35 -0
  20. supafone_labs-0.3.0/src/supafone_labs/oracle/session.py +73 -0
  21. supafone_labs-0.3.0/src/supafone_labs/postcall.py +68 -0
  22. supafone_labs-0.3.0/src/supafone_labs/runtime/__init__.py +36 -0
  23. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/__init__.py +31 -0
  24. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/base.py +89 -0
  25. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/bland.py +232 -0
  26. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/cartesia.py +102 -0
  27. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/deepgram.py +270 -0
  28. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/elevenlabs.py +236 -0
  29. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/generic.py +157 -0
  30. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/gpt_realtime.py +215 -0
  31. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/grok.py +199 -0
  32. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/inworld.py +119 -0
  33. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/livekit.py +182 -0
  34. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/pipecat.py +225 -0
  35. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/retell.py +197 -0
  36. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/ultravox.py +188 -0
  37. supafone_labs-0.3.0/src/supafone_labs/runtime/adapters/vapi.py +235 -0
  38. supafone_labs-0.3.0/src/supafone_labs/runtime/core/__init__.py +12 -0
  39. supafone_labs-0.3.0/src/supafone_labs/runtime/core/capabilities.py +15 -0
  40. supafone_labs-0.3.0/src/supafone_labs/runtime/core/decision.py +83 -0
  41. supafone_labs-0.3.0/src/supafone_labs/runtime/core/events.py +71 -0
  42. supafone_labs-0.3.0/src/supafone_labs/runtime/core/policies/__init__.py +1 -0
  43. supafone_labs-0.3.0/src/supafone_labs/runtime/core/policies/consent.py +27 -0
  44. supafone_labs-0.3.0/src/supafone_labs/runtime/core/policies/recovery.py +49 -0
  45. supafone_labs-0.3.0/src/supafone_labs/runtime/core/policies/scheduling.py +53 -0
  46. supafone_labs-0.3.0/src/supafone_labs/runtime/core/policies/truth.py +31 -0
  47. supafone_labs-0.3.0/src/supafone_labs/runtime/core/policies/watchdog.py +59 -0
  48. supafone_labs-0.3.0/src/supafone_labs/runtime/core/runtime.py +134 -0
  49. supafone_labs-0.3.0/src/supafone_labs/runtime/core/state.py +314 -0
  50. supafone_labs-0.3.0/src/supafone_labs/runtime/replay/__init__.py +5 -0
  51. supafone_labs-0.3.0/src/supafone_labs/runtime/replay/event_log.py +19 -0
  52. supafone_labs-0.3.0/src/supafone_labs/runtime/replay/inspector.py +18 -0
  53. supafone_labs-0.3.0/src/supafone_labs/runtime/replay/snapshot.py +14 -0
  54. supafone_labs-0.3.0/src/supafone_labs/runtime/workflows/__init__.py +4 -0
  55. supafone_labs-0.3.0/src/supafone_labs/runtime/workflows/generic_support.py +21 -0
  56. supafone_labs-0.3.0/src/supafone_labs/runtime/workflows/tool_contracts.py +14 -0
  57. supafone_labs-0.3.0/src/supafone_labs/stt/__init__.py +29 -0
  58. supafone_labs-0.3.0/src/supafone_labs/stt/deepgram_live.py +277 -0
  59. supafone_labs-0.3.0/src/supafone_labs/stt/language.py +188 -0
  60. supafone_labs-0.3.0/src/supafone_labs/telemetry.py +180 -0
  61. supafone_labs-0.3.0/src/supafone_labs/tiers.py +55 -0
  62. supafone_labs-0.3.0/src/supafone_labs/tts/__init__.py +32 -0
  63. supafone_labs-0.3.0/src/supafone_labs/tts/base.py +58 -0
  64. supafone_labs-0.3.0/src/supafone_labs/tts/cartesia_tts.py +60 -0
  65. supafone_labs-0.3.0/src/supafone_labs/tts/deepgram_tts.py +47 -0
  66. supafone_labs-0.3.0/src/supafone_labs/tts/elevenlabs_tts.py +45 -0
  67. supafone_labs-0.3.0/src/supafone_labs/tts/hosted_tts.py +49 -0
  68. supafone_labs-0.3.0/src/supafone_labs/tts/http_base.py +40 -0
  69. supafone_labs-0.3.0/src/supafone_labs/tts/inworld_tts.py +66 -0
  70. supafone_labs-0.3.0/src/supafone_labs/tts/registry.py +65 -0
  71. supafone_labs-0.3.0/src/supafone_labs/tts/supafone_labs_tts.py +75 -0
  72. supafone_labs-0.3.0/src/supafone_labs/types.py +213 -0
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ .env
11
+
12
+ # Tooling
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ .mypy_cache/
16
+ .coverage
17
+ htmlcov/
18
+
19
+ # Docs
20
+ site/
21
+
22
+ # OS / editor
23
+ .DS_Store
24
+ .idea/
25
+ .vscode/
26
+
27
+ # LaTeX build artifacts
28
+ paper/*.aux
29
+ paper/*.log
30
+ paper/*.out
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sam Savage
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,470 @@
1
+ Metadata-Version: 2.4
2
+ Name: supafone-labs
3
+ Version: 0.3.0
4
+ Summary: Give any voice agent a second mind — in one line.
5
+ Project-URL: Homepage, https://labs.supafone.ai
6
+ Project-URL: Documentation, https://labs.supafone.ai/docs.html
7
+ Project-URL: Repository, https://github.com/samthedataman/supafone-labs
8
+ Project-URL: Issues, https://github.com/samthedataman/supafone-labs/issues
9
+ Author-email: Sam Savage <samatcrispy@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agents,gpt-realtime,oracle,prompt-optimization,ultravox,vapi,voice-ai
13
+ Requires-Python: >=3.11
14
+ Requires-Dist: pydantic>=2.0.0
15
+ Provides-Extra: all
16
+ Requires-Dist: anthropic>=0.40.0; extra == 'all'
17
+ Requires-Dist: email-validator>=2.0.0; extra == 'all'
18
+ Requires-Dist: fastapi>=0.115.0; extra == 'all'
19
+ Requires-Dist: httpx>=0.27.0; extra == 'all'
20
+ Requires-Dist: openai>=1.0.0; extra == 'all'
21
+ Requires-Dist: stripe>=10.0.0; extra == 'all'
22
+ Requires-Dist: uvicorn>=0.30.0; extra == 'all'
23
+ Requires-Dist: websockets>=12.0; extra == 'all'
24
+ Provides-Extra: anthropic
25
+ Requires-Dist: anthropic>=0.40.0; extra == 'anthropic'
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
28
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
29
+ Requires-Dist: ruff>=0.3.0; extra == 'dev'
30
+ Provides-Extra: http
31
+ Requires-Dist: httpx>=0.27.0; extra == 'http'
32
+ Provides-Extra: openai
33
+ Requires-Dist: openai>=1.0.0; extra == 'openai'
34
+ Provides-Extra: server
35
+ Requires-Dist: email-validator>=2.0.0; extra == 'server'
36
+ Requires-Dist: fastapi>=0.115.0; extra == 'server'
37
+ Requires-Dist: stripe>=10.0.0; extra == 'server'
38
+ Requires-Dist: uvicorn>=0.30.0; extra == 'server'
39
+ Provides-Extra: stt
40
+ Requires-Dist: websockets>=12.0; extra == 'stt'
41
+ Description-Content-Type: text/markdown
42
+
43
+ <div align="center">
44
+
45
+ # Supafone Labs
46
+
47
+ **The voice-agent framework behind Supafone.** Create complete inbound and
48
+ outbound agents with managed numbers, voices, stages, tools, artifacts, and
49
+ Supafone Pro watcher built in — or attach the same second mind to any platform.
50
+
51
+ [![CI](https://github.com/samthedataman/supafone-labs/actions/workflows/ci.yml/badge.svg)](https://github.com/samthedataman/supafone-labs/actions/workflows/ci.yml)
52
+ [![PyPI](https://img.shields.io/pypi/v/supafone-labs)](https://pypi.org/project/supafone-labs/)
53
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue)](https://pypi.org/project/supafone-labs/)
54
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
55
+ [![API](https://img.shields.io/badge/cloud%20API-live-3fd0c9)](https://api.labs.supafone.ai/healthz)
56
+
57
+ [**Website**](https://labs.supafone.ai) ·
58
+ [**Docs**](https://labs.supafone.ai/docs.html) ·
59
+ [**Console**](https://labs.supafone.ai/console.html) ·
60
+ [**Get a free API key**](https://labs.supafone.ai/get-key.html) ·
61
+ [**API reference**](https://api.labs.supafone.ai/docs)
62
+
63
+ </div>
64
+
65
+ ---
66
+
67
+ ```python
68
+ import supafone_labs
69
+
70
+ brain = supafone_labs.supercharge(my_agent) # that's the whole integration
71
+ ```
72
+
73
+ ```ts
74
+ import { Supafone } from "@supafone/labs";
75
+
76
+ const supafone = new Supafone({ apiKey: process.env.SUPAFONE_API_KEY! });
77
+
78
+ const agent = await supafone.labs.agents.createInboundWithNumber({
79
+ agentKey: "northline-intake",
80
+ name: "Northline intake",
81
+ assistantName: "Maya",
82
+ websiteUrl: "https://northline.example",
83
+ number: { search: { areaCode: "415" } },
84
+ labs: { enabled: true, model: "gemma" },
85
+ });
86
+ ```
87
+
88
+ The TypeScript package is also the canonical client for the Supafone hosted
89
+ agent API at `https://api.supafone.ai/api/v1/labs`. The default path buys and
90
+ routes Supafone-managed numbers, so developers do not need to create Twilio,
91
+ Ultravox, Cartesia, Inworld, ElevenLabs, or Deepgram accounts just to ship an
92
+ agent. BYOK remains available when a team already owns those provider accounts.
93
+
94
+ ## Why this exists
95
+
96
+ **A voice agent is one mind on a stopwatch.** To sound human it must answer in
97
+ well under a second — which means the model that *talks* can never afford to
98
+ *think*. And everything that decides whether a call succeeds is thinking:
99
+ reading distress in a caller's voice, noticing they just switched to Spanish,
100
+ catching the agent about to promise something the API failed to do, remembering
101
+ that this firm never quotes fees on the phone. The latency budget forbids all
102
+ of it. That's not a prompt-engineering problem; it's an architecture problem.
103
+
104
+ **Humans solved this decades ago.** Every great call floor has a supervisor
105
+ with a headset — listening to the call, saying nothing to the customer, sliding
106
+ a note across the desk: *"she's scared, slow down"*, *"stop — don't quote the
107
+ fee"*, *"the booking didn't go through, don't say it did."* The agent keeps
108
+ talking; the note changes the call. Nobody expects the person speaking to also
109
+ be the person supervising. Yet that's exactly what we ask of every voice agent
110
+ shipped today.
111
+
112
+ **Supafone Labs is the supervisor.** A second, slower mind that runs *beside* the
113
+ call instead of inside its latency budget: it taps every turn, maintains a
114
+ live belief state — who's calling, what they want, how they feel, what language
115
+ they're speaking — and slides its note across the desk through your platform's
116
+ native silent channel. The caller never hears it. The agent reads it mid-call.
117
+
118
+ **Why silent injection, not a better prompt?** Because prompts are frozen at
119
+ call-start and calls are alive. The moment that matters — the caller starts
120
+ crying, the summary contradicts the tool result, the language flips — is by
121
+ definition the moment your prompt didn't anticipate.
122
+
123
+ **Why every platform?** Because teams switch voice stacks constantly, and the
124
+ coaching layer is exactly the part you can't afford to rewrite. One canonical
125
+ contract in, one whisper out, compiled to whatever you run this quarter.
126
+
127
+ **Why open source with a cloud?** Because a system that whispers into your
128
+ calls must be inspectable — every directive is in the audit log, and the whole
129
+ brain is MIT. The cloud exists for one reason: one key that runs the models,
130
+ the voices, and the transcription is more convenient than five vendor accounts.
131
+
132
+ **And when the second mind fails?** Nothing happens. It runs behind a timeout,
133
+ off the hot path; a stalled oracle yields no note and the call proceeds exactly
134
+ as it would have without us. Degrade-safety is tested, not promised.
135
+
136
+ ## Every platform, one whisper
137
+
138
+ <div align="center">
139
+ <table>
140
+ <tr>
141
+ <td align="center" width="110"><img src="https://www.google.com/s2/favicons?domain=vapi.ai&sz=128" width="36" alt="Vapi"><br><sub><b>Vapi</b></sub></td>
142
+ <td align="center" width="110"><img src="https://www.google.com/s2/favicons?domain=retellai.com&sz=128" width="36" alt="Retell"><br><sub><b>Retell AI</b></sub></td>
143
+ <td align="center" width="110"><img src="https://www.google.com/s2/favicons?domain=elevenlabs.io&sz=128" width="36" alt="ElevenLabs"><br><sub><b>ElevenLabs</b></sub></td>
144
+ <td align="center" width="110"><img src="https://www.google.com/s2/favicons?domain=ultravox.ai&sz=128" width="36" alt="Ultravox"><br><sub><b>Ultravox</b></sub></td>
145
+ <td align="center" width="110"><img src="https://www.google.com/s2/favicons?domain=openai.com&sz=128" width="36" alt="OpenAI"><br><sub><b>GPT-Realtime</b></sub></td>
146
+ <td align="center" width="110"><img src="https://www.google.com/s2/favicons?domain=x.ai&sz=128" width="36" alt="xAI"><br><sub><b>Grok Voice</b></sub></td>
147
+ <td align="center" width="110"><img src="https://www.google.com/s2/favicons?domain=deepgram.com&sz=128" width="36" alt="Deepgram"><br><sub><b>Deepgram</b></sub></td>
148
+ </tr>
149
+ <tr>
150
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=bland.ai&sz=128" width="36" alt="Bland"><br><sub><b>Bland</b></sub></td>
151
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=pipecat.ai&sz=128" width="36" alt="Pipecat"><br><sub><b>Pipecat</b></sub></td>
152
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=livekit.io&sz=128" width="36" alt="LiveKit"><br><sub><b>LiveKit</b></sub></td>
153
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=cartesia.ai&sz=128" width="36" alt="Cartesia"><br><sub><b>Cartesia</b></sub></td>
154
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=inworld.ai&sz=128" width="36" alt="Inworld"><br><sub><b>Inworld</b></sub></td>
155
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=anthropic.com&sz=128" width="36" alt="Anthropic"><br><sub><b>Claude</b></sub></td>
156
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=twilio.com&sz=128" width="36" alt="Twilio"><br><sub><b>Twilio</b></sub></td>
157
+ </tr>
158
+ <tr>
159
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=telnyx.com&sz=128" width="36" alt="Telnyx"><br><sub><b>Telnyx</b></sub></td>
160
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=signalwire.com&sz=128" width="36" alt="SignalWire"><br><sub><b>SignalWire</b></sub></td>
161
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=vonage.com&sz=128" width="36" alt="Vonage"><br><sub><b>Vonage</b></sub></td>
162
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=plivo.com&sz=128" width="36" alt="Plivo"><br><sub><b>Plivo</b></sub></td>
163
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=jambonz.org&sz=128" width="36" alt="Jambonz"><br><sub><b>Jambonz</b></sub></td>
164
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=freeswitch.com&sz=128" width="36" alt="FreeSWITCH"><br><sub><b>FreeSWITCH</b></sub></td>
165
+ <td align="center"><img src="https://www.google.com/s2/favicons?domain=asterisk.org&sz=128" width="36" alt="Asterisk"><br><sub><b>Asterisk</b></sub></td>
166
+ </tr>
167
+ </table>
168
+ </div>
169
+
170
+ ## Get started in 60 seconds
171
+
172
+ **1 — Get a key** (5 free minutes, no card):
173
+
174
+ ```bash
175
+ curl -X POST https://api.labs.supafone.ai/v1/signup \
176
+ -H "Content-Type: application/json" -d '{"email": "you@company.com"}'
177
+ # -> { "key": "sl_live_…", "free_minutes": 5.0 } (also emailed to you)
178
+
179
+ export SUPAFONE_LABS_API_KEY=sl_live_…
180
+ ```
181
+
182
+ **2 — Install and supercharge:**
183
+
184
+ ```bash
185
+ pip install supafone-labs[all]
186
+ ```
187
+
188
+ ```python
189
+ import supafone_labs
190
+
191
+ brain = supafone_labs.supercharge(my_agent, scenario="legal_intake")
192
+ result = await brain.observe(raw_event) # feed your platform's events
193
+ # result.actions -> the compiled native whisper (or [] if the oracle is quiet)
194
+ ```
195
+
196
+ With the key set, the oracle, TTS, and live multilingual STT all run on
197
+ Supafone Labs' hosted infrastructure. Without it, everything runs on **your own
198
+ vendor keys** — or fully offline on deterministic fakes. Same code, all three
199
+ modes.
200
+
201
+ **3 — Watch it work** in the [console](https://labs.supafone.ai/console.html):
202
+ your balance, usage, and an auditable log of every instruction your second
203
+ mind whispered.
204
+
205
+ ## Hosted Supafone agents
206
+
207
+ Use `@supafone/labs` when you want Supafone to host the whole agent:
208
+
209
+ ```ts
210
+ const inbound = await supafone.labs.agents.createInboundWithNumber({
211
+ agentKey: "northline-intake",
212
+ name: "Northline intake",
213
+ assistantName: "Maya",
214
+ websiteUrl: "https://northline.example",
215
+ number: { search: { areaCode: "415" } },
216
+ tools: { callRouting: true, scheduling: true, sms: true, voicemail: true },
217
+ labs: { enabled: true, model: "gemma" },
218
+ });
219
+
220
+ const outbound = await supafone.labs.agents.createOutboundWithNumber({
221
+ agentKey: "northline-sales",
222
+ name: "Northline sales team",
223
+ number: { search: { areaCode: "415" } },
224
+ labs: { enabled: true, model: "gemma" },
225
+ });
226
+ ```
227
+
228
+ What Supafone handles in the default path:
229
+
230
+ - Supafone-managed phone number search, purchase, assignment, and routing.
231
+ - Managed voice provider accounts for Cartesia, Inworld, ElevenLabs-compatible,
232
+ Ultravox, and Deepgram-backed paths.
233
+ - Multistage inbound and outbound presets instead of one flat prompt.
234
+ - Built-in tools for routing, scheduling, SMS, email, voicemail, knowledge,
235
+ escalation, transcripts, recordings, and summaries.
236
+ - Supafone Pro live watcher/call coach.
237
+
238
+ BYOK is advanced, not required:
239
+
240
+ ```ts
241
+ await supafone.labs.telephony.configure({
242
+ mode: "byok",
243
+ provider: "twilio",
244
+ credentials: {
245
+ accountSid: process.env.TWILIO_ACCOUNT_SID!,
246
+ authToken: process.env.TWILIO_AUTH_TOKEN!,
247
+ fromNumber: "+14155550123",
248
+ },
249
+ });
250
+ ```
251
+
252
+ ## How it works
253
+
254
+ ```
255
+ ┌─────────────────────────────────────────────┐
256
+ your live call ────▶│ TAP 13 platform adapters + │
257
+ (any platform) │ Deepgram nova-3 multilingual │
258
+ │ STT for audio-only stacks │
259
+ ├─────────────────────────────────────────────┤
260
+ │ THINK belief state + coaching oracle │
261
+ │ (off the latency path, timeout- │
262
+ │ bounded, degrade-safe) │
263
+ ├─────────────────────────────────────────────┤
264
+ silent whisper ◀────│ WHISPER compiled to the platform's │
265
+ (native channel) │ native control — never spoken │
266
+ └─────────────────────────────────────────────┘
267
+ ```
268
+
269
+ ## The Cloud API
270
+
271
+ One key fronts the whole stack — hosted oracle models, four TTS engines under
272
+ one voice namespace, and live multilingual transcription. Billed by the
273
+ minute; every request itemized.
274
+
275
+ | Endpoint | What it does |
276
+ |---|---|
277
+ | `POST /v1/signup` | Self-serve key — 5 free minutes, no card |
278
+ | `POST /v1/oracle/complete` | Hosted LLM completion (Claude / GPT / Grok, prefix-routed) |
279
+ | `GET /v1/models` | Live model catalog, fetched hourly from vendors — **never stale** |
280
+ | `POST /v1/tts` | Hosted TTS: Deepgram Aura, Cartesia, ElevenLabs, Inworld |
281
+ | `GET /v1/voices` | The hosted voice catalog |
282
+ | `POST /v1/stt` | Prerecorded transcription (nova-3, 10-language code-switching) |
283
+ | `WS /v1/stt/live` | Live streaming STT — the multilingual tap, zero Deepgram account |
284
+ | `GET /v1/usage` | Today's request counts |
285
+ | `GET /v1/billing/balance` | Minutes remaining + top-up links |
286
+ | `GET /v1/logs` | The audit trail: every whisper, timestamped and billed |
287
+
288
+ <details>
289
+ <summary><b>Python</b></summary>
290
+
291
+ ```python
292
+ import httpx
293
+
294
+ API, KEY = "https://api.labs.supafone.ai", os.environ["SUPAFONE_LABS_API_KEY"]
295
+
296
+ r = httpx.post(f"{API}/v1/oracle/complete",
297
+ headers={"Authorization": f"Bearer {KEY}"},
298
+ json={"model": "supafone-labs-oracle", "messages": [...]})
299
+ directive = r.json()["text"] # the silent coaching line
300
+
301
+ audio = httpx.post(f"{API}/v1/tts",
302
+ headers={"Authorization": f"Bearer {KEY}"},
303
+ json={"voice": "supafone-labs-calm-en", "text": "Right away."}).content
304
+ ```
305
+ </details>
306
+
307
+ <details>
308
+ <summary><b>TypeScript</b></summary>
309
+
310
+ ```ts
311
+ const API = "https://api.labs.supafone.ai";
312
+ const auth = { Authorization: `Bearer ${process.env.SUPAFONE_LABS_API_KEY}` };
313
+
314
+ const { text } = await fetch(`${API}/v1/oracle/complete`, {
315
+ method: "POST",
316
+ headers: { ...auth, "Content-Type": "application/json" },
317
+ body: JSON.stringify({ model: "supafone-labs-oracle", messages: [...] }),
318
+ }).then(r => r.json());
319
+
320
+ // live multilingual STT — language-tagged Results, 10 languages, code-switching
321
+ const ws = new WebSocket(`${API.replace("https","wss")}/v1/stt/live` +
322
+ `?api_key=${KEY}&language=multi&encoding=linear16&sample_rate=16000`);
323
+ ```
324
+ </details>
325
+
326
+ Full reference with every endpoint, WebSocket framing, and error shapes:
327
+ [**docs**](https://labs.supafone.ai/docs.html) · interactive
328
+ [OpenAPI](https://api.labs.supafone.ai/docs).
329
+
330
+ ## Pricing
331
+
332
+ | | |
333
+ |---|---|
334
+ | **Signup** | 5 free minutes, no card |
335
+ | **Pay as you go** | [$10 → 400 minutes](https://buy.stripe.com/7sY00d4Mz4yoaiF9003VC01) |
336
+ | **Subscription** | [$49/mo → 2,000 minutes](https://buy.stripe.com/14A28l6UH4yo3Uh4JK3VC00) |
337
+ | **Metering** | oracle call = 1s · TTS ≈ seconds of speech · live STT = session time |
338
+ | **Self-host** | free forever — the gateway (`cloud/`) is in this repo, MIT |
339
+
340
+ Every billed second is itemized in [`/v1/logs`](https://labs.supafone.ai/console.html).
341
+ BYO vendor keys always win when present — leaving the cloud is deleting one
342
+ environment variable.
343
+
344
+ ## Works with every voice platform
345
+
346
+ Speech-to-speech models, STT→LLM→TTS pipelines, frameworks, and raw speech
347
+ engines each get the injection channel they actually have:
348
+
349
+ | Platform | Kind | Whisper delivery |
350
+ |---|---|---|
351
+ | Ultravox | S2S agent | `inject_message` |
352
+ | OpenAI GPT-Realtime · xAI Grok | S2S agents | `session.update` prompt patch |
353
+ | Vapi | pipeline agent | `assistant_override` |
354
+ | Retell | custom-LLM WS | system message into your LLM turn |
355
+ | ElevenLabs Agents | pipeline agent | `contextual_update` |
356
+ | Deepgram Voice Agent | pipeline agent | `UpdatePrompt` |
357
+ | Pipecat · LiveKit Agents | frameworks | context frame / chat-context append |
358
+ | Bland · Cartesia · Inworld | tap-only | observed, honestly not injectable |
359
+ | Anything else | webhook | `GenericWebhookAdapter`, configurable |
360
+
361
+ Five providers are verified against **live APIs** in the repeatable test suite
362
+ (`pytest -m live`); the rest are built to current official docs with citations
363
+ — [docs/providers.md](docs/providers.md) marks which is which. Telephony is
364
+ transport-agnostic: Twilio, Telnyx, SignalWire, Vonage, Plivo, LiveKit SIP,
365
+ Jambonz, FreeSWITCH/Asterisk, and SIPREC forks all feed the same tap
366
+ ([SIP matrix](https://labs.supafone.ai/docs.html#sip)).
367
+
368
+ Runnable integrations for every permutation live in [`examples/`](examples/).
369
+
370
+ ## Live multilingual transcription
371
+
372
+ Callers switch languages mid-sentence; the tap keeps up. Deepgram nova-3
373
+ `language=multi` code-switches live across en/es/fr/de/hi/ru/pt/ja/it/nl,
374
+ every utterance arrives language-tagged, and the coaching comes back in the
375
+ caller's language — Spanish callers get Spanish guardrails, silently, mid-call.
376
+
377
+ ```python
378
+ from supafone_labs.stt import MultilingualCallTap, recommended_setup
379
+
380
+ recommended_setup("vapi") # -> use Vapi's transcripts, skip the tap
381
+ recommended_setup("ultravox", multilingual=True) # -> tap becomes the language authority
382
+
383
+ tap = MultilingualCallTap(brain, session_id=call_sid) # any SIP/audio fork
384
+ await tap.feed(track="inbound", payload_b64=frame)
385
+ ```
386
+
387
+ One rule prevents every bad combination: **exactly one transcript source per
388
+ call** — `recommended_setup()` picks it, so you never double-ingest or
389
+ double-pay. With `SUPAFONE_LABS_API_KEY` set and no Deepgram account, the tap
390
+ routes through the hosted proxy automatically.
391
+
392
+ ## Pick your model. Write your prompts.
393
+
394
+ ```python
395
+ brain = supafone_labs.SupafoneLabs(
396
+ provider="ultravox",
397
+ oracle_model="claude-sonnet-4-6", # provider auto-inferred (Anthropic/OpenAI/xAI/hosted)
398
+ oracle_instructions="Coach for a bilingual intake desk. Empathy before logistics.",
399
+ )
400
+
401
+ models = await supafone_labs.discover_oracle_models() # live vendor catalogs, cached hourly
402
+ ```
403
+
404
+ Model routing is prefix-based and the catalogs are fetched from vendor APIs at
405
+ runtime — **a model released tomorrow works today**, no package update. The
406
+ static table in `config.py` is an offline fallback only.
407
+
408
+ ## Built for production
409
+
410
+ - **Degrade-safe by construction** — the oracle runs behind a timeout off the
411
+ hot path; a stalled LLM, a dead STT socket, or a failed TTS backend can never
412
+ take down the call it's shadowing. The TTS chain fails downward
413
+ (hosted → your keys → offline audio); the tap no-ops without credentials.
414
+ - **Auditable** — every whispered instruction is in `/v1/logs` with a
415
+ timestamp and its exact cost. No black box.
416
+ - **Tested like infrastructure** — 200+ offline tests (every adapter's parse,
417
+ injection compile, and capability honesty; end-to-end facade runs per
418
+ provider; billing; tiering) plus live contract checks against Deepgram,
419
+ Ultravox, ElevenLabs, Cartesia, and Inworld.
420
+ - **No lock-in** — MIT package, MIT gateway. Self-host the whole cloud:
421
+ `cd cloud && uvicorn app:app`.
422
+
423
+ ## The research behind it
424
+
425
+ The architecture is an assembly of five peer-reviewed threads — dual-process
426
+ talker/reasoner agents (DeepMind's [Talker-Reasoner](https://arxiv.org/abs/2410.08328)),
427
+ the evidence that models [can't reliably self-correct](https://arxiv.org/abs/2310.01798)
428
+ (hence an *external* supervisor), generator/verifier splits
429
+ ([Cobbe 2021](https://arxiv.org/abs/2110.14168), [Lightman 2023](https://arxiv.org/abs/2305.20050),
430
+ [Baker 2025](https://arxiv.org/abs/2503.11926)), inference-time multi-model oversight
431
+ (Sakana AI's [AB-MCTS](https://arxiv.org/abs/2503.04412)), and feedback-driven prompt
432
+ optimization ([OPRO](https://arxiv.org/abs/2309.03409), [DSPy](https://arxiv.org/abs/2310.03714),
433
+ [TextGrad](https://arxiv.org/abs/2406.07496)). All 22 citations, verified and annotated:
434
+ [**the research page**](https://labs.supafone.ai/research.html), and the full synthesis —
435
+ meta-analysis plus the formal runtime treatment — is the
436
+ [**whitepaper (PDF)**](https://labs.supafone.ai/whitepaper.pdf)
437
+ ([LaTeX source](paper/whitepaper.tex)).
438
+
439
+ ## Repo layout
440
+
441
+ ```
442
+ src/supafone_labs/ the package — facade, oracle, runtime + 13 adapters, tts, stt, tiers
443
+ cloud/ Supafone Labs Cloud — the hosted gateway (FastAPI)
444
+ landing/ the website (landing, get-key, console, docs)
445
+ examples/ one runnable integration per platform + TypeScript client
446
+ tests/ 200+ offline tests · live contract checks (pytest -m live)
447
+ docs/ provider capability matrix + quickstart
448
+ ```
449
+
450
+ ## Development
451
+
452
+ ```bash
453
+ make install # editable install + dev tools
454
+ make test # offline suite (live tests skip without keys)
455
+ pytest -m live # live provider contract checks
456
+ make lint # ruff
457
+ cd cloud && uvicorn app:app --reload # run the gateway locally
458
+ ```
459
+
460
+ ## Security
461
+
462
+ Keys are bearer credentials — treat `sl_live_…` like a password. The gateway
463
+ stores no call audio; logs keep a 240-char excerpt per request (last 1,000 per
464
+ key) for your own auditability. Report vulnerabilities via
465
+ [SECURITY.md](SECURITY.md).
466
+
467
+ ## License
468
+
469
+ MIT © 2026 Sam Savage. Free tier is free forever; the cloud exists because one
470
+ key that runs everything is more convenient than five vendor accounts.