@sentry/junior 0.94.0 → 0.95.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 (119) hide show
  1. package/dist/{agent-hooks-ZG7IDOIN.js → agent-hooks-FTQ5EGPO.js} +9 -10
  2. package/dist/api/people/list.js +7 -7
  3. package/dist/api/people/profile.js +7 -7
  4. package/dist/api/people/shared.d.ts +2 -2
  5. package/dist/api-reference.d.ts +1 -1
  6. package/dist/app.js +427 -196
  7. package/dist/{catalog-runtime-NZHMSMYC.js → catalog-runtime-2D7IVKUT.js} +3 -3
  8. package/dist/chat/advisor-request.d.ts +4 -0
  9. package/dist/chat/agent/request.d.ts +2 -0
  10. package/dist/chat/agent/resume.d.ts +2 -0
  11. package/dist/chat/conversations/history.d.ts +128 -0
  12. package/dist/chat/conversations/legacy-import.d.ts +38 -0
  13. package/dist/chat/conversations/messages.d.ts +39 -0
  14. package/dist/chat/conversations/projection.d.ts +94 -0
  15. package/dist/chat/conversations/retention.d.ts +36 -0
  16. package/dist/chat/conversations/sql/conversation-row.d.ts +14 -0
  17. package/dist/chat/conversations/sql/history.d.ts +4 -0
  18. package/dist/chat/conversations/sql/legacy-history-import.d.ts +55 -0
  19. package/dist/chat/conversations/sql/messages.d.ts +4 -0
  20. package/dist/chat/conversations/sql/migrations.d.ts +14 -3
  21. package/dist/chat/conversations/sql/purge.d.ts +53 -0
  22. package/dist/chat/conversations/sql/store.d.ts +7 -2
  23. package/dist/chat/conversations/store.d.ts +19 -0
  24. package/dist/chat/conversations/visible-compactions.d.ts +11 -0
  25. package/dist/chat/conversations/visible-messages.d.ts +47 -0
  26. package/dist/chat/db.d.ts +12 -1
  27. package/dist/chat/identities/sql.d.ts +1 -1
  28. package/dist/chat/logging.d.ts +2 -1
  29. package/dist/chat/resource-events/store.d.ts +2 -1
  30. package/dist/chat/runtime/reply-executor.d.ts +8 -0
  31. package/dist/chat/runtime/thread-state.d.ts +2 -0
  32. package/dist/chat/sandbox/resources.d.ts +4 -0
  33. package/dist/chat/services/mcp-auth-orchestration.d.ts +8 -0
  34. package/dist/chat/services/plugin-auth-orchestration.d.ts +12 -0
  35. package/dist/chat/services/turn-session-record.d.ts +14 -2
  36. package/dist/chat/sleep.d.ts +2 -0
  37. package/dist/chat/state/conversation.d.ts +7 -4
  38. package/dist/chat/state/session-log.d.ts +23 -1
  39. package/dist/chat/state/turn-session.d.ts +6 -0
  40. package/dist/chat/tool-support/private-trace-result.d.ts +4 -0
  41. package/dist/chat/tool-support/zod-tool.d.ts +1 -0
  42. package/dist/chat/tools/advisor/tool.d.ts +9 -4
  43. package/dist/chat/tools/definition.d.ts +2 -0
  44. package/dist/chat/tools/execution/tool-error-handler.d.ts +2 -2
  45. package/dist/chat/tools/system-time.d.ts +8 -0
  46. package/dist/chat/xml.d.ts +2 -0
  47. package/dist/{chunk-NYWPISSO.js → chunk-2XXEKR44.js} +1 -1
  48. package/dist/{chunk-QGEWC27H.js → chunk-5XMNOD3S.js} +5 -7
  49. package/dist/{chunk-NFXSLTYG.js → chunk-6ONME5IG.js} +864 -62
  50. package/dist/{chunk-LFLTJQVR.js → chunk-7FBGKXPE.js} +4 -0
  51. package/dist/{chunk-MC4ZZE4Q.js → chunk-AYP4ERVZ.js} +1 -1
  52. package/dist/{chunk-GHGPTPBL.js → chunk-B7PUBQQM.js} +1 -1
  53. package/dist/chunk-CM5EZD5F.js +17 -0
  54. package/dist/chunk-CRRBJ3JP.js +1037 -0
  55. package/dist/{chunk-G3E7SCME.js → chunk-CZEX6KIQ.js} +23 -0
  56. package/dist/{chunk-TNUUATT7.js → chunk-E3E2XNCN.js} +2 -2
  57. package/dist/{chunk-LNCREA5Z.js → chunk-EKNJM5IG.js} +3 -127
  58. package/dist/{chunk-NAPITCZ6.js → chunk-GUE7HTNR.js} +251 -6
  59. package/dist/{chunk-BTH37NCU.js → chunk-GVOUCI2O.js} +1 -1
  60. package/dist/{chunk-YYBX2BD5.js → chunk-GY34VGP5.js} +1 -1
  61. package/dist/{chunk-KRMANDHI.js → chunk-HCXXB35T.js} +1481 -349
  62. package/dist/{chunk-YTNPU7I2.js → chunk-HDTO3A74.js} +2 -2
  63. package/dist/{chunk-YJ4OPVNA.js → chunk-HZNJLKKI.js} +1 -1
  64. package/dist/{chunk-HDNWZMUN.js → chunk-KDPCGVIT.js} +116 -51
  65. package/dist/chunk-N4RNJ32C.js +48 -0
  66. package/dist/{chunk-UUB3D2XI.js → chunk-NSCHU54X.js} +8 -10
  67. package/dist/{chunk-PFXC67GJ.js → chunk-RAIB6WSG.js} +6 -80
  68. package/dist/chunk-WAGQ377B.js +724 -0
  69. package/dist/{chunk-6H4PP63X.js → chunk-WCMQJE4F.js} +24 -14
  70. package/dist/{chunk-S6QKIGRM.js → chunk-WPOJ443W.js} +15 -25
  71. package/dist/{chunk-MAVOJ54A.js → chunk-XX4N4E6C.js} +25 -388
  72. package/dist/cli/chat.js +24 -23
  73. package/dist/cli/check.js +4 -4
  74. package/dist/cli/plugins.js +11 -12
  75. package/dist/cli/snapshot-warmup.js +7 -8
  76. package/dist/cli/upgrade.js +78 -17
  77. package/dist/db/schema/agent-steps.d.ts +134 -0
  78. package/dist/db/schema/conversation-messages.d.ts +153 -0
  79. package/dist/{chat/conversations/sql → db}/schema/conversations.d.ts +34 -0
  80. package/dist/{chat/conversations/sql → db}/schema.d.ts +319 -8
  81. package/dist/db-W55B74OP.js +24 -0
  82. package/dist/deployment.d.ts +2 -0
  83. package/dist/handlers/retention.d.ts +6 -0
  84. package/dist/instrumentation.js +16 -3
  85. package/dist/legacy-import-ZPLGLAFD.js +17 -0
  86. package/dist/nitro.js +14 -4
  87. package/dist/reporting/conversations/activity.d.ts +40 -0
  88. package/dist/reporting/conversations/context.d.ts +8 -0
  89. package/dist/reporting/conversations/details.d.ts +6 -0
  90. package/dist/reporting/conversations/index.d.ts +4 -0
  91. package/dist/reporting/conversations/shared.d.ts +9 -0
  92. package/dist/reporting/conversations/statistics.d.ts +4 -0
  93. package/dist/reporting/conversations/summaries.d.ts +17 -0
  94. package/dist/reporting/conversations/transcript.d.ts +28 -0
  95. package/dist/reporting/conversations/types.d.ts +178 -0
  96. package/dist/reporting/conversations.d.ts +1 -178
  97. package/dist/reporting.d.ts +4 -3
  98. package/dist/reporting.js +603 -827
  99. package/dist/{runner-XAZPJNAQ.js → runner-OOSBDYRK.js} +35 -41
  100. package/dist/{validation-KYAWETI4.js → validation-QCGRFRFZ.js} +4 -4
  101. package/migrations/README.md +32 -0
  102. package/migrations/meta/0000_snapshot.json +978 -0
  103. package/migrations/meta/_journal.json +13 -0
  104. package/package.json +10 -7
  105. package/dist/chat/sql/schema.d.ts +0 -1049
  106. package/dist/chat/state/conversation-details.d.ts +0 -47
  107. package/dist/chunk-7STN2ZSK.js +0 -250
  108. package/dist/chunk-LE5ANBUZ.js +0 -1040
  109. package/dist/chunk-QL66APYJ.js +0 -1377
  110. package/dist/db-YDN6AFJH.js +0 -18
  111. /package/dist/{chat/sql → db}/db.d.ts +0 -0
  112. /package/dist/{chat/sql → db}/executor.d.ts +0 -0
  113. /package/dist/{chat/sql → db}/neon.d.ts +0 -0
  114. /package/dist/{chat/sql → db}/postgres.d.ts +0 -0
  115. /package/dist/{chat/conversations/sql → db}/schema/destinations.d.ts +0 -0
  116. /package/dist/{chat/conversations/sql → db}/schema/identities.d.ts +0 -0
  117. /package/dist/{chat/conversations/sql → db}/schema/migrations.d.ts +0 -0
  118. /package/dist/{chat/conversations/sql → db}/schema/timestamps.d.ts +0 -0
  119. /package/dist/{chat/conversations/sql → db}/schema/users.d.ts +0 -0
