The session parameters (model, system prompt, tools, initial context, config bag).
Binds the underlying socket. Called by the driver once the WebSocket is open.
Entry point for an inbound WebSocket frame. Classifies the raw frame to a semantic kind via classifyServerEvent, then routes to a focused per-concern handler so each translation unit stays small and testable.
The parsed Inworld server event.
Surfaces an UNEXPECTED socket close as a fatal error (expected closes — the consumer called Close — are silent). The provider hard-closes at token expiry and when it ends the session itself, so this is also how credential / session death reaches the consumer. The close handler fires after the error so consumers driving finalization from either signal converge.
Optionalcode: numberOptional WebSocket close code.
Optionalreason: stringOptional WebSocket close reason.
Surfaces a WebSocket-level failure as a FATAL session error — the transport is gone, so the consumer should finalize cleanly instead of idling on a dead socket (driver obligation #6).
The transport error message.
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.
The tools to expose to the model.
tools are a MUTABLE session.update field (components are swappable mid-session
without reconnect), so re-declaration is native: an identical set (order-insensitively) is a
silent no-op per the contract's idempotency rule; a genuinely different set is applied to the
live session immediately.
Instructions for the single spoken update.
ONE short spoken update via a response-create frame carrying per-response instructions. Collision behavior: queue. A response-create sent mid-response would collide with the in-flight generation (the provider rejects overlapping triggers), so the send is deferred until the active response completes and drained at the next boundary.
The context note to append to the conversation.
via the mutable system prompt: Inworld has no purpose-built non-interrupting context
channel, but session.update may rewrite instructions mid-session WITHOUT triggering
generation. The note is appended under a "Background updates" heading and the full prompt is
re-sent — a config write, so it never interrupts and is sent immediately even mid-response. The
model sees the notes the next time it speaks.
Sends the initial session.update frame carrying the full server-authored session config
(model, instructions, audio/STT/TTS, tools, semantic-VAD turn-taking). Always the FIRST client
frame — the provider drops audio sent before the session is configured.
The CallID from the originating RealtimeToolCall.
The tool's result as a JSON-stringified string.
the tool-call loop: sends a tool-result frame correlated by call_id. Sent
IMMEDIATELY (never queued) — the provider asked for it and owns the spoken continuation. The
busy flag is set eagerly so a queued narration can't slip in before the spoken result (driver
obligation #5 — the result must EVENTUALLY be voiced and never be dropped).
Resolves once the provider's session-ready confirmation arrives (its acknowledgment that the session config is applied); rejects if the transport dies first. Awaited by InworldRealtime.StartSession so the session is never handed to a consumer before it is actually configured (driver obligation #7).
A promise resolving on session-ready and rejecting on pre-ready transport death.
Concrete IRealtimeSession backed by a raw Inworld Realtime WebSocket.
Owns the inbound translation (Inworld wire events → Core events) and the outbound translation (Core calls → wire frames). Created by InworldRealtime.StartSession; never instantiated directly by consumers.
Provider-behavior notes (the contract deltas a consumer should know):
session.updateis the universal config channel. Model, instructions, audio/STT/TTS, tools, and turn-taking are all carried bysession.update— at connect time AND mid-session. Components are swappable without reconnect, so RegisterTools and SendContextNote are native config writes (never interrupting generation).[laugh]) — passed through verbatim in instructions; the driver does not parse or strip them.SendToolResultis sent immediately (the provider owns the spoken continuation) and marks a response active eagerly so a queued narration can't slip ahead.tool.callclears the busy flag WITHOUT draining the queue (deadlock guard, obligation #2).