Member Junction
    Preparing search index...

    Drives a client-direct real-time voice session: the browser mints an ephemeral token from the MJ server, then connects DIRECTLY to the realtime provider. Audio frames never transit the MJ server (low latency); only tool calls and final transcripts are relayed back to MJ over GraphQL.

    This service is PROVIDER-AGNOSTIC policy/orchestration. All provider wire concerns (transport, event translation, the response state machine, narration-kind tagging, playback tracking) live in a BaseRealtimeClient driver resolved through the MJ ClassFactory by the server-reported Provider key (e.g. 'openai'OpenAIRealtimeClient). Future providers (Gemini Live, …) snap in by registering a new driver — this service does not change.

    The Realtime Co-Agent (server-side) fronts the conversation's current agent — the server bakes the companion instructions + tool set into SessionConfigJson, which the client driver applies verbatim.

    Lifecycle: StartRealtimeSession → live duplex → EndRealtimeSession.

    Index

    Constructors

    Properties

    Active$: Observable<boolean> = ...

    True while a session is open (mic button active, overlay shown).

    ActiveChannels$: Observable<BaseRealtimeChannelClient<object>[]> = ...

    The session's ACTIVE interactive-channel plugins, resolved from the MJ: AI Agent Channels registry at session start (one instance per session, per channel). Emits [] before a session starts and after teardown. The overlay subscribes to register one surface tab per plugin — it never knows any concrete channel type.

    AgentName$: Observable<string> = ...

    Display name of the agent the active session fronts (set at session start).

    AppContext$: Observable<AppContextSnapshot | null> = ...

    Observable of the live app-context snapshot (see _appContext$).

    Captions$: Observable<RealtimeCaption[]> = ...

    Live captions for both sides of the conversation.

    ChannelActivity$: Observable<BaseRealtimeChannelClient<object>> = ...

    Fires with the channel PLUGIN every time the agent ACTS on that channel (a tool call was routed to its local executor — e.g. the agent drew on the whiteboard). The overlay uses the FIRST emission per channel to auto-reveal + focus the channel's surface tab, so the user discovers the surface the moment the agent starts using it. Finer-grained than SessionStarted$/SessionEnded$ (per tool call, not per session).

    ChannelFocus$: Observable<RealtimeChannelFocusEvent> = ...

    Channel requests to enter / leave the FOCUS layout (see RealtimeChannelFocusEvent). Fired when a plugin calls its host context's SetFocusMode — e.g. the whiteboard's "Focus board" toggle.

    ConnectionState$: Observable<RealtimeConnectionState> = ...

    Current connection / turn state.

    DelegationNarration$: Observable<RealtimeDelegationNarration> = ...

    EPHEMERAL spoken progress narrations (see RealtimeDelegationNarration). These are deliberately kept OUT of Captions$ and never relayed/persisted — the overlay renders them as a transient "live note" near the active working card.

    DelegationProgress$: Observable<RealtimeDelegationProgress> = ...

    Progress updates from a delegated agent run (e.g. Sage) while the realtime model waits on it. The future overlay subscribes to render a "working" card; the model also narrates these aloud.

    DelegationResult$: Observable<RealtimeDelegationResult> = ...

    Terminal result of a delegation, so the overlay can complete the working card with real content.

    Minimized$: Observable<boolean> = ...

    True while the active call overlay is MINIMIZED to the host's floating "on call" pill (e.g. after a dev link navigated away). The mic and session stay fully live — this is pure presentation state, reset to false at session start and teardown.

    ModelName$: Observable<string | null> = ...

    Display name of the realtime MODEL the active session runs on (server-reported at session start, e.g. "GPT Realtime 2"). null before a session starts / when the server didn't report one. The overlay banner shows it subtly next to the agent identity.

    SessionEnded$: Observable<{ reason: "error" | "explicit"; sessionId: string }> = ...

    Fired EXACTLY ONCE per session as teardown begins, with the prior agentSessionId (so subscribers can correlate against SessionStarted$'s sessionId) and the client-distinguishable reason — 'explicit' when the user called EndRealtimeSession, 'error' when teardown ran from a catch block. Server-side close paths (janitor, shutdown) do NOT propagate here — they happen out-of-process and have no client push channel today.

    SessionStarted$: Observable<{ channelNames: string[]; sessionId: string }> = ...

    Fired EXACTLY ONCE per session after both agentSessionId is set AND the realtime client is connected. Carries the server-issued sessionId and the ChannelName of each plugin resolved at session mint. Consumed by RealtimeSessionsAdapter (in this package) to feed @memberjunction/conversations-runtime's SessionsObserver.

    Why this exists separately from Active$: Active$ flips true BEFORE mintSession resolves, so agentSessionId is still null at that moment. Subscribers correlating (Active$, agentSessionId) would race; this event removes the race.

    Accessors

    Methods

    • Cancels ONE in-flight delegated tool call — the overlay's per-card ✕ affordance.

      EXPLICIT USER INTENT ONLY (deliberate host policy): true barge-in never aborts delegations — the narration design expects the user to talk while delegated work runs. Calls the CancelRealtimeSessionTool mutation (ownership-gated server-side); when the server reports it aborted the run, the card is flipped immediately to a FAILED "Cancelled by user" result and the eventual late result from the aborted run is suppressed (see emitDelegationResult).

      Parameters

      • callId: string

      Returns Promise<boolean>

      true when the server aborted the in-flight run; false when there was nothing to cancel (the work finished first — its real result is already racing in) or the mutation failed (logged, never thrown).

    • Cancels EVERY in-flight delegated tool call for the active session (callId-less form of the CancelRealtimeSessionTool mutation). Exposed for host policies that need a sweep-cancel (e.g. an explicit "stop everything" affordance) — NOT wired to barge-in, by the same deliberate policy as CancelDelegation.

      Returns Promise<number>

      The number of in-flight runs the server aborted (0 when nothing was tracked in flight client-side, nothing was in flight server-side, or the mutation failed).

    • Replaces the set of host-registered surface client tools the realtime ContextTool can execute. The host calls this at session start and whenever the active surface's tool set changes (the continuous-capability half of client-context delivery). Passing [] clears them.

      Parameters

      • tools: readonly { Handler: (params: Record<string, unknown>) => unknown; Name: string }[]

        The current surface client tools (name + handler). Descriptions/schemas ride the app-context manifest separately; only the executable handler is needed here.

      Returns void

    • Registers a handler for CLIENT-EXECUTED UI tools whose names start with toolNamePrefix (e.g. 'Whiteboard_' → all Whiteboard_* calls). Matching tool calls execute LOCALLY via the handler — they are never relayed to the server — and the handler's result JSON is sent back to the model as the tool_response. Re-registering the same prefix replaces the handler. The registry is cleared at session teardown.

      Parameters

      Returns void

    • Persists an interactive channel's state of record (e.g. the whiteboard's serialized scene) onto the session's MJ: AI Agent Session Channels row via SaveSessionChannelState.

      Parameters

      • channelName: string

        The channel definition name (e.g. 'Whiteboard').

      • stateJson: string

        The serialized channel state.

      • OptionalagentSessionId: string | null

        Optional EXPLICIT session id. The debounced channel-save pipeline captures the id while the session is live and passes it here, so the final teardown flush still lands on the just-closed session. Falls back to the active session's id; returns false when neither is available.

      Returns Promise<boolean>

      Whether the server persisted the state. Failures are logged, never thrown — channel persistence is best-effort and must not disturb the live call.

    • Inject a typed message into the live session as a user turn.

      Decomposed into two steps, each mirroring an existing voice path so the typed turn behaves identically to a spoken one:

      1. BaseRealtimeClient.SendText injects the text as user input and triggers a reply through the SAME collision-safe path tool results use — so it queues behind any in-flight response (progress narration / prior turn) instead of colliding.
      2. Relay the turn through the same caption + transcript paths user speech uses (onUserTranscript) so it shows in the live thread AND persists to MJ.

      No-op when no session is open / the control channel isn't ready, or when the text is empty.

      Parameters

      • text: string

      Returns void

    • Start a client-direct voice session fronting targetAgentId.

      Parameters

      • targetAgentId: string

        The agent the Realtime Co-Agent voices on behalf of.

      • OptionalconversationId: string | null

        Optional existing conversation to bind + seed context from.

      • OptionallastSessionId: string | null

        Optional prior session to chain to (resume / continuation).

      • OptionalagentName: string | null

        Optional display name of the target agent — resolved by the caller (which knows the conversation's routing context) and surfaced on AgentName$ so ANY host (composer trigger, chat-area overlay) can render it without re-resolving.

      • OptionalpreferredModelId: string | null

        Optional EXPLICIT realtime model choice (MJ: AI Models.ID). When set, the server uses exactly that model and FAILS with a clear reason if it can't (no silent fallback). Omit for the server's automatic (highest-PowerRank) selection.

      • OptionalclientTools: RealtimeToolDefinition[] | null

        Optional EXTRA client-executed UI tool declarations to expose to the realtime model alongside the server's stable tool set and the interactive-channel tools (which are aggregated automatically from the registry-resolved plugins — see ActiveChannels$). The server only DECLARES these — execution stays in the browser via handlers registered with RegisterClientToolHandler. This is an extension point for hosts with bespoke (non-channel) UI tools; most callers omit it.

      • OptionalcoAgentId: string | null

        Optional EXPLICIT co-agent choice (MJ: AI Agents.ID of an Active, Realtime-type agent) — the highest-precedence step of the server's co-agent resolution chain. When set, the server uses exactly that co-agent and FAILS with a clear reason if it can't (no silent fallback). Omit to let server metadata drive the choice: the target agent's DefaultCoAgentID, then the type-level AIAgentCoAgent default row, then the global Realtime Co-Agent.

      • OptionalconfigOverridesJson: string | null

        Optional JSON payload of SESSION CONFIG overrides (e.g. {"realtime":{"modelPreference":"<modelId>"}}), forwarded verbatim on the mint mutation. The server enforces the Realtime: Advanced Session Controls authorization on any overrides — hosts only populate this from authorization-gated pickers, and never synthesize overrides beyond what the user explicitly chose. Omit/null for the server's defaults (today's behavior).

      • OptionalrecordingConsent: boolean | null

        Optional EXPLICIT "record this call" consent for THIS session. When true, the browser records a mic + agent-audio mix and uploads it at session end. When omitted/null, the per-user persisted preference (mj.realtimeVoice.recordingConsent.v1 via UserInfoEngine) is read as the default. false never records.

      • OptionalmediaCollectionId: string | null

        Optional per-session media-kit override (MJ: Collections.ID). When set, the server-side Media channel resolves THIS collection as the agent's media kit for the session, taking precedence over the agent's DefaultMediaCollectionID. The server UUID-validates it (malformed ⇒ ignored, the agent default applies). Omit/null to use the agent default kit.

      • OptionalapplicationId: string | null
      • OptionalappContext: AppContextSnapshot | null

      Returns Promise<void>

    • Push an updated app-context snapshot mid-session (the continuous-streaming half of client-context delivery). The host (Explorer) calls this when the user navigates / the active surface's state or capability manifest changes; the ClientContextChannel turns the delta into a SendContextNote. No-op semantics when no session is live — the channel simply re-reads on next start.

      Parameters

      Returns void