# S2S Runtime Library

The `supafone-labs` package is Supafone's speech-to-speech (S2S) runtime
library. It gives an agent one canonical event and decision contract while the
speaking runtime changes underneath it. Use it to observe a live call, compile
one supervisor decision, and send the provider-native control when that runtime
supports a silent control channel.

This is an adapter library, not a replacement audio socket. Your provider still
owns the realtime media session. Supafone normalizes the events around that
session and keeps the supervision, state, QA, and provider-specific control
logic in one place.

## Install the library

### Python: local runtime adapters

```bash
pip install supafone-labs
```

The Python package includes the canonical runtime, provider adapters, supervisor
facade, replay tests, and offline BYOK mode.

### TypeScript: cloud and hosted-agent client

```bash
npm install supafone-labs
```

The TypeScript client exposes the same Supafone account contracts for hosted
agents, the cloud oracle, realtime transcription, QA, and operational APIs. Use
`whisper()` when your application owns the provider socket and needs a concise
silent directive to pass to that socket.

## One contract, multiple S2S runtimes

The Python runtime selects an adapter by provider id. Changing the provider
changes the adapter and compiled control; the event, directive, and state
contracts stay the same.

```python
from supafone_labs import Feed, SupafoneLabs

runtime = SupafoneLabs(
    provider="gpt_realtime",
    mode="return",
    feed=Feed(guardrails=["Never quote fees. Acknowledge injury first."]),
)

result = await runtime.observe(provider_event)
for action in result.actions:
    await send_to_your_live_socket(action.payload)
```

Switch the adapter without rewriting the agent loop:

```python
runtime = SupafoneLabs(provider="grok", mode="return", feed=feed)
# Other supported ids include: ultravox, inworld, elevenlabs, deepgram,
# vapi, retell, livekit, pipecat, gemini_live, bland, and cartesia.
```

Use `mode="apply"` with an agent that exposes a supported injector method, or
use `mode="return"` when your application owns delivery and will send the
compiled action itself. See [Provider Injection Examples](provider-injection-examples.md)
for provider-specific socket payloads.

## TypeScript cloud path

When the TypeScript application owns the realtime session, ask the cloud oracle
for the directive and pass the result to the provider's native control:

```ts
import { Supafone } from "supafone-labs";

const supafone = new Supafone({
  apiKey: process.env.SUPAFONE_LABS_API_KEY!,
});

const directive = await supafone.whisper(
  "Agent: How can I help?\nCaller: I was rear-ended — what do you charge?",
  { guardrails: "Never quote fees. Acknowledge injury first." },
);

if (directive) {
  // Map this one directive to your provider's native silent-control event.
  await sendToYourProvider({ text: directive });
}
```

An empty directive means the runtime found no safe correction to send. The
provider-specific mapping is documented in the [framework matrix](framework-support.md).

## Support classes

The library reports support honestly because S2S providers do not expose the
same control surface:

| Runtime group | Examples | What Supafone does |
| --- | --- | --- |
| Managed/native control | Supafone Agent Factory, Ultravox | Owns the managed delivery path and sends a deferred silent data message |
| Native S2S control | OpenAI Realtime, Grok Voice, ElevenLabs Agents, Inworld Realtime | Compiles the directive into the provider's documented live event |
| Developer-owned context | Retell custom LLM, LiveKit Agents, Pipecat | Adds the directive to the context your application owns |
| Observation only | Gemini Developer Live, Bland | Normalizes events and scores the call without inventing an unsupported hidden action |
| Explicit host hook | Cartesia Line | Emits a custom event for the host agent to handle |

Vapi and Deepgram Voice Agent support native controls and developer-owned LLM
paths. The complete acceptance criteria and exact event names are in
[Framework Coverage](framework-support.md).

## What stays stable when the runtime changes

- Canonical call events and runtime state
- Supervisor beliefs, directives, guardrails, and no-op safety behavior
- Provider capability checks and action compilation
- Transcript, recording, QA, and post-call evidence contracts
- Python, TypeScript, REST, WebSocket, and MCP access to the same hosted APIs

The S2S library does not claim that every provider has the same live injection
capability. Unsupported or uncertain controls degrade to no action so the
speaking agent can continue safely.

## Next steps

1. Install the [Python or TypeScript SDK](sdk-installation.md).
2. Run the [provider injection examples](provider-injection-examples.md).
3. Review the [framework support matrix](framework-support.md).
4. Try the [hosted agent builder](hosted-agent-builder.md) when you want
   Supafone to own the call and phone delivery path.
