@memberjunction/ai 5.40.1 → 5.41.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.
@@ -0,0 +1,468 @@
1
+ import { BaseModel } from "./baseModel.js";
2
+ /**
3
+ * A JSON-serializable value. Used to type open configuration bags and JSON-schema
4
+ * objects at the Core layer without resorting to `any`.
5
+ */
6
+ export type JSONValue = string | number | boolean | null | JSONValue[] | {
7
+ [key: string]: JSONValue;
8
+ };
9
+ /**
10
+ * A JSON object — the common shape for a JSON-schema document or an open,
11
+ * provider-specific configuration bag.
12
+ */
13
+ export type JSONObject = {
14
+ [key: string]: JSONValue;
15
+ };
16
+ /**
17
+ * Base class for real-time, full-duplex, tool-calling models.
18
+ *
19
+ * `BaseRealtimeModel` is the lowest-level primitive for streaming, bidirectional models
20
+ * (e.g. Google Gemini Live, OpenAI GPT Realtime, and — as a fast-follow — the Eleven Labs
21
+ * stack). It is a sibling of {@link BaseModel}-derived capability classes such as `BaseLLM`
22
+ * and `BaseAudioGenerator`, and is resolved through the MemberJunction `ClassFactory` by
23
+ * `AIModelType` + `DriverClass`.
24
+ *
25
+ * The contract is deliberately **modality-agnostic** — *streaming, full-duplex, tool-calling* —
26
+ * so the same primitive covers voice now and video later. It is distinct from
27
+ * `BaseAudioGenerator`, which is request/response STT/TTS (a different shape, not the
28
+ * real-time path).
29
+ *
30
+ * **Driver registration:** Concrete drivers ship in the respective `@memberjunction/ai-*`
31
+ * provider packages and self-register via the class factory, e.g.
32
+ * `@RegisterClass(BaseRealtimeModel, 'GeminiRealtime')`. The associated `MJ: AI Models`
33
+ * are typed with the `AIModelType` value **`Realtime`**.
34
+ *
35
+ * ## DRIVER AUTHOR OBLIGATIONS
36
+ *
37
+ * Hard-won, provider-independent rules every server-side realtime driver (and its
38
+ * client-direct twin — see `BaseRealtimeClient` in `@memberjunction/ai-realtime-client`)
39
+ * MUST honor. Most were paid for in live debugging; do not relearn them:
40
+ *
41
+ * 1. **Silent exit from "speaking" after a tool call.** When the model emits a tool call,
42
+ * the host typically shows its own busy ("thinking") indicator while the tool executes.
43
+ * A driver that surfaces UI state must leave any "speaking" state *silently* (no state
44
+ * emission) at tool-call time so the turn's trailing frames don't clobber the host's
45
+ * indicator.
46
+ * 2. **Busy-flag release on tool-call emission (deadlock guard).** A tool-call frame means
47
+ * the model has yielded the floor pending the result. Any internal "response active" /
48
+ * busy flag MUST be cleared at that point — otherwise the eventual `SendToolResult` (or
49
+ * a queued send) deadlocks waiting for a turn boundary that will never arrive until
50
+ * after the result is sent.
51
+ * 3. **Playback flush + honest playback reporting on interruption.** On a true barge-in the
52
+ * driver (or its client twin) must flush any locally-owned audio playback and report
53
+ * "audio playing = false" promptly — stale queued audio after an interruption is a
54
+ * product bug, not a nicety.
55
+ * 4. **Text injection must NOT echo a user transcript.** A "send typed text" capability
56
+ * must not synthesize a user-role transcript event for the injected text — the host owns
57
+ * the local echo and would render the message twice.
58
+ * 5. **Tool-result delivery invariant.** Every tool result fed back via
59
+ * {@link IRealtimeSession.SendToolResult} must EVENTUALLY be voiced/processed by the
60
+ * model and must never be dropped. If the provider rejects overlapping generation
61
+ * triggers, the driver queues the result's trigger behind the in-flight response and
62
+ * flushes it at the next turn boundary.
63
+ * 6. **Token/credential expiry surfaces as a FATAL error.** When the session's credential
64
+ * dies (ephemeral token expiry, auth revocation), the driver must surface it through
65
+ * {@link IRealtimeSession.OnError} with `Fatal: true` so the consumer finalizes cleanly
66
+ * instead of idling forever on a dead socket.
67
+ * 7. **"Ready" only after the session config is applied.** A driver (or client twin) must
68
+ * not report the session as live/listening until the server-built session config
69
+ * (system prompt + tools) has actually been applied to the provider socket — otherwise
70
+ * early turns run against an unconfigured model.
71
+ * 8. **`SessionConfig` is a private pact.** The {@link ClientRealtimeSessionConfig.SessionConfig}
72
+ * payload a server driver mints is consumed ONLY by the same-keyed client driver. Hosts
73
+ * and intermediaries treat it as an opaque blob; its shape may change between the two
74
+ * driver halves without notice.
75
+ *
76
+ * @abstract
77
+ */
78
+ export declare abstract class BaseRealtimeModel extends BaseModel {
79
+ /**
80
+ * Opens a stateful duplex session with the provider.
81
+ *
82
+ * The returned {@link IRealtimeSession} is the long-lived handle that streams media and
83
+ * transcripts in both directions, surfaces tool calls and usage telemetry, and reports
84
+ * provider-detected interruptions (barge-in). The caller is responsible for closing the
85
+ * session via {@link IRealtimeSession.Close}.
86
+ *
87
+ * @param params Configuration for the session (system prompt, tools, initial context, model, and an open config bag).
88
+ * @returns A promise resolving to the live session handle.
89
+ */
90
+ abstract StartSession(params: RealtimeSessionParams): Promise<IRealtimeSession>;
91
+ /**
92
+ * Whether this driver can mint an ephemeral, server-scoped client credential for a
93
+ * **client-direct** realtime session (the browser opens its own provider socket using a
94
+ * short-lived token the server minted).
95
+ *
96
+ * Defaults to `false`. Providers that support browser-direct sessions override this to `true`
97
+ * and implement {@link CreateClientSession}. The server-bridged topology (where the provider
98
+ * socket lives on the server, via {@link StartSession}) is supported by every driver regardless
99
+ * of this flag.
100
+ *
101
+ * @returns `true` if {@link CreateClientSession} is supported; `false` otherwise.
102
+ */
103
+ get SupportsClientDirect(): boolean;
104
+ /**
105
+ * Mints an ephemeral, server-scoped client credential plus a provider-native session config for
106
+ * a **client-direct** realtime session.
107
+ *
108
+ * In the client-direct topology the browser owns the provider socket (e.g. WebRTC), but the
109
+ * **server** still controls the prompt and tool set: it mints a short-lived token and hands back
110
+ * a {@link ClientRealtimeSessionConfig} whose `SessionConfig` the matching client driver applies
111
+ * when it opens its socket. This keeps prompt/tool authority server-side even though the media
112
+ * plane is client-direct.
113
+ *
114
+ * Not every provider supports this (some only expose a server-bridged socket), so this is a
115
+ * concrete method that throws by default rather than an abstract one — that would force every
116
+ * existing and future driver to implement it. Providers that support it override
117
+ * {@link SupportsClientDirect} to `true` and override this method.
118
+ *
119
+ * @param _params The session parameters (system prompt, tools, model, config bag).
120
+ * @returns A promise resolving to the minted {@link ClientRealtimeSessionConfig}.
121
+ * @throws Always, unless overridden by a provider that supports client-direct sessions.
122
+ */
123
+ CreateClientSession(_params: RealtimeSessionParams): Promise<ClientRealtimeSessionConfig>;
124
+ }
125
+ /**
126
+ * The server-minted configuration a browser needs to open a **client-direct** realtime session.
127
+ *
128
+ * Returned by {@link BaseRealtimeModel.CreateClientSession}. The browser authenticates to the
129
+ * provider with {@link ClientRealtimeSessionConfig.EphemeralToken} and hands
130
+ * {@link ClientRealtimeSessionConfig.SessionConfig} to the matching client driver — so the server
131
+ * retains control of the prompt and tool set even though the browser owns the socket.
132
+ *
133
+ * **`SessionConfig` is a private pact between same-keyed driver halves.** The server driver that
134
+ * minted it (selected by {@link ClientRealtimeSessionConfig.Provider}) and the client driver
135
+ * registered under the same key are the ONLY parties that understand its shape. Hosts and any
136
+ * transport in between must treat it as an opaque, serializable blob — never inspect, edit, or
137
+ * depend on its fields.
138
+ */
139
+ export interface ClientRealtimeSessionConfig {
140
+ /**
141
+ * The provider that minted the credential (e.g. `'openai'`). Lets the browser select the
142
+ * correct provider-direct client implementation.
143
+ */
144
+ Provider: string;
145
+ /**
146
+ * The provider realtime model id the session is scoped to (e.g. `gpt-realtime`).
147
+ */
148
+ Model: string;
149
+ /**
150
+ * The short-lived client secret the browser presents to the provider to authenticate its
151
+ * direct session. Server-scoped and expiring (see {@link ClientRealtimeSessionConfig.ExpiresAt}).
152
+ */
153
+ EphemeralToken: string;
154
+ /**
155
+ * ISO-8601 timestamp at which {@link ClientRealtimeSessionConfig.EphemeralToken} expires.
156
+ */
157
+ ExpiresAt: string;
158
+ /**
159
+ * The provider-native session config the matching client driver applies when it opens its
160
+ * socket (instructions/system prompt, tools, audio formats, turn detection). Because the server
161
+ * builds this, prompt and tool authority stay server-side even in the client-direct topology.
162
+ * Typed as a JSON object so it stays serializable across the server→client boundary — but its
163
+ * SHAPE is a private pact between the same-keyed server and client drivers; hosts must treat it
164
+ * opaquely and never read or rewrite its fields.
165
+ */
166
+ SessionConfig: JSONObject;
167
+ }
168
+ /**
169
+ * A long-lived, full-duplex session handle returned by {@link BaseRealtimeModel.StartSession}.
170
+ *
171
+ * All `On*` methods register a single handler invoked as the corresponding provider events
172
+ * arrive. Drivers must be written against this interface so a mock provider socket can be
173
+ * substituted for deterministic, network-free testing.
174
+ */
175
+ export interface IRealtimeSession {
176
+ /**
177
+ * Sends a client media frame to the model (audio now, video later).
178
+ *
179
+ * Fire-and-forget: frames are streamed straight to the provider with no JSON intermediation.
180
+ *
181
+ * @param chunk A raw media frame as an `ArrayBuffer`.
182
+ */
183
+ SendInput(chunk: ArrayBuffer): void;
184
+ /**
185
+ * Registers the set of tools the model may call, translating them into the provider's
186
+ * native function-calling format.
187
+ *
188
+ * The Core-level {@link RealtimeToolDefinition} is intentionally minimal: `BaseRealtimeModel`
189
+ * lives in the lowest AI layer and cannot depend on the richer tool metadata defined in
190
+ * higher packages (the agent layer) — doing so would create an illegal upward/circular
191
+ * dependency. The agent layer is responsible for **mapping its richer tool metadata down**
192
+ * to this Core type before calling `RegisterTools`, and the concrete driver maps this Core
193
+ * type **up** to the provider's native function-calling schema.
194
+ *
195
+ * Note that some providers (e.g. Eleven Labs) bind to a pre-declared tool set on a
196
+ * server-side agent configuration; for those, the driver maps these definitions onto the
197
+ * pre-declared tool names rather than registering arbitrary schemas at session start.
198
+ *
199
+ * **Idempotency rule:** a post-start registration of a set IDENTICAL to the set supplied at
200
+ * connect time (via {@link RealtimeSessionParams.Tools}) MUST be a no-op. Providers that bind
201
+ * their tool set at connect time and cannot re-declare schemas on an open session MUST no-op
202
+ * (and may log) rather than degrade the conversation — e.g. by injecting schema text into the
203
+ * conversation as content. A genuinely DIFFERENT post-start set on such a provider is
204
+ * unsupported and should be surfaced as a warning, not silently mangled.
205
+ *
206
+ * @param tools The tools to expose to the model.
207
+ */
208
+ RegisterTools(tools: RealtimeToolDefinition[]): Promise<void>;
209
+ /**
210
+ * Registers a handler for model media output frames (the media plane).
211
+ *
212
+ * @param handler Invoked with each output media frame as an `ArrayBuffer`.
213
+ */
214
+ OnOutput(handler: (chunk: ArrayBuffer) => void): void;
215
+ /**
216
+ * Registers a handler for transcript events (the text stream).
217
+ *
218
+ * Consumers typically forward these to the control plane and persist them as
219
+ * `ConversationDetail` records.
220
+ *
221
+ * @param handler Invoked with each {@link RealtimeTranscript} (partial or final).
222
+ */
223
+ OnTranscript(handler: (t: RealtimeTranscript) => void): void;
224
+ /**
225
+ * Registers a handler for model tool-call requests.
226
+ *
227
+ * Consumers execute the requested tool (under the session's context user) and feed the
228
+ * result back to the model.
229
+ *
230
+ * @param handler Invoked with each {@link RealtimeToolCall}.
231
+ */
232
+ OnToolCall(handler: (call: RealtimeToolCall) => void): void;
233
+ /**
234
+ * Send the result of an executed tool/function call back to the model so it can continue the
235
+ * turn. `output` is the JSON-stringified tool result. Called by the agent layer after it handles
236
+ * an {@link IRealtimeSession.OnToolCall}.
237
+ *
238
+ * @param callID The `CallID` from the originating {@link RealtimeToolCall}, used to correlate the result.
239
+ * @param output The tool's result as a JSON-stringified string.
240
+ * @returns A promise that resolves once the result has been sent to the provider.
241
+ */
242
+ SendToolResult(callID: string, output: string): Promise<void>;
243
+ /**
244
+ * **Optional capability** — injects background context (e.g. delegated-run progress, freshly
245
+ * retrieved data, or a state change the model should be aware of) into the model's
246
+ * conversation **without** forcing a spoken reply. The model simply has the note available
247
+ * the next time it speaks.
248
+ *
249
+ * This is the server-side counterpart of the client-direct `BaseRealtimeClient.SendContextNote`
250
+ * capability: in the server-bridged topology, the agent layer (e.g. a session runner observing
251
+ * a delegated agent run) calls this to keep the realtime model informed of long-running work
252
+ * so it can narrate naturally when asked or when it next takes the floor.
253
+ *
254
+ * Optionality models **capability**, not laziness: not every provider supports injecting
255
+ * conversation items into an already-open session (some only accept media frames and tool
256
+ * results mid-session). Drivers that cannot inject mid-session omit the member entirely, and
257
+ * callers must feature-detect (`if (session.SendContextNote) { ... }`) rather than assume it.
258
+ *
259
+ * @param text The context note to append to the conversation (plain text; the caller owns any
260
+ * prefixing/framing policy such as "[progress]" markers).
261
+ */
262
+ SendContextNote?(text: string): void;
263
+ /**
264
+ * **Optional capability** — asks the model to voice **one brief interim update** following the
265
+ * given instructions (e.g. "In one short sentence, tell the user the report agent has finished
266
+ * gathering data and is now drafting"). Used by the agent layer to narrate delegated-run
267
+ * progress while a long-running tool/agent call is still in flight.
268
+ *
269
+ * Implementations **must not collide with an in-flight model response**: providers reject or
270
+ * garble overlapping generation requests. A driver must either queue the request until the
271
+ * current response completes or skip it outright — skipping is explicitly acceptable because
272
+ * interim updates are disposable by contract (a stale "still working…" line has no value once
273
+ * the real result lands; the next update or the final result supersedes it).
274
+ *
275
+ * Like {@link IRealtimeSession.SendContextNote}, this is optional because it models provider
276
+ * capability: drivers whose provider cannot trigger an instructed, one-off spoken response
277
+ * mid-session omit the member, and callers must feature-detect before invoking.
278
+ *
279
+ * @param instructions Instructions for the single spoken update (tone, brevity, content).
280
+ */
281
+ RequestSpokenUpdate?(instructions: string): void;
282
+ /**
283
+ * Registers a handler for provider-detected interruptions (barge-in).
284
+ *
285
+ * **True barge-in only:** the handler fires ONLY when user speech interrupts ACTIVE model
286
+ * output — NOT on every user utterance. A user simply taking their normal turn while the
287
+ * model is idle is not an interruption, and drivers must not report it as one (e.g. a raw
288
+ * "speech started" frame must be gated on whether a model response is actually in flight).
289
+ *
290
+ * Turn detection / VAD is owned by the provider. The agent layer uses this hook to cancel
291
+ * the model's current turn **and** to fire the `cancellationToken` of any in-flight
292
+ * delegated agent run — a stale delegated result must never be narrated into a conversation
293
+ * that has moved on.
294
+ *
295
+ * @param handler Invoked when the provider reports a true barge-in interruption.
296
+ */
297
+ OnInterruption(handler: () => void): void;
298
+ /**
299
+ * Registers a handler for session errors.
300
+ *
301
+ * Fatality semantics mirror the client-side `BaseRealtimeClient` contract:
302
+ * - `Fatal: true` — the session is unusable (transport/socket failure, credential/token
303
+ * expiry, unexpected connection loss). The consumer should finalize the session (e.g.
304
+ * `RealtimeSessionRunner` calls `Stop()`) instead of idling forever on a dead socket.
305
+ * - `Fatal: false` — a provider-reported, recoverable error frame; the session stays open
306
+ * and the consumer should log and continue.
307
+ *
308
+ * @param handler Invoked with each {@link RealtimeSessionError}.
309
+ */
310
+ OnError(handler: (error: RealtimeSessionError) => void): void;
311
+ /**
312
+ * **Optional capability** — registers a handler invoked when the underlying provider
313
+ * connection closes WITHOUT the consumer having called {@link IRealtimeSession.Close}
314
+ * (provider-side hangup, network drop). Not fired for a consumer-initiated `Close()` —
315
+ * the caller already knows about that one.
316
+ *
317
+ * Optional because not every provider surface exposes a close signal cheaply; callers
318
+ * must feature-detect (`if (session.OnClose) { ... }`). An unexpected close is typically
319
+ * ALSO surfaced as a `Fatal` {@link IRealtimeSession.OnError}, which is the signal
320
+ * consumers should drive finalization from.
321
+ *
322
+ * @param handler Invoked when the provider connection closes unexpectedly.
323
+ */
324
+ OnClose?(handler: () => void): void;
325
+ /**
326
+ * Registers a handler for usage/telemetry updates.
327
+ *
328
+ * Usage is checkpointed incrementally by the agent layer (debounced onto the prompt run) so
329
+ * partial usage is never lost if the session is force-closed after a crash.
330
+ *
331
+ * @param handler Invoked with each {@link RealtimeUsage} update.
332
+ */
333
+ OnUsage(handler: (u: RealtimeUsage) => void): void;
334
+ /**
335
+ * Closes the session and releases the underlying provider connection.
336
+ *
337
+ * @returns A promise that resolves once the session is fully closed.
338
+ */
339
+ Close(): Promise<void>;
340
+ }
341
+ /**
342
+ * Parameters used to open a {@link IRealtimeSession} via {@link BaseRealtimeModel.StartSession}.
343
+ */
344
+ export interface RealtimeSessionParams {
345
+ /**
346
+ * The API name of the realtime model to use (the `MJ: AI Model Vendors` API name for the
347
+ * driver's provider).
348
+ */
349
+ Model: string;
350
+ /**
351
+ * The system prompt that establishes the model's persona and behavior for the session.
352
+ */
353
+ SystemPrompt: string;
354
+ /**
355
+ * Optional set of tools to register at session start. Equivalent to calling
356
+ * {@link IRealtimeSession.RegisterTools} immediately after the session opens; drivers may
357
+ * register these eagerly when the provider accepts tool schemas at session start.
358
+ */
359
+ Tools?: RealtimeToolDefinition[];
360
+ /**
361
+ * Optional initial context to seed the conversation (e.g. the prior conversation history
362
+ * and retrieved memory) so the model starts with the same context a loop agent assembles.
363
+ */
364
+ InitialContext?: string;
365
+ /**
366
+ * Optional open, provider-specific configuration bag (e.g. voice, language, turn-taking
367
+ * settings, or per-conversation override fields). Typed as a JSON object rather than `any`
368
+ * so it stays serializable and inspectable.
369
+ */
370
+ Config?: JSONObject;
371
+ }
372
+ /**
373
+ * A transcript event emitted by the model for either the user's speech or the assistant's
374
+ * response.
375
+ */
376
+ export interface RealtimeTranscript {
377
+ /**
378
+ * Whose turn this transcript belongs to.
379
+ */
380
+ Role: 'user' | 'assistant';
381
+ /**
382
+ * The transcribed text. For `IsFinal: false` events this is the incremental **DELTA** for
383
+ * the in-flight turn (drivers emit each new fragment, not a re-send of the accumulated
384
+ * text); for `IsFinal: true` it is the complete turn text.
385
+ */
386
+ Text: string;
387
+ /**
388
+ * Whether this is the final transcript for the turn (`true`) or an interim delta (`false`).
389
+ */
390
+ IsFinal: boolean;
391
+ }
392
+ /**
393
+ * An error surfaced by a realtime session via {@link IRealtimeSession.OnError}.
394
+ *
395
+ * Mirrors the client-side `RealtimeClientError` shape: `Fatal: true` means the session is
396
+ * unusable (transport failure, credential expiry, unexpected close) and the consumer should
397
+ * finalize; `Fatal: false` is a provider-reported, recoverable error frame.
398
+ */
399
+ export interface RealtimeSessionError {
400
+ /** Human-readable error message. */
401
+ Message: string;
402
+ /** Optional provider-specific error code. */
403
+ Code?: string;
404
+ /** Whether the error terminated the session. */
405
+ Fatal: boolean;
406
+ }
407
+ /**
408
+ * A tool-call request emitted by the model.
409
+ */
410
+ export interface RealtimeToolCall {
411
+ /**
412
+ * Provider-assigned identifier for this call, used to correlate the eventual tool result.
413
+ */
414
+ CallID: string;
415
+ /**
416
+ * The name of the tool the model is requesting to invoke.
417
+ */
418
+ ToolName: string;
419
+ /**
420
+ * The arguments for the call as a JSON string, exactly as the provider emitted them.
421
+ * Consumers parse this into the tool's expected parameter shape.
422
+ */
423
+ Arguments: string;
424
+ }
425
+ /**
426
+ * Incremental usage/telemetry reported during a realtime session.
427
+ *
428
+ * This is the realtime-specific counterpart to Core's request/response `ModelUsage`. Because a
429
+ * realtime session is long-lived and usage is reported in increments (and checkpointed
430
+ * incrementally), this type carries the token deltas a provider emits over the life of the
431
+ * session rather than a single final tally.
432
+ */
433
+ export interface RealtimeUsage {
434
+ /**
435
+ * Number of input tokens reported in this usage update.
436
+ */
437
+ InputTokens: number;
438
+ /**
439
+ * Number of output tokens reported in this usage update.
440
+ */
441
+ OutputTokens: number;
442
+ }
443
+ /**
444
+ * Minimal, Core-level definition of a tool exposed to a realtime model.
445
+ *
446
+ * This type lives in the lowest AI layer and is intentionally provider- and agent-agnostic.
447
+ * The agent layer maps its richer tool metadata **down** to this type before registering tools,
448
+ * and each concrete driver maps this type **up** to the provider's native function-calling
449
+ * schema. Keeping the Core type minimal avoids an illegal upward dependency from Core onto the
450
+ * agent packages.
451
+ */
452
+ export interface RealtimeToolDefinition {
453
+ /**
454
+ * The tool's name, used to match provider tool-call frames back to MJ tool execution.
455
+ */
456
+ Name: string;
457
+ /**
458
+ * A human-readable description of what the tool does. Surfaced to the model so it can decide
459
+ * when to call the tool.
460
+ */
461
+ Description: string;
462
+ /**
463
+ * A JSON-schema object describing the tool's parameters. Drivers translate this into the
464
+ * provider's native function-parameter schema.
465
+ */
466
+ ParametersSchema: JSONObject;
467
+ }
468
+ //# sourceMappingURL=baseRealtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseRealtime.d.ts","sourceRoot":"","sources":["../../src/generic/baseRealtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC;;;GAGG;AACH,MAAM,MAAM,SAAS,GACf,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEnC;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,8BAAsB,iBAAkB,SAAQ,SAAS;IACrD;;;;;;;;;;OAUG;aACa,YAAY,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAEtF;;;;;;;;;;;OAWG;IACH,IAAW,oBAAoB,IAAI,OAAO,CAEzC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACU,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,2BAA2B,CAAC;CAGzG;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,2BAA2B;IACxC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;;;;OAOG;IACH,aAAa,EAAE,UAAU,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC7B;;;;;;OAMG;IACH,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAEpC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,aAAa,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI,CAAC;IAEtD;;;;;;;OAOG;IACH,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,kBAAkB,KAAK,IAAI,GAAG,IAAI,CAAC;IAE7D;;;;;;;OAOG;IACH,UAAU,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,GAAG,IAAI,CAAC;IAE5D;;;;;;;;OAQG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D;;;;;;;;;;;;;;;;;;OAkBG;IACH,eAAe,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAErC;;;;;;;;;;;;;;;;;OAiBG;IACH,mBAAmB,CAAC,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjD;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAE1C;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,IAAI,CAAC;IAE9D;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAEpC;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI,CAAC;IAEnD;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,KAAK,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAEjC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAC/B;;OAEG;IACH,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAE3B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACjC,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAEhB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,gDAAgD;IAChD,KAAK,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC1B;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,sBAAsB;IACnC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,gBAAgB,EAAE,UAAU,CAAC;CAChC"}
@@ -0,0 +1,103 @@
1
+ import { BaseModel } from "./baseModel.js";
2
+ /**
3
+ * Base class for real-time, full-duplex, tool-calling models.
4
+ *
5
+ * `BaseRealtimeModel` is the lowest-level primitive for streaming, bidirectional models
6
+ * (e.g. Google Gemini Live, OpenAI GPT Realtime, and — as a fast-follow — the Eleven Labs
7
+ * stack). It is a sibling of {@link BaseModel}-derived capability classes such as `BaseLLM`
8
+ * and `BaseAudioGenerator`, and is resolved through the MemberJunction `ClassFactory` by
9
+ * `AIModelType` + `DriverClass`.
10
+ *
11
+ * The contract is deliberately **modality-agnostic** — *streaming, full-duplex, tool-calling* —
12
+ * so the same primitive covers voice now and video later. It is distinct from
13
+ * `BaseAudioGenerator`, which is request/response STT/TTS (a different shape, not the
14
+ * real-time path).
15
+ *
16
+ * **Driver registration:** Concrete drivers ship in the respective `@memberjunction/ai-*`
17
+ * provider packages and self-register via the class factory, e.g.
18
+ * `@RegisterClass(BaseRealtimeModel, 'GeminiRealtime')`. The associated `MJ: AI Models`
19
+ * are typed with the `AIModelType` value **`Realtime`**.
20
+ *
21
+ * ## DRIVER AUTHOR OBLIGATIONS
22
+ *
23
+ * Hard-won, provider-independent rules every server-side realtime driver (and its
24
+ * client-direct twin — see `BaseRealtimeClient` in `@memberjunction/ai-realtime-client`)
25
+ * MUST honor. Most were paid for in live debugging; do not relearn them:
26
+ *
27
+ * 1. **Silent exit from "speaking" after a tool call.** When the model emits a tool call,
28
+ * the host typically shows its own busy ("thinking") indicator while the tool executes.
29
+ * A driver that surfaces UI state must leave any "speaking" state *silently* (no state
30
+ * emission) at tool-call time so the turn's trailing frames don't clobber the host's
31
+ * indicator.
32
+ * 2. **Busy-flag release on tool-call emission (deadlock guard).** A tool-call frame means
33
+ * the model has yielded the floor pending the result. Any internal "response active" /
34
+ * busy flag MUST be cleared at that point — otherwise the eventual `SendToolResult` (or
35
+ * a queued send) deadlocks waiting for a turn boundary that will never arrive until
36
+ * after the result is sent.
37
+ * 3. **Playback flush + honest playback reporting on interruption.** On a true barge-in the
38
+ * driver (or its client twin) must flush any locally-owned audio playback and report
39
+ * "audio playing = false" promptly — stale queued audio after an interruption is a
40
+ * product bug, not a nicety.
41
+ * 4. **Text injection must NOT echo a user transcript.** A "send typed text" capability
42
+ * must not synthesize a user-role transcript event for the injected text — the host owns
43
+ * the local echo and would render the message twice.
44
+ * 5. **Tool-result delivery invariant.** Every tool result fed back via
45
+ * {@link IRealtimeSession.SendToolResult} must EVENTUALLY be voiced/processed by the
46
+ * model and must never be dropped. If the provider rejects overlapping generation
47
+ * triggers, the driver queues the result's trigger behind the in-flight response and
48
+ * flushes it at the next turn boundary.
49
+ * 6. **Token/credential expiry surfaces as a FATAL error.** When the session's credential
50
+ * dies (ephemeral token expiry, auth revocation), the driver must surface it through
51
+ * {@link IRealtimeSession.OnError} with `Fatal: true` so the consumer finalizes cleanly
52
+ * instead of idling forever on a dead socket.
53
+ * 7. **"Ready" only after the session config is applied.** A driver (or client twin) must
54
+ * not report the session as live/listening until the server-built session config
55
+ * (system prompt + tools) has actually been applied to the provider socket — otherwise
56
+ * early turns run against an unconfigured model.
57
+ * 8. **`SessionConfig` is a private pact.** The {@link ClientRealtimeSessionConfig.SessionConfig}
58
+ * payload a server driver mints is consumed ONLY by the same-keyed client driver. Hosts
59
+ * and intermediaries treat it as an opaque blob; its shape may change between the two
60
+ * driver halves without notice.
61
+ *
62
+ * @abstract
63
+ */
64
+ export class BaseRealtimeModel extends BaseModel {
65
+ /**
66
+ * Whether this driver can mint an ephemeral, server-scoped client credential for a
67
+ * **client-direct** realtime session (the browser opens its own provider socket using a
68
+ * short-lived token the server minted).
69
+ *
70
+ * Defaults to `false`. Providers that support browser-direct sessions override this to `true`
71
+ * and implement {@link CreateClientSession}. The server-bridged topology (where the provider
72
+ * socket lives on the server, via {@link StartSession}) is supported by every driver regardless
73
+ * of this flag.
74
+ *
75
+ * @returns `true` if {@link CreateClientSession} is supported; `false` otherwise.
76
+ */
77
+ get SupportsClientDirect() {
78
+ return false;
79
+ }
80
+ /**
81
+ * Mints an ephemeral, server-scoped client credential plus a provider-native session config for
82
+ * a **client-direct** realtime session.
83
+ *
84
+ * In the client-direct topology the browser owns the provider socket (e.g. WebRTC), but the
85
+ * **server** still controls the prompt and tool set: it mints a short-lived token and hands back
86
+ * a {@link ClientRealtimeSessionConfig} whose `SessionConfig` the matching client driver applies
87
+ * when it opens its socket. This keeps prompt/tool authority server-side even though the media
88
+ * plane is client-direct.
89
+ *
90
+ * Not every provider supports this (some only expose a server-bridged socket), so this is a
91
+ * concrete method that throws by default rather than an abstract one — that would force every
92
+ * existing and future driver to implement it. Providers that support it override
93
+ * {@link SupportsClientDirect} to `true` and override this method.
94
+ *
95
+ * @param _params The session parameters (system prompt, tools, model, config bag).
96
+ * @returns A promise resolving to the minted {@link ClientRealtimeSessionConfig}.
97
+ * @throws Always, unless overridden by a provider that supports client-direct sessions.
98
+ */
99
+ async CreateClientSession(_params) {
100
+ throw new Error(`${this.constructor.name} does not support client-direct realtime sessions`);
101
+ }
102
+ }
103
+ //# sourceMappingURL=baseRealtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseRealtime.js","sourceRoot":"","sources":["../../src/generic/baseRealtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAoBxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,MAAM,OAAgB,iBAAkB,SAAQ,SAAS;IAcrD;;;;;;;;;;;OAWG;IACH,IAAW,oBAAoB;QAC3B,OAAO,KAAK,CAAC;IACjB,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACI,KAAK,CAAC,mBAAmB,CAAC,OAA8B;QAC3D,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,mDAAmD,CAAC,CAAC;IACjG,CAAC;CACJ"}