@sentry/junior 0.141.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-HIRVKUQJ.js → agent-hooks-WDJQQAPH.js} +10 -10
- package/dist/api/schema/task.d.ts +8 -0
- package/dist/api/schema.js +1 -1
- package/dist/api.js +34 -22
- package/dist/app.js +62 -91
- package/dist/{catalog-runtime-XVLED5UH.js → catalog-runtime-CLHTYBHB.js} +5 -5
- package/dist/chat/event-tasks/types.d.ts +7 -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/short-title.d.ts +25 -0
- package/dist/chat/state/conversation.d.ts +6 -17
- package/dist/chat/tools/create-event-task.d.ts +1 -0
- package/dist/{chunk-OHO46E7F.js → chunk-4EZV6URQ.js} +88 -36
- package/dist/{chunk-3H42HMA2.js → chunk-4L7PKEHM.js} +5 -1
- package/dist/{chunk-HQAFIN6O.js → chunk-5ITSZIAP.js} +1 -1
- package/dist/{chunk-UONUDOJP.js → chunk-5QVVW3FY.js} +7 -7
- package/dist/{chunk-5LPWHC7Q.js → chunk-6IMKBHCG.js} +80 -46
- package/dist/{chunk-2DOVDDZJ.js → chunk-7R3CGEMF.js} +3 -3
- package/dist/{chunk-BBLO66XT.js → chunk-A646AKNB.js} +2 -2
- package/dist/{chunk-PIQKV7IR.js → chunk-B2H7NI5C.js} +10 -451
- package/dist/{chunk-NFL4FRIU.js → chunk-CA4WLRA3.js} +4 -4
- package/dist/{chunk-6FRAWWGR.js → chunk-CBMIVCPM.js} +2 -2
- package/dist/chunk-DRTWANQF.js +67 -0
- package/dist/{chunk-44NWPKY3.js → chunk-HVTWCMDS.js} +1 -1
- package/dist/{chunk-43OPSFUY.js → chunk-JIWZ7T4C.js} +1 -1
- package/dist/{chunk-PGJUJCOQ.js → chunk-LGY7YX5O.js} +1 -1
- package/dist/{chunk-OFQBDHVG.js → chunk-LL3BGP7J.js} +1 -1
- package/dist/{chunk-HN4UZTG7.js → chunk-LXLBYA6N.js} +2 -2
- package/dist/{chunk-FWXSPJRN.js → chunk-N3H7G5K6.js} +1 -1
- package/dist/{chunk-6U44QGXL.js → chunk-NWO5IB7V.js} +1 -1
- package/dist/{chunk-YWM6MJT4.js → chunk-OGQGJAD7.js} +2 -0
- package/dist/{chunk-DBKS7JR2.js → chunk-OQAPYAXH.js} +3 -3
- package/dist/{chunk-7ULXCNOZ.js → chunk-PWDCFIQG.js} +6 -6
- package/dist/{chunk-FZFJZZR3.js → chunk-QDRMQI5W.js} +4 -4
- package/dist/{chunk-DK3GQWJK.js → chunk-R7E476CH.js} +6 -6
- package/dist/{chunk-DVIJ6DP6.js → chunk-RYYBUI34.js} +2 -2
- package/dist/{chunk-5MFCEKR6.js → chunk-SCHH6264.js} +3 -3
- package/dist/{chunk-LMGKSDO4.js → chunk-SF6YKONJ.js} +1 -1
- package/dist/{chunk-H4WNQFBH.js → chunk-T4NFQ5SG.js} +5 -5
- package/dist/{chunk-A2O7SGK5.js → chunk-VJMBLWYR.js} +6 -6
- package/dist/{chunk-DKH4WGZU.js → chunk-WJEW7UNC.js} +341 -16
- package/dist/{chunk-EYD523BV.js → chunk-WYLSMTWU.js} +1 -1
- package/dist/{chunk-UFEU4UX6.js → chunk-XAW6IN6M.js} +1 -1
- package/dist/chunk-XFHSZNOX.js +75 -0
- package/dist/{chunk-LIVSCWI5.js → chunk-ZPNUI4L3.js} +23 -26
- package/dist/cli/chat.js +32 -30
- 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-PSMQZR4P.js → db-6N4CD5AI.js} +7 -7
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-XZUK2AT6.js → oauth-callback-server-G4K2X56R.js} +23 -21
- package/dist/{runner-5EKJCQWP.js → runner-DEIHVRUE.js} +24 -25
- package/dist/{skills-2PRM42SE.js → skills-FZVJ6ZFW.js} +6 -6
- package/dist/{spawn-UGTLRTFP.js → spawn-WD4F67SZ.js} +17 -17
- package/dist/{validation-XLXAIRTR.js → validation-EOLSG7B6.js} +6 -6
- package/dist/version.js +1 -1
- package/dist/{work-CNTNEQ2Q.js → work-AS3IBMLA.js} +16 -16
- package/dist/{worker-BGW7CKZ7.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 +5 -5
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
recordTaskExecution
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7R3CGEMF.js";
|
|
4
4
|
import {
|
|
5
5
|
pluginTaskId,
|
|
6
6
|
pluginTaskParamsSchema,
|
|
7
7
|
sendVercelPluginTask
|
|
8
8
|
} from "./chunk-5I6ORJUY.js";
|
|
9
|
+
import {
|
|
10
|
+
calculateContextCompactionTargetTokens,
|
|
11
|
+
estimateTextTokens,
|
|
12
|
+
getConversationContextCompactionTriggerTokens
|
|
13
|
+
} from "./chunk-DRTWANQF.js";
|
|
9
14
|
import {
|
|
10
15
|
buildDeterministicTurnId,
|
|
11
16
|
clearPendingAuth,
|
|
@@ -17,18 +22,20 @@ import {
|
|
|
17
22
|
instructionTextForProjection,
|
|
18
23
|
isToolResultError,
|
|
19
24
|
isToolResultMessage,
|
|
20
|
-
markConversationMessage,
|
|
21
25
|
markTurnClosed,
|
|
22
26
|
markTurnCompleted,
|
|
23
27
|
mergeArtifactsState,
|
|
24
28
|
normalizeToolNameFromResult,
|
|
25
29
|
persistThreadStateById,
|
|
26
|
-
stripRuntimeTurnContext
|
|
27
|
-
|
|
28
|
-
} from "./chunk-PIQKV7IR.js";
|
|
30
|
+
stripRuntimeTurnContext
|
|
31
|
+
} from "./chunk-B2H7NI5C.js";
|
|
29
32
|
import {
|
|
30
33
|
JUNIOR_THREAD_STATE_TTL_MS
|
|
31
34
|
} from "./chunk-3Y47VMHV.js";
|
|
35
|
+
import {
|
|
36
|
+
fallbackShortTitle,
|
|
37
|
+
generateShortTitle
|
|
38
|
+
} from "./chunk-XFHSZNOX.js";
|
|
32
39
|
import {
|
|
33
40
|
createPluginConversationEvents,
|
|
34
41
|
createPluginEmbedder,
|
|
@@ -36,21 +43,23 @@ import {
|
|
|
36
43
|
createPluginModel,
|
|
37
44
|
createPluginState,
|
|
38
45
|
getPlugins
|
|
39
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-PWDCFIQG.js";
|
|
40
47
|
import {
|
|
41
48
|
getConversationStore,
|
|
42
49
|
getDb,
|
|
43
50
|
sameActorIdentity
|
|
44
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-SCHH6264.js";
|
|
45
52
|
import {
|
|
46
53
|
getStateAdapter
|
|
47
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-NWO5IB7V.js";
|
|
48
55
|
import {
|
|
49
56
|
ProviderError,
|
|
57
|
+
botConfig,
|
|
58
|
+
escapeXml,
|
|
50
59
|
findProviderError,
|
|
51
60
|
getProviderErrorAttributes,
|
|
52
61
|
getProviderErrorUserMessage
|
|
53
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-A646AKNB.js";
|
|
54
63
|
import {
|
|
55
64
|
credentialSubjectSchema
|
|
56
65
|
} from "./chunk-RUIXF3YQ.js";
|
|
@@ -58,8 +67,315 @@ import {
|
|
|
58
67
|
parseSlackMessageTs
|
|
59
68
|
} from "./chunk-F3B2YJ76.js";
|
|
60
69
|
import {
|
|
61
|
-
buildTurnFailureResponse
|
|
62
|
-
|
|
70
|
+
buildTurnFailureResponse,
|
|
71
|
+
logWarn,
|
|
72
|
+
setSpanAttributes
|
|
73
|
+
} from "./chunk-XAW6IN6M.js";
|
|
74
|
+
|
|
75
|
+
// src/chat/services/conversation-memory.ts
|
|
76
|
+
var CONTEXT_MIN_LIVE_MESSAGES = 12;
|
|
77
|
+
var CONTEXT_COMPACTION_BATCH_SIZE = 24;
|
|
78
|
+
var CONTEXT_MAX_COMPACTIONS = 16;
|
|
79
|
+
var CONTEXT_MAX_MESSAGE_CHARS = 3200;
|
|
80
|
+
var SLACK_USER_ID_DISPLAY_PATTERN = /^[UW][A-Z0-9]{5,}$/;
|
|
81
|
+
function generateConversationId(prefix) {
|
|
82
|
+
return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
83
|
+
}
|
|
84
|
+
function normalizeConversationText(text) {
|
|
85
|
+
return text.replace(/\r\n?/g, "\n").trim();
|
|
86
|
+
}
|
|
87
|
+
function buildImageContextSuffix(message, conversation) {
|
|
88
|
+
const byFileId = conversation?.vision.byFileId;
|
|
89
|
+
const imageFileIds = message.meta?.imageFileIds ?? [];
|
|
90
|
+
if (!byFileId || imageFileIds.length === 0) {
|
|
91
|
+
return "";
|
|
92
|
+
}
|
|
93
|
+
const summaries = imageFileIds.map((fileId) => byFileId[fileId]?.summary?.trim()).filter((summary) => Boolean(summary));
|
|
94
|
+
if (summaries.length === 0) {
|
|
95
|
+
return "";
|
|
96
|
+
}
|
|
97
|
+
return ` [image context: ${summaries.join(" | ")}]`;
|
|
98
|
+
}
|
|
99
|
+
function renderConversationMessageLine(message, conversation) {
|
|
100
|
+
const displayName = conversationAuthorDisplayName(message);
|
|
101
|
+
const text = message.text.replace(/\s+/g, " ").slice(0, CONTEXT_MAX_MESSAGE_CHARS);
|
|
102
|
+
const markers = [];
|
|
103
|
+
if (message.meta?.replied === false) {
|
|
104
|
+
markers.push(
|
|
105
|
+
`assistant skipped: ${message.meta?.skippedReason ?? "no-reply route"}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
if (message.meta?.explicitMention) {
|
|
109
|
+
markers.push("explicit mention");
|
|
110
|
+
}
|
|
111
|
+
const markerSuffix = markers.length > 0 ? ` (${markers.join("; ")})` : "";
|
|
112
|
+
const imageContext = buildImageContextSuffix(message, conversation);
|
|
113
|
+
return `[${message.role}] ${displayName}: ${text}${imageContext}${markerSuffix}`;
|
|
114
|
+
}
|
|
115
|
+
function conversationAuthorDisplayName(message) {
|
|
116
|
+
const author = message.author;
|
|
117
|
+
const fullName = authorDisplayField(author?.fullName, author?.userId);
|
|
118
|
+
const userName = authorDisplayField(author?.userName, author?.userId);
|
|
119
|
+
return fullName ?? userName ?? (message.role === "assistant" ? botConfig.userName : message.role);
|
|
120
|
+
}
|
|
121
|
+
function authorDisplayField(value, userId) {
|
|
122
|
+
if (!value || value === userId || SLACK_USER_ID_DISPLAY_PATTERN.test(value)) {
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
function estimateConversationContextTokens(conversation) {
|
|
128
|
+
return estimateTextTokens(buildConversationContext(conversation) ?? "");
|
|
129
|
+
}
|
|
130
|
+
function upsertConversationMessage(conversation, message) {
|
|
131
|
+
const existingIndex = conversation.messages.findIndex(
|
|
132
|
+
(entry) => entry.id === message.id
|
|
133
|
+
);
|
|
134
|
+
if (existingIndex >= 0) {
|
|
135
|
+
conversation.messages[existingIndex] = {
|
|
136
|
+
...conversation.messages[existingIndex],
|
|
137
|
+
...message,
|
|
138
|
+
meta: {
|
|
139
|
+
...conversation.messages[existingIndex]?.meta,
|
|
140
|
+
...message.meta
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
return message.id;
|
|
144
|
+
}
|
|
145
|
+
conversation.messages.push(message);
|
|
146
|
+
return message.id;
|
|
147
|
+
}
|
|
148
|
+
function recordDeliveredAssistantMessage(args) {
|
|
149
|
+
const prefix = `${args.sessionId}:assistant:`;
|
|
150
|
+
const ordinal = args.conversation.messages.filter(
|
|
151
|
+
(message) => message.id.startsWith(prefix)
|
|
152
|
+
).length + 1;
|
|
153
|
+
const messageId = `${prefix}${ordinal}`;
|
|
154
|
+
markConversationMessage(args.conversation, args.userMessageId, {
|
|
155
|
+
replied: true,
|
|
156
|
+
skippedReason: void 0
|
|
157
|
+
});
|
|
158
|
+
upsertConversationMessage(args.conversation, {
|
|
159
|
+
id: messageId,
|
|
160
|
+
role: "assistant",
|
|
161
|
+
text: normalizeConversationText(args.text),
|
|
162
|
+
createdAtMs: Date.now(),
|
|
163
|
+
author: {
|
|
164
|
+
userName: botConfig.userName,
|
|
165
|
+
isBot: true
|
|
166
|
+
},
|
|
167
|
+
meta: {
|
|
168
|
+
replied: true
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return messageId;
|
|
172
|
+
}
|
|
173
|
+
function turnHasReply(conversation, turnId) {
|
|
174
|
+
const assistantPrefix = `${turnId}:assistant:`;
|
|
175
|
+
return conversation.messages.some(
|
|
176
|
+
(message) => message.role === "assistant" && message.id.startsWith(assistantPrefix)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
function markConversationMessage(conversation, messageId, patch) {
|
|
180
|
+
if (!messageId) return;
|
|
181
|
+
const messageIndex = conversation.messages.findIndex(
|
|
182
|
+
(entry) => entry.id === messageId
|
|
183
|
+
);
|
|
184
|
+
if (messageIndex < 0) return;
|
|
185
|
+
const current = conversation.messages[messageIndex];
|
|
186
|
+
conversation.messages[messageIndex] = {
|
|
187
|
+
...current,
|
|
188
|
+
meta: {
|
|
189
|
+
...current.meta ?? {},
|
|
190
|
+
...patch
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function buildConversationContext(conversation, options = {}) {
|
|
195
|
+
const messages = conversation.messages.filter(
|
|
196
|
+
(entry) => entry.id !== options.excludeMessageId
|
|
197
|
+
);
|
|
198
|
+
if (messages.length === 0 && conversation.compactions.length === 0) {
|
|
199
|
+
return void 0;
|
|
200
|
+
}
|
|
201
|
+
const lines = [];
|
|
202
|
+
if (conversation.compactions.length > 0) {
|
|
203
|
+
lines.push("<thread-compactions>");
|
|
204
|
+
for (const [index, compaction] of conversation.compactions.entries()) {
|
|
205
|
+
lines.push(
|
|
206
|
+
` <compaction index="${index + 1}" covered_messages="${compaction.coveredMessageCount}" created_at="${new Date(compaction.createdAtMs).toISOString()}">`,
|
|
207
|
+
compaction.summary,
|
|
208
|
+
" </compaction>"
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
lines.push("</thread-compactions>");
|
|
212
|
+
}
|
|
213
|
+
if (messages.length > 0) {
|
|
214
|
+
if (lines.length > 0) {
|
|
215
|
+
lines.push("");
|
|
216
|
+
}
|
|
217
|
+
lines.push("<thread-transcript>");
|
|
218
|
+
for (const [index, message] of messages.entries()) {
|
|
219
|
+
const author = escapeXml(conversationAuthorDisplayName(message));
|
|
220
|
+
const actorIdAttr = message.author?.userId ? ` actor_id="${escapeXml(message.author.userId)}"` : "";
|
|
221
|
+
const ts = new Date(message.createdAtMs).toISOString();
|
|
222
|
+
const slackTsAttr = message.meta?.slackTs ? ` slack_ts="${escapeXml(message.meta.slackTs)}"` : "";
|
|
223
|
+
lines.push(
|
|
224
|
+
` <message index="${index + 1}" ts="${ts}" role="${message.role}" author="${author}"${actorIdAttr}${slackTsAttr}>`,
|
|
225
|
+
renderConversationMessageLine(message, conversation),
|
|
226
|
+
" </message>"
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
lines.push("</thread-transcript>");
|
|
230
|
+
}
|
|
231
|
+
return lines.join("\n");
|
|
232
|
+
}
|
|
233
|
+
function pruneCompactions(compactions) {
|
|
234
|
+
if (compactions.length <= CONTEXT_MAX_COMPACTIONS) {
|
|
235
|
+
return compactions;
|
|
236
|
+
}
|
|
237
|
+
const overflowCount = compactions.length - CONTEXT_MAX_COMPACTIONS + 1;
|
|
238
|
+
const merged = compactions.slice(0, overflowCount);
|
|
239
|
+
const mergedSummary = merged.map((entry) => entry.summary).join("\n").slice(0, 3500);
|
|
240
|
+
const coveredMessageCount = merged.reduce(
|
|
241
|
+
(count, entry) => count + entry.coveredMessageCount,
|
|
242
|
+
0
|
|
243
|
+
);
|
|
244
|
+
const compacted = {
|
|
245
|
+
id: generateConversationId("compaction"),
|
|
246
|
+
createdAtMs: Date.now(),
|
|
247
|
+
summary: mergedSummary,
|
|
248
|
+
coveredMessageCount
|
|
249
|
+
};
|
|
250
|
+
return [compacted, ...compactions.slice(overflowCount)];
|
|
251
|
+
}
|
|
252
|
+
async function summarizeConversationChunk(messages, conversation, context, deps) {
|
|
253
|
+
const transcript = messages.map((message) => renderConversationMessageLine(message, conversation)).join("\n");
|
|
254
|
+
try {
|
|
255
|
+
const result = await deps.completeText({
|
|
256
|
+
modelId: botConfig.fastModelId,
|
|
257
|
+
temperature: 0,
|
|
258
|
+
messages: [
|
|
259
|
+
{
|
|
260
|
+
role: "user",
|
|
261
|
+
content: [
|
|
262
|
+
"Summarize the following older Slack thread transcript segment for future assistant turns.",
|
|
263
|
+
"Keep the summary factual and concise. Do not invent details.",
|
|
264
|
+
"",
|
|
265
|
+
"Output exactly three XML sections in this order:",
|
|
266
|
+
"<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>",
|
|
267
|
+
"<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>",
|
|
268
|
+
"<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>",
|
|
269
|
+
"",
|
|
270
|
+
"Do not output any text outside the three sections.",
|
|
271
|
+
"",
|
|
272
|
+
transcript
|
|
273
|
+
].join("\n"),
|
|
274
|
+
timestamp: Date.now()
|
|
275
|
+
}
|
|
276
|
+
],
|
|
277
|
+
metadata: {
|
|
278
|
+
modelId: botConfig.fastModelId,
|
|
279
|
+
threadId: context.threadId ?? "",
|
|
280
|
+
channelId: context.channelId ?? "",
|
|
281
|
+
actorId: context.actorId ?? "",
|
|
282
|
+
runId: context.runId ?? ""
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
const summary = result.text.trim();
|
|
286
|
+
if (summary.length > 0) {
|
|
287
|
+
return summary.slice(0, 3500);
|
|
288
|
+
}
|
|
289
|
+
} catch (error) {
|
|
290
|
+
logWarn("conversation.compaction.summary.failed", {
|
|
291
|
+
"exception.message": error instanceof Error ? error.message : String(error),
|
|
292
|
+
"app.compaction_messages_covered": messages.length
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
return transcript.slice(0, 2800);
|
|
296
|
+
}
|
|
297
|
+
async function generateThreadTitleWithDeps(sourceText, deps) {
|
|
298
|
+
const title = await generateShortTitle({
|
|
299
|
+
completeText: deps.completeText,
|
|
300
|
+
kind: "conversation",
|
|
301
|
+
sourceText
|
|
302
|
+
});
|
|
303
|
+
return title ?? fallbackShortTitle(sourceText, "Conversation");
|
|
304
|
+
}
|
|
305
|
+
function getThreadTitleSourceMessage(conversation) {
|
|
306
|
+
let firstMessage;
|
|
307
|
+
for (const message of conversation.messages) {
|
|
308
|
+
if (!isHumanConversationMessage(message)) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (!firstMessage) {
|
|
312
|
+
firstMessage = message;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
if (message.createdAtMs < firstMessage.createdAtMs) {
|
|
316
|
+
firstMessage = message;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (message.createdAtMs === firstMessage.createdAtMs && message.id < firstMessage.id) {
|
|
320
|
+
firstMessage = message;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return firstMessage;
|
|
324
|
+
}
|
|
325
|
+
async function compactConversationIfNeededWithDeps(conversation, context, deps) {
|
|
326
|
+
let estimatedTokens = estimateConversationContextTokens(conversation);
|
|
327
|
+
setSpanAttributes({
|
|
328
|
+
"app.context_tokens_estimated": estimatedTokens
|
|
329
|
+
});
|
|
330
|
+
const triggerTokens = getConversationContextCompactionTriggerTokens();
|
|
331
|
+
const targetTokens = calculateContextCompactionTargetTokens(triggerTokens);
|
|
332
|
+
while (estimatedTokens > triggerTokens && conversation.messages.length > CONTEXT_MIN_LIVE_MESSAGES) {
|
|
333
|
+
const compactCount = Math.min(
|
|
334
|
+
CONTEXT_COMPACTION_BATCH_SIZE,
|
|
335
|
+
conversation.messages.length - CONTEXT_MIN_LIVE_MESSAGES
|
|
336
|
+
);
|
|
337
|
+
if (compactCount <= 0) {
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
const compactedChunk = conversation.messages.slice(0, compactCount);
|
|
341
|
+
const summary = await summarizeConversationChunk(
|
|
342
|
+
compactedChunk,
|
|
343
|
+
conversation,
|
|
344
|
+
context,
|
|
345
|
+
deps
|
|
346
|
+
);
|
|
347
|
+
conversation.compactions.push({
|
|
348
|
+
id: generateConversationId("compaction"),
|
|
349
|
+
createdAtMs: Date.now(),
|
|
350
|
+
summary,
|
|
351
|
+
coveredMessageCount: compactedChunk.length
|
|
352
|
+
});
|
|
353
|
+
conversation.compactions = pruneCompactions(conversation.compactions);
|
|
354
|
+
conversation.messages = conversation.messages.slice(compactCount);
|
|
355
|
+
estimatedTokens = estimateConversationContextTokens(conversation);
|
|
356
|
+
setSpanAttributes({
|
|
357
|
+
"app.compaction_messages_covered": compactCount,
|
|
358
|
+
"app.compaction.trigger_tokens": triggerTokens,
|
|
359
|
+
"app.compaction.target_tokens": targetTokens,
|
|
360
|
+
"app.context_tokens_estimated": estimatedTokens
|
|
361
|
+
});
|
|
362
|
+
if (estimatedTokens <= targetTokens) {
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function createConversationMemoryService(deps) {
|
|
368
|
+
return {
|
|
369
|
+
compactConversationIfNeeded: async (conversation, context) => await compactConversationIfNeededWithDeps(conversation, context, deps),
|
|
370
|
+
generateThreadTitle: async (sourceText) => await generateThreadTitleWithDeps(sourceText, deps)
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
function isHumanConversationMessage(message) {
|
|
374
|
+
return message.role === "user" && message.author?.isBot !== true;
|
|
375
|
+
}
|
|
376
|
+
function getConversationMessageSlackTs(message) {
|
|
377
|
+
return parseSlackMessageTs(message.meta?.slackTs);
|
|
378
|
+
}
|
|
63
379
|
|
|
64
380
|
// src/chat/runtime/delivered-turn-state.ts
|
|
65
381
|
function buildDeliveredTurnStatePatch(args) {
|
|
@@ -77,8 +393,7 @@ function buildDeliveredTurnStatePatch(args) {
|
|
|
77
393
|
markTurnCompleted({
|
|
78
394
|
conversation,
|
|
79
395
|
nowMs: Date.now(),
|
|
80
|
-
sessionId: args.sessionId
|
|
81
|
-
updateConversationStats
|
|
396
|
+
sessionId: args.sessionId
|
|
82
397
|
});
|
|
83
398
|
return {
|
|
84
399
|
artifacts,
|
|
@@ -95,7 +410,7 @@ import {
|
|
|
95
410
|
|
|
96
411
|
// src/chat/services/turn-session-routing.ts
|
|
97
412
|
async function resolveTurnSessionRouting(args) {
|
|
98
|
-
const conversationStore = args.conversationStore ?? (await import("./db-
|
|
413
|
+
const conversationStore = args.conversationStore ?? (await import("./db-6N4CD5AI.js")).getConversationStore();
|
|
99
414
|
const conversation = await conversationStore.get({
|
|
100
415
|
conversationId: args.conversationId
|
|
101
416
|
});
|
|
@@ -935,8 +1250,7 @@ function completeAuthPauseTurn(args) {
|
|
|
935
1250
|
markTurnClosed({
|
|
936
1251
|
conversation: args.conversation,
|
|
937
1252
|
nowMs: Date.now(),
|
|
938
|
-
sessionId: args.sessionId
|
|
939
|
-
updateConversationStats
|
|
1253
|
+
sessionId: args.sessionId
|
|
940
1254
|
});
|
|
941
1255
|
}
|
|
942
1256
|
async function persistAuthPauseTurnState(args) {
|
|
@@ -970,6 +1284,17 @@ export {
|
|
|
970
1284
|
listPendingDispatchMailboxAppends,
|
|
971
1285
|
claimDispatchMailboxAppend,
|
|
972
1286
|
getPluginDispatchProjection,
|
|
1287
|
+
normalizeConversationText,
|
|
1288
|
+
estimateConversationContextTokens,
|
|
1289
|
+
upsertConversationMessage,
|
|
1290
|
+
recordDeliveredAssistantMessage,
|
|
1291
|
+
turnHasReply,
|
|
1292
|
+
markConversationMessage,
|
|
1293
|
+
buildConversationContext,
|
|
1294
|
+
getThreadTitleSourceMessage,
|
|
1295
|
+
createConversationMemoryService,
|
|
1296
|
+
isHumanConversationMessage,
|
|
1297
|
+
getConversationMessageSlackTs,
|
|
973
1298
|
buildDeliveredTurnStatePatch,
|
|
974
1299
|
getTurnUserMessage,
|
|
975
1300
|
getTurnUserMessageId,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
botConfig
|
|
3
|
+
} from "./chunk-A646AKNB.js";
|
|
4
|
+
import {
|
|
5
|
+
logWarn
|
|
6
|
+
} from "./chunk-XAW6IN6M.js";
|
|
7
|
+
|
|
8
|
+
// src/chat/services/short-title.ts
|
|
9
|
+
var SHORT_TITLE_MAX_LENGTH = 60;
|
|
10
|
+
var TITLE_PROMPTS = {
|
|
11
|
+
conversation: [
|
|
12
|
+
"Generate a concise 5-8 word Slack conversation title from the first user message below.",
|
|
13
|
+
"Capture the user's main request.",
|
|
14
|
+
"Reply with ONLY the title, with no quotes or trailing punctuation."
|
|
15
|
+
],
|
|
16
|
+
task: [
|
|
17
|
+
"Generate a concise 5-8 word task title from the task instruction below.",
|
|
18
|
+
"Capture the task's main purpose.",
|
|
19
|
+
"Reply with ONLY the title, with no quotes or trailing punctuation."
|
|
20
|
+
]
|
|
21
|
+
};
|
|
22
|
+
function normalizeShortTitle(value) {
|
|
23
|
+
return value.replace(/\s+/g, " ").trim().slice(0, SHORT_TITLE_MAX_LENGTH);
|
|
24
|
+
}
|
|
25
|
+
function fallbackShortTitle(sourceText, fallback = "Untitled") {
|
|
26
|
+
const firstLine = sourceText.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0) ?? "";
|
|
27
|
+
return normalizeShortTitle(firstLine) || fallback;
|
|
28
|
+
}
|
|
29
|
+
async function generateShortTitle(args) {
|
|
30
|
+
const sourceText = args.sourceText.trim();
|
|
31
|
+
if (!sourceText) return void 0;
|
|
32
|
+
try {
|
|
33
|
+
const result = await args.completeText({
|
|
34
|
+
modelId: botConfig.fastModelId,
|
|
35
|
+
temperature: 0,
|
|
36
|
+
messages: [
|
|
37
|
+
{
|
|
38
|
+
role: "user",
|
|
39
|
+
content: [
|
|
40
|
+
...TITLE_PROMPTS[args.kind],
|
|
41
|
+
"",
|
|
42
|
+
args.kind === "conversation" ? `First user message: ${sourceText.slice(0, 500)}` : `Task instruction: ${sourceText.slice(0, 500)}`
|
|
43
|
+
].join("\n"),
|
|
44
|
+
timestamp: Date.now()
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
metadata: {
|
|
48
|
+
modelId: botConfig.fastModelId
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
const title = normalizeShortTitle(result.text);
|
|
52
|
+
return title || void 0;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
logWarn(`${args.kind}.title.generation.failed`, {
|
|
55
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
56
|
+
});
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function resolveTaskTitle(args) {
|
|
61
|
+
const explicit = normalizeShortTitle(args.title ?? "");
|
|
62
|
+
if (explicit) return explicit;
|
|
63
|
+
return generateShortTitle({
|
|
64
|
+
completeText: args.completeText,
|
|
65
|
+
kind: "task",
|
|
66
|
+
sourceText: args.instruction
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
SHORT_TITLE_MAX_LENGTH,
|
|
72
|
+
fallbackShortTitle,
|
|
73
|
+
generateShortTitle,
|
|
74
|
+
resolveTaskTitle
|
|
75
|
+
};
|
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
ensureConversationWake,
|
|
6
6
|
requestConversationWork
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CA4WLRA3.js";
|
|
8
8
|
import {
|
|
9
|
+
buildConversationContext,
|
|
9
10
|
buildDeliveredTurnStatePatch,
|
|
10
11
|
finalizeFailedTurnReplyWithEvent,
|
|
11
12
|
getInterruptionMarker,
|
|
@@ -13,11 +14,14 @@ import {
|
|
|
13
14
|
getTurnUserMessageId,
|
|
14
15
|
getTurnUserReplyAttachmentContext,
|
|
15
16
|
getTurnUserSlackMessageTs,
|
|
17
|
+
markConversationMessage,
|
|
16
18
|
persistAuthPauseTurnState,
|
|
19
|
+
recordDeliveredAssistantMessage,
|
|
17
20
|
requireTurnFailureEventId,
|
|
18
21
|
resolveTurnSessionRouting,
|
|
19
|
-
scheduleSessionCompletedPluginTasks
|
|
20
|
-
|
|
22
|
+
scheduleSessionCompletedPluginTasks,
|
|
23
|
+
turnHasReply
|
|
24
|
+
} from "./chunk-WJEW7UNC.js";
|
|
21
25
|
import {
|
|
22
26
|
ConversationTurnLifecycleService
|
|
23
27
|
} from "./chunk-Q6QZTTLS.js";
|
|
@@ -35,7 +39,7 @@ import {
|
|
|
35
39
|
getMcpProviderErrorAttributes,
|
|
36
40
|
getMcpStoredOAuthCredentials,
|
|
37
41
|
resolvePluginOAuthAccount
|
|
38
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-5QVVW3FY.js";
|
|
39
43
|
import {
|
|
40
44
|
RetryableDeliveryError
|
|
41
45
|
} from "./chunk-R776HKPK.js";
|
|
@@ -51,11 +55,10 @@ import {
|
|
|
51
55
|
removeReactionFromMessage,
|
|
52
56
|
resolveBaseUrl,
|
|
53
57
|
truncateStatusText
|
|
54
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-R7E476CH.js";
|
|
55
59
|
import {
|
|
56
60
|
TurnSliceLimitExceededError,
|
|
57
61
|
abandonAgentTurnSessionRecord,
|
|
58
|
-
buildConversationContext,
|
|
59
62
|
buildTurnLimitResponse,
|
|
60
63
|
clearPendingAuth,
|
|
61
64
|
coerceThreadArtifactsState,
|
|
@@ -71,43 +74,39 @@ import {
|
|
|
71
74
|
hydrateConversationMessages,
|
|
72
75
|
isPendingAuthLatestRequest,
|
|
73
76
|
loadProjection,
|
|
74
|
-
markConversationMessage,
|
|
75
77
|
markTurnFailed,
|
|
76
78
|
persistCompletedSessionRecord,
|
|
77
79
|
persistThreadStateById,
|
|
78
80
|
persistWithRetry,
|
|
79
81
|
recordAgentTurnSessionSummary,
|
|
80
82
|
recordAuthenticationLinked,
|
|
81
|
-
recordAuthorizationCompleted
|
|
82
|
-
|
|
83
|
-
turnHasReply,
|
|
84
|
-
updateConversationStats
|
|
85
|
-
} from "./chunk-PIQKV7IR.js";
|
|
83
|
+
recordAuthorizationCompleted
|
|
84
|
+
} from "./chunk-B2H7NI5C.js";
|
|
86
85
|
import {
|
|
87
86
|
parseSlackThreadId,
|
|
88
87
|
readSlackRawMessageContext,
|
|
89
88
|
resolveSlackChannelIdFromMessage,
|
|
90
89
|
resolveSlackChannelIdFromThreadId
|
|
91
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-5ITSZIAP.js";
|
|
92
91
|
import {
|
|
93
92
|
getDashboardConversationLink,
|
|
94
93
|
getPluginSlackConversationLink
|
|
95
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-PWDCFIQG.js";
|
|
96
95
|
import {
|
|
97
96
|
SlackActionError,
|
|
98
97
|
getHeaderString,
|
|
99
98
|
getSlackClient,
|
|
100
99
|
isDmChannel,
|
|
101
100
|
normalizeSlackConversationId
|
|
102
|
-
} from "./chunk-
|
|
101
|
+
} from "./chunk-RYYBUI34.js";
|
|
103
102
|
import {
|
|
104
103
|
getConversationEventStore,
|
|
105
104
|
requireSlackDestination
|
|
106
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-SCHH6264.js";
|
|
107
106
|
import {
|
|
108
107
|
acquireActiveLock,
|
|
109
108
|
getStateAdapter
|
|
110
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-NWO5IB7V.js";
|
|
111
110
|
import {
|
|
112
111
|
FUNCTION_TIMEOUT_BUFFER_SECONDS,
|
|
113
112
|
botConfig,
|
|
@@ -116,18 +115,18 @@ import {
|
|
|
116
115
|
getRuntimeMetadata,
|
|
117
116
|
normalizeSlackEmojiName,
|
|
118
117
|
standardModelId
|
|
119
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-A646AKNB.js";
|
|
120
119
|
import {
|
|
121
120
|
discoverSkills
|
|
122
|
-
} from "./chunk-
|
|
121
|
+
} from "./chunk-CBMIVCPM.js";
|
|
123
122
|
import {
|
|
124
123
|
pluginCatalogRuntime
|
|
125
|
-
} from "./chunk-
|
|
124
|
+
} from "./chunk-WYLSMTWU.js";
|
|
126
125
|
import {
|
|
127
126
|
buildOAuthTokenRequest,
|
|
128
127
|
hasRequiredOAuthScope,
|
|
129
128
|
parseOAuthTokenResponse
|
|
130
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-SF6YKONJ.js";
|
|
131
130
|
import {
|
|
132
131
|
createSlackResumeActor,
|
|
133
132
|
isUserActor
|
|
@@ -143,7 +142,7 @@ import {
|
|
|
143
142
|
setTags,
|
|
144
143
|
toOptionalString,
|
|
145
144
|
withLogContext
|
|
146
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-XAW6IN6M.js";
|
|
147
146
|
import {
|
|
148
147
|
homeDir
|
|
149
148
|
} from "./chunk-H4HBKISO.js";
|
|
@@ -1925,8 +1924,7 @@ async function persistFailedReplyState(channelId, threadTs, sessionId, expectedV
|
|
|
1925
1924
|
nowMs: Date.now(),
|
|
1926
1925
|
sessionId,
|
|
1927
1926
|
userMessageId: getTurnUserMessageId(conversation, sessionId),
|
|
1928
|
-
markConversationMessage
|
|
1929
|
-
updateConversationStats
|
|
1927
|
+
markConversationMessage
|
|
1930
1928
|
});
|
|
1931
1929
|
await failSessionRecordBestEffort({
|
|
1932
1930
|
conversationId: threadId,
|
|
@@ -2533,8 +2531,7 @@ async function persistFailedOAuthReplyState(args) {
|
|
|
2533
2531
|
nowMs: Date.now(),
|
|
2534
2532
|
sessionId: args.sessionId,
|
|
2535
2533
|
userMessageId: getTurnUserMessage(conversation, args.sessionId)?.id,
|
|
2536
|
-
markConversationMessage
|
|
2537
|
-
updateConversationStats
|
|
2534
|
+
markConversationMessage
|
|
2538
2535
|
});
|
|
2539
2536
|
await failSessionRecordBestEffort2({
|
|
2540
2537
|
conversationId: args.conversationId,
|