@sentry/junior 0.88.0 → 0.90.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 (158) hide show
  1. package/README.md +16 -5
  2. package/dist/{agent-hooks-RIJ5TSWP.js → agent-hooks-MXAF7RQL.js} +10 -10
  3. package/dist/api/people/list.js +8 -8
  4. package/dist/api/people/profile.js +8 -8
  5. package/dist/api-reference.d.ts +1 -1
  6. package/dist/app.js +716 -732
  7. package/dist/{catalog-runtime-MW7XERSU.js → catalog-runtime-DXE6NXHT.js} +5 -5
  8. package/dist/chat/agent/index.d.ts +4 -0
  9. package/dist/chat/agent/prompt.d.ts +78 -0
  10. package/dist/chat/{respond.d.ts → agent/request.d.ts} +98 -55
  11. package/dist/chat/agent/resume.d.ts +65 -0
  12. package/dist/chat/agent/sandbox.d.ts +15 -0
  13. package/dist/chat/agent/session.d.ts +20 -0
  14. package/dist/chat/agent/skills.d.ts +26 -0
  15. package/dist/chat/agent/tools.d.ts +78 -0
  16. package/dist/chat/agent-dispatch/runner.d.ts +3 -5
  17. package/dist/chat/app/production.d.ts +3 -1
  18. package/dist/chat/app/services.d.ts +1 -4
  19. package/dist/chat/logging.d.ts +2 -0
  20. package/dist/chat/mcp/tool-manager.d.ts +1 -6
  21. package/dist/chat/pi/messages.d.ts +18 -2
  22. package/dist/chat/pi/transcript.d.ts +31 -0
  23. package/dist/chat/plugins/agent-hooks.d.ts +2 -2
  24. package/dist/chat/prompt.d.ts +1 -1
  25. package/dist/chat/runtime/agent-continue-runner.d.ts +5 -5
  26. package/dist/chat/runtime/agent-run-outcome.d.ts +21 -0
  27. package/dist/chat/runtime/agent-runner.d.ts +11 -0
  28. package/dist/chat/runtime/delivered-turn-state.d.ts +2 -2
  29. package/dist/chat/runtime/generated-artifacts.d.ts +16 -0
  30. package/dist/chat/runtime/reply-executor.d.ts +2 -2
  31. package/dist/chat/runtime/slack-resume.d.ts +21 -12
  32. package/dist/chat/runtime/turn.d.ts +5 -39
  33. package/dist/chat/services/reply-delivery-plan.d.ts +0 -8
  34. package/dist/chat/services/turn-failure-response.d.ts +4 -4
  35. package/dist/chat/services/turn-result.d.ts +4 -7
  36. package/dist/chat/slack/channel.d.ts +9 -5
  37. package/dist/chat/slack/client.d.ts +3 -1
  38. package/dist/chat/slack/context.d.ts +17 -5
  39. package/dist/chat/slack/id-param.d.ts +25 -0
  40. package/dist/chat/slack/ids.d.ts +18 -4
  41. package/dist/chat/slack/outbound.d.ts +16 -0
  42. package/dist/chat/slack/output.d.ts +3 -3
  43. package/dist/chat/slack/reply.d.ts +4 -7
  44. package/dist/chat/slack/timestamp-param.d.ts +25 -0
  45. package/dist/chat/slack/tools/canvas/context.d.ts +18 -0
  46. package/dist/chat/slack/tools/canvas/create.d.ts +4 -0
  47. package/dist/chat/slack/tools/canvas/edit.d.ts +3 -0
  48. package/dist/chat/slack/tools/canvas/read.d.ts +6 -0
  49. package/dist/chat/slack/tools/canvas/write.d.ts +3 -0
  50. package/dist/chat/{tools/slack → slack/tools}/channel-access.d.ts +4 -3
  51. package/dist/chat/{tools → slack/tools}/channel-capabilities.d.ts +2 -0
  52. package/dist/chat/slack/tools/channel-list-messages.d.ts +3 -0
  53. package/dist/chat/{tools/slack → slack/tools}/context.d.ts +5 -4
  54. package/dist/chat/slack/tools/list/add-items.d.ts +3 -0
  55. package/dist/chat/{tools/slack/lists.d.ts → slack/tools/list/api.d.ts} +2 -1
  56. package/dist/chat/slack/tools/list/create.d.ts +3 -0
  57. package/dist/chat/slack/tools/list/get-items.d.ts +3 -0
  58. package/dist/chat/slack/tools/list/update-item.d.ts +3 -0
  59. package/dist/chat/slack/tools/message-add-reaction.d.ts +4 -0
  60. package/dist/chat/slack/tools/send-message.d.ts +11 -0
  61. package/dist/chat/{tools/slack → slack/tools}/slack-message-url.d.ts +5 -5
  62. package/dist/chat/slack/tools/thread-read.d.ts +6 -0
  63. package/dist/chat/slack/tools/user-lookup.d.ts +2 -0
  64. package/dist/chat/slack/users.d.ts +2 -1
  65. package/dist/chat/{services → slack}/vision-context.d.ts +4 -2
  66. package/dist/chat/state/session-log.d.ts +1 -1
  67. package/dist/chat/tool-exposure.d.ts +10 -0
  68. package/dist/chat/tool-support/catalog-tool-call.d.ts +10 -0
  69. package/dist/chat/{tools/execution → tool-support}/normalize-result.d.ts +4 -1
  70. package/dist/chat/{tools/agent-tools.d.ts → tool-support/pi-tool-adapter.d.ts} +3 -9
  71. package/dist/chat/tool-support/schema-summary.d.ts +2 -0
  72. package/dist/chat/{tools → tool-support}/skill/mcp-tool-summary.d.ts +0 -6
  73. package/dist/chat/tool-support/structured-result.d.ts +73 -0
  74. package/dist/chat/tool-support/text-range-result.d.ts +58 -0
  75. package/dist/chat/tool-support/tool-execution-report.d.ts +7 -0
  76. package/dist/chat/tool-support/zod-tool.d.ts +27 -0
  77. package/dist/chat/tools/advisor/tool.d.ts +9 -18
  78. package/dist/chat/tools/definition.d.ts +56 -9
  79. package/dist/chat/tools/execute-tool.d.ts +3 -0
  80. package/dist/chat/tools/index.d.ts +3 -2
  81. package/dist/chat/tools/resource-events.d.ts +3 -13
  82. package/dist/chat/tools/runtime/report-progress.d.ts +1 -3
  83. package/dist/chat/tools/sandbox/bash.d.ts +1 -4
  84. package/dist/chat/tools/sandbox/edit-file.d.ts +25 -7
  85. package/dist/chat/tools/sandbox/file-uploads.d.ts +30 -0
  86. package/dist/chat/tools/sandbox/file-utils.d.ts +10 -1
  87. package/dist/chat/tools/sandbox/find-files.d.ts +12 -11
  88. package/dist/chat/tools/sandbox/grep.d.ts +18 -12
  89. package/dist/chat/tools/sandbox/list-dir.d.ts +15 -7
  90. package/dist/chat/tools/sandbox/read-file.d.ts +2 -31
  91. package/dist/chat/tools/sandbox/write-file.d.ts +1 -4
  92. package/dist/chat/tools/search-tools.d.ts +4 -0
  93. package/dist/chat/tools/skill/call-mcp-tool.d.ts +1 -4
  94. package/dist/chat/tools/skill/load-skill.d.ts +4 -5
  95. package/dist/chat/tools/skill/search-mcp-tools.d.ts +1 -5
  96. package/dist/chat/tools/system-time.d.ts +1 -1
  97. package/dist/chat/tools/types.d.ts +15 -5
  98. package/dist/chat/tools/web/fetch-content.d.ts +4 -2
  99. package/dist/chat/tools/web/fetch-tool.d.ts +4 -4
  100. package/dist/chat/tools/web/image-generate.d.ts +4 -3
  101. package/dist/chat/tools/web/search.d.ts +1 -4
  102. package/dist/{chunk-4IXHIV37.js → chunk-2S7M37HY.js} +6 -8
  103. package/dist/{chunk-L7OHKDOX.js → chunk-3MPOMK3K.js} +58 -7
  104. package/dist/{chunk-V6XDCS3X.js → chunk-5GBUZI6M.js} +4 -4
  105. package/dist/{chunk-7ES37H6U.js → chunk-AN2437E3.js} +4 -4
  106. package/dist/chunk-AOISHLSF.js +747 -0
  107. package/dist/{chunk-NYJLQI42.js → chunk-BKSZL4QO.js} +11257 -11957
  108. package/dist/{chunk-XS6NLQPA.js → chunk-DACFZ5CI.js} +474 -33
  109. package/dist/chunk-GCWD2VHP.js +1216 -0
  110. package/dist/chunk-GHGPTPBL.js +53 -0
  111. package/dist/{chunk-S35CPNPT.js → chunk-HXL2ZV74.js} +40 -216
  112. package/dist/{chunk-PBV4ZIVM.js → chunk-IRRMABQD.js} +1 -1
  113. package/dist/{chunk-2DPZRS3B.js → chunk-IX76WFJV.js} +8 -8
  114. package/dist/{chunk-66NX7MNW.js → chunk-KC42JAAQ.js} +1 -1
  115. package/dist/chunk-LFLTJQVR.js +90 -0
  116. package/dist/{chunk-IATAYWFU.js → chunk-NW7AXDA5.js} +2 -2
  117. package/dist/{chunk-F22AM3OW.js → chunk-NYWPISSO.js} +1 -1
  118. package/dist/chunk-OB42YVAE.js +16 -0
  119. package/dist/chunk-ONFOWI2D.js +955 -0
  120. package/dist/chunk-PHZHJTCK.js +1062 -0
  121. package/dist/{chunk-6UPQ5GTJ.js → chunk-QCKGI74V.js} +7 -7
  122. package/dist/{chunk-YPAE5RH3.js → chunk-RS6ANWVT.js} +1 -1
  123. package/dist/{chunk-C5NCV3OB.js → chunk-TYUXD3FN.js} +1 -1
  124. package/dist/{chunk-KBFQXJL4.js → chunk-XP7F4LYB.js} +5 -7
  125. package/dist/{chunk-VMBZFPZM.js → chunk-ZUK7BL63.js} +187 -9
  126. package/dist/cli/chat.js +55 -40
  127. package/dist/cli/check.js +6 -6
  128. package/dist/cli/init.js +30 -36
  129. package/dist/cli/plugins.js +16 -16
  130. package/dist/cli/snapshot-warmup.js +9 -9
  131. package/dist/cli/upgrade.js +21 -21
  132. package/dist/db-CXI7PR5U.js +18 -0
  133. package/dist/handlers/agent-dispatch.d.ts +3 -3
  134. package/dist/handlers/mcp-oauth-callback.d.ts +3 -3
  135. package/dist/handlers/oauth-callback.d.ts +3 -3
  136. package/dist/instrumentation.js +6 -5
  137. package/dist/nitro.js +3 -7
  138. package/dist/reporting.js +23 -25
  139. package/dist/{runner-BCRF2FCI.js → runner-FKL3RAHA.js} +89 -77
  140. package/dist/{validation-FMJO3L5P.js → validation-I7GD2YWS.js} +6 -6
  141. package/package.json +6 -6
  142. package/dist/chat/respond-helpers.d.ts +0 -82
  143. package/dist/chat/services/attachment-claims.d.ts +0 -2
  144. package/dist/chat/services/channel-intent.d.ts +0 -2
  145. package/dist/chat/tools/sandbox/attach-file.d.ts +0 -7
  146. package/dist/chat/tools/slack/canvas-tools.d.ts +0 -30
  147. package/dist/chat/tools/slack/channel-list-messages.d.ts +0 -9
  148. package/dist/chat/tools/slack/channel-post-message.d.ts +0 -5
  149. package/dist/chat/tools/slack/list-tools.d.ts +0 -21
  150. package/dist/chat/tools/slack/message-add-reaction.d.ts +0 -5
  151. package/dist/chat/tools/slack/thread-read.d.ts +0 -12
  152. package/dist/chat/tools/slack/user-lookup.d.ts +0 -8
  153. package/dist/chunk-AHLSXMOU.js +0 -506
  154. package/dist/chunk-FTMXFBDC.js +0 -49
  155. package/dist/chunk-KBSLCOGE.js +0 -2226
  156. package/dist/chunk-KQKIA4CU.js +0 -186
  157. package/dist/db-37HOGLI7.js +0 -18
  158. /package/dist/chat/{tools/slack/canvases.d.ts → slack/tools/canvas/api.d.ts} +0 -0
