ProtectedContextThe host context, available from Initialize until Dispose.
null outside that window — guard with ?. in any code that can run early/late.
ProtectedSessionProtectedSessionMax time ResolveAgentSessionId waits for the session id to bind before giving up, and the poll interval it re-checks on. Protected so tests can shrink the wait; production keeps the defaults (the real mint race is sub-second, 8s is generous headroom).
ReadonlyStateThe media state of record — created fresh with the plugin (one per session).
The channel definition name — MUST match the MJ: AI Agent Channels row's Name
(e.g. 'Whiteboard'). Used as the persistence key for SerializeState saves
and as the channel tab's stable key.
OPTIONAL accent color for the channel's tab (a CSS color string, e.g. an hsl() /
token). When a plugin supplies one, the overlay paints the tab's dot + active underline
with it; when omitted (the default null), the overlay derives a stable, deterministic
color from the ChannelName so every channel still reads as a distinct, colored
surface. A channel only overrides this to enforce a specific brand accent.
Font Awesome icon class for the channel's tab (e.g. 'fa-solid fa-chalkboard').
Label for the channel's tab on the overlay's surface panel (e.g. 'Whiteboard').
The shared name prefix of every tool this channel exposes (e.g. 'Whiteboard_').
The host registers ONE local-execution route per plugin: tool calls whose name starts
with this prefix go to ApplyAgentTool instead of the server relay.
Executes one Media_* tool call LOCALLY: parse args, mutate the state engine, push a [media]
background context note so the agent stays aware of the surface, and return a short JSON result
string for the model. Never throws — malformed args resolve to a { success: false, error }
payload the model can narrate. Works with or without a bound surface (it mutates the state engine,
which the surface observes).
Wires the dynamically-created media surface (before first CD): shared state engine + agent name, plus the live session's MJ provider so FileID-backed items stream securely (mj-storage-media-player
Tears the plugin down at session end: release the surface binding, unsubscribe
state-engine subscriptions, then drop the context. Subclasses overriding this MUST
call super.Dispose(). Any final state save has already been flushed by the host
(the debounced RealtimeChannelContext.RequestSave pipeline) before disposal.
First-run intro shown the first time the user opens the Media tab (once per user).
The Angular component the overlay creates dynamically as this channel's tab pane, or null
for a server-only channel that renders no MJ surface (its surface, if any, lives on the
external platform — e.g. a bridge-contributed native whiteboard or meeting-controls channel).
When this returns null, the overlay renders NO tab for the channel and never calls
BindSurface/UnbindSurface — but the channel's tools (GetToolDefinitions /
ApplyAgentTool) and perception (RealtimeChannelContext.SendContextNote) still run.
A created surface instance is handed straight back via BindSurface; the host treats it as
opaque.
Default: null (server-only). A channel with a rendered surface overrides this to return its
component type.
The channel's CLIENT-EXECUTED tool declarations, aggregated by the session service
into the clientTools set declared to the realtime model at session mint. The server
only DECLARES these — execution stays in the browser via ApplyAgentTool.
Whether this channel has a rendered MJ surface (GetSurfaceComponent returns non-null).
The overlay uses this to decide whether to register a surface tab; server-only channels are
false. Override only if surface availability must be decided WITHOUT constructing the type
(the default calls GetSurfaceComponent once).
Binds the host context and invokes the OnInitialize hook. Called exactly once per session, right after ClassFactory instantiation and before any tool call or surface bind.
ProtectedOnPersist the media surface (host-debounced) on EVERY mutation — agent tools and tab changes.
The focus pill's "exit" affordance, routed by the overlay to the channel that holds
focus. Implementations should leave focus mode through their OWN surface (so surface
toggles stay in sync), ultimately emitting Context.SetFocusMode(false). The overlay
defensively clears its layout flag as well, so a no-op default is safe.
ProtectedResolveResolves the live RealtimeChannelContext.AgentSessionID, briefly WAITING for it when it
isn't bound yet rather than giving up instantly. AgentSessionID is a live getter over the
session service's current id: it reads null in the window BEFORE the session mints (the
realtime model can fire a tool call the very first beat it connects, before mintSession
resolves) and again AFTER teardown. Server-backed tool paths (e.g. the Remote Browser channel's
browser_* tools) call this instead of reading Context?.AgentSessionID synchronously, so a tool
invoked a beat early WAITS for the session to come live — defense-in-depth against the
"session id missing" race — instead of returning a hard failure to the model.
Returns the id as soon as it's non-null (the common path resolves immediately, no delay), or
null if it's still unbound after SessionIdWaitTimeoutMs — or the channel was
Disposed in the meantime (Context goes null, so we stop waiting on a torn-down session).
Rehydrates a prior session's saved media into THIS session's state engine (in place — the
State instance and its subscriptions are preserved). Tolerant: malformed JSON returns
false and the surface stays empty.
The Media channel's serialized state of record (persisted under ChannelName).
Called by the host when the surface component is being destroyed (tab panel collapsed / overlay torn down). Drop the instance reference and unsubscribe any output subscriptions — after this, ApplyAgentTool runs in its no-surface mode. Default: no-op.
The shared MEDIA SURFACE as a pluggable interactive channel — a BaseRealtimeChannelClient resolved from the
MJ: AI Agent Channelsregistry row whoseClientPluginClassis'RealtimeMediaChannel'. One instance per session (created via ClassFactory at session start).It owns a MediaChannelState engine and contributes the channel's full contract:
Media_*client-executed tool set (MEDIA_TOOL_DEFINITIONS); ApplyAgentTool parses the args, mutates the state engine, returns a short JSON result string, and sends the model a[media]background context note (so it stays aware of what's on screen). Works with NO surface bound — the tools mutate the state engine directly.'Media'; a prior session's media is rehydrated via RestoreState.Modeled directly on
RealtimeWhiteboardChannel.