@sentry/junior 0.140.0 → 0.142.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-BFTDRFUO.js → agent-hooks-WDJQQAPH.js} +10 -10
- package/dist/api/conversations/detail.d.ts +1 -0
- package/dist/api/conversations/event-list.d.ts +1 -0
- package/dist/api/schema/conversation.d.ts +4 -0
- package/dist/api/schema/task.d.ts +8 -0
- package/dist/api/schema.js +1 -1
- package/dist/api.js +35 -23
- package/dist/app.js +63 -92
- package/dist/{catalog-runtime-RK664S5T.js → catalog-runtime-CLHTYBHB.js} +5 -5
- package/dist/chat/agent/repository-context.d.ts +1 -0
- package/dist/chat/conversations/history.d.ts +2 -0
- package/dist/chat/conversations/projection.d.ts +8 -0
- package/dist/chat/conversations/store.d.ts +5 -0
- package/dist/chat/conversations/structured-events.d.ts +11 -0
- package/dist/chat/event-tasks/types.d.ts +7 -1
- package/dist/chat/runtime/thread-state.d.ts +3 -1
- package/dist/chat/runtime/turn.d.ts +0 -4
- package/dist/chat/scheduled-tasks/tools/create.d.ts +1 -0
- package/dist/chat/scheduled-tasks/types.d.ts +5 -0
- package/dist/chat/services/conversation-memory.d.ts +2 -1
- package/dist/chat/services/guardian-action-policy.d.ts +1 -1
- package/dist/chat/services/short-title.d.ts +25 -0
- package/dist/chat/state/conversation.d.ts +6 -17
- package/dist/chat/state/turn-session.d.ts +3 -4
- package/dist/chat/tools/create-event-task.d.ts +1 -0
- package/dist/{chunk-MYVCHWDG.js → chunk-4EZV6URQ.js} +107 -37
- package/dist/{chunk-557HLSNH.js → chunk-4L7PKEHM.js} +5 -1
- package/dist/{chunk-WTGLUX4K.js → chunk-5ITSZIAP.js} +1 -1
- package/dist/{chunk-3CUBAGA3.js → chunk-5QVVW3FY.js} +7 -7
- package/dist/{chunk-XX2QNQN4.js → chunk-6IMKBHCG.js} +81 -47
- package/dist/{chunk-3B7O3GNU.js → chunk-7R3CGEMF.js} +3 -3
- package/dist/{chunk-S3FAOKQU.js → chunk-A646AKNB.js} +29 -29
- package/dist/{chunk-BMFRFSTM.js → chunk-B2H7NI5C.js} +165 -535
- package/dist/{chunk-AA2EPMUF.js → chunk-CA4WLRA3.js} +4 -4
- package/dist/{chunk-D3X2PI3D.js → chunk-CBMIVCPM.js} +2 -2
- package/dist/chunk-DRTWANQF.js +67 -0
- package/dist/{chunk-CDQ4YIZM.js → chunk-HLXXQI5Q.js} +55 -1
- package/dist/{chunk-TKTZ4L4Z.js → chunk-HVTWCMDS.js} +1 -1
- package/dist/{chunk-CPPTBHQN.js → chunk-JIWZ7T4C.js} +1 -1
- package/dist/{chunk-UXMRN2ZX.js → chunk-LGY7YX5O.js} +1 -1
- package/dist/{chunk-YB363QGA.js → chunk-LL3BGP7J.js} +1 -1
- package/dist/{chunk-TGIKZJ3Y.js → chunk-LXLBYA6N.js} +2 -2
- package/dist/{chunk-XROWZSOY.js → chunk-N3H7G5K6.js} +1 -1
- package/dist/{chunk-J5H65GY2.js → chunk-NWO5IB7V.js} +1 -1
- package/dist/{chunk-YWM6MJT4.js → chunk-OGQGJAD7.js} +2 -0
- package/dist/{chunk-VRDHAITB.js → chunk-OQAPYAXH.js} +3 -3
- package/dist/{chunk-4PIT6O7A.js → chunk-PWDCFIQG.js} +6 -6
- package/dist/{chunk-OGNL2QY7.js → chunk-QDRMQI5W.js} +4 -4
- package/dist/{chunk-5KAZMR5U.js → chunk-R7E476CH.js} +6 -6
- package/dist/{chunk-HEFBGCCU.js → chunk-RYYBUI34.js} +2 -2
- package/dist/{chunk-WSWM6A3R.js → chunk-SCHH6264.js} +19 -3
- package/dist/{chunk-I3OZR3HG.js → chunk-SF6YKONJ.js} +1 -1
- package/dist/{chunk-DMDOKRPC.js → chunk-T4NFQ5SG.js} +5 -5
- package/dist/{chunk-5YAWB2AX.js → chunk-VJMBLWYR.js} +15 -17
- package/dist/{chunk-A6BI25J3.js → chunk-WJEW7UNC.js} +341 -16
- package/dist/{chunk-N2I7W2VS.js → chunk-WYLSMTWU.js} +1 -1
- package/dist/{chunk-NPL66ZWL.js → chunk-XAW6IN6M.js} +1 -1
- package/dist/chunk-XFHSZNOX.js +75 -0
- package/dist/{chunk-Z2A7BDHT.js → chunk-ZPNUI4L3.js} +23 -26
- package/dist/cli/chat.js +33 -31
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +13 -13
- package/dist/cli/snapshot-create.js +9 -9
- package/dist/cli/upgrade.js +7 -7
- package/dist/db/schema/event-tasks.d.ts +20 -52
- package/dist/db/schema/scheduled-tasks.d.ts +17 -0
- package/dist/db/schema.d.ts +36 -52
- package/dist/{db-QOGYDDQM.js → db-6N4CD5AI.js} +7 -7
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-CT4RMGCP.js → oauth-callback-server-G4K2X56R.js} +24 -22
- package/dist/{runner-PHMLHNLX.js → runner-DEIHVRUE.js} +25 -26
- package/dist/{skills-AYRM4QGF.js → skills-FZVJ6ZFW.js} +6 -6
- package/dist/spawn-WD4F67SZ.js +38 -0
- package/dist/{validation-M5JNGRGL.js → validation-EOLSG7B6.js} +6 -6
- package/dist/version.js +1 -1
- package/dist/{work-LZWE6HK4.js → work-AS3IBMLA.js} +17 -17
- package/dist/{worker-KOGPXFYK.js → worker-VGGNGOUU.js} +10 -10
- package/migrations/0023_task_title_columns.sql +2 -0
- package/migrations/meta/0023_snapshot.json +2198 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +4 -4
- package/dist/spawn-OGRQFUNK.js +0 -38
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
JUNIOR_NATIVE_EVENT_NAMESPACE,
|
|
6
6
|
ToolInputError,
|
|
7
7
|
addAgentTurnUsage,
|
|
8
|
-
|
|
8
|
+
agentsInstructionsUpdatedEvent,
|
|
9
9
|
authenticationLinkedEvent,
|
|
10
10
|
authenticationUnlinkedEvent
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-HLXXQI5Q.js";
|
|
12
12
|
import {
|
|
13
13
|
agentHistoryItemSchema,
|
|
14
14
|
bindProviderConversation,
|
|
@@ -21,35 +21,28 @@ import {
|
|
|
21
21
|
instructionProvenanceFor,
|
|
22
22
|
sanitizePostgresJson,
|
|
23
23
|
withConversationEventLock
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-SCHH6264.js";
|
|
25
25
|
import {
|
|
26
26
|
SANDBOX_WORKSPACE_ROOT,
|
|
27
27
|
sleep
|
|
28
28
|
} from "./chunk-EM225ITJ.js";
|
|
29
29
|
import {
|
|
30
30
|
getStateAdapter
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-NWO5IB7V.js";
|
|
32
32
|
import {
|
|
33
33
|
botConfig,
|
|
34
|
-
escapeXml,
|
|
35
|
-
resolveGatewayModel,
|
|
36
34
|
unwrapCurrentInstruction
|
|
37
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-A646AKNB.js";
|
|
38
36
|
import {
|
|
39
37
|
toStoredSlackActor
|
|
40
38
|
} from "./chunk-HZF5P5UN.js";
|
|
41
|
-
import {
|
|
42
|
-
parseSlackMessageTs
|
|
43
|
-
} from "./chunk-F3B2YJ76.js";
|
|
44
39
|
import {
|
|
45
40
|
getActiveTraceId,
|
|
46
41
|
isRecord,
|
|
47
42
|
logException,
|
|
48
|
-
logWarn,
|
|
49
|
-
setSpanAttributes,
|
|
50
43
|
toOptionalNumber,
|
|
51
44
|
toOptionalString
|
|
52
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-XAW6IN6M.js";
|
|
53
46
|
|
|
54
47
|
// src/chat/turn-context-tag.ts
|
|
55
48
|
var TURN_CONTEXT_TAG = "runtime-turn-context";
|
|
@@ -188,392 +181,6 @@ function stripRuntimeTurnContext(messages) {
|
|
|
188
181
|
});
|
|
189
182
|
}
|
|
190
183
|
|
|
191
|
-
// src/chat/services/context-budget.ts
|
|
192
|
-
var COMPACTION_TRIGGER_RATIO = 0.9;
|
|
193
|
-
var CONTEXT_INPUT_LIMIT_RATIO = 0.95;
|
|
194
|
-
var COMPACTION_TARGET_RATIO = 0.8;
|
|
195
|
-
var FALLBACK_CONTEXT_WINDOW_TOKENS = 4e5;
|
|
196
|
-
function positiveInteger(value, fallback) {
|
|
197
|
-
return Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
|
|
198
|
-
}
|
|
199
|
-
function estimateTextTokens(text) {
|
|
200
|
-
return Math.ceil(text.length / 4);
|
|
201
|
-
}
|
|
202
|
-
function calculateContextCompactionTriggerTokens(model) {
|
|
203
|
-
const contextWindow = positiveInteger(
|
|
204
|
-
model.contextWindow,
|
|
205
|
-
FALLBACK_CONTEXT_WINDOW_TOKENS
|
|
206
|
-
);
|
|
207
|
-
return Math.max(1, Math.floor(contextWindow * COMPACTION_TRIGGER_RATIO));
|
|
208
|
-
}
|
|
209
|
-
function calculateContextInputLimitTokens(model) {
|
|
210
|
-
const contextWindow = positiveInteger(
|
|
211
|
-
model.contextWindow,
|
|
212
|
-
FALLBACK_CONTEXT_WINDOW_TOKENS
|
|
213
|
-
);
|
|
214
|
-
return Math.max(1, Math.floor(contextWindow * CONTEXT_INPUT_LIMIT_RATIO));
|
|
215
|
-
}
|
|
216
|
-
function calculateContextCompactionTargetTokens(triggerTokens) {
|
|
217
|
-
return Math.max(1, Math.floor(triggerTokens * COMPACTION_TARGET_RATIO));
|
|
218
|
-
}
|
|
219
|
-
function getModelContextBudget(modelId) {
|
|
220
|
-
const model = resolveGatewayModel(modelId);
|
|
221
|
-
const advertisedContextWindow = positiveInteger(
|
|
222
|
-
model.contextWindow,
|
|
223
|
-
FALLBACK_CONTEXT_WINDOW_TOKENS
|
|
224
|
-
);
|
|
225
|
-
return {
|
|
226
|
-
contextWindow: Math.min(
|
|
227
|
-
botConfig.contextWindowTokens,
|
|
228
|
-
advertisedContextWindow
|
|
229
|
-
)
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
function getAgentContextCompactionTriggerTokens(modelId) {
|
|
233
|
-
return calculateContextCompactionTriggerTokens(
|
|
234
|
-
getModelContextBudget(modelId)
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
function getAgentContextInputLimitTokens(modelId) {
|
|
238
|
-
return calculateContextInputLimitTokens(getModelContextBudget(modelId));
|
|
239
|
-
}
|
|
240
|
-
function getConversationContextCompactionTriggerTokens() {
|
|
241
|
-
return calculateContextCompactionTriggerTokens(
|
|
242
|
-
getModelContextBudget(botConfig.fastModelId)
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// src/chat/services/conversation-memory.ts
|
|
247
|
-
var CONTEXT_MIN_LIVE_MESSAGES = 12;
|
|
248
|
-
var CONTEXT_COMPACTION_BATCH_SIZE = 24;
|
|
249
|
-
var CONTEXT_MAX_COMPACTIONS = 16;
|
|
250
|
-
var CONTEXT_MAX_MESSAGE_CHARS = 3200;
|
|
251
|
-
var SLACK_USER_ID_DISPLAY_PATTERN = /^[UW][A-Z0-9]{5,}$/;
|
|
252
|
-
function generateConversationId(prefix) {
|
|
253
|
-
return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
254
|
-
}
|
|
255
|
-
function normalizeConversationText(text) {
|
|
256
|
-
return text.replace(/\r\n?/g, "\n").trim();
|
|
257
|
-
}
|
|
258
|
-
function buildImageContextSuffix(message, conversation) {
|
|
259
|
-
const byFileId = conversation?.vision.byFileId;
|
|
260
|
-
const imageFileIds = message.meta?.imageFileIds ?? [];
|
|
261
|
-
if (!byFileId || imageFileIds.length === 0) {
|
|
262
|
-
return "";
|
|
263
|
-
}
|
|
264
|
-
const summaries = imageFileIds.map((fileId) => byFileId[fileId]?.summary?.trim()).filter((summary) => Boolean(summary));
|
|
265
|
-
if (summaries.length === 0) {
|
|
266
|
-
return "";
|
|
267
|
-
}
|
|
268
|
-
return ` [image context: ${summaries.join(" | ")}]`;
|
|
269
|
-
}
|
|
270
|
-
function renderConversationMessageLine(message, conversation) {
|
|
271
|
-
const displayName = conversationAuthorDisplayName(message);
|
|
272
|
-
const text = message.text.replace(/\s+/g, " ").slice(0, CONTEXT_MAX_MESSAGE_CHARS);
|
|
273
|
-
const markers = [];
|
|
274
|
-
if (message.meta?.replied === false) {
|
|
275
|
-
markers.push(
|
|
276
|
-
`assistant skipped: ${message.meta?.skippedReason ?? "no-reply route"}`
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
if (message.meta?.explicitMention) {
|
|
280
|
-
markers.push("explicit mention");
|
|
281
|
-
}
|
|
282
|
-
const markerSuffix = markers.length > 0 ? ` (${markers.join("; ")})` : "";
|
|
283
|
-
const imageContext = buildImageContextSuffix(message, conversation);
|
|
284
|
-
return `[${message.role}] ${displayName}: ${text}${imageContext}${markerSuffix}`;
|
|
285
|
-
}
|
|
286
|
-
function conversationAuthorDisplayName(message) {
|
|
287
|
-
const author = message.author;
|
|
288
|
-
const fullName = authorDisplayField(author?.fullName, author?.userId);
|
|
289
|
-
const userName = authorDisplayField(author?.userName, author?.userId);
|
|
290
|
-
return fullName ?? userName ?? (message.role === "assistant" ? botConfig.userName : message.role);
|
|
291
|
-
}
|
|
292
|
-
function authorDisplayField(value, userId) {
|
|
293
|
-
if (!value || value === userId || SLACK_USER_ID_DISPLAY_PATTERN.test(value)) {
|
|
294
|
-
return void 0;
|
|
295
|
-
}
|
|
296
|
-
return value;
|
|
297
|
-
}
|
|
298
|
-
function updateConversationStats(conversation) {
|
|
299
|
-
const contextText = buildConversationContext(conversation);
|
|
300
|
-
conversation.stats.estimatedContextTokens = estimateTextTokens(
|
|
301
|
-
contextText ?? ""
|
|
302
|
-
);
|
|
303
|
-
conversation.stats.totalMessageCount = conversation.messages.length;
|
|
304
|
-
conversation.stats.updatedAtMs = Date.now();
|
|
305
|
-
}
|
|
306
|
-
function upsertConversationMessage(conversation, message) {
|
|
307
|
-
const existingIndex = conversation.messages.findIndex(
|
|
308
|
-
(entry) => entry.id === message.id
|
|
309
|
-
);
|
|
310
|
-
if (existingIndex >= 0) {
|
|
311
|
-
conversation.messages[existingIndex] = {
|
|
312
|
-
...conversation.messages[existingIndex],
|
|
313
|
-
...message,
|
|
314
|
-
meta: {
|
|
315
|
-
...conversation.messages[existingIndex]?.meta,
|
|
316
|
-
...message.meta
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
updateConversationStats(conversation);
|
|
320
|
-
return message.id;
|
|
321
|
-
}
|
|
322
|
-
conversation.messages.push(message);
|
|
323
|
-
updateConversationStats(conversation);
|
|
324
|
-
return message.id;
|
|
325
|
-
}
|
|
326
|
-
function recordDeliveredAssistantMessage(args) {
|
|
327
|
-
const prefix = `${args.sessionId}:assistant:`;
|
|
328
|
-
const ordinal = args.conversation.messages.filter(
|
|
329
|
-
(message) => message.id.startsWith(prefix)
|
|
330
|
-
).length + 1;
|
|
331
|
-
const messageId = `${prefix}${ordinal}`;
|
|
332
|
-
markConversationMessage(args.conversation, args.userMessageId, {
|
|
333
|
-
replied: true,
|
|
334
|
-
skippedReason: void 0
|
|
335
|
-
});
|
|
336
|
-
upsertConversationMessage(args.conversation, {
|
|
337
|
-
id: messageId,
|
|
338
|
-
role: "assistant",
|
|
339
|
-
text: normalizeConversationText(args.text),
|
|
340
|
-
createdAtMs: Date.now(),
|
|
341
|
-
author: {
|
|
342
|
-
userName: botConfig.userName,
|
|
343
|
-
isBot: true
|
|
344
|
-
},
|
|
345
|
-
meta: {
|
|
346
|
-
replied: true
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
return messageId;
|
|
350
|
-
}
|
|
351
|
-
function turnHasReply(conversation, turnId) {
|
|
352
|
-
const assistantPrefix = `${turnId}:assistant:`;
|
|
353
|
-
return conversation.messages.some(
|
|
354
|
-
(message) => message.role === "assistant" && message.id.startsWith(assistantPrefix)
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
function markConversationMessage(conversation, messageId, patch) {
|
|
358
|
-
if (!messageId) return;
|
|
359
|
-
const messageIndex = conversation.messages.findIndex(
|
|
360
|
-
(entry) => entry.id === messageId
|
|
361
|
-
);
|
|
362
|
-
if (messageIndex < 0) return;
|
|
363
|
-
const current = conversation.messages[messageIndex];
|
|
364
|
-
conversation.messages[messageIndex] = {
|
|
365
|
-
...current,
|
|
366
|
-
meta: {
|
|
367
|
-
...current.meta ?? {},
|
|
368
|
-
...patch
|
|
369
|
-
}
|
|
370
|
-
};
|
|
371
|
-
updateConversationStats(conversation);
|
|
372
|
-
}
|
|
373
|
-
function buildConversationContext(conversation, options = {}) {
|
|
374
|
-
const messages = conversation.messages.filter(
|
|
375
|
-
(entry) => entry.id !== options.excludeMessageId
|
|
376
|
-
);
|
|
377
|
-
if (messages.length === 0 && conversation.compactions.length === 0) {
|
|
378
|
-
return void 0;
|
|
379
|
-
}
|
|
380
|
-
const lines = [];
|
|
381
|
-
if (conversation.compactions.length > 0) {
|
|
382
|
-
lines.push("<thread-compactions>");
|
|
383
|
-
for (const [index, compaction] of conversation.compactions.entries()) {
|
|
384
|
-
lines.push(
|
|
385
|
-
` <compaction index="${index + 1}" covered_messages="${compaction.coveredMessageCount}" created_at="${new Date(compaction.createdAtMs).toISOString()}">`,
|
|
386
|
-
compaction.summary,
|
|
387
|
-
" </compaction>"
|
|
388
|
-
);
|
|
389
|
-
}
|
|
390
|
-
lines.push("</thread-compactions>");
|
|
391
|
-
}
|
|
392
|
-
if (messages.length > 0) {
|
|
393
|
-
if (lines.length > 0) {
|
|
394
|
-
lines.push("");
|
|
395
|
-
}
|
|
396
|
-
lines.push("<thread-transcript>");
|
|
397
|
-
for (const [index, message] of messages.entries()) {
|
|
398
|
-
const author = escapeXml(conversationAuthorDisplayName(message));
|
|
399
|
-
const actorIdAttr = message.author?.userId ? ` actor_id="${escapeXml(message.author.userId)}"` : "";
|
|
400
|
-
const ts = new Date(message.createdAtMs).toISOString();
|
|
401
|
-
const slackTsAttr = message.meta?.slackTs ? ` slack_ts="${escapeXml(message.meta.slackTs)}"` : "";
|
|
402
|
-
lines.push(
|
|
403
|
-
` <message index="${index + 1}" ts="${ts}" role="${message.role}" author="${author}"${actorIdAttr}${slackTsAttr}>`,
|
|
404
|
-
renderConversationMessageLine(message, conversation),
|
|
405
|
-
" </message>"
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
lines.push("</thread-transcript>");
|
|
409
|
-
}
|
|
410
|
-
return lines.join("\n");
|
|
411
|
-
}
|
|
412
|
-
function pruneCompactions(compactions) {
|
|
413
|
-
if (compactions.length <= CONTEXT_MAX_COMPACTIONS) {
|
|
414
|
-
return compactions;
|
|
415
|
-
}
|
|
416
|
-
const overflowCount = compactions.length - CONTEXT_MAX_COMPACTIONS + 1;
|
|
417
|
-
const merged = compactions.slice(0, overflowCount);
|
|
418
|
-
const mergedSummary = merged.map((entry) => entry.summary).join("\n").slice(0, 3500);
|
|
419
|
-
const coveredMessageCount = merged.reduce(
|
|
420
|
-
(count, entry) => count + entry.coveredMessageCount,
|
|
421
|
-
0
|
|
422
|
-
);
|
|
423
|
-
const compacted = {
|
|
424
|
-
id: generateConversationId("compaction"),
|
|
425
|
-
createdAtMs: Date.now(),
|
|
426
|
-
summary: mergedSummary,
|
|
427
|
-
coveredMessageCount
|
|
428
|
-
};
|
|
429
|
-
return [compacted, ...compactions.slice(overflowCount)];
|
|
430
|
-
}
|
|
431
|
-
async function summarizeConversationChunk(messages, conversation, context, deps) {
|
|
432
|
-
const transcript = messages.map((message) => renderConversationMessageLine(message, conversation)).join("\n");
|
|
433
|
-
try {
|
|
434
|
-
const result = await deps.completeText({
|
|
435
|
-
modelId: botConfig.fastModelId,
|
|
436
|
-
temperature: 0,
|
|
437
|
-
messages: [
|
|
438
|
-
{
|
|
439
|
-
role: "user",
|
|
440
|
-
content: [
|
|
441
|
-
"Summarize the following older Slack thread transcript segment for future assistant turns.",
|
|
442
|
-
"Keep the summary factual and concise. Do not invent details.",
|
|
443
|
-
"",
|
|
444
|
-
"Output exactly three XML sections in this order:",
|
|
445
|
-
"<active-asks> one bullet per outstanding user ask that has not been narrowed, answered, or replaced by a later turn. Omit the section body if none. </active-asks>",
|
|
446
|
-
"<resolved-or-replaced-asks> one bullet per ask that has been replaced, narrowed, answered, or already acted on in this segment. Include the replacement/outcome inline. Omit the section body if none. </resolved-or-replaced-asks>",
|
|
447
|
-
"<facts> one bullet per durable fact useful regardless of scope: names, ids, URLs, decisions, locations, preferences, constraints that remain true. Omit the section body if none. </facts>",
|
|
448
|
-
"",
|
|
449
|
-
"Do not output any text outside the three sections.",
|
|
450
|
-
"",
|
|
451
|
-
transcript
|
|
452
|
-
].join("\n"),
|
|
453
|
-
timestamp: Date.now()
|
|
454
|
-
}
|
|
455
|
-
],
|
|
456
|
-
metadata: {
|
|
457
|
-
modelId: botConfig.fastModelId,
|
|
458
|
-
threadId: context.threadId ?? "",
|
|
459
|
-
channelId: context.channelId ?? "",
|
|
460
|
-
actorId: context.actorId ?? "",
|
|
461
|
-
runId: context.runId ?? ""
|
|
462
|
-
}
|
|
463
|
-
});
|
|
464
|
-
const summary = result.text.trim();
|
|
465
|
-
if (summary.length > 0) {
|
|
466
|
-
return summary.slice(0, 3500);
|
|
467
|
-
}
|
|
468
|
-
} catch (error) {
|
|
469
|
-
logWarn("conversation.compaction.summary.failed", {
|
|
470
|
-
"exception.message": error instanceof Error ? error.message : String(error),
|
|
471
|
-
"app.compaction_messages_covered": messages.length
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
return transcript.slice(0, 2800);
|
|
475
|
-
}
|
|
476
|
-
async function generateThreadTitleWithDeps(sourceText, deps) {
|
|
477
|
-
const result = await deps.completeText({
|
|
478
|
-
modelId: botConfig.fastModelId,
|
|
479
|
-
temperature: 0,
|
|
480
|
-
messages: [
|
|
481
|
-
{
|
|
482
|
-
role: "user",
|
|
483
|
-
content: [
|
|
484
|
-
"Generate a concise 5-8 word Slack conversation title from the first user message below.",
|
|
485
|
-
"Capture the user's main request.",
|
|
486
|
-
"Reply with ONLY the title, with no quotes or trailing punctuation.",
|
|
487
|
-
"",
|
|
488
|
-
`First user message: ${sourceText.slice(0, 500)}`
|
|
489
|
-
].join("\n"),
|
|
490
|
-
timestamp: Date.now()
|
|
491
|
-
}
|
|
492
|
-
],
|
|
493
|
-
metadata: {
|
|
494
|
-
modelId: botConfig.fastModelId
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
return result.text.trim().slice(0, 60);
|
|
498
|
-
}
|
|
499
|
-
function getThreadTitleSourceMessage(conversation) {
|
|
500
|
-
let firstMessage;
|
|
501
|
-
for (const message of conversation.messages) {
|
|
502
|
-
if (!isHumanConversationMessage(message)) {
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
if (!firstMessage) {
|
|
506
|
-
firstMessage = message;
|
|
507
|
-
continue;
|
|
508
|
-
}
|
|
509
|
-
if (message.createdAtMs < firstMessage.createdAtMs) {
|
|
510
|
-
firstMessage = message;
|
|
511
|
-
continue;
|
|
512
|
-
}
|
|
513
|
-
if (message.createdAtMs === firstMessage.createdAtMs && message.id < firstMessage.id) {
|
|
514
|
-
firstMessage = message;
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
return firstMessage;
|
|
518
|
-
}
|
|
519
|
-
async function compactConversationIfNeededWithDeps(conversation, context, deps) {
|
|
520
|
-
updateConversationStats(conversation);
|
|
521
|
-
let estimatedTokens = conversation.stats.estimatedContextTokens;
|
|
522
|
-
setSpanAttributes({
|
|
523
|
-
"app.context_tokens_estimated": estimatedTokens
|
|
524
|
-
});
|
|
525
|
-
const triggerTokens = getConversationContextCompactionTriggerTokens();
|
|
526
|
-
const targetTokens = calculateContextCompactionTargetTokens(triggerTokens);
|
|
527
|
-
while (estimatedTokens > triggerTokens && conversation.messages.length > CONTEXT_MIN_LIVE_MESSAGES) {
|
|
528
|
-
const compactCount = Math.min(
|
|
529
|
-
CONTEXT_COMPACTION_BATCH_SIZE,
|
|
530
|
-
conversation.messages.length - CONTEXT_MIN_LIVE_MESSAGES
|
|
531
|
-
);
|
|
532
|
-
if (compactCount <= 0) {
|
|
533
|
-
break;
|
|
534
|
-
}
|
|
535
|
-
const compactedChunk = conversation.messages.slice(0, compactCount);
|
|
536
|
-
const summary = await summarizeConversationChunk(
|
|
537
|
-
compactedChunk,
|
|
538
|
-
conversation,
|
|
539
|
-
context,
|
|
540
|
-
deps
|
|
541
|
-
);
|
|
542
|
-
conversation.compactions.push({
|
|
543
|
-
id: generateConversationId("compaction"),
|
|
544
|
-
createdAtMs: Date.now(),
|
|
545
|
-
summary,
|
|
546
|
-
coveredMessageCount: compactedChunk.length
|
|
547
|
-
});
|
|
548
|
-
conversation.compactions = pruneCompactions(conversation.compactions);
|
|
549
|
-
conversation.messages = conversation.messages.slice(compactCount);
|
|
550
|
-
conversation.stats.compactedMessageCount += compactCount;
|
|
551
|
-
updateConversationStats(conversation);
|
|
552
|
-
estimatedTokens = conversation.stats.estimatedContextTokens;
|
|
553
|
-
setSpanAttributes({
|
|
554
|
-
"app.compaction_messages_covered": compactCount,
|
|
555
|
-
"app.compaction.trigger_tokens": triggerTokens,
|
|
556
|
-
"app.compaction.target_tokens": targetTokens,
|
|
557
|
-
"app.context_tokens_estimated": estimatedTokens
|
|
558
|
-
});
|
|
559
|
-
if (estimatedTokens <= targetTokens) {
|
|
560
|
-
break;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
function createConversationMemoryService(deps) {
|
|
565
|
-
return {
|
|
566
|
-
compactConversationIfNeeded: async (conversation, context) => await compactConversationIfNeededWithDeps(conversation, context, deps),
|
|
567
|
-
generateThreadTitle: async (sourceText) => await generateThreadTitleWithDeps(sourceText, deps)
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
function isHumanConversationMessage(message) {
|
|
571
|
-
return message.role === "user" && message.author?.isBot !== true;
|
|
572
|
-
}
|
|
573
|
-
function getConversationMessageSlackTs(message) {
|
|
574
|
-
return parseSlackMessageTs(message.meta?.slackTs);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
184
|
// src/chat/conversations/messages.ts
|
|
578
185
|
import { createHash } from "crypto";
|
|
579
186
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
@@ -714,7 +321,6 @@ async function hydrateConversationMessages(args) {
|
|
|
714
321
|
);
|
|
715
322
|
args.conversation.compactions = history.compaction ? projectConversationMessageSummaries([history.compaction]) : [];
|
|
716
323
|
args.conversation.messages = projectConversationMessages(history);
|
|
717
|
-
updateConversationStats(args.conversation);
|
|
718
324
|
}
|
|
719
325
|
async function persistConversationMessages(args) {
|
|
720
326
|
if (!args.conversationId || args.conversation.messages.length === 0) return;
|
|
@@ -1214,6 +820,59 @@ async function recordAuthenticationAccountChange(action, args) {
|
|
|
1214
820
|
async function recordAuthenticationLinked(args) {
|
|
1215
821
|
await recordAuthenticationAccountChange("linked", args);
|
|
1216
822
|
}
|
|
823
|
+
async function loadAgentsEvent(conversationId) {
|
|
824
|
+
const event = await getConversationEventStore().loadLatestStructuredEvent(
|
|
825
|
+
conversationId,
|
|
826
|
+
JUNIOR_NATIVE_EVENT_NAMESPACE,
|
|
827
|
+
agentsInstructionsUpdatedEvent.eventName
|
|
828
|
+
);
|
|
829
|
+
if (!event || event.data.type !== "structured_event") return void 0;
|
|
830
|
+
return {
|
|
831
|
+
content: agentsInstructionsUpdatedEvent.parse(
|
|
832
|
+
event.data.content
|
|
833
|
+
),
|
|
834
|
+
seq: event.seq
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
function agentsInstructionsIdempotencyKey(args) {
|
|
838
|
+
const previous = args.previousSeq ?? "none";
|
|
839
|
+
return `native:${JUNIOR_NATIVE_EVENT_NAMESPACE}:agents_instructions_updated:${args.turnId}:${args.action}:${previous}->${args.fingerprint}`;
|
|
840
|
+
}
|
|
841
|
+
async function recordAgentsInstructionsUpdated(args) {
|
|
842
|
+
const previous = await loadAgentsEvent(args.conversationId);
|
|
843
|
+
const instructions = args.instructions;
|
|
844
|
+
if (previous && (!instructions && previous.content.action === "cleared" || instructions && previous.content.action !== "cleared" && previous.content.fingerprint === instructions.fingerprint && previous.content.directory === instructions.directory)) {
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
const action = !instructions ? "cleared" : previous && previous.content.action !== "cleared" ? "replaced" : "loaded";
|
|
848
|
+
const fingerprint = instructions?.fingerprint ?? "cleared";
|
|
849
|
+
const content = agentsInstructionsUpdatedEvent.parse({
|
|
850
|
+
action,
|
|
851
|
+
fingerprint,
|
|
852
|
+
sources: instructions?.sources ?? [],
|
|
853
|
+
...instructions ? { directory: instructions.directory } : {},
|
|
854
|
+
...instructions ? { textBytes: Buffer.byteLength(instructions.text, "utf8") } : {}
|
|
855
|
+
});
|
|
856
|
+
await getConversationEventStore().append(args.conversationId, [
|
|
857
|
+
{
|
|
858
|
+
createdAtMs: Date.now(),
|
|
859
|
+
idempotencyKey: agentsInstructionsIdempotencyKey({
|
|
860
|
+
action,
|
|
861
|
+
fingerprint,
|
|
862
|
+
previousSeq: previous?.seq,
|
|
863
|
+
turnId: args.turnId
|
|
864
|
+
}),
|
|
865
|
+
data: {
|
|
866
|
+
type: "structured_event",
|
|
867
|
+
namespace: JUNIOR_NATIVE_EVENT_NAMESPACE,
|
|
868
|
+
name: agentsInstructionsUpdatedEvent.eventName,
|
|
869
|
+
version: agentsInstructionsUpdatedEvent.version,
|
|
870
|
+
turnId: args.turnId,
|
|
871
|
+
content
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
]);
|
|
875
|
+
}
|
|
1217
876
|
async function loadTurnRoute(args) {
|
|
1218
877
|
const event = await getConversationEventStore().loadByIdempotencyKey(
|
|
1219
878
|
args.conversationId,
|
|
@@ -1334,7 +993,6 @@ function isTurnInputDeferredError(error) {
|
|
|
1334
993
|
}
|
|
1335
994
|
function startActiveTurn(args) {
|
|
1336
995
|
args.conversation.processing.activeTurnId = args.nextTurnId;
|
|
1337
|
-
args.updateConversationStats(args.conversation);
|
|
1338
996
|
}
|
|
1339
997
|
function clearActiveTurn(conversation, sessionId) {
|
|
1340
998
|
if (!sessionId || conversation.processing.activeTurnId === sessionId) {
|
|
@@ -1344,12 +1002,10 @@ function clearActiveTurn(conversation, sessionId) {
|
|
|
1344
1002
|
function markTurnClosed(args) {
|
|
1345
1003
|
clearActiveTurn(args.conversation, args.sessionId);
|
|
1346
1004
|
args.conversation.processing.lastCompletedAtMs = args.nowMs;
|
|
1347
|
-
args.updateConversationStats(args.conversation);
|
|
1348
1005
|
}
|
|
1349
1006
|
function markTurnCompleted(args) {
|
|
1350
1007
|
clearActiveTurn(args.conversation, args.sessionId);
|
|
1351
1008
|
args.conversation.processing.lastCompletedAtMs = args.nowMs;
|
|
1352
|
-
args.updateConversationStats(args.conversation);
|
|
1353
1009
|
}
|
|
1354
1010
|
function markTurnFailed(args) {
|
|
1355
1011
|
clearActiveTurn(args.conversation, args.sessionId);
|
|
@@ -1358,7 +1014,6 @@ function markTurnFailed(args) {
|
|
|
1358
1014
|
replied: false,
|
|
1359
1015
|
skippedReason: "reply failed"
|
|
1360
1016
|
});
|
|
1361
|
-
args.updateConversationStats(args.conversation);
|
|
1362
1017
|
}
|
|
1363
1018
|
|
|
1364
1019
|
// src/chat/no-reply.ts
|
|
@@ -1402,9 +1057,6 @@ function getAssistantReplyText(message) {
|
|
|
1402
1057
|
}
|
|
1403
1058
|
|
|
1404
1059
|
// src/chat/state/turn-session.ts
|
|
1405
|
-
import {
|
|
1406
|
-
actorSchema
|
|
1407
|
-
} from "@sentry/junior-plugin-api";
|
|
1408
1060
|
import { z as z2 } from "zod";
|
|
1409
1061
|
|
|
1410
1062
|
// src/chat/repository-instructions.ts
|
|
@@ -1420,7 +1072,7 @@ var RIPGREP_EXCLUDED_GLOBS = [
|
|
|
1420
1072
|
];
|
|
1421
1073
|
var DEFAULT_SEARCH_COMMAND_TIMEOUT_MS = 3e4;
|
|
1422
1074
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
1423
|
-
function
|
|
1075
|
+
function positiveInteger(value) {
|
|
1424
1076
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
1425
1077
|
return void 0;
|
|
1426
1078
|
}
|
|
@@ -1767,6 +1419,9 @@ function agentTurnSessionConversationIndexKey(conversationId) {
|
|
|
1767
1419
|
// src/chat/state/turn-session.ts
|
|
1768
1420
|
var AGENT_TURN_SESSION_RESUME_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1769
1421
|
var AGENT_TURN_SESSION_TERMINAL_TTL_MS = 60 * 60 * 1e3;
|
|
1422
|
+
function executionMetricsForSession(conversation, sessionId) {
|
|
1423
|
+
return conversation?.executionMetrics?.runId === sessionId ? conversation.executionMetrics : void 0;
|
|
1424
|
+
}
|
|
1770
1425
|
function definedProps(values) {
|
|
1771
1426
|
return Object.fromEntries(
|
|
1772
1427
|
Object.entries(values).filter(([, value]) => value !== void 0)
|
|
@@ -1807,18 +1462,12 @@ var agentTurnSessionSummarySchema = z2.object({
|
|
|
1807
1462
|
updatedAtMs: nonNegativeNumberSchema
|
|
1808
1463
|
}).strip();
|
|
1809
1464
|
var storedAgentTurnSessionRecordSchema = z2.object({
|
|
1810
|
-
channelName: z2.string().min(1).optional(),
|
|
1811
1465
|
version: z2.number().int().nonnegative(),
|
|
1812
1466
|
conversationId: z2.string().min(1),
|
|
1813
|
-
cumulativeDurationMs: nonNegativeNumberSchema,
|
|
1814
|
-
cumulativeUsage: agentTurnUsageSchema.optional(),
|
|
1815
1467
|
dispatchId: z2.string().min(1).optional(),
|
|
1816
1468
|
dispatchOutcome: z2.enum(["blocked", "completed", "failed"]).optional(),
|
|
1817
1469
|
resultMessageId: z2.string().min(1).optional(),
|
|
1818
1470
|
lastProgressAtMs: nonNegativeNumberSchema,
|
|
1819
|
-
loadedSkillNames: z2.array(z2.string()).optional(),
|
|
1820
|
-
modelId: z2.string().min(1).optional(),
|
|
1821
|
-
reasoningLevel: z2.string().min(1).optional(),
|
|
1822
1471
|
resumeReason: agentTurnResumeReasonSchema.optional(),
|
|
1823
1472
|
resumedFromSliceId: z2.number().int().nonnegative().optional(),
|
|
1824
1473
|
sessionId: z2.string().min(1),
|
|
@@ -1828,7 +1477,6 @@ var storedAgentTurnSessionRecordSchema = z2.object({
|
|
|
1828
1477
|
surface: agentTurnSurfaceSchema.optional(),
|
|
1829
1478
|
traceId: z2.string().optional(),
|
|
1830
1479
|
updatedAtMs: nonNegativeNumberSchema,
|
|
1831
|
-
actors: z2.array(actorSchema).optional(),
|
|
1832
1480
|
committedSeq: seqCursorSchema,
|
|
1833
1481
|
historyVersion: z2.number().int().nonnegative().optional(),
|
|
1834
1482
|
errorMessage: z2.string().optional(),
|
|
@@ -1908,7 +1556,7 @@ async function recordConversationActivityMetadata(args) {
|
|
|
1908
1556
|
visibility: isChild ? void 0 : args.destinationVisibility
|
|
1909
1557
|
});
|
|
1910
1558
|
}
|
|
1911
|
-
function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessageIndex, restoreVolatileContext = true) {
|
|
1559
|
+
function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessageIndex, restoreVolatileContext = true, runtimeMetadata) {
|
|
1912
1560
|
const restoredProjection = restoreVolatileContext && (stored.state === "running" || stored.state === "awaiting_resume") ? restoreRuntimeContext(piProjection, stored.runtimeContext) : piProjection;
|
|
1913
1561
|
return {
|
|
1914
1562
|
version: stored.version,
|
|
@@ -1921,17 +1569,17 @@ function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessag
|
|
|
1921
1569
|
updatedAtMs: stored.updatedAtMs,
|
|
1922
1570
|
piMessages: restoredProjection.messages,
|
|
1923
1571
|
piMessageProvenance: restoredProjection.provenance,
|
|
1924
|
-
actors:
|
|
1925
|
-
cumulativeDurationMs:
|
|
1572
|
+
actors: instructionActors(piProjection.provenance),
|
|
1573
|
+
cumulativeDurationMs: runtimeMetadata?.cumulativeDurationMs ?? 0,
|
|
1926
1574
|
...definedProps({
|
|
1927
|
-
channelName:
|
|
1928
|
-
cumulativeUsage:
|
|
1575
|
+
channelName: runtimeMetadata?.channelName,
|
|
1576
|
+
cumulativeUsage: runtimeMetadata?.cumulativeUsage,
|
|
1577
|
+
loadedSkillNames: runtimeMetadata?.loadedSkillNames,
|
|
1578
|
+
modelId: runtimeMetadata?.modelId,
|
|
1579
|
+
reasoningLevel: runtimeMetadata?.reasoningLevel,
|
|
1929
1580
|
dispatchId: stored.dispatchId,
|
|
1930
1581
|
dispatchOutcome: stored.dispatchOutcome,
|
|
1931
1582
|
errorMessage: stored.errorMessage,
|
|
1932
|
-
loadedSkillNames: stored.loadedSkillNames,
|
|
1933
|
-
modelId: stored.modelId,
|
|
1934
|
-
reasoningLevel: stored.reasoningLevel,
|
|
1935
1583
|
resumeReason: stored.resumeReason,
|
|
1936
1584
|
resultMessageId: stored.resultMessageId,
|
|
1937
1585
|
resumedFromSliceId: stored.resumedFromSliceId,
|
|
@@ -2008,11 +1656,18 @@ async function materializeStoredAgentTurnSessionRecord(conversationId, sessionId
|
|
|
2008
1656
|
const followsReplacement = followCurrentReplacement && (parsed.state === "running" || parsed.state === "awaiting_resume") && parsed.historyVersion !== void 0 && parsed.historyVersion !== currentHistoryVersion;
|
|
2009
1657
|
const piProjection = followsReplacement ? projectConversationEvents(currentHistory) : pinnedProjection;
|
|
2010
1658
|
const turnStartMessageIndex = followsReplacement ? 0 : parsed.turnStartSeq === void 0 ? void 0 : piProjection.seqs.filter((seq) => seq <= parsed.turnStartSeq).length;
|
|
1659
|
+
const conversation = await getConversationStore().get({ conversationId });
|
|
1660
|
+
const executionMetrics = executionMetricsForSession(conversation, sessionId);
|
|
2011
1661
|
return materializeAgentTurnSessionRecord(
|
|
2012
1662
|
parsed,
|
|
2013
1663
|
piProjection,
|
|
2014
1664
|
turnStartMessageIndex,
|
|
2015
|
-
!followsReplacement && (parsed.historyVersion === void 0 || parsed.historyVersion === currentHistoryVersion)
|
|
1665
|
+
!followsReplacement && (parsed.historyVersion === void 0 || parsed.historyVersion === currentHistoryVersion),
|
|
1666
|
+
{
|
|
1667
|
+
channelName: conversation?.channelName,
|
|
1668
|
+
cumulativeDurationMs: executionMetrics?.durationMs,
|
|
1669
|
+
cumulativeUsage: executionMetrics?.usage
|
|
1670
|
+
}
|
|
2016
1671
|
);
|
|
2017
1672
|
}
|
|
2018
1673
|
async function getAgentTurnSessionRecord(conversationId, sessionId) {
|
|
@@ -2041,18 +1696,11 @@ function buildStoredRecord(args) {
|
|
|
2041
1696
|
lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
|
|
2042
1697
|
updatedAtMs: nowMs,
|
|
2043
1698
|
committedSeq: args.committedSeq,
|
|
2044
|
-
cumulativeDurationMs: args.cumulativeDurationMs,
|
|
2045
1699
|
...definedProps({
|
|
2046
|
-
actors: args.actors,
|
|
2047
|
-
channelName: args.channelName,
|
|
2048
|
-
cumulativeUsage: args.cumulativeUsage,
|
|
2049
1700
|
dispatchId: args.dispatchId,
|
|
2050
1701
|
dispatchOutcome: args.dispatchOutcome,
|
|
2051
1702
|
errorMessage: args.errorMessage,
|
|
2052
1703
|
historyVersion: args.historyVersion,
|
|
2053
|
-
loadedSkillNames: args.loadedSkillNames,
|
|
2054
|
-
modelId: args.modelId,
|
|
2055
|
-
reasoningLevel: args.reasoningLevel,
|
|
2056
1704
|
resumeReason: args.resumeReason,
|
|
2057
1705
|
resultMessageId: args.resultMessageId,
|
|
2058
1706
|
resumedFromSliceId: args.resumedFromSliceId,
|
|
@@ -2074,7 +1722,7 @@ async function setStoredRecord(args) {
|
|
|
2074
1722
|
destinationVisibility: args.destinationVisibility,
|
|
2075
1723
|
nowMs: Date.now(),
|
|
2076
1724
|
source: args.source,
|
|
2077
|
-
summary: storedRecord
|
|
1725
|
+
summary: { ...storedRecord, ...args.runtimeMetadata }
|
|
2078
1726
|
});
|
|
2079
1727
|
await stateAdapter.set(
|
|
2080
1728
|
agentTurnSessionKey(storedRecord.conversationId, storedRecord.sessionId),
|
|
@@ -2091,7 +1739,9 @@ async function setStoredRecord(args) {
|
|
|
2091
1739
|
messages: [...args.piMessages],
|
|
2092
1740
|
provenance: [...args.piMessageProvenance]
|
|
2093
1741
|
},
|
|
2094
|
-
args.turnStartMessageIndex
|
|
1742
|
+
args.turnStartMessageIndex,
|
|
1743
|
+
true,
|
|
1744
|
+
args.runtimeMetadata
|
|
2095
1745
|
);
|
|
2096
1746
|
}
|
|
2097
1747
|
async function updateAgentTurnSessionState(args) {
|
|
@@ -2106,6 +1756,16 @@ async function updateAgentTurnSessionState(args) {
|
|
|
2106
1756
|
piMessages: args.existing.piMessages,
|
|
2107
1757
|
piMessageProvenance: args.existing.piMessageProvenance,
|
|
2108
1758
|
ttlMs: agentTurnSessionRecordTtlMs(args.state),
|
|
1759
|
+
runtimeMetadata: {
|
|
1760
|
+
cumulativeDurationMs: args.existing.cumulativeDurationMs,
|
|
1761
|
+
...definedProps({
|
|
1762
|
+
channelName: args.existing.channelName,
|
|
1763
|
+
cumulativeUsage: args.existing.cumulativeUsage,
|
|
1764
|
+
loadedSkillNames: args.existing.loadedSkillNames,
|
|
1765
|
+
modelId: args.existing.modelId,
|
|
1766
|
+
reasoningLevel: args.existing.reasoningLevel
|
|
1767
|
+
})
|
|
1768
|
+
},
|
|
2109
1769
|
...definedProps({
|
|
2110
1770
|
turnStartMessageIndex: args.existing.turnStartMessageIndex
|
|
2111
1771
|
}),
|
|
@@ -2118,18 +1778,11 @@ async function updateAgentTurnSessionState(args) {
|
|
|
2118
1778
|
startedAtMs: parsed.startedAtMs,
|
|
2119
1779
|
lastProgressAtMs: parsed.lastProgressAtMs,
|
|
2120
1780
|
previousVersion: parsed.version,
|
|
2121
|
-
cumulativeDurationMs: args.existing.cumulativeDurationMs,
|
|
2122
|
-
actors: args.existing.actors,
|
|
2123
1781
|
...definedProps({
|
|
2124
|
-
channelName: parsed.channelName,
|
|
2125
|
-
cumulativeUsage: args.existing.cumulativeUsage,
|
|
2126
1782
|
dispatchId: args.existing.dispatchId,
|
|
2127
1783
|
dispatchOutcome: args.existing.dispatchOutcome,
|
|
2128
1784
|
errorMessage: args.errorMessage ?? args.existing.errorMessage,
|
|
2129
1785
|
historyVersion: parsed.historyVersion,
|
|
2130
|
-
loadedSkillNames: args.existing.loadedSkillNames,
|
|
2131
|
-
modelId: args.existing.modelId,
|
|
2132
|
-
reasoningLevel: args.existing.reasoningLevel,
|
|
2133
1786
|
resumeReason: args.existing.resumeReason,
|
|
2134
1787
|
resultMessageId: args.existing.resultMessageId,
|
|
2135
1788
|
resumedFromSliceId: args.existing.resumedFromSliceId,
|
|
@@ -2145,6 +1798,13 @@ async function upsertAgentTurnSessionRecord(args) {
|
|
|
2145
1798
|
args.conversationId,
|
|
2146
1799
|
args.sessionId
|
|
2147
1800
|
);
|
|
1801
|
+
const conversation = await (args.conversationStore ?? getConversationStore()).get({
|
|
1802
|
+
conversationId: args.conversationId
|
|
1803
|
+
});
|
|
1804
|
+
const executionMetrics = executionMetricsForSession(
|
|
1805
|
+
conversation,
|
|
1806
|
+
args.sessionId
|
|
1807
|
+
);
|
|
2148
1808
|
const existingDispatchId = existingRecord?.dispatchId ?? (await listAgentTurnSessionSummariesForConversation(args.conversationId)).find((summary) => summary.sessionId === args.sessionId)?.dispatchId;
|
|
2149
1809
|
if (existingDispatchId && args.dispatchId && existingDispatchId !== args.dispatchId) {
|
|
2150
1810
|
throw new Error(
|
|
@@ -2181,6 +1841,16 @@ async function upsertAgentTurnSessionRecord(args) {
|
|
|
2181
1841
|
piMessages: commit.messages,
|
|
2182
1842
|
piMessageProvenance: commit.provenance,
|
|
2183
1843
|
ttlMs,
|
|
1844
|
+
// TODO(#1267): remove the temporary caller-to-SQL metadata write once the
|
|
1845
|
+
// SQL-only turn-session readers have completed rollout.
|
|
1846
|
+
runtimeMetadata: {
|
|
1847
|
+
channelName: args.channelName ?? conversation?.channelName,
|
|
1848
|
+
cumulativeDurationMs: args.cumulativeDurationMs ?? executionMetrics?.durationMs ?? 0,
|
|
1849
|
+
cumulativeUsage: args.cumulativeUsage ?? executionMetrics?.usage,
|
|
1850
|
+
loadedSkillNames: args.loadedSkillNames,
|
|
1851
|
+
modelId: args.modelId,
|
|
1852
|
+
reasoningLevel: args.reasoningLevel
|
|
1853
|
+
},
|
|
2184
1854
|
// Pass through only an explicit override so indexes stay on the resume window
|
|
2185
1855
|
// by default even when the record takes a short terminal TTL.
|
|
2186
1856
|
...definedProps({ indexTtlMs: args.ttlMs }),
|
|
@@ -2193,22 +1863,11 @@ async function upsertAgentTurnSessionRecord(args) {
|
|
|
2193
1863
|
committedSeq: commit.committedSeq,
|
|
2194
1864
|
historyVersion: commit.historyVersion,
|
|
2195
1865
|
previousVersion: existingRecord?.version,
|
|
2196
|
-
cumulativeDurationMs: args.cumulativeDurationMs ?? existingRecord?.cumulativeDurationMs ?? 0,
|
|
2197
|
-
modelId: args.modelId,
|
|
2198
|
-
actors: instructionActors([
|
|
2199
|
-
...(existingRecord?.actors ?? []).map(instructionProvenanceFor),
|
|
2200
|
-
...(args.actors ?? []).map(instructionProvenanceFor),
|
|
2201
|
-
...commit.provenance
|
|
2202
|
-
]),
|
|
2203
1866
|
...definedProps({
|
|
2204
|
-
channelName: args.channelName ?? existingRecord?.channelName,
|
|
2205
|
-
cumulativeUsage: args.cumulativeUsage,
|
|
2206
1867
|
dispatchId: args.dispatchId ?? existingRecord?.dispatchId,
|
|
2207
1868
|
dispatchOutcome: args.dispatchOutcome ?? existingRecord?.dispatchOutcome,
|
|
2208
1869
|
errorMessage: args.errorMessage,
|
|
2209
1870
|
lastProgressAtMs: args.lastProgressAtMs,
|
|
2210
|
-
loadedSkillNames: args.loadedSkillNames,
|
|
2211
|
-
reasoningLevel: args.reasoningLevel ?? existingRecord?.reasoningLevel,
|
|
2212
1871
|
resumeReason: args.resumeReason,
|
|
2213
1872
|
resultMessageId: args.resultMessageId ?? existingRecord?.resultMessageId,
|
|
2214
1873
|
resumedFromSliceId: args.resumedFromSliceId,
|
|
@@ -2226,6 +1885,14 @@ async function recordAgentTurnSessionSummary(args) {
|
|
|
2226
1885
|
args.conversationId,
|
|
2227
1886
|
args.sessionId
|
|
2228
1887
|
);
|
|
1888
|
+
const conversationStore = args.conversationStore ?? getConversationStore();
|
|
1889
|
+
const conversation = await conversationStore.get({
|
|
1890
|
+
conversationId: args.conversationId
|
|
1891
|
+
});
|
|
1892
|
+
const executionMetrics = executionMetricsForSession(
|
|
1893
|
+
conversation,
|
|
1894
|
+
args.sessionId
|
|
1895
|
+
);
|
|
2229
1896
|
const priorSummary = (await listAgentTurnSessionSummariesForConversation(args.conversationId)).find((summary2) => summary2.sessionId === args.sessionId);
|
|
2230
1897
|
const existing = stored ?? priorSummary;
|
|
2231
1898
|
const existingDispatchId = existing?.dispatchId;
|
|
@@ -2255,16 +1922,16 @@ async function recordAgentTurnSessionSummary(args) {
|
|
|
2255
1922
|
};
|
|
2256
1923
|
await recordConversationActivityMetadata({
|
|
2257
1924
|
actor: args.actor,
|
|
2258
|
-
conversationStore
|
|
1925
|
+
conversationStore,
|
|
2259
1926
|
destination: args.destination,
|
|
2260
1927
|
destinationVisibility: args.destinationVisibility,
|
|
2261
1928
|
nowMs,
|
|
2262
1929
|
source: args.source,
|
|
2263
1930
|
summary: {
|
|
2264
1931
|
...summary,
|
|
2265
|
-
channelName: args.channelName ??
|
|
2266
|
-
cumulativeDurationMs: args.cumulativeDurationMs ??
|
|
2267
|
-
cumulativeUsage: args.cumulativeUsage ??
|
|
1932
|
+
channelName: args.channelName ?? conversation?.channelName,
|
|
1933
|
+
cumulativeDurationMs: args.cumulativeDurationMs ?? executionMetrics?.durationMs ?? 0,
|
|
1934
|
+
cumulativeUsage: args.cumulativeUsage ?? executionMetrics?.usage,
|
|
2268
1935
|
startedAtMs: stored?.startedAtMs ?? args.startedAtMs ?? nowMs
|
|
2269
1936
|
}
|
|
2270
1937
|
});
|
|
@@ -2493,9 +2160,9 @@ async function persistCompletedSessionRecord(args) {
|
|
|
2493
2160
|
destination: args.destination,
|
|
2494
2161
|
destinationVisibility: args.destinationVisibility,
|
|
2495
2162
|
dispatchId: args.dispatchId,
|
|
2496
|
-
loadedSkillNames: args.loadedSkillNames
|
|
2163
|
+
loadedSkillNames: args.loadedSkillNames,
|
|
2497
2164
|
modelId: args.modelId,
|
|
2498
|
-
reasoningLevel: args.reasoningLevel
|
|
2165
|
+
reasoningLevel: args.reasoningLevel,
|
|
2499
2166
|
sessionId: args.sessionId,
|
|
2500
2167
|
source: args.source,
|
|
2501
2168
|
surface: args.surface,
|
|
@@ -2574,7 +2241,7 @@ async function persistAuthPauseSessionRecord(args) {
|
|
|
2574
2241
|
// Auth-pause keeps caller-owned skill names only.
|
|
2575
2242
|
loadedSkillNames: args.loadedSkillNames,
|
|
2576
2243
|
modelId: args.modelId,
|
|
2577
|
-
reasoningLevel: args.reasoningLevel
|
|
2244
|
+
reasoningLevel: args.reasoningLevel,
|
|
2578
2245
|
sessionId: args.sessionId,
|
|
2579
2246
|
source: args.source,
|
|
2580
2247
|
surface: args.surface
|
|
@@ -2645,7 +2312,7 @@ async function persistContinuationSessionRecord(args) {
|
|
|
2645
2312
|
// Continuation keeps caller-owned skill names only.
|
|
2646
2313
|
loadedSkillNames: args.loadedSkillNames,
|
|
2647
2314
|
modelId: args.modelId,
|
|
2648
|
-
reasoningLevel: args.reasoningLevel
|
|
2315
|
+
reasoningLevel: args.reasoningLevel,
|
|
2649
2316
|
sessionId: args.sessionId,
|
|
2650
2317
|
source: args.source,
|
|
2651
2318
|
surface: args.surface
|
|
@@ -2713,7 +2380,7 @@ async function persistYieldSessionRecord(args) {
|
|
|
2713
2380
|
// Yield keeps caller-owned skill names only.
|
|
2714
2381
|
loadedSkillNames: args.loadedSkillNames,
|
|
2715
2382
|
modelId: args.modelId,
|
|
2716
|
-
reasoningLevel: args.reasoningLevel
|
|
2383
|
+
reasoningLevel: args.reasoningLevel,
|
|
2717
2384
|
sessionId: args.sessionId,
|
|
2718
2385
|
source: args.source,
|
|
2719
2386
|
surface: args.surface
|
|
@@ -2752,19 +2419,11 @@ async function persistYieldSessionRecord(args) {
|
|
|
2752
2419
|
|
|
2753
2420
|
// src/chat/state/conversation.ts
|
|
2754
2421
|
function defaultConversationState() {
|
|
2755
|
-
const nowMs = Date.now();
|
|
2756
2422
|
return {
|
|
2757
2423
|
schemaVersion: 1,
|
|
2758
2424
|
messages: [],
|
|
2759
2425
|
compactions: [],
|
|
2760
|
-
backfill: {},
|
|
2761
2426
|
processing: {},
|
|
2762
|
-
stats: {
|
|
2763
|
-
estimatedContextTokens: 0,
|
|
2764
|
-
totalMessageCount: 0,
|
|
2765
|
-
compactedMessageCount: 0,
|
|
2766
|
-
updatedAtMs: nowMs
|
|
2767
|
-
},
|
|
2768
2427
|
vision: {
|
|
2769
2428
|
byFileId: {}
|
|
2770
2429
|
}
|
|
@@ -2799,27 +2458,14 @@ function coerceThreadConversationState(value) {
|
|
|
2799
2458
|
}
|
|
2800
2459
|
const root = value;
|
|
2801
2460
|
const rawConversation = isRecord(root.conversation) ? root.conversation : {};
|
|
2802
|
-
const base = defaultConversationState();
|
|
2803
2461
|
const messages = [];
|
|
2804
2462
|
const compactions = [];
|
|
2805
|
-
const rawBackfill = isRecord(rawConversation.backfill) ? rawConversation.backfill : {};
|
|
2806
|
-
const backfill = {
|
|
2807
|
-
completedAtMs: toOptionalNumber(rawBackfill.completedAtMs),
|
|
2808
|
-
source: rawBackfill.source === "recent_messages" || rawBackfill.source === "thread_fetch" ? rawBackfill.source : void 0
|
|
2809
|
-
};
|
|
2810
2463
|
const rawProcessing = isRecord(rawConversation.processing) ? rawConversation.processing : {};
|
|
2811
2464
|
const processing = {
|
|
2812
2465
|
activeTurnId: toOptionalString(rawProcessing.activeTurnId),
|
|
2813
2466
|
lastCompletedAtMs: toOptionalNumber(rawProcessing.lastCompletedAtMs),
|
|
2814
2467
|
pendingAuth: coercePendingAuthState(rawProcessing.pendingAuth)
|
|
2815
2468
|
};
|
|
2816
|
-
const rawStats = isRecord(rawConversation.stats) ? rawConversation.stats : {};
|
|
2817
|
-
const stats = {
|
|
2818
|
-
estimatedContextTokens: toOptionalNumber(rawStats.estimatedContextTokens) ?? base.stats.estimatedContextTokens,
|
|
2819
|
-
totalMessageCount: toOptionalNumber(rawStats.totalMessageCount) ?? messages.length,
|
|
2820
|
-
compactedMessageCount: toOptionalNumber(rawStats.compactedMessageCount) ?? 0,
|
|
2821
|
-
updatedAtMs: toOptionalNumber(rawStats.updatedAtMs) ?? base.stats.updatedAtMs
|
|
2822
|
-
};
|
|
2823
2469
|
const rawVision = isRecord(rawConversation.vision) ? rawConversation.vision : {};
|
|
2824
2470
|
const rawVisionByFileId = isRecord(rawVision.byFileId) ? rawVision.byFileId : {};
|
|
2825
2471
|
const byFileId = {};
|
|
@@ -2838,9 +2484,7 @@ function coerceThreadConversationState(value) {
|
|
|
2838
2484
|
schemaVersion: 1,
|
|
2839
2485
|
messages,
|
|
2840
2486
|
compactions,
|
|
2841
|
-
backfill,
|
|
2842
2487
|
processing,
|
|
2843
|
-
stats,
|
|
2844
2488
|
vision: {
|
|
2845
2489
|
backfillCompletedAtMs: toOptionalNumber(rawVision.backfillCompletedAtMs),
|
|
2846
2490
|
byFileId
|
|
@@ -2848,19 +2492,13 @@ function coerceThreadConversationState(value) {
|
|
|
2848
2492
|
};
|
|
2849
2493
|
}
|
|
2850
2494
|
function buildConversationStatePatch(conversation) {
|
|
2851
|
-
const {
|
|
2852
|
-
compactions: _compactions,
|
|
2853
|
-
messages: _messages,
|
|
2854
|
-
...scratch
|
|
2855
|
-
} = conversation;
|
|
2856
2495
|
return {
|
|
2857
2496
|
conversation: {
|
|
2858
|
-
...scratch,
|
|
2859
2497
|
schemaVersion: 1,
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2498
|
+
processing: { ...conversation.processing },
|
|
2499
|
+
vision: {
|
|
2500
|
+
backfillCompletedAtMs: conversation.vision.backfillCompletedAtMs,
|
|
2501
|
+
byFileId: { ...conversation.vision.byFileId }
|
|
2864
2502
|
}
|
|
2865
2503
|
}
|
|
2866
2504
|
};
|
|
@@ -3136,6 +2774,19 @@ function buildThreadStatePayload(patch) {
|
|
|
3136
2774
|
}
|
|
3137
2775
|
return payload;
|
|
3138
2776
|
}
|
|
2777
|
+
async function mergePersistedState(key, payload) {
|
|
2778
|
+
if (Object.keys(payload).length === 0) {
|
|
2779
|
+
return;
|
|
2780
|
+
}
|
|
2781
|
+
const stateAdapter = getStateAdapter();
|
|
2782
|
+
await stateAdapter.connect();
|
|
2783
|
+
const existing = await stateAdapter.get(key) ?? {};
|
|
2784
|
+
await stateAdapter.set(
|
|
2785
|
+
key,
|
|
2786
|
+
{ ...existing, ...payload },
|
|
2787
|
+
JUNIOR_THREAD_STATE_TTL_MS
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
3139
2790
|
function mergeArtifactsState(artifacts, patch) {
|
|
3140
2791
|
if (!patch) {
|
|
3141
2792
|
return artifacts;
|
|
@@ -3172,11 +2823,14 @@ async function persistThreadState(thread, patch) {
|
|
|
3172
2823
|
await persistThreadRuntimeState(thread, patch);
|
|
3173
2824
|
}
|
|
3174
2825
|
async function persistThreadRuntimeState(thread, patch) {
|
|
3175
|
-
const
|
|
3176
|
-
if (
|
|
3177
|
-
|
|
2826
|
+
const threadId = toOptionalString(thread.id) ?? toOptionalString(thread.runId);
|
|
2827
|
+
if (!threadId) {
|
|
2828
|
+
throw new Error("thread id is required to persist runtime scratch");
|
|
3178
2829
|
}
|
|
3179
|
-
await
|
|
2830
|
+
await mergePersistedState(
|
|
2831
|
+
threadStateKey(threadId),
|
|
2832
|
+
buildThreadStatePayload(patch)
|
|
2833
|
+
);
|
|
3180
2834
|
}
|
|
3181
2835
|
async function getPersistedThreadState(threadId) {
|
|
3182
2836
|
const stateAdapter = getStateAdapter();
|
|
@@ -3199,26 +2853,21 @@ async function persistThreadStateById(threadId, patch) {
|
|
|
3199
2853
|
conversationId: threadId
|
|
3200
2854
|
});
|
|
3201
2855
|
}
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
}
|
|
3206
|
-
const stateAdapter = getStateAdapter();
|
|
3207
|
-
await stateAdapter.connect();
|
|
3208
|
-
const key = threadStateKey(threadId);
|
|
3209
|
-
const existing = await stateAdapter.get(key) ?? {};
|
|
3210
|
-
await stateAdapter.set(
|
|
3211
|
-
key,
|
|
3212
|
-
{ ...existing, ...payload },
|
|
3213
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
2856
|
+
await mergePersistedState(
|
|
2857
|
+
threadStateKey(threadId),
|
|
2858
|
+
buildThreadStatePayload(patch)
|
|
3214
2859
|
);
|
|
3215
2860
|
}
|
|
3216
2861
|
function getChannelConfigurationService(thread) {
|
|
3217
2862
|
const channel = thread.channel;
|
|
2863
|
+
const channelId = toOptionalString(thread.channelId) ?? toOptionalString(channel.id);
|
|
2864
|
+
if (!channelId) {
|
|
2865
|
+
throw new Error("channel id is required to load channel configuration");
|
|
2866
|
+
}
|
|
3218
2867
|
return createChannelConfigurationService({
|
|
3219
|
-
load: async () => channel.state,
|
|
2868
|
+
load: async () => await channel.state,
|
|
3220
2869
|
save: async (state) => {
|
|
3221
|
-
await
|
|
2870
|
+
await mergePersistedState(channelStateKey(channelId), {
|
|
3222
2871
|
configuration: state
|
|
3223
2872
|
});
|
|
3224
2873
|
}
|
|
@@ -3228,15 +2877,9 @@ function getChannelConfigurationServiceById(channelId) {
|
|
|
3228
2877
|
return createChannelConfigurationService({
|
|
3229
2878
|
load: async () => await getPersistedChannelState(channelId),
|
|
3230
2879
|
save: async (state) => {
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
const existing = await stateAdapter.get(key) ?? {};
|
|
3235
|
-
await stateAdapter.set(
|
|
3236
|
-
key,
|
|
3237
|
-
{ ...existing, configuration: state },
|
|
3238
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
3239
|
-
);
|
|
2880
|
+
await mergePersistedState(channelStateKey(channelId), {
|
|
2881
|
+
configuration: state
|
|
2882
|
+
});
|
|
3240
2883
|
}
|
|
3241
2884
|
});
|
|
3242
2885
|
}
|
|
@@ -3323,20 +2966,6 @@ export {
|
|
|
3323
2966
|
historyItemFromPiMessage,
|
|
3324
2967
|
piMessageFromHistoryItem,
|
|
3325
2968
|
persistConversationMessageSummaries,
|
|
3326
|
-
estimateTextTokens,
|
|
3327
|
-
getAgentContextCompactionTriggerTokens,
|
|
3328
|
-
getAgentContextInputLimitTokens,
|
|
3329
|
-
normalizeConversationText,
|
|
3330
|
-
updateConversationStats,
|
|
3331
|
-
upsertConversationMessage,
|
|
3332
|
-
recordDeliveredAssistantMessage,
|
|
3333
|
-
turnHasReply,
|
|
3334
|
-
markConversationMessage,
|
|
3335
|
-
buildConversationContext,
|
|
3336
|
-
getThreadTitleSourceMessage,
|
|
3337
|
-
createConversationMemoryService,
|
|
3338
|
-
isHumanConversationMessage,
|
|
3339
|
-
getConversationMessageSlackTs,
|
|
3340
2969
|
hydrateConversationMessages,
|
|
3341
2970
|
persistConversationMessages,
|
|
3342
2971
|
loadProjection,
|
|
@@ -3349,6 +2978,7 @@ export {
|
|
|
3349
2978
|
recordAuthorizationRequested,
|
|
3350
2979
|
recordAuthorizationCompleted,
|
|
3351
2980
|
recordAuthenticationLinked,
|
|
2981
|
+
recordAgentsInstructionsUpdated,
|
|
3352
2982
|
loadTurnRoute,
|
|
3353
2983
|
recordTurnRoute,
|
|
3354
2984
|
recordToolExecutionStarted,
|
|
@@ -3356,7 +2986,7 @@ export {
|
|
|
3356
2986
|
MAX_TEXT_CHARS,
|
|
3357
2987
|
RIPGREP_EXCLUDED_GLOBS,
|
|
3358
2988
|
DEFAULT_SEARCH_COMMAND_TIMEOUT_MS,
|
|
3359
|
-
|
|
2989
|
+
positiveInteger,
|
|
3360
2990
|
normalizeToLf,
|
|
3361
2991
|
truncateText,
|
|
3362
2992
|
isMissingPathError,
|