@sentry/junior 0.108.0 → 0.109.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 (62) hide show
  1. package/dist/{agent-hooks-NU5HK3PS.js → agent-hooks-FHHVLNPA.js} +12 -12
  2. package/dist/api/conversations/events.d.ts +1 -1
  3. package/dist/api/conversations/schema.d.ts +57 -6
  4. package/dist/api/schema.js +1 -1
  5. package/dist/api.js +108 -22
  6. package/dist/app.d.ts +1 -0
  7. package/dist/app.js +1481 -420
  8. package/dist/{catalog-runtime-FOFNPR3P.js → catalog-runtime-DMGJSLV2.js} +6 -4
  9. package/dist/chat/conversations/sql/store.d.ts +0 -7
  10. package/dist/chat/log-context.d.ts +40 -0
  11. package/dist/chat/logging.d.ts +3 -26
  12. package/dist/chat/runtime/slack-resume.d.ts +2 -2
  13. package/dist/chat/services/turn-session-record.d.ts +0 -2
  14. package/dist/chat/slack/reply.d.ts +7 -19
  15. package/dist/chat/state/conversation.d.ts +1 -0
  16. package/dist/chat/task-execution/slack-work.d.ts +2 -2
  17. package/dist/chunk-3SXUV423.js +10 -0
  18. package/dist/{chunk-3RGQLX2F.js → chunk-72OMGPDS.js} +1010 -26
  19. package/dist/{chunk-2XXEKR44.js → chunk-7Q6WCISF.js} +1 -1
  20. package/dist/{chunk-TE4QHJH4.js → chunk-FENLIFJD.js} +72 -591
  21. package/dist/{chunk-XKB7LGIW.js → chunk-FWJRXN4F.js} +3 -3
  22. package/dist/{chunk-PUAMO4PI.js → chunk-HHVY4SMP.js} +41 -7
  23. package/dist/{chunk-B5I5LMSP.js → chunk-HO5NT6OE.js} +5 -7
  24. package/dist/{chunk-O24R4DCK.js → chunk-ISMWX44P.js} +93 -55
  25. package/dist/{chunk-7FBGKXPE.js → chunk-IVVGFRQQ.js} +5 -0
  26. package/dist/{chunk-KPMPQ6AA.js → chunk-IXKSQGIO.js} +90 -100
  27. package/dist/{chunk-SS67LUOK.js → chunk-JNAVF45E.js} +6 -7
  28. package/dist/{chunk-DY7TRYB5.js → chunk-MGUMR35T.js} +1 -1
  29. package/dist/{chunk-A5CO2EHL.js → chunk-MXW4GL53.js} +11 -15
  30. package/dist/{chunk-RT5BUHR5.js → chunk-O3JMSZLI.js} +1 -1
  31. package/dist/chunk-OCD3OZRK.js +125 -0
  32. package/dist/{chunk-H3QYZL7K.js → chunk-OUHNWH46.js} +28 -3
  33. package/dist/{chunk-VIXFG2VC.js → chunk-PLB7MRCQ.js} +1 -2
  34. package/dist/{chunk-UD6THJ2I.js → chunk-QY636HZU.js} +114 -12
  35. package/dist/{chunk-VH6KWKG2.js → chunk-RGX4V75M.js} +3 -3
  36. package/dist/{chunk-B7PUBQQM.js → chunk-SYAQIR5Z.js} +1 -1
  37. package/dist/chunk-TMBRFULF.js +471 -0
  38. package/dist/{chunk-YIPD3L6L.js → chunk-TT6GMXNA.js} +8 -10
  39. package/dist/{chunk-YT72TOEK.js → chunk-WHMOBKT7.js} +2 -2
  40. package/dist/cli/chat.js +23 -23
  41. package/dist/cli/check.js +8 -6
  42. package/dist/cli/plugins.js +16 -16
  43. package/dist/cli/snapshot-warmup.js +10 -9
  44. package/dist/cli/upgrade.js +314 -3505
  45. package/dist/db/db.d.ts +1 -1
  46. package/dist/{db-AMRBAT5D.js → db-V3NU72O2.js} +8 -6
  47. package/dist/instrumentation.js +3 -2
  48. package/dist/nitro.js +5 -4
  49. package/dist/{runner-TQH5GAJ4.js → runner-JYBCQBLK.js} +17 -20
  50. package/dist/{skills-ITNHBARB.js → skills-U6MDAST7.js} +7 -5
  51. package/dist/{validation-AGQ46ZGV.js → validation-72N3JVRU.js} +7 -5
  52. package/dist/version.d.ts +2 -0
  53. package/dist/version.js +7 -0
  54. package/migrations/0006_drop_legacy_conversation_messages.sql +1 -0
  55. package/migrations/README.md +12 -9
  56. package/migrations/meta/0006_snapshot.json +948 -0
  57. package/migrations/meta/_journal.json +7 -0
  58. package/package.json +9 -5
  59. package/dist/chunk-AHJR2IFF.js +0 -115
  60. package/dist/chunk-G3E7SCME.js +0 -28
  61. package/dist/chunk-J3B3FPP2.js +0 -1061
  62. package/dist/chunk-TWINAEZQ.js +0 -1283