@@ -0,0 +1,724 @@
1
+ import {
2
+ ensureLegacyConversationImport
3
+ } from "./chunk-CRRBJ3JP.js";
4
+ import {
5
+ contextProvenance,
6
+ getAgentStepStore,
7
+ getConversationStore,
8
+ instructionActors,
9
+ instructionProvenanceFor
10
+ } from "./chunk-6ONME5IG.js";
11
+ import {
12
+ getStateAdapter
13
+ } from "./chunk-GUE7HTNR.js";
14
+ import {
15
+ toStoredSlackActor
16
+ } from "./chunk-WPOJ443W.js";
17
+
18
+ // src/chat/conversations/projection.ts
19
+ import { isDeepStrictEqual } from "util";
20
+ function authorizationObservationMessage(entry, createdAtMs) {
21
+ const label = entry.kind === "mcp" ? "MCP authorization" : "Authorization";
22
+ return {
23
+ role: "user",
24
+ content: [
25
+ {
26
+ type: "text",
27
+ text: `${label} completed for provider "${entry.provider}". Continue the blocked request and retry the provider operation if needed.`
28
+ }
29
+ ],
30
+ timestamp: createdAtMs
31
+ };
32
+ }
33
+ function piEntryProvenance(entry) {
34
+ return entry.provenance ?? contextProvenance;
35
+ }
36
+ function projectSteps(steps, opts) {
37
+ const messages = [];
38
+ const provenance = [];
39
+ const seqs = [];
40
+ for (const step of steps) {
41
+ if (opts?.maxSeq !== void 0 && step.seq > opts.maxSeq) {
42
+ break;
43
+ }
44
+ if (step.entry.type === "pi_message") {
45
+ messages.push(step.entry.message);
46
+ provenance.push(piEntryProvenance(step.entry));
47
+ seqs.push(step.seq);
48
+ continue;
49
+ }
50
+ if (step.entry.type === "authorization_completed") {
51
+ messages.push(
52
+ authorizationObservationMessage(step.entry, step.createdAtMs)
53
+ );
54
+ provenance.push(contextProvenance);
55
+ seqs.push(step.seq);
56
+ }
57
+ }
58
+ return { messages, provenance, seqs };
59
+ }
60
+ function connectedMcpProvidersFromSteps(steps) {
61
+ const providers = /* @__PURE__ */ new Set();
62
+ for (const step of steps) {
63
+ if (step.entry.type === "mcp_provider_connected") {
64
+ providers.add(step.entry.provider);
65
+ }
66
+ }
67
+ return [...providers].sort((left, right) => left.localeCompare(right));
68
+ }
69
+ function isUserMessage(message) {
70
+ return message.role === "user";
71
+ }
72
+ function countMatchingPrefix(left, right) {
73
+ const limit = Math.min(left.length, right.length);
74
+ for (let index = 0; index < limit; index += 1) {
75
+ if (!isDeepStrictEqual(left[index], right[index])) {
76
+ return index;
77
+ }
78
+ }
79
+ return limit;
80
+ }
81
+ function resolveCommitProvenance(args) {
82
+ if (args.explicitProvenance) {
83
+ if (args.explicitProvenance.length !== args.nextMessages.length) {
84
+ throw new Error("commit provenance must align one-to-one with messages");
85
+ }
86
+ return args.explicitProvenance;
87
+ }
88
+ const matchingPrefix = args.matchingPrefix;
89
+ const provenance = args.nextMessages.map(
90
+ (_, index) => index < matchingPrefix ? args.existing.provenance[index] ?? contextProvenance : contextProvenance
91
+ );
92
+ if (args.newMessageProvenance) {
93
+ for (let index = args.nextMessages.length - 1; index >= matchingPrefix; index -= 1) {
94
+ if (isUserMessage(args.nextMessages[index])) {
95
+ provenance[index] = args.newMessageProvenance;
96
+ break;
97
+ }
98
+ }
99
+ }
100
+ if (args.trailingMessageProvenance) {
101
+ if (args.trailingMessageProvenance.length > provenance.length) {
102
+ throw new Error(
103
+ "trailing commit provenance cannot exceed committed messages"
104
+ );
105
+ }
106
+ const newMessageCount = args.nextMessages.length - matchingPrefix;
107
+ if (args.trailingMessageProvenance.length > newMessageCount) {
108
+ throw new Error(
109
+ "trailing commit provenance must align to newly committed messages"
110
+ );
111
+ }
112
+ const start = provenance.length - args.trailingMessageProvenance.length;
113
+ args.trailingMessageProvenance.forEach((entry, offset) => {
114
+ provenance[start + offset] = entry;
115
+ });
116
+ }
117
+ return provenance;
118
+ }
119
+ async function importLegacyIfNeeded(args) {
120
+ await ensureLegacyConversationImport({ conversationId: args.conversationId });
121
+ }
122
+ async function loadProjection(args) {
123
+ await importLegacyIfNeeded(args);
124
+ const steps = await getAgentStepStore().loadCurrentEpoch(args.conversationId);
125
+ return projectSteps(steps).messages;
126
+ }
127
+ async function loadProjectionWithProvenance(args) {
128
+ await importLegacyIfNeeded(args);
129
+ const steps = await getAgentStepStore().loadCurrentEpoch(args.conversationId);
130
+ const { messages, provenance } = projectSteps(steps);
131
+ return { messages, provenance };
132
+ }
133
+ async function loadTurnProjection(args) {
134
+ await importLegacyIfNeeded(args);
135
+ const stepStore = getAgentStepStore();
136
+ if (args.committedSeq < 0) {
137
+ return projectSteps(await stepStore.loadCurrentEpoch(args.conversationId));
138
+ }
139
+ const history = await stepStore.loadHistory(args.conversationId);
140
+ const committedStep = history.find((step) => step.seq === args.committedSeq);
141
+ if (!committedStep) {
142
+ return void 0;
143
+ }
144
+ const epochSteps = history.filter(
145
+ (step) => step.contextEpoch === committedStep.contextEpoch
146
+ );
147
+ return args.includeTail ? projectSteps(epochSteps) : projectSteps(epochSteps, { maxSeq: args.committedSeq });
148
+ }
149
+ async function loadConnectedMcpProviders(args) {
150
+ await importLegacyIfNeeded(args);
151
+ const steps = await getAgentStepStore().loadCurrentEpoch(args.conversationId);
152
+ return connectedMcpProvidersFromSteps(steps);
153
+ }
154
+ function messageTimestamp(message) {
155
+ const timestamp = message.timestamp;
156
+ return typeof timestamp === "number" ? timestamp : Date.now();
157
+ }
158
+ async function commitMessages(args) {
159
+ const stepStore = getAgentStepStore();
160
+ const existing = projectSteps(
161
+ await stepStore.loadCurrentEpoch(args.conversationId)
162
+ );
163
+ const matchingPrefix = countMatchingPrefix(existing.messages, args.messages);
164
+ const nextProvenance = resolveCommitProvenance({
165
+ existing,
166
+ nextMessages: args.messages,
167
+ matchingPrefix,
168
+ ...args.provenance ? { explicitProvenance: args.provenance } : {},
169
+ ...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {},
170
+ ...args.newMessageProvenance ? { newMessageProvenance: args.newMessageProvenance } : {}
171
+ });
172
+ if (matchingPrefix === existing.messages.length) {
173
+ const newMessages = args.messages.slice(matchingPrefix);
174
+ await stepStore.append(
175
+ args.conversationId,
176
+ newMessages.map((message, index) => ({
177
+ entry: {
178
+ type: "pi_message",
179
+ message,
180
+ provenance: nextProvenance[matchingPrefix + index]
181
+ },
182
+ createdAtMs: messageTimestamp(message)
183
+ }))
184
+ );
185
+ } else {
186
+ await stepStore.startEpoch(args.conversationId, {
187
+ reason: "rollback",
188
+ messages: args.messages.map((message, index) => ({
189
+ message,
190
+ createdAtMs: messageTimestamp(message),
191
+ provenance: nextProvenance[index]
192
+ }))
193
+ });
194
+ }
195
+ const committed = projectSteps(
196
+ await stepStore.loadCurrentEpoch(args.conversationId)
197
+ );
198
+ return {
199
+ committedSeq: committed.seqs.at(-1) ?? -1,
200
+ messageSeqs: committed.seqs,
201
+ provenance: nextProvenance
202
+ };
203
+ }
204
+ async function recordMcpProviderConnected(args) {
205
+ const stepStore = getAgentStepStore();
206
+ const steps = await stepStore.loadCurrentEpoch(args.conversationId);
207
+ if (connectedMcpProvidersFromSteps(steps).includes(args.provider)) {
208
+ return;
209
+ }
210
+ await stepStore.append(args.conversationId, [
211
+ {
212
+ entry: { type: "mcp_provider_connected", provider: args.provider },
213
+ createdAtMs: Date.now()
214
+ }
215
+ ]);
216
+ }
217
+ async function recordAuthorizationRequested(args) {
218
+ const stepStore = getAgentStepStore();
219
+ const steps = await stepStore.loadCurrentEpoch(args.conversationId);
220
+ if (steps.some(
221
+ (step) => step.entry.type === "authorization_requested" && step.entry.authorizationId === args.authorizationId
222
+ )) {
223
+ return;
224
+ }
225
+ await stepStore.append(args.conversationId, [
226
+ {
227
+ entry: {
228
+ type: "authorization_requested",
229
+ kind: args.kind,
230
+ provider: args.provider,
231
+ actorId: args.actorId,
232
+ authorizationId: args.authorizationId,
233
+ delivery: args.delivery
234
+ },
235
+ createdAtMs: Date.now()
236
+ }
237
+ ]);
238
+ }
239
+ async function recordAuthorizationCompleted(args) {
240
+ const stepStore = getAgentStepStore();
241
+ const steps = await stepStore.loadCurrentEpoch(args.conversationId);
242
+ if (steps.some(
243
+ (step) => step.entry.type === "authorization_completed" && step.entry.authorizationId === args.authorizationId
244
+ )) {
245
+ return;
246
+ }
247
+ await stepStore.append(args.conversationId, [
248
+ {
249
+ entry: {
250
+ type: "authorization_completed",
251
+ kind: args.kind,
252
+ provider: args.provider,
253
+ actorId: args.actorId,
254
+ authorizationId: args.authorizationId
255
+ },
256
+ createdAtMs: Date.now()
257
+ }
258
+ ]);
259
+ }
260
+ async function recordToolExecutionStarted(args) {
261
+ await getAgentStepStore().append(args.conversationId, [
262
+ {
263
+ entry: {
264
+ type: "tool_execution_started",
265
+ toolCallId: args.toolCallId,
266
+ toolName: args.toolName,
267
+ ...args.args !== void 0 ? { args: args.args } : {}
268
+ },
269
+ createdAtMs: args.createdAtMs ?? Date.now()
270
+ }
271
+ ]);
272
+ }
273
+
274
+ // src/chat/state/turn-session.ts
275
+ import { THREAD_STATE_TTL_MS } from "chat";
276
+ import {
277
+ actorSchema,
278
+ destinationSchema,
279
+ sourceSchema
280
+ } from "@sentry/junior-plugin-api";
281
+ import { z } from "zod";
282
+ var AGENT_TURN_SESSION_PREFIX = "junior:agent_turn_session";
283
+ var AGENT_TURN_SESSION_INDEX_KEY = `${AGENT_TURN_SESSION_PREFIX}:index`;
284
+ var AGENT_TURN_SESSION_INDEX_MAX_LENGTH = 5e3;
285
+ var AGENT_TURN_SESSION_TTL_MS = THREAD_STATE_TTL_MS;
286
+ var agentTurnSessionStatusSchema = z.enum([
287
+ "running",
288
+ "awaiting_resume",
289
+ "completed",
290
+ "failed",
291
+ "abandoned"
292
+ ]);
293
+ var agentTurnSurfaceSchema = z.enum([
294
+ "slack",
295
+ "api",
296
+ "scheduler",
297
+ "internal"
298
+ ]);
299
+ var agentTurnResumeReasonSchema = z.enum([
300
+ "timeout",
301
+ "auth",
302
+ "yield"
303
+ ]);
304
+ var nonNegativeNumberSchema = z.number().finite().nonnegative();
305
+ var seqCursorSchema = z.number().int().min(-1);
306
+ var agentTurnUsageSchema = z.object({
307
+ inputTokens: nonNegativeNumberSchema.optional(),
308
+ outputTokens: nonNegativeNumberSchema.optional(),
309
+ cachedInputTokens: nonNegativeNumberSchema.optional(),
310
+ cacheCreationTokens: nonNegativeNumberSchema.optional(),
311
+ totalTokens: nonNegativeNumberSchema.optional()
312
+ }).strict();
313
+ var agentTurnSessionSummarySchema = z.object({
314
+ channelName: z.string().min(1).optional(),
315
+ version: z.number().int().nonnegative(),
316
+ conversationId: z.string().min(1),
317
+ cumulativeDurationMs: nonNegativeNumberSchema,
318
+ cumulativeUsage: agentTurnUsageSchema.optional(),
319
+ destination: destinationSchema.optional(),
320
+ source: sourceSchema.optional(),
321
+ lastProgressAtMs: nonNegativeNumberSchema,
322
+ loadedSkillNames: z.array(z.string()).optional(),
323
+ modelId: z.string().min(1).optional(),
324
+ reasoningLevel: z.string().min(1).optional(),
325
+ actor: actorSchema.optional(),
326
+ resumeReason: agentTurnResumeReasonSchema.optional(),
327
+ resumedFromSliceId: z.number().int().nonnegative().optional(),
328
+ sessionId: z.string().min(1),
329
+ sliceId: z.number().int().nonnegative(),
330
+ startedAtMs: nonNegativeNumberSchema,
331
+ state: agentTurnSessionStatusSchema,
332
+ surface: agentTurnSurfaceSchema.optional(),
333
+ traceId: z.string().optional(),
334
+ updatedAtMs: nonNegativeNumberSchema
335
+ }).strict();
336
+ var storedAgentTurnSessionRecordSchema = agentTurnSessionSummarySchema.extend({
337
+ committedSeq: seqCursorSchema,
338
+ errorMessage: z.string().optional(),
339
+ turnStartSeq: seqCursorSchema.optional()
340
+ }).strict();
341
+ function agentTurnSessionKey(conversationId, sessionId) {
342
+ return `${AGENT_TURN_SESSION_PREFIX}:${conversationId}:${sessionId}`;
343
+ }
344
+ function agentTurnSessionConversationIndexKey(conversationId) {
345
+ return `${AGENT_TURN_SESSION_PREFIX}:conversation:${conversationId}:index`;
346
+ }
347
+ function conversationExecutionFromSummary(summary) {
348
+ const status = summary.state === "completed" || summary.state === "abandoned" ? "idle" : summary.state;
349
+ return {
350
+ status,
351
+ runId: summary.sessionId,
352
+ updatedAtMs: summary.updatedAtMs
353
+ };
354
+ }
355
+ function sessionLogActor(actor) {
356
+ return actor?.platform === "slack" ? toStoredSlackActor(actor) : void 0;
357
+ }
358
+ function parseAgentTurnSessionRecord(value) {
359
+ return storedAgentTurnSessionRecordSchema.parse(value);
360
+ }
361
+ function parseAgentTurnSessionSummary(value) {
362
+ return agentTurnSessionSummarySchema.parse(value);
363
+ }
364
+ async function appendAgentTurnSessionSummary(summary, ttlMs) {
365
+ const stateAdapter = getStateAdapter();
366
+ await Promise.all([
367
+ stateAdapter.appendToList(AGENT_TURN_SESSION_INDEX_KEY, summary, {
368
+ maxLength: AGENT_TURN_SESSION_INDEX_MAX_LENGTH,
369
+ ttlMs
370
+ }),
371
+ stateAdapter.appendToList(
372
+ agentTurnSessionConversationIndexKey(summary.conversationId),
373
+ summary,
374
+ { ttlMs }
375
+ )
376
+ ]);
377
+ }
378
+ async function recordConversationActivityMetadata(args) {
379
+ const conversationStore = args.conversationStore ?? getConversationStore();
380
+ const source = args.summary.destination?.platform === "local" ? "local" : args.summary.surface;
381
+ await conversationStore.recordActivity({
382
+ activityAtMs: args.summary.updatedAtMs,
383
+ channelName: args.summary.channelName,
384
+ conversationId: args.summary.conversationId,
385
+ destination: args.summary.destination,
386
+ nowMs: args.nowMs,
387
+ actor: sessionLogActor(args.summary.actor),
388
+ source,
389
+ visibility: args.destinationVisibility
390
+ });
391
+ await conversationStore.recordExecution({
392
+ channelName: args.summary.channelName,
393
+ conversationId: args.summary.conversationId,
394
+ createdAtMs: args.summary.startedAtMs,
395
+ destination: args.summary.destination,
396
+ execution: conversationExecutionFromSummary(args.summary),
397
+ lastActivityAtMs: args.summary.updatedAtMs,
398
+ actor: sessionLogActor(args.summary.actor),
399
+ source,
400
+ updatedAtMs: args.nowMs,
401
+ visibility: args.destinationVisibility
402
+ });
403
+ }
404
+ function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessageIndex) {
405
+ return {
406
+ version: stored.version,
407
+ ...stored.channelName ? { channelName: stored.channelName } : {},
408
+ conversationId: stored.conversationId,
409
+ sessionId: stored.sessionId,
410
+ sliceId: stored.sliceId,
411
+ state: stored.state,
412
+ startedAtMs: stored.startedAtMs,
413
+ lastProgressAtMs: stored.lastProgressAtMs,
414
+ updatedAtMs: stored.updatedAtMs,
415
+ piMessages: piProjection.messages,
416
+ piMessageProvenance: piProjection.provenance,
417
+ actors: instructionActors(piProjection.provenance),
418
+ cumulativeDurationMs: stored.cumulativeDurationMs,
419
+ ...stored.destination ? { destination: stored.destination } : {},
420
+ ...stored.source ? { source: stored.source } : {},
421
+ ...stored.cumulativeUsage ? { cumulativeUsage: stored.cumulativeUsage } : {},
422
+ ...stored.resumeReason ? { resumeReason: stored.resumeReason } : {},
423
+ ...stored.errorMessage ? { errorMessage: stored.errorMessage } : {},
424
+ ...stored.loadedSkillNames ? { loadedSkillNames: stored.loadedSkillNames } : {},
425
+ ...stored.modelId ? { modelId: stored.modelId } : {},
426
+ ...stored.reasoningLevel ? { reasoningLevel: stored.reasoningLevel } : {},
427
+ ...stored.actor ? { actor: stored.actor } : {},
428
+ ...stored.resumedFromSliceId !== void 0 ? { resumedFromSliceId: stored.resumedFromSliceId } : {},
429
+ ...stored.surface ? { surface: stored.surface } : {},
430
+ ...stored.traceId ? { traceId: stored.traceId } : {},
431
+ ...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {}
432
+ };
433
+ }
434
+ async function getStoredAgentTurnSessionRecord(conversationId, sessionId) {
435
+ const stateAdapter = getStateAdapter();
436
+ await stateAdapter.connect();
437
+ const value = await stateAdapter.get(
438
+ agentTurnSessionKey(conversationId, sessionId)
439
+ );
440
+ return value == null ? void 0 : parseAgentTurnSessionRecord(value);
441
+ }
442
+ async function getAgentTurnSessionRecord(conversationId, sessionId) {
443
+ const parsed = await getStoredAgentTurnSessionRecord(
444
+ conversationId,
445
+ sessionId
446
+ );
447
+ if (!parsed) {
448
+ return void 0;
449
+ }
450
+ const piProjection = await loadTurnProjection({
451
+ conversationId,
452
+ committedSeq: parsed.committedSeq,
453
+ // Unfinished records include the current-epoch tail so parked input
454
+ // appended after the last safe boundary stays model-visible on resume.
455
+ includeTail: parsed.state === "running" || parsed.state === "awaiting_resume"
456
+ });
457
+ if (!piProjection) {
458
+ return void 0;
459
+ }
460
+ const turnStartMessageIndex = parsed.turnStartSeq === void 0 ? void 0 : piProjection.seqs.filter((seq) => seq <= parsed.turnStartSeq).length;
461
+ return materializeAgentTurnSessionRecord(
462
+ parsed,
463
+ piProjection,
464
+ turnStartMessageIndex
465
+ );
466
+ }
467
+ function buildStoredRecord(args) {
468
+ const nowMs = Date.now();
469
+ return {
470
+ version: (args.previousVersion ?? 0) + 1,
471
+ ...args.channelName ? { channelName: args.channelName } : {},
472
+ conversationId: args.conversationId,
473
+ sessionId: args.sessionId,
474
+ sliceId: args.sliceId,
475
+ state: args.state,
476
+ startedAtMs: args.startedAtMs ?? nowMs,
477
+ lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
478
+ updatedAtMs: nowMs,
479
+ committedSeq: args.committedSeq,
480
+ ...args.turnStartSeq !== void 0 ? { turnStartSeq: args.turnStartSeq } : {},
481
+ cumulativeDurationMs: args.cumulativeDurationMs,
482
+ ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
483
+ ...args.destination ? { destination: args.destination } : {},
484
+ ...args.source ? { source: args.source } : {},
485
+ ...args.actor ? { actor: args.actor } : {},
486
+ ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
487
+ ...args.modelId ? { modelId: args.modelId } : {},
488
+ ...args.reasoningLevel ? { reasoningLevel: args.reasoningLevel } : {},
489
+ ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
490
+ ...args.errorMessage ? { errorMessage: args.errorMessage } : {},
491
+ ...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
492
+ ...args.surface ? { surface: args.surface } : {},
493
+ ...args.traceId ? { traceId: args.traceId } : {}
494
+ };
495
+ }
496
+ async function setStoredRecord(args) {
497
+ const stateAdapter = getStateAdapter();
498
+ await stateAdapter.connect();
499
+ await recordConversationActivityMetadata({
500
+ conversationStore: args.conversationStore,
501
+ destinationVisibility: args.destinationVisibility,
502
+ nowMs: Date.now(),
503
+ summary: args.record
504
+ });
505
+ await stateAdapter.set(
506
+ agentTurnSessionKey(args.record.conversationId, args.record.sessionId),
507
+ args.record,
508
+ args.ttlMs
509
+ );
510
+ const {
511
+ committedSeq: _committedSeq,
512
+ errorMessage: _errorMessage,
513
+ turnStartSeq: _turnStartSeq,
514
+ ...summary
515
+ } = args.record;
516
+ await appendAgentTurnSessionSummary(summary, args.ttlMs);
517
+ return materializeAgentTurnSessionRecord(
518
+ args.record,
519
+ {
520
+ messages: [...args.piMessages],
521
+ provenance: [...args.piMessageProvenance]
522
+ },
523
+ args.turnStartMessageIndex
524
+ );
525
+ }
526
+ async function updateAgentTurnSessionState(args) {
527
+ const parsed = await getStoredAgentTurnSessionRecord(
528
+ args.existing.conversationId,
529
+ args.existing.sessionId
530
+ );
531
+ if (!parsed || parsed.version !== args.existing.version) {
532
+ return void 0;
533
+ }
534
+ return await setStoredRecord({
535
+ piMessages: args.existing.piMessages,
536
+ piMessageProvenance: args.existing.piMessageProvenance,
537
+ ttlMs: AGENT_TURN_SESSION_TTL_MS,
538
+ ...args.existing.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: args.existing.turnStartMessageIndex } : {},
539
+ record: buildStoredRecord({
540
+ conversationId: args.existing.conversationId,
541
+ sessionId: args.existing.sessionId,
542
+ sliceId: args.existing.sliceId,
543
+ state: args.state,
544
+ committedSeq: parsed.committedSeq,
545
+ ...parsed.turnStartSeq !== void 0 ? { turnStartSeq: parsed.turnStartSeq } : {},
546
+ ...parsed.channelName ? { channelName: parsed.channelName } : {},
547
+ startedAtMs: parsed.startedAtMs,
548
+ lastProgressAtMs: parsed.lastProgressAtMs,
549
+ previousVersion: parsed.version,
550
+ cumulativeDurationMs: args.existing.cumulativeDurationMs,
551
+ ...args.existing.cumulativeUsage ? { cumulativeUsage: args.existing.cumulativeUsage } : {},
552
+ ...args.existing.destination ? { destination: args.existing.destination } : {},
553
+ ...args.existing.source ? { source: args.existing.source } : {},
554
+ ...args.existing.loadedSkillNames ? { loadedSkillNames: args.existing.loadedSkillNames } : {},
555
+ ...args.existing.modelId ? { modelId: args.existing.modelId } : {},
556
+ ...args.existing.reasoningLevel ? { reasoningLevel: args.existing.reasoningLevel } : {},
557
+ ...args.existing.actor ? { actor: args.existing.actor } : {},
558
+ ...args.existing.resumeReason ? { resumeReason: args.existing.resumeReason } : {},
559
+ ...args.existing.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.existing.resumedFromSliceId } : {},
560
+ ...args.existing.surface ? { surface: args.existing.surface } : {},
561
+ ...args.existing.traceId ? { traceId: args.existing.traceId } : {},
562
+ ...args.errorMessage ?? args.existing.errorMessage ? { errorMessage: args.errorMessage ?? args.existing.errorMessage } : {}
563
+ })
564
+ });
565
+ }
566
+ async function upsertAgentTurnSessionRecord(args) {
567
+ const existingRecord = await getStoredAgentTurnSessionRecord(
568
+ args.conversationId,
569
+ args.sessionId
570
+ );
571
+ const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
572
+ const instructionActor = args.actor ?? existingRecord?.actor;
573
+ const commit = await commitMessages({
574
+ conversationId: args.conversationId,
575
+ messages: args.piMessages,
576
+ ...instructionActor ? { newMessageProvenance: instructionProvenanceFor(instructionActor) } : {},
577
+ ...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {}
578
+ });
579
+ const turnStartSeq = args.turnStartMessageIndex === void 0 ? existingRecord?.turnStartSeq : args.turnStartMessageIndex <= 0 ? -1 : commit.messageSeqs[args.turnStartMessageIndex - 1] ?? commit.committedSeq;
580
+ const turnStartMessageIndex = args.turnStartMessageIndex ?? (turnStartSeq === void 0 ? void 0 : commit.messageSeqs.filter((seq) => seq <= turnStartSeq).length);
581
+ return await setStoredRecord({
582
+ conversationStore: args.conversationStore,
583
+ destinationVisibility: args.destinationVisibility,
584
+ piMessages: args.piMessages,
585
+ piMessageProvenance: commit.provenance,
586
+ ttlMs,
587
+ ...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {},
588
+ record: buildStoredRecord({
589
+ ...args.channelName ?? existingRecord?.channelName ? { channelName: args.channelName ?? existingRecord?.channelName } : {},
590
+ conversationId: args.conversationId,
591
+ sessionId: args.sessionId,
592
+ sliceId: args.sliceId,
593
+ state: args.state,
594
+ ...existingRecord?.startedAtMs !== void 0 ? { startedAtMs: existingRecord.startedAtMs } : {},
595
+ ...args.lastProgressAtMs !== void 0 ? { lastProgressAtMs: args.lastProgressAtMs } : {},
596
+ committedSeq: commit.committedSeq,
597
+ ...turnStartSeq !== void 0 ? { turnStartSeq } : {},
598
+ previousVersion: existingRecord?.version,
599
+ cumulativeDurationMs: args.cumulativeDurationMs ?? existingRecord?.cumulativeDurationMs ?? 0,
600
+ ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
601
+ ...args.destination ?? existingRecord?.destination ? { destination: args.destination ?? existingRecord?.destination } : {},
602
+ ...args.source ?? existingRecord?.source ? { source: args.source ?? existingRecord?.source } : {},
603
+ ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
604
+ ...existingRecord?.modelId ?? args.modelId ? { modelId: existingRecord?.modelId ?? args.modelId } : {},
605
+ ...args.reasoningLevel ?? existingRecord?.reasoningLevel ? {
606
+ reasoningLevel: args.reasoningLevel ?? existingRecord?.reasoningLevel
607
+ } : {},
608
+ ...args.actor ?? existingRecord?.actor ? { actor: args.actor ?? existingRecord?.actor } : {},
609
+ ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
610
+ ...args.errorMessage ? { errorMessage: args.errorMessage } : {},
611
+ ...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
612
+ ...args.surface ?? existingRecord?.surface ? { surface: args.surface ?? existingRecord?.surface } : {},
613
+ ...args.traceId ?? existingRecord?.traceId ? { traceId: args.traceId ?? existingRecord?.traceId } : {}
614
+ })
615
+ });
616
+ }
617
+ async function recordAgentTurnSessionSummary(args) {
618
+ const existing = await getStoredAgentTurnSessionRecord(
619
+ args.conversationId,
620
+ args.sessionId
621
+ );
622
+ const nowMs = Date.now();
623
+ const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
624
+ const summary = {
625
+ version: existing?.version ?? 0,
626
+ ...args.channelName ?? existing?.channelName ? { channelName: args.channelName ?? existing?.channelName } : {},
627
+ conversationId: args.conversationId,
628
+ sessionId: args.sessionId,
629
+ sliceId: args.sliceId,
630
+ startedAtMs: existing?.startedAtMs ?? args.startedAtMs ?? nowMs,
631
+ lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
632
+ state: args.state,
633
+ updatedAtMs: nowMs,
634
+ cumulativeDurationMs: args.cumulativeDurationMs ?? existing?.cumulativeDurationMs ?? 0,
635
+ ...args.cumulativeUsage ?? existing?.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage ?? existing?.cumulativeUsage } : {},
636
+ ...args.destination ?? existing?.destination ? { destination: args.destination ?? existing?.destination } : {},
637
+ ...args.source ?? existing?.source ? { source: args.source ?? existing?.source } : {},
638
+ ...args.actor ?? existing?.actor ? { actor: args.actor ?? existing?.actor } : {},
639
+ ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : existing?.loadedSkillNames ? { loadedSkillNames: existing.loadedSkillNames } : {},
640
+ ...existing?.modelId ?? args.modelId ? { modelId: existing?.modelId ?? args.modelId } : {},
641
+ ...args.reasoningLevel ?? existing?.reasoningLevel ? { reasoningLevel: args.reasoningLevel ?? existing?.reasoningLevel } : {},
642
+ ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
643
+ ...args.surface ?? existing?.surface ? { surface: args.surface ?? existing?.surface } : {},
644
+ ...args.traceId ?? existing?.traceId ? { traceId: args.traceId ?? existing?.traceId } : {}
645
+ };
646
+ await recordConversationActivityMetadata({
647
+ conversationStore: args.conversationStore,
648
+ destinationVisibility: args.destinationVisibility,
649
+ nowMs,
650
+ summary
651
+ });
652
+ await appendAgentTurnSessionSummary(summary, ttlMs);
653
+ }
654
+ async function readAgentTurnSessionSummariesFromIndex(key) {
655
+ const stateAdapter = getStateAdapter();
656
+ await stateAdapter.connect();
657
+ const values = await stateAdapter.getList(key);
658
+ const summaries = /* @__PURE__ */ new Map();
659
+ for (const value of [...values].reverse()) {
660
+ const summary = parseAgentTurnSessionSummary(value);
661
+ const key2 = `${summary.conversationId}:${summary.sessionId}`;
662
+ if (!summaries.has(key2)) {
663
+ summaries.set(key2, summary);
664
+ }
665
+ }
666
+ return [...summaries.values()].sort(
667
+ (left, right) => right.updatedAtMs - left.updatedAtMs
668
+ );
669
+ }
670
+ async function listAgentTurnSessionSummariesForConversation(conversationId) {
671
+ const summaries = await readAgentTurnSessionSummariesFromIndex(
672
+ agentTurnSessionConversationIndexKey(conversationId)
673
+ );
674
+ if (summaries.length > 0) {
675
+ return summaries;
676
+ }
677
+ return (await readAgentTurnSessionSummariesFromIndex(AGENT_TURN_SESSION_INDEX_KEY)).filter((summary) => summary.conversationId === conversationId);
678
+ }
679
+ async function abandonAgentTurnSessionRecord(args) {
680
+ const existing = await getAgentTurnSessionRecord(
681
+ args.conversationId,
682
+ args.sessionId
683
+ );
684
+ if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned") {
685
+ return void 0;
686
+ }
687
+ return await updateAgentTurnSessionState({
688
+ existing,
689
+ state: "abandoned",
690
+ errorMessage: args.errorMessage ?? existing.errorMessage
691
+ });
692
+ }
693
+ async function failAgentTurnSessionRecord(args) {
694
+ const existing = await getAgentTurnSessionRecord(
695
+ args.conversationId,
696
+ args.sessionId
697
+ );
698
+ if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned" || existing.version !== args.expectedVersion) {
699
+ return void 0;
700
+ }
701
+ return await updateAgentTurnSessionState({
702
+ existing,
703
+ state: "failed",
704
+ errorMessage: args.errorMessage ?? existing.errorMessage
705
+ });
706
+ }
707
+
708
+ export {
709
+ projectSteps,
710
+ loadProjection,
711
+ loadProjectionWithProvenance,
712
+ loadConnectedMcpProviders,
713
+ commitMessages,
714
+ recordMcpProviderConnected,
715
+ recordAuthorizationRequested,
716
+ recordAuthorizationCompleted,
717
+ recordToolExecutionStarted,
718
+ getAgentTurnSessionRecord,
719
+ upsertAgentTurnSessionRecord,
720
+ recordAgentTurnSessionSummary,
721
+ listAgentTurnSessionSummariesForConversation,
722
+ abandonAgentTurnSessionRecord,
723
+ failAgentTurnSessionRecord
724
+ };