@memberjunction/ai-agents 6.2.0-edge.2 → 6.2.0-edge.4
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/README.md +6 -0
- 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 +51 -2
- package/dist/AgentRunner.d.ts.map +1 -1
- package/dist/AgentRunner.js +121 -23
- package/dist/AgentRunner.js.map +1 -1
- package/dist/ConversationCompactionManager.d.ts +9 -1
- package/dist/ConversationCompactionManager.d.ts.map +1 -1
- package/dist/ConversationCompactionManager.js +6 -3
- package/dist/ConversationCompactionManager.js.map +1 -1
- package/dist/ConversationToolManager.d.ts +13 -2
- package/dist/ConversationToolManager.d.ts.map +1 -1
- package/dist/ConversationToolManager.js +19 -3
- package/dist/ConversationToolManager.js.map +1 -1
- package/dist/KnowledgeAgent.d.ts.map +1 -1
- package/dist/KnowledgeAgent.js +6 -1
- package/dist/KnowledgeAgent.js.map +1 -1
- package/dist/MJAIAgentRequestEntityServer.d.ts +6 -0
- package/dist/MJAIAgentRequestEntityServer.d.ts.map +1 -1
- package/dist/MJAIAgentRequestEntityServer.js +26 -1
- package/dist/MJAIAgentRequestEntityServer.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-run-watchdog.d.ts +65 -5
- package/dist/agent-run-watchdog.d.ts.map +1 -1
- package/dist/agent-run-watchdog.js +143 -28
- package/dist/agent-run-watchdog.js.map +1 -1
- package/dist/agent-types/loop-agent-prompt-params.d.ts +7 -0
- package/dist/agent-types/loop-agent-prompt-params.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-prompt-params.js +1 -0
- package/dist/agent-types/loop-agent-prompt-params.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/artifact-tools/SearchResultSetToolLibrary.js +4 -4
- package/dist/artifact-tools/SearchResultSetToolLibrary.js.map +1 -1
- package/dist/base-agent.d.ts +310 -26
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +867 -244
- package/dist/base-agent.js.map +1 -1
- package/dist/client-tool-results.d.ts +45 -0
- package/dist/client-tool-results.d.ts.map +1 -0
- package/dist/client-tool-results.js +94 -0
- package/dist/client-tool-results.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -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/prior-turn-tool-result-cache.d.ts +31 -12
- package/dist/prior-turn-tool-result-cache.d.ts.map +1 -1
- package/dist/prior-turn-tool-result-cache.js +59 -16
- package/dist/prior-turn-tool-result-cache.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 +63 -3
- package/dist/realtime/bridge-realtime-session-factory.d.ts.map +1 -1
- package/dist/realtime/bridge-realtime-session-factory.js +83 -22
- package/dist/realtime/bridge-realtime-session-factory.js.map +1 -1
- package/dist/realtime/bridge-realtime-usage-recorder.d.ts +81 -0
- package/dist/realtime/bridge-realtime-usage-recorder.d.ts.map +1 -0
- package/dist/realtime/bridge-realtime-usage-recorder.js +194 -0
- package/dist/realtime/bridge-realtime-usage-recorder.js.map +1 -0
- 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/client-only-channel-server.d.ts +83 -0
- package/dist/realtime/client-only-channel-server.d.ts.map +1 -0
- package/dist/realtime/client-only-channel-server.js +107 -0
- package/dist/realtime/client-only-channel-server.js.map +1 -0
- package/dist/realtime/identity-verification-channel-server.d.ts +50 -0
- package/dist/realtime/identity-verification-channel-server.d.ts.map +1 -0
- package/dist/realtime/identity-verification-channel-server.js +66 -0
- package/dist/realtime/identity-verification-channel-server.js.map +1 -0
- package/dist/realtime/interactive-component-channel-server.d.ts +39 -0
- package/dist/realtime/interactive-component-channel-server.d.ts.map +1 -0
- package/dist/realtime/interactive-component-channel-server.js +55 -0
- package/dist/realtime/interactive-component-channel-server.js.map +1 -0
- package/dist/realtime/realtime-avatar-resolution.d.ts +194 -0
- package/dist/realtime/realtime-avatar-resolution.d.ts.map +1 -0
- package/dist/realtime/realtime-avatar-resolution.js +208 -0
- package/dist/realtime/realtime-avatar-resolution.js.map +1 -0
- package/dist/realtime/realtime-channel-policy.d.ts +81 -0
- package/dist/realtime/realtime-channel-policy.d.ts.map +1 -0
- package/dist/realtime/realtime-channel-policy.js +91 -0
- package/dist/realtime/realtime-channel-policy.js.map +1 -0
- package/dist/realtime/realtime-channel-server-host.d.ts +14 -0
- package/dist/realtime/realtime-channel-server-host.d.ts.map +1 -1
- package/dist/realtime/realtime-channel-server-host.js +35 -0
- package/dist/realtime/realtime-channel-server-host.js.map +1 -1
- package/dist/realtime/realtime-client-session-service.d.ts +493 -30
- package/dist/realtime/realtime-client-session-service.d.ts.map +1 -1
- package/dist/realtime/realtime-client-session-service.js +825 -98
- package/dist/realtime/realtime-client-session-service.js.map +1 -1
- package/dist/realtime/realtime-coagent-config.d.ts +94 -15
- package/dist/realtime/realtime-coagent-config.d.ts.map +1 -1
- package/dist/realtime/realtime-coagent-config.js +109 -4
- package/dist/realtime/realtime-coagent-config.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-recording-store.d.ts +136 -16
- package/dist/realtime/realtime-recording-store.d.ts.map +1 -1
- package/dist/realtime/realtime-recording-store.js +505 -39
- package/dist/realtime/realtime-recording-store.js.map +1 -1
- 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 +16 -191
- package/dist/realtime/realtime-session-runner.js.map +1 -1
- package/dist/realtime/realtime-vendor-resolution.d.ts +9 -0
- package/dist/realtime/realtime-vendor-resolution.d.ts.map +1 -1
- package/dist/realtime/realtime-vendor-resolution.js +16 -5
- package/dist/realtime/realtime-vendor-resolution.js.map +1 -1
- package/dist/realtime/realtime-video-output-gate.d.ts +83 -0
- package/dist/realtime/realtime-video-output-gate.d.ts.map +1 -0
- package/dist/realtime/realtime-video-output-gate.js +79 -0
- package/dist/realtime/realtime-video-output-gate.js.map +1 -0
- 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/dist/tool-result-format.d.ts +14 -0
- package/dist/tool-result-format.d.ts.map +1 -1
- package/dist/tool-result-format.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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"}
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Shared MJStorage finalize for realtime session recordings — the single code path both
|
|
3
|
-
* the **server-bridged** capture (`BaseAgent.finalizeRealtimeRecording`) and the **client-direct**
|
|
4
|
-
* browser upload (`RealtimeClientSessionResolver.UploadRealtimeRecording`) use to: resolve the agent's
|
|
5
|
-
* recording storage account, upload the audio, link it to the `AIAgentSession`, and stamp the session's
|
|
6
|
-
* recording fields. Keeps the storage policy in one place rather than duplicated per topology.
|
|
7
|
-
*
|
|
8
|
-
* @module @memberjunction/ai-agents
|
|
9
|
-
*/
|
|
10
1
|
import { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
11
2
|
import { MJAIAgentEntity } from '@memberjunction/core-entities';
|
|
12
3
|
import { RealtimeRecordingMedia } from './realtime-recording-capture.js';
|
|
@@ -44,6 +35,20 @@ export interface StoreRealtimeRecordingInput {
|
|
|
44
35
|
* waveform without re-decoding the audio. Best-effort — a sidecar failure never fails the recording.
|
|
45
36
|
*/
|
|
46
37
|
Peaks?: number[];
|
|
38
|
+
/** Name of the uploaded file. Defaults to `recording.<ext>`. */
|
|
39
|
+
FileName?: string;
|
|
40
|
+
/** Description stored on the `MJ: Files` row (e.g. how a recovered recording was assembled). */
|
|
41
|
+
Description?: string;
|
|
42
|
+
/**
|
|
43
|
+
* When true, the order becomes re-check -> stamp -> link: the session is re-read immediately before
|
|
44
|
+
* the stamp and, if it already has a `RecordingFileID`, that recording is left alone (nothing is
|
|
45
|
+
* linked or stamped; the result is `Superseded`). The link is written only after the stamp saved, so
|
|
46
|
+
* a superseded or failed store never leaves a link row. Best effort, not a guarantee: without a
|
|
47
|
+
* compare-and-set, a recording stamped inside the one load -> save window is still overwritten.
|
|
48
|
+
* Recovery sets this. Left false (the default) for the end-of-call upload, which links and then
|
|
49
|
+
* stamps unconditionally.
|
|
50
|
+
*/
|
|
51
|
+
PreserveExistingRecording?: boolean;
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
49
54
|
* Reads a stored recording's bytes back through **authenticated** MJStorage (server-side `GetObject` on
|
|
@@ -73,12 +78,13 @@ export interface WriteRecordingSegmentInput {
|
|
|
73
78
|
ContextUser: UserInfo;
|
|
74
79
|
}
|
|
75
80
|
/**
|
|
76
|
-
* Writes ONE crash-recovery segment shard (`seg-NNNN.<ext>`) into the session's folder as a RAW
|
|
81
|
+
* Writes ONE crash-recovery segment shard (`seg-NNNN[.r<rate>].<ext>`) into the session's folder as a RAW
|
|
77
82
|
* storage object — no `MJ: Files` row, no session stamping. Shards are durability insurance during a
|
|
78
83
|
* live call (so a browser/tab death loses at most the last window); they are byte-slices of one
|
|
79
84
|
* continuous stream (only the first carries the container header), so they are NOT individually
|
|
80
|
-
* playable — recovery
|
|
81
|
-
* canonical consolidated file lands
|
|
85
|
+
* playable — recovery (see {@link RecoverRealtimeRecordingFromSegments}) concatenates them in index order,
|
|
86
|
+
* filling absent indexes with silence. They are deleted once the canonical consolidated file lands
|
|
87
|
+
* ({@link DeleteRealtimeRecordingSegments}), or by the recovery path once it has stamped its own file. Never throws.
|
|
82
88
|
*
|
|
83
89
|
* @returns `true` on success.
|
|
84
90
|
*/
|
|
@@ -97,8 +103,10 @@ export declare function WriteRecordingPeaksSidecar(sessionID: string, storageAcc
|
|
|
97
103
|
/** @deprecated Use {@link WriteRecordingPeaksSidecar}. */
|
|
98
104
|
export declare function writeRecordingPeaksSidecar(sessionID: string, storageAccountID: string, peaks: number[] | undefined, contextUser: UserInfo): Promise<boolean>;
|
|
99
105
|
/**
|
|
100
|
-
* Deletes
|
|
101
|
-
* after {@link
|
|
106
|
+
* Deletes every `seg-*` shard in a session's folder, leaving the consolidated `recording.*` file. Called
|
|
107
|
+
* after {@link StoreRealtimeRecording} writes the canonical file at end of call. The recovery path
|
|
108
|
+
* ({@link RecoverRealtimeRecordingFromSegments}) does not use this: it deletes only the shards it listed
|
|
109
|
+
* and assembled, so a shard written after its listing is not lost. Never throws.
|
|
102
110
|
*
|
|
103
111
|
* @returns The number of shards deleted.
|
|
104
112
|
*/
|
|
@@ -107,10 +115,20 @@ export declare function DeleteRealtimeRecordingSegments(sessionID: string, stora
|
|
|
107
115
|
export declare function deleteRealtimeRecordingSegments(sessionID: string, storageAccountID: string, contextUser: UserInfo): Promise<number>;
|
|
108
116
|
/** Outcome of {@link storeRealtimeRecording}. */
|
|
109
117
|
export interface StoreRealtimeRecordingResult {
|
|
110
|
-
/**
|
|
118
|
+
/**
|
|
119
|
+
* The uploaded `MJ: Files` id; null when the upload itself failed. With `PreserveExistingRecording`
|
|
120
|
+
* it is also set alongside an `ErrorMessage` when the file was uploaded but the session could not be
|
|
121
|
+
* re-read or stamped: that file is an orphan, neither linked nor stamped.
|
|
122
|
+
*/
|
|
111
123
|
readonly FileID: string | null;
|
|
112
|
-
/** Why it failed, verbatim from the layer that knew. Null on success
|
|
124
|
+
/** Why it failed, verbatim from the layer that knew. Null on success and on `Superseded`. */
|
|
113
125
|
readonly ErrorMessage: string | null;
|
|
126
|
+
/**
|
|
127
|
+
* True only when `PreserveExistingRecording` was set and the re-check right before the stamp found
|
|
128
|
+
* the session already had a recording: the file was uploaded but deliberately not linked or stamped,
|
|
129
|
+
* so it is an orphan. False on every other path.
|
|
130
|
+
*/
|
|
131
|
+
readonly Superseded: boolean;
|
|
114
132
|
}
|
|
115
133
|
/**
|
|
116
134
|
* Uploads a session recording to MJStorage, links it to the `AIAgentSession` (via
|
|
@@ -125,4 +143,106 @@ export interface StoreRealtimeRecordingResult {
|
|
|
125
143
|
export declare function StoreRealtimeRecording(input: StoreRealtimeRecordingInput): Promise<StoreRealtimeRecordingResult>;
|
|
126
144
|
/** @deprecated Use {@link StoreRealtimeRecording}. */
|
|
127
145
|
export declare function storeRealtimeRecording(input: StoreRealtimeRecordingInput): Promise<StoreRealtimeRecordingResult>;
|
|
146
|
+
/** One recovered shard: its zero-based position in the recording and its raw mono PCM16-LE bytes. */
|
|
147
|
+
export interface RecordingSegmentBytes {
|
|
148
|
+
readonly Index: number;
|
|
149
|
+
readonly Bytes: Buffer;
|
|
150
|
+
}
|
|
151
|
+
/** A WAV assembled from shards, plus what had to be invented to keep it aligned. */
|
|
152
|
+
export interface AssembledRecording {
|
|
153
|
+
/** Canonical 44-byte-header mono 16-bit PCM WAV. */
|
|
154
|
+
readonly Wav: Buffer;
|
|
155
|
+
/** Shard indexes (ascending) that were absent and filled with silence. */
|
|
156
|
+
readonly MissingIndexes: number[];
|
|
157
|
+
/** Byte length used for each silent gap; reported even when nothing was missing. */
|
|
158
|
+
readonly GapBytes: number;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Assembles recovered recording shards into one WAV, in index order, filling every absent index with
|
|
162
|
+
* silence. Silence (rather than skipping the gap) keeps all later audio at its true time offset, so it
|
|
163
|
+
* stays aligned with transcript cues, which are offsets from the session's `RecordingStartedAt`.
|
|
164
|
+
*
|
|
165
|
+
* The gap length is the median length of the present shards excluding the highest present index (that
|
|
166
|
+
* one is normally a partial window); with a single shard, that shard's length. It is rounded down to
|
|
167
|
+
* an even byte count (whole 16-bit samples), minimum 2.
|
|
168
|
+
*
|
|
169
|
+
* The byte ceiling does not bound the index range on its own: under the default ceiling a single shard
|
|
170
|
+
* at index ~10^9 still fits, and the missing-index list grows with the highest index. Callers handling
|
|
171
|
+
* untrusted shards must cap the shard count and highest index themselves (recovery does, via
|
|
172
|
+
* {@link MAX_RECOVERY_SEGMENTS}) and pass a smaller `maxDataBytes`.
|
|
173
|
+
*
|
|
174
|
+
* @param segments Recovered shards; any order, unique non-negative integer indexes starting from 0.
|
|
175
|
+
* @param sampleRate Sample rate of the PCM data, in Hz.
|
|
176
|
+
* @param maxDataBytes Ceiling on the PCM data size (shards plus gap fill), checked before anything is
|
|
177
|
+
* allocated. Defaults to the WAV format's own limit; callers handling untrusted shards pass less.
|
|
178
|
+
* @throws Error on no segments, an invalid sample rate or index, a duplicate index, an empty or
|
|
179
|
+
* odd-length shard, or a result too large for a WAV.
|
|
180
|
+
*/
|
|
181
|
+
export declare function BuildRecordingFromSegments(segments: RecordingSegmentBytes[], sampleRate: number, maxDataBytes?: number): AssembledRecording;
|
|
182
|
+
/**
|
|
183
|
+
* Most shards recovery will assemble. At ~15 s per shard this is an hour of audio, far past any real
|
|
184
|
+
* call; a listing at or beyond it (by count or by highest index) is treated as corrupt or hostile and
|
|
185
|
+
* fails closed rather than allocating a huge WAV.
|
|
186
|
+
*/
|
|
187
|
+
export declare const MAX_RECOVERY_SEGMENTS = 240;
|
|
188
|
+
/**
|
|
189
|
+
* Ceiling on the PCM data a recovery will assemble: 384 MiB covers an hour of 48 kHz mono PCM16
|
|
190
|
+
* (345.6 MB) with headroom. Shard sizes are client-controlled (the GraphQL body limit is 50 MB, so one
|
|
191
|
+
* shard can be ~37 MB) and gaps are filled with silence, so without this a session owner could make the
|
|
192
|
+
* janitor allocate gigabytes. Checked against listed sizes, running actual bytes, and the assembled size.
|
|
193
|
+
*
|
|
194
|
+
* It caps the data, not the process's memory: the shard buffers are still held while the WAV is
|
|
195
|
+
* assembled (2x), and storage drivers can copy on read (the S3 driver copies each shard once more), so
|
|
196
|
+
* peak memory for one recovery is up to about three times this: two 288 MB recoveries raised the API
|
|
197
|
+
* process's RSS by 730 MB and 920 MB.
|
|
198
|
+
*/
|
|
199
|
+
export declare const MAX_RECOVERY_BYTES: number;
|
|
200
|
+
/** Input to {@link RecoverRealtimeRecordingFromSegments}. */
|
|
201
|
+
export interface RecoverRealtimeRecordingInput {
|
|
202
|
+
SessionID: string;
|
|
203
|
+
/** Storage account the shards were written to. */
|
|
204
|
+
StorageAccountID: string;
|
|
205
|
+
/** The recording `t0`, stamped on the session (recovery cannot derive it from the shards). */
|
|
206
|
+
StartedAt: Date;
|
|
207
|
+
ContextUser: UserInfo;
|
|
208
|
+
Provider: IMetadataProvider;
|
|
209
|
+
}
|
|
210
|
+
/** What {@link RecoverRealtimeRecordingFromSegments} did. */
|
|
211
|
+
export type RecoverRealtimeRecordingOutcome = 'Recovered' | 'NoSegments' | 'Superseded' | 'Failed';
|
|
212
|
+
/** Result of {@link RecoverRealtimeRecordingFromSegments}. */
|
|
213
|
+
export interface RecoverRealtimeRecordingResult {
|
|
214
|
+
readonly Outcome: RecoverRealtimeRecordingOutcome;
|
|
215
|
+
/** The recovered `MJ: Files` id; set for `Recovered`, and for `Superseded` when an orphan was uploaded. */
|
|
216
|
+
readonly FileID: string | null;
|
|
217
|
+
/** Number of shards found in the session folder. */
|
|
218
|
+
readonly SegmentCount: number;
|
|
219
|
+
/** Shard indexes that were absent and filled with estimated silence. */
|
|
220
|
+
readonly MissingIndexes: number[];
|
|
221
|
+
/** Why recovery failed; null otherwise. */
|
|
222
|
+
readonly ErrorMessage: string | null;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Rebuilds a session's recording from the `seg-*` crash-recovery shards left in its storage folder —
|
|
226
|
+
* for a call whose browser died or whose end-of-call upload never ran, so no `recording.*` exists.
|
|
227
|
+
* Shards are concatenated in order (silence for absent ones), uploaded under a per-attempt
|
|
228
|
+
* `recording-recovered-<epoch ms>-<random hex>.wav`, stamped on the session, linked, and only then
|
|
229
|
+
* deleted. Deletion happens only after a reload confirms the session points at the recovered file, so a
|
|
230
|
+
* failure at any step leaves the shards for the next try. If the session has (or gains) another
|
|
231
|
+
* recording, the outcome is `Superseded` and the shards are kept. Deferring to that recording is best
|
|
232
|
+
* effort: the session is re-checked immediately before the stamp, but a recording stamped inside that
|
|
233
|
+
* one load -> save window is overwritten (there is no compare-and-set).
|
|
234
|
+
*
|
|
235
|
+
* The sample rate comes from the shard keys (`seg-NNNN.r<rate>.pcm`) or, for legacy `seg-NNNN.pcm`
|
|
236
|
+
* shards, from each object's stored content type. When no shard declares a rate (a legacy shard on a
|
|
237
|
+
* driver that keeps no content type, such as Box), it is inferred from the size of the full shards; see
|
|
238
|
+
* {@link LEGACY_SHARD_SECONDS}.
|
|
239
|
+
*
|
|
240
|
+
* Once the stamp has saved, the outcome is `Recovered` even if the confirming reload or a shard delete
|
|
241
|
+
* fails; the shards it could not remove are named in a `LogError` (nothing revisits a stamped session).
|
|
242
|
+
*
|
|
243
|
+
* Never throws: every failure is logged with the session id and returned as `Failed`.
|
|
244
|
+
*
|
|
245
|
+
* @param input Session, storage account, recording `t0`, and server context.
|
|
246
|
+
*/
|
|
247
|
+
export declare function RecoverRealtimeRecordingFromSegments(input: RecoverRealtimeRecordingInput): Promise<RecoverRealtimeRecordingResult>;
|
|
128
248
|
//# sourceMappingURL=realtime-recording-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-recording-store.d.ts","sourceRoot":"","sources":["../../src/realtime/realtime-recording-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"realtime-recording-store.d.ts","sourceRoot":"","sources":["../../src/realtime/realtime-recording-store.ts"],"names":[],"mappings":"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"}
|