@@ -1,1061 +0,0 @@
1
- import {
2
- agentTurnUsageSchema
3
- } from "./chunk-MU6HHZEN.js";
4
- import {
5
- getStateAdapter
6
- } from "./chunk-H3QYZL7K.js";
7
- import {
8
- contextProvenance,
9
- createSqlConversationEventStore,
10
- getConversationEventStore,
11
- getConversationStore,
12
- getSqlExecutor,
13
- instructionActors,
14
- instructionProvenanceFor,
15
- sanitizePostgresJson,
16
- withConversationEventLock
17
- } from "./chunk-TE4QHJH4.js";
18
- import {
19
- retainRuntimeTurnContext,
20
- stripRuntimeTurnContext
21
- } from "./chunk-SS67LUOK.js";
22
- import {
23
- toStoredSlackActor
24
- } from "./chunk-VIXFG2VC.js";
25
- import {
26
- logWarn
27
- } from "./chunk-O24R4DCK.js";
28
- import {
29
- isRecord,
30
- toOptionalNumber,
31
- toOptionalString
32
- } from "./chunk-OB42YVAE.js";
33
-
34
- // src/chat/conversations/projection.ts
35
- import { isDeepStrictEqual } from "util";
36
-
37
- // src/chat/pi/messages.ts
38
- import { z } from "zod";
39
- var piMessageSchema = z.object({
40
- role: z.string()
41
- }).passthrough().transform((value) => value);
42
- var piContentMessageSchema = z.object({
43
- content: z.array(z.unknown()),
44
- role: z.string().min(1)
45
- }).passthrough().transform((value) => value);
46
-
47
- // src/chat/pi/conversation-events.ts
48
- function authorizationObservationMessage(data, createdAtMs) {
49
- const label = data.kind === "mcp" ? "MCP authorization" : "Authorization";
50
- return piMessageSchema.parse({
51
- role: "user",
52
- content: [
53
- {
54
- type: "text",
55
- text: `${label} completed for provider "${data.provider}". Continue the blocked request and retry the provider operation if needed.`
56
- }
57
- ],
58
- timestamp: createdAtMs
59
- });
60
- }
61
- function messageEventProvenance(data) {
62
- return data.provenance ?? contextProvenance;
63
- }
64
- function durableMessages(message) {
65
- return stripRuntimeTurnContext([piMessageSchema.parse(message)]);
66
- }
67
- function projectConversationEvents(events, options) {
68
- const messages = [];
69
- const provenance = [];
70
- const seqs = [];
71
- let modelProfile = "standard";
72
- let modelId;
73
- for (const event of events) {
74
- if (options?.maxSeq !== void 0 && event.seq > options.maxSeq) break;
75
- if (event.data.type === "unknown") {
76
- throw new Error(
77
- `Unsupported conversation event "${event.data.originalType}" at seq ${event.seq} (schema version ${event.schemaVersion})`
78
- );
79
- }
80
- if (event.data.type === "compaction" || event.data.type === "handoff" || event.data.type === "rollback") {
81
- modelProfile = event.data.modelProfile;
82
- modelId = event.data.modelId;
83
- for (const replacement of event.data.replacementHistory) {
84
- for (const message of durableMessages(replacement.message)) {
85
- messages.push(message);
86
- provenance.push(replacement.provenance ?? contextProvenance);
87
- seqs.push(replacement.sourceEventSeq ?? event.seq);
88
- }
89
- }
90
- continue;
91
- }
92
- if (event.data.type === "agent_step") {
93
- for (const message of durableMessages(event.data.message)) {
94
- messages.push(message);
95
- provenance.push(messageEventProvenance(event.data));
96
- seqs.push(event.seq);
97
- }
98
- continue;
99
- }
100
- if (event.data.type === "authorization_completed") {
101
- messages.push(
102
- authorizationObservationMessage(event.data, event.createdAtMs)
103
- );
104
- provenance.push(contextProvenance);
105
- seqs.push(event.seq);
106
- }
107
- }
108
- return { messages, provenance, seqs, modelProfile, modelId };
109
- }
110
-
111
- // src/chat/conversations/projection.ts
112
- function connectedMcpProvidersFromEvents(events) {
113
- const providers = /* @__PURE__ */ new Set();
114
- for (const event of events) {
115
- if (event.data.type === "mcp_provider_connected") {
116
- providers.add(event.data.provider);
117
- }
118
- }
119
- return [...providers].sort((left, right) => left.localeCompare(right));
120
- }
121
- function isUserMessage(message) {
122
- return message.role === "user";
123
- }
124
- function countMatchingPrefix(left, right) {
125
- const limit = Math.min(left.length, right.length);
126
- for (let index = 0; index < limit; index += 1) {
127
- if (!isDeepStrictEqual(left[index], right[index])) {
128
- return index;
129
- }
130
- }
131
- return limit;
132
- }
133
- function normalizeDurableMessage(message) {
134
- return piMessageSchema.parse(
135
- JSON.parse(JSON.stringify(sanitizePostgresJson(message)))
136
- );
137
- }
138
- function resolveCommitProvenance(args) {
139
- if (args.explicitProvenance) {
140
- if (args.explicitProvenance.length !== args.nextMessages.length) {
141
- throw new Error("commit provenance must align one-to-one with messages");
142
- }
143
- return args.explicitProvenance;
144
- }
145
- const matchingPrefix = args.matchingPrefix;
146
- const provenance = args.nextMessages.map(
147
- (_, index) => index < matchingPrefix ? args.existing.provenance[index] ?? contextProvenance : contextProvenance
148
- );
149
- if (args.newMessageProvenance) {
150
- for (let index = args.nextMessages.length - 1; index >= matchingPrefix; index -= 1) {
151
- if (isUserMessage(args.nextMessages[index])) {
152
- provenance[index] = args.newMessageProvenance;
153
- break;
154
- }
155
- }
156
- }
157
- if (args.trailingMessageProvenance) {
158
- if (args.trailingMessageProvenance.length > provenance.length) {
159
- throw new Error(
160
- "trailing commit provenance cannot exceed committed messages"
161
- );
162
- }
163
- const newMessageCount = args.nextMessages.length - matchingPrefix;
164
- if (args.trailingMessageProvenance.length > newMessageCount) {
165
- throw new Error(
166
- "trailing commit provenance must align to newly committed messages"
167
- );
168
- }
169
- const start = provenance.length - args.trailingMessageProvenance.length;
170
- args.trailingMessageProvenance.forEach((entry, offset) => {
171
- provenance[start + offset] = entry;
172
- });
173
- }
174
- return provenance;
175
- }
176
- async function loadProjection(args) {
177
- const events = await getConversationEventStore().loadCurrentHistory(
178
- args.conversationId
179
- );
180
- return projectConversationEvents(events).messages;
181
- }
182
- async function loadConversationProjection(args) {
183
- const events = await getConversationEventStore().loadCurrentHistory(
184
- args.conversationId
185
- );
186
- return projectConversationEvents(events);
187
- }
188
- async function openConversationProjection(args) {
189
- const events = await getConversationEventStore().loadCurrentHistory(
190
- args.conversationId
191
- );
192
- return projectConversationEvents(events);
193
- }
194
- async function loadTurnProjection(args) {
195
- const eventStore = getConversationEventStore();
196
- if (args.committedSeq < 0) {
197
- return projectConversationEvents(
198
- await eventStore.loadCurrentHistory(args.conversationId)
199
- );
200
- }
201
- const historyEvents = await eventStore.loadHistoryContaining(
202
- args.conversationId,
203
- args.committedSeq,
204
- args.includeTail ? void 0 : args.committedSeq
205
- );
206
- if (!historyEvents) {
207
- return void 0;
208
- }
209
- return projectConversationEvents(historyEvents);
210
- }
211
- async function loadConnectedMcpProviders(args) {
212
- const events = await getConversationEventStore().loadCurrentHistory(
213
- args.conversationId
214
- );
215
- return connectedMcpProvidersFromEvents(events);
216
- }
217
- function messageTimestamp(message) {
218
- const timestamp = message.timestamp;
219
- return typeof timestamp === "number" ? timestamp : Date.now();
220
- }
221
- async function commitMessages(args) {
222
- const executor = args.executor ?? getSqlExecutor();
223
- return await withConversationEventLock(
224
- executor,
225
- args.conversationId,
226
- async () => executor.transaction(
227
- async () => await commitMessagesLocked(args, executor)
228
- )
229
- );
230
- }
231
- async function commitMessagesLocked(args, executor) {
232
- const eventStore = createSqlConversationEventStore(executor);
233
- const currentEvents = await eventStore.loadCurrentHistory(
234
- args.conversationId
235
- );
236
- const current = projectConversationEvents(currentEvents);
237
- const nextLocalMessages = stripRuntimeTurnContext(args.messages).map(
238
- normalizeDurableMessage
239
- );
240
- const matchingPrefix = countMatchingPrefix(
241
- current.messages,
242
- nextLocalMessages
243
- );
244
- const nextLocalProvenance = resolveCommitProvenance({
245
- existing: current,
246
- nextMessages: nextLocalMessages,
247
- matchingPrefix,
248
- ...args.provenance ? { explicitProvenance: args.provenance } : {},
249
- ...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {},
250
- ...args.newMessageProvenance ? { newMessageProvenance: args.newMessageProvenance } : {}
251
- });
252
- if (matchingPrefix === current.messages.length) {
253
- const newMessages = nextLocalMessages.slice(matchingPrefix);
254
- await eventStore.append(
255
- args.conversationId,
256
- newMessages.map((message, index) => ({
257
- data: {
258
- type: "agent_step",
259
- message,
260
- provenance: nextLocalProvenance[matchingPrefix + index]
261
- },
262
- createdAtMs: messageTimestamp(message)
263
- }))
264
- );
265
- } else {
266
- throw new Error(
267
- `Agent history for ${args.conversationId} changed before its committed boundary`
268
- );
269
- }
270
- const committedEvents = await eventStore.loadCurrentHistory(
271
- args.conversationId
272
- );
273
- const committed = projectConversationEvents(committedEvents);
274
- return {
275
- committedSeq: committedEvents.at(-1)?.seq ?? -1,
276
- historyVersion: committedEvents.at(-1)?.historyVersion ?? 0,
277
- messageSeqs: committed.seqs,
278
- messages: nextLocalMessages,
279
- provenance: nextLocalProvenance
280
- };
281
- }
282
- async function recordMcpProviderConnected(args) {
283
- const eventStore = getConversationEventStore();
284
- const events = await eventStore.loadCurrentHistory(args.conversationId);
285
- if (connectedMcpProvidersFromEvents(events).includes(args.provider)) {
286
- return;
287
- }
288
- await eventStore.append(args.conversationId, [
289
- {
290
- data: { type: "mcp_provider_connected", provider: args.provider },
291
- createdAtMs: Date.now()
292
- }
293
- ]);
294
- }
295
- async function recordAuthorizationRequested(args) {
296
- const eventStore = getConversationEventStore();
297
- const events = await eventStore.loadCurrentHistory(args.conversationId);
298
- if (events.some(
299
- (event) => event.data.type === "authorization_requested" && event.data.authorizationId === args.authorizationId
300
- )) {
301
- return;
302
- }
303
- await eventStore.append(args.conversationId, [
304
- {
305
- data: {
306
- type: "authorization_requested",
307
- kind: args.kind,
308
- provider: args.provider,
309
- actorId: args.actorId,
310
- authorizationId: args.authorizationId,
311
- delivery: args.delivery
312
- },
313
- createdAtMs: Date.now()
314
- }
315
- ]);
316
- }
317
- async function recordAuthorizationCompleted(args) {
318
- const eventStore = getConversationEventStore();
319
- const events = await eventStore.loadCurrentHistory(args.conversationId);
320
- if (events.some(
321
- (event) => event.data.type === "authorization_completed" && event.data.authorizationId === args.authorizationId
322
- )) {
323
- return;
324
- }
325
- await eventStore.append(args.conversationId, [
326
- {
327
- data: {
328
- type: "authorization_completed",
329
- kind: args.kind,
330
- provider: args.provider,
331
- actorId: args.actorId,
332
- authorizationId: args.authorizationId
333
- },
334
- createdAtMs: Date.now()
335
- }
336
- ]);
337
- }
338
- async function recordToolExecutionStarted(args) {
339
- await getConversationEventStore().append(args.conversationId, [
340
- {
341
- data: {
342
- type: "tool_execution_started",
343
- toolCallId: args.toolCallId,
344
- toolName: args.toolName
345
- },
346
- createdAtMs: args.createdAtMs ?? Date.now()
347
- }
348
- ]);
349
- }
350
-
351
- // src/chat/state/conversation.ts
352
- function defaultConversationState() {
353
- const nowMs = Date.now();
354
- return {
355
- schemaVersion: 1,
356
- messages: [],
357
- compactions: [],
358
- backfill: {},
359
- processing: {},
360
- stats: {
361
- estimatedContextTokens: 0,
362
- totalMessageCount: 0,
363
- compactedMessageCount: 0,
364
- updatedAtMs: nowMs
365
- },
366
- vision: {
367
- byFileId: {}
368
- }
369
- };
370
- }
371
- function coercePendingAuthState(value) {
372
- if (!isRecord(value)) {
373
- return void 0;
374
- }
375
- const kind = value.kind;
376
- const provider = toOptionalString(value.provider);
377
- const actorId = toOptionalString(value.actorId);
378
- const authSessionId = toOptionalString(value.authSessionId);
379
- const scope = toOptionalString(value.scope);
380
- const sessionId = toOptionalString(value.sessionId);
381
- const linkSentAtMs = toOptionalNumber(value.linkSentAtMs);
382
- if (kind !== "mcp" && kind !== "plugin" || !provider || !actorId || kind === "mcp" && !authSessionId || !sessionId || typeof linkSentAtMs !== "number") {
383
- return void 0;
384
- }
385
- const base = {
386
- provider,
387
- actorId,
388
- ...scope ? { scope } : {},
389
- sessionId,
390
- linkSentAtMs
391
- };
392
- return kind === "mcp" ? { ...base, authSessionId, kind } : { ...base, kind };
393
- }
394
- function coerceThreadConversationState(value) {
395
- if (!isRecord(value)) {
396
- return defaultConversationState();
397
- }
398
- const root = value;
399
- const rawConversation = isRecord(root.conversation) ? root.conversation : {};
400
- const base = defaultConversationState();
401
- const messages = [];
402
- const compactions = [];
403
- const rawBackfill = isRecord(rawConversation.backfill) ? rawConversation.backfill : {};
404
- const backfill = {
405
- completedAtMs: toOptionalNumber(rawBackfill.completedAtMs),
406
- source: rawBackfill.source === "recent_messages" || rawBackfill.source === "thread_fetch" ? rawBackfill.source : void 0
407
- };
408
- const rawProcessing = isRecord(rawConversation.processing) ? rawConversation.processing : {};
409
- const processing = {
410
- activeTurnId: toOptionalString(rawProcessing.activeTurnId),
411
- lastCompletedAtMs: toOptionalNumber(rawProcessing.lastCompletedAtMs),
412
- pendingAuth: coercePendingAuthState(rawProcessing.pendingAuth)
413
- };
414
- const rawStats = isRecord(rawConversation.stats) ? rawConversation.stats : {};
415
- const stats = {
416
- estimatedContextTokens: toOptionalNumber(rawStats.estimatedContextTokens) ?? base.stats.estimatedContextTokens,
417
- totalMessageCount: toOptionalNumber(rawStats.totalMessageCount) ?? messages.length,
418
- compactedMessageCount: toOptionalNumber(rawStats.compactedMessageCount) ?? 0,
419
- updatedAtMs: toOptionalNumber(rawStats.updatedAtMs) ?? base.stats.updatedAtMs
420
- };
421
- const rawVision = isRecord(rawConversation.vision) ? rawConversation.vision : {};
422
- const rawVisionByFileId = isRecord(rawVision.byFileId) ? rawVision.byFileId : {};
423
- const byFileId = {};
424
- for (const [fileId, value2] of Object.entries(rawVisionByFileId)) {
425
- if (typeof fileId !== "string" || fileId.trim().length === 0) continue;
426
- if (!isRecord(value2)) continue;
427
- const summary = toOptionalString(value2.summary);
428
- const analyzedAtMs = toOptionalNumber(value2.analyzedAtMs);
429
- if (!summary || !analyzedAtMs) continue;
430
- byFileId[fileId] = {
431
- summary,
432
- analyzedAtMs
433
- };
434
- }
435
- return {
436
- schemaVersion: 1,
437
- messages,
438
- compactions,
439
- backfill,
440
- processing,
441
- stats,
442
- vision: {
443
- backfillCompletedAtMs: toOptionalNumber(rawVision.backfillCompletedAtMs),
444
- byFileId
445
- }
446
- };
447
- }
448
- function buildConversationStatePatch(conversation) {
449
- const {
450
- compactions: _compactions,
451
- messages: _messages,
452
- ...scratch
453
- } = conversation;
454
- return {
455
- conversation: {
456
- ...scratch,
457
- schemaVersion: 1,
458
- stats: {
459
- ...conversation.stats,
460
- totalMessageCount: conversation.messages.length,
461
- updatedAtMs: Date.now()
462
- }
463
- }
464
- };
465
- }
466
-
467
- // src/chat/state/turn-session.ts
468
- import { THREAD_STATE_TTL_MS } from "chat";
469
- import {
470
- actorSchema,
471
- destinationSchema,
472
- sourceSchema
473
- } from "@sentry/junior-plugin-api";
474
- import { z as z2 } from "zod";
475
-
476
- // src/chat/state/turn-session-keys.ts
477
- var AGENT_TURN_SESSION_PREFIX = "junior:agent_turn_session";
478
- function agentTurnSessionKey(conversationId, sessionId) {
479
- return `${AGENT_TURN_SESSION_PREFIX}:${conversationId}:${sessionId}`;
480
- }
481
- function agentTurnSessionConversationIndexKey(conversationId) {
482
- return `${AGENT_TURN_SESSION_PREFIX}:conversation:${conversationId}:index`;
483
- }
484
-
485
- // src/chat/state/turn-session.ts
486
- var AGENT_TURN_SESSION_INDEX_KEY = `${AGENT_TURN_SESSION_PREFIX}:index`;
487
- var AGENT_TURN_SESSION_INDEX_MAX_LENGTH = 5e3;
488
- var AGENT_TURN_SESSION_INDEX_READ_CONCURRENCY = 25;
489
- var AGENT_TURN_SESSION_TTL_MS = THREAD_STATE_TTL_MS;
490
- var agentTurnSessionStatusSchema = z2.enum([
491
- "running",
492
- "awaiting_resume",
493
- "completed",
494
- "failed",
495
- "abandoned"
496
- ]);
497
- var agentTurnSurfaceSchema = z2.enum([
498
- "slack",
499
- "api",
500
- "scheduler",
501
- "internal"
502
- ]);
503
- var agentTurnResumeReasonSchema = z2.enum([
504
- "timeout",
505
- "auth",
506
- "yield",
507
- "retry"
508
- ]);
509
- var nonNegativeNumberSchema = z2.number().finite().nonnegative();
510
- var seqCursorSchema = z2.number().int().min(-1);
511
- var agentTurnSessionSummarySchema = z2.object({
512
- channelName: z2.string().min(1).optional(),
513
- version: z2.number().int().nonnegative(),
514
- conversationId: z2.string().min(1),
515
- cumulativeDurationMs: nonNegativeNumberSchema,
516
- cumulativeUsage: agentTurnUsageSchema.optional(),
517
- destination: destinationSchema.optional(),
518
- source: sourceSchema.optional(),
519
- lastProgressAtMs: nonNegativeNumberSchema,
520
- loadedSkillNames: z2.array(z2.string()).optional(),
521
- modelId: z2.string().min(1).optional(),
522
- reasoningLevel: z2.string().min(1).optional(),
523
- actor: actorSchema.optional(),
524
- resumeReason: agentTurnResumeReasonSchema.optional(),
525
- resumedFromSliceId: z2.number().int().nonnegative().optional(),
526
- sessionId: z2.string().min(1),
527
- sliceId: z2.number().int().nonnegative(),
528
- startedAtMs: nonNegativeNumberSchema,
529
- state: agentTurnSessionStatusSchema,
530
- surface: agentTurnSurfaceSchema.optional(),
531
- traceId: z2.string().optional(),
532
- updatedAtMs: nonNegativeNumberSchema
533
- }).strict();
534
- var storedAgentTurnSessionRecordSchema = agentTurnSessionSummarySchema.extend({
535
- actors: z2.array(actorSchema).optional(),
536
- committedSeq: seqCursorSchema,
537
- historyVersion: z2.number().int().nonnegative().optional(),
538
- errorMessage: z2.string().optional(),
539
- turnStartSeq: seqCursorSchema.optional(),
540
- runtimeContext: z2.array(piMessageSchema).optional()
541
- }).strict();
542
- function conversationExecutionFromSummary(summary) {
543
- const status = summary.state === "completed" || summary.state === "abandoned" ? "idle" : summary.state;
544
- return {
545
- status,
546
- runId: summary.sessionId,
547
- updatedAtMs: summary.updatedAtMs
548
- };
549
- }
550
- function sessionLogActor(actor) {
551
- return actor?.platform === "slack" ? toStoredSlackActor(actor) : void 0;
552
- }
553
- function parseAgentTurnSessionRecord(value) {
554
- return storedAgentTurnSessionRecordSchema.parse(value);
555
- }
556
- function parseAgentTurnSessionSummary(value) {
557
- return agentTurnSessionSummarySchema.parse(value);
558
- }
559
- async function appendAgentTurnSessionSummary(summary, ttlMs) {
560
- const stateAdapter = getStateAdapter();
561
- await Promise.all([
562
- stateAdapter.appendToList(AGENT_TURN_SESSION_INDEX_KEY, summary, {
563
- maxLength: AGENT_TURN_SESSION_INDEX_MAX_LENGTH,
564
- ttlMs
565
- }),
566
- stateAdapter.appendToList(
567
- agentTurnSessionConversationIndexKey(summary.conversationId),
568
- summary,
569
- { ttlMs }
570
- )
571
- ]);
572
- }
573
- async function recordConversationActivityMetadata(args) {
574
- const conversationStore = args.conversationStore ?? getConversationStore();
575
- const source = args.summary.destination?.platform === "local" ? "local" : args.summary.surface;
576
- await conversationStore.recordActivity({
577
- activityAtMs: args.summary.updatedAtMs,
578
- channelName: args.summary.channelName,
579
- conversationId: args.summary.conversationId,
580
- destination: args.summary.destination,
581
- nowMs: args.nowMs,
582
- actor: sessionLogActor(args.summary.actor),
583
- source,
584
- visibility: args.destinationVisibility
585
- });
586
- await conversationStore.recordExecution({
587
- channelName: args.summary.channelName,
588
- conversationId: args.summary.conversationId,
589
- createdAtMs: args.summary.startedAtMs,
590
- destination: args.summary.destination,
591
- execution: conversationExecutionFromSummary(args.summary),
592
- lastActivityAtMs: args.summary.updatedAtMs,
593
- metrics: {
594
- durationMs: args.summary.cumulativeDurationMs,
595
- ...args.summary.cumulativeUsage ? { usage: args.summary.cumulativeUsage } : {}
596
- },
597
- actor: sessionLogActor(args.summary.actor),
598
- source,
599
- updatedAtMs: args.nowMs,
600
- visibility: args.destinationVisibility
601
- });
602
- }
603
- function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessageIndex, restoreVolatileContext = true) {
604
- const piMessages = restoreVolatileContext && (stored.state === "running" || stored.state === "awaiting_resume") ? restoreRuntimeContext(piProjection.messages, stored.runtimeContext) : piProjection.messages;
605
- return {
606
- version: stored.version,
607
- ...stored.channelName ? { channelName: stored.channelName } : {},
608
- conversationId: stored.conversationId,
609
- sessionId: stored.sessionId,
610
- sliceId: stored.sliceId,
611
- state: stored.state,
612
- startedAtMs: stored.startedAtMs,
613
- lastProgressAtMs: stored.lastProgressAtMs,
614
- updatedAtMs: stored.updatedAtMs,
615
- piMessages,
616
- piMessageProvenance: piProjection.provenance,
617
- actors: stored.actors ?? instructionActors(piProjection.provenance),
618
- cumulativeDurationMs: stored.cumulativeDurationMs,
619
- ...stored.destination ? { destination: stored.destination } : {},
620
- ...stored.source ? { source: stored.source } : {},
621
- ...stored.cumulativeUsage ? { cumulativeUsage: stored.cumulativeUsage } : {},
622
- ...stored.resumeReason ? { resumeReason: stored.resumeReason } : {},
623
- ...stored.errorMessage ? { errorMessage: stored.errorMessage } : {},
624
- ...stored.loadedSkillNames ? { loadedSkillNames: stored.loadedSkillNames } : {},
625
- ...stored.modelId ? { modelId: stored.modelId } : {},
626
- ...stored.reasoningLevel ? { reasoningLevel: stored.reasoningLevel } : {},
627
- ...stored.actor ? { actor: stored.actor } : {},
628
- ...stored.resumedFromSliceId !== void 0 ? { resumedFromSliceId: stored.resumedFromSliceId } : {},
629
- ...stored.surface ? { surface: stored.surface } : {},
630
- ...stored.traceId ? { traceId: stored.traceId } : {},
631
- ...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {}
632
- };
633
- }
634
- function restoreRuntimeContext(messages, runtimeContext) {
635
- if (!runtimeContext || runtimeContext.length === 0) return messages;
636
- const restored = [...messages];
637
- for (const runtimeMessage of runtimeContext) {
638
- const runtime = runtimeMessage;
639
- const targetIndex = restored.findIndex((message) => {
640
- const candidate = message;
641
- return candidate.role === "user" && candidate.timestamp === runtime.timestamp;
642
- });
643
- if (targetIndex < 0) {
644
- restored.push(runtimeMessage);
645
- continue;
646
- }
647
- const target = restored[targetIndex];
648
- restored[targetIndex] = {
649
- ...restored[targetIndex],
650
- content: [
651
- ...Array.isArray(runtime.content) ? runtime.content : [],
652
- ...Array.isArray(target.content) ? target.content : []
653
- ]
654
- };
655
- }
656
- return restored;
657
- }
658
- async function getStoredAgentTurnSessionRecord(conversationId, sessionId) {
659
- const stateAdapter = getStateAdapter();
660
- await stateAdapter.connect();
661
- const value = await stateAdapter.get(
662
- agentTurnSessionKey(conversationId, sessionId)
663
- );
664
- return value == null ? void 0 : parseAgentTurnSessionRecord(value);
665
- }
666
- async function materializeStoredAgentTurnSessionRecord(conversationId, sessionId, followCurrentReplacement) {
667
- const parsed = await getStoredAgentTurnSessionRecord(
668
- conversationId,
669
- sessionId
670
- );
671
- if (!parsed) {
672
- return void 0;
673
- }
674
- const pinnedProjection = await loadTurnProjection({
675
- conversationId,
676
- committedSeq: parsed.committedSeq,
677
- // Unfinished records include the current-epoch tail so parked input
678
- // appended after the last safe boundary stays model-visible on resume.
679
- includeTail: parsed.state === "running" || parsed.state === "awaiting_resume"
680
- });
681
- if (!pinnedProjection) {
682
- return void 0;
683
- }
684
- const currentHistory = await getConversationEventStore().loadCurrentHistory(conversationId);
685
- const currentHistoryVersion = currentHistory.at(-1)?.historyVersion ?? parsed.historyVersion ?? 0;
686
- const followsReplacement = followCurrentReplacement && (parsed.state === "running" || parsed.state === "awaiting_resume") && parsed.historyVersion !== void 0 && parsed.historyVersion !== currentHistoryVersion;
687
- const piProjection = followsReplacement ? projectConversationEvents(currentHistory) : pinnedProjection;
688
- const turnStartMessageIndex = followsReplacement ? 0 : parsed.turnStartSeq === void 0 ? void 0 : piProjection.seqs.filter((seq) => seq <= parsed.turnStartSeq).length;
689
- return materializeAgentTurnSessionRecord(
690
- parsed,
691
- piProjection,
692
- turnStartMessageIndex,
693
- !followsReplacement && (parsed.historyVersion === void 0 || parsed.historyVersion === currentHistoryVersion)
694
- );
695
- }
696
- async function getAgentTurnSessionRecord(conversationId, sessionId) {
697
- return await materializeStoredAgentTurnSessionRecord(
698
- conversationId,
699
- sessionId,
700
- false
701
- );
702
- }
703
- async function getAgentTurnSessionRecordForResume(conversationId, sessionId) {
704
- return await materializeStoredAgentTurnSessionRecord(
705
- conversationId,
706
- sessionId,
707
- true
708
- );
709
- }
710
- function buildStoredRecord(args) {
711
- const nowMs = Date.now();
712
- return {
713
- version: (args.previousVersion ?? 0) + 1,
714
- ...args.channelName ? { channelName: args.channelName } : {},
715
- conversationId: args.conversationId,
716
- sessionId: args.sessionId,
717
- sliceId: args.sliceId,
718
- state: args.state,
719
- startedAtMs: args.startedAtMs ?? nowMs,
720
- lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
721
- updatedAtMs: nowMs,
722
- committedSeq: args.committedSeq,
723
- ...args.historyVersion !== void 0 ? { historyVersion: args.historyVersion } : {},
724
- ...args.turnStartSeq !== void 0 ? { turnStartSeq: args.turnStartSeq } : {},
725
- ...args.runtimeContext && args.runtimeContext.length > 0 ? { runtimeContext: args.runtimeContext } : {},
726
- cumulativeDurationMs: args.cumulativeDurationMs,
727
- ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
728
- ...args.destination ? { destination: args.destination } : {},
729
- ...args.source ? { source: args.source } : {},
730
- ...args.actor ? { actor: args.actor } : {},
731
- ...args.actors ? { actors: args.actors } : {},
732
- ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
733
- ...args.modelId ? { modelId: args.modelId } : {},
734
- ...args.reasoningLevel ? { reasoningLevel: args.reasoningLevel } : {},
735
- ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
736
- ...args.errorMessage ? { errorMessage: args.errorMessage } : {},
737
- ...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
738
- ...args.surface ? { surface: args.surface } : {},
739
- ...args.traceId ? { traceId: args.traceId } : {}
740
- };
741
- }
742
- async function setStoredRecord(args) {
743
- const stateAdapter = getStateAdapter();
744
- await stateAdapter.connect();
745
- await recordConversationActivityMetadata({
746
- conversationStore: args.conversationStore,
747
- destinationVisibility: args.destinationVisibility,
748
- nowMs: Date.now(),
749
- summary: args.record
750
- });
751
- await stateAdapter.set(
752
- agentTurnSessionKey(args.record.conversationId, args.record.sessionId),
753
- args.record,
754
- args.ttlMs
755
- );
756
- const {
757
- actors: _actors,
758
- committedSeq: _committedSeq,
759
- historyVersion: _historyVersion,
760
- errorMessage: _errorMessage,
761
- turnStartSeq: _turnStartSeq,
762
- runtimeContext: _runtimeContext,
763
- ...summary
764
- } = args.record;
765
- await appendAgentTurnSessionSummary(summary, args.ttlMs);
766
- return materializeAgentTurnSessionRecord(
767
- args.record,
768
- {
769
- messages: [...args.piMessages],
770
- provenance: [...args.piMessageProvenance]
771
- },
772
- args.turnStartMessageIndex
773
- );
774
- }
775
- async function updateAgentTurnSessionState(args) {
776
- const parsed = await getStoredAgentTurnSessionRecord(
777
- args.existing.conversationId,
778
- args.existing.sessionId
779
- );
780
- if (!parsed || parsed.version !== args.existing.version) {
781
- return void 0;
782
- }
783
- return await setStoredRecord({
784
- piMessages: args.existing.piMessages,
785
- piMessageProvenance: args.existing.piMessageProvenance,
786
- ttlMs: AGENT_TURN_SESSION_TTL_MS,
787
- ...args.existing.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: args.existing.turnStartMessageIndex } : {},
788
- record: buildStoredRecord({
789
- conversationId: args.existing.conversationId,
790
- sessionId: args.existing.sessionId,
791
- sliceId: args.existing.sliceId,
792
- state: args.state,
793
- committedSeq: parsed.committedSeq,
794
- ...parsed.historyVersion !== void 0 ? { historyVersion: parsed.historyVersion } : {},
795
- ...parsed.turnStartSeq !== void 0 ? { turnStartSeq: parsed.turnStartSeq } : {},
796
- ...parsed.runtimeContext ? { runtimeContext: parsed.runtimeContext } : {},
797
- ...parsed.channelName ? { channelName: parsed.channelName } : {},
798
- startedAtMs: parsed.startedAtMs,
799
- lastProgressAtMs: parsed.lastProgressAtMs,
800
- previousVersion: parsed.version,
801
- cumulativeDurationMs: args.existing.cumulativeDurationMs,
802
- ...args.existing.cumulativeUsage ? { cumulativeUsage: args.existing.cumulativeUsage } : {},
803
- ...args.existing.destination ? { destination: args.existing.destination } : {},
804
- ...args.existing.source ? { source: args.existing.source } : {},
805
- ...args.existing.loadedSkillNames ? { loadedSkillNames: args.existing.loadedSkillNames } : {},
806
- ...args.existing.modelId ? { modelId: args.existing.modelId } : {},
807
- ...args.existing.reasoningLevel ? { reasoningLevel: args.existing.reasoningLevel } : {},
808
- ...args.existing.actor ? { actor: args.existing.actor } : {},
809
- actors: args.existing.actors,
810
- ...args.existing.resumeReason ? { resumeReason: args.existing.resumeReason } : {},
811
- ...args.existing.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.existing.resumedFromSliceId } : {},
812
- ...args.existing.surface ? { surface: args.existing.surface } : {},
813
- ...args.existing.traceId ? { traceId: args.existing.traceId } : {},
814
- ...args.errorMessage ?? args.existing.errorMessage ? { errorMessage: args.errorMessage ?? args.existing.errorMessage } : {}
815
- })
816
- });
817
- }
818
- async function upsertAgentTurnSessionRecord(args) {
819
- const existingRecord = await getStoredAgentTurnSessionRecord(
820
- args.conversationId,
821
- args.sessionId
822
- );
823
- const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
824
- const instructionActor = args.actor ?? existingRecord?.actor;
825
- const commit = await commitMessages({
826
- conversationId: args.conversationId,
827
- messages: args.piMessages,
828
- ...instructionActor ? { newMessageProvenance: instructionProvenanceFor(instructionActor) } : {},
829
- ...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {}
830
- });
831
- const durableTurnStartMessageIndex = args.turnStartMessageIndex === void 0 ? void 0 : stripRuntimeTurnContext(
832
- args.piMessages.slice(0, args.turnStartMessageIndex)
833
- ).length;
834
- const runtimeContext = retainRuntimeTurnContext(args.piMessages);
835
- const retainedRuntimeContext = runtimeContext.length > 0 ? runtimeContext : existingRecord?.historyVersion === commit.historyVersion ? existingRecord.runtimeContext : void 0;
836
- const turnStartSeq = durableTurnStartMessageIndex === void 0 ? existingRecord?.turnStartSeq : durableTurnStartMessageIndex <= 0 ? -1 : commit.messageSeqs[durableTurnStartMessageIndex - 1] ?? commit.committedSeq;
837
- const turnStartMessageIndex = durableTurnStartMessageIndex ?? (turnStartSeq === void 0 ? void 0 : commit.messageSeqs.filter((seq) => seq <= turnStartSeq).length);
838
- return await setStoredRecord({
839
- conversationStore: args.conversationStore,
840
- destinationVisibility: args.destinationVisibility,
841
- piMessages: commit.messages,
842
- piMessageProvenance: commit.provenance,
843
- ttlMs,
844
- ...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {},
845
- record: buildStoredRecord({
846
- ...args.channelName ?? existingRecord?.channelName ? { channelName: args.channelName ?? existingRecord?.channelName } : {},
847
- conversationId: args.conversationId,
848
- sessionId: args.sessionId,
849
- sliceId: args.sliceId,
850
- state: args.state,
851
- ...existingRecord?.startedAtMs !== void 0 ? { startedAtMs: existingRecord.startedAtMs } : {},
852
- ...args.lastProgressAtMs !== void 0 ? { lastProgressAtMs: args.lastProgressAtMs } : {},
853
- committedSeq: commit.committedSeq,
854
- historyVersion: commit.historyVersion,
855
- ...turnStartSeq !== void 0 ? { turnStartSeq } : {},
856
- ...retainedRuntimeContext ? { runtimeContext: retainedRuntimeContext } : {},
857
- previousVersion: existingRecord?.version,
858
- cumulativeDurationMs: args.cumulativeDurationMs ?? existingRecord?.cumulativeDurationMs ?? 0,
859
- ...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
860
- ...args.destination ?? existingRecord?.destination ? { destination: args.destination ?? existingRecord?.destination } : {},
861
- ...args.source ?? existingRecord?.source ? { source: args.source ?? existingRecord?.source } : {},
862
- ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
863
- modelId: args.modelId,
864
- ...args.reasoningLevel ?? existingRecord?.reasoningLevel ? {
865
- reasoningLevel: args.reasoningLevel ?? existingRecord?.reasoningLevel
866
- } : {},
867
- ...args.actor ?? existingRecord?.actor ? { actor: args.actor ?? existingRecord?.actor } : {},
868
- actors: instructionActors([
869
- ...(existingRecord?.actors ?? []).map(instructionProvenanceFor),
870
- ...(args.actors ?? []).map(instructionProvenanceFor),
871
- ...commit.provenance
872
- ]),
873
- ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
874
- ...args.errorMessage ? { errorMessage: args.errorMessage } : {},
875
- ...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
876
- ...args.surface ?? existingRecord?.surface ? { surface: args.surface ?? existingRecord?.surface } : {},
877
- ...args.traceId ?? existingRecord?.traceId ? { traceId: args.traceId ?? existingRecord?.traceId } : {}
878
- })
879
- });
880
- }
881
- async function recordAgentTurnSessionSummary(args) {
882
- const existing = await getStoredAgentTurnSessionRecord(
883
- args.conversationId,
884
- args.sessionId
885
- );
886
- const nowMs = Date.now();
887
- const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
888
- const summary = {
889
- version: existing?.version ?? 0,
890
- ...args.channelName ?? existing?.channelName ? { channelName: args.channelName ?? existing?.channelName } : {},
891
- conversationId: args.conversationId,
892
- sessionId: args.sessionId,
893
- sliceId: args.sliceId,
894
- startedAtMs: existing?.startedAtMs ?? args.startedAtMs ?? nowMs,
895
- lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
896
- state: args.state,
897
- updatedAtMs: nowMs,
898
- cumulativeDurationMs: args.cumulativeDurationMs ?? existing?.cumulativeDurationMs ?? 0,
899
- ...args.cumulativeUsage ?? existing?.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage ?? existing?.cumulativeUsage } : {},
900
- ...args.destination ?? existing?.destination ? { destination: args.destination ?? existing?.destination } : {},
901
- ...args.source ?? existing?.source ? { source: args.source ?? existing?.source } : {},
902
- ...args.actor ?? existing?.actor ? { actor: args.actor ?? existing?.actor } : {},
903
- ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : existing?.loadedSkillNames ? { loadedSkillNames: existing.loadedSkillNames } : {},
904
- ...args.modelId ?? existing?.modelId ? { modelId: args.modelId ?? existing?.modelId } : {},
905
- ...args.reasoningLevel ?? existing?.reasoningLevel ? { reasoningLevel: args.reasoningLevel ?? existing?.reasoningLevel } : {},
906
- ...args.resumeReason ? { resumeReason: args.resumeReason } : {},
907
- ...args.surface ?? existing?.surface ? { surface: args.surface ?? existing?.surface } : {},
908
- ...args.traceId ?? existing?.traceId ? { traceId: args.traceId ?? existing?.traceId } : {}
909
- };
910
- await recordConversationActivityMetadata({
911
- conversationStore: args.conversationStore,
912
- destinationVisibility: args.destinationVisibility,
913
- nowMs,
914
- summary
915
- });
916
- await appendAgentTurnSessionSummary(summary, ttlMs);
917
- }
918
- async function readAgentTurnSessionSummariesFromIndex(key, stateAdapter) {
919
- await stateAdapter.connect();
920
- const values = await stateAdapter.getList(key);
921
- const summaries = /* @__PURE__ */ new Map();
922
- for (const value of [...values].reverse()) {
923
- let summary;
924
- try {
925
- summary = parseAgentTurnSessionSummary(value);
926
- } catch (error) {
927
- logWarn(
928
- "agent_turn_session_summary_parse_failed",
929
- {},
930
- {
931
- "app.state.key": key,
932
- "exception.message": error instanceof Error ? error.message : String(error)
933
- },
934
- "Skipping an invalid turn-session summary index entry"
935
- );
936
- continue;
937
- }
938
- const summaryKey = `${summary.conversationId}:${summary.sessionId}`;
939
- if (!summaries.has(summaryKey)) {
940
- summaries.set(summaryKey, summary);
941
- }
942
- }
943
- return [...summaries.values()].sort(
944
- (left, right) => right.updatedAtMs - left.updatedAtMs
945
- );
946
- }
947
- async function listAgentTurnSessionSummariesForConversation(conversationId) {
948
- const stateAdapter = getStateAdapter();
949
- const summaries = await listBoundedAgentTurnSessionSummariesForConversation(conversationId);
950
- if (summaries.length > 0) {
951
- return summaries;
952
- }
953
- return (await readAgentTurnSessionSummariesFromIndex(
954
- AGENT_TURN_SESSION_INDEX_KEY,
955
- stateAdapter
956
- )).filter((summary) => summary.conversationId === conversationId);
957
- }
958
- async function listBoundedAgentTurnSessionSummariesForConversation(conversationId) {
959
- return readAgentTurnSessionSummariesFromIndex(
960
- agentTurnSessionConversationIndexKey(conversationId),
961
- getStateAdapter()
962
- );
963
- }
964
- async function listAgentTurnSessionSummariesForConversations(stateAdapter, conversationIds) {
965
- const ids = [...new Set(conversationIds)];
966
- const globalSummaries = await readAgentTurnSessionSummariesFromIndex(
967
- AGENT_TURN_SESSION_INDEX_KEY,
968
- stateAdapter
969
- );
970
- const globalByConversation = /* @__PURE__ */ new Map();
971
- for (const summary of globalSummaries) {
972
- globalByConversation.set(summary.conversationId, [
973
- ...globalByConversation.get(summary.conversationId) ?? [],
974
- summary
975
- ]);
976
- }
977
- const summariesByConversation = /* @__PURE__ */ new Map();
978
- let nextIndex = 0;
979
- const readNext = async () => {
980
- while (nextIndex < ids.length) {
981
- const conversationId = ids[nextIndex];
982
- nextIndex += 1;
983
- if (!conversationId) continue;
984
- const summaries = await readAgentTurnSessionSummariesFromIndex(
985
- agentTurnSessionConversationIndexKey(conversationId),
986
- stateAdapter
987
- );
988
- summariesByConversation.set(
989
- conversationId,
990
- summaries.length > 0 ? summaries : globalByConversation.get(conversationId) ?? []
991
- );
992
- }
993
- };
994
- await Promise.all(
995
- Array.from(
996
- {
997
- length: Math.min(AGENT_TURN_SESSION_INDEX_READ_CONCURRENCY, ids.length)
998
- },
999
- readNext
1000
- )
1001
- );
1002
- return summariesByConversation;
1003
- }
1004
- async function abandonAgentTurnSessionRecord(args) {
1005
- const existing = await getAgentTurnSessionRecord(
1006
- args.conversationId,
1007
- args.sessionId
1008
- );
1009
- if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned") {
1010
- return void 0;
1011
- }
1012
- return await updateAgentTurnSessionState({
1013
- existing,
1014
- state: "abandoned",
1015
- errorMessage: args.errorMessage ?? existing.errorMessage
1016
- });
1017
- }
1018
- async function failAgentTurnSessionRecord(args) {
1019
- const existing = await getAgentTurnSessionRecord(
1020
- args.conversationId,
1021
- args.sessionId
1022
- );
1023
- if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned" || existing.version !== args.expectedVersion) {
1024
- return void 0;
1025
- }
1026
- return await updateAgentTurnSessionState({
1027
- existing,
1028
- state: "failed",
1029
- errorMessage: args.errorMessage ?? existing.errorMessage
1030
- });
1031
- }
1032
-
1033
- // src/chat/state/ttl.ts
1034
- var JUNIOR_THREAD_STATE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
1035
-
1036
- export {
1037
- piMessageSchema,
1038
- loadProjection,
1039
- loadConversationProjection,
1040
- openConversationProjection,
1041
- loadConnectedMcpProviders,
1042
- commitMessages,
1043
- recordMcpProviderConnected,
1044
- recordAuthorizationRequested,
1045
- recordAuthorizationCompleted,
1046
- recordToolExecutionStarted,
1047
- AGENT_TURN_SESSION_PREFIX,
1048
- agentTurnSessionKey,
1049
- agentTurnSessionConversationIndexKey,
1050
- getAgentTurnSessionRecord,
1051
- getAgentTurnSessionRecordForResume,
1052
- upsertAgentTurnSessionRecord,
1053
- recordAgentTurnSessionSummary,
1054
- listAgentTurnSessionSummariesForConversation,
1055
- listAgentTurnSessionSummariesForConversations,
1056
- abandonAgentTurnSessionRecord,
1057
- failAgentTurnSessionRecord,
1058
- JUNIOR_THREAD_STATE_TTL_MS,
1059
- coerceThreadConversationState,
1060
- buildConversationStatePatch
1061
- };