ProtectedconstructorPost-close linger (ms) before BaseRealtimeChannelServer.Dispose runs, so the client's
legitimate post-close state flush still routes through the plugin. 0 disposes immediately
(used by tests). Mutable on purpose — a deployment-level knob, not per-session state.
Number of sessions currently holding live (or close-lingering) plugin instances.
StaticInstanceProcess-wide singleton accessor (Global Object Store backed via BaseSingleton).
Routes ONE server-executed tool call to the session's plugin that owns it, matched by the plugin's BaseRealtimeChannelServer.ToolNamePrefix, and returns its result. Resolution picks the plugin whose (non-empty) prefix the tool name starts with — the longest matching prefix wins, so overlapping prefixes resolve deterministically.
Never throws: an unowned tool (no channel prefix matches), an unknown session, or a plugin that
throws all resolve to a structured { Success: false } result so the model always receives a
consistent tool_response.
The session the tool call belongs to.
The full tool name the model invoked.
The raw arguments JSON the model emitted.
The execution result (or a structured error).
The Global Object Store is a place to store global objects that need to be shared across the application. Depending on the execution environment, this could be the window object in a browser, or the global object in a node environment, or something else in other contexts. The key here is that in some cases static variables are not truly shared because it is possible that a given class might have copies of its code in multiple paths in a deployed application. This approach ensures that no matter how many code copies might exist, there is only one instance of the object in question by using the Global Object Store.
Returns the live plugin instance for (agentSessionID, channelName), or null when none
exists (no plugin resolved for that channel, unknown session, or already disposed).
Lookup is case/whitespace-insensitive on both keys.
Aggregates the server-executed tool definitions every live plugin of a session contributes
(each plugin's BaseRealtimeChannelServer.GetServerToolDefinitions, possibly
runtime-computed) into one flat set — the per-session server-channel tool vocabulary fed into
RealtimeSessionRunner.ServerChannelTools.
Tolerant by contract: a plugin whose GetServerToolDefinitions throws is logged and skipped,
never breaking the assembly. An unknown session returns [].
The session whose channels' server tools to collect.
The aggregated tool definitions across all of the session's live channel plugins.
Channel-state-save entry point, invoked PRE-persistence. Routes the payload to the session's matching plugin and returns the string to persist:
stateJson;null/empty/non-string, or throws (logged) → the original stateJson.A plugin can therefore only ever transform a save — it can never lose or block one.
Session-closed entry point — invoked from EVERY close provenance (explicit, janitor sweeps,
shutdown drain, error teardown; SessionManager.CloseSession is the single funnel). Fires
each plugin's OnSessionClosed(reason) (failures logged, siblings unaffected), then defers
Dispose() by DisposeLingerMs so the client's post-close state flush still routes
through the plugins. Idempotent: an unknown session, or one whose close hooks already fired
(disposal pending), is a no-op. Never throws.
Session-started entry point. Loads the ACTIVE channel registry rows, resolves each row's
ServerPluginClass through the ClassFactory into ONE fresh instance for this session, and
brackets each with Initialize(ctx) + OnSessionStarted(). Rows with no registered plugin
are skipped with a log; a plugin whose start bracket throws is dropped (logged) without
touching its siblings. Never throws — any registry/host failure degrades to "no plugins".
Idempotent per session: a second start notification for a session that already holds instances is ignored (logged) rather than double-initializing.
Returns true when the given tool name is owned by a live channel of the session.
Protected StaticgetReturns the singleton instance of the class. If the instance does not exist, it is created and stored in the Global Object Store. If className is provided it will be used as part of the key in the Global Object Store, otherwise the actual class name will be used. NOTE: the class name used by default is the lowest level of the object hierarchy, so if you have a class that extends another class, the lowest level class name will be used.
OptionalclassName: string
Singleton host that owns every live
BaseRealtimeChannelServerinstance in this process — one instance per (session × active channel row with a resolvableServerPluginClass).Lifecycle routing (who calls what)
SessionManager.CreateSessionafter the session row persistsInitialize(ctx)thenOnSessionStarted()per resolved pluginSaveSessionChannelStateresolver, pre-persistenceOnChannelStateSave(stateJson)SessionManager.CloseSession(all close provenances)OnSessionClosed(reason)per plugin, then deferredDispose()Janitor / cross-host notes
SessionManager.CloseSession, so a session whose plugins live in this process is eventually cleaned up here even when its client vanished — including when ANOTHER instance won the close race (CloseSession's already-closed path still notifies this host, and an unknown session is a no-op).