@memberjunction/ai-agents 6.2.0-edge.2 → 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.
- package/dist/AgentDecisionService.d.ts +8 -1
- package/dist/AgentDecisionService.d.ts.map +1 -1
- package/dist/AgentDecisionService.js +4 -0
- package/dist/AgentDecisionService.js.map +1 -1
- package/dist/AgentRunner.d.ts +2 -0
- package/dist/AgentRunner.d.ts.map +1 -1
- package/dist/AgentRunner.js +7 -2
- package/dist/AgentRunner.js.map +1 -1
- package/dist/ConversationCompactionManager.d.ts +7 -1
- package/dist/ConversationCompactionManager.d.ts.map +1 -1
- package/dist/ConversationCompactionManager.js +4 -1
- package/dist/ConversationCompactionManager.js.map +1 -1
- package/dist/PayloadFeedbackManager.d.ts +3 -0
- package/dist/PayloadFeedbackManager.d.ts.map +1 -1
- package/dist/PayloadFeedbackManager.js +2 -1
- package/dist/PayloadFeedbackManager.js.map +1 -1
- package/dist/agent-types/loop-agent-type.d.ts +20 -0
- package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-type.js +73 -2
- package/dist/agent-types/loop-agent-type.js.map +1 -1
- package/dist/base-agent.d.ts +35 -8
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +106 -28
- package/dist/base-agent.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/native-tools/action-tool-builder.d.ts +14 -0
- package/dist/native-tools/action-tool-builder.d.ts.map +1 -1
- package/dist/native-tools/action-tool-builder.js +62 -7
- package/dist/native-tools/action-tool-builder.js.map +1 -1
- package/dist/native-tools/control-tools.d.ts +17 -1
- package/dist/native-tools/control-tools.d.ts.map +1 -1
- package/dist/native-tools/control-tools.js +40 -3
- package/dist/native-tools/control-tools.js.map +1 -1
- package/dist/realtime/bridge-host-params.d.ts +22 -0
- package/dist/realtime/bridge-host-params.d.ts.map +1 -0
- package/dist/realtime/bridge-host-params.js +53 -0
- package/dist/realtime/bridge-host-params.js.map +1 -0
- package/dist/realtime/bridge-realtime-session-factory.d.ts +19 -1
- package/dist/realtime/bridge-realtime-session-factory.d.ts.map +1 -1
- package/dist/realtime/bridge-realtime-session-factory.js +15 -2
- package/dist/realtime/bridge-realtime-session-factory.js.map +1 -1
- package/dist/realtime/bridge-session-transcript-sink.d.ts +37 -0
- package/dist/realtime/bridge-session-transcript-sink.d.ts.map +1 -0
- package/dist/realtime/bridge-session-transcript-sink.js +58 -0
- package/dist/realtime/bridge-session-transcript-sink.js.map +1 -0
- package/dist/realtime/realtime-client-session-service.d.ts +68 -5
- package/dist/realtime/realtime-client-session-service.d.ts.map +1 -1
- package/dist/realtime/realtime-client-session-service.js +97 -25
- package/dist/realtime/realtime-client-session-service.js.map +1 -1
- package/dist/realtime/realtime-coagent-resolution.d.ts +90 -0
- package/dist/realtime/realtime-coagent-resolution.d.ts.map +1 -0
- package/dist/realtime/realtime-coagent-resolution.js +186 -0
- package/dist/realtime/realtime-coagent-resolution.js.map +1 -0
- package/dist/realtime/realtime-delegation-narrator.d.ts +97 -0
- package/dist/realtime/realtime-delegation-narrator.d.ts.map +1 -0
- package/dist/realtime/realtime-delegation-narrator.js +162 -0
- package/dist/realtime/realtime-delegation-narrator.js.map +1 -0
- package/dist/realtime/realtime-session-runner.d.ts +2 -82
- package/dist/realtime/realtime-session-runner.d.ts.map +1 -1
- package/dist/realtime/realtime-session-runner.js +12 -187
- package/dist/realtime/realtime-session-runner.js.map +1 -1
- package/dist/rubric-evaluation-agent-runner.js +17 -8
- package/dist/rubric-evaluation-agent-runner.js.map +1 -1
- package/dist/self-check.d.ts +6 -3
- package/dist/self-check.d.ts.map +1 -1
- package/dist/self-check.js +3 -3
- package/dist/self-check.js.map +1 -1
- package/package.json +19 -19
|
@@ -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
|
-
/**
|
|
223
|
-
private
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EACH,iBAAiB,EAEjB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EAEb,sBAAsB,EAIzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAEH,6BAA6B,EAC7B,+BAA+B,EAC/B,uBAAuB,EACvB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACtB,MAAM,wBAAwB,CAAC;AAKhC,OAAO,EACH,6BAA6B,EAC7B,+BAA+B,EAC/B,uBAAuB,EACvB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACtB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACtC;;;;OAIG;IACH,KAAK,EAAE,iBAAiB,CAAC;IAEzB;;;;;OAKG;IACH,aAAa,EAAE,qBAAqB,CAAC;IAErC;;;OAGG;IACH,UAAU,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAEtC;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAE9C;;;;;;OAMG;IACH,wBAAwB,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAEpF;;;;;OAKG;IACH,gBAAgB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAEjF;;;;OAIG;IACH,WAAW,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAEtE;;;;;;OAMG;IACH,iBAAiB,EAAE,CAAC,UAAU,EAAE,kBAAkB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAE9E;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,2BAA2B,CAAC;IAExC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAExC;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAElC;;;;OAIG;IACH,eAAe,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzD;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC,+EAA+E;IAC/E,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAEnC;;;;;;OAMG;IACH,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9C;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC,4CAA4C;IAC5C,SAAS,CAAC,EAAE,oBAAoB,CAAC;IAEjC,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,UAAU,EAAE,aAAa,CAAC;IAC1B,2DAA2D;IAC3D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,qBAAa,qBAAqB;IAC9B,kGAAkG;IAClG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,+BAA+B,CAAQ;
|
|
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 {
|
|
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.
|
|
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.
|
|
296
|
-
// delegation frame self-decrements via its own finally (AbortInFlight unwinds them)
|
|
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.
|
|
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.
|
|
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.
|
|
520
|
+
this.narrator.Cancel();
|
|
696
521
|
// Abort any still-in-flight delegation before tearing down.
|
|
697
522
|
this.toolBroker.AbortInFlight();
|
|
698
523
|
let errorMessage;
|