@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.
Files changed (148) hide show
  1. package/README.md +6 -0
  2. package/dist/AgentDecisionService.d.ts +8 -1
  3. package/dist/AgentDecisionService.d.ts.map +1 -1
  4. package/dist/AgentDecisionService.js +4 -0
  5. package/dist/AgentDecisionService.js.map +1 -1
  6. package/dist/AgentRunner.d.ts +51 -2
  7. package/dist/AgentRunner.d.ts.map +1 -1
  8. package/dist/AgentRunner.js +121 -23
  9. package/dist/AgentRunner.js.map +1 -1
  10. package/dist/ConversationCompactionManager.d.ts +9 -1
  11. package/dist/ConversationCompactionManager.d.ts.map +1 -1
  12. package/dist/ConversationCompactionManager.js +6 -3
  13. package/dist/ConversationCompactionManager.js.map +1 -1
  14. package/dist/ConversationToolManager.d.ts +13 -2
  15. package/dist/ConversationToolManager.d.ts.map +1 -1
  16. package/dist/ConversationToolManager.js +19 -3
  17. package/dist/ConversationToolManager.js.map +1 -1
  18. package/dist/KnowledgeAgent.d.ts.map +1 -1
  19. package/dist/KnowledgeAgent.js +6 -1
  20. package/dist/KnowledgeAgent.js.map +1 -1
  21. package/dist/MJAIAgentRequestEntityServer.d.ts +6 -0
  22. package/dist/MJAIAgentRequestEntityServer.d.ts.map +1 -1
  23. package/dist/MJAIAgentRequestEntityServer.js +26 -1
  24. package/dist/MJAIAgentRequestEntityServer.js.map +1 -1
  25. package/dist/PayloadFeedbackManager.d.ts +3 -0
  26. package/dist/PayloadFeedbackManager.d.ts.map +1 -1
  27. package/dist/PayloadFeedbackManager.js +2 -1
  28. package/dist/PayloadFeedbackManager.js.map +1 -1
  29. package/dist/agent-run-watchdog.d.ts +65 -5
  30. package/dist/agent-run-watchdog.d.ts.map +1 -1
  31. package/dist/agent-run-watchdog.js +143 -28
  32. package/dist/agent-run-watchdog.js.map +1 -1
  33. package/dist/agent-types/loop-agent-prompt-params.d.ts +7 -0
  34. package/dist/agent-types/loop-agent-prompt-params.d.ts.map +1 -1
  35. package/dist/agent-types/loop-agent-prompt-params.js +1 -0
  36. package/dist/agent-types/loop-agent-prompt-params.js.map +1 -1
  37. package/dist/agent-types/loop-agent-type.d.ts +20 -0
  38. package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
  39. package/dist/agent-types/loop-agent-type.js +73 -2
  40. package/dist/agent-types/loop-agent-type.js.map +1 -1
  41. package/dist/artifact-tools/SearchResultSetToolLibrary.js +4 -4
  42. package/dist/artifact-tools/SearchResultSetToolLibrary.js.map +1 -1
  43. package/dist/base-agent.d.ts +310 -26
  44. package/dist/base-agent.d.ts.map +1 -1
  45. package/dist/base-agent.js +867 -244
  46. package/dist/base-agent.js.map +1 -1
  47. package/dist/client-tool-results.d.ts +45 -0
  48. package/dist/client-tool-results.d.ts.map +1 -0
  49. package/dist/client-tool-results.js +94 -0
  50. package/dist/client-tool-results.js.map +1 -0
  51. package/dist/index.d.ts +9 -0
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +9 -0
  54. package/dist/index.js.map +1 -1
  55. package/dist/native-tools/action-tool-builder.d.ts +14 -0
  56. package/dist/native-tools/action-tool-builder.d.ts.map +1 -1
  57. package/dist/native-tools/action-tool-builder.js +62 -7
  58. package/dist/native-tools/action-tool-builder.js.map +1 -1
  59. package/dist/native-tools/control-tools.d.ts +17 -1
  60. package/dist/native-tools/control-tools.d.ts.map +1 -1
  61. package/dist/native-tools/control-tools.js +40 -3
  62. package/dist/native-tools/control-tools.js.map +1 -1
  63. package/dist/prior-turn-tool-result-cache.d.ts +31 -12
  64. package/dist/prior-turn-tool-result-cache.d.ts.map +1 -1
  65. package/dist/prior-turn-tool-result-cache.js +59 -16
  66. package/dist/prior-turn-tool-result-cache.js.map +1 -1
  67. package/dist/realtime/bridge-host-params.d.ts +22 -0
  68. package/dist/realtime/bridge-host-params.d.ts.map +1 -0
  69. package/dist/realtime/bridge-host-params.js +53 -0
  70. package/dist/realtime/bridge-host-params.js.map +1 -0
  71. package/dist/realtime/bridge-realtime-session-factory.d.ts +63 -3
  72. package/dist/realtime/bridge-realtime-session-factory.d.ts.map +1 -1
  73. package/dist/realtime/bridge-realtime-session-factory.js +83 -22
  74. package/dist/realtime/bridge-realtime-session-factory.js.map +1 -1
  75. package/dist/realtime/bridge-realtime-usage-recorder.d.ts +81 -0
  76. package/dist/realtime/bridge-realtime-usage-recorder.d.ts.map +1 -0
  77. package/dist/realtime/bridge-realtime-usage-recorder.js +194 -0
  78. package/dist/realtime/bridge-realtime-usage-recorder.js.map +1 -0
  79. package/dist/realtime/bridge-session-transcript-sink.d.ts +37 -0
  80. package/dist/realtime/bridge-session-transcript-sink.d.ts.map +1 -0
  81. package/dist/realtime/bridge-session-transcript-sink.js +58 -0
  82. package/dist/realtime/bridge-session-transcript-sink.js.map +1 -0
  83. package/dist/realtime/client-only-channel-server.d.ts +83 -0
  84. package/dist/realtime/client-only-channel-server.d.ts.map +1 -0
  85. package/dist/realtime/client-only-channel-server.js +107 -0
  86. package/dist/realtime/client-only-channel-server.js.map +1 -0
  87. package/dist/realtime/identity-verification-channel-server.d.ts +50 -0
  88. package/dist/realtime/identity-verification-channel-server.d.ts.map +1 -0
  89. package/dist/realtime/identity-verification-channel-server.js +66 -0
  90. package/dist/realtime/identity-verification-channel-server.js.map +1 -0
  91. package/dist/realtime/interactive-component-channel-server.d.ts +39 -0
  92. package/dist/realtime/interactive-component-channel-server.d.ts.map +1 -0
  93. package/dist/realtime/interactive-component-channel-server.js +55 -0
  94. package/dist/realtime/interactive-component-channel-server.js.map +1 -0
  95. package/dist/realtime/realtime-avatar-resolution.d.ts +194 -0
  96. package/dist/realtime/realtime-avatar-resolution.d.ts.map +1 -0
  97. package/dist/realtime/realtime-avatar-resolution.js +208 -0
  98. package/dist/realtime/realtime-avatar-resolution.js.map +1 -0
  99. package/dist/realtime/realtime-channel-policy.d.ts +81 -0
  100. package/dist/realtime/realtime-channel-policy.d.ts.map +1 -0
  101. package/dist/realtime/realtime-channel-policy.js +91 -0
  102. package/dist/realtime/realtime-channel-policy.js.map +1 -0
  103. package/dist/realtime/realtime-channel-server-host.d.ts +14 -0
  104. package/dist/realtime/realtime-channel-server-host.d.ts.map +1 -1
  105. package/dist/realtime/realtime-channel-server-host.js +35 -0
  106. package/dist/realtime/realtime-channel-server-host.js.map +1 -1
  107. package/dist/realtime/realtime-client-session-service.d.ts +493 -30
  108. package/dist/realtime/realtime-client-session-service.d.ts.map +1 -1
  109. package/dist/realtime/realtime-client-session-service.js +825 -98
  110. package/dist/realtime/realtime-client-session-service.js.map +1 -1
  111. package/dist/realtime/realtime-coagent-config.d.ts +94 -15
  112. package/dist/realtime/realtime-coagent-config.d.ts.map +1 -1
  113. package/dist/realtime/realtime-coagent-config.js +109 -4
  114. package/dist/realtime/realtime-coagent-config.js.map +1 -1
  115. package/dist/realtime/realtime-coagent-resolution.d.ts +90 -0
  116. package/dist/realtime/realtime-coagent-resolution.d.ts.map +1 -0
  117. package/dist/realtime/realtime-coagent-resolution.js +186 -0
  118. package/dist/realtime/realtime-coagent-resolution.js.map +1 -0
  119. package/dist/realtime/realtime-delegation-narrator.d.ts +97 -0
  120. package/dist/realtime/realtime-delegation-narrator.d.ts.map +1 -0
  121. package/dist/realtime/realtime-delegation-narrator.js +162 -0
  122. package/dist/realtime/realtime-delegation-narrator.js.map +1 -0
  123. package/dist/realtime/realtime-recording-store.d.ts +136 -16
  124. package/dist/realtime/realtime-recording-store.d.ts.map +1 -1
  125. package/dist/realtime/realtime-recording-store.js +505 -39
  126. package/dist/realtime/realtime-recording-store.js.map +1 -1
  127. package/dist/realtime/realtime-session-runner.d.ts +2 -82
  128. package/dist/realtime/realtime-session-runner.d.ts.map +1 -1
  129. package/dist/realtime/realtime-session-runner.js +16 -191
  130. package/dist/realtime/realtime-session-runner.js.map +1 -1
  131. package/dist/realtime/realtime-vendor-resolution.d.ts +9 -0
  132. package/dist/realtime/realtime-vendor-resolution.d.ts.map +1 -1
  133. package/dist/realtime/realtime-vendor-resolution.js +16 -5
  134. package/dist/realtime/realtime-vendor-resolution.js.map +1 -1
  135. package/dist/realtime/realtime-video-output-gate.d.ts +83 -0
  136. package/dist/realtime/realtime-video-output-gate.d.ts.map +1 -0
  137. package/dist/realtime/realtime-video-output-gate.js +79 -0
  138. package/dist/realtime/realtime-video-output-gate.js.map +1 -0
  139. package/dist/rubric-evaluation-agent-runner.js +17 -8
  140. package/dist/rubric-evaluation-agent-runner.js.map +1 -1
  141. package/dist/self-check.d.ts +6 -3
  142. package/dist/self-check.d.ts.map +1 -1
  143. package/dist/self-check.js +3 -3
  144. package/dist/self-check.js.map +1 -1
  145. package/dist/tool-result-format.d.ts +14 -0
  146. package/dist/tool-result-format.d.ts.map +1 -1
  147. package/dist/tool-result-format.js.map +1 -1
  148. package/package.json +19 -19