@@ -0,0 +1,1216 @@
1
+ import {
2
+ getConnectedStateContext,
3
+ getStateAdapter
4
+ } from "./chunk-RS6ANWVT.js";
5
+ import {
6
+ getConversationStore
7
+ } from "./chunk-2S7M37HY.js";
8
+ import {
9
+ getChatConfig
10
+ } from "./chunk-HXL2ZV74.js";
11
+ import {
12
+ parseDestination
13
+ } from "./chunk-GHGPTPBL.js";
14
+ import {
15
+ logWarn,
16
+ parseRequester,
17
+ storedSlackRequesterSchema,
18
+ toStoredSlackRequester
19
+ } from "./chunk-ZUK7BL63.js";
20
+ import {
21
+ isRecord
22
+ } from "./chunk-OB42YVAE.js";
23
+
24
+ // src/chat/state/session-log.ts
25
+ import { isDeepStrictEqual } from "util";
26
+ import { z as z2 } from "zod";
27
+
28
+ // src/chat/pi/messages.ts
29
+ import { z } from "zod";
30
+ var piMessageSchema = z.object({
31
+ role: z.string()
32
+ }).passthrough().transform((value) => value);
33
+ var piContentMessageSchema = z.object({
34
+ content: z.array(z.unknown()),
35
+ role: z.string().min(1)
36
+ }).passthrough().transform((value) => value);
37
+
38
+ // src/chat/state/session-log.ts
39
+ var AGENT_SESSION_LOG_PREFIX = "junior:agent-session-log";
40
+ var AGENT_SESSION_LOG_SCHEMA_VERSION = 1;
41
+ var INITIAL_SESSION_ID = "session_0";
42
+ var SESSION_ID_PREFIX = "session_";
43
+ var STATE_STORE_LOCK_TTL_MS = 5e3;
44
+ var piMessageEntrySchema = z2.object({
45
+ schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
46
+ type: z2.literal("pi_message"),
47
+ sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
48
+ message: piMessageSchema,
49
+ requester: storedSlackRequesterSchema.optional()
50
+ });
51
+ var projectionResetEntrySchema = z2.object({
52
+ schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
53
+ type: z2.literal("projection_reset"),
54
+ sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
55
+ messages: z2.array(piMessageSchema),
56
+ requester: storedSlackRequesterSchema.optional()
57
+ });
58
+ var requesterRecordedEntrySchema = z2.object({
59
+ schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
60
+ type: z2.literal("requester_recorded"),
61
+ sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
62
+ requester: storedSlackRequesterSchema
63
+ });
64
+ var mcpProviderConnectedEntrySchema = z2.object({
65
+ schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
66
+ type: z2.literal("mcp_provider_connected"),
67
+ sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
68
+ provider: z2.string().min(1)
69
+ });
70
+ var authorizationKindSchema = z2.union([
71
+ z2.literal("plugin"),
72
+ z2.literal("mcp")
73
+ ]);
74
+ var authorizationRequestedEntrySchema = z2.object({
75
+ schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
76
+ type: z2.literal("authorization_requested"),
77
+ sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
78
+ createdAtMs: z2.number().int().nonnegative(),
79
+ kind: authorizationKindSchema,
80
+ provider: z2.string().min(1),
81
+ requesterId: z2.string().min(1),
82
+ authorizationId: z2.string().min(1),
83
+ delivery: z2.union([
84
+ z2.literal("private_link_sent"),
85
+ z2.literal("private_link_reused")
86
+ ])
87
+ });
88
+ var authorizationCompletedEntrySchema = z2.object({
89
+ schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
90
+ type: z2.literal("authorization_completed"),
91
+ sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
92
+ createdAtMs: z2.number().int().nonnegative(),
93
+ kind: authorizationKindSchema,
94
+ provider: z2.string().min(1),
95
+ requesterId: z2.string().min(1),
96
+ authorizationId: z2.string().min(1)
97
+ });
98
+ var transcriptRefSchema = z2.object({
99
+ type: z2.literal("advisor_session"),
100
+ parentConversationId: z2.string().min(1),
101
+ key: z2.string().min(1)
102
+ });
103
+ var toolExecutionStartedEntrySchema = z2.object({
104
+ schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
105
+ type: z2.literal("tool_execution_started"),
106
+ sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
107
+ createdAtMs: z2.number().int().nonnegative(),
108
+ toolCallId: z2.string().min(1),
109
+ toolName: z2.string().min(1),
110
+ args: z2.unknown().optional()
111
+ });
112
+ var subagentStartedEntrySchema = z2.object({
113
+ schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
114
+ type: z2.literal("subagent_started"),
115
+ sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
116
+ subagentInvocationId: z2.string().min(1),
117
+ subagentKind: z2.string().min(1),
118
+ parentToolCallId: z2.string().min(1).optional(),
119
+ parentConversationId: z2.string().min(1),
120
+ parentSessionId: z2.string().min(1).optional(),
121
+ transcriptRef: transcriptRefSchema,
122
+ historyMode: z2.literal("shared"),
123
+ createdAtMs: z2.number().int().nonnegative()
124
+ });
125
+ var subagentEndedEntrySchema = z2.object({
126
+ schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
127
+ type: z2.literal("subagent_ended"),
128
+ sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
129
+ subagentInvocationId: z2.string().min(1),
130
+ outcome: z2.union([
131
+ z2.literal("success"),
132
+ z2.literal("error"),
133
+ z2.literal("aborted")
134
+ ]),
135
+ errorCode: z2.string().min(1).optional(),
136
+ transcriptEndMessageIndex: z2.number().int().nonnegative().optional(),
137
+ transcriptStartMessageIndex: z2.number().int().nonnegative().optional(),
138
+ createdAtMs: z2.number().int().nonnegative()
139
+ });
140
+ var sessionLogEntrySchema = z2.discriminatedUnion("type", [
141
+ piMessageEntrySchema,
142
+ projectionResetEntrySchema,
143
+ requesterRecordedEntrySchema,
144
+ mcpProviderConnectedEntrySchema,
145
+ authorizationRequestedEntrySchema,
146
+ authorizationCompletedEntrySchema,
147
+ toolExecutionStartedEntrySchema,
148
+ subagentStartedEntrySchema,
149
+ subagentEndedEntrySchema
150
+ ]);
151
+ function key(scope) {
152
+ const prefix = getChatConfig().state.keyPrefix;
153
+ return [
154
+ ...prefix ? [prefix] : [],
155
+ AGENT_SESSION_LOG_PREFIX,
156
+ scope.conversationId
157
+ ].join(":");
158
+ }
159
+ function rawKey(scope) {
160
+ return [AGENT_SESSION_LOG_PREFIX, scope.conversationId].join(":");
161
+ }
162
+ function normalizeMessageCount(value) {
163
+ return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
164
+ }
165
+ function countMatchingPrefix(left, right) {
166
+ const limit = Math.min(left.length, right.length);
167
+ for (let index = 0; index < limit; index += 1) {
168
+ if (!isDeepStrictEqual(left[index], right[index])) {
169
+ return index;
170
+ }
171
+ }
172
+ return limit;
173
+ }
174
+ function entrySessionId(entry) {
175
+ return entry.sessionId ?? INITIAL_SESSION_ID;
176
+ }
177
+ function isActivityEntry(entry) {
178
+ return entry.type === "tool_execution_started" || entry.type === "subagent_started" || entry.type === "subagent_ended";
179
+ }
180
+ function latestProjectionResetIndex(entries) {
181
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
182
+ if (entries[index]?.type === "projection_reset") {
183
+ return index;
184
+ }
185
+ }
186
+ return -1;
187
+ }
188
+ function currentSessionId(entries) {
189
+ const resetIndex = latestProjectionResetIndex(entries);
190
+ if (resetIndex < 0) {
191
+ return INITIAL_SESSION_ID;
192
+ }
193
+ return entrySessionId(entries[resetIndex]);
194
+ }
195
+ function nextSessionId(entries) {
196
+ const resetCount = entries.filter(
197
+ (entry) => entry.type === "projection_reset"
198
+ ).length;
199
+ return `${SESSION_ID_PREFIX}${resetCount + 1}`;
200
+ }
201
+ function projectionEntries(entries, sessionId) {
202
+ if (sessionId) {
203
+ const sessionEntries = [];
204
+ let started = false;
205
+ for (const entry of entries) {
206
+ const entryId = entrySessionId(entry);
207
+ if (!started) {
208
+ if (entryId !== sessionId) {
209
+ continue;
210
+ }
211
+ started = true;
212
+ } else if (entry.type === "projection_reset" && entryId !== sessionId) {
213
+ break;
214
+ }
215
+ if (entryId === sessionId) {
216
+ sessionEntries.push(entry);
217
+ }
218
+ }
219
+ return sessionEntries;
220
+ }
221
+ const resetIndex = latestProjectionResetIndex(entries);
222
+ const startIndex = resetIndex < 0 ? 0 : resetIndex;
223
+ const currentId = resetIndex < 0 ? INITIAL_SESSION_ID : entrySessionId(entries[resetIndex]);
224
+ return entries.slice(startIndex).filter((entry) => entrySessionId(entry) === currentId);
225
+ }
226
+ function findLastIndex(values, predicate) {
227
+ for (let index = values.length - 1; index >= 0; index -= 1) {
228
+ if (predicate(values[index])) return index;
229
+ }
230
+ return -1;
231
+ }
232
+ function piEntry(message, sessionId, requester) {
233
+ return {
234
+ schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
235
+ type: "pi_message",
236
+ sessionId,
237
+ message,
238
+ ...requester ? { requester } : {}
239
+ };
240
+ }
241
+ function resetEntry(messages, sessionId, requester) {
242
+ return {
243
+ schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
244
+ type: "projection_reset",
245
+ sessionId,
246
+ messages,
247
+ ...requester ? { requester } : {}
248
+ };
249
+ }
250
+ function requesterRecordedEntry(requester, sessionId) {
251
+ return {
252
+ schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
253
+ type: "requester_recorded",
254
+ sessionId,
255
+ requester
256
+ };
257
+ }
258
+ function mcpProviderConnectedEntry(provider, sessionId) {
259
+ return {
260
+ schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
261
+ type: "mcp_provider_connected",
262
+ sessionId,
263
+ provider
264
+ };
265
+ }
266
+ function authorizationObservationMessage(entry) {
267
+ const label = entry.kind === "mcp" ? "MCP authorization" : "Authorization";
268
+ return {
269
+ role: "user",
270
+ content: [
271
+ {
272
+ type: "text",
273
+ text: `${label} completed for provider "${entry.provider}". Continue the blocked request and retry the provider operation if needed.`
274
+ }
275
+ ],
276
+ timestamp: entry.createdAtMs
277
+ };
278
+ }
279
+ function authorizationRequestedEntry(args) {
280
+ return {
281
+ schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
282
+ type: "authorization_requested",
283
+ sessionId: args.sessionId,
284
+ createdAtMs: args.createdAtMs,
285
+ kind: args.kind,
286
+ provider: args.provider,
287
+ requesterId: args.requesterId,
288
+ authorizationId: args.authorizationId,
289
+ delivery: args.delivery
290
+ };
291
+ }
292
+ function authorizationCompletedEntry(args) {
293
+ return {
294
+ schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
295
+ type: "authorization_completed",
296
+ sessionId: args.sessionId,
297
+ createdAtMs: args.createdAtMs,
298
+ kind: args.kind,
299
+ provider: args.provider,
300
+ requesterId: args.requesterId,
301
+ authorizationId: args.authorizationId
302
+ };
303
+ }
304
+ function toolExecutionStartedEntry(args) {
305
+ return {
306
+ schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
307
+ type: "tool_execution_started",
308
+ sessionId: args.sessionId,
309
+ createdAtMs: args.createdAtMs,
310
+ toolCallId: args.toolCallId,
311
+ toolName: args.toolName,
312
+ ...args.args !== void 0 ? { args: args.args } : {}
313
+ };
314
+ }
315
+ function subagentStartedEntry(args) {
316
+ return {
317
+ schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
318
+ type: "subagent_started",
319
+ sessionId: args.sessionId,
320
+ subagentInvocationId: args.subagentInvocationId,
321
+ subagentKind: args.subagentKind,
322
+ ...args.parentToolCallId ? { parentToolCallId: args.parentToolCallId } : {},
323
+ parentConversationId: args.parentConversationId,
324
+ ...args.parentSessionId ? { parentSessionId: args.parentSessionId } : {},
325
+ transcriptRef: args.transcriptRef,
326
+ historyMode: args.historyMode,
327
+ createdAtMs: args.createdAtMs
328
+ };
329
+ }
330
+ function subagentEndedEntry(args) {
331
+ return {
332
+ schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
333
+ type: "subagent_ended",
334
+ sessionId: args.sessionId,
335
+ subagentInvocationId: args.subagentInvocationId,
336
+ outcome: args.outcome,
337
+ ...args.errorCode ? { errorCode: args.errorCode } : {},
338
+ ...args.transcriptEndMessageIndex !== void 0 ? { transcriptEndMessageIndex: args.transcriptEndMessageIndex } : {},
339
+ ...args.transcriptStartMessageIndex !== void 0 ? { transcriptStartMessageIndex: args.transcriptStartMessageIndex } : {},
340
+ createdAtMs: args.createdAtMs
341
+ };
342
+ }
343
+ function decode(value) {
344
+ if (typeof value === "string") {
345
+ return decode(JSON.parse(value));
346
+ }
347
+ const parsed = sessionLogEntrySchema.safeParse(value);
348
+ if (parsed.success) {
349
+ return parsed.data;
350
+ }
351
+ return piEntry(piMessageSchema.parse(value), INITIAL_SESSION_ID);
352
+ }
353
+ function project(entries, sessionId) {
354
+ let messages = [];
355
+ let requester;
356
+ for (const entry of projectionEntries(entries, sessionId)) {
357
+ if (entry.type === "pi_message") {
358
+ messages.push(entry.message);
359
+ if (entry.message.role === "user" && entry.requester) {
360
+ requester = entry.requester;
361
+ }
362
+ continue;
363
+ }
364
+ if (entry.type === "requester_recorded") {
365
+ requester = entry.requester;
366
+ continue;
367
+ }
368
+ if (entry.type === "authorization_completed") {
369
+ messages.push(authorizationObservationMessage(entry));
370
+ continue;
371
+ }
372
+ if (entry.type === "projection_reset") {
373
+ messages = [...entry.messages];
374
+ if (entry.requester) {
375
+ requester = entry.requester;
376
+ }
377
+ continue;
378
+ }
379
+ }
380
+ return { messages, requester };
381
+ }
382
+ function projectMessages(entries, sessionId) {
383
+ return project(entries, sessionId).messages;
384
+ }
385
+ function connectedMcpProviders(entries, sessionId) {
386
+ const providers = /* @__PURE__ */ new Set();
387
+ for (const entry of projectionEntries(entries, sessionId)) {
388
+ if (entry.type === "mcp_provider_connected") {
389
+ providers.add(entry.provider);
390
+ }
391
+ }
392
+ return [...providers].sort((left, right) => left.localeCompare(right));
393
+ }
394
+ function commitEntries(existingMessages, nextMessages, sessionId, entries, existingRequester, requester) {
395
+ const matchingPrefix = countMatchingPrefix(existingMessages, nextMessages);
396
+ if (matchingPrefix === existingMessages.length) {
397
+ const newMessages = nextMessages.slice(matchingPrefix);
398
+ if (newMessages.length === 0 && requester && !isDeepStrictEqual(existingRequester, requester)) {
399
+ return {
400
+ entries: [requesterRecordedEntry(requester, sessionId)],
401
+ sessionId
402
+ };
403
+ }
404
+ const requesterIndex = requester ? findLastIndex(newMessages, (m) => m.role === "user") : -1;
405
+ return {
406
+ entries: newMessages.map(
407
+ (message, index) => piEntry(
408
+ message,
409
+ sessionId,
410
+ index === requesterIndex ? requester : void 0
411
+ )
412
+ ),
413
+ sessionId
414
+ };
415
+ }
416
+ const resetSessionId = nextSessionId(entries);
417
+ return {
418
+ entries: [
419
+ resetEntry(nextMessages, resetSessionId, requester ?? existingRequester)
420
+ ],
421
+ sessionId: resetSessionId
422
+ };
423
+ }
424
+ function redisStore(redisStateAdapter) {
425
+ const client = redisStateAdapter.getClient();
426
+ return {
427
+ async append({ entries, scope, ttlMs }) {
428
+ const listKey = key(scope);
429
+ if (entries.length > 0) {
430
+ await client.rPush(
431
+ listKey,
432
+ entries.map((entry) => JSON.stringify(entry))
433
+ );
434
+ }
435
+ await client.pExpire(listKey, Math.max(1, ttlMs));
436
+ },
437
+ async read(scope) {
438
+ const values = await client.lRange(key(scope), 0, -1);
439
+ return values.map(decode);
440
+ }
441
+ };
442
+ }
443
+ function stateStore() {
444
+ const stateAdapter = getStateAdapter();
445
+ return {
446
+ async append({ entries, scope, ttlMs }) {
447
+ const listKey = rawKey(scope);
448
+ const lock = await stateAdapter.acquireLock(
449
+ `${listKey}:commit`,
450
+ STATE_STORE_LOCK_TTL_MS
451
+ );
452
+ if (!lock) {
453
+ throw new Error("Could not acquire session log commit lock");
454
+ }
455
+ try {
456
+ const existingValue = await stateAdapter.get(listKey);
457
+ const existingEntries = Array.isArray(existingValue) ? existingValue.map(decode) : (await stateAdapter.getList(listKey)).map(decode);
458
+ await stateAdapter.set(
459
+ listKey,
460
+ [...existingEntries, ...entries],
461
+ Math.max(1, ttlMs)
462
+ );
463
+ } finally {
464
+ await stateAdapter.releaseLock(lock);
465
+ }
466
+ },
467
+ async read(scope) {
468
+ const listKey = rawKey(scope);
469
+ const value = await stateAdapter.get(listKey);
470
+ if (Array.isArray(value)) {
471
+ return value.map(decode);
472
+ }
473
+ const values = await stateAdapter.getList(listKey);
474
+ return values.map(decode);
475
+ }
476
+ };
477
+ }
478
+ async function defaultStore() {
479
+ const { redisStateAdapter, stateAdapter } = await getConnectedStateContext();
480
+ if (redisStateAdapter) {
481
+ return redisStore(redisStateAdapter);
482
+ }
483
+ await stateAdapter.connect();
484
+ return stateStore();
485
+ }
486
+ async function loadEntries(args) {
487
+ const store = args.store ?? await defaultStore();
488
+ return await store.read(args);
489
+ }
490
+ async function loadActivityEntries(args) {
491
+ const entries = await loadEntries(args);
492
+ return projectionEntries(entries, args.sessionId).filter(isActivityEntry);
493
+ }
494
+ async function loadMessages(args) {
495
+ const messageCount = normalizeMessageCount(args.messageCount);
496
+ if (messageCount === 0) {
497
+ return [];
498
+ }
499
+ const store = args.store ?? await defaultStore();
500
+ const messages = projectMessages(await store.read(args), args.sessionId);
501
+ return messages.length >= messageCount ? messages.slice(0, messageCount) : void 0;
502
+ }
503
+ async function loadProjection(args) {
504
+ const store = args.store ?? await defaultStore();
505
+ return project(await store.read(args), args.sessionId).messages;
506
+ }
507
+ async function loadConnectedMcpProviders(args) {
508
+ return connectedMcpProviders(await loadEntries(args));
509
+ }
510
+ async function recordMcpProviderConnected(args) {
511
+ const store = args.store ?? await defaultStore();
512
+ const entries = await store.read(args);
513
+ const sessionId = currentSessionId(entries);
514
+ if (connectedMcpProviders(entries).includes(args.provider)) {
515
+ return;
516
+ }
517
+ await store.append({
518
+ scope: args,
519
+ entries: [mcpProviderConnectedEntry(args.provider, sessionId)],
520
+ ttlMs: args.ttlMs
521
+ });
522
+ }
523
+ async function recordAuthorizationRequested(args) {
524
+ const store = args.store ?? await defaultStore();
525
+ const entries = await store.read(args);
526
+ const sessionId = currentSessionId(entries);
527
+ if (projectionEntries(entries).some(
528
+ (entry) => entry.type === "authorization_requested" && entry.authorizationId === args.authorizationId
529
+ )) {
530
+ return;
531
+ }
532
+ await store.append({
533
+ scope: args,
534
+ entries: [
535
+ authorizationRequestedEntry({
536
+ createdAtMs: Date.now(),
537
+ kind: args.kind,
538
+ sessionId,
539
+ provider: args.provider,
540
+ requesterId: args.requesterId,
541
+ authorizationId: args.authorizationId,
542
+ delivery: args.delivery
543
+ })
544
+ ],
545
+ ttlMs: args.ttlMs
546
+ });
547
+ }
548
+ async function recordAuthorizationCompleted(args) {
549
+ const store = args.store ?? await defaultStore();
550
+ const entries = await store.read(args);
551
+ const sessionId = currentSessionId(entries);
552
+ if (projectionEntries(entries).some(
553
+ (entry) => entry.type === "authorization_completed" && entry.authorizationId === args.authorizationId
554
+ )) {
555
+ return;
556
+ }
557
+ await store.append({
558
+ scope: args,
559
+ entries: [
560
+ authorizationCompletedEntry({
561
+ createdAtMs: Date.now(),
562
+ kind: args.kind,
563
+ sessionId,
564
+ provider: args.provider,
565
+ requesterId: args.requesterId,
566
+ authorizationId: args.authorizationId
567
+ })
568
+ ],
569
+ ttlMs: args.ttlMs
570
+ });
571
+ }
572
+ async function recordToolExecutionStarted(args) {
573
+ const store = args.store ?? await defaultStore();
574
+ const entries = await store.read(args);
575
+ const sessionId = args.sessionId ?? currentSessionId(entries);
576
+ await store.append({
577
+ scope: args,
578
+ entries: [
579
+ toolExecutionStartedEntry({
580
+ args: args.args,
581
+ createdAtMs: args.createdAtMs ?? Date.now(),
582
+ sessionId,
583
+ toolCallId: args.toolCallId,
584
+ toolName: args.toolName
585
+ })
586
+ ],
587
+ ttlMs: args.ttlMs
588
+ });
589
+ }
590
+ async function recordSubagentStarted(args) {
591
+ const store = args.store ?? await defaultStore();
592
+ const entries = await store.read(args);
593
+ const sessionId = args.sessionId ?? currentSessionId(entries);
594
+ await store.append({
595
+ scope: args,
596
+ entries: [
597
+ subagentStartedEntry({
598
+ createdAtMs: args.createdAtMs ?? Date.now(),
599
+ historyMode: args.historyMode,
600
+ parentConversationId: args.parentConversationId,
601
+ parentSessionId: args.parentSessionId,
602
+ parentToolCallId: args.parentToolCallId,
603
+ sessionId,
604
+ subagentInvocationId: args.subagentInvocationId,
605
+ subagentKind: args.subagentKind,
606
+ transcriptRef: args.transcriptRef
607
+ })
608
+ ],
609
+ ttlMs: args.ttlMs
610
+ });
611
+ }
612
+ async function recordSubagentEnded(args) {
613
+ const store = args.store ?? await defaultStore();
614
+ const entries = await store.read(args);
615
+ const sessionId = args.sessionId ?? currentSessionId(entries);
616
+ await store.append({
617
+ scope: args,
618
+ entries: [
619
+ subagentEndedEntry({
620
+ createdAtMs: args.createdAtMs ?? Date.now(),
621
+ errorCode: args.errorCode,
622
+ outcome: args.outcome,
623
+ sessionId,
624
+ subagentInvocationId: args.subagentInvocationId,
625
+ transcriptEndMessageIndex: args.transcriptEndMessageIndex,
626
+ transcriptStartMessageIndex: args.transcriptStartMessageIndex
627
+ })
628
+ ],
629
+ ttlMs: args.ttlMs
630
+ });
631
+ }
632
+ async function commitMessages(args) {
633
+ const store = args.store ?? await defaultStore();
634
+ const entries = await store.read(args);
635
+ const existingProjection = project(entries);
636
+ const currentId = currentSessionId(entries);
637
+ const commit = commitEntries(
638
+ existingProjection.messages,
639
+ args.messages,
640
+ currentId,
641
+ entries,
642
+ existingProjection.requester,
643
+ args.requester
644
+ );
645
+ await store.append({
646
+ scope: args,
647
+ entries: commit.entries,
648
+ ttlMs: args.ttlMs
649
+ });
650
+ return {
651
+ sessionId: commit.sessionId
652
+ };
653
+ }
654
+
655
+ // src/chat/xml.ts
656
+ function escapeXml(value) {
657
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
658
+ }
659
+
660
+ // src/chat/state/turn-session.ts
661
+ import { THREAD_STATE_TTL_MS } from "chat";
662
+ import {
663
+ sourceSchema
664
+ } from "@sentry/junior-plugin-api";
665
+ var AGENT_TURN_SESSION_PREFIX = "junior:agent_turn_session";
666
+ var AGENT_TURN_SESSION_INDEX_KEY = `${AGENT_TURN_SESSION_PREFIX}:index`;
667
+ var AGENT_TURN_SESSION_INDEX_MAX_LENGTH = 5e3;
668
+ var AGENT_TURN_SESSION_TTL_MS = THREAD_STATE_TTL_MS;
669
+ function agentTurnSessionKey(conversationId, sessionId) {
670
+ return `${AGENT_TURN_SESSION_PREFIX}:${conversationId}:${sessionId}`;
671
+ }
672
+ function agentTurnSessionConversationIndexKey(conversationId) {
673
+ return `${AGENT_TURN_SESSION_PREFIX}:conversation:${conversationId}:index`;
674
+ }
675
+ function toFiniteNonNegativeNumber(value) {
676
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : void 0;
677
+ }
678
+ function toNonNegativeInteger(value) {
679
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : void 0;
680
+ }
681
+ function parseAgentTurnUsage(value) {
682
+ if (!isRecord(value)) {
683
+ return void 0;
684
+ }
685
+ const usage = {};
686
+ for (const field of [
687
+ "inputTokens",
688
+ "outputTokens",
689
+ "cachedInputTokens",
690
+ "cacheCreationTokens",
691
+ "totalTokens"
692
+ ]) {
693
+ const count = toFiniteNonNegativeNumber(value[field]);
694
+ if (count !== void 0) {
695
+ usage[field] = count;
696
+ }
697
+ }
698
+ return Object.keys(usage).length > 0 ? usage : void 0;
699
+ }
700
+ function parseStoredRecord(value) {
701
+ if (isRecord(value)) {
702
+ return value;
703
+ }
704
+ if (typeof value !== "string") {
705
+ return void 0;
706
+ }
707
+ try {
708
+ const parsed = JSON.parse(value);
709
+ return isRecord(parsed) ? parsed : void 0;
710
+ } catch {
711
+ return void 0;
712
+ }
713
+ }
714
+ function parseAgentTurnSessionStatus(parsed) {
715
+ const status = parsed.state;
716
+ if (status === "running" || status === "awaiting_resume" || status === "completed" || status === "failed" || status === "abandoned") {
717
+ return status;
718
+ }
719
+ return void 0;
720
+ }
721
+ function parseAgentTurnSurface(value) {
722
+ return value === "slack" || value === "api" || value === "scheduler" || value === "internal" ? value : void 0;
723
+ }
724
+ function conversationExecutionFromSummary(summary) {
725
+ const status = summary.state === "completed" || summary.state === "abandoned" ? "idle" : summary.state;
726
+ return {
727
+ status,
728
+ runId: summary.sessionId,
729
+ updatedAtMs: summary.updatedAtMs
730
+ };
731
+ }
732
+ function parseSource(value) {
733
+ const result = sourceSchema.safeParse(value);
734
+ return result.success ? result.data : void 0;
735
+ }
736
+ function sessionLogRequester(requester) {
737
+ return requester?.platform === "slack" ? toStoredSlackRequester(requester) : void 0;
738
+ }
739
+ function parseAgentTurnSessionFields(parsed) {
740
+ const status = parseAgentTurnSessionStatus(parsed);
741
+ if (!status) {
742
+ return void 0;
743
+ }
744
+ const channelName = typeof parsed.channelName === "string" && parsed.channelName.trim() ? parsed.channelName.trim() : void 0;
745
+ const conversationId = parsed.conversationId;
746
+ const sessionId = parsed.sessionId;
747
+ const sliceId = toFiniteNonNegativeNumber(parsed.sliceId);
748
+ const version = toFiniteNonNegativeNumber(parsed.version);
749
+ const updatedAtMs = toFiniteNonNegativeNumber(parsed.updatedAtMs);
750
+ const cumulativeDurationMs = toFiniteNonNegativeNumber(parsed.cumulativeDurationMs) ?? 0;
751
+ const cumulativeUsage = parseAgentTurnUsage(parsed.cumulativeUsage);
752
+ const lastProgressAtMs = toFiniteNonNegativeNumber(parsed.lastProgressAtMs);
753
+ const logSessionId = typeof parsed.logSessionId === "string" ? parsed.logSessionId : void 0;
754
+ const requester = parsed.requester === void 0 ? void 0 : parseRequester(parsed.requester);
755
+ const startedAtMs = toFiniteNonNegativeNumber(parsed.startedAtMs);
756
+ const surface = parseAgentTurnSurface(parsed.surface);
757
+ const turnStartMessageIndex = toNonNegativeInteger(
758
+ parsed.turnStartMessageIndex
759
+ );
760
+ const destination = parsed.destination === void 0 ? void 0 : parseDestination(parsed.destination);
761
+ const source = parsed.source === void 0 ? void 0 : parseSource(parsed.source);
762
+ if (typeof conversationId !== "string" || typeof sessionId !== "string" || sliceId === void 0 || version === void 0 || updatedAtMs === void 0 || parsed.destination !== void 0 && !destination || parsed.source !== void 0 && !source || parsed.requester !== void 0 && !requester) {
763
+ return void 0;
764
+ }
765
+ return {
766
+ version,
767
+ ...channelName ? { channelName } : {},
768
+ conversationId,
769
+ sessionId,
770
+ sliceId,
771
+ state: status,
772
+ startedAtMs: startedAtMs ?? updatedAtMs,
773
+ lastProgressAtMs: lastProgressAtMs ?? updatedAtMs,
774
+ updatedAtMs,
775
+ cumulativeDurationMs,
776
+ ...logSessionId ? { logSessionId } : {},
777
+ ...cumulativeUsage ? { cumulativeUsage } : {},
778
+ ...destination ? { destination } : {},
779
+ ...source ? { source } : {},
780
+ ...requester ? { requester } : {},
781
+ ...Array.isArray(parsed.loadedSkillNames) ? {
782
+ loadedSkillNames: parsed.loadedSkillNames.filter(
783
+ (value) => typeof value === "string"
784
+ )
785
+ } : {},
786
+ ...parsed.resumeReason === "timeout" || parsed.resumeReason === "auth" || parsed.resumeReason === "yield" ? { resumeReason: parsed.resumeReason } : {},
787
+ ...typeof parsed.errorMessage === "string" ? { errorMessage: parsed.errorMessage } : {},
788
+ ...typeof parsed.resumedFromSliceId === "number" ? { resumedFromSliceId: parsed.resumedFromSliceId } : {},
789
+ ...surface ? { surface } : {},
790
+ ...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {},
791
+ ...typeof parsed.traceId === "string" ? { traceId: parsed.traceId } : {}
792
+ };
793
+ }
794
+ function parseAgentTurnSessionRecord(value) {
795
+ const parsed = parseStoredRecord(value);
796
+ if (!parsed) {
797
+ return void 0;
798
+ }
799
+ const fields = parseAgentTurnSessionFields(parsed);
800
+ const committedMessageCount = toFiniteNonNegativeNumber(
801
+ parsed.committedMessageCount
802
+ );
803
+ if (!fields || committedMessageCount === void 0) {
804
+ return void 0;
805
+ }
806
+ return {
807
+ ...fields,
808
+ committedMessageCount
809
+ };
810
+ }
811
+ function parseAgentTurnSessionSummary(value) {
812
+ const stored = parseStoredRecord(value);
813
+ if (!stored) {
814
+ return void 0;
815
+ }
816
+ const parsed = parseAgentTurnSessionFields(stored);
817
+ if (!parsed) {
818
+ return void 0;
819
+ }
820
+ const {
821
+ errorMessage: _errorMessage,
822
+ logSessionId: _logSessionId,
823
+ turnStartMessageIndex: _turnStartMessageIndex,
824
+ ...summary
825
+ } = parsed;
826
+ return summary;
827
+ }
828
+ async function appendAgentTurnSessionSummary(summary, ttlMs) {
829
+ const stateAdapter = getStateAdapter();
830
+ await Promise.all([
831
+ stateAdapter.appendToList(AGENT_TURN_SESSION_INDEX_KEY, summary, {
832
+ maxLength: AGENT_TURN_SESSION_INDEX_MAX_LENGTH,
833
+ ttlMs
834
+ }),
835
+ stateAdapter.appendToList(
836
+ agentTurnSessionConversationIndexKey(summary.conversationId),
837
+ summary,
838
+ { ttlMs }
839
+ )
840
+ ]);
841
+ }
842
+ async function recordConversationActivityMetadata(args) {
843
+ const conversationStore = args.conversationStore ?? getConversationStore();
844
+ const source = args.summary.destination?.platform === "local" ? "local" : args.summary.surface;
845
+ try {
846
+ await conversationStore.recordActivity({
847
+ activityAtMs: args.summary.updatedAtMs,
848
+ channelName: args.summary.channelName,
849
+ conversationId: args.summary.conversationId,
850
+ destination: args.summary.destination,
851
+ nowMs: args.nowMs,
852
+ requester: sessionLogRequester(args.summary.requester),
853
+ source,
854
+ visibility: args.destinationVisibility
855
+ });
856
+ await conversationStore.recordExecution({
857
+ channelName: args.summary.channelName,
858
+ conversationId: args.summary.conversationId,
859
+ createdAtMs: args.summary.startedAtMs,
860
+ destination: args.summary.destination,
861
+ execution: conversationExecutionFromSummary(args.summary),
862
+ lastActivityAtMs: args.summary.updatedAtMs,
863
+ requester: sessionLogRequester(args.summary.requester),
864
+ source,
865
+ updatedAtMs: args.nowMs,
866
+ visibility: args.destinationVisibility
867
+ });
868
+ } catch (error) {
869
+ logWarn(
870
+ "conversation_activity_metadata_update_failed",
871
+ { conversationId: args.summary.conversationId },
872
+ {
873
+ "exception.message": error instanceof Error ? error.message : String(error)
874
+ },
875
+ "Failed to update conversation activity metadata"
876
+ );
877
+ }
878
+ }
879
+ function materializePiMessages(committedMessageCount, includeProjectionTail, sessionMessages, sessionProjection) {
880
+ if (committedMessageCount === 0) {
881
+ return sessionProjection;
882
+ }
883
+ if (includeProjectionTail && sessionProjection.length >= committedMessageCount) {
884
+ return sessionProjection;
885
+ }
886
+ if (sessionMessages) {
887
+ return sessionMessages;
888
+ }
889
+ if (sessionProjection.length >= committedMessageCount) {
890
+ return sessionProjection.slice(0, committedMessageCount);
891
+ }
892
+ return void 0;
893
+ }
894
+ function materializeAgentTurnSessionRecord(stored, piMessages) {
895
+ return {
896
+ version: stored.version,
897
+ ...stored.channelName ? { channelName: stored.channelName } : {},
898
+ conversationId: stored.conversationId,
899
+ sessionId: stored.sessionId,
900
+ sliceId: stored.sliceId,
901
+ state: stored.state,
902
+ startedAtMs: stored.startedAtMs,
903
+ lastProgressAtMs: stored.lastProgressAtMs,
904
+ updatedAtMs: stored.updatedAtMs,
905
+ piMessages,
906
+ cumulativeDurationMs: stored.cumulativeDurationMs,
907
+ ...stored.destination ? { destination: stored.destination } : {},
908
+ ...stored.source ? { source: stored.source } : {},
909
+ ...stored.cumulativeUsage ? { cumulativeUsage: stored.cumulativeUsage } : {},
910
+ ...stored.resumeReason ? { resumeReason: stored.resumeReason } : {},
911
+ ...stored.errorMessage ? { errorMessage: stored.errorMessage } : {},
912
+ ...stored.loadedSkillNames ? { loadedSkillNames: stored.loadedSkillNames } : {},
913
+ ...stored.requester ? { requester: stored.requester } : {},
914
+ ...stored.resumedFromSliceId !== void 0 ? { resumedFromSliceId: stored.resumedFromSliceId } : {},
915
+ ...stored.surface ? { surface: stored.surface } : {},
916
+ ...stored.traceId ? { traceId: stored.traceId } : {},
917
+ ...stored.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: stored.turnStartMessageIndex } : {}
918
+ };
919
+ }
920
+ async function getStoredAgentTurnSessionRecord(conversationId, sessionId) {
921
+ const stateAdapter = getStateAdapter();
922
+ await stateAdapter.connect();
923
+ const value = await stateAdapter.get(
924
+ agentTurnSessionKey(conversationId, sessionId)
925
+ );
926
+ return parseAgentTurnSessionRecord(value);
927
+ }
928
+ async function getAgentTurnSessionRecord(conversationId, sessionId) {
929
+ const parsed = await getStoredAgentTurnSessionRecord(
930
+ conversationId,
931
+ sessionId
932
+ );
933
+ if (!parsed) {
934
+ return void 0;
935
+ }
936
+ const sessionMessages = await loadMessages({
937
+ conversationId,
938
+ messageCount: parsed.committedMessageCount,
939
+ ...parsed.logSessionId ? { sessionId: parsed.logSessionId } : {}
940
+ });
941
+ const sessionProjection = await loadProjection({
942
+ conversationId,
943
+ ...parsed.logSessionId ? { sessionId: parsed.logSessionId } : {}
944
+ });
945
+ const piMessages = materializePiMessages(
946
+ parsed.committedMessageCount,
947
+ parsed.state === "running" || parsed.state === "awaiting_resume",
948
+ sessionMessages,
949
+ sessionProjection
950
+ );
951
+ if (!piMessages) {
952
+ return void 0;
953
+ }
954
+ return materializeAgentTurnSessionRecord(parsed, piMessages);
955
+ }
956
+ function buildStoredRecord(args) {
957
+ const nowMs = Date.now();
958
+ return {
959
+ version: (args.previousVersion ?? 0) + 1,
960
+ ...args.channelName ? { channelName: args.channelName } : {},
961
+ conversationId: args.conversationId,
962
+ sessionId: args.sessionId,
963
+ sliceId: args.sliceId,
964
+ state: args.state,
965
+ startedAtMs: args.startedAtMs ?? nowMs,
966
+ lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
967
+ updatedAtMs: nowMs,
968
+ committedMessageCount: args.committedMessageCount,
969
+ ...args.logSessionId ? { logSessionId: args.logSessionId } : {},
970
+ cumulativeDurationMs: args.cumulativeDurationMs,
971
+ ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
972
+ ...args.destination ? { destination: args.destination } : {},
973
+ ...args.source ? { source: args.source } : {},
974
+ ...args.requester ? { requester: args.requester } : {},
975
+ ...Array.isArray(args.loadedSkillNames) ? {
976
+ loadedSkillNames: args.loadedSkillNames.filter(
977
+ (value) => typeof value === "string"
978
+ )
979
+ } : {},
980
+ ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
981
+ ...args.errorMessage ? { errorMessage: args.errorMessage } : {},
982
+ ...typeof args.resumedFromSliceId === "number" ? { resumedFromSliceId: args.resumedFromSliceId } : {},
983
+ ...args.surface ? { surface: args.surface } : {},
984
+ ...args.traceId ? { traceId: args.traceId } : {},
985
+ ...args.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: args.turnStartMessageIndex } : {}
986
+ };
987
+ }
988
+ async function setStoredRecord(args) {
989
+ const stateAdapter = getStateAdapter();
990
+ await stateAdapter.connect();
991
+ await stateAdapter.set(
992
+ agentTurnSessionKey(args.record.conversationId, args.record.sessionId),
993
+ args.record,
994
+ args.ttlMs
995
+ );
996
+ const {
997
+ committedMessageCount: _committedMessageCount,
998
+ errorMessage: _errorMessage,
999
+ logSessionId: _logSessionId,
1000
+ turnStartMessageIndex: _turnStartMessageIndex,
1001
+ ...summary
1002
+ } = args.record;
1003
+ await appendAgentTurnSessionSummary(summary, args.ttlMs);
1004
+ await recordConversationActivityMetadata({
1005
+ conversationStore: args.conversationStore,
1006
+ destinationVisibility: args.destinationVisibility,
1007
+ nowMs: Date.now(),
1008
+ summary
1009
+ });
1010
+ return materializeAgentTurnSessionRecord(args.record, [...args.piMessages]);
1011
+ }
1012
+ async function updateAgentTurnSessionState(args) {
1013
+ const parsed = await getStoredAgentTurnSessionRecord(
1014
+ args.existing.conversationId,
1015
+ args.existing.sessionId
1016
+ );
1017
+ if (!parsed || parsed.version !== args.existing.version) {
1018
+ return void 0;
1019
+ }
1020
+ return await setStoredRecord({
1021
+ piMessages: args.existing.piMessages,
1022
+ ttlMs: AGENT_TURN_SESSION_TTL_MS,
1023
+ record: buildStoredRecord({
1024
+ conversationId: args.existing.conversationId,
1025
+ sessionId: args.existing.sessionId,
1026
+ sliceId: args.existing.sliceId,
1027
+ state: args.state,
1028
+ committedMessageCount: parsed.committedMessageCount,
1029
+ ...parsed.channelName ? { channelName: parsed.channelName } : {},
1030
+ startedAtMs: parsed.startedAtMs,
1031
+ lastProgressAtMs: parsed.lastProgressAtMs,
1032
+ previousVersion: parsed.version,
1033
+ ...parsed.logSessionId ? { logSessionId: parsed.logSessionId } : {},
1034
+ cumulativeDurationMs: args.existing.cumulativeDurationMs,
1035
+ ...args.existing.cumulativeUsage ? { cumulativeUsage: args.existing.cumulativeUsage } : {},
1036
+ ...args.existing.destination ? { destination: args.existing.destination } : {},
1037
+ ...args.existing.source ? { source: args.existing.source } : {},
1038
+ ...args.existing.loadedSkillNames ? { loadedSkillNames: args.existing.loadedSkillNames } : {},
1039
+ ...args.existing.requester ? { requester: args.existing.requester } : {},
1040
+ ...args.existing.resumeReason ? { resumeReason: args.existing.resumeReason } : {},
1041
+ ...args.existing.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.existing.resumedFromSliceId } : {},
1042
+ ...args.existing.surface ? { surface: args.existing.surface } : {},
1043
+ ...args.existing.traceId ? { traceId: args.existing.traceId } : {},
1044
+ ...args.existing.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: args.existing.turnStartMessageIndex } : {},
1045
+ ...args.errorMessage ?? args.existing.errorMessage ? { errorMessage: args.errorMessage ?? args.existing.errorMessage } : {}
1046
+ })
1047
+ });
1048
+ }
1049
+ async function upsertAgentTurnSessionRecord(args) {
1050
+ const existingRecord = await getStoredAgentTurnSessionRecord(
1051
+ args.conversationId,
1052
+ args.sessionId
1053
+ );
1054
+ const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
1055
+ const commit = await commitMessages({
1056
+ conversationId: args.conversationId,
1057
+ messages: args.piMessages,
1058
+ requester: sessionLogRequester(args.requester ?? existingRecord?.requester),
1059
+ ttlMs
1060
+ });
1061
+ return await setStoredRecord({
1062
+ conversationStore: args.conversationStore,
1063
+ destinationVisibility: args.destinationVisibility,
1064
+ piMessages: args.piMessages,
1065
+ ttlMs,
1066
+ record: buildStoredRecord({
1067
+ ...args.channelName ?? existingRecord?.channelName ? { channelName: args.channelName ?? existingRecord?.channelName } : {},
1068
+ conversationId: args.conversationId,
1069
+ sessionId: args.sessionId,
1070
+ sliceId: args.sliceId,
1071
+ state: args.state,
1072
+ ...existingRecord?.startedAtMs !== void 0 ? { startedAtMs: existingRecord.startedAtMs } : {},
1073
+ ...args.lastProgressAtMs !== void 0 ? { lastProgressAtMs: args.lastProgressAtMs } : {},
1074
+ committedMessageCount: args.piMessages.length,
1075
+ logSessionId: commit.sessionId,
1076
+ previousVersion: existingRecord?.version,
1077
+ cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existingRecord?.cumulativeDurationMs ?? 0,
1078
+ ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
1079
+ ...args.destination ?? existingRecord?.destination ? { destination: args.destination ?? existingRecord?.destination } : {},
1080
+ ...args.source ?? existingRecord?.source ? { source: args.source ?? existingRecord?.source } : {},
1081
+ ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
1082
+ ...args.requester ?? existingRecord?.requester ? { requester: args.requester ?? existingRecord?.requester } : {},
1083
+ ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
1084
+ ...args.errorMessage ? { errorMessage: args.errorMessage } : {},
1085
+ ...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
1086
+ ...args.surface ?? existingRecord?.surface ? { surface: args.surface ?? existingRecord?.surface } : {},
1087
+ ...args.traceId ?? existingRecord?.traceId ? { traceId: args.traceId ?? existingRecord?.traceId } : {},
1088
+ ...(args.turnStartMessageIndex ?? existingRecord?.turnStartMessageIndex) !== void 0 ? {
1089
+ turnStartMessageIndex: args.turnStartMessageIndex ?? existingRecord?.turnStartMessageIndex
1090
+ } : {}
1091
+ })
1092
+ });
1093
+ }
1094
+ async function recordAgentTurnSessionSummary(args) {
1095
+ const existing = await getStoredAgentTurnSessionRecord(
1096
+ args.conversationId,
1097
+ args.sessionId
1098
+ );
1099
+ const nowMs = Date.now();
1100
+ const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
1101
+ const summary = {
1102
+ version: existing?.version ?? 0,
1103
+ ...args.channelName ?? existing?.channelName ? { channelName: args.channelName ?? existing?.channelName } : {},
1104
+ conversationId: args.conversationId,
1105
+ sessionId: args.sessionId,
1106
+ sliceId: args.sliceId,
1107
+ startedAtMs: existing?.startedAtMs ?? args.startedAtMs ?? nowMs,
1108
+ lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
1109
+ state: args.state,
1110
+ updatedAtMs: nowMs,
1111
+ cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existing?.cumulativeDurationMs ?? 0,
1112
+ ...args.cumulativeUsage ?? existing?.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage ?? existing?.cumulativeUsage } : {},
1113
+ ...args.destination ?? existing?.destination ? { destination: args.destination ?? existing?.destination } : {},
1114
+ ...args.source ?? existing?.source ? { source: args.source ?? existing?.source } : {},
1115
+ ...args.requester ?? existing?.requester ? { requester: args.requester ?? existing?.requester } : {},
1116
+ ...Array.isArray(args.loadedSkillNames) ? {
1117
+ loadedSkillNames: args.loadedSkillNames.filter(
1118
+ (value) => typeof value === "string"
1119
+ )
1120
+ } : existing?.loadedSkillNames ? { loadedSkillNames: existing.loadedSkillNames } : {},
1121
+ ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
1122
+ ...args.surface ?? existing?.surface ? { surface: args.surface ?? existing?.surface } : {},
1123
+ ...args.traceId ?? existing?.traceId ? { traceId: args.traceId ?? existing?.traceId } : {}
1124
+ };
1125
+ await appendAgentTurnSessionSummary(summary, ttlMs);
1126
+ await recordConversationActivityMetadata({
1127
+ conversationStore: args.conversationStore,
1128
+ destinationVisibility: args.destinationVisibility,
1129
+ nowMs,
1130
+ summary
1131
+ });
1132
+ }
1133
+ async function readAgentTurnSessionSummariesFromIndex(key2) {
1134
+ const stateAdapter = getStateAdapter();
1135
+ await stateAdapter.connect();
1136
+ const values = await stateAdapter.getList(key2);
1137
+ const summaries = /* @__PURE__ */ new Map();
1138
+ for (const value of [...values].reverse()) {
1139
+ const summary = parseAgentTurnSessionSummary(value);
1140
+ if (!summary) {
1141
+ continue;
1142
+ }
1143
+ const key3 = `${summary.conversationId}:${summary.sessionId}`;
1144
+ if (!summaries.has(key3)) {
1145
+ summaries.set(key3, summary);
1146
+ }
1147
+ }
1148
+ return [...summaries.values()].sort(
1149
+ (left, right) => right.updatedAtMs - left.updatedAtMs
1150
+ );
1151
+ }
1152
+ async function listAgentTurnSessionSummariesForConversation(conversationId) {
1153
+ const summaries = await readAgentTurnSessionSummariesFromIndex(
1154
+ agentTurnSessionConversationIndexKey(conversationId)
1155
+ );
1156
+ if (summaries.length > 0) {
1157
+ return summaries;
1158
+ }
1159
+ return (await readAgentTurnSessionSummariesFromIndex(AGENT_TURN_SESSION_INDEX_KEY)).filter((summary) => summary.conversationId === conversationId);
1160
+ }
1161
+ async function abandonAgentTurnSessionRecord(args) {
1162
+ const existing = await getAgentTurnSessionRecord(
1163
+ args.conversationId,
1164
+ args.sessionId
1165
+ );
1166
+ if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned") {
1167
+ return void 0;
1168
+ }
1169
+ return await updateAgentTurnSessionState({
1170
+ existing,
1171
+ state: "abandoned",
1172
+ errorMessage: args.errorMessage ?? existing.errorMessage
1173
+ });
1174
+ }
1175
+ async function failAgentTurnSessionRecord(args) {
1176
+ const existing = await getAgentTurnSessionRecord(
1177
+ args.conversationId,
1178
+ args.sessionId
1179
+ );
1180
+ if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned" || existing.version !== args.expectedVersion) {
1181
+ return void 0;
1182
+ }
1183
+ return await updateAgentTurnSessionState({
1184
+ existing,
1185
+ state: "failed",
1186
+ errorMessage: args.errorMessage ?? existing.errorMessage
1187
+ });
1188
+ }
1189
+
1190
+ // src/chat/interruption-marker.ts
1191
+ var INTERRUPTED_MARKER = "\n\n[Response interrupted before completion]";
1192
+ function getInterruptionMarker() {
1193
+ return INTERRUPTED_MARKER;
1194
+ }
1195
+
1196
+ export {
1197
+ piContentMessageSchema,
1198
+ loadActivityEntries,
1199
+ loadProjection,
1200
+ loadConnectedMcpProviders,
1201
+ recordMcpProviderConnected,
1202
+ recordAuthorizationRequested,
1203
+ recordAuthorizationCompleted,
1204
+ recordToolExecutionStarted,
1205
+ recordSubagentStarted,
1206
+ recordSubagentEnded,
1207
+ commitMessages,
1208
+ escapeXml,
1209
+ getAgentTurnSessionRecord,
1210
+ upsertAgentTurnSessionRecord,
1211
+ recordAgentTurnSessionSummary,
1212
+ listAgentTurnSessionSummariesForConversation,
1213
+ abandonAgentTurnSessionRecord,
1214
+ failAgentTurnSessionRecord,
1215
+ getInterruptionMarker
1216
+ };