@memberjunction/ai-agents 6.2.0-edge.1 → 6.2.0-edge.3

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 (131) hide show
  1. package/README.md +18 -0
  2. package/dist/AgentDecisionService.d.ts +90 -0
  3. package/dist/AgentDecisionService.d.ts.map +1 -0
  4. package/dist/AgentDecisionService.js +159 -0
  5. package/dist/AgentDecisionService.js.map +1 -0
  6. package/dist/AgentRunner.d.ts +9 -0
  7. package/dist/AgentRunner.d.ts.map +1 -1
  8. package/dist/AgentRunner.js +23 -7
  9. package/dist/AgentRunner.js.map +1 -1
  10. package/dist/ConversationCompactionManager.d.ts +7 -1
  11. package/dist/ConversationCompactionManager.d.ts.map +1 -1
  12. package/dist/ConversationCompactionManager.js +4 -1
  13. package/dist/ConversationCompactionManager.js.map +1 -1
  14. package/dist/KnowledgeAgent.d.ts.map +1 -1
  15. package/dist/KnowledgeAgent.js +6 -6
  16. package/dist/KnowledgeAgent.js.map +1 -1
  17. package/dist/PayloadFeedbackManager.d.ts +116 -14
  18. package/dist/PayloadFeedbackManager.d.ts.map +1 -1
  19. package/dist/PayloadFeedbackManager.js +229 -88
  20. package/dist/PayloadFeedbackManager.js.map +1 -1
  21. package/dist/agent-context-injector.d.ts +47 -3
  22. package/dist/agent-context-injector.d.ts.map +1 -1
  23. package/dist/agent-context-injector.js +77 -10
  24. package/dist/agent-context-injector.js.map +1 -1
  25. package/dist/agent-memory-context-builder.d.ts +13 -0
  26. package/dist/agent-memory-context-builder.d.ts.map +1 -1
  27. package/dist/agent-memory-context-builder.js +24 -5
  28. package/dist/agent-memory-context-builder.js.map +1 -1
  29. package/dist/agent-types/flow-agent-type.d.ts +97 -0
  30. package/dist/agent-types/flow-agent-type.d.ts.map +1 -1
  31. package/dist/agent-types/flow-agent-type.js +281 -24
  32. package/dist/agent-types/flow-agent-type.js.map +1 -1
  33. package/dist/agent-types/flow-graph-executor.d.ts +12 -1
  34. package/dist/agent-types/flow-graph-executor.d.ts.map +1 -1
  35. package/dist/agent-types/flow-graph-executor.js +25 -1
  36. package/dist/agent-types/flow-graph-executor.js.map +1 -1
  37. package/dist/agent-types/loop-agent-prompt-params.d.ts +239 -66
  38. package/dist/agent-types/loop-agent-prompt-params.d.ts.map +1 -1
  39. package/dist/agent-types/loop-agent-prompt-params.js +47 -2
  40. package/dist/agent-types/loop-agent-prompt-params.js.map +1 -1
  41. package/dist/agent-types/loop-agent-response-type.d.ts +12 -1
  42. package/dist/agent-types/loop-agent-response-type.d.ts.map +1 -1
  43. package/dist/agent-types/loop-agent-response-type.js.map +1 -1
  44. package/dist/agent-types/loop-agent-type.d.ts +26 -0
  45. package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
  46. package/dist/agent-types/loop-agent-type.js +115 -5
  47. package/dist/agent-types/loop-agent-type.js.map +1 -1
  48. package/dist/base-agent.d.ts +527 -10
  49. package/dist/base-agent.d.ts.map +1 -1
  50. package/dist/base-agent.js +1779 -110
  51. package/dist/base-agent.js.map +1 -1
  52. package/dist/catalog-narrowing.d.ts +136 -0
  53. package/dist/catalog-narrowing.d.ts.map +1 -0
  54. package/dist/catalog-narrowing.js +212 -0
  55. package/dist/catalog-narrowing.js.map +1 -0
  56. package/dist/decision-discovery.d.ts +401 -0
  57. package/dist/decision-discovery.d.ts.map +1 -0
  58. package/dist/decision-discovery.js +511 -0
  59. package/dist/decision-discovery.js.map +1 -0
  60. package/dist/finish-if-mode-warnings.d.ts +39 -0
  61. package/dist/finish-if-mode-warnings.d.ts.map +1 -0
  62. package/dist/finish-if-mode-warnings.js +78 -0
  63. package/dist/finish-if-mode-warnings.js.map +1 -0
  64. package/dist/finish-if-state.d.ts +72 -0
  65. package/dist/finish-if-state.d.ts.map +1 -0
  66. package/dist/finish-if-state.js +109 -0
  67. package/dist/finish-if-state.js.map +1 -0
  68. package/dist/index.d.ts +10 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +11 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/memory-manager-agent.d.ts +108 -2
  73. package/dist/memory-manager-agent.d.ts.map +1 -1
  74. package/dist/memory-manager-agent.js +172 -9
  75. package/dist/memory-manager-agent.js.map +1 -1
  76. package/dist/memory-note-gate.d.ts +208 -0
  77. package/dist/memory-note-gate.d.ts.map +1 -0
  78. package/dist/memory-note-gate.js +294 -0
  79. package/dist/memory-note-gate.js.map +1 -0
  80. package/dist/native-tools/action-tool-builder.d.ts +14 -0
  81. package/dist/native-tools/action-tool-builder.d.ts.map +1 -1
  82. package/dist/native-tools/action-tool-builder.js +62 -7
  83. package/dist/native-tools/action-tool-builder.js.map +1 -1
  84. package/dist/native-tools/control-tools.d.ts +17 -1
  85. package/dist/native-tools/control-tools.d.ts.map +1 -1
  86. package/dist/native-tools/control-tools.js +40 -3
  87. package/dist/native-tools/control-tools.js.map +1 -1
  88. package/dist/realtime/bridge-host-params.d.ts +22 -0
  89. package/dist/realtime/bridge-host-params.d.ts.map +1 -0
  90. package/dist/realtime/bridge-host-params.js +53 -0
  91. package/dist/realtime/bridge-host-params.js.map +1 -0
  92. package/dist/realtime/bridge-realtime-session-factory.d.ts +23 -2
  93. package/dist/realtime/bridge-realtime-session-factory.d.ts.map +1 -1
  94. package/dist/realtime/bridge-realtime-session-factory.js +22 -6
  95. package/dist/realtime/bridge-realtime-session-factory.js.map +1 -1
  96. package/dist/realtime/bridge-room-transcript-sink.d.ts.map +1 -1
  97. package/dist/realtime/bridge-room-transcript-sink.js +15 -9
  98. package/dist/realtime/bridge-room-transcript-sink.js.map +1 -1
  99. package/dist/realtime/bridge-session-transcript-sink.d.ts +37 -0
  100. package/dist/realtime/bridge-session-transcript-sink.d.ts.map +1 -0
  101. package/dist/realtime/bridge-session-transcript-sink.js +58 -0
  102. package/dist/realtime/bridge-session-transcript-sink.js.map +1 -0
  103. package/dist/realtime/realtime-client-session-service.d.ts +117 -12
  104. package/dist/realtime/realtime-client-session-service.d.ts.map +1 -1
  105. package/dist/realtime/realtime-client-session-service.js +162 -39
  106. package/dist/realtime/realtime-client-session-service.js.map +1 -1
  107. package/dist/realtime/realtime-coagent-resolution.d.ts +90 -0
  108. package/dist/realtime/realtime-coagent-resolution.d.ts.map +1 -0
  109. package/dist/realtime/realtime-coagent-resolution.js +186 -0
  110. package/dist/realtime/realtime-coagent-resolution.js.map +1 -0
  111. package/dist/realtime/realtime-delegation-narrator.d.ts +97 -0
  112. package/dist/realtime/realtime-delegation-narrator.d.ts.map +1 -0
  113. package/dist/realtime/realtime-delegation-narrator.js +162 -0
  114. package/dist/realtime/realtime-delegation-narrator.js.map +1 -0
  115. package/dist/realtime/realtime-session-runner.d.ts +2 -82
  116. package/dist/realtime/realtime-session-runner.d.ts.map +1 -1
  117. package/dist/realtime/realtime-session-runner.js +12 -187
  118. package/dist/realtime/realtime-session-runner.js.map +1 -1
  119. package/dist/realtime/realtime-vendor-resolution.d.ts +8 -3
  120. package/dist/realtime/realtime-vendor-resolution.d.ts.map +1 -1
  121. package/dist/realtime/realtime-vendor-resolution.js +3 -3
  122. package/dist/realtime/realtime-vendor-resolution.js.map +1 -1
  123. package/dist/rubric-evaluation-agent-runner.d.ts +2 -0
  124. package/dist/rubric-evaluation-agent-runner.d.ts.map +1 -0
  125. package/dist/rubric-evaluation-agent-runner.js +47 -0
  126. package/dist/rubric-evaluation-agent-runner.js.map +1 -0
  127. package/dist/self-check.d.ts +101 -0
  128. package/dist/self-check.d.ts.map +1 -0
  129. package/dist/self-check.js +74 -0
  130. package/dist/self-check.js.map +1 -0
  131. package/package.json +19 -18
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @fileoverview `DelegationNarrator` — spoken progress updates while a delegated agent run is in flight, for
3
+ * every SERVER-held realtime session (the generic session runner, and a bridged phone call).
4
+ *
5
+ * While the co-agent hands work to a target agent the caller would otherwise sit in silence. The narrator
6
+ * receives the delegated run's progress events and:
7
+ *
8
+ * - always injects each significant one as a background context note (so the model can draw on it), and
9
+ * - schedules a THROTTLED spoken update — first ~5 s into a burst, then no more often than every ~8 s, with
10
+ * floods aggregated into one digest — built with {@link BuildServerNarrationInstructions}.
11
+ *
12
+ * It was extracted from `RealtimeSessionRunner` so a bridged call (which never constructs a runner) speaks
13
+ * progress identically instead of re-implementing the pacing.
14
+ *
15
+ * @module @memberjunction/ai-agents
16
+ * @author MemberJunction.com
17
+ */
18
+ import type { IRealtimeSession } from '@memberjunction/ai';
19
+ import type { DelegatedResult, DelegateToTargetRequest } from './realtime-tool-broker.js';
20
+ /** The collaborators a {@link DelegationNarrator} needs. */
21
+ export interface DelegationNarratorDeps {
22
+ /** The live session to speak on, or `null` when there is none (a stale event is then dropped). */
23
+ GetSession: () => IRealtimeSession | null;
24
+ /** The DB-driven narration instruction template, or `null`/absent for the built-in wording. */
25
+ NarrationInstructionsTemplate?: string | null;
26
+ /** Minimum gap (ms) between spoken updates (`realtime.narration.paceMs`); absent/invalid uses the default. */
27
+ NarrationPaceMs?: number | null;
28
+ }
29
+ /** Narration state and pacing for one realtime session. One instance per session. */
30
+ export declare class DelegationNarrator {
31
+ private readonly deps;
32
+ /** First spoken update fires no earlier than this long after a delegation burst starts. */
33
+ private static readonly firstNarrationDelayMs;
34
+ /** Minimum gap between SUBSEQUENT spoken updates (floods aggregate into one digest). */
35
+ private static readonly defaultIntervalMs;
36
+ /** Max progress messages aggregated into one spoken digest. */
37
+ private static readonly maxDigestMessages;
38
+ /**
39
+ * Progress steps worth narrating — mirrors the client-direct resolver's filter so both topologies narrate the
40
+ * same signal and drop the same initialization/finalization noise.
41
+ */
42
+ private static readonly significantProgressSteps;
43
+ /** Count of delegations currently in flight (anchors the burst lifecycle). */
44
+ private activeDelegations;
45
+ /** Epoch ms when the current burst began (first in-flight delegation); 0 = no active burst. */
46
+ private burstStartedAt;
47
+ /** Epoch ms of the last spoken update; 0 = never. SESSION-global spacing floor. */
48
+ private lastNarrationAt;
49
+ /** Spoken updates so far in the current burst (1-based numbering for the instructions). */
50
+ private narrationCount;
51
+ /** Aggregation buffer: distinct progress messages since the last spoken update (oldest first). */
52
+ private pendingMessages;
53
+ /** Tail message of the last digest, so an identical trailing progress event is not re-buffered. */
54
+ private lastNarratedTail;
55
+ /** Pending deferred-narration timer; cancelled when the delegation finishes or the user barges in. */
56
+ private timer;
57
+ constructor(deps: DelegationNarratorDeps);
58
+ /**
59
+ * Runs one delegated call through `delegate` while owning the narration burst around it: progress events are
60
+ * threaded back through {@link DelegateToTargetRequest.OnProgress}, and when the delegation finishes (success,
61
+ * failure or abort) any still-pending spoken update is cancelled — the final result is about to be voiced.
62
+ */
63
+ Run(request: DelegateToTargetRequest, delegate: (request: DelegateToTargetRequest) => Promise<DelegatedResult>): Promise<DelegatedResult>;
64
+ /**
65
+ * Owns the narration burst around any delegated work: anchors a burst when `work` starts and cancels pending
66
+ * narration when it settles. Use this directly when the caller threads {@link HandleProgress} through as the
67
+ * delegated run's own progress callback (the bridged-call path), rather than through {@link Run}.
68
+ */
69
+ Track<T>(work: () => Promise<T>): Promise<T>;
70
+ /** Cancels any deferred spoken update, drops the digest buffer and resets the burst-timing state. */
71
+ Cancel(): void;
72
+ /**
73
+ * Consumes one delegated-run progress event: significant steps only; always a context note; and a throttled
74
+ * spoken update when the provider can voice one.
75
+ */
76
+ HandleProgress(progress: {
77
+ step: string;
78
+ message: string;
79
+ }): void;
80
+ /**
81
+ * Anchors a fresh burst when nothing else is in flight OR the burst state was reset (by {@link Cancel}) — the
82
+ * second condition keeps timing correct when a prior delegation failed to honour its abort and left the
83
+ * counter elevated. {@link lastNarrationAt} is deliberately NOT reset across bursts.
84
+ */
85
+ private beginDelegation;
86
+ /** Closes one delegation; when none remain in flight, pending narration is cancelled. */
87
+ private endDelegation;
88
+ /** Adds a progress message to the digest buffer (deduped, capped, oldest-first). */
89
+ private bufferMessage;
90
+ /** ms until the next spoken update is allowed: >= ~5 s after the burst began AND >= the interval since the last. */
91
+ private nextDelayMs;
92
+ /** The configured pace when it is a positive finite number, else the built-in default. */
93
+ private intervalMs;
94
+ /** Speaks the aggregated digest — unless the work already finished or the session is gone. */
95
+ private fireDeferredNarration;
96
+ }
97
+ //# sourceMappingURL=realtime-delegation-narrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-delegation-narrator.d.ts","sourceRoot":"","sources":["../../src/realtime/realtime-delegation-narrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAGvF,4DAA4D;AAC5D,MAAM,WAAW,sBAAsB;IACnC,kGAAkG;IAClG,UAAU,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;IAC1C,+FAA+F;IAC/F,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,8GAA8G;IAC9G,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,qFAAqF;AACrF,qBAAa,kBAAkB;IA4Bf,OAAO,CAAC,QAAQ,CAAC,IAAI;IA3BjC,2FAA2F;IAC3F,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAQ;IACrD,wFAAwF;IACxF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IACjD,+DAA+D;IAC/D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAK;IAC9C;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAyF;IAEzI,8EAA8E;IAC9E,OAAO,CAAC,iBAAiB,CAAK;IAC9B,+FAA+F;IAC/F,OAAO,CAAC,cAAc,CAAK;IAC3B,mFAAmF;IACnF,OAAO,CAAC,eAAe,CAAK;IAC5B,2FAA2F;IAC3F,OAAO,CAAC,cAAc,CAAK;IAC3B,kGAAkG;IAClG,OAAO,CAAC,eAAe,CAAgB;IACvC,mGAAmG;IACnG,OAAO,CAAC,gBAAgB,CAAM;IAC9B,sGAAsG;IACtG,OAAO,CAAC,KAAK,CAA8C;gBAE9B,IAAI,EAAE,sBAAsB;IAEzD;;;;OAIG;IACU,GAAG,CAAC,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;IAItJ;;;;OAIG;IACU,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IASzD,qGAAqG;IAC9F,MAAM,IAAI,IAAI;IAWrB;;;OAGG;IACI,cAAc,CAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAkBxE;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAUvB,yFAAyF;IACzF,OAAO,CAAC,aAAa;IAOrB,oFAAoF;IACpF,OAAO,CAAC,aAAa;IAUrB,oHAAoH;IACpH,OAAO,CAAC,WAAW;IAOnB,0FAA0F;IAC1F,OAAO,CAAC,UAAU;IAKlB,8FAA8F;IAC9F,OAAO,CAAC,qBAAqB;CAchC"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @fileoverview `DelegationNarrator` — spoken progress updates while a delegated agent run is in flight, for
3
+ * every SERVER-held realtime session (the generic session runner, and a bridged phone call).
4
+ *
5
+ * While the co-agent hands work to a target agent the caller would otherwise sit in silence. The narrator
6
+ * receives the delegated run's progress events and:
7
+ *
8
+ * - always injects each significant one as a background context note (so the model can draw on it), and
9
+ * - schedules a THROTTLED spoken update — first ~5 s into a burst, then no more often than every ~8 s, with
10
+ * floods aggregated into one digest — built with {@link BuildServerNarrationInstructions}.
11
+ *
12
+ * It was extracted from `RealtimeSessionRunner` so a bridged call (which never constructs a runner) speaks
13
+ * progress identically instead of re-implementing the pacing.
14
+ *
15
+ * @module @memberjunction/ai-agents
16
+ * @author MemberJunction.com
17
+ */
18
+ import { BuildServerNarrationInstructions } from './realtime-narration.js';
19
+ /** Narration state and pacing for one realtime session. One instance per session. */
20
+ export class DelegationNarrator {
21
+ /** First spoken update fires no earlier than this long after a delegation burst starts. */
22
+ static { this.firstNarrationDelayMs = 5000; }
23
+ /** Minimum gap between SUBSEQUENT spoken updates (floods aggregate into one digest). */
24
+ static { this.defaultIntervalMs = 8000; }
25
+ /** Max progress messages aggregated into one spoken digest. */
26
+ static { this.maxDigestMessages = 4; }
27
+ /**
28
+ * Progress steps worth narrating — mirrors the client-direct resolver's filter so both topologies narrate the
29
+ * same signal and drop the same initialization/finalization noise.
30
+ */
31
+ static { this.significantProgressSteps = ['prompt_execution', 'action_execution', 'subagent_execution', 'decision_processing']; }
32
+ constructor(deps) {
33
+ this.deps = deps;
34
+ /** Count of delegations currently in flight (anchors the burst lifecycle). */
35
+ this.activeDelegations = 0;
36
+ /** Epoch ms when the current burst began (first in-flight delegation); 0 = no active burst. */
37
+ this.burstStartedAt = 0;
38
+ /** Epoch ms of the last spoken update; 0 = never. SESSION-global spacing floor. */
39
+ this.lastNarrationAt = 0;
40
+ /** Spoken updates so far in the current burst (1-based numbering for the instructions). */
41
+ this.narrationCount = 0;
42
+ /** Aggregation buffer: distinct progress messages since the last spoken update (oldest first). */
43
+ this.pendingMessages = [];
44
+ /** Tail message of the last digest, so an identical trailing progress event is not re-buffered. */
45
+ this.lastNarratedTail = '';
46
+ /** Pending deferred-narration timer; cancelled when the delegation finishes or the user barges in. */
47
+ this.timer = null;
48
+ }
49
+ /**
50
+ * Runs one delegated call through `delegate` while owning the narration burst around it: progress events are
51
+ * threaded back through {@link DelegateToTargetRequest.OnProgress}, and when the delegation finishes (success,
52
+ * failure or abort) any still-pending spoken update is cancelled — the final result is about to be voiced.
53
+ */
54
+ async Run(request, delegate) {
55
+ return this.Track(() => delegate({ ...request, OnProgress: (progress) => this.HandleProgress(progress) }));
56
+ }
57
+ /**
58
+ * Owns the narration burst around any delegated work: anchors a burst when `work` starts and cancels pending
59
+ * narration when it settles. Use this directly when the caller threads {@link HandleProgress} through as the
60
+ * delegated run's own progress callback (the bridged-call path), rather than through {@link Run}.
61
+ */
62
+ async Track(work) {
63
+ this.beginDelegation();
64
+ try {
65
+ return await work();
66
+ }
67
+ finally {
68
+ this.endDelegation();
69
+ }
70
+ }
71
+ /** Cancels any deferred spoken update, drops the digest buffer and resets the burst-timing state. */
72
+ Cancel() {
73
+ if (this.timer) {
74
+ clearTimeout(this.timer);
75
+ this.timer = null;
76
+ }
77
+ this.pendingMessages = [];
78
+ this.burstStartedAt = 0;
79
+ this.narrationCount = 0;
80
+ this.lastNarratedTail = '';
81
+ }
82
+ /**
83
+ * Consumes one delegated-run progress event: significant steps only; always a context note; and a throttled
84
+ * spoken update when the provider can voice one.
85
+ */
86
+ HandleProgress(progress) {
87
+ if (!DelegationNarrator.significantProgressSteps.includes(progress.step)) {
88
+ return;
89
+ }
90
+ const session = this.deps.GetSession();
91
+ if (!session || this.activeDelegations === 0) {
92
+ return; // session gone / delegation already finished — stale event
93
+ }
94
+ session.SendContextNote?.(`[delegated-agent progress] ${progress.message}`);
95
+ if (!session.RequestSpokenUpdate) {
96
+ return; // provider can't voice an instructed one-off update — context note only
97
+ }
98
+ this.bufferMessage(progress.message);
99
+ if (this.pendingMessages.length > 0 && !this.timer) {
100
+ this.timer = setTimeout(() => this.fireDeferredNarration(), this.nextDelayMs());
101
+ }
102
+ }
103
+ /**
104
+ * Anchors a fresh burst when nothing else is in flight OR the burst state was reset (by {@link Cancel}) — the
105
+ * second condition keeps timing correct when a prior delegation failed to honour its abort and left the
106
+ * counter elevated. {@link lastNarrationAt} is deliberately NOT reset across bursts.
107
+ */
108
+ beginDelegation() {
109
+ if (this.activeDelegations === 0 || this.burstStartedAt === 0) {
110
+ this.burstStartedAt = Date.now();
111
+ this.narrationCount = 0;
112
+ this.pendingMessages = [];
113
+ this.lastNarratedTail = '';
114
+ }
115
+ this.activeDelegations++;
116
+ }
117
+ /** Closes one delegation; when none remain in flight, pending narration is cancelled. */
118
+ endDelegation() {
119
+ this.activeDelegations = Math.max(0, this.activeDelegations - 1);
120
+ if (this.activeDelegations === 0) {
121
+ this.Cancel();
122
+ }
123
+ }
124
+ /** Adds a progress message to the digest buffer (deduped, capped, oldest-first). */
125
+ bufferMessage(message) {
126
+ if (message === this.lastNarratedTail || this.pendingMessages.includes(message)) {
127
+ return;
128
+ }
129
+ this.pendingMessages.push(message);
130
+ if (this.pendingMessages.length > DelegationNarrator.maxDigestMessages) {
131
+ this.pendingMessages.shift();
132
+ }
133
+ }
134
+ /** ms until the next spoken update is allowed: >= ~5 s after the burst began AND >= the interval since the last. */
135
+ nextDelayMs() {
136
+ const now = Date.now();
137
+ const firstAnchor = this.narrationCount === 0 ? this.burstStartedAt + DelegationNarrator.firstNarrationDelayMs : 0;
138
+ const spacingFloor = this.lastNarrationAt > 0 ? this.lastNarrationAt + this.intervalMs() : 0;
139
+ return Math.max(50, Math.max(firstAnchor, spacingFloor) - now);
140
+ }
141
+ /** The configured pace when it is a positive finite number, else the built-in default. */
142
+ intervalMs() {
143
+ const pace = this.deps.NarrationPaceMs;
144
+ return typeof pace === 'number' && Number.isFinite(pace) && pace > 0 ? pace : DelegationNarrator.defaultIntervalMs;
145
+ }
146
+ /** Speaks the aggregated digest — unless the work already finished or the session is gone. */
147
+ fireDeferredNarration() {
148
+ this.timer = null;
149
+ const session = this.deps.GetSession();
150
+ if (!session?.RequestSpokenUpdate || this.pendingMessages.length === 0 || this.activeDelegations === 0) {
151
+ this.pendingMessages = [];
152
+ return;
153
+ }
154
+ const digest = this.pendingMessages.join(' → ');
155
+ this.lastNarratedTail = this.pendingMessages[this.pendingMessages.length - 1];
156
+ this.pendingMessages = [];
157
+ this.narrationCount++;
158
+ this.lastNarrationAt = Date.now();
159
+ session.RequestSpokenUpdate(BuildServerNarrationInstructions(this.deps.NarrationInstructionsTemplate, digest, this.narrationCount));
160
+ }
161
+ }
162
+ //# sourceMappingURL=realtime-delegation-narrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-delegation-narrator.js","sourceRoot":"","sources":["../../src/realtime/realtime-delegation-narrator.ts"],"names":[],"mappings":"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"}
@@ -194,17 +194,6 @@ export interface RealtimeSessionResult {
194
194
  export declare class RealtimeSessionRunner {
195
195
  /** Default upper bound (ms) on the teardown transcript drain — see `TranscriptFlushTimeoutMs`. */
196
196
  private static readonly defaultTranscriptFlushTimeoutMs;
197
- /** First spoken update fires no earlier than this long after a delegation burst starts. */
198
- private static readonly firstNarrationDelayMs;
199
- /** Minimum gap between SUBSEQUENT spoken updates (floods aggregate into one digest). */
200
- private static readonly NarrationIntervalMs;
201
- /** Max progress messages aggregated into one spoken digest. */
202
- private static readonly maxDigestMessages;
203
- /**
204
- * Progress steps worth narrating — mirrors the client-direct resolver's filter so both
205
- * topologies narrate the same signal and drop the same initialization/finalization noise.
206
- */
207
- private static readonly significantProgressSteps;
208
197
  private deps;
209
198
  private session;
210
199
  /** Accumulated usage across all `OnUsage` deltas, flushed to the checkpoint on debounce/close. */
@@ -219,20 +208,8 @@ export declare class RealtimeSessionRunner {
219
208
  private usageDirty;
220
209
  /** Pending debounce timer handle for usage checkpoints. */
221
210
  private usageDebounceTimer;
222
- /** Count of delegations currently in flight (anchors the narration burst lifecycle). */
223
- private activeDelegations;
224
- /** Epoch ms when the current delegation burst began (first in-flight delegation). */
225
- private narrationBurstStartedAt;
226
- /** Epoch ms of the last spoken update; 0 = never. SESSION-global spacing floor. */
227
- private lastNarrationAt;
228
- /** Spoken updates so far in the current burst (1-based numbering for the instructions). */
229
- private narrationCount;
230
- /** Aggregation buffer: distinct progress messages since the last spoken update (oldest first). */
231
- private pendingNarrationMessages;
232
- /** Tail message of the last digest, so an identical trailing progress event isn't re-buffered. */
233
- private lastNarratedTail;
234
- /** Pending deferred-narration timer; cancelled when the delegation finishes / barge-in lands. */
235
- private narrationTimer;
211
+ /** Spoken progress updates while a delegated run is in flight (pacing + digest state live there). */
212
+ private readonly narrator;
236
213
  /**
237
214
  * The shared, topology-agnostic tool-execution path. The runner delegates all tool-call routing,
238
215
  * abort-controller ownership, and result/error serialization to this broker so the server-bridged
@@ -391,63 +368,6 @@ export declare class RealtimeSessionRunner {
391
368
  * model's current turn are owned by the provider; the consequence for delegated work is ours.
392
369
  */
393
370
  private handleInterruption;
394
- /**
395
- * Runs one delegated call through the injected delegate while owning the NARRATION burst
396
- * around it: progress events are threaded back via {@link DelegateToTargetRequest.OnProgress},
397
- * and when the delegation finishes (success, failure, or abort) any still-pending spoken
398
- * update is cancelled — the final tool result is about to be voiced, so an interim "still
399
- * working…" line is moot.
400
- */
401
- private runDelegateWithNarration;
402
- /**
403
- * Anchors a fresh narration burst when no other delegation is in flight. Deliberately NOT
404
- * reset across bursts: {@link lastNarrationAt} (the ~8s spacing floor is SESSION-global, so
405
- * sequential tool calls seconds apart can never narrate faster than the interval).
406
- */
407
- private beginDelegationBurst;
408
- /** Closes one delegation; when none remain in flight, pending narration is cancelled. */
409
- private endDelegation;
410
- /**
411
- * Consumes one delegated-run progress event:
412
- * - significant steps only (mirrors the client-direct resolver's filter);
413
- * - the message is ALWAYS injected as a background context note (feature-detected —
414
- * {@link IRealtimeSession.SendContextNote} is an optional capability) so the model can
415
- * draw on it whenever it next speaks;
416
- * - a THROTTLED spoken update is scheduled (feature-detected —
417
- * {@link IRealtimeSession.RequestSpokenUpdate} is optional): first at ~5s into the burst,
418
- * then every ~8s, with floods aggregated into ONE digest. Collision with an in-flight
419
- * model response is the DRIVER's obligation (queue or skip) per the
420
- * `RequestSpokenUpdate` contract, so the runner does not gate on busy state.
421
- */
422
- private handleDelegationProgress;
423
- /** Adds a progress message to the digest buffer (deduped, capped, oldest-first). */
424
- private bufferNarrationMessage;
425
- /**
426
- * ms until the next spoken update is allowed. Two constraints, BOTH enforced:
427
- * - first update of a burst: no earlier than ~5s after the burst started;
428
- * - ~8s since the last spoken update, SESSION-global.
429
- */
430
- private nextNarrationDelayMs;
431
- /**
432
- * The effective spoken-update spacing: the deps' configuration-driven
433
- * {@link RealtimeSessionRunnerDeps.NarrationPaceMs} when it is a positive finite number,
434
- * else the built-in {@link RealtimeSessionRunner.NarrationIntervalMs} default.
435
- */
436
- private narrationIntervalMs;
437
- /**
438
- * Speaks the aggregated progress digest — unless the work already finished (buffer cancelled)
439
- * or the session is gone. Per-turn collision safety is the driver's `RequestSpokenUpdate`
440
- * obligation (queue or skip), so no busy gate is needed here.
441
- */
442
- private fireDeferredNarration;
443
- /**
444
- * Cancels any deferred spoken update, drops the digest buffer, and RESETS the burst-timing state
445
- * (anchor time, spoken-update count, dedup tail). Callers invoke this exactly when the current
446
- * burst is ending or being torn down (delegation done, barge-in, reconnect, Stop), so clearing the
447
- * anchor to 0 marks "no active burst" — {@link beginDelegationBurst} then re-anchors the next
448
- * delegation cleanly even if {@link activeDelegations} is still elevated by a stuck delegate.
449
- */
450
- private cancelPendingNarration;
451
371
  /**
452
372
  * Closes the session and finalizes usage. Idempotent: a second call is a no-op.
453
373
  *
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-session-runner.d.ts","sourceRoot":"","sources":["../../src/realtime/realtime-session-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"realtime-session-runner.d.ts","sourceRoot":"","sources":["../../src/realtime/realtime-session-runner.ts"],"names":[],"mappings":"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"}
@@ -21,7 +21,7 @@
21
21
  * @author MemberJunction.com
22
22
  */
23
23
  import { RealtimeToolBroker, INVOKE_TARGET_AGENT_TOOL_NAME, INVOKE_TARGET_AGENT_DESCRIPTION } from './realtime-tool-broker.js';
24
- import { BuildServerNarrationInstructions } from './realtime-narration.js';
24
+ import { DelegationNarrator } from './realtime-delegation-narrator.js';
25
25
  // Re-surface the shared tool-execution contract under this module so existing consumers and tests
26
26
  // keep their import paths. The single source of truth is `realtime-tool-broker.ts`.
27
27
  export { INVOKE_TARGET_AGENT_TOOL_NAME, INVOKE_TARGET_AGENT_DESCRIPTION };
@@ -34,20 +34,6 @@ export { INVOKE_TARGET_AGENT_TOOL_NAME, INVOKE_TARGET_AGENT_DESCRIPTION };
34
34
  export class RealtimeSessionRunner {
35
35
  /** Default upper bound (ms) on the teardown transcript drain — see `TranscriptFlushTimeoutMs`. */
36
36
  static { this.defaultTranscriptFlushTimeoutMs = 5000; }
37
- // ── Delegated-run progress narration (server-bridged B3) ──────────────────
38
- /** First spoken update fires no earlier than this long after a delegation burst starts. */
39
- static { this.firstNarrationDelayMs = 5000; }
40
- /** Minimum gap between SUBSEQUENT spoken updates (floods aggregate into one digest). */
41
- static { this.NarrationIntervalMs = 8000; } // case-violation-ok-legacy-back-compat: the camelCase name is already declared in this class
42
- /** Max progress messages aggregated into one spoken digest. */
43
- static { this.maxDigestMessages = 4; }
44
- /**
45
- * Progress steps worth narrating — mirrors the client-direct resolver's filter so both
46
- * topologies narrate the same signal and drop the same initialization/finalization noise.
47
- */
48
- static { this.significantProgressSteps = [
49
- 'prompt_execution', 'action_execution', 'subagent_execution', 'decision_processing'
50
- ]; }
51
37
  /**
52
38
  * @param deps The injected collaborators that drive the session.
53
39
  */
@@ -65,30 +51,21 @@ export class RealtimeSessionRunner {
65
51
  this.usageDirty = false;
66
52
  /** Pending debounce timer handle for usage checkpoints. */
67
53
  this.usageDebounceTimer = null;
68
- /** Count of delegations currently in flight (anchors the narration burst lifecycle). */
69
- this.activeDelegations = 0;
70
- /** Epoch ms when the current delegation burst began (first in-flight delegation). */
71
- this.narrationBurstStartedAt = 0;
72
- /** Epoch ms of the last spoken update; 0 = never. SESSION-global spacing floor. */
73
- this.lastNarrationAt = 0;
74
- /** Spoken updates so far in the current burst (1-based numbering for the instructions). */
75
- this.narrationCount = 0;
76
- /** Aggregation buffer: distinct progress messages since the last spoken update (oldest first). */
77
- this.pendingNarrationMessages = [];
78
- /** Tail message of the last digest, so an identical trailing progress event isn't re-buffered. */
79
- this.lastNarratedTail = '';
80
- /** Pending deferred-narration timer; cancelled when the delegation finishes / barge-in lands. */
81
- this.narrationTimer = null;
82
54
  /** Count of transcript turns persisted, surfaced in the result. */
83
55
  this.transcriptTurnCount = 0;
84
56
  /** Whether {@link Stop} has been initiated, to make finalization idempotent. */
85
57
  this.stopped = false;
86
58
  this.deps = deps;
59
+ this.narrator = new DelegationNarrator({
60
+ GetSession: () => this.session,
61
+ NarrationInstructionsTemplate: deps.NarrationInstructionsTemplate,
62
+ NarrationPaceMs: deps.NarrationPaceMs,
63
+ });
87
64
  this.toolBroker = new RealtimeToolBroker({
88
65
  // Wrapped so the runner can (a) anchor the narration burst lifecycle around each
89
66
  // delegated run and (b) thread its own OnProgress into the delegate — the production
90
67
  // delegate (BaseAgent.delegateRealtimeToTarget) passes it into the child RunAgent.
91
- DelegateToTarget: (request) => this.runDelegateWithNarration(request),
68
+ DelegateToTarget: (request) => this.narrator.Run(request, (r) => deps.DelegateToTarget(r)),
92
69
  // Route non-target tool calls through the runner so server-channel tools execute via
93
70
  // their dedicated handler before falling back to the generic executor.
94
71
  ExecuteTool: (call) => this.executeNonTargetTool(call),
@@ -292,13 +269,10 @@ export class RealtimeSessionRunner {
292
269
  // SEAM-2: the OLD session is dead — abort any in-flight delegation (its result would
293
270
  // otherwise be relayed to the fresh session as a function_call_output carrying a
294
271
  // call_id the new provider session never issued) and drop any queued (now-stale)
295
- // progress-narration text. We do NOT blanket-reset activeDelegations: each in-flight
296
- // delegation frame self-decrements via its own finally (AbortInFlight unwinds them), so
297
- // zeroing the shared counter here would corrupt it for a CONCURRENT delegation that
298
- // outlives the reconnect (its completion would decrement a count that now belongs to a
299
- // newly-started delegation, suppressing the new one's narration).
272
+ // progress-narration text. The narrator does NOT blanket-reset its in-flight count: each
273
+ // delegation frame self-decrements via its own finally (AbortInFlight unwinds them).
300
274
  this.toolBroker.AbortInFlight();
301
- this.cancelPendingNarration();
275
+ this.narrator.Cancel();
302
276
  try {
303
277
  await this.session?.Close();
304
278
  }
@@ -516,156 +490,7 @@ export class RealtimeSessionRunner {
516
490
  this.deps.LogStatus?.('✋ Barge-in detected — aborting in-flight delegated run if any.', true);
517
491
  this.toolBroker.AbortInFlight();
518
492
  // The user took the floor — any pending spoken progress update is stale.
519
- this.cancelPendingNarration();
520
- }
521
- // ── Delegated-run progress narration (server-bridged B3) ──────────────────
522
- /**
523
- * Runs one delegated call through the injected delegate while owning the NARRATION burst
524
- * around it: progress events are threaded back via {@link DelegateToTargetRequest.OnProgress},
525
- * and when the delegation finishes (success, failure, or abort) any still-pending spoken
526
- * update is cancelled — the final tool result is about to be voiced, so an interim "still
527
- * working…" line is moot.
528
- */
529
- async runDelegateWithNarration(request) {
530
- this.beginDelegationBurst();
531
- try {
532
- return await this.deps.DelegateToTarget({
533
- ...request,
534
- OnProgress: (progress) => this.handleDelegationProgress(progress)
535
- });
536
- }
537
- finally {
538
- this.endDelegation();
539
- }
540
- }
541
- /**
542
- * Anchors a fresh narration burst when no other delegation is in flight. Deliberately NOT
543
- * reset across bursts: {@link lastNarrationAt} (the ~8s spacing floor is SESSION-global, so
544
- * sequential tool calls seconds apart can never narrate faster than the interval).
545
- */
546
- beginDelegationBurst() {
547
- // Anchor a fresh burst either when nothing else is in flight OR when the burst state was reset
548
- // (narrationBurstStartedAt === 0) by a {@link cancelPendingNarration} — e.g. a reconnect that
549
- // aborted the prior delegation(s). The second condition matters when a prior delegation FAILED
550
- // to honor its abort and left {@link activeDelegations} elevated: without it this new delegation
551
- // would inherit the dead burst's stale anchor (collapsing the 5s first-narration delay) and its
552
- // climbing update count. Decoupling the re-anchor from the counter keeps burst timing correct
553
- // regardless of a stuck delegate.
554
- if (this.activeDelegations === 0 || this.narrationBurstStartedAt === 0) {
555
- this.narrationBurstStartedAt = Date.now();
556
- this.narrationCount = 0;
557
- this.pendingNarrationMessages = [];
558
- this.lastNarratedTail = '';
559
- }
560
- this.activeDelegations++;
561
- }
562
- /** Closes one delegation; when none remain in flight, pending narration is cancelled. */
563
- endDelegation() {
564
- this.activeDelegations = Math.max(0, this.activeDelegations - 1);
565
- if (this.activeDelegations === 0) {
566
- this.cancelPendingNarration();
567
- }
568
- }
569
- /**
570
- * Consumes one delegated-run progress event:
571
- * - significant steps only (mirrors the client-direct resolver's filter);
572
- * - the message is ALWAYS injected as a background context note (feature-detected —
573
- * {@link IRealtimeSession.SendContextNote} is an optional capability) so the model can
574
- * draw on it whenever it next speaks;
575
- * - a THROTTLED spoken update is scheduled (feature-detected —
576
- * {@link IRealtimeSession.RequestSpokenUpdate} is optional): first at ~5s into the burst,
577
- * then every ~8s, with floods aggregated into ONE digest. Collision with an in-flight
578
- * model response is the DRIVER's obligation (queue or skip) per the
579
- * `RequestSpokenUpdate` contract, so the runner does not gate on busy state.
580
- */
581
- handleDelegationProgress(progress) {
582
- if (!RealtimeSessionRunner.significantProgressSteps.includes(progress.step)) {
583
- return;
584
- }
585
- const session = this.session;
586
- if (!session || this.activeDelegations === 0) {
587
- return; // session gone / delegation already finished — stale event
588
- }
589
- session.SendContextNote?.(`[delegated-agent progress] ${progress.message}`);
590
- if (!session.RequestSpokenUpdate) {
591
- return; // provider can't voice an instructed one-off update — context note only
592
- }
593
- this.bufferNarrationMessage(progress.message);
594
- if (this.pendingNarrationMessages.length > 0 && !this.narrationTimer) {
595
- this.narrationTimer = setTimeout(() => this.fireDeferredNarration(), this.nextNarrationDelayMs());
596
- }
597
- }
598
- /** Adds a progress message to the digest buffer (deduped, capped, oldest-first). */
599
- bufferNarrationMessage(message) {
600
- if (message === this.lastNarratedTail || this.pendingNarrationMessages.includes(message)) {
601
- return;
602
- }
603
- this.pendingNarrationMessages.push(message);
604
- if (this.pendingNarrationMessages.length > RealtimeSessionRunner.maxDigestMessages) {
605
- this.pendingNarrationMessages.shift();
606
- }
607
- }
608
- /**
609
- * ms until the next spoken update is allowed. Two constraints, BOTH enforced:
610
- * - first update of a burst: no earlier than ~5s after the burst started;
611
- * - ~8s since the last spoken update, SESSION-global.
612
- */
613
- nextNarrationDelayMs() {
614
- const now = Date.now();
615
- const firstAnchor = this.narrationCount === 0
616
- ? this.narrationBurstStartedAt + RealtimeSessionRunner.firstNarrationDelayMs
617
- : 0;
618
- const spacingFloor = this.lastNarrationAt > 0
619
- ? this.lastNarrationAt + this.narrationIntervalMs()
620
- : 0;
621
- return Math.max(50, Math.max(firstAnchor, spacingFloor) - now);
622
- }
623
- /**
624
- * The effective spoken-update spacing: the deps' configuration-driven
625
- * {@link RealtimeSessionRunnerDeps.NarrationPaceMs} when it is a positive finite number,
626
- * else the built-in {@link RealtimeSessionRunner.NarrationIntervalMs} default.
627
- */
628
- narrationIntervalMs() {
629
- const pace = this.deps.NarrationPaceMs;
630
- return typeof pace === 'number' && Number.isFinite(pace) && pace > 0
631
- ? pace
632
- : RealtimeSessionRunner.NarrationIntervalMs;
633
- }
634
- /**
635
- * Speaks the aggregated progress digest — unless the work already finished (buffer cancelled)
636
- * or the session is gone. Per-turn collision safety is the driver's `RequestSpokenUpdate`
637
- * obligation (queue or skip), so no busy gate is needed here.
638
- */
639
- fireDeferredNarration() {
640
- this.narrationTimer = null;
641
- const session = this.session;
642
- if (!session?.RequestSpokenUpdate || this.pendingNarrationMessages.length === 0 || this.activeDelegations === 0) {
643
- this.pendingNarrationMessages = [];
644
- return;
645
- }
646
- const digest = this.pendingNarrationMessages.join(' → ');
647
- this.lastNarratedTail = this.pendingNarrationMessages[this.pendingNarrationMessages.length - 1];
648
- this.pendingNarrationMessages = [];
649
- this.narrationCount++;
650
- this.lastNarrationAt = Date.now();
651
- session.RequestSpokenUpdate(BuildServerNarrationInstructions(this.deps.NarrationInstructionsTemplate, digest, this.narrationCount));
652
- }
653
- /**
654
- * Cancels any deferred spoken update, drops the digest buffer, and RESETS the burst-timing state
655
- * (anchor time, spoken-update count, dedup tail). Callers invoke this exactly when the current
656
- * burst is ending or being torn down (delegation done, barge-in, reconnect, Stop), so clearing the
657
- * anchor to 0 marks "no active burst" — {@link beginDelegationBurst} then re-anchors the next
658
- * delegation cleanly even if {@link activeDelegations} is still elevated by a stuck delegate.
659
- */
660
- cancelPendingNarration() {
661
- if (this.narrationTimer) {
662
- clearTimeout(this.narrationTimer);
663
- this.narrationTimer = null;
664
- }
665
- this.pendingNarrationMessages = [];
666
- this.narrationBurstStartedAt = 0;
667
- this.narrationCount = 0;
668
- this.lastNarratedTail = '';
493
+ this.narrator.Cancel();
669
494
  }
670
495
  /**
671
496
  * Closes the session and finalizes usage. Idempotent: a second call is a no-op.
@@ -692,7 +517,7 @@ export class RealtimeSessionRunner {
692
517
  }
693
518
  await this.flushUsage();
694
519
  // A pending spoken progress update is meaningless on a closing session.
695
- this.cancelPendingNarration();
520
+ this.narrator.Cancel();
696
521
  // Abort any still-in-flight delegation before tearing down.
697
522
  this.toolBroker.AbortInFlight();
698
523
  let errorMessage;