The injectable provider-connection seam.
The provider profile (defaults to OpenAI's so existing direct construction keeps working).
ProtectedresponseWhether a model response is currently in flight. Minimal response tracking that mirrors the
client driver's state machine: set on response.created (and eagerly whenever this session
sends its own response.create, so back-to-back local triggers can't race the server event),
cleared on response.done — which the API emits for every terminal status, including
cancelled after barge-in, so the flag can never stick. Consumed by
OpenAIRealtimeSession.RequestSpokenUpdate to skip (not collide with) an active
response, since the API rejects overlapping response.create requests.
Protected (not private) so compat-endpoint session subclasses can apply provider-specific robustness tweaks (e.g. HuggingFace marks a response active on the first audio delta and releases the flag when a tool call yields the floor).
ProtectedconfigReadiness deadline in milliseconds for the deferred-config wait. Only affects consumers of WaitForConfigApplied; the deferred apply itself is not cancelled. Overridable.
Applies the initial session config: system prompt + tools via session.update, optional initial
context as a user message. Called once by OpenAIRealtime.StartSession.
Deferral is profile-driven. On OpenAI the realtime WebSocket is NOT open when StartSession
returns — sending session.update synchronously races the handshake and the instructions (the
system prompt + tools) are silently dropped, so the model runs with NO prompt (no identity, no
companion framing). We therefore wait for the server's session.created frame — the first event once
the socket is open and the session exists, and the canonical moment to configure a realtime session —
exactly the point the browser/client-direct path applies its config. Idempotent (a re-emitted
session.created can't double-apply); the listener removes itself once it fires. Providers whose
socket accepts config immediately (xAI) set the profile flag false and send synchronously.
The session parameters.
Closes the session and releases the underlying provider connection.
A promise that resolves once the session is fully closed.
ProtecteddispatchRoutes a provider server event to the matching contract handler. Each branch delegates to a small, single-purpose handler to keep this dispatcher flat.
Protected (not private) so OpenAI-compatible session subclasses can pre-translate legacy / beta frame aliases before delegating here.
The OpenAI realtime server event.
Optional capability — registers a handler invoked when the underlying provider
connection closes WITHOUT the consumer having called IRealtimeSession.Close
(provider-side hangup, network drop). Not fired for a consumer-initiated Close() —
the caller already knows about that one.
Optional because not every provider surface exposes a close signal cheaply; callers
must feature-detect (if (session.OnClose) { ... }). An unexpected close is typically
ALSO surfaced as a Fatal IRealtimeSession.OnError, which is the signal
consumers should drive finalization from.
Invoked when the provider connection closes unexpectedly.
Registers a handler for session errors.
Fatality semantics mirror the client-side BaseRealtimeClient contract:
Fatal: true — the session is unusable (transport/socket failure, credential/token
expiry, unexpected connection loss). The consumer should finalize the session (e.g.
RealtimeSessionRunner calls Stop()) instead of idling forever on a dead socket.Fatal: false — a provider-reported, recoverable error frame; the session stays open
and the consumer should log and continue.Invoked with each RealtimeSessionError.
Registers a handler for provider-detected interruptions (barge-in).
True barge-in only: the handler fires ONLY when user speech interrupts ACTIVE model output — NOT on every user utterance. A user simply taking their normal turn while the model is idle is not an interruption, and drivers must not report it as one (e.g. a raw "speech started" frame must be gated on whether a model response is actually in flight).
Turn detection / VAD is owned by the provider. The agent layer uses this hook to cancel
the model's current turn and to fire the cancellationToken of any in-flight
delegated agent run — a stale delegated result must never be narrated into a conversation
that has moved on.
Invoked when the provider reports a true barge-in interruption.
Registers a handler for model audio output frames (the audio media plane).
Invoked with each output audio frame as an ArrayBuffer.
Registers a handler for model tool-call requests.
Consumers execute the requested tool (under the session's context user) and feed the result back to the model.
Invoked with each RealtimeToolCall.
Registers a handler for transcript events (the text stream).
Consumers typically forward these to the control plane and persist them as
ConversationDetail records.
Invoked with each RealtimeTranscript (partial or final).
Registers a handler for usage/telemetry updates.
Usage is checkpointed incrementally by the agent layer (debounced onto the prompt run) so partial usage is never lost if the session is force-closed after a crash.
Invoked with each RealtimeUsage update.
Registers the set of tools the model may call, translating them into the provider's native function-calling format.
The Core-level RealtimeToolDefinition is intentionally minimal: BaseRealtimeModel
lives in the lowest AI layer and cannot depend on the richer tool metadata defined in
higher packages (the agent layer) — doing so would create an illegal upward/circular
dependency. The agent layer is responsible for mapping its richer tool metadata down
to this Core type before calling RegisterTools, and the concrete driver maps this Core
type up to the provider's native function-calling schema.
Note that some providers (e.g. Eleven Labs) bind to a pre-declared tool set on a server-side agent configuration; for those, the driver maps these definitions onto the pre-declared tool names rather than registering arbitrary schemas at session start.
Idempotency rule: a post-start registration of a set IDENTICAL to the set supplied at connect time (via RealtimeSessionParams.Tools) MUST be a no-op. Providers that bind their tool set at connect time and cannot re-declare schemas on an open session MUST no-op (and may log) rather than degrade the conversation — e.g. by injecting schema text into the conversation as content. A genuinely DIFFERENT post-start set on such a provider is unsupported and should be surfaced as a warning, not silently mangled.
The tools to expose to the model.
Instructions for the single spoken update. Blank/empty means "respond now using
the SESSION system prompt" (the meeting-mode bridge trigger passes ''); only a non-empty value is
forwarded as a per-response override.
ONE short spoken update via response.create with per-response instructions.
Collision behavior: skip. The Realtime API rejects a response.create while another
response is active, so when responseActive is set the request is dropped — interim
updates are disposable by contract (the next update or the final result supersedes them).
When sent, the flag is set eagerly (before the server's response.created echo) so two
back-to-back local triggers can't both fire.
The context note to append to the conversation.
a system-role conversation item (conversation.item.create) the model can draw
on the next time it speaks, WITHOUT a response.create — so no spoken reply is forced.
NOTE: the role must be 'system' — gpt-realtime rejects 'developer' items ("Developer
messages are only supported for quicksilver sessions"); same constraint the client-direct
driver hit. Item creation is always safe mid-response on OpenAI, so no collision guard is
needed here (unlike OpenAIRealtimeSession.RequestSpokenUpdate).
Sends a client media frame to the model.
Fire-and-forget: frames are streamed straight to the provider with no JSON intermediation. The
optional kind tags the media plane — 'audio' (default, back-compatible: existing callers and
audio-only drivers need not pass or read it) or 'video' for a camera frame to a video-capable
model (one that BaseRealtimeModel.SupportsVideo). Audio-only drivers ignore 'video'
frames.
A raw media frame as an ArrayBuffer.
The CallID from the originating RealtimeToolCall.
The tool's result as a JSON-stringified string.
Resolves once the initial session config has been APPLIED (sent on the socket) — immediately
for providers that configure synchronously, or on the server's session.created frame for
deferring providers. Rejects if the transport dies (fatal error or unexpected close) or the
consumer closes the session before the config went out.
The base OpenAIRealtime.StartSession deliberately does NOT await this (OpenAI
semantics: the session handle is returned while the handshake completes). Drivers whose
contract promises "ready only after config is applied" (HuggingFace) await it in their
StartSession override.
Live IRealtimeSession backed by an IOpenAIRealtimeConnection.
Holds the registered handlers and the single
'event'listener that fans the provider's server-event stream out to the contract handlers via OpenAIRealtimeSession.dispatch.The session is profile-parameterized (see OpenAIRealtimeProfile) so OpenAI-compatible provider subclasses reuse it verbatim with their own knobs.