@athenaintel/react 0.55.0 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/README.md +84 -1
  2. package/dist/agent-runtime/src/answer-label.cjs +8 -2
  3. package/dist/agent-runtime/src/answer-label.cjs.map +1 -1
  4. package/dist/agent-runtime/src/answer-label.d.ts +10 -4
  5. package/dist/agent-runtime/src/answer-label.js +8 -2
  6. package/dist/agent-runtime/src/answer-label.js.map +1 -1
  7. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs +6 -3
  8. package/dist/agent-runtime/src/deep-agent-transport-recipe.cjs.map +1 -1
  9. package/dist/agent-runtime/src/deep-agent-transport-recipe.js +6 -3
  10. package/dist/agent-runtime/src/deep-agent-transport-recipe.js.map +1 -1
  11. package/dist/agent-runtime/src/edit-command.cjs +40 -19
  12. package/dist/agent-runtime/src/edit-command.cjs.map +1 -1
  13. package/dist/agent-runtime/src/edit-command.d.ts +2 -0
  14. package/dist/agent-runtime/src/edit-command.js +41 -20
  15. package/dist/agent-runtime/src/edit-command.js.map +1 -1
  16. package/dist/agent-runtime/src/generated/runconfig-contract.cjs +8 -0
  17. package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  18. package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +9 -0
  19. package/dist/agent-runtime/src/generated/runconfig-contract.js +8 -0
  20. package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  21. package/dist/agent-runtime/src/history-store.cjs +426 -0
  22. package/dist/agent-runtime/src/history-store.cjs.map +1 -0
  23. package/dist/agent-runtime/src/history-store.d.ts +282 -0
  24. package/dist/agent-runtime/src/history-store.js +426 -0
  25. package/dist/agent-runtime/src/history-store.js.map +1 -0
  26. package/dist/agent-runtime/src/inbound-channel.cjs +96 -0
  27. package/dist/agent-runtime/src/inbound-channel.cjs.map +1 -0
  28. package/dist/agent-runtime/src/inbound-channel.d.ts +75 -0
  29. package/dist/agent-runtime/src/inbound-channel.js +96 -0
  30. package/dist/agent-runtime/src/inbound-channel.js.map +1 -0
  31. package/dist/agent-runtime/src/index.d.ts +6 -5
  32. package/dist/agent-runtime/src/interrupts.cjs +45 -3
  33. package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
  34. package/dist/agent-runtime/src/interrupts.d.ts +51 -4
  35. package/dist/agent-runtime/src/interrupts.js +46 -4
  36. package/dist/agent-runtime/src/interrupts.js.map +1 -1
  37. package/dist/agent-runtime/src/message-window.cjs +43 -5
  38. package/dist/agent-runtime/src/message-window.cjs.map +1 -1
  39. package/dist/agent-runtime/src/message-window.d.ts +26 -2
  40. package/dist/agent-runtime/src/message-window.js +44 -6
  41. package/dist/agent-runtime/src/message-window.js.map +1 -1
  42. package/dist/agent-runtime/src/offline-status.cjs.map +1 -1
  43. package/dist/agent-runtime/src/offline-status.d.ts +110 -4
  44. package/dist/agent-runtime/src/offline-status.js.map +1 -1
  45. package/dist/agent-runtime/src/runtime.d.ts +1 -0
  46. package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +8 -8
  47. package/dist/agent-runtime/src/tool-metadata.cjs +16 -0
  48. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  49. package/dist/agent-runtime/src/tool-metadata.js +16 -0
  50. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  51. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +8 -16
  52. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  53. package/dist/agent-runtime/src/use-deep-agent-thread.d.ts +1 -9
  54. package/dist/agent-runtime/src/use-deep-agent-thread.js +9 -17
  55. package/dist/agent-runtime/src/use-deep-agent-thread.js.map +1 -1
  56. package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +86 -79
  57. package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
  58. package/dist/agent-runtime/src/use-deep-agent-window-sync.d.ts +2 -27
  59. package/dist/agent-runtime/src/use-deep-agent-window-sync.js +89 -82
  60. package/dist/agent-runtime/src/use-deep-agent-window-sync.js.map +1 -1
  61. package/dist/auth/AthenaSSOProvider.cjs +54 -12
  62. package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
  63. package/dist/auth/AthenaSSOProvider.d.ts +23 -2
  64. package/dist/auth/AthenaSSOProvider.js +54 -12
  65. package/dist/auth/AthenaSSOProvider.js.map +1 -1
  66. package/dist/auth/index.cjs +2 -0
  67. package/dist/auth/index.cjs.map +1 -1
  68. package/dist/auth/index.d.ts +1 -0
  69. package/dist/auth/index.js +2 -0
  70. package/dist/auth/index.js.map +1 -1
  71. package/dist/auth/sign-back-in.cjs +141 -0
  72. package/dist/auth/sign-back-in.cjs.map +1 -0
  73. package/dist/auth/sign-back-in.d.ts +117 -0
  74. package/dist/auth/sign-back-in.js +141 -0
  75. package/dist/auth/sign-back-in.js.map +1 -0
  76. package/dist/chat/AthenaChat.cjs +7 -2
  77. package/dist/chat/AthenaChat.cjs.map +1 -1
  78. package/dist/chat/AthenaChat.js +7 -2
  79. package/dist/chat/AthenaChat.js.map +1 -1
  80. package/dist/chat/StatewireApprovalCard.cjs +6 -2
  81. package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
  82. package/dist/chat/StatewireApprovalCard.d.ts +8 -1
  83. package/dist/chat/StatewireApprovalCard.js +7 -3
  84. package/dist/chat/StatewireApprovalCard.js.map +1 -1
  85. package/dist/chat/super-grouping/CollapsibleGroup.cjs +1 -1
  86. package/dist/chat/super-grouping/CollapsibleGroup.cjs.map +1 -1
  87. package/dist/chat/super-grouping/CollapsibleGroup.d.ts +6 -5
  88. package/dist/chat/super-grouping/CollapsibleGroup.js +1 -1
  89. package/dist/chat/super-grouping/CollapsibleGroup.js.map +1 -1
  90. package/dist/chat/super-grouping/earlier-steps-button.cjs +5 -6
  91. package/dist/chat/super-grouping/earlier-steps-button.cjs.map +1 -1
  92. package/dist/chat/super-grouping/earlier-steps-button.d.ts +6 -6
  93. package/dist/chat/super-grouping/earlier-steps-button.js +5 -6
  94. package/dist/chat/super-grouping/earlier-steps-button.js.map +1 -1
  95. package/dist/chat/super-grouping/toolkit-map.cjs +1 -0
  96. package/dist/chat/super-grouping/toolkit-map.cjs.map +1 -1
  97. package/dist/chat/super-grouping/toolkit-map.js +1 -0
  98. package/dist/chat/super-grouping/toolkit-map.js.map +1 -1
  99. package/dist/chat/super-grouping/use-turn-steps.cjs +3 -3
  100. package/dist/chat/super-grouping/use-turn-steps.js +1 -1
  101. package/dist/chat-ui/index.cjs +4 -0
  102. package/dist/chat-ui/index.cjs.map +1 -1
  103. package/dist/chat-ui/index.d.ts +1 -0
  104. package/dist/chat-ui/index.js +5 -1
  105. package/dist/chat-ui/index.js.map +1 -1
  106. package/dist/chat-ui/messages/inbound-channel-message.cjs +219 -0
  107. package/dist/chat-ui/messages/inbound-channel-message.cjs.map +1 -0
  108. package/dist/chat-ui/messages/inbound-channel-message.d.ts +60 -0
  109. package/dist/chat-ui/messages/inbound-channel-message.js +219 -0
  110. package/dist/chat-ui/messages/inbound-channel-message.js.map +1 -0
  111. package/dist/chat-ui/messages/inbound-channel-reader.cjs +184 -0
  112. package/dist/chat-ui/messages/inbound-channel-reader.cjs.map +1 -0
  113. package/dist/chat-ui/messages/inbound-channel-reader.d.ts +65 -0
  114. package/dist/chat-ui/messages/inbound-channel-reader.js +184 -0
  115. package/dist/chat-ui/messages/inbound-channel-reader.js.map +1 -0
  116. package/dist/chat-ui/messages/message-components.cjs +18 -14
  117. package/dist/chat-ui/messages/message-components.cjs.map +1 -1
  118. package/dist/chat-ui/messages/message-components.d.ts +7 -0
  119. package/dist/chat-ui/messages/message-components.js +19 -15
  120. package/dist/chat-ui/messages/message-components.js.map +1 -1
  121. package/dist/chat-ui/thread/statewire-history-edge.cjs +0 -4
  122. package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
  123. package/dist/chat-ui/thread/statewire-history-edge.d.ts +5 -7
  124. package/dist/chat-ui/thread/statewire-history-edge.js +1 -5
  125. package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
  126. package/dist/composer/sign-back-in-draft.cjs +62 -0
  127. package/dist/composer/sign-back-in-draft.cjs.map +1 -0
  128. package/dist/composer/sign-back-in-draft.d.ts +34 -0
  129. package/dist/composer/sign-back-in-draft.js +62 -0
  130. package/dist/composer/sign-back-in-draft.js.map +1 -0
  131. package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
  132. package/dist/diagnostics/athena-diagnostics.d.ts +6 -1
  133. package/dist/diagnostics/athena-diagnostics.js.map +1 -1
  134. package/dist/index.cjs +8 -0
  135. package/dist/index.cjs.map +1 -1
  136. package/dist/index.d.ts +2 -0
  137. package/dist/index.js +8 -0
  138. package/dist/index.js.map +1 -1
  139. package/dist/provider/AthenaProvider.cjs +60 -14
  140. package/dist/provider/AthenaProvider.cjs.map +1 -1
  141. package/dist/provider/AthenaProvider.js +60 -14
  142. package/dist/provider/AthenaProvider.js.map +1 -1
  143. package/dist/provider/statewire-window-context.cjs.map +1 -1
  144. package/dist/provider/statewire-window-context.d.ts +8 -8
  145. package/dist/provider/statewire-window-context.js.map +1 -1
  146. package/dist/react/package.json.cjs +1 -1
  147. package/dist/react/package.json.js +1 -1
  148. package/dist/runtime/auth.cjs +11 -0
  149. package/dist/runtime/auth.cjs.map +1 -1
  150. package/dist/runtime/auth.d.ts +18 -1
  151. package/dist/runtime/auth.js +11 -0
  152. package/dist/runtime/auth.js.map +1 -1
  153. package/dist/runtime/useAthenaStatewireRuntime.cjs +0 -2
  154. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  155. package/dist/runtime/useAthenaStatewireRuntime.d.ts +5 -5
  156. package/dist/runtime/useAthenaStatewireRuntime.js +0 -2
  157. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  158. package/dist/styles.css +1 -1
  159. package/package.json +1 -1
  160. package/dist/agent-runtime/src/history-pages.cjs +0 -279
  161. package/dist/agent-runtime/src/history-pages.cjs.map +0 -1
  162. package/dist/agent-runtime/src/history-pages.d.ts +0 -252
  163. package/dist/agent-runtime/src/history-pages.js +0 -279
  164. package/dist/agent-runtime/src/history-pages.js.map +0 -1
