@memberjunction/realtime-runtime 0.0.0 → 6.2.0-edge.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,183 @@
1
+ Business Source License 1.1
2
+
3
+ License text copyright (c) 2024 MariaDB plc, All Rights Reserved.
4
+ "Business Source License" is a trademark of MariaDB plc.
5
+
6
+ -----------------------------------------------------------------------------
7
+
8
+ Parameters
9
+
10
+ Licensor: Blue Cypress, Inc.
11
+
12
+ Licensed Work: MemberJunction.
13
+ The Licensed Work is (c) 2023-2026 Blue Cypress, Inc.
14
+
15
+ Additional Use Grant: Subject to the terms of this License, Licensor grants
16
+ you the following additional rights to make Production
17
+ Use of the Licensed Work.
18
+
19
+ 1. Internal Use
20
+
21
+ You may make production use of the Licensed Work for
22
+ your own internal business or organizational operations.
23
+
24
+ 2. Nonprofit Use
25
+
26
+ If you are a Nonprofit, you may make production use of
27
+ the Licensed Work for the operations and activities of
28
+ your Organizational Family.
29
+
30
+ 3. MemberJunction Certified Program Use
31
+
32
+ If you are authorized by Licensor under the
33
+ MemberJunction Certified Program to provide professional
34
+ services using the Licensed Work, you may make
35
+ production use of the Licensed Work in providing such
36
+ professional services to a client, provided that:
37
+
38
+ (a) the Licensed Work is deployed in, and the applicable
39
+ production use occurs within, an environment owned,
40
+ leased, licensed, subscribed to, or otherwise controlled
41
+ by that client; and
42
+
43
+ (b) the production use is for that client's own internal
44
+ business or organizational operations or is otherwise
45
+ independently permitted to that client under this
46
+ Additional Use Grant.
47
+
48
+ 4. Definitions Applicable to the Additional Use Grant
49
+
50
+ "Affiliate" means, with respect to a specified Person,
51
+ any other Person that directly or indirectly Controls,
52
+ is Controlled by, or is under common Control with such
53
+ specified Person.
54
+
55
+ "Control" (including the terms "Controls," "Controlled
56
+ by," and "under common Control with") means the direct
57
+ or indirect possession of the power to direct or cause
58
+ the direction of the management and policies of a
59
+ Person, whether through ownership of voting interests,
60
+ by contract, or otherwise.
61
+
62
+ "Organizational Family" means, with respect to a Person,
63
+ (a) such Person and its Affiliates, and (b) any
64
+ nonprofit organization, governmental entity, chapter,
65
+ division, local affiliate, regional affiliate, state
66
+ affiliate, national affiliate, or other entity that is
67
+ formally affiliated with such Person through governing
68
+ documents, a charter, bylaws, a membership agreement, or
69
+ another written organizational instrument, and is
70
+ recognized under such documents as part of the same
71
+ organizational structure.
72
+
73
+ "Nonprofit" means a Person recognized by the Internal
74
+ Revenue Service as exempt from federal income taxation
75
+ under Section 501(c)(3), 501(c)(4), 501(c)(5), or
76
+ 501(c)(6) of the Internal Revenue Code, or a foreign
77
+ organization recognized under substantially equivalent
78
+ laws.
79
+
80
+ A Person claiming eligibility as a Nonprofit shall, upon
81
+ Licensor's reasonable request, provide documentation
82
+ reasonably sufficient to demonstrate that it qualifies
83
+ as a Nonprofit. If such Person materially misrepresents,
84
+ or is unable to demonstrate, its qualification as a
85
+ Nonprofit, the rights granted to such Person under
86
+ Section 2 of this Additional Use Grant shall terminate.
87
+
88
+ "MemberJunction Certified Program" means Licensor's
89
+ then-current program for certifying and authorizing a
90
+ Person to provide professional services using the
91
+ Licensed Work.
92
+
93
+ "Person" means any individual, corporation, limited
94
+ liability company, partnership, association, nonprofit
95
+ organization, governmental entity, or other legal or
96
+ organizational entity.
97
+
98
+ Change Date: Four (4) years from the date the Licensed Work is first
99
+ made available.
100
+
101
+ Change License: MIT License.
102
+
103
+ For information about alternative licensing arrangements for the Licensed
104
+ Work, please contact Blue Cypress, Inc.
105
+
106
+ -----------------------------------------------------------------------------
107
+
108
+ Terms
109
+
110
+ The Licensor hereby grants you the right to copy, modify, create derivative
111
+ works, redistribute, and make non-production use of the Licensed Work. The
112
+ Licensor may make an Additional Use Grant, above, permitting limited
113
+ production use.
114
+
115
+ Effective on the Change Date, or the fourth anniversary of the first publicly
116
+ available distribution of a specific version of the Licensed Work under this
117
+ License, whichever comes first, the Licensor hereby grants you rights under
118
+ the terms of the Change License, and the rights granted in the paragraph
119
+ above terminate.
120
+
121
+ If your use of the Licensed Work does not comply with the requirements
122
+ currently in effect as described in this License, you must purchase a
123
+ commercial license from the Licensor, its affiliated entities, or authorized
124
+ resellers, or you must refrain from using the Licensed Work.
125
+
126
+ All copies of the original and modified Licensed Work, and derivative works
127
+ of the Licensed Work, are subject to this License. This License applies
128
+ separately for each version of the Licensed Work and the Change Date may vary
129
+ for each version of the Licensed Work released by Licensor.
130
+
131
+ You must conspicuously display this License on each original or modified copy
132
+ of the Licensed Work. If you receive the Licensed Work in original or
133
+ modified form from a third party, the terms and conditions set forth in this
134
+ License apply to your use of that work.
135
+
136
+ Any use of the Licensed Work in violation of this License will automatically
137
+ terminate your rights under this License for the current and all other
138
+ versions of the Licensed Work.
139
+
140
+ This License does not grant you any right in any trademark or logo of
141
+ Licensor or its affiliates (provided that you may use a trademark or logo of
142
+ Licensor as expressly required by this License).
143
+
144
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
145
+ AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
146
+ EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
147
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
148
+ TITLE.
149
+
150
+ MariaDB hereby grants you permission to use this License's text to license
151
+ your works, and to refer to it using the trademark "Business Source License",
152
+ as long as you comply with the Covenants of Licensor below.
153
+
154
+ -----------------------------------------------------------------------------
155
+
156
+ Covenants of Licensor
157
+
158
+ In consideration of the right to use this License's text and the "Business
159
+ Source License" name and trademark, Licensor covenants to MariaDB, and to all
160
+ other recipients of the licensed work to be provided by Licensor:
161
+
162
+ 1. To specify as the Change License the GPL Version 2.0 or any later version,
163
+ or a license that is compatible with GPL Version 2.0 or a later version,
164
+ where "compatible" means that software provided under the Change License
165
+ can be included in a program with software provided under GPL Version 2.0
166
+ or a later version. Licensor may specify additional Change Licenses without
167
+ limitation.
168
+
169
+ 2. To either: (a) specify an additional grant of rights to use that does not
170
+ impose any additional restriction on the right granted in this License, as
171
+ the Additional Use Grant; or (b) insert the text "None".
172
+
173
+ 3. To specify a Change Date.
174
+
175
+ 4. Not to modify this License in any other way.
176
+
177
+ -----------------------------------------------------------------------------
178
+
179
+ Notice
180
+
181
+ The Business Source License (this document, or the "License") is not an Open
182
+ Source license. However, the Licensed Work will eventually be made available
183
+ under an Open Source License, as stated in this License.
@@ -0,0 +1,402 @@
1
+ import type { Observable } from 'rxjs';
2
+ import { IMetadataProvider } from '@memberjunction/core';
3
+ import { JSONValue, RealtimeToolDefinition, RealtimeTrackDescriptor, RealtimeTrackDirection } from '@memberjunction/ai';
4
+ import type { BaseRealtimeClient } from '@memberjunction/ai-realtime-client';
5
+ import type { AppContextSnapshot } from '@memberjunction/ai-core-plus';
6
+ /**
7
+ * A UI framework's component-class reference, as far as this runtime is concerned.
8
+ *
9
+ * This was `Type<T>` from `@angular/core`. That import was the *only* Angular tie in this file —
10
+ * and it was never a real dependency: the runtime receives a component class from a channel plugin
11
+ * and hands it to the host to render. It never constructs one, never reads a property off one, and
12
+ * never cares what framework produced it.
13
+ *
14
+ * It is deliberately opaque. Trying to describe a component class *structurally* here would be
15
+ * dishonest precision: each framework's constructor contract differs, and narrowing to any one of
16
+ * them re-couples the runtime to that framework. The runtime only ever carries this value from the
17
+ * plugin to the host, so "a class" is the whole of what it needs to know — the host, which does
18
+ * know what a component is, narrows it at the single point where it instantiates one.
19
+ *
20
+ * Angular's `Type<T>` satisfies this unchanged, so no existing plugin needs editing. Without it,
21
+ * every interactive channel — the whiteboard, the remote browser, the media surface — is
22
+ * permanently Angular-only, which is exactly why a non-Angular host could not offer channels.
23
+ */
24
+ export type RealtimeSurfaceComponentType = Function;
25
+ /**
26
+ * Host services handed to a {@link BaseRealtimeChannelClient} at {@link BaseRealtimeChannelClient.Initialize}.
27
+ *
28
+ * The context is the plugin's ONLY line back to the live session — channels never talk to
29
+ * `RealtimeSessionService` (or any host component) directly, which is what keeps them drop-in
30
+ * plugins. Every member is host-implemented:
31
+ *
32
+ * - the SESSION SERVICE supplies {@link SendContextNote} (perception feed into the live
33
+ * model), {@link RequestSave} (debounced state-of-record persistence onto the session's
34
+ * `MJ: AI Agent Session Channels` row) and {@link AgentName};
35
+ * - the OVERLAY SHELL wires {@link SetFocusMode} (through the service's focus stream) so a
36
+ * channel surface can request the focus layout — main call column collapsed, surface
37
+ * panel filling the overlay, floating call pill riding on top.
38
+ */
39
+ export interface RealtimeChannelContext {
40
+ /** Display name of the agent the live session fronts (e.g. `"Sage"`), fixed at session start. */
41
+ AgentName: string;
42
+ /**
43
+ * The MJ metadata provider the live session runs on — the SAME `IMetadataProvider` instance that
44
+ * authenticates the session (NOT necessarily the global default). A channel whose surface renders
45
+ * MemberJunction-backed data (e.g. the Media channel streaming an `MJ: Files` record through
46
+ * `mj-storage-media-player`) threads THIS provider into its surface / GraphQL calls so it stays
47
+ * multi-provider safe. `null` only in degenerate/early states; channels fall back to the global
48
+ * default when absent.
49
+ */
50
+ Provider: IMetadataProvider | null;
51
+ /**
52
+ * Feeds a background context note into the live realtime model (no spoken reply is
53
+ * requested) — the PERCEPTION direction of the channel: serialized state deltas flow here
54
+ * so the agent stays aware of what's on the surface. No-op when the session isn't live.
55
+ */
56
+ SendContextNote(text: string): void;
57
+ /**
58
+ * Asks the host to persist `stateJson` as this channel's state of record. The host
59
+ * DEBOUNCES (a change burst becomes one save) and flushes any pending save at session
60
+ * teardown — the plugin just calls this on every state mutation and never schedules
61
+ * timers itself. Best-effort: persistence failures are logged host-side, never thrown.
62
+ */
63
+ RequestSave(stateJson: string): void;
64
+ /**
65
+ * Requests (or releases) the FOCUS layout for this channel's surface: the overlay
66
+ * collapses the main call column so the surface owns the screen, with a compact floating
67
+ * call pill keeping mute / thread / end reachable. Any channel may request it; the host
68
+ * tracks which channel holds focus and routes the pill's "exit" back to it via
69
+ * {@link BaseRealtimeChannelClient.RequestFocusExit}.
70
+ */
71
+ SetFocusMode(on: boolean): void;
72
+ /**
73
+ * Asks the live model to SPEAK a response to the supplied instructions RIGHT NOW —
74
+ * the channel's "react to this" path, e.g. a widget submission the user expects an
75
+ * audible reaction to ({@link SendContextNote} deliberately never triggers speech).
76
+ * Rides the realtime client's spoken-update channel, so on some providers the spoken
77
+ * reply is narration-kind (ephemeral, not persisted as a caption). OPTIONAL member:
78
+ * older host contexts may not supply it — plugins must call it null-safely.
79
+ */
80
+ RequestSpokenResponse?(instructions: string): void;
81
+ /**
82
+ * Persists a snapshot of the channel's state as a first-class versioned artifact
83
+ * (`MJ: Artifacts` + version, linked into conversation history when possible) — e.g. the
84
+ * whiteboard's "Save to artifacts". Distinct from {@link RealtimeChannelContext.RequestSave},
85
+ * which maintains the session's rolling state of record. Best-effort: resolves to the
86
+ * created Artifact ID, or `null` on failure (logged host-side, never thrown). Works during
87
+ * the call AND right after it ends (the host retains the session id for late saves).
88
+ */
89
+ SaveAsArtifact(name: string, contentJson: string): Promise<string | null>;
90
+ /**
91
+ * The live `MJ: AI Agent Sessions` id this channel belongs to, or `null` before the
92
+ * session has minted / after it has torn down. A channel whose tools or surface drive a
93
+ * SERVER-SIDE resource (e.g. the Remote Browser channel's server-hosted browser) passes
94
+ * this as the `agentSessionID` argument to its own GraphQL resolvers via
95
+ * {@link ExecuteServerAction}. Most channels (whiteboard, shared doc) keep all state
96
+ * client-side and never read it.
97
+ */
98
+ AgentSessionID: string | null;
99
+ /**
100
+ * Executes a CHANNEL-SPECIFIC GraphQL operation against the session's MJ server — the
101
+ * escape hatch for channels backed by a SERVER-SIDE resource that the generic
102
+ * {@link RequestSave} / {@link SaveAsArtifact} contract doesn't cover (e.g. the Remote
103
+ * Browser channel driving a server-hosted browser through its own
104
+ * `ExecuteRemoteBrowserAction` mutation + `RemoteBrowserSnapshot` query).
105
+ *
106
+ * The host runs the operation through the SAME provider the live session uses, so the
107
+ * request rides the authenticated session. Best-effort and tolerant: a transport or
108
+ * server error resolves to `null` (logged host-side) rather than throwing, so a channel
109
+ * can map the failure to a model-readable result string without `try/catch`.
110
+ *
111
+ * @typeParam TResult The expected shape of the GraphQL operation's data payload.
112
+ * @param query The GraphQL query/mutation document.
113
+ * @param variables The operation variables (all JSON-serializable).
114
+ * @returns The operation's `data` payload, or `null` on any failure / when no session is live.
115
+ */
116
+ ExecuteServerAction<TResult>(query: string, variables: Record<string, JSONValue>): Promise<TResult | null>;
117
+ /**
118
+ * OPTIONAL — the live app-context stream (where the user is, what they see, and the available
119
+ * client-tool + agent manifest), pushed by the host (Explorer) at session start and on subsequent
120
+ * changes. The headless `ClientContextChannel` subscribes to this and streams deltas to the model
121
+ * via {@link SendContextNote}. Absent on hosts that don't supply app context (e.g. custom apps);
122
+ * channels must read it null-safely.
123
+ */
124
+ AppContext$?: Observable<AppContextSnapshot | null>;
125
+ /**
126
+ * OPTIONAL — executes a host-registered surface CLIENT TOOL by name (the handlers the host wired
127
+ * from the active surface's `SetAgentClientTools`). The headless `ClientContextChannel`'s
128
+ * `ContextTool` proxy routes the model's `{ action, params }` here so a surface tool runs in the
129
+ * browser with no server round-trip. Best-effort and tolerant — resolves to a structured result
130
+ * (never throws); `Success: false` for an unknown tool or a thrown handler. Absent on hosts that
131
+ * register no client tools.
132
+ *
133
+ * @param name The client-tool name (the model's `action`).
134
+ * @param params The tool parameters (the model's `params`).
135
+ * @returns A structured result the channel serializes back to the model.
136
+ */
137
+ ExecuteClientTool?(name: string, params: Record<string, unknown>): Promise<{
138
+ Success: boolean;
139
+ Result?: unknown;
140
+ ErrorMessage?: string;
141
+ }>;
142
+ /**
143
+ * OPTIONAL — sends a visual frame into the live session's inbound video track
144
+ * (e.g. from Whiteboard or Remote Browser video bridges). No-op when the session
145
+ * has not established an inbound video track or is not live.
146
+ *
147
+ * @param base64Image The image data (base64-encoded JPEG/PNG).
148
+ * @param mimeType The image MIME type (defaults to 'image/jpeg').
149
+ */
150
+ SendVideoFrame?(base64Image: string, mimeType?: string): void;
151
+ /**
152
+ * OPTIONAL — checks whether a media track is currently established on the live session.
153
+ */
154
+ IsTrackEstablished?(modality: string, direction: RealtimeTrackDirection): boolean;
155
+ /**
156
+ * OPTIONAL — the underlying {@link BaseRealtimeClient} driving the media and transport planes.
157
+ */
158
+ Client?: BaseRealtimeClient | null;
159
+ }
160
+ /**
161
+ * The first-run INTRO content for an interactive channel — the concise "what is this surface
162
+ * and how do I use it" copy the overlay shows the very first time a user opens this channel's
163
+ * tab (persisted "seen" per user, so it's shown ONCE per channel per user).
164
+ *
165
+ * A channel opts in by overriding {@link BaseRealtimeChannelClient.GetOnboardingDetails}; the
166
+ * default returns `null`, so the base Voice/text channel (which has no plugin at all) AND any
167
+ * plugin that doesn't override it show nothing.
168
+ */
169
+ export interface ChannelOnboardingDetails {
170
+ /** Short title, usually the surface name (e.g. `"Whiteboard"`). */
171
+ Heading: string;
172
+ /** One or two sentences: what the surface is and what the user can expect to see on it. */
173
+ Description: string;
174
+ /** Optional quick-tip bullets (kept to 2-3 short, scannable lines). */
175
+ Tips?: string[];
176
+ /** Optional Font Awesome icon class for the intro panel (e.g. `'fa-solid fa-chalkboard'`). */
177
+ IconClass?: string;
178
+ }
179
+ /**
180
+ * Base class for CLIENT-SIDE interactive-channel plugins (per
181
+ * `plans/ai-agent-sessions.md` → "Interactive Channels" / "Pluggable Channel Interfaces").
182
+ *
183
+ * An interactive channel is a bidirectional surface the session's single realtime agent
184
+ * both PERCEIVES and ACTS UPON (whiteboard, shared doc, map, …). A concrete plugin
185
+ * contributes everything the channel needs, so the session service / call overlay carry
186
+ * ZERO channel-specific wiring:
187
+ *
188
+ * 1. a CLIENT-EXECUTED TOOL SET ({@link GetToolDefinitions}, declared to the realtime
189
+ * model at session mint) plus the local executor ({@link ApplyAgentTool}) the host
190
+ * routes `{@link ToolNamePrefix}*` calls to — the ACTION direction;
191
+ * 2. a STATE→CONTEXT SERIALIZER policy — the plugin owns its state engine and pushes
192
+ * coalesced deltas through {@link RealtimeChannelContext.SendContextNote} — the
193
+ * PERCEPTION direction;
194
+ * 3. an OPTIONAL ANGULAR SURFACE ({@link GetSurfaceComponent}) the overlay creates dynamically
195
+ * in a channel tab, handed back through {@link BindSurface} so the plugin wires its own
196
+ * inputs/outputs (the host never knows the component's API). A channel may be **server-only**
197
+ * (no rendered surface) — e.g. a bridge-contributed meeting-controls or native-whiteboard
198
+ * channel whose surface lives on the external platform, not in MJ. Such a channel returns
199
+ * `null` from {@link GetSurfaceComponent} ({@link HasSurface} is `false`) and the overlay
200
+ * simply skips its tab while still wiring its tools + perception;
201
+ * 4. a STATE OF RECORD ({@link SerializeState}, persisted via
202
+ * {@link RealtimeChannelContext.RequestSave} under {@link ChannelName}).
203
+ *
204
+ * ### Registration & resolution (mirrors the realtime model drivers)
205
+ * Concrete plugins are `@RegisterClass(BaseRealtimeChannelClient, '<ClientPluginClass>')`
206
+ * and are resolved at session start from the `MJ: AI Agent Channels` registry: each ACTIVE
207
+ * row's `ClientPluginClass` is the ClassFactory key (exactly how `BaseRealtimeClient`
208
+ * drivers resolve by provider key). Ship a `Load<YourChannel>()` no-op alongside the class
209
+ * and call it from a static code path to defeat tree-shaking.
210
+ *
211
+ * ### Lifecycle — ONE INSTANCE PER SESSION (not a singleton)
212
+ * `ClassFactory.CreateInstance` → {@link Initialize}(ctx) → zero or more
213
+ * {@link BindSurface}/{@link UnbindSurface} cycles (the surface pane is created/destroyed
214
+ * with the overlay's tab panel, e.g. collapse/expand) → {@link Dispose} at teardown.
215
+ * {@link ApplyAgentTool} MUST work with NO surface bound (apply to the state engine
216
+ * directly; skip the UI garnish) — tool calls can arrive while the panel is collapsed.
217
+ *
218
+ * @typeParam TSurface The plugin's Angular surface component type. The host only ever
219
+ * sees the default (`object`) — the typed parameter exists so concrete plugins get a
220
+ * fully typed {@link BindSurface} without casts.
221
+ */
222
+ export declare abstract class BaseRealtimeChannelClient<TSurface extends object = object> {
223
+ /**
224
+ * The host context, available from {@link Initialize} until {@link Dispose}.
225
+ * `null` outside that window — guard with `?.` in any code that can run early/late.
226
+ */
227
+ protected Context: RealtimeChannelContext | null;
228
+ /**
229
+ * The channel definition name — MUST match the `MJ: AI Agent Channels` row's `Name`
230
+ * (e.g. `'Whiteboard'`). Used as the persistence key for {@link SerializeState} saves
231
+ * and as the channel tab's stable key.
232
+ */
233
+ abstract get ChannelName(): string;
234
+ /**
235
+ * The shared name prefix of every tool this channel exposes (e.g. `'Whiteboard_'`).
236
+ * The host registers ONE local-execution route per plugin: tool calls whose name starts
237
+ * with this prefix go to {@link ApplyAgentTool} instead of the server relay.
238
+ */
239
+ abstract get ToolNamePrefix(): string;
240
+ /** Label for the channel's tab on the overlay's surface panel (e.g. `'Whiteboard'`). */
241
+ abstract get TabTitle(): string;
242
+ /** Font Awesome icon class for the channel's tab (e.g. `'fa-solid fa-chalkboard'`). */
243
+ abstract get TabIcon(): string;
244
+ /**
245
+ * OPTIONAL accent color for the channel's tab (a CSS color string, e.g. an `hsl()` /
246
+ * token). When a plugin supplies one, the overlay paints the tab's dot + active underline
247
+ * with it; when omitted (the default `null`), the overlay derives a stable, deterministic
248
+ * color from the {@link ChannelName} so every channel still reads as a distinct, colored
249
+ * surface. A channel only overrides this to enforce a specific brand accent.
250
+ */
251
+ get TabColor(): string | null;
252
+ /**
253
+ * The channel's CLIENT-EXECUTED tool declarations, aggregated by the session service
254
+ * into the `clientTools` set declared to the realtime model at session mint. The server
255
+ * only DECLARES these — execution stays in the browser via {@link ApplyAgentTool}.
256
+ */
257
+ abstract GetToolDefinitions(): RealtimeToolDefinition[];
258
+ /**
259
+ * Executes ONE agent tool call locally (the ACTION direction) and returns the result
260
+ * JSON string fed back to the model as the `tool_response`. Called for every tool whose
261
+ * name starts with {@link ToolNamePrefix}. Must work both WITH a bound surface (apply +
262
+ * UI garnish) and WITHOUT one (apply to the state engine directly — the tab pane may not
263
+ * exist, e.g. the surface panel is collapsed). Should not throw: return a
264
+ * `{ success: false, error }` payload so the model can narrate the failure (the host
265
+ * additionally wraps anything thrown).
266
+ */
267
+ abstract ApplyAgentTool(toolName: string, argsJson: string): string | Promise<string>;
268
+ /**
269
+ * The Angular component the overlay creates dynamically as this channel's tab pane, or `null`
270
+ * for a **server-only** channel that renders no MJ surface (its surface, if any, lives on the
271
+ * external platform — e.g. a bridge-contributed native whiteboard or meeting-controls channel).
272
+ *
273
+ * When this returns `null`, the overlay renders NO tab for the channel and never calls
274
+ * {@link BindSurface}/{@link UnbindSurface} — but the channel's tools ({@link GetToolDefinitions} /
275
+ * {@link ApplyAgentTool}) and perception ({@link RealtimeChannelContext.SendContextNote}) still run.
276
+ * A created surface instance is handed straight back via {@link BindSurface}; the host treats it as
277
+ * opaque.
278
+ *
279
+ * Default: `null` (server-only). A channel with a rendered surface overrides this to return its
280
+ * component type.
281
+ */
282
+ GetSurfaceComponent(): RealtimeSurfaceComponentType | null;
283
+ /**
284
+ * Whether this channel has a rendered MJ surface ({@link GetSurfaceComponent} returns non-null).
285
+ * The overlay uses this to decide whether to register a surface tab; server-only channels are
286
+ * `false`. Override only if surface availability must be decided WITHOUT constructing the type
287
+ * (the default calls {@link GetSurfaceComponent} once).
288
+ */
289
+ HasSurface(): boolean;
290
+ /**
291
+ * The channel's FIRST-RUN INTRO content, or `null` when the channel offers no onboarding.
292
+ * The overlay shows this once per channel per user — the first time the user opens this
293
+ * channel's surface tab — and remembers "seen" via the user's settings (NOT localStorage),
294
+ * so it never re-appears on later sessions or other devices.
295
+ *
296
+ * Default: `null` (no intro). The base Voice/text channel has no plugin at all, so it never
297
+ * shows an intro; an interactive channel with a surface worth explaining (whiteboard, remote
298
+ * browser, …) overrides this to return its {@link ChannelOnboardingDetails}. A plugin that
299
+ * doesn't override it simply shows nothing — onboarding is strictly opt-in.
300
+ */
301
+ GetOnboardingDetails(): ChannelOnboardingDetails | null;
302
+ /**
303
+ * Called by the host right after it created the surface component (and BEFORE the
304
+ * component's first change detection, so inputs set here are visible in its `ngOnInit`).
305
+ * The plugin — which knows its own component type — sets inputs (state engine, agent
306
+ * name, …) and subscribes outputs here, wiring perception/garnish flows back through
307
+ * {@link Context}. May be called again with a NEW instance after an
308
+ * {@link UnbindSurface} (the pane is destroyed/recreated with the tab panel).
309
+ */
310
+ abstract BindSurface(instance: TSurface): void;
311
+ /**
312
+ * Called by the host when the surface component is being destroyed (tab panel
313
+ * collapsed / overlay torn down). Drop the instance reference and unsubscribe any
314
+ * output subscriptions — after this, {@link ApplyAgentTool} runs in its no-surface
315
+ * mode. Default: no-op.
316
+ */
317
+ UnbindSurface(): void;
318
+ /**
319
+ * Binds the host context and invokes the {@link OnInitialize} hook. Called exactly once
320
+ * per session, right after ClassFactory instantiation and before any tool call or
321
+ * surface bind.
322
+ */
323
+ Initialize(ctx: RealtimeChannelContext): void;
324
+ /**
325
+ * Subclass hook invoked from {@link Initialize} once {@link Context} is bound — wire
326
+ * state-engine subscriptions (e.g. state change → `Context.RequestSave(...)`) here.
327
+ * Default: no-op.
328
+ */
329
+ protected OnInitialize(): void;
330
+ /**
331
+ * Subclass hook invoked once the realtime session is connected and live (the client driver
332
+ * is created, connected, and media tracks negotiated). Channels that establish media bridges
333
+ * (e.g. video streaming) can start them here when `Context.Client` is available.
334
+ * Default: no-op.
335
+ */
336
+ OnSessionStarted(): void;
337
+ /**
338
+ * Max time {@link ResolveAgentSessionId} waits for the session id to bind before giving up, and the
339
+ * poll interval it re-checks on. Protected so tests can shrink the wait; production keeps the
340
+ * defaults (the real mint race is sub-second, 8s is generous headroom).
341
+ */
342
+ protected SessionIdWaitTimeoutMs: number;
343
+ protected SessionIdWaitIntervalMs: number;
344
+ /**
345
+ * Resolves the live {@link RealtimeChannelContext.AgentSessionID}, briefly WAITING for it when it
346
+ * isn't bound yet rather than giving up instantly. `AgentSessionID` is a live getter over the
347
+ * session service's current id: it reads `null` in the window BEFORE the session mints (the
348
+ * realtime model can fire a tool call the very first beat it connects, before `mintSession`
349
+ * resolves) and again AFTER teardown. Server-backed tool paths (e.g. the Remote Browser channel's
350
+ * `browser_*` tools) call this instead of reading `Context?.AgentSessionID` synchronously, so a tool
351
+ * invoked a beat early WAITS for the session to come live — defense-in-depth against the
352
+ * "session id missing" race — instead of returning a hard failure to the model.
353
+ *
354
+ * Returns the id as soon as it's non-null (the common path resolves immediately, no delay), or
355
+ * `null` if it's still unbound after {@link SessionIdWaitTimeoutMs} — or the channel was
356
+ * {@link Dispose}d in the meantime (`Context` goes null, so we stop waiting on a torn-down session).
357
+ */
358
+ protected ResolveAgentSessionId(): Promise<string | null>;
359
+ /**
360
+ * Serializes the channel's current state of record (the payload persisted on the
361
+ * session's channel row), or `null` when the channel keeps no persistent state.
362
+ * Default: `null`.
363
+ */
364
+ SerializeState(): string | null;
365
+ /**
366
+ * Restores a PRIOR session's saved channel state (the payload a previous session
367
+ * persisted via {@link SerializeState} / {@link RealtimeChannelContext.RequestSave}).
368
+ * Invoked by the session host AFTER {@link Initialize} and BEFORE any surface binding,
369
+ * when a prior session's saved state exists for this channel.
370
+ *
371
+ * Returns `true` when the state was applied; `false` when the channel ignored it —
372
+ * either because it keeps no persistent state (this default) or because the payload was
373
+ * malformed/incompatible. Implementations MUST be tolerant: never throw on bad input,
374
+ * just return `false` and start fresh.
375
+ */
376
+ RestoreState(stateJson: string): boolean;
377
+ /**
378
+ * The focus pill's "exit" affordance, routed by the overlay to the channel that holds
379
+ * focus. Implementations should leave focus mode through their OWN surface (so surface
380
+ * toggles stay in sync), ultimately emitting `Context.SetFocusMode(false)`. The overlay
381
+ * defensively clears its layout flag as well, so a no-op default is safe.
382
+ */
383
+ RequestFocusExit(): void;
384
+ /**
385
+ * Media tracks this client channel can SOURCE — samples flowing into the model.
386
+ * Default `[]`.
387
+ */
388
+ GetSourcedTracks(): readonly RealtimeTrackDescriptor[];
389
+ /**
390
+ * Media tracks this client channel can SINK — samples flowing from the model OUT.
391
+ * Default `[]`.
392
+ */
393
+ GetSunkTracks(): readonly RealtimeTrackDescriptor[];
394
+ /**
395
+ * Tears the plugin down at session end: release the surface binding, unsubscribe
396
+ * state-engine subscriptions, then drop the context. Subclasses overriding this MUST
397
+ * call `super.Dispose()`. Any final state save has already been flushed by the host
398
+ * (the debounced {@link RealtimeChannelContext.RequestSave} pipeline) before disposal.
399
+ */
400
+ Dispose(): void;
401
+ }
402
+ //# sourceMappingURL=base-realtime-channel-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-realtime-channel-client.d.ts","sourceRoot":"","sources":["../../src/channels/base-realtime-channel-client.ts"],"names":[],"mappings":"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"}