@scenaro/sdk separates two things that most voice SDKs bundle together: the session
contract your app codes against, and the realtime engine that actually moves audio and
data. That boundary is called Transport.
You rarely need this page to ship a voice experience —
useScenaroSession
hides Transport completely for the embed path. Read this if you’re deciding whether code
belongs in your app or in a Transport-specific extension, or if you’re curious how the SDK
stays engine-agnostic.Why a Transport boundary exists
Today, Transport is implemented with LiveKit — WebRTC audio plus a data channel for the agent ↔ frontend protocol. Tomorrow it could be Pipecat or another realtime engine.ScenaroSession never calls
LiveKit directly — it calls an internal Transport interface, and a LiveKitTransport
implements that interface underneath.
This mirrors the internal boundary in the SDK source —
packages/sdk/src/core/transport.ts:
@scenaro/sdk — it’s an internal seam, not a plugin
API you implement yourself. What it buys you as a developer is a stable contract on top of it.
Two levels: portable contract vs engine extension
| Level | What it is | Stability | Examples |
|---|---|---|---|
| Portable contract | Scenaro’s session API, independent of the engine underneath | Stable across future Transport implementations | status, agentState, messages, config, tools, session events |
| Engine extension | The current engine’s own API surface | Tied to LiveKit today — not guaranteed to carry over | room, RoomContext, @livekit/components-react hooks/components |
useScenaroSession. Code that calls room.localParticipant... or uses
LiveKit’s React hooks is written against the current engine directly — the same trade-off you’d
make using that engine standalone.
What “transport session” means in the docs
Across the documentation, transport session refers to the realtime connection established bystart() — audio (if enabled) plus the data channel carrying the protocol.
The wire response from POST /v1/public/session is described as transport credentials:
today those fields are named livekit_token and livekit_url (see
ScenaroClient.startSession), because LiveKit is the
current implementation. The field names are not renamed as part of this documentation
alignment — only the prose around them is engine-agnostic.
Implementations
| Engine | Status | Where |
|---|---|---|
| LiveKit | Current, only implementation | packages/sdk/src/transport/livekit/ |
| Pipecat | Not implemented — this boundary exists so it could be added without rewriting ScenaroSession | — |
Next steps
- Advanced: Transport extensions — using the LiveKit engine extension surface
- Key concepts — scenario, auth, protocol
- Protocol reference — the data carried over Transport