@@ -0,0 +1,426 @@
1
+ import { DEEP_AGENT_MAIN_NS, DEEP_AGENT_HISTORY_PAGE_COMMAND, DEEP_AGENT_MAX_HISTORY_PAGE_TURNS, DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION, DEEP_AGENT_MAX_HISTORY_PAGE_STEPS, DEEP_AGENT_MESSAGE_HISTORY_HEADER, DEEP_AGENT_MESSAGE_HISTORY_PAGED } from "./generated/runconfig-contract.js";
2
+ import { QUIET_TOOL_NAMES } from "./tool-names.js";
3
+ const DEEP_AGENT_HISTORY_STORE_LIMIT = 8;
4
+ const DEEP_AGENT_TURN_STEPS_PAGE = 100;
5
+ const DEEP_AGENT_TURN_STEPS_KEY = "athena_turn_steps";
6
+ function toolCalls(messages) {
7
+ let tools = 0;
8
+ let delegations = 0;
9
+ for (const message of messages) {
10
+ if (message.type !== "ai") continue;
11
+ for (const call of message.tool_calls ?? []) {
12
+ if (QUIET_TOOL_NAMES.has(call.name)) continue;
13
+ tools += 1;
14
+ if (call.name === "task") delegations += 1;
15
+ }
16
+ }
17
+ return { tools, delegations };
18
+ }
19
+ const markedCopies = /* @__PURE__ */ new WeakMap();
20
+ function withMarker(message, marker) {
21
+ const key = `${marker.thread}\0${marker.turn}\0${marker.hiddenSteps}\0${marker.hiddenTools}\0${marker.hiddenDelegations}\0${marker.before ?? ""}`;
22
+ const cached = markedCopies.get(message);
23
+ if ((cached == null ? void 0 : cached.key) === key) return cached.message;
24
+ const kwargs = message.additional_kwargs;
25
+ const marked = {
26
+ ...message,
27
+ additional_kwargs: { ...kwargs ?? {}, [DEEP_AGENT_TURN_STEPS_KEY]: marker }
28
+ };
29
+ markedCopies.set(message, { key, message: marked });
30
+ return marked;
31
+ }
32
+ function createDeepAgentHistoryStore() {
33
+ const parents = /* @__PURE__ */ new Map();
34
+ const summaries = /* @__PURE__ */ new Map();
35
+ const turnStarts = /* @__PURE__ */ new Map();
36
+ const messages = /* @__PURE__ */ new Map();
37
+ const loadingSteps = /* @__PURE__ */ new Set();
38
+ const listeners = /* @__PURE__ */ new Set();
39
+ let unserved = false;
40
+ let unservedBy;
41
+ let version = 0;
42
+ const notify = () => {
43
+ version += 1;
44
+ for (const listener of [...listeners]) listener();
45
+ };
46
+ const marker = (threadId, turn, state) => {
47
+ var _a;
48
+ const loaded = toolCalls(state.loaded);
49
+ return {
50
+ turn,
51
+ thread: threadId,
52
+ hiddenSteps: state.more ? Math.max(0, state.steps.count - state.loaded.length) : 0,
53
+ hiddenTools: Math.max(0, state.steps.tools - loaded.tools),
54
+ hiddenDelegations: Math.max(0, state.steps.delegations - loaded.delegations),
55
+ before: (_a = state.loaded[0]) == null ? void 0 : _a.id
56
+ };
57
+ };
58
+ const store = {
59
+ get unserved() {
60
+ return unserved;
61
+ },
62
+ get unservedBy() {
63
+ return unservedBy;
64
+ },
65
+ get version() {
66
+ return version;
67
+ },
68
+ markUnserved(connection) {
69
+ unservedBy = connection;
70
+ if (unserved) return;
71
+ unserved = true;
72
+ notify();
73
+ },
74
+ markServed() {
75
+ unservedBy = void 0;
76
+ if (!unserved) return;
77
+ unserved = false;
78
+ notify();
79
+ },
80
+ recordChain(ids, chainMessages, startsTranscript) {
81
+ for (let index = 0; index < ids.length; index += 1) {
82
+ const id = ids[index];
83
+ if (index > 0) parents.set(id, ids[index - 1]);
84
+ else if (startsTranscript) parents.set(id, null);
85
+ const message = chainMessages.get(id);
86
+ if (message !== void 0) messages.set(id, message);
87
+ }
88
+ },
89
+ addPage({ before, messages: page, moreBefore, summarized }) {
90
+ let changed = false;
91
+ const setParent = (id, parent) => {
92
+ if (parents.get(id) === parent) return;
93
+ parents.set(id, parent);
94
+ changed = true;
95
+ };
96
+ const ids = [];
97
+ for (const message of page) {
98
+ if (typeof message.id !== "string" || !message.id) continue;
99
+ ids.push(message.id);
100
+ if (messages.get(message.id) !== message) {
101
+ messages.set(message.id, message);
102
+ changed = true;
103
+ }
104
+ }
105
+ for (const [index, id] of ids.entries()) {
106
+ if (index > 0) setParent(id, ids[index - 1]);
107
+ else if (!moreBefore) setParent(id, null);
108
+ else if (parents.get(id) === null) {
109
+ parents.delete(id);
110
+ changed = true;
111
+ }
112
+ }
113
+ const last = ids.at(-1);
114
+ if (last !== void 0) setParent(before, last);
115
+ else if (!moreBefore) setParent(before, null);
116
+ for (const [turn, summary] of summarized ?? []) {
117
+ const held = summaries.get(turn);
118
+ if (held === void 0) {
119
+ summaries.set(turn, {
120
+ ...summary,
121
+ shownAfter: summary.resume,
122
+ loaded: [],
123
+ more: summary.steps.count > 0
124
+ });
125
+ turnStarts.set(turn, turn);
126
+ turnStarts.set(summary.resume, turn);
127
+ changed = true;
128
+ continue;
129
+ }
130
+ const oldest = held.loaded[0];
131
+ const newest = held.loaded.at(-1);
132
+ if (oldest !== void 0 && newest !== void 0) {
133
+ setParent(oldest.id, parents.get(held.shownAfter) ?? null);
134
+ setParent(held.shownAfter, newest.id);
135
+ }
136
+ }
137
+ if (unserved) {
138
+ unserved = false;
139
+ unservedBy = void 0;
140
+ changed = true;
141
+ }
142
+ if (changed) notify();
143
+ return changed;
144
+ },
145
+ addSteps({ turn, messages: steps, moreBefore }) {
146
+ const held = summaries.get(turn);
147
+ if (held === void 0) return false;
148
+ const loadedIds = new Set(held.loaded.map((message) => message.id));
149
+ const fresh = steps.filter(
150
+ (message) => typeof message.id === "string" && message.id && !loadedIds.has(message.id)
151
+ );
152
+ const more = moreBefore && fresh.length > 0;
153
+ if (fresh.length === 0) {
154
+ if (held.more === more) return false;
155
+ held.more = more;
156
+ notify();
157
+ return true;
158
+ }
159
+ const above = parents.get(held.resume);
160
+ const freshIds = fresh.map((message) => message.id);
161
+ for (const [index, id] of freshIds.entries()) {
162
+ messages.set(id, fresh[index]);
163
+ if (index > 0) parents.set(id, freshIds[index - 1]);
164
+ else if (above !== void 0) parents.set(id, above);
165
+ }
166
+ parents.set(held.resume, freshIds.at(-1));
167
+ turnStarts.delete(held.resume);
168
+ held.resume = freshIds[0];
169
+ turnStarts.set(held.resume, turn);
170
+ held.loaded = [...fresh, ...held.loaded];
171
+ held.more = more;
172
+ notify();
173
+ return true;
174
+ },
175
+ olderThan(id) {
176
+ const ids = [];
177
+ const older = [];
178
+ const seen = /* @__PURE__ */ new Set([id]);
179
+ let parent = parents.get(id);
180
+ while (typeof parent === "string" && !seen.has(parent)) {
181
+ const message = messages.get(parent);
182
+ if (message === void 0) break;
183
+ seen.add(parent);
184
+ ids.push(parent);
185
+ older.push(message);
186
+ parent = parents.get(parent);
187
+ }
188
+ ids.reverse();
189
+ older.reverse();
190
+ return { ids, messages: older, hasOlder: parent !== null };
191
+ },
192
+ parentOf(id) {
193
+ return parents.get(id);
194
+ },
195
+ turnSteps(turnId) {
196
+ var _a;
197
+ return (_a = summaries.get(turnId)) == null ? void 0 : _a.steps;
198
+ },
199
+ markTurns(threadId, transcript) {
200
+ if (summaries.size === 0) return transcript;
201
+ let marked = null;
202
+ let pending = null;
203
+ const started = /* @__PURE__ */ new Set();
204
+ for (const [index, message] of transcript.entries()) {
205
+ const id = typeof message.id === "string" ? message.id : void 0;
206
+ const turn = id === void 0 ? void 0 : turnStarts.get(id);
207
+ if (turn !== void 0 && !started.has(turn)) {
208
+ started.add(turn);
209
+ const state = summaries.get(turn);
210
+ pending = marker(threadId, turn, state);
211
+ } else if (message.type === "human") {
212
+ pending = null;
213
+ }
214
+ if (pending === null || message.type !== "ai") continue;
215
+ marked ?? (marked = [...transcript]);
216
+ marked[index] = withMarker(message, pending);
217
+ pending = null;
218
+ }
219
+ return marked ?? transcript;
220
+ },
221
+ isLoadingSteps(turn) {
222
+ return loadingSteps.has(turn);
223
+ },
224
+ async loadSteps({ send, turn, steps = DEEP_AGENT_TURN_STEPS_PAGE }) {
225
+ const held = summaries.get(turn);
226
+ if (held === void 0 || !held.more || loadingSteps.has(turn)) return;
227
+ loadingSteps.add(turn);
228
+ try {
229
+ const answer = readTurnStepsResult(await send(buildTurnStepsCommand({ turn, before: held.resume, steps })));
230
+ if (answer === null || answer.turn !== turn) {
231
+ throw new Error("history/page answered steps in a shape this client cannot read");
232
+ }
233
+ store.addSteps(answer);
234
+ } finally {
235
+ loadingSteps.delete(turn);
236
+ }
237
+ },
238
+ subscribe(listener) {
239
+ listeners.add(listener);
240
+ return () => {
241
+ listeners.delete(listener);
242
+ };
243
+ }
244
+ };
245
+ return store;
246
+ }
247
+ const HISTORY_STORES = Symbol.for("@athenaintel/agent-runtime/history-stores");
248
+ function registry() {
249
+ const host = globalThis;
250
+ return host[HISTORY_STORES] ?? (host[HISTORY_STORES] = { stores: /* @__PURE__ */ new Map(), listeners: /* @__PURE__ */ new Set(), version: 0 });
251
+ }
252
+ const notifyRegistry = () => {
253
+ const shared = registry();
254
+ shared.version += 1;
255
+ for (const listener of [...shared.listeners]) listener();
256
+ };
257
+ function deepAgentHistoryStore(threadId) {
258
+ const { stores } = registry();
259
+ let store = stores.get(threadId);
260
+ if (store !== void 0) {
261
+ stores.delete(threadId);
262
+ stores.set(threadId, store);
263
+ return store;
264
+ }
265
+ store = createDeepAgentHistoryStore();
266
+ store.subscribe(notifyRegistry);
267
+ stores.set(threadId, store);
268
+ while (stores.size > DEEP_AGENT_HISTORY_STORE_LIMIT) {
269
+ const oldest = stores.keys().next().value;
270
+ stores.delete(oldest);
271
+ }
272
+ return store;
273
+ }
274
+ function peekDeepAgentHistoryStore(threadId) {
275
+ return registry().stores.get(threadId);
276
+ }
277
+ function subscribeDeepAgentHistory(listener) {
278
+ const { listeners } = registry();
279
+ listeners.add(listener);
280
+ return () => {
281
+ listeners.delete(listener);
282
+ };
283
+ }
284
+ function deepAgentHistoryVersion() {
285
+ return registry().version;
286
+ }
287
+ function clearDeepAgentHistoryStores() {
288
+ const { stores } = registry();
289
+ if (stores.size === 0) return;
290
+ stores.clear();
291
+ notifyRegistry();
292
+ }
293
+ function loadDeepAgentTurnSteps({
294
+ send,
295
+ marker,
296
+ steps
297
+ }) {
298
+ if (marker.hiddenSteps === 0) return Promise.resolve();
299
+ const store = peekDeepAgentHistoryStore(marker.thread);
300
+ if (store === void 0) return Promise.resolve();
301
+ return store.loadSteps({ send, turn: marker.turn, ...steps !== void 0 && { steps } });
302
+ }
303
+ function hostServesHistoryPage(version) {
304
+ return typeof version === "number" && version >= DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION;
305
+ }
306
+ function isHistoryPageUnserved(error) {
307
+ const failure = error == null ? void 0 : error.failure;
308
+ return (failure == null ? void 0 : failure.fate) === "rejected" && failure.code === "unknown-command";
309
+ }
310
+ function withDeclaredPagedHistory(headers) {
311
+ if (DEEP_AGENT_MESSAGE_HISTORY_HEADER in headers) return headers;
312
+ return { ...headers, [DEEP_AGENT_MESSAGE_HISTORY_HEADER]: DEEP_AGENT_MESSAGE_HISTORY_PAGED };
313
+ }
314
+ const DEEP_AGENT_HISTORY_PAGE_TURNS = 10;
315
+ function buildHistoryPageCommand({
316
+ before,
317
+ turns = DEEP_AGENT_HISTORY_PAGE_TURNS
318
+ }) {
319
+ return {
320
+ type: DEEP_AGENT_HISTORY_PAGE_COMMAND,
321
+ before,
322
+ turns: Math.max(1, Math.min(DEEP_AGENT_MAX_HISTORY_PAGE_TURNS, Math.trunc(turns)))
323
+ };
324
+ }
325
+ function buildTurnStepsCommand({
326
+ turn,
327
+ before,
328
+ steps = DEEP_AGENT_TURN_STEPS_PAGE
329
+ }) {
330
+ return {
331
+ type: DEEP_AGENT_HISTORY_PAGE_COMMAND,
332
+ turn,
333
+ ...before !== void 0 && { before },
334
+ steps: Math.max(1, Math.min(DEEP_AGENT_MAX_HISTORY_PAGE_STEPS, Math.trunc(steps)))
335
+ };
336
+ }
337
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
338
+ const isCount = (value) => typeof value === "number" && Number.isInteger(value) && value >= 0;
339
+ const isId = (value) => typeof value === "string" && value.length > 0;
340
+ const readTurnSteps = (value) => {
341
+ if (value === null) return null;
342
+ if (!isRecord(value)) return void 0;
343
+ const { count, tools, delegations, first, last } = value;
344
+ if (!isCount(count) || !isCount(tools) || !isCount(delegations)) return void 0;
345
+ const id = (entry) => isId(entry) ? entry : null;
346
+ return { count, tools, delegations, first: id(first), last: id(last) };
347
+ };
348
+ function readMessages(value) {
349
+ if (!Array.isArray(value)) return null;
350
+ for (const message of value) {
351
+ if (!isRecord(message) || !isId(message.id)) return null;
352
+ }
353
+ return value;
354
+ }
355
+ function readHistoryPageResult(payload, before) {
356
+ var _a, _b, _c, _d;
357
+ if (!isRecord(payload) || !Array.isArray(payload.turns) || !isRecord(payload.more)) return null;
358
+ if (typeof payload.more.before !== "boolean") return null;
359
+ const page = [];
360
+ const turns = [];
361
+ for (const turn of payload.turns) {
362
+ if (!isRecord(turn) || !isId(turn.id)) return null;
363
+ const turnMessages = readMessages(turn.messages);
364
+ if (turnMessages === null) return null;
365
+ const steps = readTurnSteps(turn.steps);
366
+ if (steps === void 0 && turn.steps !== void 0) return null;
367
+ turns.push({ id: turn.id, messages: turnMessages, steps: steps ?? null });
368
+ page.push(...turnMessages);
369
+ }
370
+ const summarized = /* @__PURE__ */ new Map();
371
+ for (const [index, turn] of turns.entries()) {
372
+ if (turn.steps === null) continue;
373
+ const shown = ((_a = turn.messages[0]) == null ? void 0 : _a.id) === turn.id ? turn.messages.slice(1) : turn.messages;
374
+ const resume = ((_b = shown[0]) == null ? void 0 : _b.id) ?? ((_d = (_c = turns[index + 1]) == null ? void 0 : _c.messages[0]) == null ? void 0 : _d.id) ?? before;
375
+ summarized.set(turn.id, { steps: turn.steps, resume });
376
+ }
377
+ return { before, messages: page, moreBefore: payload.more.before, summarized };
378
+ }
379
+ function readTurnStepsResult(payload) {
380
+ if (!isRecord(payload) || !isId(payload.turn) || !isRecord(payload.more)) return null;
381
+ if (typeof payload.more.before !== "boolean") return null;
382
+ const steps = readMessages(payload.messages);
383
+ if (steps === null) return null;
384
+ return { turn: payload.turn, messages: steps, moreBefore: payload.more.before };
385
+ }
386
+ function readTurnStepsMarker(message) {
387
+ if (!isRecord(message) || !isRecord(message.additional_kwargs)) return void 0;
388
+ const marker = message.additional_kwargs[DEEP_AGENT_TURN_STEPS_KEY];
389
+ if (!isRecord(marker) || !isId(marker.turn) || !isId(marker.thread)) return void 0;
390
+ const { hiddenSteps, hiddenTools, hiddenDelegations, before } = marker;
391
+ if (!isCount(hiddenSteps) || !isCount(hiddenTools) || !isCount(hiddenDelegations)) return void 0;
392
+ return {
393
+ turn: marker.turn,
394
+ thread: marker.thread,
395
+ hiddenSteps,
396
+ hiddenTools,
397
+ hiddenDelegations,
398
+ before: isId(before) ? before : void 0
399
+ };
400
+ }
401
+ function historyPageAsInterestRequest(command) {
402
+ return { ns: DEEP_AGENT_MAIN_NS, before: command.turns, at: command.before };
403
+ }
404
+ export {
405
+ DEEP_AGENT_HISTORY_PAGE_TURNS,
406
+ DEEP_AGENT_HISTORY_STORE_LIMIT,
407
+ DEEP_AGENT_TURN_STEPS_KEY,
408
+ DEEP_AGENT_TURN_STEPS_PAGE,
409
+ buildHistoryPageCommand,
410
+ buildTurnStepsCommand,
411
+ clearDeepAgentHistoryStores,
412
+ createDeepAgentHistoryStore,
413
+ deepAgentHistoryStore,
414
+ deepAgentHistoryVersion,
415
+ historyPageAsInterestRequest,
416
+ hostServesHistoryPage,
417
+ isHistoryPageUnserved,
418
+ loadDeepAgentTurnSteps,
419
+ peekDeepAgentHistoryStore,
420
+ readHistoryPageResult,
421
+ readTurnStepsMarker,
422
+ readTurnStepsResult,
423
+ subscribeDeepAgentHistory,
424
+ withDeclaredPagedHistory
425
+ };
426
+ //# sourceMappingURL=history-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-store.js","sources":["../../../../agent-runtime/src/history-store.ts"],"sourcesContent":["import type { LangChainMessage } from '@assistant-ui/react-langgraph';\nimport {\n DEEP_AGENT_HISTORY_PAGE_COMMAND,\n DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION,\n DEEP_AGENT_MAIN_NS,\n DEEP_AGENT_MAX_HISTORY_PAGE_STEPS,\n DEEP_AGENT_MAX_HISTORY_PAGE_TURNS,\n DEEP_AGENT_MESSAGE_HISTORY_HEADER,\n DEEP_AGENT_MESSAGE_HISTORY_PAGED,\n} from './generated/runconfig-contract';\nimport { QUIET_TOOL_NAMES } from './tool-names';\n\n/**\n * Older history on the client — the client half of agora's `history/page`.\n *\n * On a host whose `protocol` lane advertises\n * `DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION`, an attach states only its head\n * (and its lane follows) on `athena/interest`, and says on its attach headers\n * that it keeps older history itself ({@link withDeclaredPagedHistory}).\n * Older messages come back from the one-shot `history/page` command\n * (`{before, turns}` answers whole turns ending before `before`, oldest\n * first; a long turn rides as its prompt and answer, its steps counted) and\n * live here, never in the attach's view, so the interest document stays the\n * same small size however deep the viewer scrolls, and scrolling back moves\n * the page anchor instead of growing a list.\n *\n * The store keeps each message's parent as the reader sees the transcript,\n * and which message starts it. Every read of the interest window records the\n * parents its live chain shows, so a message that slides out of the head (the\n * host holds the head down to its floor for at most\n * `DEEP_AGENT_MAX_HELD_HEAD` messages) stays reachable here, and a re-attach\n * on any pod finds what was loaded. A page records the parents it shows (a\n * summarized turn's answer follows its prompt). A host parent never changes:\n * an edit or rewind mints new ids, a branch switch keeps each id's parent.\n * {@link readDeepAgentMessageWindow} joins the store under the live chain by\n * walking parents back from its first message, so only ancestors of the live\n * view are ever shown: a rewound tail is never reached.\n *\n * A summarized turn's left-out steps come back on request (`history/page`\n * with its `turn`, newest first, {@link DeepAgentHistoryStore.loadSteps}) and\n * are spliced in where the page left them out: between the turn's prompt and\n * the first message shown after it. The join marks each summarized turn on\n * its first reply message ({@link DEEP_AGENT_TURN_STEPS_KEY}), so a renderer\n * reads its exact counts (\"Used 313 tools\") and can offer the steps still\n * left out.\n *\n * One store per conversation, shared by every reader in the JS context (the\n * converter, the edit path, the history edge), so they agree on what is\n * loaded. The registry keeps the most recently read\n * {@link DEEP_AGENT_HISTORY_STORE_LIMIT} conversations.\n */\n\n/** Conversations whose stores the registry keeps (least recently read evicted). */\nexport const DEEP_AGENT_HISTORY_STORE_LIMIT = 8;\n\n/** Steps of one summarized turn one `history/page` asks for. */\nexport const DEEP_AGENT_TURN_STEPS_PAGE = 100;\n\n/** `additional_kwargs` key the join marks a summarized turn's first reply message with. */\nexport const DEEP_AGENT_TURN_STEPS_KEY = 'athena_turn_steps';\n\n/**\n * What a summarized turn's page left out (`steps` on a `history/page` turn):\n * counted over the left-out messages only, so a reader adds what it holds.\n */\nexport interface DeepAgentHistoryTurnSteps {\n /** Messages left out. */\n count: number;\n /** Tool calls among the messages left out. */\n tools: number;\n /** Of which `task` delegations. */\n delegations: number;\n /** The oldest and newest message left out. */\n first: string | null;\n last: string | null;\n}\n\n/** A turn a page summarized: what it left out, and where. */\nexport interface DeepAgentHistorySummarizedTurn {\n steps: DeepAgentHistoryTurnSteps;\n /**\n * The message the left-out steps end before: the first the page shows after\n * the turn's prompt, or — for a turn cut short by what the asker held — the\n * message the page was asked before.\n */\n resume: string;\n}\n\n/** One `history/page` answer, read off the wire. */\nexport interface DeepAgentHistoryPage {\n /** The message the page ends before. */\n before: string;\n /** Oldest first. */\n messages: LangChainMessage[];\n /** Whether the transcript holds messages older than the page. */\n moreBefore: boolean;\n /** The page's summarized turns, by their first message's id. */\n summarized?: ReadonlyMap<string, DeepAgentHistorySummarizedTurn>;\n}\n\n/** One `history/page` answer to `{turn, before, steps}`: a summarized turn's steps. */\nexport interface DeepAgentTurnStepsPage {\n turn: string;\n /** Steps, oldest first. */\n messages: LangChainMessage[];\n /** Older steps of the turn remain. */\n moreBefore: boolean;\n}\n\n/** What the store holds older than one message. */\nexport interface DeepAgentHistoryOlder {\n /** Ids, oldest first, ending right before the message asked about. */\n ids: string[];\n messages: LangChainMessage[];\n /** Whether anything older than `ids[0]` (or the message itself) may exist. */\n hasOlder: boolean;\n}\n\n/**\n * The marker the join puts on a summarized turn's first reply message: the\n * turn's steps not shown yet, so a renderer reads exact counts and knows\n * whether opening it has steps to fetch ({@link loadDeepAgentTurnSteps}).\n */\nexport interface DeepAgentTurnStepsMarker {\n /** The turn's first message: the id its steps are paged by. */\n turn: string;\n /** The conversation it belongs to (its history store). */\n thread: string;\n /** Steps not loaded yet. */\n hiddenSteps: number;\n /** Tool calls among them. */\n hiddenTools: number;\n /** Of which `task` delegations. */\n hiddenDelegations: number;\n /** The oldest step loaded; `undefined` while none is. */\n before: string | undefined;\n}\n\n/** How the store asks the host: the thread's `sendCommand` (its answer, the command's payload). */\nexport type DeepAgentHistorySend = (command: HistoryPageCommand | TurnStepsCommand) => unknown;\n\nexport interface DeepAgentHistoryStore {\n /**\n * Whether the host refused `history/page` although its `protocol` lane\n * advertises it (a host without the command): readers then read the live\n * view alone and page by interest, until {@link markServed}.\n */\n readonly unserved: boolean;\n /** The connection the refusal came on (`markUnserved`): a later one may land on a host that serves it. */\n readonly unservedBy: unknown;\n /** Bumped on every change readers can see (a page, steps, the unserved flag). */\n readonly version: number;\n markUnserved(connection?: unknown): void;\n markServed(): void;\n /**\n * Record what a live chain shows: each entry's parent is the one before it,\n * and with `startsTranscript` its first entry has none. Messages are kept by\n * id (the newest form seen). Silent: a live chain changes nothing its own\n * reader shows.\n */\n recordChain(\n ids: readonly string[],\n messages: ReadonlyMap<string, LangChainMessage>,\n startsTranscript: boolean\n ): void;\n /**\n * Take in one page; notifies. `false` for an empty page that told nothing\n * new. A page's messages are the transcript as the reader sees it: a\n * summarized turn's answer follows its prompt, its steps left out.\n */\n addPage(page: DeepAgentHistoryPage): boolean;\n /**\n * Take in a summarized turn's older steps, spliced in where its page left\n * them out; notifies. `false` for a turn the store does not hold.\n */\n addSteps(page: DeepAgentTurnStepsPage): boolean;\n /** What a summarized turn's page left out, by the turn's first message id. */\n turnSteps(turnId: string): DeepAgentHistoryTurnSteps | undefined;\n /** Everything the store holds older than `id`, walking parents back. */\n olderThan(id: string): DeepAgentHistoryOlder;\n /** The host parent of `id`: `null` at the transcript's start, `undefined` while unknown. */\n parentOf(id: string): string | null | undefined;\n /**\n * `messages` (a transcript as a reader shows it, oldest first) with each\n * summarized turn's marker on its first reply message\n * ({@link DEEP_AGENT_TURN_STEPS_KEY}); the same array when none applies.\n */\n markTurns(threadId: string, messages: LangChainMessage[]): LangChainMessage[];\n /** Whether a steps request for the turn is in flight — the loader's dedupe. */\n isLoadingSteps(turn: string): boolean;\n /**\n * Fetches a summarized turn's next older steps (`history/page` with its\n * `turn`) into the store. A turn already loading, unknown, or with no steps\n * left is a no-op. Rejects with the host's refusal, or when the answer is\n * not a page this client reads.\n */\n loadSteps(options: { send: DeepAgentHistorySend; turn: string; steps?: number }): Promise<void>;\n subscribe(listener: () => void): () => void;\n}\n\ninterface SummarizedTurnState extends DeepAgentHistorySummarizedTurn {\n /** The message the page showed right after the gap; `resume` moves down as steps load. */\n shownAfter: string;\n /** Steps loaded, oldest first. */\n loaded: LangChainMessage[];\n /** Older steps remain to load. */\n more: boolean;\n}\n\n/**\n * The tool calls among `messages` a converter shows. The host counts every\n * call of a turn; a quiet call (`QUIET_TOOL_NAMES`) never renders, so it stays\n * in the hidden count once loaded and the turn's total holds still as its\n * steps load.\n */\nfunction toolCalls(messages: readonly LangChainMessage[]): { tools: number; delegations: number } {\n let tools = 0;\n let delegations = 0;\n for (const message of messages) {\n if (message.type !== 'ai') continue;\n for (const call of message.tool_calls ?? []) {\n if (QUIET_TOOL_NAMES.has(call.name)) continue;\n tools += 1;\n if (call.name === 'task') delegations += 1;\n }\n }\n return { tools, delegations };\n}\n\n/** The marked copy of a message, reused while the message and its marker are the same. */\nconst markedCopies = new WeakMap<object, { key: string; message: LangChainMessage }>();\n\nfunction withMarker(message: LangChainMessage, marker: DeepAgentTurnStepsMarker): LangChainMessage {\n const key = `${marker.thread}\\u0000${marker.turn}\\u0000${marker.hiddenSteps}\\u0000${marker.hiddenTools}\\u0000${marker.hiddenDelegations}\\u0000${marker.before ?? ''}`;\n const cached = markedCopies.get(message);\n if (cached?.key === key) return cached.message;\n // Every wire message carries `additional_kwargs` in practice; the upstream\n // type leaves it off tool messages.\n const kwargs = (message as { additional_kwargs?: Record<string, unknown> }).additional_kwargs;\n const marked = {\n ...message,\n additional_kwargs: { ...(kwargs ?? {}), [DEEP_AGENT_TURN_STEPS_KEY]: marker },\n } as LangChainMessage;\n markedCopies.set(message, { key, message: marked });\n return marked;\n}\n\nexport function createDeepAgentHistoryStore(): DeepAgentHistoryStore {\n const parents = new Map<string, string | null>();\n const summaries = new Map<string, SummarizedTurnState>();\n /** A summarized turn by the messages its marker may start at: its prompt and where its steps resume. */\n const turnStarts = new Map<string, string>();\n const messages = new Map<string, LangChainMessage>();\n const loadingSteps = new Set<string>();\n const listeners = new Set<() => void>();\n let unserved = false;\n let unservedBy: unknown;\n let version = 0;\n const notify = () => {\n version += 1;\n for (const listener of [...listeners]) listener();\n };\n const marker = (threadId: string, turn: string, state: SummarizedTurnState): DeepAgentTurnStepsMarker => {\n // The host counts only the messages the page left out; of those, the\n // steps loaded since render on their own, so they leave the hidden count.\n const loaded = toolCalls(state.loaded);\n return {\n turn,\n thread: threadId,\n hiddenSteps: state.more ? Math.max(0, state.steps.count - state.loaded.length) : 0,\n hiddenTools: Math.max(0, state.steps.tools - loaded.tools),\n hiddenDelegations: Math.max(0, state.steps.delegations - loaded.delegations),\n before: state.loaded[0]?.id,\n };\n };\n const store: DeepAgentHistoryStore = {\n get unserved() {\n return unserved;\n },\n get unservedBy() {\n return unservedBy;\n },\n get version() {\n return version;\n },\n markUnserved(connection) {\n unservedBy = connection;\n if (unserved) return;\n unserved = true;\n notify();\n },\n markServed() {\n unservedBy = undefined;\n if (!unserved) return;\n unserved = false;\n notify();\n },\n recordChain(ids, chainMessages, startsTranscript) {\n for (let index = 0; index < ids.length; index += 1) {\n const id = ids[index] as string;\n if (index > 0) parents.set(id, ids[index - 1] as string);\n else if (startsTranscript) parents.set(id, null);\n const message = chainMessages.get(id);\n if (message !== undefined) messages.set(id, message);\n }\n },\n addPage({ before, messages: page, moreBefore, summarized }) {\n let changed = false;\n const setParent = (id: string, parent: string | null) => {\n if (parents.get(id) === parent) return;\n parents.set(id, parent);\n changed = true;\n };\n const ids: string[] = [];\n for (const message of page) {\n if (typeof message.id !== 'string' || !message.id) continue;\n ids.push(message.id);\n if (messages.get(message.id) !== message) {\n messages.set(message.id, message);\n changed = true;\n }\n }\n for (const [index, id] of ids.entries()) {\n if (index > 0) setParent(id, ids[index - 1] as string);\n else if (!moreBefore) setParent(id, null);\n else if (parents.get(id) === null) {\n // The host says more lies before it: a remembered start was wrong.\n parents.delete(id);\n changed = true;\n }\n }\n const last = ids.at(-1);\n if (last !== undefined) setParent(before, last);\n else if (!moreBefore) setParent(before, null);\n for (const [turn, summary] of summarized ?? []) {\n const held = summaries.get(turn);\n if (held === undefined) {\n summaries.set(turn, {\n ...summary,\n shownAfter: summary.resume,\n loaded: [],\n more: summary.steps.count > 0,\n });\n turnStarts.set(turn, turn);\n turnStarts.set(summary.resume, turn);\n changed = true;\n continue;\n }\n const oldest = held.loaded[0];\n const newest = held.loaded.at(-1);\n if (oldest !== undefined && newest !== undefined) {\n // The same turn paged again (another reader asked the same page):\n // keep the steps already spliced in where the page left them out.\n setParent(oldest.id as string, parents.get(held.shownAfter) ?? null);\n setParent(held.shownAfter, newest.id as string);\n }\n }\n if (unserved) {\n unserved = false;\n unservedBy = undefined;\n changed = true;\n }\n if (changed) notify();\n return changed;\n },\n addSteps({ turn, messages: steps, moreBefore }) {\n const held = summaries.get(turn);\n if (held === undefined) return false;\n const loadedIds = new Set(held.loaded.map((message) => message.id));\n const fresh = steps.filter(\n (message) => typeof message.id === 'string' && message.id && !loadedIds.has(message.id)\n );\n const more = moreBefore && fresh.length > 0;\n if (fresh.length === 0) {\n if (held.more === more) return false;\n held.more = more;\n notify();\n return true;\n }\n // Splice the steps in where the gap is: after what precedes it (the\n // prompt), before where the shown transcript resumes.\n const above = parents.get(held.resume);\n const freshIds = fresh.map((message) => message.id as string);\n for (const [index, id] of freshIds.entries()) {\n messages.set(id, fresh[index] as LangChainMessage);\n if (index > 0) parents.set(id, freshIds[index - 1] as string);\n else if (above !== undefined) parents.set(id, above);\n }\n parents.set(held.resume, freshIds.at(-1) as string);\n turnStarts.delete(held.resume);\n held.resume = freshIds[0] as string;\n turnStarts.set(held.resume, turn);\n held.loaded = [...fresh, ...held.loaded];\n held.more = more;\n notify();\n return true;\n },\n olderThan(id) {\n const ids: string[] = [];\n const older: LangChainMessage[] = [];\n const seen = new Set<string>([id]);\n let parent = parents.get(id);\n while (typeof parent === 'string' && !seen.has(parent)) {\n const message = messages.get(parent);\n if (message === undefined) break;\n seen.add(parent);\n ids.push(parent);\n older.push(message);\n parent = parents.get(parent);\n }\n ids.reverse();\n older.reverse();\n return { ids, messages: older, hasOlder: parent !== null };\n },\n parentOf(id) {\n return parents.get(id);\n },\n turnSteps(turnId) {\n return summaries.get(turnId)?.steps;\n },\n markTurns(threadId, transcript) {\n if (summaries.size === 0) return transcript;\n let marked: LangChainMessage[] | null = null;\n let pending: DeepAgentTurnStepsMarker | null = null;\n const started = new Set<string>();\n for (const [index, message] of transcript.entries()) {\n const id = typeof message.id === 'string' ? message.id : undefined;\n const turn = id === undefined ? undefined : turnStarts.get(id);\n if (turn !== undefined && !started.has(turn)) {\n started.add(turn);\n const state = summaries.get(turn) as SummarizedTurnState;\n pending = marker(threadId, turn, state);\n } else if (message.type === 'human') {\n // The turn showed no reply before the next one began.\n pending = null;\n }\n // The marker rides an assistant message: a tool result whose call is\n // older than what is shown converts to no row.\n if (pending === null || message.type !== 'ai') continue;\n marked ??= [...transcript];\n marked[index] = withMarker(message, pending);\n pending = null;\n }\n return marked ?? transcript;\n },\n isLoadingSteps(turn) {\n return loadingSteps.has(turn);\n },\n async loadSteps({ send, turn, steps = DEEP_AGENT_TURN_STEPS_PAGE }) {\n const held = summaries.get(turn);\n if (held === undefined || !held.more || loadingSteps.has(turn)) return;\n loadingSteps.add(turn);\n try {\n const answer = readTurnStepsResult(await send(buildTurnStepsCommand({ turn, before: held.resume, steps })));\n if (answer === null || answer.turn !== turn) {\n throw new Error('history/page answered steps in a shape this client cannot read');\n }\n store.addSteps(answer);\n } finally {\n loadingSteps.delete(turn);\n }\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n return store;\n}\n\n/**\n * The registry lives on `globalThis`, not in module scope, because two copies\n * of this module can run in one page: the SDK bundles agent-runtime into its\n * dist while a host (Spaces, the Chrome extension, the Office add-in) imports\n * it directly. The host's thread joins pages through its copy while the SDK's\n * history edge and steps control load them through their own; both must see\n * one store per conversation.\n */\nconst HISTORY_STORES = Symbol.for('@athenaintel/agent-runtime/history-stores');\n\ninterface HistoryStoreRegistry {\n stores: Map<string, DeepAgentHistoryStore>;\n listeners: Set<() => void>;\n version: number;\n}\n\ntype HistoryStoreRegistryHost = typeof globalThis & { [HISTORY_STORES]?: HistoryStoreRegistry };\n\n// process-local: this client only — the older history it has read, in memory; nothing is persisted\nfunction registry(): HistoryStoreRegistry {\n const host = globalThis as HistoryStoreRegistryHost;\n return (host[HISTORY_STORES] ??= { stores: new Map(), listeners: new Set(), version: 0 });\n}\n\nconst notifyRegistry = () => {\n const shared = registry();\n shared.version += 1;\n for (const listener of [...shared.listeners]) listener();\n};\n\n/** The conversation's history store, created on first use and marked most recently read. */\nexport function deepAgentHistoryStore(threadId: string): DeepAgentHistoryStore {\n const { stores } = registry();\n let store = stores.get(threadId);\n if (store !== undefined) {\n stores.delete(threadId);\n stores.set(threadId, store);\n return store;\n }\n store = createDeepAgentHistoryStore();\n store.subscribe(notifyRegistry);\n stores.set(threadId, store);\n while (stores.size > DEEP_AGENT_HISTORY_STORE_LIMIT) {\n const oldest = stores.keys().next().value as string;\n stores.delete(oldest);\n }\n return store;\n}\n\n/** The conversation's store if the registry holds one, without creating or touching it. */\nexport function peekDeepAgentHistoryStore(threadId: string): DeepAgentHistoryStore | undefined {\n return registry().stores.get(threadId);\n}\n\n/** Any store's visible change (a page, steps, the unserved flag): what a converter re-runs on. */\nexport function subscribeDeepAgentHistory(listener: () => void): () => void {\n const { listeners } = registry();\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nexport function deepAgentHistoryVersion(): number {\n return registry().version;\n}\n\n/** Drop every conversation's store (sign-out, an identity change, tests). */\nexport function clearDeepAgentHistoryStores(): void {\n const { stores } = registry();\n if (stores.size === 0) return;\n stores.clear();\n notifyRegistry();\n}\n\n/**\n * Fetch the next older steps of the summarized turn a marker names, into its\n * conversation's store (the converter re-runs and shows them). A no-op when\n * the store is gone (evicted, cleared) or the turn has no steps left.\n */\nexport function loadDeepAgentTurnSteps({\n send,\n marker,\n steps,\n}: {\n send: DeepAgentHistorySend;\n marker: Pick<DeepAgentTurnStepsMarker, 'thread' | 'turn' | 'hiddenSteps'>;\n steps?: number;\n}): Promise<void> {\n if (marker.hiddenSteps === 0) return Promise.resolve();\n const store = peekDeepAgentHistoryStore(marker.thread);\n if (store === undefined) return Promise.resolve();\n return store.loadSteps({ send, turn: marker.turn, ...(steps !== undefined && { steps }) });\n}\n\n/** Whether a steps request for the marker's turn is in flight. */\nexport function isLoadingDeepAgentTurnSteps(marker: Pick<DeepAgentTurnStepsMarker, 'thread' | 'turn'>): boolean {\n return peekDeepAgentHistoryStore(marker.thread)?.isLoadingSteps(marker.turn) ?? false;\n}\n\n/** Whether the host's advertised contract version serves `history/page`. */\nexport function hostServesHistoryPage(version: number | null | undefined): boolean {\n return typeof version === 'number' && version >= DEEP_AGENT_HISTORY_PAGE_PROTOCOL_VERSION;\n}\n\n/**\n * Whether a `history/page` failure says this host does not serve the\n * command: statewire's `unknown-command`, a host without it although its\n * `protocol` lane advertises it. Any other refusal (a vanished anchor, a\n * malformed request, a host that cannot answer right now) is that page's\n * failure, reported to the reader, who may ask again; it never takes the\n * conversation off its store, whose history stays shown.\n */\nexport function isHistoryPageUnserved(error: unknown): boolean {\n const failure = (error as { failure?: { fate?: unknown; code?: unknown } } | null | undefined)\n ?.failure;\n return failure?.fate === 'rejected' && failure.code === 'unknown-command';\n}\n\n/**\n * Attach headers saying the client keeps older history itself\n * (`x-athena-deep-agent-history: paged`): the host then holds its head down\n * to its floor for at most `DEEP_AGENT_MAX_HELD_HEAD` messages, since what\n * slides out stays in the store. Every attach of this build says so: every\n * reader joins the store (`readDeepAgentMessageWindow`). An explicit entry\n * wins.\n */\nexport function withDeclaredPagedHistory(headers: Record<string, string>): Record<string, string> {\n if (DEEP_AGENT_MESSAGE_HISTORY_HEADER in headers) return headers;\n return { ...headers, [DEEP_AGENT_MESSAGE_HISTORY_HEADER]: DEEP_AGENT_MESSAGE_HISTORY_PAGED };\n}\n\n/**\n * The windowed wire's page commands on the statewire command union, so\n * `sendCommand({ type: 'history/page', … })` typechecks wherever the\n * deep-agent host is driven (an attach-ACL read, like `history/lane`).\n */\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /** One page of older transcript history. */\n historyPage: HistoryPageCommand;\n /** One summarized turn's steps. */\n historyTurnSteps: TurnStepsCommand;\n }\n }\n}\n\n/**\n * The turns `history/page` reads per page: about a screen and a half of\n * conversation, however long each run was (a long turn rides as its prompt\n * and answer, its steps counted).\n */\nexport const DEEP_AGENT_HISTORY_PAGE_TURNS = 10;\n\n/** The `history/page` command: up to `turns` whole turns ending before `before`. */\nexport interface HistoryPageCommand {\n readonly type: typeof DEEP_AGENT_HISTORY_PAGE_COMMAND;\n readonly before: string;\n readonly turns: number;\n}\n\n/** The `history/page` command asking for one summarized turn's steps older than `before`. */\nexport interface TurnStepsCommand {\n readonly type: typeof DEEP_AGENT_HISTORY_PAGE_COMMAND;\n readonly turn: string;\n readonly before?: string;\n readonly steps: number;\n}\n\nexport function buildHistoryPageCommand({\n before,\n turns = DEEP_AGENT_HISTORY_PAGE_TURNS,\n}: {\n before: string;\n turns?: number;\n}): HistoryPageCommand {\n return {\n type: DEEP_AGENT_HISTORY_PAGE_COMMAND,\n before,\n turns: Math.max(1, Math.min(DEEP_AGENT_MAX_HISTORY_PAGE_TURNS, Math.trunc(turns))),\n };\n}\n\nexport function buildTurnStepsCommand({\n turn,\n before,\n steps = DEEP_AGENT_TURN_STEPS_PAGE,\n}: {\n turn: string;\n before?: string | undefined;\n steps?: number;\n}): TurnStepsCommand {\n return {\n type: DEEP_AGENT_HISTORY_PAGE_COMMAND,\n turn,\n ...(before !== undefined && { before }),\n steps: Math.max(1, Math.min(DEEP_AGENT_MAX_HISTORY_PAGE_STEPS, Math.trunc(steps))),\n };\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isCount = (value: unknown): value is number =>\n typeof value === 'number' && Number.isInteger(value) && value >= 0;\n\nconst isId = (value: unknown): value is string => typeof value === 'string' && value.length > 0;\n\nconst readTurnSteps = (value: unknown): DeepAgentHistoryTurnSteps | null | undefined => {\n if (value === null) return null;\n if (!isRecord(value)) return undefined;\n const { count, tools, delegations, first, last } = value;\n if (!isCount(count) || !isCount(tools) || !isCount(delegations)) return undefined;\n const id = (entry: unknown) => (isId(entry) ? entry : null);\n return { count, tools, delegations, first: id(first), last: id(last) };\n};\n\nfunction readMessages(value: unknown): LangChainMessage[] | null {\n if (!Array.isArray(value)) return null;\n for (const message of value) {\n if (!isRecord(message) || !isId(message.id)) return null;\n }\n return value as LangChainMessage[];\n}\n\n/**\n * A `history/page` answer to `{before, turns}` read as one page of messages:\n * the turns' shown messages, oldest first (a summarized turn's prompt and\n * answer, its steps left out and counted in `summarized`). `null` when\n * malformed.\n */\nexport function readHistoryPageResult(\n payload: unknown,\n before: string\n): (DeepAgentHistoryPage & { summarized: ReadonlyMap<string, DeepAgentHistorySummarizedTurn> }) | null {\n if (!isRecord(payload) || !Array.isArray(payload.turns) || !isRecord(payload.more)) return null;\n if (typeof payload.more.before !== 'boolean') return null;\n const page: LangChainMessage[] = [];\n const turns: { id: string; messages: LangChainMessage[]; steps: DeepAgentHistoryTurnSteps | null }[] = [];\n for (const turn of payload.turns) {\n if (!isRecord(turn) || !isId(turn.id)) return null;\n const turnMessages = readMessages(turn.messages);\n if (turnMessages === null) return null;\n const steps = readTurnSteps(turn.steps);\n if (steps === undefined && turn.steps !== undefined) return null;\n turns.push({ id: turn.id, messages: turnMessages, steps: steps ?? null });\n page.push(...turnMessages);\n }\n const summarized = new Map<string, DeepAgentHistorySummarizedTurn>();\n for (const [index, turn] of turns.entries()) {\n if (turn.steps === null) continue;\n // The steps left out sit right after the prompt; the shown transcript\n // resumes at the next message the page carries, or — a turn the asker's\n // own messages cut short — at the message the page was asked before.\n const shown = turn.messages[0]?.id === turn.id ? turn.messages.slice(1) : turn.messages;\n const resume = shown[0]?.id ?? turns[index + 1]?.messages[0]?.id ?? before;\n summarized.set(turn.id, { steps: turn.steps, resume });\n }\n return { before, messages: page, moreBefore: payload.more.before, summarized };\n}\n\n/** A `history/page` answer to `{turn, before?, steps}`, or `null` when it is malformed. */\nexport function readTurnStepsResult(payload: unknown): DeepAgentTurnStepsPage | null {\n if (!isRecord(payload) || !isId(payload.turn) || !isRecord(payload.more)) return null;\n if (typeof payload.more.before !== 'boolean') return null;\n const steps = readMessages(payload.messages);\n if (steps === null) return null;\n return { turn: payload.turn, messages: steps, moreBefore: payload.more.before };\n}\n\n/** The marker a join put on a source message, or `undefined`. */\nexport function readTurnStepsMarker(message: unknown): DeepAgentTurnStepsMarker | undefined {\n if (!isRecord(message) || !isRecord(message.additional_kwargs)) return undefined;\n const marker = message.additional_kwargs[DEEP_AGENT_TURN_STEPS_KEY];\n if (!isRecord(marker) || !isId(marker.turn) || !isId(marker.thread)) return undefined;\n const { hiddenSteps, hiddenTools, hiddenDelegations, before } = marker;\n if (!isCount(hiddenSteps) || !isCount(hiddenTools) || !isCount(hiddenDelegations)) return undefined;\n return {\n turn: marker.turn,\n thread: marker.thread,\n hiddenSteps,\n hiddenTools,\n hiddenDelegations,\n before: isId(before) ? before : undefined,\n };\n}\n\n/** The interest-request shape a page is reported as (telemetry parity with interest pages). */\nexport function historyPageAsInterestRequest(command: HistoryPageCommand): {\n ns: typeof DEEP_AGENT_MAIN_NS;\n before: number;\n at: string;\n} {\n return { ns: DEEP_AGENT_MAIN_NS, before: command.turns, at: command.before };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const INBOUND_CHANNEL_KEY = "inbound_channel";
4
+ const INBOUND_CONTEXT_OPEN = "<inbound-message-context>";
5
+ const LEADING_CONTEXT = /^<inbound-message-context>([\s\S]*?)<\/inbound-message-context>\n*/;
6
+ const SLACK_QUOTED_THREAD_OPEN = "Earlier messages in this Slack thread (oldest first):";
7
+ const SLACK_QUOTED_THREAD_MESSAGE = "The message that mentioned you:";
8
+ const GROUP_TEXT_SOURCE = "Group SMS text message";
9
+ function leadingInboundContext(text) {
10
+ if (!text.startsWith(INBOUND_CONTEXT_OPEN)) return null;
11
+ const match = LEADING_CONTEXT.exec(text);
12
+ if (match === null) return null;
13
+ return {
14
+ raw: match[0].trimEnd(),
15
+ lines: match[1] ?? "",
16
+ rest: text.slice(match[0].length).trimStart()
17
+ };
18
+ }
19
+ function inboundContextValue(lines, key) {
20
+ for (const line of lines.split("\n")) {
21
+ const separator = line.indexOf(":");
22
+ if (separator > 0 && line.slice(0, separator).trim() === key) {
23
+ return line.slice(separator + 1).trim() || null;
24
+ }
25
+ }
26
+ return null;
27
+ }
28
+ function stripInboundContext(text) {
29
+ var _a;
30
+ return ((_a = leadingInboundContext(text)) == null ? void 0 : _a.rest) ?? text;
31
+ }
32
+ function splitInboundBody(context) {
33
+ const { lines, rest } = context;
34
+ const source = inboundContextValue(lines, "source");
35
+ if (source === "Slack" && rest.startsWith(`${SLACK_QUOTED_THREAD_OPEN}
36
+ `)) {
37
+ const marker = `
38
+
39
+ ${SLACK_QUOTED_THREAD_MESSAGE}`;
40
+ const at = rest.indexOf(marker);
41
+ if (at !== -1) {
42
+ const quoted = rest.slice(SLACK_QUOTED_THREAD_OPEN.length, at).trim();
43
+ return { body: rest.slice(at + marker.length).trimStart(), quoted: quoted || null };
44
+ }
45
+ }
46
+ if (source === GROUP_TEXT_SOURCE) {
47
+ const sender = inboundContextValue(lines, "sender_name");
48
+ const newline = rest.indexOf("\n");
49
+ const firstLine = newline === -1 ? rest : rest.slice(0, newline);
50
+ if (sender && firstLine.endsWith(GROUP_TEXT_SAID) && collapseWhitespace(firstLine.slice(0, -GROUP_TEXT_SAID.length)) === sender) {
51
+ return { body: newline === -1 ? "" : rest.slice(newline + 1), quoted: null };
52
+ }
53
+ }
54
+ return { body: rest, quoted: null };
55
+ }
56
+ const GROUP_TEXT_SAID = " said:";
57
+ function collapseWhitespace(value) {
58
+ return value.split(/\s+/).filter((word) => word.length > 0).join(" ");
59
+ }
60
+ function envelopeOf(custom) {
61
+ const raw = custom == null ? void 0 : custom[INBOUND_CHANNEL_KEY];
62
+ return typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : null;
63
+ }
64
+ function envelopeString(envelope, key) {
65
+ const value = envelope[key];
66
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
67
+ }
68
+ function isInboundChannelMessage(custom) {
69
+ const envelope = envelopeOf(custom);
70
+ return envelope !== null && envelopeString(envelope, "channel") !== null;
71
+ }
72
+ function inboundMessageBody({
73
+ custom,
74
+ text
75
+ }) {
76
+ if (!isInboundChannelMessage(custom)) return text;
77
+ const context = leadingInboundContext(text);
78
+ return context === null ? text : splitInboundBody(context).body;
79
+ }
80
+ function inboundEmailSubject(custom) {
81
+ const envelope = envelopeOf(custom);
82
+ if (envelope === null) return null;
83
+ const channel = envelopeString(envelope, "channel");
84
+ return channel === "email" || channel === "agent_email" ? envelopeString(envelope, "subject") : null;
85
+ }
86
+ exports.GROUP_TEXT_SOURCE = GROUP_TEXT_SOURCE;
87
+ exports.INBOUND_CHANNEL_KEY = INBOUND_CHANNEL_KEY;
88
+ exports.INBOUND_CONTEXT_OPEN = INBOUND_CONTEXT_OPEN;
89
+ exports.inboundContextValue = inboundContextValue;
90
+ exports.inboundEmailSubject = inboundEmailSubject;
91
+ exports.inboundMessageBody = inboundMessageBody;
92
+ exports.isInboundChannelMessage = isInboundChannelMessage;
93
+ exports.leadingInboundContext = leadingInboundContext;
94
+ exports.splitInboundBody = splitInboundBody;
95
+ exports.stripInboundContext = stripInboundContext;
96
+ //# sourceMappingURL=inbound-channel.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-channel.cjs","sources":["../../../../agent-runtime/src/inbound-channel.ts"],"sourcesContent":["/**\n * A user turn that reached the agent through a channel (Slack, email, a\n * text, Microsoft Teams, the Programmatic API, a voice memo): the reading\n * every client needs on every user bubble, kept small.\n *\n * Two things arrive with such a turn (agora\n * `services/channels/inbound_channel.py`):\n *\n * - The `inbound_channel` envelope in its message metadata, which the shipped\n * converter exposes as `metadata.custom.inbound_channel`: the channel, who\n * sent it (a name and an address or number), an email's subject and the\n * files the channel imported. Metadata never reaches the model.\n * - A routing block at the very start of its text, between\n * `<inbound-message-context>` tags: one `key: value` line per fact the agent\n * is told (the Slack channel and ids, the numbers a text went between, an\n * email's recipients, how a reply is delivered). Text is the model's only\n * way to know where a message came from, so the block stays in it.\n *\n * A person reads the words that were sent ({@link inboundMessageBody}), marked\n * with the channel and the sender; what the agent read is there on request\n * (the SDK's channel line, which loads its full reading only when a channel\n * message is shown). A message is a channel message only when it carries the\n * envelope: anyone can type the tags at the start of a chat message, and\n * their words then show as typed.\n */\n\n/** `metadata.custom` key the channel routers stamp on an inbound user turn. */\nexport const INBOUND_CHANNEL_KEY = 'inbound_channel';\n\n/** The routing block's tags (agora `INBOUND_CONTEXT_OPEN` / `INBOUND_CONTEXT_CLOSE`). */\nexport const INBOUND_CONTEXT_OPEN = '<inbound-message-context>';\nexport const INBOUND_CONTEXT_CLOSE = '</inbound-message-context>';\n\n/**\n * Anchored to the start: routers only ever prepend the block, so a sender who\n * types the tags inside their own words keeps that text (agora\n * `_LEADING_CONTEXT_RE`, Olympus `stripInboundContext`).\n */\nconst LEADING_CONTEXT = /^<inbound-message-context>([\\s\\S]*?)<\\/inbound-message-context>\\n*/;\n\n/**\n * The lines the Slack router puts around the thread a mention came in, when\n * the mention starts a conversation (agora `slack_router._build_message_text`).\n */\nconst SLACK_QUOTED_THREAD_OPEN = 'Earlier messages in this Slack thread (oldest first):';\nconst SLACK_QUOTED_THREAD_MESSAGE = 'The message that mentioned you:';\n\n/** The `source:` a group text's block names (agora `sms_group_router`). */\nexport const GROUP_TEXT_SOURCE = 'Group SMS text message';\n\n/** The routing block at the start of a message's text, as read without labels. */\nexport interface LeadingInboundContext {\n /** The block exactly as the agent read it, tags included. */\n readonly raw: string;\n /** The `key: value` lines between the tags. */\n readonly lines: string;\n /** The text after the block. */\n readonly rest: string;\n}\n\n/** The routing block at the start of `text`, or `null` when the text does not start with one. */\nexport function leadingInboundContext(text: string): LeadingInboundContext | null {\n if (!text.startsWith(INBOUND_CONTEXT_OPEN)) return null;\n const match = LEADING_CONTEXT.exec(text);\n if (match === null) return null;\n return {\n raw: match[0].trimEnd(),\n lines: match[1] ?? '',\n rest: text.slice(match[0].length).trimStart(),\n };\n}\n\n/** The block's value for `key` (its first `key: value` line), or `null`. */\nexport function inboundContextValue(lines: string, key: string): string | null {\n for (const line of lines.split('\\n')) {\n const separator = line.indexOf(':');\n if (separator > 0 && line.slice(0, separator).trim() === key) {\n return line.slice(separator + 1).trim() || null;\n }\n }\n return null;\n}\n\n/** The text with a leading routing block removed (agora `strip_inbound_context`). */\nexport function stripInboundContext(text: string): string {\n return leadingInboundContext(text)?.rest ?? text;\n}\n\n/**\n * The words after the block, without what a channel put ahead of them for\n * the agent: the Slack thread a mention came in (returned as `quoted`), a\n * group text's \"<name> said:\" line.\n */\nexport function splitInboundBody(context: LeadingInboundContext): {\n readonly body: string;\n readonly quoted: string | null;\n} {\n const { lines, rest } = context;\n const source = inboundContextValue(lines, 'source');\n if (source === 'Slack' && rest.startsWith(`${SLACK_QUOTED_THREAD_OPEN}\\n`)) {\n const marker = `\\n\\n${SLACK_QUOTED_THREAD_MESSAGE}`;\n const at = rest.indexOf(marker);\n if (at !== -1) {\n const quoted = rest.slice(SLACK_QUOTED_THREAD_OPEN.length, at).trim();\n return { body: rest.slice(at + marker.length).trimStart(), quoted: quoted || null };\n }\n }\n if (source === GROUP_TEXT_SOURCE) {\n // The block's values have their whitespace collapsed (agora\n // `build_inbound_context_block`); the \"<name> said:\" line keeps the name\n // as saved, so the two compare collapsed.\n const sender = inboundContextValue(lines, 'sender_name');\n const newline = rest.indexOf('\\n');\n const firstLine = newline === -1 ? rest : rest.slice(0, newline);\n if (sender && firstLine.endsWith(GROUP_TEXT_SAID) && collapseWhitespace(firstLine.slice(0, -GROUP_TEXT_SAID.length)) === sender) {\n return { body: newline === -1 ? '' : rest.slice(newline + 1), quoted: null };\n }\n }\n return { body: rest, quoted: null };\n}\n\n/** What follows the sender's name on a group text's first line (agora `_build_group_message_text`). */\nconst GROUP_TEXT_SAID = ' said:';\n\nfunction collapseWhitespace(value: string): string {\n return value.split(/\\s+/).filter((word) => word.length > 0).join(' ');\n}\n\nfunction envelopeOf(custom: Record<string, unknown> | null | undefined): Record<string, unknown> | null {\n const raw = custom?.[INBOUND_CHANNEL_KEY];\n return typeof raw === 'object' && raw !== null && !Array.isArray(raw)\n ? (raw as Record<string, unknown>)\n : null;\n}\n\nfunction envelopeString(envelope: Record<string, unknown>, key: string): string | null {\n const value = envelope[key];\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;\n}\n\n/**\n * Whether a thread message came in over a channel: it carries the\n * `inbound_channel` envelope with a channel. A primitive, so safe as a\n * `useAuiState` selector.\n */\nexport function isInboundChannelMessage(custom: Record<string, unknown> | null | undefined): boolean {\n const envelope = envelopeOf(custom);\n return envelope !== null && envelopeString(envelope, 'channel') !== null;\n}\n\n/**\n * What the person wrote: a channel message's `text` without its leading\n * routing block and what the channel quoted ahead of the words. Any other\n * text comes back unchanged: a message without the envelope (tags someone\n * typed stay as typed), and text without a block. Safe on every user turn and\n * on its own output.\n */\nexport function inboundMessageBody({\n custom,\n text,\n}: {\n custom: Record<string, unknown> | null | undefined;\n text: string;\n}): string {\n if (!isInboundChannelMessage(custom)) return text;\n const context = leadingInboundContext(text);\n return context === null ? text : splitInboundBody(context).body;\n}\n\n/** An email's subject, from the envelope; `null` for any other message. */\nexport function inboundEmailSubject(custom: Record<string, unknown> | null | undefined): string | null {\n const envelope = envelopeOf(custom);\n if (envelope === null) return null;\n const channel = envelopeString(envelope, 'channel');\n return channel === 'email' || channel === 'agent_email' ? envelopeString(envelope, 'subject') : null;\n}\n"],"names":[],"mappings":"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"}