@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.
- package/dist/{agent-hooks-NU5HK3PS.js → agent-hooks-FHHVLNPA.js} +12 -12
- package/dist/api/conversations/events.d.ts +1 -1
- package/dist/api/conversations/schema.d.ts +57 -6
- package/dist/api/schema.js +1 -1
- package/dist/api.js +108 -22
- package/dist/app.d.ts +1 -0
- package/dist/app.js +1481 -420
- package/dist/{catalog-runtime-FOFNPR3P.js → catalog-runtime-DMGJSLV2.js} +6 -4
- package/dist/chat/conversations/sql/store.d.ts +0 -7
- package/dist/chat/log-context.d.ts +40 -0
- package/dist/chat/logging.d.ts +3 -26
- package/dist/chat/runtime/slack-resume.d.ts +2 -2
- package/dist/chat/services/turn-session-record.d.ts +0 -2
- package/dist/chat/slack/reply.d.ts +7 -19
- package/dist/chat/state/conversation.d.ts +1 -0
- package/dist/chat/task-execution/slack-work.d.ts +2 -2
- package/dist/chunk-3SXUV423.js +10 -0
- package/dist/{chunk-3RGQLX2F.js → chunk-72OMGPDS.js} +1010 -26
- package/dist/{chunk-2XXEKR44.js → chunk-7Q6WCISF.js} +1 -1
- package/dist/{chunk-TE4QHJH4.js → chunk-FENLIFJD.js} +72 -591
- package/dist/{chunk-XKB7LGIW.js → chunk-FWJRXN4F.js} +3 -3
- package/dist/{chunk-PUAMO4PI.js → chunk-HHVY4SMP.js} +41 -7
- package/dist/{chunk-B5I5LMSP.js → chunk-HO5NT6OE.js} +5 -7
- package/dist/{chunk-O24R4DCK.js → chunk-ISMWX44P.js} +93 -55
- package/dist/{chunk-7FBGKXPE.js → chunk-IVVGFRQQ.js} +5 -0
- package/dist/{chunk-KPMPQ6AA.js → chunk-IXKSQGIO.js} +90 -100
- package/dist/{chunk-SS67LUOK.js → chunk-JNAVF45E.js} +6 -7
- package/dist/{chunk-DY7TRYB5.js → chunk-MGUMR35T.js} +1 -1
- package/dist/{chunk-A5CO2EHL.js → chunk-MXW4GL53.js} +11 -15
- package/dist/{chunk-RT5BUHR5.js → chunk-O3JMSZLI.js} +1 -1
- package/dist/chunk-OCD3OZRK.js +125 -0
- package/dist/{chunk-H3QYZL7K.js → chunk-OUHNWH46.js} +28 -3
- package/dist/{chunk-VIXFG2VC.js → chunk-PLB7MRCQ.js} +1 -2
- package/dist/{chunk-UD6THJ2I.js → chunk-QY636HZU.js} +114 -12
- package/dist/{chunk-VH6KWKG2.js → chunk-RGX4V75M.js} +3 -3
- package/dist/{chunk-B7PUBQQM.js → chunk-SYAQIR5Z.js} +1 -1
- package/dist/chunk-TMBRFULF.js +471 -0
- package/dist/{chunk-YIPD3L6L.js → chunk-TT6GMXNA.js} +8 -10
- package/dist/{chunk-YT72TOEK.js → chunk-WHMOBKT7.js} +2 -2
- package/dist/cli/chat.js +23 -23
- package/dist/cli/check.js +8 -6
- package/dist/cli/plugins.js +16 -16
- package/dist/cli/snapshot-warmup.js +10 -9
- package/dist/cli/upgrade.js +314 -3505
- package/dist/db/db.d.ts +1 -1
- package/dist/{db-AMRBAT5D.js → db-V3NU72O2.js} +8 -6
- package/dist/instrumentation.js +3 -2
- package/dist/nitro.js +5 -4
- package/dist/{runner-TQH5GAJ4.js → runner-JYBCQBLK.js} +17 -20
- package/dist/{skills-ITNHBARB.js → skills-U6MDAST7.js} +7 -5
- package/dist/{validation-AGQ46ZGV.js → validation-72N3JVRU.js} +7 -5
- package/dist/version.d.ts +2 -0
- package/dist/version.js +7 -0
- package/migrations/0006_drop_legacy_conversation_messages.sql +1 -0
- package/migrations/README.md +12 -9
- package/migrations/meta/0006_snapshot.json +948 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +9 -5
- package/dist/chunk-AHJR2IFF.js +0 -115
- package/dist/chunk-G3E7SCME.js +0 -28
- package/dist/chunk-J3B3FPP2.js +0 -1061
- package/dist/chunk-TWINAEZQ.js +0 -1283
package/dist/chunk-J3B3FPP2.js
DELETED
|
@@ -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
|
-
};
|