@@ -0,0 +1,81 @@
1
+ import type { RealtimeUsage } from '@memberjunction/ai';
2
+ import { type RealtimeUsageRecord } from '@memberjunction/ai-engine-base';
3
+ /** How long after the first unwritten update the recorder writes, in milliseconds. */
4
+ export declare const BRIDGE_USAGE_FLUSH_MS = 10000;
5
+ /** One write: the token amounts since the previous write, and the per-modality usage. */
6
+ export interface BridgeUsageWrite {
7
+ /** Input tokens to add. */
8
+ InputTokens: number;
9
+ /** Output tokens to add. */
10
+ OutputTokens: number;
11
+ /** Per-modality amounts to add, and the latest running totals; absent when the session reported none. */
12
+ Details?: RealtimeUsageRecord;
13
+ }
14
+ /** Stores one {@link BridgeUsageWrite}; resolves `false` when nothing was stored. */
15
+ export type BridgeUsageWriter = (write: BridgeUsageWrite) => Promise<boolean>;
16
+ /** What a recorder has accepted over its life, for the session's closing log line. */
17
+ export interface BridgeUsageTotals {
18
+ InputTokens: number;
19
+ OutputTokens: number;
20
+ /** Seconds of video the model generated (an avatar). */
21
+ OutputVideoSeconds: number;
22
+ }
23
+ /**
24
+ * Adds up one bridged session's usage and writes it on a timer and at close. A failed write keeps its usage for the
25
+ * next one; the write at close is the last attempt.
26
+ */
27
+ export declare class BridgeRealtimeUsageRecorder {
28
+ private readonly writer;
29
+ private readonly label;
30
+ private readonly flushMs;
31
+ private inputTokens;
32
+ private outputTokens;
33
+ private details;
34
+ private timer;
35
+ private writeChain;
36
+ private closed;
37
+ private lateUpdateLogged;
38
+ private readonly accepted;
39
+ /**
40
+ * @param writer Stores one write.
41
+ * @param label Names the session in log lines (for example its prompt run id).
42
+ * @param flushMs How long after the first unwritten update to write.
43
+ */
44
+ constructor(writer: BridgeUsageWriter, label: string, flushMs?: number);
45
+ /** What the recorder has accepted so far. */
46
+ get Totals(): Readonly<BridgeUsageTotals>;
47
+ /** Whether the recorder holds usage that is not written yet. */
48
+ get HasUnwrittenUsage(): boolean;
49
+ /**
50
+ * Takes one `OnUsage` update. An update that adds nothing is ignored; the first one that does starts the write timer.
51
+ * After {@link Close} an update is dropped, and the first one dropped is logged.
52
+ *
53
+ * @param usage The update the session reported.
54
+ */
55
+ Add(usage: RealtimeUsage): void;
56
+ /** Writes what is unwritten now, after any write in progress. Never rejects. */
57
+ Flush(): Promise<void>;
58
+ /**
59
+ * Stops taking updates and writes what is unwritten. When that last write fails, its amounts are logged and dropped.
60
+ * Safe to call more than once.
61
+ */
62
+ Close(): Promise<void>;
63
+ /** Adds the update's token totals to the unwritten ones. Returns whether it added anything. */
64
+ private addTokens;
65
+ /** Adds the update's per-modality usage and session duration to the unwritten record. Returns whether it held any. */
66
+ private addDetails;
67
+ /** Starts the write timer unless one is running. The timer never keeps the process alive. */
68
+ private armWrite;
69
+ private clearTimer;
70
+ /** Writes the unwritten usage once; a failed write puts its usage back. */
71
+ private writeUnwritten;
72
+ /** Moves the unwritten usage into a write, or returns `null` when there is none. */
73
+ private takeUnwritten;
74
+ /** Puts a failed write's usage back, together with what arrived since. */
75
+ private putBack;
76
+ /** Forgets the unwritten usage. */
77
+ private clearUnwritten;
78
+ /** Logs the first update dropped after close. */
79
+ private logLateUpdate;
80
+ }
81
+ //# sourceMappingURL=bridge-realtime-usage-recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-realtime-usage-recorder.d.ts","sourceRoot":"","sources":["../../src/realtime/bridge-realtime-usage-recorder.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAA4C,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAEpH,sFAAsF;AACtF,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C,yFAAyF;AACzF,MAAM,WAAW,gBAAgB;IAC7B,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,yGAAyG;IACzG,OAAO,CAAC,EAAE,mBAAmB,CAAC;CACjC;AAED,qFAAqF;AACrF,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9E,sFAAsF;AACtF,MAAM,WAAW,iBAAiB;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,kBAAkB,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,qBAAa,2BAA2B;IAgBhC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAjB5B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiF;IAE1G;;;;OAIG;gBAEkB,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAA8B;IAG5D,6CAA6C;IAC7C,IAAW,MAAM,IAAI,QAAQ,CAAC,iBAAiB,CAAC,CAE/C;IAED,gEAAgE;IAChE,IAAW,iBAAiB,IAAI,OAAO,CAEtC;IAED;;;;;OAKG;IACI,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAYtC,gFAAgF;IACzE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM7B;;;OAGG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBnC,+FAA+F;IAC/F,OAAO,CAAC,SAAS;IAejB,sHAAsH;IACtH,OAAO,CAAC,UAAU;IAclB,6FAA6F;IAC7F,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,UAAU;IAOlB,2EAA2E;YAC7D,cAAc;IAgB5B,oFAAoF;IACpF,OAAO,CAAC,aAAa;IAarB,0EAA0E;IAC1E,OAAO,CAAC,OAAO;IAQf,mCAAmC;IACnC,OAAO,CAAC,cAAc;IAMtB,iDAAiD;IACjD,OAAO,CAAC,aAAa;CAUxB"}
@@ -0,0 +1,194 @@
1
+ /**
2
+ * @fileoverview Records the usage a server-held (bridged) realtime session reports. It adds up the session's `OnUsage`
3
+ * updates and writes them through a writer (the co-agent prompt run's usage accumulation) {@link BRIDGE_USAGE_FLUSH_MS}
4
+ * after the first unwritten update, and once more when it is closed, so the run is priced at finalize from its final
5
+ * counts. After it is closed it stores nothing more. Per-modality usage follows the realtime usage record's rules
6
+ * (`AddRealtimeUsageRecord`): amounts add up, running totals keep the larger value.
7
+ *
8
+ * @module @memberjunction/ai-agents
9
+ */
10
+ import { LogError, LogStatus, LogStatusEx } from '@memberjunction/core';
11
+ import { AddRealtimeUsageRecord, HasRealtimeUsage } from '@memberjunction/ai-engine-base';
12
+ /** How long after the first unwritten update the recorder writes, in milliseconds. */
13
+ export const BRIDGE_USAGE_FLUSH_MS = 10_000;
14
+ /**
15
+ * Adds up one bridged session's usage and writes it on a timer and at close. A failed write keeps its usage for the
16
+ * next one; the write at close is the last attempt.
17
+ */
18
+ export class BridgeRealtimeUsageRecorder {
19
+ /**
20
+ * @param writer Stores one write.
21
+ * @param label Names the session in log lines (for example its prompt run id).
22
+ * @param flushMs How long after the first unwritten update to write.
23
+ */
24
+ constructor(writer, label, flushMs = BRIDGE_USAGE_FLUSH_MS) {
25
+ this.writer = writer;
26
+ this.label = label;
27
+ this.flushMs = flushMs;
28
+ this.inputTokens = 0;
29
+ this.outputTokens = 0;
30
+ this.details = null;
31
+ this.timer = null;
32
+ this.writeChain = Promise.resolve();
33
+ this.closed = false;
34
+ this.lateUpdateLogged = false;
35
+ this.accepted = { InputTokens: 0, OutputTokens: 0, OutputVideoSeconds: 0 };
36
+ }
37
+ /** What the recorder has accepted so far. */
38
+ get Totals() {
39
+ return this.accepted;
40
+ }
41
+ /** Whether the recorder holds usage that is not written yet. */
42
+ get HasUnwrittenUsage() {
43
+ return this.inputTokens > 0 || this.outputTokens > 0 || HasRealtimeUsage(this.details);
44
+ }
45
+ /**
46
+ * Takes one `OnUsage` update. An update that adds nothing is ignored; the first one that does starts the write timer.
47
+ * After {@link Close} an update is dropped, and the first one dropped is logged.
48
+ *
49
+ * @param usage The update the session reported.
50
+ */
51
+ Add(usage) {
52
+ if (this.closed) {
53
+ this.logLateUpdate(usage);
54
+ return;
55
+ }
56
+ const addedTokens = this.addTokens(usage);
57
+ const addedDetails = this.addDetails(usage);
58
+ if (addedTokens || addedDetails) {
59
+ this.armWrite();
60
+ }
61
+ }
62
+ /** Writes what is unwritten now, after any write in progress. Never rejects. */
63
+ Flush() {
64
+ this.clearTimer();
65
+ this.writeChain = this.writeChain.then(() => this.writeUnwritten());
66
+ return this.writeChain;
67
+ }
68
+ /**
69
+ * Stops taking updates and writes what is unwritten. When that last write fails, its amounts are logged and dropped.
70
+ * Safe to call more than once.
71
+ */
72
+ async Close() {
73
+ if (this.closed) {
74
+ await this.writeChain;
75
+ return;
76
+ }
77
+ this.closed = true;
78
+ await this.Flush();
79
+ if (this.HasUnwrittenUsage) {
80
+ LogError(`[Bridged usage] ${this.label}: the last usage write failed; not stored: ${this.inputTokens} input and ` +
81
+ `${this.outputTokens} output tokens.`);
82
+ this.clearUnwritten();
83
+ }
84
+ LogStatusEx({
85
+ message: `[Bridged usage] ${this.label}: ${this.accepted.InputTokens} input and ${this.accepted.OutputTokens} output ` +
86
+ `tokens, ${this.accepted.OutputVideoSeconds} s of generated video.`,
87
+ verboseOnly: true,
88
+ });
89
+ }
90
+ /** Adds the update's token totals to the unwritten ones. Returns whether it added anything. */
91
+ addTokens(usage) {
92
+ let added = false;
93
+ if (isAmount(usage.InputTokens)) {
94
+ this.inputTokens += usage.InputTokens;
95
+ this.accepted.InputTokens += usage.InputTokens;
96
+ added = true;
97
+ }
98
+ if (isAmount(usage.OutputTokens)) {
99
+ this.outputTokens += usage.OutputTokens;
100
+ this.accepted.OutputTokens += usage.OutputTokens;
101
+ added = true;
102
+ }
103
+ return added;
104
+ }
105
+ /** Adds the update's per-modality usage and session duration to the unwritten record. Returns whether it held any. */
106
+ addDetails(usage) {
107
+ const update = AddRealtimeUsageRecord(null, {
108
+ Input: usage.InputTokenDetails,
109
+ Output: usage.OutputTokenDetails,
110
+ DurationSeconds: usage.DurationSeconds,
111
+ });
112
+ if (!HasRealtimeUsage(update)) {
113
+ return false;
114
+ }
115
+ this.details = AddRealtimeUsageRecord(this.details, update);
116
+ this.accepted.OutputVideoSeconds += update.Output?.VideoSeconds ?? 0;
117
+ return true;
118
+ }
119
+ /** Starts the write timer unless one is running. The timer never keeps the process alive. */
120
+ armWrite() {
121
+ if (this.timer) {
122
+ return;
123
+ }
124
+ this.timer = setTimeout(() => {
125
+ this.timer = null;
126
+ void this.Flush();
127
+ }, this.flushMs);
128
+ this.timer.unref?.();
129
+ }
130
+ clearTimer() {
131
+ if (this.timer) {
132
+ clearTimeout(this.timer);
133
+ this.timer = null;
134
+ }
135
+ }
136
+ /** Writes the unwritten usage once; a failed write puts its usage back. */
137
+ async writeUnwritten() {
138
+ const write = this.takeUnwritten();
139
+ if (!write) {
140
+ return;
141
+ }
142
+ let stored = false;
143
+ try {
144
+ stored = await this.writer(write);
145
+ }
146
+ catch (error) {
147
+ LogError(`[Bridged usage] ${this.label}: writing usage failed: ${error instanceof Error ? error.message : String(error)}`);
148
+ }
149
+ if (!stored) {
150
+ this.putBack(write);
151
+ }
152
+ }
153
+ /** Moves the unwritten usage into a write, or returns `null` when there is none. */
154
+ takeUnwritten() {
155
+ if (!this.HasUnwrittenUsage) {
156
+ return null;
157
+ }
158
+ const write = {
159
+ InputTokens: this.inputTokens,
160
+ OutputTokens: this.outputTokens,
161
+ ...(this.details && HasRealtimeUsage(this.details) ? { Details: this.details } : {}),
162
+ };
163
+ this.clearUnwritten();
164
+ return write;
165
+ }
166
+ /** Puts a failed write's usage back, together with what arrived since. */
167
+ putBack(write) {
168
+ this.inputTokens += write.InputTokens;
169
+ this.outputTokens += write.OutputTokens;
170
+ if (write.Details) {
171
+ this.details = AddRealtimeUsageRecord(write.Details, this.details ?? {});
172
+ }
173
+ }
174
+ /** Forgets the unwritten usage. */
175
+ clearUnwritten() {
176
+ this.inputTokens = 0;
177
+ this.outputTokens = 0;
178
+ this.details = null;
179
+ }
180
+ /** Logs the first update dropped after close. */
181
+ logLateUpdate(usage) {
182
+ if (this.lateUpdateLogged) {
183
+ return;
184
+ }
185
+ this.lateUpdateLogged = true;
186
+ LogStatus(`[Bridged usage] ${this.label}: usage reported after the session's run was finalized is not stored ` +
187
+ `(first dropped: ${usage.InputTokens} input and ${usage.OutputTokens} output tokens).`);
188
+ }
189
+ }
190
+ /** Whether a reported token total is one to add: a finite number above zero. */
191
+ function isAmount(value) {
192
+ return typeof value === 'number' && Number.isFinite(value) && value > 0;
193
+ }
194
+ //# sourceMappingURL=bridge-realtime-usage-recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-realtime-usage-recorder.js","sourceRoot":"","sources":["../../src/realtime/bridge-realtime-usage-recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @fileoverview `CreateBridgeSessionTranscriptSink` — persists a bridged call's transcript into the
3
+ * `MJ: Conversations` row that belongs to THAT session.
4
+ *
5
+ * The room sink ({@link CreateBridgeRoomTranscriptSink}) is the right shape for a multi-party meeting: one
6
+ * "Meeting Room" conversation per room, written by an elected scribe. A phone call is the opposite — one
7
+ * session, one remote party, a conversation the session manager already created. Routing a call through the
8
+ * room sink wrote its transcript into a separate global conversation owned by the system user while the call's
9
+ * own conversation stayed empty. This sink writes each final line to the session's own conversation, in order,
10
+ * the same way the browser path does (`AgentSessionID` and `UserID` stamped on every turn).
11
+ *
12
+ * @module @memberjunction/ai-agents
13
+ * @author MemberJunction.com
14
+ */
15
+ import type { BridgeRoomTranscriptSink } from './bridge-room-transcript-sink.js';
16
+ /** What identifies the conversation a session's transcript belongs to. */
17
+ export interface BridgeSessionTranscriptSinkOptions {
18
+ /** The `MJ: Conversations` row to write turns into (the one the session manager created for the call). */
19
+ ConversationID: string;
20
+ /** The `MJ: AI Agent Sessions` row the turns belong to. */
21
+ AgentSessionID: string;
22
+ /**
23
+ * The agent attributed on the agent's own turns. Defaults to the line's agent (the voicing co-agent); a call
24
+ * passes the TARGET agent instead, since that is the persona the caller believes they are talking to.
25
+ */
26
+ AgentID?: string;
27
+ }
28
+ /**
29
+ * Builds a transcript sink bound to one session's conversation. Pass the result as
30
+ * `StartBridgeSessionParams.TranscriptSink`. Writes are serialized so turns land in the order they were spoken,
31
+ * and a failed write is logged without blocking the ones behind it.
32
+ *
33
+ * @param options The conversation, session and (optional) agent attribution.
34
+ * @returns The sink.
35
+ */
36
+ export declare function CreateBridgeSessionTranscriptSink(options: BridgeSessionTranscriptSinkOptions): BridgeRoomTranscriptSink;
37
+ //# sourceMappingURL=bridge-session-transcript-sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-session-transcript-sink.d.ts","sourceRoot":"","sources":["../../src/realtime/bridge-session-transcript-sink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,wBAAwB,EAA6B,MAAM,+BAA+B,CAAC;AAEzG,0EAA0E;AAC1E,MAAM,WAAW,kCAAkC;IAC/C,0GAA0G;IAC1G,cAAc,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAID;;;;;;;GAOG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,kCAAkC,GAAG,wBAAwB,CAUvH"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @fileoverview `CreateBridgeSessionTranscriptSink` — persists a bridged call's transcript into the
3
+ * `MJ: Conversations` row that belongs to THAT session.
4
+ *
5
+ * The room sink ({@link CreateBridgeRoomTranscriptSink}) is the right shape for a multi-party meeting: one
6
+ * "Meeting Room" conversation per room, written by an elected scribe. A phone call is the opposite — one
7
+ * session, one remote party, a conversation the session manager already created. Routing a call through the
8
+ * room sink wrote its transcript into a separate global conversation owned by the system user while the call's
9
+ * own conversation stayed empty. This sink writes each final line to the session's own conversation, in order,
10
+ * the same way the browser path does (`AgentSessionID` and `UserID` stamped on every turn).
11
+ *
12
+ * @module @memberjunction/ai-agents
13
+ * @author MemberJunction.com
14
+ */
15
+ import { LogError } from '@memberjunction/core';
16
+ const CONVERSATION_DETAIL_ENTITY = 'MJ: Conversation Details';
17
+ /**
18
+ * Builds a transcript sink bound to one session's conversation. Pass the result as
19
+ * `StartBridgeSessionParams.TranscriptSink`. Writes are serialized so turns land in the order they were spoken,
20
+ * and a failed write is logged without blocking the ones behind it.
21
+ *
22
+ * @param options The conversation, session and (optional) agent attribution.
23
+ * @returns The sink.
24
+ */
25
+ export function CreateBridgeSessionTranscriptSink(options) {
26
+ let chain = Promise.resolve();
27
+ return (line, contextUser, provider) => {
28
+ if (!contextUser || !provider) {
29
+ return Promise.resolve(); // a server-side write needs a user + provider
30
+ }
31
+ const write = chain.then(() => WriteSessionTurn(options, line, contextUser, provider));
32
+ chain = write.then(() => undefined, () => undefined);
33
+ return write;
34
+ };
35
+ }
36
+ /** Writes one `MJ: Conversation Details` row for a final transcript line. Never throws. */
37
+ async function WriteSessionTurn(options, line, contextUser, provider) {
38
+ try {
39
+ const detail = await provider.GetEntityObject(CONVERSATION_DETAIL_ENTITY, contextUser);
40
+ detail.NewRecord();
41
+ detail.ConversationID = options.ConversationID;
42
+ detail.Role = line.IsAgentSpeech ? 'AI' : 'User';
43
+ detail.Message = line.Text;
44
+ detail.AgentSessionID = options.AgentSessionID;
45
+ detail.UserID = contextUser.ID;
46
+ const agentID = options.AgentID ?? line.AgentID;
47
+ if (line.IsAgentSpeech && agentID) {
48
+ detail.AgentID = agentID;
49
+ }
50
+ if (!(await detail.Save())) {
51
+ LogError(`CreateBridgeSessionTranscriptSink: failed to write a transcript turn for session ${options.AgentSessionID}: ${detail.LatestResult?.CompleteMessage ?? 'unknown error'}`);
52
+ }
53
+ }
54
+ catch (error) {
55
+ LogError(`CreateBridgeSessionTranscriptSink: transcript write threw for session ${options.AgentSessionID}: ${error instanceof Error ? error.message : String(error)}`);
56
+ }
57
+ }
58
+ //# sourceMappingURL=bridge-session-transcript-sink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-session-transcript-sink.js","sourceRoot":"","sources":["../../src/realtime/bridge-session-transcript-sink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAqB,QAAQ,EAAY,MAAM,sBAAsB,CAAC;AAiB7E,MAAM,0BAA0B,GAAG,0BAA0B,CAAC;AAE9D;;;;;;;GAOG;AACH,MAAM,UAAU,iCAAiC,CAAC,OAA2C;IACzF,IAAI,KAAK,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7C,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE;QACnC,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,8CAA8C;QAC5E,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;QACvF,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACrD,OAAO,KAAK,CAAC;IACjB,CAAC,CAAC;AACN,CAAC;AAED,2FAA2F;AAC3F,KAAK,UAAU,gBAAgB,CAC3B,OAA2C,EAC3C,IAA+B,EAC/B,WAAqB,EACrB,QAA2B;IAE3B,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,eAAe,CAA6B,0BAA0B,EAAE,WAAW,CAAC,CAAC;QACnH,MAAM,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAC/C,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QACjD,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;QAC3B,MAAM,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAC/C,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC;QAChD,IAAI,IAAI,CAAC,aAAa,IAAI,OAAO,EAAE,CAAC;YAChC,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACzB,QAAQ,CAAC,oFAAoF,OAAO,CAAC,cAAc,KAAK,MAAM,CAAC,YAAY,EAAE,eAAe,IAAI,eAAe,EAAE,CAAC,CAAC;QACvL,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,QAAQ,CAAC,yEAAyE,OAAO,CAAC,cAAc,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3K,CAAC;AACL,CAAC"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @fileoverview A generic server half for channels that run entirely in the browser.
3
+ *
4
+ * `MJ: AI Agent Channels.ServerPluginClass` is `NOT NULL`: every channel in the registry names a server plugin, even a
5
+ * channel whose verbs, state and surface all live in the client. Without this class each such channel (an Open App's
6
+ * form channel, a game, a component host) would hand-write the same empty plugin. A client-only channel instead
7
+ * points its registry row at this one:
8
+ *
9
+ * ```json
10
+ * { "fields": { "Name": "YourChannel", "ServerPluginClass": "ClientOnlyChannelServer", "ClientPluginClass": "YourChannel", ... } }
11
+ * ```
12
+ *
13
+ * The plugin takes its channel name from the registry row it was resolved for (see {@link ClientOnlyChannelServer.BindChannelName}),
14
+ * so one registered class serves any number of channels and `RealtimeChannelServerHost` never reports a name mismatch.
15
+ *
16
+ * ## What it does
17
+ *
18
+ * - Completes the registry pairing, so the channel is discoverable, scoped and killable like every other.
19
+ * - Contributes **no server tools** (`GetServerToolDefinitions()` is `[]`): every verb executes in the browser.
20
+ * - Does **not interpret or rewrite** a state-of-record save (`OnChannelStateSave` returns `null`, which the host reads as
21
+ * "keep what the client sent").
22
+ *
23
+ * ## What it does not do
24
+ *
25
+ * - **It does not decide scope.** Whether the channel is in a session at all is resolved by the channel-scoping cascade
26
+ * (`channels.include` / `exclude` / the registry's `IsActive` kill switch) BEFORE the host creates any plugin, so there is
27
+ * nothing left for a plugin to validate.
28
+ * - **It does not stop a save.** The host treats a plugin's `null` (and any thrown error) as "persist the original", so a
29
+ * server plugin cannot refuse state. Whether anything is persisted is decided by the CLIENT: a channel with no state of
30
+ * record (`SerializeState()` returns `null`, so it never requests a save) persists nothing. A channel that does request
31
+ * saves, such as an `AngularComponentChannel`, has its state stored on the session's channel row as submitted; if that state
32
+ * must not be stored, validate or redact it in a server plugin of your own (return a replacement) or do not save it.
33
+ * - **It does not authorize anything.** If the channel's verbs call server operations, those operations are the security
34
+ * boundary (they run on the session's own principal); a client-only channel adds no door of its own.
35
+ *
36
+ * Use a dedicated server plugin instead when the channel needs server tools, a server-side state normalizer, or
37
+ * session-lifecycle work.
38
+ *
39
+ * @module @memberjunction/ai-agents
40
+ * @author MemberJunction.com
41
+ */
42
+ import { BaseRealtimeChannelServer, RealtimeToolDefinition } from '@memberjunction/ai';
43
+ /** The `ServerPluginClass` key a client-only channel's registry row uses. */
44
+ export declare const CLIENT_ONLY_CHANNEL_SERVER_KEY = "ClientOnlyChannelServer";
45
+ /**
46
+ * Generic server half for a channel that runs entirely in the browser. One instance per realtime session (created by
47
+ * `RealtimeChannelServerHost` from the channel registry; never construct directly).
48
+ *
49
+ * Subclass it only to pin a fixed {@link ChannelName} under a key of your own (as the built-in Interactive Component and
50
+ * Identity Verification channels do, so their existing registry keys keep resolving); an Open App should simply use the
51
+ * registered `ClientOnlyChannelServer` key.
52
+ */
53
+ export declare class ClientOnlyChannelServer extends BaseRealtimeChannelServer {
54
+ private boundChannelName;
55
+ /**
56
+ * The channel this instance serves: the registry row's `Name`, once the host has bound it; `''` before that. A subclass
57
+ * that pins a fixed name overrides it.
58
+ */
59
+ get ChannelName(): string;
60
+ /**
61
+ * Tells the plugin which registry row it was resolved for. Called by `RealtimeChannelServerHost` right after it creates
62
+ * the instance, so a single registered class can serve any client-only channel.
63
+ *
64
+ * @param channelName The registry row's `Name`.
65
+ */
66
+ BindChannelName(channelName: string): void;
67
+ /** No server-executed tools: every verb runs in the browser. */
68
+ GetServerToolDefinitions(): RealtimeToolDefinition[];
69
+ /**
70
+ * Does not interpret or rewrite a state save. `null` means "persist what the client submitted" (the host cannot refuse a
71
+ * save through a plugin; see the file comment).
72
+ *
73
+ * @returns `null`.
74
+ */
75
+ OnChannelStateSave(): Promise<string | null>;
76
+ }
77
+ /**
78
+ * Tree-shaking prevention for {@link ClientOnlyChannelServer}'s `@RegisterClass` registration. Called from a static code
79
+ * path in the server host (and, for the Interactive Component and Identity Verification plugins, from their own load
80
+ * functions) so the registration always executes.
81
+ */
82
+ export declare function LoadClientOnlyChannelServer(): void;
83
+ //# sourceMappingURL=client-only-channel-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-only-channel-server.d.ts","sourceRoot":"","sources":["../../src/realtime/client-only-channel-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGvF,6EAA6E;AAC7E,eAAO,MAAM,8BAA8B,4BAA4B,CAAC;AAExE;;;;;;;GAOG;AACH,qBACa,uBAAwB,SAAQ,yBAAyB;IAClE,OAAO,CAAC,gBAAgB,CAAuB;IAE/C;;;OAGG;IACH,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED;;;;;OAKG;IACI,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAIjD,gEAAgE;IAChD,wBAAwB,IAAI,sBAAsB,EAAE;IAIpE;;;;;OAKG;IACmB,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAGrE;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @fileoverview A generic server half for channels that run entirely in the browser.
3
+ *
4
+ * `MJ: AI Agent Channels.ServerPluginClass` is `NOT NULL`: every channel in the registry names a server plugin, even a
5
+ * channel whose verbs, state and surface all live in the client. Without this class each such channel (an Open App's
6
+ * form channel, a game, a component host) would hand-write the same empty plugin. A client-only channel instead
7
+ * points its registry row at this one:
8
+ *
9
+ * ```json
10
+ * { "fields": { "Name": "YourChannel", "ServerPluginClass": "ClientOnlyChannelServer", "ClientPluginClass": "YourChannel", ... } }
11
+ * ```
12
+ *
13
+ * The plugin takes its channel name from the registry row it was resolved for (see {@link ClientOnlyChannelServer.BindChannelName}),
14
+ * so one registered class serves any number of channels and `RealtimeChannelServerHost` never reports a name mismatch.
15
+ *
16
+ * ## What it does
17
+ *
18
+ * - Completes the registry pairing, so the channel is discoverable, scoped and killable like every other.
19
+ * - Contributes **no server tools** (`GetServerToolDefinitions()` is `[]`): every verb executes in the browser.
20
+ * - Does **not interpret or rewrite** a state-of-record save (`OnChannelStateSave` returns `null`, which the host reads as
21
+ * "keep what the client sent").
22
+ *
23
+ * ## What it does not do
24
+ *
25
+ * - **It does not decide scope.** Whether the channel is in a session at all is resolved by the channel-scoping cascade
26
+ * (`channels.include` / `exclude` / the registry's `IsActive` kill switch) BEFORE the host creates any plugin, so there is
27
+ * nothing left for a plugin to validate.
28
+ * - **It does not stop a save.** The host treats a plugin's `null` (and any thrown error) as "persist the original", so a
29
+ * server plugin cannot refuse state. Whether anything is persisted is decided by the CLIENT: a channel with no state of
30
+ * record (`SerializeState()` returns `null`, so it never requests a save) persists nothing. A channel that does request
31
+ * saves, such as an `AngularComponentChannel`, has its state stored on the session's channel row as submitted; if that state
32
+ * must not be stored, validate or redact it in a server plugin of your own (return a replacement) or do not save it.
33
+ * - **It does not authorize anything.** If the channel's verbs call server operations, those operations are the security
34
+ * boundary (they run on the session's own principal); a client-only channel adds no door of its own.
35
+ *
36
+ * Use a dedicated server plugin instead when the channel needs server tools, a server-side state normalizer, or
37
+ * session-lifecycle work.
38
+ *
39
+ * @module @memberjunction/ai-agents
40
+ * @author MemberJunction.com
41
+ */
42
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
43
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
44
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
45
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
46
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
47
+ };
48
+ import { BaseRealtimeChannelServer } from '@memberjunction/ai';
49
+ import { RegisterClass } from '@memberjunction/global';
50
+ /** The `ServerPluginClass` key a client-only channel's registry row uses. */
51
+ export const CLIENT_ONLY_CHANNEL_SERVER_KEY = 'ClientOnlyChannelServer';
52
+ /**
53
+ * Generic server half for a channel that runs entirely in the browser. One instance per realtime session (created by
54
+ * `RealtimeChannelServerHost` from the channel registry; never construct directly).
55
+ *
56
+ * Subclass it only to pin a fixed {@link ChannelName} under a key of your own (as the built-in Interactive Component and
57
+ * Identity Verification channels do, so their existing registry keys keep resolving); an Open App should simply use the
58
+ * registered `ClientOnlyChannelServer` key.
59
+ */
60
+ let ClientOnlyChannelServer = class ClientOnlyChannelServer extends BaseRealtimeChannelServer {
61
+ constructor() {
62
+ super(...arguments);
63
+ this.boundChannelName = null;
64
+ }
65
+ /**
66
+ * The channel this instance serves: the registry row's `Name`, once the host has bound it; `''` before that. A subclass
67
+ * that pins a fixed name overrides it.
68
+ */
69
+ get ChannelName() {
70
+ return this.boundChannelName ?? '';
71
+ }
72
+ /**
73
+ * Tells the plugin which registry row it was resolved for. Called by `RealtimeChannelServerHost` right after it creates
74
+ * the instance, so a single registered class can serve any client-only channel.
75
+ *
76
+ * @param channelName The registry row's `Name`.
77
+ */
78
+ BindChannelName(channelName) {
79
+ this.boundChannelName = channelName;
80
+ }
81
+ /** No server-executed tools: every verb runs in the browser. */
82
+ GetServerToolDefinitions() {
83
+ return [];
84
+ }
85
+ /**
86
+ * Does not interpret or rewrite a state save. `null` means "persist what the client submitted" (the host cannot refuse a
87
+ * save through a plugin; see the file comment).
88
+ *
89
+ * @returns `null`.
90
+ */
91
+ async OnChannelStateSave() {
92
+ return null;
93
+ }
94
+ };
95
+ ClientOnlyChannelServer = __decorate([
96
+ RegisterClass(BaseRealtimeChannelServer, CLIENT_ONLY_CHANNEL_SERVER_KEY)
97
+ ], ClientOnlyChannelServer);
98
+ export { ClientOnlyChannelServer };
99
+ /**
100
+ * Tree-shaking prevention for {@link ClientOnlyChannelServer}'s `@RegisterClass` registration. Called from a static code
101
+ * path in the server host (and, for the Interactive Component and Identity Verification plugins, from their own load
102
+ * functions) so the registration always executes.
103
+ */
104
+ export function LoadClientOnlyChannelServer() {
105
+ // no-op: the import + call create a static reference bundlers cannot eliminate
106
+ }
107
+ //# sourceMappingURL=client-only-channel-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-only-channel-server.js","sourceRoot":"","sources":["../../src/realtime/client-only-channel-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;;;;;;;AAEH,OAAO,EAAE,yBAAyB,EAA0B,MAAM,oBAAoB,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,8BAA8B,GAAG,yBAAyB,CAAC;AAExE;;;;;;;GAOG;AAEI,IAAM,uBAAuB,GAA7B,MAAM,uBAAwB,SAAQ,yBAAyB;IAA/D;;QACK,qBAAgB,GAAkB,IAAI,CAAC;IAkCnD,CAAC;IAhCG;;;OAGG;IACH,IAAW,WAAW;QAClB,OAAO,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAC;IACvC,CAAC;IAED;;;;;OAKG;IACI,eAAe,CAAC,WAAmB;QACtC,IAAI,CAAC,gBAAgB,GAAG,WAAW,CAAC;IACxC,CAAC;IAED,gEAAgE;IAChD,wBAAwB;QACpC,OAAO,EAAE,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACa,KAAK,CAAC,kBAAkB;QACpC,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ,CAAA;AAnCY,uBAAuB;IADnC,aAAa,CAAC,yBAAyB,EAAE,8BAA8B,CAAC;GAC5D,uBAAuB,CAmCnC;;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B;IACvC,+EAA+E;AACnF,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @fileoverview Server-side channel plugin for the **Identity Verification** channel — the generic,
3
+ * opt-in channel through which a realtime agent helps a person (often an anonymous widget guest) prove
4
+ * they control an email address without leaving the call.
5
+ *
6
+ * Paired with the browser's `IdentityVerificationChannel` client plugin through the seeded
7
+ * `MJ: AI Agent Channels` row (`Name: 'IdentityVerification'`,
8
+ * `ServerPluginClass: 'IdentityVerificationChannelServer'`, `ClientPluginClass: 'IdentityVerificationChannel'`).
9
+ *
10
+ * **Why the server half is intentionally thin, and validates nothing beyond scope.** The channel's verbs
11
+ * are executed in the browser, which then calls the verification operations
12
+ * (`RequestRealtimeSessionVerification`, `SubmitRealtimeSessionVerificationCode`) on the session's own
13
+ * principal. Those operations — not this plugin — are the security boundary: domain policy, rate limits,
14
+ * code hashing, expiry and deadline extension all live in the verification service, and the server never
15
+ * trusts anything the client says about verification state. A server tool here would only be a second,
16
+ * weaker door to the same room, and a state of record would put an email address (PII) onto the session's
17
+ * channel row for no benefit — the session's verification state is already stored, hashed where it must
18
+ * be, on the session itself. So the plugin completes the registry pairing (so the channel is discoverable
19
+ * and scoped like every other) and contributes no server tools and no persisted state.
20
+ *
21
+ * "Scope" is the only thing that applies server-side: whether the channel is in a session at all is decided
22
+ * by the channel-scoping cascade (`channels.config.IdentityVerification`, opt-in by default) and the
23
+ * registry's kill switch, both resolved before this plugin is ever created.
24
+ *
25
+ * @module @memberjunction/ai-agents
26
+ * @author MemberJunction.com
27
+ */
28
+ import { ClientOnlyChannelServer } from './client-only-channel-server.js';
29
+ /** The stable channel name, matching the seeded `MJ: AI Agent Channels` row. */
30
+ export declare const IDENTITY_VERIFICATION_CHANNEL_NAME = "IdentityVerification";
31
+ /**
32
+ * Server half of the Identity Verification channel. One instance per realtime session (created by
33
+ * `RealtimeChannelServerHost` from the channel registry; never construct directly).
34
+ *
35
+ * A {@link ClientOnlyChannelServer} that pins the channel's name under its own, already-seeded registry key
36
+ * (`IdentityVerificationChannelServer`), so the existing row keeps resolving. It contributes no server tools and does not
37
+ * rewrite saves. The channel's state is a name and an email in a form: the client plugin has no state of record (it never
38
+ * requests a save), so no email address reaches the channel row. A server plugin cannot refuse a save, so that guarantee
39
+ * rests on the client plugin continuing not to request one.
40
+ */
41
+ export declare class IdentityVerificationChannelServer extends ClientOnlyChannelServer {
42
+ /** Matches the seeded `MJ: AI Agent Channels` row's `Name`. */
43
+ get ChannelName(): string;
44
+ }
45
+ /**
46
+ * Tree-shaking prevention for {@link IdentityVerificationChannelServer}'s `@RegisterClass` registration.
47
+ * Called from a static code path in the server host so the registration always executes.
48
+ */
49
+ export declare function LoadIdentityVerificationChannelServer(): void;
50
+ //# sourceMappingURL=identity-verification-channel-server.d.ts.map