@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
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
buildConversationStatePatch,
|
|
5
|
-
getAgentTurnSessionRecord,
|
|
6
|
-
getAgentTurnSessionRecordForResume,
|
|
7
|
-
upsertAgentTurnSessionRecord
|
|
8
|
-
} from "./chunk-J3B3FPP2.js";
|
|
9
|
-
import {
|
|
10
|
-
addAgentTurnUsage
|
|
2
|
+
addAgentTurnUsage,
|
|
3
|
+
agentTurnUsageSchema
|
|
11
4
|
} from "./chunk-MU6HHZEN.js";
|
|
12
5
|
import {
|
|
13
6
|
getStateAdapter
|
|
14
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OUHNWH46.js";
|
|
15
8
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
contextProvenance,
|
|
10
|
+
createSqlConversationEventStore,
|
|
11
|
+
getConversationEventStore,
|
|
12
|
+
getConversationStore,
|
|
13
|
+
getSqlExecutor,
|
|
14
|
+
instructionActors,
|
|
15
|
+
instructionProvenanceFor,
|
|
16
|
+
sanitizePostgresJson,
|
|
17
|
+
withConversationEventLock
|
|
18
|
+
} from "./chunk-FENLIFJD.js";
|
|
18
19
|
import {
|
|
19
20
|
sleep
|
|
20
21
|
} from "./chunk-4ZNGQH7C.js";
|
|
@@ -23,22 +24,345 @@ import {
|
|
|
23
24
|
escapeXml,
|
|
24
25
|
getPiMessageRole,
|
|
25
26
|
resolveGatewayModel,
|
|
27
|
+
retainRuntimeTurnContext,
|
|
26
28
|
standardModelId,
|
|
29
|
+
stripRuntimeTurnContext,
|
|
27
30
|
trimTrailingAssistantMessages
|
|
28
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-JNAVF45E.js";
|
|
32
|
+
import {
|
|
33
|
+
toStoredSlackActor
|
|
34
|
+
} from "./chunk-PLB7MRCQ.js";
|
|
29
35
|
import {
|
|
30
36
|
getActiveTraceId,
|
|
31
37
|
logException,
|
|
32
38
|
logWarn,
|
|
33
39
|
setSpanAttributes
|
|
34
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-ISMWX44P.js";
|
|
35
41
|
import {
|
|
36
42
|
isRecord,
|
|
43
|
+
toOptionalNumber,
|
|
37
44
|
toOptionalString
|
|
38
45
|
} from "./chunk-OB42YVAE.js";
|
|
39
46
|
import {
|
|
40
47
|
parseSlackMessageTs
|
|
41
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-IVVGFRQQ.js";
|
|
49
|
+
|
|
50
|
+
// src/chat/conversations/projection.ts
|
|
51
|
+
import { isDeepStrictEqual } from "util";
|
|
52
|
+
|
|
53
|
+
// src/chat/pi/messages.ts
|
|
54
|
+
import { z } from "zod";
|
|
55
|
+
var piMessageSchema = z.object({
|
|
56
|
+
role: z.string()
|
|
57
|
+
}).passthrough().transform((value) => value);
|
|
58
|
+
var piContentMessageSchema = z.object({
|
|
59
|
+
content: z.array(z.unknown()),
|
|
60
|
+
role: z.string().min(1)
|
|
61
|
+
}).passthrough().transform((value) => value);
|
|
62
|
+
|
|
63
|
+
// src/chat/pi/conversation-events.ts
|
|
64
|
+
function authorizationObservationMessage(data, createdAtMs) {
|
|
65
|
+
const label = data.kind === "mcp" ? "MCP authorization" : "Authorization";
|
|
66
|
+
return piMessageSchema.parse({
|
|
67
|
+
role: "user",
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: `${label} completed for provider "${data.provider}". Continue the blocked request and retry the provider operation if needed.`
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
timestamp: createdAtMs
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function messageEventProvenance(data) {
|
|
78
|
+
return data.provenance ?? contextProvenance;
|
|
79
|
+
}
|
|
80
|
+
function durableMessages(message) {
|
|
81
|
+
return stripRuntimeTurnContext([piMessageSchema.parse(message)]);
|
|
82
|
+
}
|
|
83
|
+
function projectConversationEvents(events, options) {
|
|
84
|
+
const messages = [];
|
|
85
|
+
const provenance = [];
|
|
86
|
+
const seqs = [];
|
|
87
|
+
let modelProfile = "standard";
|
|
88
|
+
let modelId;
|
|
89
|
+
for (const event of events) {
|
|
90
|
+
if (options?.maxSeq !== void 0 && event.seq > options.maxSeq) break;
|
|
91
|
+
if (event.data.type === "unknown") {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Unsupported conversation event "${event.data.originalType}" at seq ${event.seq} (schema version ${event.schemaVersion})`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (event.data.type === "compaction" || event.data.type === "handoff" || event.data.type === "rollback") {
|
|
97
|
+
modelProfile = event.data.modelProfile;
|
|
98
|
+
modelId = event.data.modelId;
|
|
99
|
+
for (const replacement of event.data.replacementHistory) {
|
|
100
|
+
for (const message of durableMessages(replacement.message)) {
|
|
101
|
+
messages.push(message);
|
|
102
|
+
provenance.push(replacement.provenance ?? contextProvenance);
|
|
103
|
+
seqs.push(replacement.sourceEventSeq ?? event.seq);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (event.data.type === "agent_step") {
|
|
109
|
+
for (const message of durableMessages(event.data.message)) {
|
|
110
|
+
messages.push(message);
|
|
111
|
+
provenance.push(messageEventProvenance(event.data));
|
|
112
|
+
seqs.push(event.seq);
|
|
113
|
+
}
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (event.data.type === "authorization_completed") {
|
|
117
|
+
messages.push(
|
|
118
|
+
authorizationObservationMessage(event.data, event.createdAtMs)
|
|
119
|
+
);
|
|
120
|
+
provenance.push(contextProvenance);
|
|
121
|
+
seqs.push(event.seq);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { messages, provenance, seqs, modelProfile, modelId };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/chat/conversations/projection.ts
|
|
128
|
+
function connectedMcpProvidersFromEvents(events) {
|
|
129
|
+
const providers = /* @__PURE__ */ new Set();
|
|
130
|
+
for (const event of events) {
|
|
131
|
+
if (event.data.type === "mcp_provider_connected") {
|
|
132
|
+
providers.add(event.data.provider);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return [...providers].sort((left, right) => left.localeCompare(right));
|
|
136
|
+
}
|
|
137
|
+
function isUserMessage(message) {
|
|
138
|
+
return message.role === "user";
|
|
139
|
+
}
|
|
140
|
+
function countMatchingPrefix(left, right) {
|
|
141
|
+
const limit = Math.min(left.length, right.length);
|
|
142
|
+
for (let index = 0; index < limit; index += 1) {
|
|
143
|
+
if (!isDeepStrictEqual(left[index], right[index])) {
|
|
144
|
+
return index;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return limit;
|
|
148
|
+
}
|
|
149
|
+
function normalizeDurableMessage(message) {
|
|
150
|
+
return piMessageSchema.parse(
|
|
151
|
+
JSON.parse(JSON.stringify(sanitizePostgresJson(message)))
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
function resolveCommitProvenance(args) {
|
|
155
|
+
if (args.explicitProvenance) {
|
|
156
|
+
if (args.explicitProvenance.length !== args.nextMessages.length) {
|
|
157
|
+
throw new Error("commit provenance must align one-to-one with messages");
|
|
158
|
+
}
|
|
159
|
+
return args.explicitProvenance;
|
|
160
|
+
}
|
|
161
|
+
const matchingPrefix = args.matchingPrefix;
|
|
162
|
+
const provenance = args.nextMessages.map(
|
|
163
|
+
(_, index) => index < matchingPrefix ? args.existing.provenance[index] ?? contextProvenance : contextProvenance
|
|
164
|
+
);
|
|
165
|
+
if (args.newMessageProvenance) {
|
|
166
|
+
for (let index = args.nextMessages.length - 1; index >= matchingPrefix; index -= 1) {
|
|
167
|
+
if (isUserMessage(args.nextMessages[index])) {
|
|
168
|
+
provenance[index] = args.newMessageProvenance;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (args.trailingMessageProvenance) {
|
|
174
|
+
if (args.trailingMessageProvenance.length > provenance.length) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
"trailing commit provenance cannot exceed committed messages"
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
const newMessageCount = args.nextMessages.length - matchingPrefix;
|
|
180
|
+
if (args.trailingMessageProvenance.length > newMessageCount) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
"trailing commit provenance must align to newly committed messages"
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
const start = provenance.length - args.trailingMessageProvenance.length;
|
|
186
|
+
args.trailingMessageProvenance.forEach((entry, offset) => {
|
|
187
|
+
provenance[start + offset] = entry;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return provenance;
|
|
191
|
+
}
|
|
192
|
+
async function loadProjection(args) {
|
|
193
|
+
const events = await getConversationEventStore().loadCurrentHistory(
|
|
194
|
+
args.conversationId
|
|
195
|
+
);
|
|
196
|
+
return projectConversationEvents(events).messages;
|
|
197
|
+
}
|
|
198
|
+
async function loadConversationProjection(args) {
|
|
199
|
+
const events = await getConversationEventStore().loadCurrentHistory(
|
|
200
|
+
args.conversationId
|
|
201
|
+
);
|
|
202
|
+
return projectConversationEvents(events);
|
|
203
|
+
}
|
|
204
|
+
async function openConversationProjection(args) {
|
|
205
|
+
const events = await getConversationEventStore().loadCurrentHistory(
|
|
206
|
+
args.conversationId
|
|
207
|
+
);
|
|
208
|
+
return projectConversationEvents(events);
|
|
209
|
+
}
|
|
210
|
+
async function loadTurnProjection(args) {
|
|
211
|
+
const eventStore = getConversationEventStore();
|
|
212
|
+
if (args.committedSeq < 0) {
|
|
213
|
+
return projectConversationEvents(
|
|
214
|
+
await eventStore.loadCurrentHistory(args.conversationId)
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
const historyEvents = await eventStore.loadHistoryContaining(
|
|
218
|
+
args.conversationId,
|
|
219
|
+
args.committedSeq,
|
|
220
|
+
args.includeTail ? void 0 : args.committedSeq
|
|
221
|
+
);
|
|
222
|
+
if (!historyEvents) {
|
|
223
|
+
return void 0;
|
|
224
|
+
}
|
|
225
|
+
return projectConversationEvents(historyEvents);
|
|
226
|
+
}
|
|
227
|
+
async function loadConnectedMcpProviders(args) {
|
|
228
|
+
const events = await getConversationEventStore().loadCurrentHistory(
|
|
229
|
+
args.conversationId
|
|
230
|
+
);
|
|
231
|
+
return connectedMcpProvidersFromEvents(events);
|
|
232
|
+
}
|
|
233
|
+
function messageTimestamp(message) {
|
|
234
|
+
const timestamp = message.timestamp;
|
|
235
|
+
return typeof timestamp === "number" ? timestamp : Date.now();
|
|
236
|
+
}
|
|
237
|
+
async function commitMessages(args) {
|
|
238
|
+
const executor = args.executor ?? getSqlExecutor();
|
|
239
|
+
return await withConversationEventLock(
|
|
240
|
+
executor,
|
|
241
|
+
args.conversationId,
|
|
242
|
+
async () => executor.transaction(
|
|
243
|
+
async () => await commitMessagesLocked(args, executor)
|
|
244
|
+
)
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
async function commitMessagesLocked(args, executor) {
|
|
248
|
+
const eventStore = createSqlConversationEventStore(executor);
|
|
249
|
+
const currentEvents = await eventStore.loadCurrentHistory(
|
|
250
|
+
args.conversationId
|
|
251
|
+
);
|
|
252
|
+
const current = projectConversationEvents(currentEvents);
|
|
253
|
+
const nextLocalMessages = stripRuntimeTurnContext(args.messages).map(
|
|
254
|
+
normalizeDurableMessage
|
|
255
|
+
);
|
|
256
|
+
const matchingPrefix = countMatchingPrefix(
|
|
257
|
+
current.messages,
|
|
258
|
+
nextLocalMessages
|
|
259
|
+
);
|
|
260
|
+
const nextLocalProvenance = resolveCommitProvenance({
|
|
261
|
+
existing: current,
|
|
262
|
+
nextMessages: nextLocalMessages,
|
|
263
|
+
matchingPrefix,
|
|
264
|
+
...args.provenance ? { explicitProvenance: args.provenance } : {},
|
|
265
|
+
...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {},
|
|
266
|
+
...args.newMessageProvenance ? { newMessageProvenance: args.newMessageProvenance } : {}
|
|
267
|
+
});
|
|
268
|
+
if (matchingPrefix === current.messages.length) {
|
|
269
|
+
const newMessages = nextLocalMessages.slice(matchingPrefix);
|
|
270
|
+
await eventStore.append(
|
|
271
|
+
args.conversationId,
|
|
272
|
+
newMessages.map((message, index) => ({
|
|
273
|
+
data: {
|
|
274
|
+
type: "agent_step",
|
|
275
|
+
message,
|
|
276
|
+
provenance: nextLocalProvenance[matchingPrefix + index]
|
|
277
|
+
},
|
|
278
|
+
createdAtMs: messageTimestamp(message)
|
|
279
|
+
}))
|
|
280
|
+
);
|
|
281
|
+
} else {
|
|
282
|
+
throw new Error(
|
|
283
|
+
`Agent history for ${args.conversationId} changed before its committed boundary`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
const committedEvents = await eventStore.loadCurrentHistory(
|
|
287
|
+
args.conversationId
|
|
288
|
+
);
|
|
289
|
+
const committed = projectConversationEvents(committedEvents);
|
|
290
|
+
return {
|
|
291
|
+
committedSeq: committedEvents.at(-1)?.seq ?? -1,
|
|
292
|
+
historyVersion: committedEvents.at(-1)?.historyVersion ?? 0,
|
|
293
|
+
messageSeqs: committed.seqs,
|
|
294
|
+
messages: nextLocalMessages,
|
|
295
|
+
provenance: nextLocalProvenance
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
async function recordMcpProviderConnected(args) {
|
|
299
|
+
const eventStore = getConversationEventStore();
|
|
300
|
+
const events = await eventStore.loadCurrentHistory(args.conversationId);
|
|
301
|
+
if (connectedMcpProvidersFromEvents(events).includes(args.provider)) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
await eventStore.append(args.conversationId, [
|
|
305
|
+
{
|
|
306
|
+
data: { type: "mcp_provider_connected", provider: args.provider },
|
|
307
|
+
createdAtMs: Date.now()
|
|
308
|
+
}
|
|
309
|
+
]);
|
|
310
|
+
}
|
|
311
|
+
async function recordAuthorizationRequested(args) {
|
|
312
|
+
const eventStore = getConversationEventStore();
|
|
313
|
+
const events = await eventStore.loadCurrentHistory(args.conversationId);
|
|
314
|
+
if (events.some(
|
|
315
|
+
(event) => event.data.type === "authorization_requested" && event.data.authorizationId === args.authorizationId
|
|
316
|
+
)) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
await eventStore.append(args.conversationId, [
|
|
320
|
+
{
|
|
321
|
+
data: {
|
|
322
|
+
type: "authorization_requested",
|
|
323
|
+
kind: args.kind,
|
|
324
|
+
provider: args.provider,
|
|
325
|
+
actorId: args.actorId,
|
|
326
|
+
authorizationId: args.authorizationId,
|
|
327
|
+
delivery: args.delivery
|
|
328
|
+
},
|
|
329
|
+
createdAtMs: Date.now()
|
|
330
|
+
}
|
|
331
|
+
]);
|
|
332
|
+
}
|
|
333
|
+
async function recordAuthorizationCompleted(args) {
|
|
334
|
+
const eventStore = getConversationEventStore();
|
|
335
|
+
const events = await eventStore.loadCurrentHistory(args.conversationId);
|
|
336
|
+
if (events.some(
|
|
337
|
+
(event) => event.data.type === "authorization_completed" && event.data.authorizationId === args.authorizationId
|
|
338
|
+
)) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
await eventStore.append(args.conversationId, [
|
|
342
|
+
{
|
|
343
|
+
data: {
|
|
344
|
+
type: "authorization_completed",
|
|
345
|
+
kind: args.kind,
|
|
346
|
+
provider: args.provider,
|
|
347
|
+
actorId: args.actorId,
|
|
348
|
+
authorizationId: args.authorizationId
|
|
349
|
+
},
|
|
350
|
+
createdAtMs: Date.now()
|
|
351
|
+
}
|
|
352
|
+
]);
|
|
353
|
+
}
|
|
354
|
+
async function recordToolExecutionStarted(args) {
|
|
355
|
+
await getConversationEventStore().append(args.conversationId, [
|
|
356
|
+
{
|
|
357
|
+
data: {
|
|
358
|
+
type: "tool_execution_started",
|
|
359
|
+
toolCallId: args.toolCallId,
|
|
360
|
+
toolName: args.toolName
|
|
361
|
+
},
|
|
362
|
+
createdAtMs: args.createdAtMs ?? Date.now()
|
|
363
|
+
}
|
|
364
|
+
]);
|
|
365
|
+
}
|
|
42
366
|
|
|
43
367
|
// src/chat/state/turn-id.ts
|
|
44
368
|
function buildDeterministicTurnId(messageId) {
|
|
@@ -145,6 +469,531 @@ async function persistWithRetry(persist) {
|
|
|
145
469
|
throw lastError;
|
|
146
470
|
}
|
|
147
471
|
|
|
472
|
+
// src/chat/state/turn-session.ts
|
|
473
|
+
import { THREAD_STATE_TTL_MS } from "chat";
|
|
474
|
+
import {
|
|
475
|
+
actorSchema,
|
|
476
|
+
destinationSchema,
|
|
477
|
+
sourceSchema
|
|
478
|
+
} from "@sentry/junior-plugin-api";
|
|
479
|
+
import { z as z2 } from "zod";
|
|
480
|
+
|
|
481
|
+
// src/chat/state/turn-session-keys.ts
|
|
482
|
+
var AGENT_TURN_SESSION_PREFIX = "junior:agent_turn_session";
|
|
483
|
+
function agentTurnSessionKey(conversationId, sessionId) {
|
|
484
|
+
return `${AGENT_TURN_SESSION_PREFIX}:${conversationId}:${sessionId}`;
|
|
485
|
+
}
|
|
486
|
+
function agentTurnSessionConversationIndexKey(conversationId) {
|
|
487
|
+
return `${AGENT_TURN_SESSION_PREFIX}:conversation:${conversationId}:index`;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/chat/state/turn-session.ts
|
|
491
|
+
var AGENT_TURN_SESSION_INDEX_KEY = `${AGENT_TURN_SESSION_PREFIX}:index`;
|
|
492
|
+
var AGENT_TURN_SESSION_INDEX_MAX_LENGTH = 5e3;
|
|
493
|
+
var AGENT_TURN_SESSION_TTL_MS = THREAD_STATE_TTL_MS;
|
|
494
|
+
var agentTurnSessionStatusSchema = z2.enum([
|
|
495
|
+
"running",
|
|
496
|
+
"awaiting_resume",
|
|
497
|
+
"completed",
|
|
498
|
+
"failed",
|
|
499
|
+
"abandoned"
|
|
500
|
+
]);
|
|
501
|
+
var agentTurnSurfaceSchema = z2.enum([
|
|
502
|
+
"slack",
|
|
503
|
+
"api",
|
|
504
|
+
"scheduler",
|
|
505
|
+
"internal"
|
|
506
|
+
]);
|
|
507
|
+
var agentTurnResumeReasonSchema = z2.enum([
|
|
508
|
+
"timeout",
|
|
509
|
+
"auth",
|
|
510
|
+
"yield",
|
|
511
|
+
"retry"
|
|
512
|
+
]);
|
|
513
|
+
var nonNegativeNumberSchema = z2.number().finite().nonnegative();
|
|
514
|
+
var seqCursorSchema = z2.number().int().min(-1);
|
|
515
|
+
var agentTurnSessionSummarySchema = z2.object({
|
|
516
|
+
channelName: z2.string().min(1).optional(),
|
|
517
|
+
version: z2.number().int().nonnegative(),
|
|
518
|
+
conversationId: z2.string().min(1),
|
|
519
|
+
cumulativeDurationMs: nonNegativeNumberSchema,
|
|
520
|
+
cumulativeUsage: agentTurnUsageSchema.optional(),
|
|
521
|
+
destination: destinationSchema.optional(),
|
|
522
|
+
source: sourceSchema.optional(),
|
|
523
|
+
lastProgressAtMs: nonNegativeNumberSchema,
|
|
524
|
+
loadedSkillNames: z2.array(z2.string()).optional(),
|
|
525
|
+
modelId: z2.string().min(1).optional(),
|
|
526
|
+
reasoningLevel: z2.string().min(1).optional(),
|
|
527
|
+
actor: actorSchema.optional(),
|
|
528
|
+
resumeReason: agentTurnResumeReasonSchema.optional(),
|
|
529
|
+
resumedFromSliceId: z2.number().int().nonnegative().optional(),
|
|
530
|
+
sessionId: z2.string().min(1),
|
|
531
|
+
sliceId: z2.number().int().nonnegative(),
|
|
532
|
+
startedAtMs: nonNegativeNumberSchema,
|
|
533
|
+
state: agentTurnSessionStatusSchema,
|
|
534
|
+
surface: agentTurnSurfaceSchema.optional(),
|
|
535
|
+
traceId: z2.string().optional(),
|
|
536
|
+
updatedAtMs: nonNegativeNumberSchema
|
|
537
|
+
}).strict();
|
|
538
|
+
var storedAgentTurnSessionRecordSchema = agentTurnSessionSummarySchema.extend({
|
|
539
|
+
actors: z2.array(actorSchema).optional(),
|
|
540
|
+
committedSeq: seqCursorSchema,
|
|
541
|
+
historyVersion: z2.number().int().nonnegative().optional(),
|
|
542
|
+
errorMessage: z2.string().optional(),
|
|
543
|
+
turnStartSeq: seqCursorSchema.optional(),
|
|
544
|
+
runtimeContext: z2.array(piMessageSchema).optional()
|
|
545
|
+
}).strict();
|
|
546
|
+
function conversationExecutionFromSummary(summary) {
|
|
547
|
+
const status = summary.state === "completed" || summary.state === "abandoned" ? "idle" : summary.state;
|
|
548
|
+
return {
|
|
549
|
+
status,
|
|
550
|
+
runId: summary.sessionId,
|
|
551
|
+
updatedAtMs: summary.updatedAtMs
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
function sessionLogActor(actor) {
|
|
555
|
+
return actor?.platform === "slack" ? toStoredSlackActor(actor) : void 0;
|
|
556
|
+
}
|
|
557
|
+
function parseAgentTurnSessionRecord(value) {
|
|
558
|
+
return storedAgentTurnSessionRecordSchema.parse(value);
|
|
559
|
+
}
|
|
560
|
+
function parseAgentTurnSessionSummary(value) {
|
|
561
|
+
return agentTurnSessionSummarySchema.parse(value);
|
|
562
|
+
}
|
|
563
|
+
async function appendAgentTurnSessionSummary(summary, ttlMs) {
|
|
564
|
+
const stateAdapter = getStateAdapter();
|
|
565
|
+
await Promise.all([
|
|
566
|
+
stateAdapter.appendToList(AGENT_TURN_SESSION_INDEX_KEY, summary, {
|
|
567
|
+
maxLength: AGENT_TURN_SESSION_INDEX_MAX_LENGTH,
|
|
568
|
+
ttlMs
|
|
569
|
+
}),
|
|
570
|
+
stateAdapter.appendToList(
|
|
571
|
+
agentTurnSessionConversationIndexKey(summary.conversationId),
|
|
572
|
+
summary,
|
|
573
|
+
{ ttlMs }
|
|
574
|
+
)
|
|
575
|
+
]);
|
|
576
|
+
}
|
|
577
|
+
async function recordConversationActivityMetadata(args) {
|
|
578
|
+
const conversationStore = args.conversationStore ?? getConversationStore();
|
|
579
|
+
const source = args.summary.destination?.platform === "local" ? "local" : args.summary.surface;
|
|
580
|
+
await conversationStore.recordActivity({
|
|
581
|
+
activityAtMs: args.summary.updatedAtMs,
|
|
582
|
+
channelName: args.summary.channelName,
|
|
583
|
+
conversationId: args.summary.conversationId,
|
|
584
|
+
destination: args.summary.destination,
|
|
585
|
+
nowMs: args.nowMs,
|
|
586
|
+
actor: sessionLogActor(args.summary.actor),
|
|
587
|
+
source,
|
|
588
|
+
visibility: args.destinationVisibility
|
|
589
|
+
});
|
|
590
|
+
await conversationStore.recordExecution({
|
|
591
|
+
channelName: args.summary.channelName,
|
|
592
|
+
conversationId: args.summary.conversationId,
|
|
593
|
+
createdAtMs: args.summary.startedAtMs,
|
|
594
|
+
destination: args.summary.destination,
|
|
595
|
+
execution: conversationExecutionFromSummary(args.summary),
|
|
596
|
+
lastActivityAtMs: args.summary.updatedAtMs,
|
|
597
|
+
metrics: {
|
|
598
|
+
durationMs: args.summary.cumulativeDurationMs,
|
|
599
|
+
...args.summary.cumulativeUsage ? { usage: args.summary.cumulativeUsage } : {}
|
|
600
|
+
},
|
|
601
|
+
actor: sessionLogActor(args.summary.actor),
|
|
602
|
+
source,
|
|
603
|
+
updatedAtMs: args.nowMs,
|
|
604
|
+
visibility: args.destinationVisibility
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessageIndex, restoreVolatileContext = true) {
|
|
608
|
+
const piMessages = restoreVolatileContext && (stored.state === "running" || stored.state === "awaiting_resume") ? restoreRuntimeContext(piProjection.messages, stored.runtimeContext) : piProjection.messages;
|
|
609
|
+
return {
|
|
610
|
+
version: stored.version,
|
|
611
|
+
...stored.channelName ? { channelName: stored.channelName } : {},
|
|
612
|
+
conversationId: stored.conversationId,
|
|
613
|
+
sessionId: stored.sessionId,
|
|
614
|
+
sliceId: stored.sliceId,
|
|
615
|
+
state: stored.state,
|
|
616
|
+
startedAtMs: stored.startedAtMs,
|
|
617
|
+
lastProgressAtMs: stored.lastProgressAtMs,
|
|
618
|
+
updatedAtMs: stored.updatedAtMs,
|
|
619
|
+
piMessages,
|
|
620
|
+
piMessageProvenance: piProjection.provenance,
|
|
621
|
+
actors: stored.actors ?? instructionActors(piProjection.provenance),
|
|
622
|
+
cumulativeDurationMs: stored.cumulativeDurationMs,
|
|
623
|
+
...stored.destination ? { destination: stored.destination } : {},
|
|
624
|
+
...stored.source ? { source: stored.source } : {},
|
|
625
|
+
...stored.cumulativeUsage ? { cumulativeUsage: stored.cumulativeUsage } : {},
|
|
626
|
+
...stored.resumeReason ? { resumeReason: stored.resumeReason } : {},
|
|
627
|
+
...stored.errorMessage ? { errorMessage: stored.errorMessage } : {},
|
|
628
|
+
...stored.loadedSkillNames ? { loadedSkillNames: stored.loadedSkillNames } : {},
|
|
629
|
+
...stored.modelId ? { modelId: stored.modelId } : {},
|
|
630
|
+
...stored.reasoningLevel ? { reasoningLevel: stored.reasoningLevel } : {},
|
|
631
|
+
...stored.actor ? { actor: stored.actor } : {},
|
|
632
|
+
...stored.resumedFromSliceId !== void 0 ? { resumedFromSliceId: stored.resumedFromSliceId } : {},
|
|
633
|
+
...stored.surface ? { surface: stored.surface } : {},
|
|
634
|
+
...stored.traceId ? { traceId: stored.traceId } : {},
|
|
635
|
+
...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {}
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
function restoreRuntimeContext(messages, runtimeContext) {
|
|
639
|
+
if (!runtimeContext || runtimeContext.length === 0) return messages;
|
|
640
|
+
const restored = [...messages];
|
|
641
|
+
for (const runtimeMessage of runtimeContext) {
|
|
642
|
+
const runtime = runtimeMessage;
|
|
643
|
+
const targetIndex = restored.findIndex((message) => {
|
|
644
|
+
const candidate = message;
|
|
645
|
+
return candidate.role === "user" && candidate.timestamp === runtime.timestamp;
|
|
646
|
+
});
|
|
647
|
+
if (targetIndex < 0) {
|
|
648
|
+
restored.push(runtimeMessage);
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
const target = restored[targetIndex];
|
|
652
|
+
restored[targetIndex] = {
|
|
653
|
+
...restored[targetIndex],
|
|
654
|
+
content: [
|
|
655
|
+
...Array.isArray(runtime.content) ? runtime.content : [],
|
|
656
|
+
...Array.isArray(target.content) ? target.content : []
|
|
657
|
+
]
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
return restored;
|
|
661
|
+
}
|
|
662
|
+
async function getStoredAgentTurnSessionRecord(conversationId, sessionId) {
|
|
663
|
+
const stateAdapter = getStateAdapter();
|
|
664
|
+
await stateAdapter.connect();
|
|
665
|
+
const value = await stateAdapter.get(
|
|
666
|
+
agentTurnSessionKey(conversationId, sessionId)
|
|
667
|
+
);
|
|
668
|
+
return value == null ? void 0 : parseAgentTurnSessionRecord(value);
|
|
669
|
+
}
|
|
670
|
+
async function materializeStoredAgentTurnSessionRecord(conversationId, sessionId, followCurrentReplacement) {
|
|
671
|
+
const parsed = await getStoredAgentTurnSessionRecord(
|
|
672
|
+
conversationId,
|
|
673
|
+
sessionId
|
|
674
|
+
);
|
|
675
|
+
if (!parsed) {
|
|
676
|
+
return void 0;
|
|
677
|
+
}
|
|
678
|
+
const pinnedProjection = await loadTurnProjection({
|
|
679
|
+
conversationId,
|
|
680
|
+
committedSeq: parsed.committedSeq,
|
|
681
|
+
// Unfinished records include the current-epoch tail so parked input
|
|
682
|
+
// appended after the last safe boundary stays model-visible on resume.
|
|
683
|
+
includeTail: parsed.state === "running" || parsed.state === "awaiting_resume"
|
|
684
|
+
});
|
|
685
|
+
if (!pinnedProjection) {
|
|
686
|
+
return void 0;
|
|
687
|
+
}
|
|
688
|
+
const currentHistory = await getConversationEventStore().loadCurrentHistory(conversationId);
|
|
689
|
+
const currentHistoryVersion = currentHistory.at(-1)?.historyVersion ?? parsed.historyVersion ?? 0;
|
|
690
|
+
const followsReplacement = followCurrentReplacement && (parsed.state === "running" || parsed.state === "awaiting_resume") && parsed.historyVersion !== void 0 && parsed.historyVersion !== currentHistoryVersion;
|
|
691
|
+
const piProjection = followsReplacement ? projectConversationEvents(currentHistory) : pinnedProjection;
|
|
692
|
+
const turnStartMessageIndex = followsReplacement ? 0 : parsed.turnStartSeq === void 0 ? void 0 : piProjection.seqs.filter((seq) => seq <= parsed.turnStartSeq).length;
|
|
693
|
+
return materializeAgentTurnSessionRecord(
|
|
694
|
+
parsed,
|
|
695
|
+
piProjection,
|
|
696
|
+
turnStartMessageIndex,
|
|
697
|
+
!followsReplacement && (parsed.historyVersion === void 0 || parsed.historyVersion === currentHistoryVersion)
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
async function getAgentTurnSessionRecord(conversationId, sessionId) {
|
|
701
|
+
return await materializeStoredAgentTurnSessionRecord(
|
|
702
|
+
conversationId,
|
|
703
|
+
sessionId,
|
|
704
|
+
false
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
async function getAgentTurnSessionRecordForResume(conversationId, sessionId) {
|
|
708
|
+
return await materializeStoredAgentTurnSessionRecord(
|
|
709
|
+
conversationId,
|
|
710
|
+
sessionId,
|
|
711
|
+
true
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
function buildStoredRecord(args) {
|
|
715
|
+
const nowMs = Date.now();
|
|
716
|
+
return {
|
|
717
|
+
version: (args.previousVersion ?? 0) + 1,
|
|
718
|
+
...args.channelName ? { channelName: args.channelName } : {},
|
|
719
|
+
conversationId: args.conversationId,
|
|
720
|
+
sessionId: args.sessionId,
|
|
721
|
+
sliceId: args.sliceId,
|
|
722
|
+
state: args.state,
|
|
723
|
+
startedAtMs: args.startedAtMs ?? nowMs,
|
|
724
|
+
lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
|
|
725
|
+
updatedAtMs: nowMs,
|
|
726
|
+
committedSeq: args.committedSeq,
|
|
727
|
+
...args.historyVersion !== void 0 ? { historyVersion: args.historyVersion } : {},
|
|
728
|
+
...args.turnStartSeq !== void 0 ? { turnStartSeq: args.turnStartSeq } : {},
|
|
729
|
+
...args.runtimeContext && args.runtimeContext.length > 0 ? { runtimeContext: args.runtimeContext } : {},
|
|
730
|
+
cumulativeDurationMs: args.cumulativeDurationMs,
|
|
731
|
+
...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
|
|
732
|
+
...args.destination ? { destination: args.destination } : {},
|
|
733
|
+
...args.source ? { source: args.source } : {},
|
|
734
|
+
...args.actor ? { actor: args.actor } : {},
|
|
735
|
+
...args.actors ? { actors: args.actors } : {},
|
|
736
|
+
...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
|
|
737
|
+
...args.modelId ? { modelId: args.modelId } : {},
|
|
738
|
+
...args.reasoningLevel ? { reasoningLevel: args.reasoningLevel } : {},
|
|
739
|
+
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
740
|
+
...args.errorMessage ? { errorMessage: args.errorMessage } : {},
|
|
741
|
+
...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
|
|
742
|
+
...args.surface ? { surface: args.surface } : {},
|
|
743
|
+
...args.traceId ? { traceId: args.traceId } : {}
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
async function setStoredRecord(args) {
|
|
747
|
+
const stateAdapter = getStateAdapter();
|
|
748
|
+
await stateAdapter.connect();
|
|
749
|
+
await recordConversationActivityMetadata({
|
|
750
|
+
conversationStore: args.conversationStore,
|
|
751
|
+
destinationVisibility: args.destinationVisibility,
|
|
752
|
+
nowMs: Date.now(),
|
|
753
|
+
summary: args.record
|
|
754
|
+
});
|
|
755
|
+
await stateAdapter.set(
|
|
756
|
+
agentTurnSessionKey(args.record.conversationId, args.record.sessionId),
|
|
757
|
+
args.record,
|
|
758
|
+
args.ttlMs
|
|
759
|
+
);
|
|
760
|
+
const {
|
|
761
|
+
actors: _actors,
|
|
762
|
+
committedSeq: _committedSeq,
|
|
763
|
+
historyVersion: _historyVersion,
|
|
764
|
+
errorMessage: _errorMessage,
|
|
765
|
+
turnStartSeq: _turnStartSeq,
|
|
766
|
+
runtimeContext: _runtimeContext,
|
|
767
|
+
...summary
|
|
768
|
+
} = args.record;
|
|
769
|
+
await appendAgentTurnSessionSummary(summary, args.ttlMs);
|
|
770
|
+
return materializeAgentTurnSessionRecord(
|
|
771
|
+
args.record,
|
|
772
|
+
{
|
|
773
|
+
messages: [...args.piMessages],
|
|
774
|
+
provenance: [...args.piMessageProvenance]
|
|
775
|
+
},
|
|
776
|
+
args.turnStartMessageIndex
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
async function updateAgentTurnSessionState(args) {
|
|
780
|
+
const parsed = await getStoredAgentTurnSessionRecord(
|
|
781
|
+
args.existing.conversationId,
|
|
782
|
+
args.existing.sessionId
|
|
783
|
+
);
|
|
784
|
+
if (!parsed || parsed.version !== args.existing.version) {
|
|
785
|
+
return void 0;
|
|
786
|
+
}
|
|
787
|
+
return await setStoredRecord({
|
|
788
|
+
piMessages: args.existing.piMessages,
|
|
789
|
+
piMessageProvenance: args.existing.piMessageProvenance,
|
|
790
|
+
ttlMs: AGENT_TURN_SESSION_TTL_MS,
|
|
791
|
+
...args.existing.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: args.existing.turnStartMessageIndex } : {},
|
|
792
|
+
record: buildStoredRecord({
|
|
793
|
+
conversationId: args.existing.conversationId,
|
|
794
|
+
sessionId: args.existing.sessionId,
|
|
795
|
+
sliceId: args.existing.sliceId,
|
|
796
|
+
state: args.state,
|
|
797
|
+
committedSeq: parsed.committedSeq,
|
|
798
|
+
...parsed.historyVersion !== void 0 ? { historyVersion: parsed.historyVersion } : {},
|
|
799
|
+
...parsed.turnStartSeq !== void 0 ? { turnStartSeq: parsed.turnStartSeq } : {},
|
|
800
|
+
...parsed.runtimeContext ? { runtimeContext: parsed.runtimeContext } : {},
|
|
801
|
+
...parsed.channelName ? { channelName: parsed.channelName } : {},
|
|
802
|
+
startedAtMs: parsed.startedAtMs,
|
|
803
|
+
lastProgressAtMs: parsed.lastProgressAtMs,
|
|
804
|
+
previousVersion: parsed.version,
|
|
805
|
+
cumulativeDurationMs: args.existing.cumulativeDurationMs,
|
|
806
|
+
...args.existing.cumulativeUsage ? { cumulativeUsage: args.existing.cumulativeUsage } : {},
|
|
807
|
+
...args.existing.destination ? { destination: args.existing.destination } : {},
|
|
808
|
+
...args.existing.source ? { source: args.existing.source } : {},
|
|
809
|
+
...args.existing.loadedSkillNames ? { loadedSkillNames: args.existing.loadedSkillNames } : {},
|
|
810
|
+
...args.existing.modelId ? { modelId: args.existing.modelId } : {},
|
|
811
|
+
...args.existing.reasoningLevel ? { reasoningLevel: args.existing.reasoningLevel } : {},
|
|
812
|
+
...args.existing.actor ? { actor: args.existing.actor } : {},
|
|
813
|
+
actors: args.existing.actors,
|
|
814
|
+
...args.existing.resumeReason ? { resumeReason: args.existing.resumeReason } : {},
|
|
815
|
+
...args.existing.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.existing.resumedFromSliceId } : {},
|
|
816
|
+
...args.existing.surface ? { surface: args.existing.surface } : {},
|
|
817
|
+
...args.existing.traceId ? { traceId: args.existing.traceId } : {},
|
|
818
|
+
...args.errorMessage ?? args.existing.errorMessage ? { errorMessage: args.errorMessage ?? args.existing.errorMessage } : {}
|
|
819
|
+
})
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
async function upsertAgentTurnSessionRecord(args) {
|
|
823
|
+
const existingRecord = await getStoredAgentTurnSessionRecord(
|
|
824
|
+
args.conversationId,
|
|
825
|
+
args.sessionId
|
|
826
|
+
);
|
|
827
|
+
const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
|
|
828
|
+
const instructionActor = args.actor ?? existingRecord?.actor;
|
|
829
|
+
const commit = await commitMessages({
|
|
830
|
+
conversationId: args.conversationId,
|
|
831
|
+
messages: args.piMessages,
|
|
832
|
+
...instructionActor ? { newMessageProvenance: instructionProvenanceFor(instructionActor) } : {},
|
|
833
|
+
...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {}
|
|
834
|
+
});
|
|
835
|
+
const durableTurnStartMessageIndex = args.turnStartMessageIndex === void 0 ? void 0 : stripRuntimeTurnContext(
|
|
836
|
+
args.piMessages.slice(0, args.turnStartMessageIndex)
|
|
837
|
+
).length;
|
|
838
|
+
const runtimeContext = retainRuntimeTurnContext(args.piMessages);
|
|
839
|
+
const retainedRuntimeContext = runtimeContext.length > 0 ? runtimeContext : existingRecord?.historyVersion === commit.historyVersion ? existingRecord.runtimeContext : void 0;
|
|
840
|
+
const turnStartSeq = durableTurnStartMessageIndex === void 0 ? existingRecord?.turnStartSeq : durableTurnStartMessageIndex <= 0 ? -1 : commit.messageSeqs[durableTurnStartMessageIndex - 1] ?? commit.committedSeq;
|
|
841
|
+
const turnStartMessageIndex = durableTurnStartMessageIndex ?? (turnStartSeq === void 0 ? void 0 : commit.messageSeqs.filter((seq) => seq <= turnStartSeq).length);
|
|
842
|
+
return await setStoredRecord({
|
|
843
|
+
conversationStore: args.conversationStore,
|
|
844
|
+
destinationVisibility: args.destinationVisibility,
|
|
845
|
+
piMessages: commit.messages,
|
|
846
|
+
piMessageProvenance: commit.provenance,
|
|
847
|
+
ttlMs,
|
|
848
|
+
...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {},
|
|
849
|
+
record: buildStoredRecord({
|
|
850
|
+
...args.channelName ?? existingRecord?.channelName ? { channelName: args.channelName ?? existingRecord?.channelName } : {},
|
|
851
|
+
conversationId: args.conversationId,
|
|
852
|
+
sessionId: args.sessionId,
|
|
853
|
+
sliceId: args.sliceId,
|
|
854
|
+
state: args.state,
|
|
855
|
+
...existingRecord?.startedAtMs !== void 0 ? { startedAtMs: existingRecord.startedAtMs } : {},
|
|
856
|
+
...args.lastProgressAtMs !== void 0 ? { lastProgressAtMs: args.lastProgressAtMs } : {},
|
|
857
|
+
committedSeq: commit.committedSeq,
|
|
858
|
+
historyVersion: commit.historyVersion,
|
|
859
|
+
...turnStartSeq !== void 0 ? { turnStartSeq } : {},
|
|
860
|
+
...retainedRuntimeContext ? { runtimeContext: retainedRuntimeContext } : {},
|
|
861
|
+
previousVersion: existingRecord?.version,
|
|
862
|
+
cumulativeDurationMs: args.cumulativeDurationMs ?? existingRecord?.cumulativeDurationMs ?? 0,
|
|
863
|
+
...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
|
|
864
|
+
...args.destination ?? existingRecord?.destination ? { destination: args.destination ?? existingRecord?.destination } : {},
|
|
865
|
+
...args.source ?? existingRecord?.source ? { source: args.source ?? existingRecord?.source } : {},
|
|
866
|
+
...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
|
|
867
|
+
modelId: args.modelId,
|
|
868
|
+
...args.reasoningLevel ?? existingRecord?.reasoningLevel ? {
|
|
869
|
+
reasoningLevel: args.reasoningLevel ?? existingRecord?.reasoningLevel
|
|
870
|
+
} : {},
|
|
871
|
+
...args.actor ?? existingRecord?.actor ? { actor: args.actor ?? existingRecord?.actor } : {},
|
|
872
|
+
actors: instructionActors([
|
|
873
|
+
...(existingRecord?.actors ?? []).map(instructionProvenanceFor),
|
|
874
|
+
...(args.actors ?? []).map(instructionProvenanceFor),
|
|
875
|
+
...commit.provenance
|
|
876
|
+
]),
|
|
877
|
+
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
878
|
+
...args.errorMessage ? { errorMessage: args.errorMessage } : {},
|
|
879
|
+
...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
|
|
880
|
+
...args.surface ?? existingRecord?.surface ? { surface: args.surface ?? existingRecord?.surface } : {},
|
|
881
|
+
...args.traceId ?? existingRecord?.traceId ? { traceId: args.traceId ?? existingRecord?.traceId } : {}
|
|
882
|
+
})
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
async function recordAgentTurnSessionSummary(args) {
|
|
886
|
+
const existing = await getStoredAgentTurnSessionRecord(
|
|
887
|
+
args.conversationId,
|
|
888
|
+
args.sessionId
|
|
889
|
+
);
|
|
890
|
+
const nowMs = Date.now();
|
|
891
|
+
const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
|
|
892
|
+
const summary = {
|
|
893
|
+
version: existing?.version ?? 0,
|
|
894
|
+
...args.channelName ?? existing?.channelName ? { channelName: args.channelName ?? existing?.channelName } : {},
|
|
895
|
+
conversationId: args.conversationId,
|
|
896
|
+
sessionId: args.sessionId,
|
|
897
|
+
sliceId: args.sliceId,
|
|
898
|
+
startedAtMs: existing?.startedAtMs ?? args.startedAtMs ?? nowMs,
|
|
899
|
+
lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
|
|
900
|
+
state: args.state,
|
|
901
|
+
updatedAtMs: nowMs,
|
|
902
|
+
cumulativeDurationMs: args.cumulativeDurationMs ?? existing?.cumulativeDurationMs ?? 0,
|
|
903
|
+
...args.cumulativeUsage ?? existing?.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage ?? existing?.cumulativeUsage } : {},
|
|
904
|
+
...args.destination ?? existing?.destination ? { destination: args.destination ?? existing?.destination } : {},
|
|
905
|
+
...args.source ?? existing?.source ? { source: args.source ?? existing?.source } : {},
|
|
906
|
+
...args.actor ?? existing?.actor ? { actor: args.actor ?? existing?.actor } : {},
|
|
907
|
+
...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : existing?.loadedSkillNames ? { loadedSkillNames: existing.loadedSkillNames } : {},
|
|
908
|
+
...args.modelId ?? existing?.modelId ? { modelId: args.modelId ?? existing?.modelId } : {},
|
|
909
|
+
...args.reasoningLevel ?? existing?.reasoningLevel ? { reasoningLevel: args.reasoningLevel ?? existing?.reasoningLevel } : {},
|
|
910
|
+
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
911
|
+
...args.surface ?? existing?.surface ? { surface: args.surface ?? existing?.surface } : {},
|
|
912
|
+
...args.traceId ?? existing?.traceId ? { traceId: args.traceId ?? existing?.traceId } : {}
|
|
913
|
+
};
|
|
914
|
+
await recordConversationActivityMetadata({
|
|
915
|
+
conversationStore: args.conversationStore,
|
|
916
|
+
destinationVisibility: args.destinationVisibility,
|
|
917
|
+
nowMs,
|
|
918
|
+
summary
|
|
919
|
+
});
|
|
920
|
+
await appendAgentTurnSessionSummary(summary, ttlMs);
|
|
921
|
+
}
|
|
922
|
+
async function readAgentTurnSessionSummariesFromIndex(key, stateAdapter) {
|
|
923
|
+
await stateAdapter.connect();
|
|
924
|
+
const values = await stateAdapter.getList(key);
|
|
925
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
926
|
+
for (const value of [...values].reverse()) {
|
|
927
|
+
let summary;
|
|
928
|
+
try {
|
|
929
|
+
summary = parseAgentTurnSessionSummary(value);
|
|
930
|
+
} catch (error) {
|
|
931
|
+
logWarn(
|
|
932
|
+
"agent_turn_session_summary_parse_failed",
|
|
933
|
+
{},
|
|
934
|
+
{
|
|
935
|
+
"app.state.key": key,
|
|
936
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
937
|
+
},
|
|
938
|
+
"Skipping an invalid turn-session summary index entry"
|
|
939
|
+
);
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
const summaryKey = `${summary.conversationId}:${summary.sessionId}`;
|
|
943
|
+
if (!summaries.has(summaryKey)) {
|
|
944
|
+
summaries.set(summaryKey, summary);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
return [...summaries.values()].sort(
|
|
948
|
+
(left, right) => right.updatedAtMs - left.updatedAtMs
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
async function listAgentTurnSessionSummariesForConversation(conversationId) {
|
|
952
|
+
const stateAdapter = getStateAdapter();
|
|
953
|
+
const summaries = await listBoundedAgentTurnSessionSummariesForConversation(conversationId);
|
|
954
|
+
if (summaries.length > 0) {
|
|
955
|
+
return summaries;
|
|
956
|
+
}
|
|
957
|
+
return (await readAgentTurnSessionSummariesFromIndex(
|
|
958
|
+
AGENT_TURN_SESSION_INDEX_KEY,
|
|
959
|
+
stateAdapter
|
|
960
|
+
)).filter((summary) => summary.conversationId === conversationId);
|
|
961
|
+
}
|
|
962
|
+
async function listBoundedAgentTurnSessionSummariesForConversation(conversationId) {
|
|
963
|
+
return readAgentTurnSessionSummariesFromIndex(
|
|
964
|
+
agentTurnSessionConversationIndexKey(conversationId),
|
|
965
|
+
getStateAdapter()
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
async function abandonAgentTurnSessionRecord(args) {
|
|
969
|
+
const existing = await getAgentTurnSessionRecord(
|
|
970
|
+
args.conversationId,
|
|
971
|
+
args.sessionId
|
|
972
|
+
);
|
|
973
|
+
if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned") {
|
|
974
|
+
return void 0;
|
|
975
|
+
}
|
|
976
|
+
return await updateAgentTurnSessionState({
|
|
977
|
+
existing,
|
|
978
|
+
state: "abandoned",
|
|
979
|
+
errorMessage: args.errorMessage ?? existing.errorMessage
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
async function failAgentTurnSessionRecord(args) {
|
|
983
|
+
const existing = await getAgentTurnSessionRecord(
|
|
984
|
+
args.conversationId,
|
|
985
|
+
args.sessionId
|
|
986
|
+
);
|
|
987
|
+
if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned" || existing.version !== args.expectedVersion) {
|
|
988
|
+
return void 0;
|
|
989
|
+
}
|
|
990
|
+
return await updateAgentTurnSessionState({
|
|
991
|
+
existing,
|
|
992
|
+
state: "failed",
|
|
993
|
+
errorMessage: args.errorMessage ?? existing.errorMessage
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
|
|
148
997
|
// src/chat/services/turn-limit.ts
|
|
149
998
|
var TurnSliceLimitExceededError = class extends Error {
|
|
150
999
|
constructor(maxSlices) {
|
|
@@ -162,9 +1011,9 @@ function logSessionRecordError(error, eventName, args, attributes, message) {
|
|
|
162
1011
|
error,
|
|
163
1012
|
eventName,
|
|
164
1013
|
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
1014
|
+
messageConversationId: args.logContext.threadId,
|
|
1015
|
+
userId: args.logContext.actorId,
|
|
1016
|
+
destinationName: args.logContext.channelId,
|
|
168
1017
|
runId: args.logContext.runId,
|
|
169
1018
|
assistantUserName: args.logContext.assistantUserName,
|
|
170
1019
|
modelId: args.modelId
|
|
@@ -319,7 +1168,6 @@ async function completeDeliveredTurn(args) {
|
|
|
319
1168
|
sliceId: args.sliceId,
|
|
320
1169
|
allMessages: args.messages,
|
|
321
1170
|
loadedSkillNames: args.loadedSkillNames,
|
|
322
|
-
logContext: args.logContext,
|
|
323
1171
|
modelId: args.modelId,
|
|
324
1172
|
actor: args.actor,
|
|
325
1173
|
reasoningLevel: args.reasoningLevel,
|
|
@@ -530,6 +1378,122 @@ async function persistYieldSessionRecord(args) {
|
|
|
530
1378
|
}
|
|
531
1379
|
}
|
|
532
1380
|
|
|
1381
|
+
// src/chat/state/conversation.ts
|
|
1382
|
+
function defaultConversationState() {
|
|
1383
|
+
const nowMs = Date.now();
|
|
1384
|
+
return {
|
|
1385
|
+
schemaVersion: 1,
|
|
1386
|
+
messages: [],
|
|
1387
|
+
compactions: [],
|
|
1388
|
+
backfill: {},
|
|
1389
|
+
processing: {},
|
|
1390
|
+
stats: {
|
|
1391
|
+
estimatedContextTokens: 0,
|
|
1392
|
+
totalMessageCount: 0,
|
|
1393
|
+
compactedMessageCount: 0,
|
|
1394
|
+
updatedAtMs: nowMs
|
|
1395
|
+
},
|
|
1396
|
+
vision: {
|
|
1397
|
+
byFileId: {}
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
function coercePendingAuthState(value) {
|
|
1402
|
+
if (!isRecord(value)) {
|
|
1403
|
+
return void 0;
|
|
1404
|
+
}
|
|
1405
|
+
const kind = value.kind;
|
|
1406
|
+
const provider = toOptionalString(value.provider);
|
|
1407
|
+
const actorId = toOptionalString(value.actorId);
|
|
1408
|
+
const authSessionId = toOptionalString(value.authSessionId);
|
|
1409
|
+
const scope = toOptionalString(value.scope);
|
|
1410
|
+
const sessionId = toOptionalString(value.sessionId);
|
|
1411
|
+
const linkSentAtMs = toOptionalNumber(value.linkSentAtMs);
|
|
1412
|
+
if (kind !== "mcp" && kind !== "plugin" || !provider || !actorId || kind === "mcp" && !authSessionId || !sessionId || typeof linkSentAtMs !== "number") {
|
|
1413
|
+
return void 0;
|
|
1414
|
+
}
|
|
1415
|
+
const base = {
|
|
1416
|
+
provider,
|
|
1417
|
+
actorId,
|
|
1418
|
+
...scope ? { scope } : {},
|
|
1419
|
+
sessionId,
|
|
1420
|
+
linkSentAtMs
|
|
1421
|
+
};
|
|
1422
|
+
return kind === "mcp" ? { ...base, authSessionId, kind } : { ...base, kind };
|
|
1423
|
+
}
|
|
1424
|
+
function coerceThreadConversationState(value) {
|
|
1425
|
+
if (!isRecord(value)) {
|
|
1426
|
+
return defaultConversationState();
|
|
1427
|
+
}
|
|
1428
|
+
const root = value;
|
|
1429
|
+
const rawConversation = isRecord(root.conversation) ? root.conversation : {};
|
|
1430
|
+
const base = defaultConversationState();
|
|
1431
|
+
const messages = [];
|
|
1432
|
+
const compactions = [];
|
|
1433
|
+
const rawBackfill = isRecord(rawConversation.backfill) ? rawConversation.backfill : {};
|
|
1434
|
+
const backfill = {
|
|
1435
|
+
completedAtMs: toOptionalNumber(rawBackfill.completedAtMs),
|
|
1436
|
+
source: rawBackfill.source === "recent_messages" || rawBackfill.source === "thread_fetch" ? rawBackfill.source : void 0
|
|
1437
|
+
};
|
|
1438
|
+
const rawProcessing = isRecord(rawConversation.processing) ? rawConversation.processing : {};
|
|
1439
|
+
const processing = {
|
|
1440
|
+
activeTurnId: toOptionalString(rawProcessing.activeTurnId),
|
|
1441
|
+
lastCompletedAtMs: toOptionalNumber(rawProcessing.lastCompletedAtMs),
|
|
1442
|
+
pendingAuth: coercePendingAuthState(rawProcessing.pendingAuth)
|
|
1443
|
+
};
|
|
1444
|
+
const rawStats = isRecord(rawConversation.stats) ? rawConversation.stats : {};
|
|
1445
|
+
const stats = {
|
|
1446
|
+
estimatedContextTokens: toOptionalNumber(rawStats.estimatedContextTokens) ?? base.stats.estimatedContextTokens,
|
|
1447
|
+
totalMessageCount: toOptionalNumber(rawStats.totalMessageCount) ?? messages.length,
|
|
1448
|
+
compactedMessageCount: toOptionalNumber(rawStats.compactedMessageCount) ?? 0,
|
|
1449
|
+
updatedAtMs: toOptionalNumber(rawStats.updatedAtMs) ?? base.stats.updatedAtMs
|
|
1450
|
+
};
|
|
1451
|
+
const rawVision = isRecord(rawConversation.vision) ? rawConversation.vision : {};
|
|
1452
|
+
const rawVisionByFileId = isRecord(rawVision.byFileId) ? rawVision.byFileId : {};
|
|
1453
|
+
const byFileId = {};
|
|
1454
|
+
for (const [fileId, value2] of Object.entries(rawVisionByFileId)) {
|
|
1455
|
+
if (typeof fileId !== "string" || fileId.trim().length === 0) continue;
|
|
1456
|
+
if (!isRecord(value2)) continue;
|
|
1457
|
+
const summary = toOptionalString(value2.summary);
|
|
1458
|
+
const analyzedAtMs = toOptionalNumber(value2.analyzedAtMs);
|
|
1459
|
+
if (!summary || !analyzedAtMs) continue;
|
|
1460
|
+
byFileId[fileId] = {
|
|
1461
|
+
summary,
|
|
1462
|
+
analyzedAtMs
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
return {
|
|
1466
|
+
schemaVersion: 1,
|
|
1467
|
+
messages,
|
|
1468
|
+
compactions,
|
|
1469
|
+
backfill,
|
|
1470
|
+
processing,
|
|
1471
|
+
stats,
|
|
1472
|
+
vision: {
|
|
1473
|
+
backfillCompletedAtMs: toOptionalNumber(rawVision.backfillCompletedAtMs),
|
|
1474
|
+
byFileId
|
|
1475
|
+
}
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
function buildConversationStatePatch(conversation) {
|
|
1479
|
+
const {
|
|
1480
|
+
compactions: _compactions,
|
|
1481
|
+
messages: _messages,
|
|
1482
|
+
...scratch
|
|
1483
|
+
} = conversation;
|
|
1484
|
+
return {
|
|
1485
|
+
conversation: {
|
|
1486
|
+
...scratch,
|
|
1487
|
+
schemaVersion: 1,
|
|
1488
|
+
stats: {
|
|
1489
|
+
...conversation.stats,
|
|
1490
|
+
totalMessageCount: conversation.messages.length,
|
|
1491
|
+
updatedAtMs: Date.now()
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
|
|
533
1497
|
// src/chat/services/context-budget.ts
|
|
534
1498
|
var COMPACTION_TRIGGER_INPUT_RATIO = 0.75;
|
|
535
1499
|
var COMPACTION_OUTPUT_RESERVE_RATIO = 0.25;
|
|
@@ -804,9 +1768,9 @@ async function summarizeConversationChunk(messages, conversation, context, deps)
|
|
|
804
1768
|
logWarn(
|
|
805
1769
|
"conversation_compaction_summary_failed",
|
|
806
1770
|
{
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1771
|
+
messageConversationId: context.threadId,
|
|
1772
|
+
userId: context.actorId,
|
|
1773
|
+
destinationName: context.channelId,
|
|
810
1774
|
runId: context.runId,
|
|
811
1775
|
assistantUserName: botConfig.userName,
|
|
812
1776
|
modelId: botConfig.fastModelId
|
|
@@ -923,10 +1887,10 @@ function getConversationMessageSlackTs(message) {
|
|
|
923
1887
|
|
|
924
1888
|
// src/chat/conversations/messages.ts
|
|
925
1889
|
import { createHash } from "crypto";
|
|
926
|
-
import { isDeepStrictEqual as
|
|
1890
|
+
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
927
1891
|
|
|
928
1892
|
// src/chat/conversations/message-summaries.ts
|
|
929
|
-
import { isDeepStrictEqual } from "util";
|
|
1893
|
+
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
930
1894
|
function projectConversationMessageSummaries(events) {
|
|
931
1895
|
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
932
1896
|
const data = events[index]?.data;
|
|
@@ -940,7 +1904,7 @@ async function persistConversationMessageSummaries(args) {
|
|
|
940
1904
|
const eventStore = getConversationEventStore();
|
|
941
1905
|
const history = await eventStore.loadMessageHistory(args.conversationId);
|
|
942
1906
|
const existing = history.compaction ? projectConversationMessageSummaries([history.compaction]) : [];
|
|
943
|
-
if (
|
|
1907
|
+
if (isDeepStrictEqual2(existing, args.conversation.compactions)) {
|
|
944
1908
|
return;
|
|
945
1909
|
}
|
|
946
1910
|
const liveMessageIds = new Set(
|
|
@@ -1078,7 +2042,7 @@ async function persistConversationMessages(args) {
|
|
|
1078
2042
|
const events = args.conversation.messages.flatMap((message) => {
|
|
1079
2043
|
const stored = toStoredConversationMessage(message);
|
|
1080
2044
|
const existing = existingMessages.get(stored.messageId);
|
|
1081
|
-
const changed = existing !== void 0 && !
|
|
2045
|
+
const changed = existing !== void 0 && !isDeepStrictEqual3(toStoredConversationMessage(existing), stored);
|
|
1082
2046
|
const messageEvent = existing ? changed ? [
|
|
1083
2047
|
{
|
|
1084
2048
|
idempotencyKey: `message:${stored.messageId}:update:${messageStateKey(stored)}`,
|
|
@@ -1372,6 +2336,9 @@ function createChannelConfigurationService(storage) {
|
|
|
1372
2336
|
};
|
|
1373
2337
|
}
|
|
1374
2338
|
|
|
2339
|
+
// src/chat/state/ttl.ts
|
|
2340
|
+
var JUNIOR_THREAD_STATE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2341
|
+
|
|
1375
2342
|
// src/chat/runtime/thread-state.ts
|
|
1376
2343
|
function threadStateKey(threadId) {
|
|
1377
2344
|
return `thread-state:${threadId}`;
|
|
@@ -1565,6 +2532,15 @@ function isPendingAuthLatestRequest(conversation, pendingAuth) {
|
|
|
1565
2532
|
}
|
|
1566
2533
|
|
|
1567
2534
|
export {
|
|
2535
|
+
loadProjection,
|
|
2536
|
+
loadConversationProjection,
|
|
2537
|
+
openConversationProjection,
|
|
2538
|
+
loadConnectedMcpProviders,
|
|
2539
|
+
commitMessages,
|
|
2540
|
+
recordMcpProviderConnected,
|
|
2541
|
+
recordAuthorizationRequested,
|
|
2542
|
+
recordAuthorizationCompleted,
|
|
2543
|
+
recordToolExecutionStarted,
|
|
1568
2544
|
buildDeterministicTurnId,
|
|
1569
2545
|
buildDeterministicAssistantMessageId,
|
|
1570
2546
|
ConversationTurnBoundaryError,
|
|
@@ -1579,6 +2555,12 @@ export {
|
|
|
1579
2555
|
markTurnClosed,
|
|
1580
2556
|
markTurnCompleted,
|
|
1581
2557
|
markTurnFailed,
|
|
2558
|
+
getAgentTurnSessionRecord,
|
|
2559
|
+
getAgentTurnSessionRecordForResume,
|
|
2560
|
+
recordAgentTurnSessionSummary,
|
|
2561
|
+
listAgentTurnSessionSummariesForConversation,
|
|
2562
|
+
abandonAgentTurnSessionRecord,
|
|
2563
|
+
failAgentTurnSessionRecord,
|
|
1582
2564
|
persistWithRetry,
|
|
1583
2565
|
TurnSliceLimitExceededError,
|
|
1584
2566
|
buildTurnLimitResponse,
|
|
@@ -1590,11 +2572,13 @@ export {
|
|
|
1590
2572
|
persistContinuationSessionRecord,
|
|
1591
2573
|
persistYieldSessionRecord,
|
|
1592
2574
|
getInterruptionMarker,
|
|
2575
|
+
JUNIOR_THREAD_STATE_TTL_MS,
|
|
1593
2576
|
canReusePendingAuthLink,
|
|
1594
2577
|
getConversationPendingAuth,
|
|
1595
2578
|
clearPendingAuth,
|
|
1596
2579
|
abandonReplacedPendingAuth,
|
|
1597
2580
|
isPendingAuthLatestRequest,
|
|
2581
|
+
coerceThreadConversationState,
|
|
1598
2582
|
persistConversationMessageSummaries,
|
|
1599
2583
|
estimateTextTokens,
|
|
1600
2584
|
getAgentContextCompactionTriggerTokens,
|