@memberjunction/ai-agents 5.40.2 → 5.42.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.
Files changed (88) hide show
  1. package/README.md +53 -0
  2. package/dist/AgentRunner.d.ts +5 -2
  3. package/dist/AgentRunner.d.ts.map +1 -1
  4. package/dist/AgentRunner.js +14 -4
  5. package/dist/AgentRunner.js.map +1 -1
  6. package/dist/MemoryWriteManager.d.ts +188 -0
  7. package/dist/MemoryWriteManager.d.ts.map +1 -0
  8. package/dist/MemoryWriteManager.js +299 -0
  9. package/dist/MemoryWriteManager.js.map +1 -0
  10. package/dist/agent-context-injector.d.ts +29 -0
  11. package/dist/agent-context-injector.d.ts.map +1 -1
  12. package/dist/agent-context-injector.js +90 -32
  13. package/dist/agent-context-injector.js.map +1 -1
  14. package/dist/agent-memory-context-builder.d.ts +100 -0
  15. package/dist/agent-memory-context-builder.d.ts.map +1 -0
  16. package/dist/agent-memory-context-builder.js +172 -0
  17. package/dist/agent-memory-context-builder.js.map +1 -0
  18. package/dist/agent-types/index.d.ts +1 -0
  19. package/dist/agent-types/index.d.ts.map +1 -1
  20. package/dist/agent-types/index.js +1 -0
  21. package/dist/agent-types/index.js.map +1 -1
  22. package/dist/agent-types/loop-agent-response-type.d.ts +12 -1
  23. package/dist/agent-types/loop-agent-response-type.d.ts.map +1 -1
  24. package/dist/agent-types/loop-agent-response-type.js.map +1 -1
  25. package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
  26. package/dist/agent-types/loop-agent-type.js +4 -0
  27. package/dist/agent-types/loop-agent-type.js.map +1 -1
  28. package/dist/agent-types/realtime-agent-type.d.ts +146 -0
  29. package/dist/agent-types/realtime-agent-type.d.ts.map +1 -0
  30. package/dist/agent-types/realtime-agent-type.js +176 -0
  31. package/dist/agent-types/realtime-agent-type.js.map +1 -0
  32. package/dist/base-agent.d.ts +386 -39
  33. package/dist/base-agent.d.ts.map +1 -1
  34. package/dist/base-agent.js +1121 -261
  35. package/dist/base-agent.js.map +1 -1
  36. package/dist/index.d.ts +13 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +17 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/memory-manager-agent.d.ts +99 -4
  41. package/dist/memory-manager-agent.d.ts.map +1 -1
  42. package/dist/memory-manager-agent.js +349 -117
  43. package/dist/memory-manager-agent.js.map +1 -1
  44. package/dist/realtime/bridge-realtime-session-factory.d.ts +111 -0
  45. package/dist/realtime/bridge-realtime-session-factory.d.ts.map +1 -0
  46. package/dist/realtime/bridge-realtime-session-factory.js +163 -0
  47. package/dist/realtime/bridge-realtime-session-factory.js.map +1 -0
  48. package/dist/realtime/bridge-room-transcript-sink.d.ts +58 -0
  49. package/dist/realtime/bridge-room-transcript-sink.d.ts.map +1 -0
  50. package/dist/realtime/bridge-room-transcript-sink.js +127 -0
  51. package/dist/realtime/bridge-room-transcript-sink.js.map +1 -0
  52. package/dist/realtime/meeting-controls-channel-server.d.ts +198 -0
  53. package/dist/realtime/meeting-controls-channel-server.d.ts.map +1 -0
  54. package/dist/realtime/meeting-controls-channel-server.js +319 -0
  55. package/dist/realtime/meeting-controls-channel-server.js.map +1 -0
  56. package/dist/realtime/meeting-controls-state.d.ts +191 -0
  57. package/dist/realtime/meeting-controls-state.d.ts.map +1 -0
  58. package/dist/realtime/meeting-controls-state.js +219 -0
  59. package/dist/realtime/meeting-controls-state.js.map +1 -0
  60. package/dist/realtime/realtime-channel-server-host.d.ts +166 -0
  61. package/dist/realtime/realtime-channel-server-host.d.ts.map +1 -0
  62. package/dist/realtime/realtime-channel-server-host.js +378 -0
  63. package/dist/realtime/realtime-channel-server-host.js.map +1 -0
  64. package/dist/realtime/realtime-client-session-service.d.ts +1026 -0
  65. package/dist/realtime/realtime-client-session-service.d.ts.map +1 -0
  66. package/dist/realtime/realtime-client-session-service.js +1607 -0
  67. package/dist/realtime/realtime-client-session-service.js.map +1 -0
  68. package/dist/realtime/realtime-coagent-config.d.ts +258 -0
  69. package/dist/realtime/realtime-coagent-config.d.ts.map +1 -0
  70. package/dist/realtime/realtime-coagent-config.js +408 -0
  71. package/dist/realtime/realtime-coagent-config.js.map +1 -0
  72. package/dist/realtime/realtime-narration.d.ts +67 -0
  73. package/dist/realtime/realtime-narration.d.ts.map +1 -0
  74. package/dist/realtime/realtime-narration.js +127 -0
  75. package/dist/realtime/realtime-narration.js.map +1 -0
  76. package/dist/realtime/realtime-session-runner.d.ts +383 -0
  77. package/dist/realtime/realtime-session-runner.d.ts.map +1 -0
  78. package/dist/realtime/realtime-session-runner.js +532 -0
  79. package/dist/realtime/realtime-session-runner.js.map +1 -0
  80. package/dist/realtime/realtime-tool-broker.d.ts +294 -0
  81. package/dist/realtime/realtime-tool-broker.d.ts.map +1 -0
  82. package/dist/realtime/realtime-tool-broker.js +206 -0
  83. package/dist/realtime/realtime-tool-broker.js.map +1 -0
  84. package/dist/realtime/whiteboard-channel-server.d.ts +50 -0
  85. package/dist/realtime/whiteboard-channel-server.d.ts.map +1 -0
  86. package/dist/realtime/whiteboard-channel-server.js +85 -0
  87. package/dist/realtime/whiteboard-channel-server.js.map +1 -0
  88. package/package.json +17 -17
@@ -0,0 +1,408 @@
1
+ /**
2
+ * @fileoverview PURE configuration module for Realtime co-agent type configuration —
3
+ * the deep-merge + parse + normalize pipeline behind the effective-configuration contract:
4
+ *
5
+ * ```
6
+ * AIAgentType.DefaultConfiguration ← AIAgent.TypeConfiguration ← runtime overrides
7
+ * (base layer) (per-agent layer) (per-session layer)
8
+ * ```
9
+ *
10
+ * Later layers win **per key**: plain objects deep-merge, while arrays and primitives
11
+ * replace wholesale. The merged result is normalized into the typed
12
+ * {@link RealtimeCoAgentConfig} shape (wrong-typed fields are dropped, never thrown on).
13
+ *
14
+ * This module is deliberately **framework-free**: no DB, no metadata provider, no logging
15
+ * imports — every function is a pure transformation so it can be exercised exhaustively in
16
+ * unit tests and reused verbatim by the session service (`realtime-client-session-service.ts`),
17
+ * the server-bridged path (`base-agent.ts`), and the MJServer resolver
18
+ * (`RealtimeClientSessionResolver.ts`).
19
+ *
20
+ * The canonical JSON shape (the Realtime agent type's `ConfigSchema` is seeded to this):
21
+ * ```jsonc
22
+ * { "realtime": {
23
+ * "modelPreference": "<AI Model name or ID>",
24
+ * "voice": { "default": { "tone": "…", "speakingStyle": "…" },
25
+ * "providers": { "openai": { "voice": "alloy" },
26
+ * "elevenlabs": { "voiceId": "…" },
27
+ * "gemini": { "voice": "…" },
28
+ * "assemblyai": { "voice": "…" } } },
29
+ * "allowUserModelOverride": true,
30
+ * "narration": { "paceMs": 8000 } } }
31
+ * ```
32
+ *
33
+ * @module @memberjunction/ai-agents
34
+ * @author MemberJunction.com
35
+ */
36
+ /**
37
+ * The MJ Authorization name that gates RUNTIME overrides on realtime session start:
38
+ * `configOverridesJson` and explicit realtime-model selection that deviates from the
39
+ * co-agent's metadata-configured preference. Seeded in `metadata/authorizations/.realtime.json`.
40
+ */
41
+ export const REALTIME_ADVANCED_SESSION_CONTROLS_AUTHORIZATION = 'Realtime: Advanced Session Controls';
42
+ /** True for a plain JSON object (not null, not an array). */
43
+ function isPlainObject(value) {
44
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
45
+ }
46
+ /** Case/whitespace-insensitive id/name equality (UUIDs differ only by case across DB platforms). */
47
+ function idsEqual(a, b) {
48
+ if (!a || !b) {
49
+ return false;
50
+ }
51
+ return a.trim().toLowerCase() === b.trim().toLowerCase();
52
+ }
53
+ /**
54
+ * Deep-merges configuration layers, EARLIEST first — later layers win per key.
55
+ *
56
+ * Merge rules (per key):
57
+ * - plain object vs plain object → recursive deep merge;
58
+ * - anything else (arrays, strings, numbers, booleans, `null`) → the later value REPLACES;
59
+ * - `null` is a real JSON value and replaces like any primitive;
60
+ * - `undefined` values in a later layer are skipped (they cannot exist in parsed JSON anyway).
61
+ *
62
+ * `null`/`undefined` LAYERS are skipped entirely. The inputs are never mutated; the result is a
63
+ * fresh object graph.
64
+ *
65
+ * @param layers The configuration layers, base first, most-specific last.
66
+ * @returns The merged configuration object (empty object when every layer is absent).
67
+ */
68
+ export function DeepMergeConfigs(...layers) {
69
+ const result = {};
70
+ for (const layer of layers) {
71
+ if (!isPlainObject(layer)) {
72
+ continue;
73
+ }
74
+ mergeInto(result, layer);
75
+ }
76
+ return result;
77
+ }
78
+ /** Recursive worker for {@link DeepMergeConfigs} — merges `source` into `target` in place. */
79
+ function mergeInto(target, source) {
80
+ for (const key of Object.keys(source)) {
81
+ const incoming = source[key];
82
+ if (incoming === undefined) {
83
+ continue;
84
+ }
85
+ const existing = target[key];
86
+ if (isPlainObject(existing) && isPlainObject(incoming)) {
87
+ mergeInto(existing, incoming);
88
+ }
89
+ else if (isPlainObject(incoming)) {
90
+ const copy = {};
91
+ mergeInto(copy, incoming);
92
+ target[key] = copy;
93
+ }
94
+ else if (Array.isArray(incoming)) {
95
+ target[key] = incoming.slice();
96
+ }
97
+ else {
98
+ target[key] = incoming;
99
+ }
100
+ }
101
+ }
102
+ /**
103
+ * TOLERANTLY parses one configuration layer (a `TypeConfiguration` / `DefaultConfiguration` /
104
+ * runtime-overrides JSON string). Returns `null` — never throws — for absent, blank, malformed,
105
+ * or non-object payloads (arrays and scalars are not valid configuration layers).
106
+ *
107
+ * @param json The raw JSON string, or `null`/`undefined`.
108
+ * @returns The parsed plain object, or `null` when the layer contributes nothing.
109
+ */
110
+ export function ParseRealtimeTypeConfiguration(json) {
111
+ if (typeof json !== 'string' || json.trim().length === 0) {
112
+ return null;
113
+ }
114
+ try {
115
+ const parsed = JSON.parse(json);
116
+ return isPlainObject(parsed) ? parsed : null;
117
+ }
118
+ catch {
119
+ return null;
120
+ }
121
+ }
122
+ /**
123
+ * Resolves the EFFECTIVE realtime configuration from the layers of the contract by tolerantly parsing
124
+ * each (see {@link ParseRealtimeTypeConfiguration}), deep-merging them (later wins per key, see
125
+ * {@link DeepMergeConfigs}), and normalizing into the typed {@link RealtimeCoAgentConfig} shape
126
+ * (wrong-typed fields dropped, never thrown on).
127
+ *
128
+ * **Precedence (lowest → highest):**
129
+ * `AIAgentType.DefaultConfiguration` < **co-agent** `AIAgent.TypeConfiguration` < **target agent**
130
+ * `AIAgent.TypeConfiguration` < runtime override. This is the single, surface-agnostic precedence cascade
131
+ * for model + voice + persona across EVERY realtime host (native chat, LiveKit, future Zoom/Teams) — see
132
+ * `plans/realtime/realtime-core-host-convergence.md`. The **target** layer is what lets a voiced agent
133
+ * (Sage, Marketing Agent, …) carry its own persisted voice/model that the shared co-agent then speaks with;
134
+ * it wins over the co-agent's defaults but yields to an explicit per-session runtime override.
135
+ *
136
+ * @param typeDefaultJson The agent TYPE's `DefaultConfiguration` JSON (base layer).
137
+ * @param agentJson The CO-AGENT's `TypeConfiguration` JSON (shared per-co-agent layer).
138
+ * @param overridesJson Runtime overrides JSON (per-session layer; already authorization-gated by the caller).
139
+ * @param targetAgentJson Optional TARGET agent's `TypeConfiguration` JSON (per-voiced-agent layer). Merged
140
+ * ABOVE the co-agent and BELOW the runtime override regardless of argument position. Omit when there is
141
+ * no distinct target (e.g. the co-agent voicing itself).
142
+ * @returns The normalized effective configuration. `realtime` is absent when no layer supplied a usable section.
143
+ */
144
+ export function ResolveEffectiveRealtimeConfig(typeDefaultJson, agentJson, overridesJson, targetAgentJson) {
145
+ // Merge order = precedence (later wins): type-default < co-agent < target < runtime-override.
146
+ const merged = DeepMergeConfigs(ParseRealtimeTypeConfiguration(typeDefaultJson), ParseRealtimeTypeConfiguration(agentJson), ParseRealtimeTypeConfiguration(targetAgentJson), ParseRealtimeTypeConfiguration(overridesJson));
147
+ return normalizeConfig(merged);
148
+ }
149
+ /** Normalizes a merged raw config object into the typed, sanity-checked shape. */
150
+ function normalizeConfig(merged) {
151
+ const rawRealtime = merged['realtime'];
152
+ if (!isPlainObject(rawRealtime)) {
153
+ return {};
154
+ }
155
+ const section = {};
156
+ const modelPreference = rawRealtime['modelPreference'];
157
+ if (typeof modelPreference === 'string' && modelPreference.trim().length > 0) {
158
+ section.modelPreference = modelPreference.trim();
159
+ }
160
+ if (typeof rawRealtime['allowUserModelOverride'] === 'boolean') {
161
+ section.allowUserModelOverride = rawRealtime['allowUserModelOverride'];
162
+ }
163
+ const voice = normalizeVoice(rawRealtime['voice']);
164
+ if (voice) {
165
+ section.voice = voice;
166
+ }
167
+ const narration = normalizeNarration(rawRealtime['narration']);
168
+ if (narration) {
169
+ section.narration = narration;
170
+ }
171
+ const video = normalizeVideo(rawRealtime['video']);
172
+ if (video) {
173
+ section.video = video;
174
+ }
175
+ return Object.keys(section).length > 0 ? { realtime: section } : { realtime: {} };
176
+ }
177
+ /** Normalizes the `video` block; returns `null` when nothing usable survives. */
178
+ function normalizeVideo(raw) {
179
+ if (!isPlainObject(raw)) {
180
+ return null;
181
+ }
182
+ const video = {};
183
+ if (typeof raw['enabled'] === 'boolean') {
184
+ video.enabled = raw['enabled'];
185
+ }
186
+ if (typeof raw['provider'] === 'string' && raw['provider'].trim().length > 0) {
187
+ video.provider = raw['provider'].trim();
188
+ }
189
+ if (typeof raw['avatarId'] === 'string' && raw['avatarId'].trim().length > 0) {
190
+ video.avatarId = raw['avatarId'].trim();
191
+ }
192
+ const rawProviders = raw['providers'];
193
+ if (isPlainObject(rawProviders)) {
194
+ const providers = {};
195
+ for (const key of Object.keys(rawProviders)) {
196
+ const settings = rawProviders[key];
197
+ if (isPlainObject(settings) && key.trim().length > 0) {
198
+ providers[key] = settings;
199
+ }
200
+ }
201
+ if (Object.keys(providers).length > 0) {
202
+ video.providers = providers;
203
+ }
204
+ }
205
+ return Object.keys(video).length > 0 ? video : null;
206
+ }
207
+ /** Normalizes the `voice` block; returns `null` when nothing usable survives. */
208
+ function normalizeVoice(raw) {
209
+ if (!isPlainObject(raw)) {
210
+ return null;
211
+ }
212
+ const voice = {};
213
+ const rawDefault = raw['default'];
214
+ if (isPlainObject(rawDefault)) {
215
+ const persona = {};
216
+ if (typeof rawDefault['tone'] === 'string' && rawDefault['tone'].trim().length > 0) {
217
+ persona.tone = rawDefault['tone'].trim();
218
+ }
219
+ if (typeof rawDefault['speakingStyle'] === 'string' && rawDefault['speakingStyle'].trim().length > 0) {
220
+ persona.speakingStyle = rawDefault['speakingStyle'].trim();
221
+ }
222
+ if (Object.keys(persona).length > 0) {
223
+ voice.default = persona;
224
+ }
225
+ }
226
+ const rawProviders = raw['providers'];
227
+ if (isPlainObject(rawProviders)) {
228
+ const providers = {};
229
+ for (const key of Object.keys(rawProviders)) {
230
+ const settings = rawProviders[key];
231
+ if (isPlainObject(settings) && key.trim().length > 0) {
232
+ providers[key] = settings;
233
+ }
234
+ }
235
+ if (Object.keys(providers).length > 0) {
236
+ voice.providers = providers;
237
+ }
238
+ }
239
+ return Object.keys(voice).length > 0 ? voice : null;
240
+ }
241
+ /** Normalizes the `narration` block; returns `null` when nothing usable survives. */
242
+ function normalizeNarration(raw) {
243
+ if (!isPlainObject(raw)) {
244
+ return null;
245
+ }
246
+ const paceMs = raw['paceMs'];
247
+ if (typeof paceMs === 'number' && Number.isFinite(paceMs) && paceMs > 0) {
248
+ return { paceMs: Math.floor(paceMs) };
249
+ }
250
+ return null;
251
+ }
252
+ /** Normalizes a provider key / driver class for matching: lowercase, alphanumerics only. */
253
+ function normalizeKey(value) {
254
+ return value.toLowerCase().replace(/[^a-z0-9]/g, '');
255
+ }
256
+ /**
257
+ * Picks the provider-specific voice settings for a resolved realtime driver.
258
+ *
259
+ * Provider keys (`openai`, `elevenlabs`, `gemini`, `assemblyai`, …) are matched against the
260
+ * vendor `DriverClass` (e.g. `OpenAIRealtime`, `ElevenLabsRealtime`) by normalized-prefix:
261
+ * both sides are lowercased and stripped of non-alphanumerics, then the driver class must START
262
+ * WITH the provider key (`openairealtime`.startsWith(`openai`)). A bare provider name (e.g.
263
+ * `'openai'` from `ClientRealtimeSessionConfig.Provider`) matches the same way. The LONGEST
264
+ * matching key wins when several match.
265
+ *
266
+ * @param config The effective configuration.
267
+ * @param driverClassOrProvider The vendor `DriverClass` or the provider key itself.
268
+ * @returns The matched settings object (opaque driver pact), or `null` when none match.
269
+ */
270
+ export function GetProviderVoiceSettings(config, driverClassOrProvider) {
271
+ const providers = config?.realtime?.voice?.providers;
272
+ if (!providers || !driverClassOrProvider) {
273
+ return null;
274
+ }
275
+ const normalizedDriver = normalizeKey(driverClassOrProvider);
276
+ if (normalizedDriver.length === 0) {
277
+ return null;
278
+ }
279
+ let best = null;
280
+ for (const key of Object.keys(providers)) {
281
+ const normalizedKey = normalizeKey(key);
282
+ if (normalizedKey.length === 0 || !normalizedDriver.startsWith(normalizedKey)) {
283
+ continue;
284
+ }
285
+ if (!best || normalizedKey.length > normalizeKey(best.key).length) {
286
+ best = { key, settings: providers[key] };
287
+ }
288
+ }
289
+ return best?.settings ?? null;
290
+ }
291
+ /**
292
+ * Builds the "Voice & manner" system-prompt section from the effective voice persona —
293
+ * appended to the server-built companion system prompt at mint. Returns an empty string when
294
+ * neither `tone` nor `speakingStyle` is configured (the section simply doesn't appear).
295
+ *
296
+ * @param config The effective configuration.
297
+ * @returns The prompt section text, or `''`.
298
+ */
299
+ export function BuildVoiceMannerSection(config) {
300
+ const persona = config?.realtime?.voice?.default;
301
+ if (!persona) {
302
+ return '';
303
+ }
304
+ const lines = [];
305
+ if (persona.tone) {
306
+ lines.push(`Tone: ${persona.tone}`);
307
+ }
308
+ if (persona.speakingStyle) {
309
+ lines.push(`Speaking style: ${persona.speakingStyle}`);
310
+ }
311
+ if (lines.length === 0) {
312
+ return '';
313
+ }
314
+ return `Voice & manner:\n${lines.join('\n')}`;
315
+ }
316
+ /**
317
+ * Builds the runtime-override `ConfigOverridesJson` envelope (the highest-precedence cascade layer) from a
318
+ * per-session model and/or voice choice — the **single, surface-agnostic** shape every realtime host uses
319
+ * to carry a dev's pick into {@link ResolveEffectiveRealtimeConfig}. The native-chat picker produces the
320
+ * same shape client-side (`BuildRealtimeConfigOverridesJson` in `@memberjunction/ng-conversations`); the
321
+ * server-bridged hosts (LiveKit, Zoom/Teams) build it here so both funnel into the one override slot.
322
+ *
323
+ * Envelope: `{"realtime":{"modelPreference":"<id>","voice":{"providers":{"openai":{"voice":"<v>"}}}}}`.
324
+ * `openai` is the realtime provider today; add providers here when others ship realtime voices.
325
+ *
326
+ * @param modelId The `MJ: AI Models` Name or ID to prefer, or null/empty for none.
327
+ * @param voice The provider-native voice id (e.g. `echo`), or null/empty for none.
328
+ * @returns The JSON string, or `null` when nothing was overridden (keeps the cascade at its lower layers).
329
+ */
330
+ export function BuildRealtimeOverridesJson(modelId, voice) {
331
+ const m = modelId?.trim() ?? '';
332
+ const v = voice?.trim() ?? '';
333
+ if (m.length === 0 && v.length === 0) {
334
+ return null;
335
+ }
336
+ const realtime = {};
337
+ if (m.length > 0) {
338
+ realtime.modelPreference = m;
339
+ }
340
+ if (v.length > 0) {
341
+ realtime.voice = { providers: { openai: { voice: v } } };
342
+ }
343
+ return JSON.stringify({ realtime });
344
+ }
345
+ /**
346
+ * Reads the effective narration pace (minimum gap in ms between spoken progress updates), or
347
+ * `null` when not configured. Already sanity-checked by normalization (positive finite integer).
348
+ *
349
+ * @param config The effective configuration.
350
+ * @returns The pace in ms, or `null`.
351
+ */
352
+ export function GetNarrationPaceMs(config) {
353
+ return config?.realtime?.narration?.paceMs ?? null;
354
+ }
355
+ /**
356
+ * PURE authorization-policy decision for runtime overrides on a realtime session start.
357
+ *
358
+ * Rules (Amith-approved product contract):
359
+ * 1. No overrides requested → allowed (the everyday flow is never gated here — `CanRun` on the
360
+ * target agent remains the only gate for plain session starts and for target selection).
361
+ * 2. `configOverridesJson` present → caller MUST hold the
362
+ * {@link REALTIME_ADVANCED_SESSION_CONTROLS_AUTHORIZATION} authorization.
363
+ * 3. An explicit runtime model that EQUALS the metadata-configured preference is not a
364
+ * deviation → no gate.
365
+ * 4. A DEVIATING explicit runtime model → caller must hold the authorization AND the effective
366
+ * `allowUserModelOverride` must not be `false` (the policy blocks even authorized callers).
367
+ *
368
+ * The check is deliberately a structured REJECTION (the caller throws the `DenialReason`), never
369
+ * a silent ignore — a caller who asked for something specific must learn it was refused.
370
+ *
371
+ * @param input The override request + caller authorization + effective policy.
372
+ * @returns The decision.
373
+ */
374
+ export function EvaluateRuntimeOverrideAuthorization(input) {
375
+ const requestedModel = input.RequestedModelID?.trim() ? input.RequestedModelID.trim() : null;
376
+ const modelDeviates = requestedModel !== null && !idsEqual(requestedModel, input.MetadataPreferredModelID);
377
+ if (!input.HasConfigOverrides && !modelDeviates) {
378
+ return { Allowed: true };
379
+ }
380
+ if (input.HasConfigOverrides && !input.CallerHasAdvancedControls) {
381
+ return {
382
+ Allowed: false,
383
+ DenialReason: `Runtime configuration overrides (configOverridesJson) require the ` +
384
+ `'${REALTIME_ADVANCED_SESSION_CONTROLS_AUTHORIZATION}' authorization. The session can be ` +
385
+ `started without overrides to use the co-agent's configured defaults.`
386
+ };
387
+ }
388
+ if (modelDeviates) {
389
+ if (!input.CallerHasAdvancedControls) {
390
+ return {
391
+ Allowed: false,
392
+ DenialReason: `Explicit realtime model selection requires the ` +
393
+ `'${REALTIME_ADVANCED_SESSION_CONTROLS_AUTHORIZATION}' authorization. Omit preferredModelId ` +
394
+ `to use the co-agent's configured model.`
395
+ };
396
+ }
397
+ if (input.AllowUserModelOverride === false) {
398
+ return {
399
+ Allowed: false,
400
+ DenialReason: `This co-agent's configuration sets realtime.allowUserModelOverride=false — per-session ` +
401
+ `model overrides are disabled by policy, even for authorized callers. Omit preferredModelId ` +
402
+ `to use the configured model.`
403
+ };
404
+ }
405
+ }
406
+ return { Allowed: true };
407
+ }
408
+ //# sourceMappingURL=realtime-coagent-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-coagent-config.js","sourceRoot":"","sources":["../../src/realtime/realtime-coagent-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @fileoverview Shared narration helpers for BOTH realtime topologies.
3
+ *
4
+ * Two concerns live here so they exist exactly once:
5
+ *
6
+ * 1. **DB template resolution** — {@link ResolveNarrationInstructionsTemplate} looks up the
7
+ * seeded `Realtime Co-Agent - Progress Narration` prompt (with the deprecated pre-rename
8
+ * fallback) in {@link AIEngine}'s cached prompts. The client-direct path threads the
9
+ * template to the browser at session mint; the server-bridged path
10
+ * ({@link import('./realtime-session-runner.js').RealtimeSessionRunner}) consumes it directly.
11
+ * 2. **Instruction building** — {@link BuildServerNarrationInstructions} substitutes the
12
+ * template's placeholders (or falls back to the documented built-in first-person wording)
13
+ * for the server-bridged runner's spoken progress updates. The Angular voice session has
14
+ * its own richer builder (it also chains the model's PRIOR spoken narrations, which only
15
+ * the browser can observe); this server-side builder is deliberately compact.
16
+ *
17
+ * @module @memberjunction/ai-agents
18
+ * @author MemberJunction.com
19
+ */
20
+ /**
21
+ * The seeded name of the `MJ: AI Prompts` row whose `TemplateText` carries the first-person
22
+ * progress-narration instructions (with a `{{ progressMessage }}` placeholder).
23
+ */
24
+ export declare const NARRATION_PROMPT_NAME = "Realtime Co-Agent - Progress Narration";
25
+ /**
26
+ * DEPRECATED legacy name of {@link NARRATION_PROMPT_NAME}, from before the co-agent's rename
27
+ * from "Voice Co-Agent" to "Realtime Co-Agent". Deployments that have not re-synced the prompt
28
+ * seed still carry this name, so {@link ResolveNarrationInstructionsTemplate} falls back to it
29
+ * (with a deprecation log).
30
+ */
31
+ export declare const LEGACY_NARRATION_PROMPT_NAME = "Voice Co-Agent - Progress Narration";
32
+ /**
33
+ * Resolves the DB-driven progress-narration instruction template: the Active `MJ: AI Prompts`
34
+ * row named {@link NARRATION_PROMPT_NAME}, read from {@link AIEngine}'s cached prompts. When
35
+ * the current name is absent, falls back to the DEPRECATED {@link LEGACY_NARRATION_PROMPT_NAME}
36
+ * (pre-rename seed) with a deprecation log. **Tolerant**: returns `null` (never throws) when
37
+ * neither prompt is present, the text is empty, or the engine cache is unavailable — consumers
38
+ * fall back to the built-in narration instruction wording.
39
+ *
40
+ * @returns The template text (containing a `{{ progressMessage }}` placeholder), or `null`.
41
+ */
42
+ export declare function ResolveNarrationInstructionsTemplate(): string | null;
43
+ /**
44
+ * The documented BUILT-IN fallback wording for a server-bridged spoken progress update —
45
+ * strictly first person (the co-agent owns the work), one short sentence, no repetition.
46
+ * Used when no DB template resolved for the deployment.
47
+ *
48
+ * @param digest The aggregated progress digest (one or more updates, oldest first).
49
+ * @param updateNumber 1-based number of this spoken update within the current task.
50
+ * @returns The complete spoken-update instruction text.
51
+ */
52
+ export declare function DefaultServerNarrationInstructions(digest: string, updateNumber: number): string;
53
+ /**
54
+ * Builds the spoken-update instructions for the server-bridged runner from the DB template
55
+ * (substituting `{{ progressMessage }}` / `{{ updateNumber }}`, space and no-space variants),
56
+ * falling back to {@link DefaultServerNarrationInstructions} when the template is absent or
57
+ * blank. The `{{ priorNarrations }}` placeholder is substituted with a neutral note — the
58
+ * server-bridged path cannot observe what the model actually SAID (those transcripts ride the
59
+ * provider socket), unlike the browser host which chains them.
60
+ *
61
+ * @param template The DB-driven instruction template, or `null`/`undefined` when unavailable.
62
+ * @param digest The aggregated progress digest (one or more updates, oldest first).
63
+ * @param updateNumber 1-based number of this spoken update within the current task.
64
+ * @returns The complete spoken-update instruction text.
65
+ */
66
+ export declare function BuildServerNarrationInstructions(template: string | null | undefined, digest: string, updateNumber: number): string;
67
+ //# sourceMappingURL=realtime-narration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-narration.d.ts","sourceRoot":"","sources":["../../src/realtime/realtime-narration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH;;;GAGG;AACH,eAAO,MAAM,qBAAqB,2CAA2C,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,wCAAwC,CAAC;AAOlF;;;;;;;;;GASG;AACH,wBAAgB,oCAAoC,IAAI,MAAM,GAAG,IAAI,CAmBpE;AAwBD;;;;;;;;GAQG;AACH,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAU/F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gCAAgC,CAC5C,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACrB,MAAM,CAcR"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @fileoverview Shared narration helpers for BOTH realtime topologies.
3
+ *
4
+ * Two concerns live here so they exist exactly once:
5
+ *
6
+ * 1. **DB template resolution** — {@link ResolveNarrationInstructionsTemplate} looks up the
7
+ * seeded `Realtime Co-Agent - Progress Narration` prompt (with the deprecated pre-rename
8
+ * fallback) in {@link AIEngine}'s cached prompts. The client-direct path threads the
9
+ * template to the browser at session mint; the server-bridged path
10
+ * ({@link import('./realtime-session-runner.js').RealtimeSessionRunner}) consumes it directly.
11
+ * 2. **Instruction building** — {@link BuildServerNarrationInstructions} substitutes the
12
+ * template's placeholders (or falls back to the documented built-in first-person wording)
13
+ * for the server-bridged runner's spoken progress updates. The Angular voice session has
14
+ * its own richer builder (it also chains the model's PRIOR spoken narrations, which only
15
+ * the browser can observe); this server-side builder is deliberately compact.
16
+ *
17
+ * @module @memberjunction/ai-agents
18
+ * @author MemberJunction.com
19
+ */
20
+ import { LogStatus } from '@memberjunction/core';
21
+ import { AIEngine } from '@memberjunction/aiengine';
22
+ /**
23
+ * The seeded name of the `MJ: AI Prompts` row whose `TemplateText` carries the first-person
24
+ * progress-narration instructions (with a `{{ progressMessage }}` placeholder).
25
+ */
26
+ export const NARRATION_PROMPT_NAME = 'Realtime Co-Agent - Progress Narration';
27
+ /**
28
+ * DEPRECATED legacy name of {@link NARRATION_PROMPT_NAME}, from before the co-agent's rename
29
+ * from "Voice Co-Agent" to "Realtime Co-Agent". Deployments that have not re-synced the prompt
30
+ * seed still carry this name, so {@link ResolveNarrationInstructionsTemplate} falls back to it
31
+ * (with a deprecation log).
32
+ */
33
+ export const LEGACY_NARRATION_PROMPT_NAME = 'Voice Co-Agent - Progress Narration';
34
+ /** Placeholder token variants substituted by {@link BuildServerNarrationInstructions}. */
35
+ const PROGRESS_TOKENS = ['{{ progressMessage }}', '{{progressMessage}}'];
36
+ const PRIOR_TOKENS = ['{{ priorNarrations }}', '{{priorNarrations}}'];
37
+ const NUMBER_TOKENS = ['{{ updateNumber }}', '{{updateNumber}}'];
38
+ /**
39
+ * Resolves the DB-driven progress-narration instruction template: the Active `MJ: AI Prompts`
40
+ * row named {@link NARRATION_PROMPT_NAME}, read from {@link AIEngine}'s cached prompts. When
41
+ * the current name is absent, falls back to the DEPRECATED {@link LEGACY_NARRATION_PROMPT_NAME}
42
+ * (pre-rename seed) with a deprecation log. **Tolerant**: returns `null` (never throws) when
43
+ * neither prompt is present, the text is empty, or the engine cache is unavailable — consumers
44
+ * fall back to the built-in narration instruction wording.
45
+ *
46
+ * @returns The template text (containing a `{{ progressMessage }}` placeholder), or `null`.
47
+ */
48
+ export function ResolveNarrationInstructionsTemplate() {
49
+ try {
50
+ const current = findActiveNarrationPromptText(NARRATION_PROMPT_NAME);
51
+ if (current) {
52
+ return current;
53
+ }
54
+ const legacy = findActiveNarrationPromptText(LEGACY_NARRATION_PROMPT_NAME);
55
+ if (legacy) {
56
+ LogStatus(`Realtime narration: resolved the narration prompt via its DEPRECATED legacy name ` +
57
+ `'${LEGACY_NARRATION_PROMPT_NAME}'. Re-sync the prompt seed metadata to rename it to ` +
58
+ `'${NARRATION_PROMPT_NAME}'.`);
59
+ return legacy;
60
+ }
61
+ return null;
62
+ }
63
+ catch {
64
+ return null; // engine cache unavailable — tolerated, consumers fall back
65
+ }
66
+ }
67
+ /**
68
+ * Finds the Active `MJ: AI Prompts` row with the given name (case/whitespace-insensitive) in
69
+ * {@link AIEngine}'s cached prompts and returns its non-empty `TemplateText`, or `null`.
70
+ */
71
+ function findActiveNarrationPromptText(promptName) {
72
+ const wanted = promptName.toLowerCase();
73
+ const prompt = (AIEngine.Instance.Prompts ?? []).find(p => p.Name?.trim().toLowerCase() === wanted && p.Status === 'Active');
74
+ const text = prompt?.TemplateText;
75
+ return text && text.trim().length > 0 ? text : null;
76
+ }
77
+ /** Replaces every occurrence of each token variant with the value. */
78
+ function replaceTokens(text, tokens, value) {
79
+ let out = text;
80
+ for (const t of tokens) {
81
+ out = out.split(t).join(value);
82
+ }
83
+ return out;
84
+ }
85
+ /**
86
+ * The documented BUILT-IN fallback wording for a server-bridged spoken progress update —
87
+ * strictly first person (the co-agent owns the work), one short sentence, no repetition.
88
+ * Used when no DB template resolved for the deployment.
89
+ *
90
+ * @param digest The aggregated progress digest (one or more updates, oldest first).
91
+ * @param updateNumber 1-based number of this spoken update within the current task.
92
+ * @returns The complete spoken-update instruction text.
93
+ */
94
+ export function DefaultServerNarrationInstructions(digest, updateNumber) {
95
+ return (`Live progress on the work YOU are doing for the user (oldest first): ${digest}. ` +
96
+ `This is spoken update #${updateNumber} for this task. ` +
97
+ `Say ONE short, natural sentence in the FIRST PERSON continuing the story of what you are doing ` +
98
+ `("I'm pulling that up now", "Got the first part — grabbing the rest"). VARY the phrasing across ` +
99
+ `updates and never repeat information you've already conveyed — only add what's new. Strictly first ` +
100
+ `person: the words "it" and the agent's name must not be the subject of your sentence, and never say ` +
101
+ `generic filler like "it's still running in the background".`);
102
+ }
103
+ /**
104
+ * Builds the spoken-update instructions for the server-bridged runner from the DB template
105
+ * (substituting `{{ progressMessage }}` / `{{ updateNumber }}`, space and no-space variants),
106
+ * falling back to {@link DefaultServerNarrationInstructions} when the template is absent or
107
+ * blank. The `{{ priorNarrations }}` placeholder is substituted with a neutral note — the
108
+ * server-bridged path cannot observe what the model actually SAID (those transcripts ride the
109
+ * provider socket), unlike the browser host which chains them.
110
+ *
111
+ * @param template The DB-driven instruction template, or `null`/`undefined` when unavailable.
112
+ * @param digest The aggregated progress digest (one or more updates, oldest first).
113
+ * @param updateNumber 1-based number of this spoken update within the current task.
114
+ * @returns The complete spoken-update instruction text.
115
+ */
116
+ export function BuildServerNarrationInstructions(template, digest, updateNumber) {
117
+ if (!template || template.trim().length === 0) {
118
+ return DefaultServerNarrationInstructions(digest, updateNumber);
119
+ }
120
+ let out = replaceTokens(template, PROGRESS_TOKENS, digest);
121
+ out = replaceTokens(out, PRIOR_TOKENS, updateNumber <= 1
122
+ ? 'Nothing yet — this is your first spoken update for this task.'
123
+ : `You have already spoken ${updateNumber - 1} update(s) for this task — do not repeat yourself; only add what's new.`);
124
+ out = replaceTokens(out, NUMBER_TOKENS, String(updateNumber));
125
+ return out;
126
+ }
127
+ //# sourceMappingURL=realtime-narration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-narration.js","sourceRoot":"","sources":["../../src/realtime/realtime-narration.ts"],"names":[],"mappings":"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"}