@sentry/junior 0.147.0 → 0.149.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-HS6VGUPM.js → agent-hooks-CWMCXAMT.js} +10 -10
- package/dist/api/conversations/access.d.ts +2 -1
- package/dist/api/conversations/aggregate.d.ts +2 -0
- package/dist/api/conversations/archive.d.ts +3 -5
- package/dist/api/conversations/create.d.ts +6 -0
- package/dist/api/conversations/detail.d.ts +2 -296
- package/dist/api/conversations/event-list.d.ts +2 -193
- package/dist/api/conversations/list.d.ts +4 -66
- package/dist/api/conversations/pending-messages.d.ts +15 -0
- package/dist/api/conversations/routes.d.ts +1 -1
- package/dist/api/conversations/stats.d.ts +0 -54
- package/dist/api/http.d.ts +2 -6
- package/dist/api/locations/detail.d.ts +3 -111
- package/dist/api/locations/list.d.ts +0 -45
- package/dist/api/locations/query.d.ts +2 -1
- package/dist/api/locations/routes.d.ts +1 -1
- package/dist/api/people/list.d.ts +0 -29
- package/dist/api/people/profile.d.ts +2 -106
- package/dist/api/people/profile.query.d.ts +2 -1
- package/dist/api/people/routes.d.ts +1 -1
- package/dist/api/people/shared.d.ts +3 -1
- package/dist/api/people/spend.d.ts +3 -4
- package/dist/api/personal-tokens/routes.d.ts +2 -2
- package/dist/api/route.d.ts +8 -14
- package/dist/api/schema/conversation.d.ts +130 -25
- package/dist/api/schema/location.d.ts +4 -0
- package/dist/api/schema/person.d.ts +7 -3
- package/dist/api/schema.d.ts +2 -2
- package/dist/api/schema.js +13 -1
- package/dist/api/stats.d.ts +0 -13
- package/dist/api/validation.d.ts +7 -0
- package/dist/api/viewer.d.ts +3 -0
- package/dist/api.d.ts +2 -1
- package/dist/api.js +772 -561
- package/dist/app.js +241 -204
- package/dist/{catalog-runtime-M6ZTPYRV.js → catalog-runtime-GAW5APVI.js} +5 -5
- package/dist/chat/actor.d.ts +4 -1
- package/dist/chat/agent/request.d.ts +2 -0
- package/dist/chat/agent/resume.d.ts +1 -0
- package/dist/chat/agent-dispatch/context.d.ts +2 -2
- package/dist/chat/agent-invocations/types.d.ts +52 -0
- package/dist/chat/api-turns/work.d.ts +108 -0
- package/dist/chat/app/services.d.ts +1 -1
- package/dist/chat/conversations/history.d.ts +60 -0
- package/dist/chat/conversations/provenance.d.ts +6 -0
- package/dist/chat/conversations/sql/actor-identity.d.ts +19 -0
- package/dist/chat/conversations/store.d.ts +1 -1
- package/dist/chat/resource-events/store.d.ts +1 -1
- package/dist/chat/runtime/reply-executor.d.ts +1 -3
- package/dist/chat/runtime/slack-runtime.d.ts +2 -1
- package/dist/chat/runtime/turn-preparation.d.ts +9 -0
- package/dist/chat/scheduled-tasks/tool-support.d.ts +5 -5
- package/dist/chat/scheduled-tasks/tools/create.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/delete.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/list.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/run-now.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/update.d.ts +2 -2
- package/dist/chat/services/conversation-memory.d.ts +2 -2
- package/dist/chat/services/conversation-title.d.ts +20 -0
- package/dist/chat/slack/assistant-thread/title.d.ts +10 -27
- package/dist/chat/slack/channel.d.ts +26 -0
- package/dist/chat/slack/dispatch-turn.d.ts +1 -0
- package/dist/chat/slack/timestamp-param.d.ts +0 -2
- package/dist/chat/slack/{tools → tool-support}/canvas/api.d.ts +1 -1
- package/dist/chat/slack/{tools → tool-support}/canvas/context.d.ts +3 -0
- package/dist/chat/slack/tool-support/channel-access.d.ts +42 -0
- package/dist/chat/slack/tool-support/channel-target.d.ts +27 -0
- package/dist/chat/slack/tool-support/list/params.d.ts +5 -0
- package/dist/chat/slack/tools/canvas/create.d.ts +1 -1
- package/dist/chat/slack/tools/channel-join.d.ts +28 -0
- package/dist/chat/slack/tools/channel-list-messages.d.ts +3 -2
- package/dist/chat/slack/tools/conversation-message-search.d.ts +2 -8
- package/dist/chat/slack/tools/message-add-reaction.d.ts +1 -1
- package/dist/chat/slack/tools/public-search.d.ts +63 -2
- package/dist/chat/slack/tools/send-files.d.ts +1 -1
- package/dist/chat/slack/tools/thread-read.d.ts +2 -5
- package/dist/chat/source.d.ts +2 -0
- package/dist/chat/state/conversation.d.ts +1 -0
- package/dist/chat/task-execution/checkpoint.d.ts +1 -0
- package/dist/chat/task-execution/state.d.ts +9 -4
- package/dist/chat/task-execution/store.d.ts +3 -2
- package/dist/chat/task-execution/turn-cursor.d.ts +2 -0
- package/dist/chat/task-execution/worker.d.ts +2 -0
- package/dist/chat/tasks/read.d.ts +1 -1
- package/dist/chat/tools/search-conversation-events.d.ts +1 -1
- package/dist/chat/tools/types.d.ts +11 -4
- package/dist/chat/tools/watch-resource-events.d.ts +2 -2
- package/dist/{chunk-ORO3PWKQ.js → chunk-25SC7D6Z.js} +1 -1
- package/dist/{chunk-GGB4WL5A.js → chunk-2JHKISQA.js} +1 -1
- package/dist/{chunk-AVZDSUFB.js → chunk-2P6BQQER.js} +4 -4
- package/dist/{chunk-7NVJVJID.js → chunk-32CXPIZE.js} +2 -2
- package/dist/{chunk-YSB2N563.js → chunk-3GYZ5YEH.js} +121 -87
- package/dist/{chunk-DU74WPIC.js → chunk-3I2IVWSZ.js} +1 -1
- package/dist/{chunk-SVHUEHUL.js → chunk-3JVUWLR7.js} +65 -4
- package/dist/{chunk-RXBVB2JM.js → chunk-3KGQOKIG.js} +1 -1
- package/dist/{chunk-YBVXBNSV.js → chunk-4JGM7FXO.js} +2 -2
- package/dist/{chunk-AZ7EAOBE.js → chunk-4YKPOYRV.js} +5 -5
- package/dist/chunk-5CWUQXXT.js +806 -0
- package/dist/{chunk-DLDRQHG5.js → chunk-6G5RCDKP.js} +1 -1
- package/dist/{chunk-AYU72WO7.js → chunk-75DSYFFB.js} +47 -70
- package/dist/{chunk-YHDERDRO.js → chunk-7BH46NB4.js} +91 -75
- package/dist/{chunk-745QJ3ZA.js → chunk-ALJG73MQ.js} +2 -2
- package/dist/chunk-ART7P442.js +48 -0
- package/dist/{chunk-7A4M7PCV.js → chunk-DK5UT6PQ.js} +1180 -556
- package/dist/{chunk-AIOK6LAG.js → chunk-EW2LNCRL.js} +813 -44
- package/dist/chunk-EXW76GW4.js +36 -0
- package/dist/chunk-GDFF3BQG.js +136 -0
- package/dist/{chunk-7UQIVT6G.js → chunk-JMH3DBM5.js} +6 -6
- package/dist/{chunk-CWP5RHVX.js → chunk-JMSMXXED.js} +12 -5
- package/dist/{chunk-CSZINQJ2.js → chunk-MEMURSBG.js} +1 -1
- package/dist/{chunk-YNTTROJT.js → chunk-QIW7OQEO.js} +1 -1
- package/dist/{chunk-Q4R73I43.js → chunk-RB26T3LU.js} +58 -28
- package/dist/{chunk-4LJO56OJ.js → chunk-RLVZIWNQ.js} +1 -1
- package/dist/{chunk-SGZO7UWH.js → chunk-SWHPVZBV.js} +2 -2
- package/dist/{chunk-PVNG6UMU.js → chunk-TFBNBXPU.js} +22 -10
- package/dist/{chunk-EFLJ2WJH.js → chunk-URDCZAL4.js} +5 -5
- package/dist/{chunk-6H5SZR24.js → chunk-UZGASGOD.js} +300 -383
- package/dist/{chunk-YEO3VX72.js → chunk-W7UONUIZ.js} +8 -6
- package/dist/{chunk-JUUKWRBE.js → chunk-X22XXSZA.js} +1 -1
- package/dist/{chunk-X5UY34KT.js → chunk-XPYWWMHR.js} +8 -8
- package/dist/{chunk-IIOOO4FQ.js → chunk-ZYMYLLWG.js} +2 -1
- package/dist/cli/chat.js +32 -35
- 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/agent-invocations.d.ts +20 -0
- package/dist/db/schema/conversation-annotations.d.ts +2 -2
- package/dist/db/schema.d.ts +22 -2
- package/dist/{db-CSEW4RII.js → db-JBZLRIVY.js} +7 -7
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-FUEV5HNG.js → oauth-callback-server-MNTVYY2I.js} +24 -26
- package/dist/{runner-U3XHSKSH.js → runner-K24BWZSZ.js} +23 -25
- package/dist/{skills-AKE6W3WI.js → skills-AU5ST2CG.js} +6 -6
- package/dist/spawn-6PO7CVJ6.js +38 -0
- package/dist/{validation-WDTAULUF.js → validation-IXGZCFRO.js} +6 -6
- package/dist/version.js +1 -1
- package/dist/{work-C3HAO2BG.js → work-WCZIYILX.js} +18 -19
- package/dist/{worker-LNP4YKBM.js → worker-U2AACBEY.js} +11 -10
- package/package.json +6 -5
- package/dist/api/health.d.ts +0 -7
- package/dist/api/personal-tokens/create.d.ts +0 -11
- package/dist/api/personal-tokens/list.d.ts +0 -12
- package/dist/api/personal-tokens/revoke.d.ts +0 -5
- package/dist/api/plugin-reports.d.ts +0 -63
- package/dist/api/plugins.d.ts +0 -8
- package/dist/api/runtime.d.ts +0 -24
- package/dist/api/skills.d.ts +0 -6
- package/dist/chat/slack/tools/channel-access.d.ts +0 -30
- package/dist/chunk-34GS7B6L.js +0 -115
- package/dist/chunk-AVOCH2Z5.js +0 -285
- package/dist/chunk-HLXXQI5Q.js +0 -238
- package/dist/chunk-K4SZAP3K.js +0 -67
- package/dist/chunk-R776HKPK.js +0 -81
- package/dist/chunk-Z4YU7Z4L.js +0 -76
- package/dist/spawn-B6GDTWJ4.js +0 -39
- /package/dist/chat/slack/{tools → tool-support}/canvas/markdown.d.ts +0 -0
- /package/dist/chat/slack/{tools → tool-support}/channel-capabilities.d.ts +0 -0
- /package/dist/chat/slack/{tools → tool-support}/context.d.ts +0 -0
- /package/dist/chat/slack/{tools → tool-support}/list/api.d.ts +0 -0
- /package/dist/chat/slack/{tools → tool-support}/slack-message-url.d.ts +0 -0
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
addAgentTurnUsage,
|
|
5
|
-
agentsInstructionsUpdatedEvent,
|
|
6
|
-
authenticationLinkedEvent,
|
|
7
|
-
authenticationUnlinkedEvent
|
|
8
|
-
} from "./chunk-HLXXQI5Q.js";
|
|
2
|
+
usageSchema
|
|
3
|
+
} from "./chunk-PDO5BLNM.js";
|
|
9
4
|
import {
|
|
10
5
|
agentHistoryItemSchema,
|
|
11
6
|
bindProviderConversation,
|
|
@@ -18,7 +13,7 @@ import {
|
|
|
18
13
|
instructionProvenanceFor,
|
|
19
14
|
sanitizePostgresJson,
|
|
20
15
|
withConversationEventLock
|
|
21
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-3GYZ5YEH.js";
|
|
22
17
|
import {
|
|
23
18
|
SANDBOX_WORKSPACE_ROOT,
|
|
24
19
|
sleep
|
|
@@ -28,18 +23,26 @@ import {
|
|
|
28
23
|
fenceLock,
|
|
29
24
|
getStateAdapter,
|
|
30
25
|
withLock
|
|
31
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-25SC7D6Z.js";
|
|
32
27
|
import {
|
|
33
28
|
botConfig,
|
|
29
|
+
completeText,
|
|
30
|
+
escapeXml,
|
|
31
|
+
resolveGatewayModel,
|
|
34
32
|
unwrapCurrentInstruction
|
|
35
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-32CXPIZE.js";
|
|
36
34
|
import {
|
|
37
35
|
toStoredSlackActor
|
|
38
36
|
} from "./chunk-HZF5P5UN.js";
|
|
37
|
+
import {
|
|
38
|
+
parseSlackMessageTs
|
|
39
|
+
} from "./chunk-F3B2YJ76.js";
|
|
39
40
|
import {
|
|
40
41
|
getActiveTraceId,
|
|
41
|
-
logException
|
|
42
|
-
|
|
42
|
+
logException,
|
|
43
|
+
logWarn,
|
|
44
|
+
setSpanAttributes
|
|
45
|
+
} from "./chunk-RLVZIWNQ.js";
|
|
43
46
|
|
|
44
47
|
// src/chat/turn-context-tag.ts
|
|
45
48
|
var TURN_CONTEXT_TAG = "runtime-turn-context";
|
|
@@ -178,10 +181,518 @@ function stripRuntimeTurnContext(messages) {
|
|
|
178
181
|
});
|
|
179
182
|
}
|
|
180
183
|
|
|
184
|
+
// src/chat/services/context-budget.ts
|
|
185
|
+
var COMPACTION_TRIGGER_RATIO = 0.9;
|
|
186
|
+
var CONTEXT_INPUT_LIMIT_RATIO = 0.95;
|
|
187
|
+
var COMPACTION_TARGET_RATIO = 0.8;
|
|
188
|
+
var FALLBACK_CONTEXT_WINDOW_TOKENS = 4e5;
|
|
189
|
+
function positiveInteger(value, fallback) {
|
|
190
|
+
return Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
|
|
191
|
+
}
|
|
192
|
+
function estimateTextTokens(text) {
|
|
193
|
+
return Math.ceil(text.length / 4);
|
|
194
|
+
}
|
|
195
|
+
function calculateContextCompactionTriggerTokens(model) {
|
|
196
|
+
const contextWindow = positiveInteger(
|
|
197
|
+
model.contextWindow,
|
|
198
|
+
FALLBACK_CONTEXT_WINDOW_TOKENS
|
|
199
|
+
);
|
|
200
|
+
return Math.max(1, Math.floor(contextWindow * COMPACTION_TRIGGER_RATIO));
|
|
201
|
+
}
|
|
202
|
+
function calculateContextInputLimitTokens(model) {
|
|
203
|
+
const contextWindow = positiveInteger(
|
|
204
|
+
model.contextWindow,
|
|
205
|
+
FALLBACK_CONTEXT_WINDOW_TOKENS
|
|
206
|
+
);
|
|
207
|
+
return Math.max(1, Math.floor(contextWindow * CONTEXT_INPUT_LIMIT_RATIO));
|
|
208
|
+
}
|
|
209
|
+
function calculateContextCompactionTargetTokens(triggerTokens) {
|
|
210
|
+
return Math.max(1, Math.floor(triggerTokens * COMPACTION_TARGET_RATIO));
|
|
211
|
+
}
|
|
212
|
+
function getModelContextBudget(modelId) {
|
|
213
|
+
const model = resolveGatewayModel(modelId);
|
|
214
|
+
const advertisedContextWindow = positiveInteger(
|
|
215
|
+
model.contextWindow,
|
|
216
|
+
FALLBACK_CONTEXT_WINDOW_TOKENS
|
|
217
|
+
);
|
|
218
|
+
return {
|
|
219
|
+
contextWindow: Math.min(
|
|
220
|
+
botConfig.contextWindowTokens,
|
|
221
|
+
advertisedContextWindow
|
|
222
|
+
)
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function getAgentContextCompactionTriggerTokens(modelId) {
|
|
226
|
+
return calculateContextCompactionTriggerTokens(
|
|
227
|
+
getModelContextBudget(modelId)
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
function getAgentContextInputLimitTokens(modelId) {
|
|
231
|
+
return calculateContextInputLimitTokens(getModelContextBudget(modelId));
|
|
232
|
+
}
|
|
233
|
+
function getConversationContextCompactionTriggerTokens() {
|
|
234
|
+
return calculateContextCompactionTriggerTokens(
|
|
235
|
+
getModelContextBudget(botConfig.fastModelId)
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// src/chat/services/conversation-memory.ts
|
|
240
|
+
var CONTEXT_MIN_LIVE_MESSAGES = 12;
|
|
241
|
+
var CONTEXT_COMPACTION_BATCH_SIZE = 24;
|
|
242
|
+
var CONTEXT_MAX_COMPACTIONS = 16;
|
|
243
|
+
var CONTEXT_MAX_MESSAGE_CHARS = 3200;
|
|
244
|
+
var SLACK_USER_ID_DISPLAY_PATTERN = /^[UW][A-Z0-9]{5,}$/;
|
|
245
|
+
function generateConversationId(prefix) {
|
|
246
|
+
return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
247
|
+
}
|
|
248
|
+
function normalizeConversationText(text) {
|
|
249
|
+
return text.replace(/\r\n?/g, "\n").trim();
|
|
250
|
+
}
|
|
251
|
+
function buildImageContextSuffix(message, conversation) {
|
|
252
|
+
const byFileId = conversation?.vision.byFileId;
|
|
253
|
+
const imageFileIds = message.meta?.imageFileIds ?? [];
|
|
254
|
+
if (!byFileId || imageFileIds.length === 0) {
|
|
255
|
+
return "";
|
|
256
|
+
}
|
|
257
|
+
const summaries = imageFileIds.map((fileId) => byFileId[fileId]?.summary?.trim()).filter((summary) => Boolean(summary));
|
|
258
|
+
if (summaries.length === 0) {
|
|
259
|
+
return "";
|
|
260
|
+
}
|
|
261
|
+
return ` [image context: ${summaries.join(" | ")}]`;
|
|
262
|
+
}
|
|
263
|
+
function renderConversationMessageLine(message, conversation) {
|
|
264
|
+
const displayName = conversationAuthorDisplayName(message);
|
|
265
|
+
const text = message.text.replace(/\s+/g, " ").slice(0, CONTEXT_MAX_MESSAGE_CHARS);
|
|
266
|
+
const markers = [];
|
|
267
|
+
if (message.meta?.replied === false) {
|
|
268
|
+
markers.push(
|
|
269
|
+
`assistant skipped: ${message.meta?.skippedReason ?? "no-reply route"}`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
if (message.meta?.explicitMention) {
|
|
273
|
+
markers.push("explicit mention");
|
|
274
|
+
}
|
|
275
|
+
const markerSuffix = markers.length > 0 ? ` (${markers.join("; ")})` : "";
|
|
276
|
+
const imageContext = buildImageContextSuffix(message, conversation);
|
|
277
|
+
return `[${message.role}] ${displayName}: ${text}${imageContext}${markerSuffix}`;
|
|
278
|
+
}
|
|
279
|
+
function conversationAuthorDisplayName(message) {
|
|
280
|
+
const author = message.author;
|
|
281
|
+
const fullName = authorDisplayField(author?.fullName, author?.userId);
|
|
282
|
+
const userName = authorDisplayField(author?.userName, author?.userId);
|
|
283
|
+
return fullName ?? userName ?? (message.role === "assistant" ? botConfig.userName : message.role);
|
|
284
|
+
}
|
|
285
|
+
function authorDisplayField(value, userId) {
|
|
286
|
+
if (!value || value === userId || SLACK_USER_ID_DISPLAY_PATTERN.test(value)) {
|
|
287
|
+
return void 0;
|
|
288
|
+
}
|
|
289
|
+
return value;
|
|
290
|
+
}
|
|
291
|
+
function estimateConversationContextTokens(conversation) {
|
|
292
|
+
return estimateTextTokens(buildConversationContext(conversation) ?? "");
|
|
293
|
+
}
|
|
294
|
+
function upsertConversationMessage(conversation, message) {
|
|
295
|
+
const existingIndex = conversation.messages.findIndex(
|
|
296
|
+
(entry) => entry.id === message.id
|
|
297
|
+
);
|
|
298
|
+
if (existingIndex >= 0) {
|
|
299
|
+
conversation.messages[existingIndex] = {
|
|
300
|
+
...conversation.messages[existingIndex],
|
|
301
|
+
...message,
|
|
302
|
+
meta: {
|
|
303
|
+
...conversation.messages[existingIndex]?.meta,
|
|
304
|
+
...message.meta
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
return message.id;
|
|
308
|
+
}
|
|
309
|
+
conversation.messages.push(message);
|
|
310
|
+
return message.id;
|
|
311
|
+
}
|
|
312
|
+
function recordDeliveredAssistantMessage(args) {
|
|
313
|
+
const prefix = `${args.sessionId}:assistant:`;
|
|
314
|
+
const ordinal = args.conversation.messages.filter(
|
|
315
|
+
(message) => message.id.startsWith(prefix)
|
|
316
|
+
).length + 1;
|
|
317
|
+
const messageId = `${prefix}${ordinal}`;
|
|
318
|
+
markConversationMessage(args.conversation, args.userMessageId, {
|
|
319
|
+
replied: true,
|
|
320
|
+
skippedReason: void 0
|
|
321
|
+
});
|
|
322
|
+
upsertConversationMessage(args.conversation, {
|
|
323
|
+
id: messageId,
|
|
324
|
+
role: "assistant",
|
|
325
|
+
text: normalizeConversationText(args.text),
|
|
326
|
+
createdAtMs: Date.now(),
|
|
327
|
+
author: {
|
|
328
|
+
userName: botConfig.userName,
|
|
329
|
+
isBot: true
|
|
330
|
+
},
|
|
331
|
+
meta: {
|
|
332
|
+
replied: true,
|
|
333
|
+
...args.source ? { source: args.source } : {}
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
return messageId;
|
|
337
|
+
}
|
|
338
|
+
function turnHasReply(conversation, turnId) {
|
|
339
|
+
const assistantPrefix = `${turnId}:assistant:`;
|
|
340
|
+
return conversation.messages.some(
|
|
341
|
+
(message) => message.role === "assistant" && message.id.startsWith(assistantPrefix)
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
function markConversationMessage(conversation, messageId, patch) {
|
|
345
|
+
if (!messageId) return;
|
|
346
|
+
const messageIndex = conversation.messages.findIndex(
|
|
347
|
+
(entry) => entry.id === messageId
|
|
348
|
+
);
|
|
349
|
+
if (messageIndex < 0) return;
|
|
350
|
+
const current = conversation.messages[messageIndex];
|
|
351
|
+
conversation.messages[messageIndex] = {
|
|
352
|
+
...current,
|
|
353
|
+
meta: {
|
|
354
|
+
...current.meta ?? {},
|
|
355
|
+
...patch
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function buildConversationContext(conversation, options = {}) {
|
|
360
|
+
const messages = conversation.messages.filter(
|
|
361
|
+
(entry) => entry.id !== options.excludeMessageId
|
|
362
|
+
);
|
|
363
|
+
if (messages.length === 0 && conversation.compactions.length === 0) {
|
|
364
|
+
return void 0;
|
|
365
|
+
}
|
|
366
|
+
const lines = [];
|
|
367
|
+
if (conversation.compactions.length > 0) {
|
|
368
|
+
lines.push("<thread-compactions>");
|
|
369
|
+
for (const [index, compaction] of conversation.compactions.entries()) {
|
|
370
|
+
lines.push(
|
|
371
|
+
` <compaction index="${index + 1}" covered_messages="${compaction.coveredMessageCount}" created_at="${new Date(compaction.createdAtMs).toISOString()}">`,
|
|
372
|
+
compaction.summary,
|
|
373
|
+
" </compaction>"
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
lines.push("</thread-compactions>");
|
|
377
|
+
}
|
|
378
|
+
if (messages.length > 0) {
|
|
379
|
+
if (lines.length > 0) {
|
|
380
|
+
lines.push("");
|
|
381
|
+
}
|
|
382
|
+
lines.push("<thread-transcript>");
|
|
383
|
+
for (const [index, message] of messages.entries()) {
|
|
384
|
+
const author = escapeXml(conversationAuthorDisplayName(message));
|
|
385
|
+
const actorIdAttr = message.author?.userId ? ` actor_id="${escapeXml(message.author.userId)}"` : "";
|
|
386
|
+
const ts = new Date(message.createdAtMs).toISOString();
|
|
387
|
+
const slackTsAttr = message.meta?.slackTs ? ` slack_ts="${escapeXml(message.meta.slackTs)}"` : "";
|
|
388
|
+
lines.push(
|
|
389
|
+
` <message index="${index + 1}" ts="${ts}" role="${message.role}" author="${author}"${actorIdAttr}${slackTsAttr}>`,
|
|
390
|
+
renderConversationMessageLine(message, conversation),
|
|
391
|
+
" </message>"
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
lines.push("</thread-transcript>");
|
|
395
|
+
}
|
|
396
|
+
return lines.join("\n");
|
|
397
|
+
}
|
|
398
|
+
function pruneCompactions(compactions) {
|
|
399
|
+
if (compactions.length <= CONTEXT_MAX_COMPACTIONS) {
|
|
400
|
+
return compactions;
|
|
401
|
+
}
|
|
402
|
+
const overflowCount = compactions.length - CONTEXT_MAX_COMPACTIONS + 1;
|
|
403
|
+
const merged = compactions.slice(0, overflowCount);
|
|
404
|
+
const mergedSummary = merged.map((entry) => entry.summary).join("\n").slice(0, 3500);
|
|
405
|
+
const coveredMessageCount = merged.reduce(
|
|
406
|
+
(count, entry) => count + entry.coveredMessageCount,
|
|
407
|
+
0
|
|
408
|
+
);
|
|
409
|
+
const compacted = {
|
|
410
|
+
id: generateConversationId("compaction"),
|
|
411
|
+
createdAtMs: Date.now(),
|
|
412
|
+
summary: mergedSummary,
|
|
413
|
+
coveredMessageCount
|
|
414
|
+
};
|
|
415
|
+
return [compacted, ...compactions.slice(overflowCount)];
|
|
416
|
+
}
|
|
417
|
+
async function summarizeConversationChunk(messages, conversation, context, deps) {
|
|
418
|
+
const transcript = messages.map((message) => renderConversationMessageLine(message, conversation)).join("\n");
|
|
419
|
+
try {
|
|
420
|
+
const result = await deps.completeText({
|
|
421
|
+
modelId: botConfig.fastModelId,
|
|
422
|
+
temperature: 0,
|
|
423
|
+
promptName: "junior.thread_compaction",
|
|
424
|
+
messages: [
|
|
425
|
+
{
|
|
426
|
+
role: "user",
|
|
427
|
+
content: [
|
|
428
|
+
"Summarize the following older Slack thread transcript segment for future assistant turns.",
|
|
429
|
+
"Keep the summary factual and concise. Do not invent details.",
|
|
430
|
+
"",
|
|
431
|
+
"Output exactly three XML sections in this order:",
|
|
432
|
+
"<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>",
|
|
433
|
+
"<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>",
|
|
434
|
+
"<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>",
|
|
435
|
+
"",
|
|
436
|
+
"Do not output any text outside the three sections.",
|
|
437
|
+
"",
|
|
438
|
+
transcript
|
|
439
|
+
].join("\n"),
|
|
440
|
+
timestamp: Date.now()
|
|
441
|
+
}
|
|
442
|
+
],
|
|
443
|
+
metadata: {
|
|
444
|
+
modelId: botConfig.fastModelId,
|
|
445
|
+
threadId: context.threadId ?? "",
|
|
446
|
+
channelId: context.channelId ?? "",
|
|
447
|
+
actorId: context.actorId ?? "",
|
|
448
|
+
runId: context.runId ?? ""
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
const summary = result.text.trim();
|
|
452
|
+
if (summary.length > 0) {
|
|
453
|
+
return summary.slice(0, 3500);
|
|
454
|
+
}
|
|
455
|
+
} catch (error) {
|
|
456
|
+
logWarn("conversation.compaction.summary.failed", {
|
|
457
|
+
"exception.message": error instanceof Error ? error.message : String(error),
|
|
458
|
+
"app.compaction_messages_covered": messages.length
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
return transcript.slice(0, 2800);
|
|
462
|
+
}
|
|
463
|
+
function getThreadTitleSourceMessage(conversation) {
|
|
464
|
+
let firstMessage;
|
|
465
|
+
for (const message of conversation.messages) {
|
|
466
|
+
if (!isHumanConversationMessage(message)) {
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
if (!firstMessage) {
|
|
470
|
+
firstMessage = message;
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
if (message.createdAtMs < firstMessage.createdAtMs) {
|
|
474
|
+
firstMessage = message;
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
if (message.createdAtMs === firstMessage.createdAtMs && message.id < firstMessage.id) {
|
|
478
|
+
firstMessage = message;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return firstMessage;
|
|
482
|
+
}
|
|
483
|
+
async function compactConversationIfNeededWithDeps(conversation, context, deps) {
|
|
484
|
+
let estimatedTokens = estimateConversationContextTokens(conversation);
|
|
485
|
+
setSpanAttributes({
|
|
486
|
+
"app.context_tokens_estimated": estimatedTokens
|
|
487
|
+
});
|
|
488
|
+
const triggerTokens = getConversationContextCompactionTriggerTokens();
|
|
489
|
+
const targetTokens = calculateContextCompactionTargetTokens(triggerTokens);
|
|
490
|
+
while (estimatedTokens > triggerTokens && conversation.messages.length > CONTEXT_MIN_LIVE_MESSAGES) {
|
|
491
|
+
const compactCount = Math.min(
|
|
492
|
+
CONTEXT_COMPACTION_BATCH_SIZE,
|
|
493
|
+
conversation.messages.length - CONTEXT_MIN_LIVE_MESSAGES
|
|
494
|
+
);
|
|
495
|
+
if (compactCount <= 0) {
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
const compactedChunk = conversation.messages.slice(0, compactCount);
|
|
499
|
+
const summary = await summarizeConversationChunk(
|
|
500
|
+
compactedChunk,
|
|
501
|
+
conversation,
|
|
502
|
+
context,
|
|
503
|
+
deps
|
|
504
|
+
);
|
|
505
|
+
conversation.compactions.push({
|
|
506
|
+
id: generateConversationId("compaction"),
|
|
507
|
+
createdAtMs: Date.now(),
|
|
508
|
+
summary,
|
|
509
|
+
coveredMessageCount: compactedChunk.length
|
|
510
|
+
});
|
|
511
|
+
conversation.compactions = pruneCompactions(conversation.compactions);
|
|
512
|
+
conversation.messages = conversation.messages.slice(compactCount);
|
|
513
|
+
estimatedTokens = estimateConversationContextTokens(conversation);
|
|
514
|
+
setSpanAttributes({
|
|
515
|
+
"app.compaction_messages_covered": compactCount,
|
|
516
|
+
"app.compaction.trigger_tokens": triggerTokens,
|
|
517
|
+
"app.compaction.target_tokens": targetTokens,
|
|
518
|
+
"app.context_tokens_estimated": estimatedTokens
|
|
519
|
+
});
|
|
520
|
+
if (estimatedTokens <= targetTokens) {
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function createConversationMemoryService(deps) {
|
|
526
|
+
return {
|
|
527
|
+
compactConversationIfNeeded: async (conversation, context) => await compactConversationIfNeededWithDeps(conversation, context, deps)
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function isHumanConversationMessage(message) {
|
|
531
|
+
return message.role === "user" && message.author?.isBot !== true;
|
|
532
|
+
}
|
|
533
|
+
function getConversationMessageSlackTs(message) {
|
|
534
|
+
return parseSlackMessageTs(message.meta?.slackTs);
|
|
535
|
+
}
|
|
536
|
+
|
|
181
537
|
// src/chat/conversations/messages.ts
|
|
182
538
|
import { createHash } from "crypto";
|
|
183
539
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
184
540
|
|
|
541
|
+
// src/chat/services/short-title.ts
|
|
542
|
+
var SHORT_TITLE_MAX_LENGTH = 60;
|
|
543
|
+
var TITLE_PROMPTS = {
|
|
544
|
+
conversation: [
|
|
545
|
+
"Generate a concise 5-8 word conversation title from the first user message below.",
|
|
546
|
+
"Capture the user's main request.",
|
|
547
|
+
"Reply with ONLY the title, with no quotes or trailing punctuation."
|
|
548
|
+
],
|
|
549
|
+
task: [
|
|
550
|
+
"Generate a concise 5-8 word task title from the task instruction below.",
|
|
551
|
+
"Capture the task's main purpose.",
|
|
552
|
+
"Reply with ONLY the title, with no quotes or trailing punctuation."
|
|
553
|
+
]
|
|
554
|
+
};
|
|
555
|
+
function normalizeShortTitle(value) {
|
|
556
|
+
return value.replace(/\s+/g, " ").trim().slice(0, SHORT_TITLE_MAX_LENGTH);
|
|
557
|
+
}
|
|
558
|
+
function fallbackShortTitle(sourceText, fallback = "Untitled") {
|
|
559
|
+
const firstLine = sourceText.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0) ?? "";
|
|
560
|
+
return normalizeShortTitle(firstLine) || fallback;
|
|
561
|
+
}
|
|
562
|
+
async function generateShortTitle(args) {
|
|
563
|
+
const sourceText = args.sourceText.trim();
|
|
564
|
+
if (!sourceText) return void 0;
|
|
565
|
+
try {
|
|
566
|
+
const result = await args.completeText({
|
|
567
|
+
modelId: botConfig.fastModelId,
|
|
568
|
+
temperature: 0,
|
|
569
|
+
promptName: `junior.${args.kind}_title`,
|
|
570
|
+
messages: [
|
|
571
|
+
{
|
|
572
|
+
role: "user",
|
|
573
|
+
content: [
|
|
574
|
+
...TITLE_PROMPTS[args.kind],
|
|
575
|
+
"",
|
|
576
|
+
args.kind === "conversation" ? `First user message: ${sourceText.slice(0, 500)}` : `Task instruction: ${sourceText.slice(0, 500)}`
|
|
577
|
+
].join("\n"),
|
|
578
|
+
timestamp: Date.now()
|
|
579
|
+
}
|
|
580
|
+
],
|
|
581
|
+
metadata: {
|
|
582
|
+
modelId: botConfig.fastModelId
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
const title = normalizeShortTitle(result.text);
|
|
586
|
+
return title || void 0;
|
|
587
|
+
} catch (error) {
|
|
588
|
+
logWarn(`${args.kind}.title.generation.failed`, {
|
|
589
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
590
|
+
});
|
|
591
|
+
return void 0;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
async function resolveTaskTitle(args) {
|
|
595
|
+
const explicit = normalizeShortTitle(args.title ?? "");
|
|
596
|
+
if (explicit) return explicit;
|
|
597
|
+
return generateShortTitle({
|
|
598
|
+
completeText: args.completeText,
|
|
599
|
+
kind: "task",
|
|
600
|
+
sourceText: args.instruction
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/chat/services/conversation-title.ts
|
|
605
|
+
var inFlightTitles = /* @__PURE__ */ new Map();
|
|
606
|
+
async function ensureConversationTitle(args) {
|
|
607
|
+
const pending = inFlightTitles.get(args.conversationId);
|
|
608
|
+
if (pending) {
|
|
609
|
+
return pending;
|
|
610
|
+
}
|
|
611
|
+
const work = ensureConversationTitleOnce(args).finally(() => {
|
|
612
|
+
inFlightTitles.delete(args.conversationId);
|
|
613
|
+
});
|
|
614
|
+
inFlightTitles.set(args.conversationId, work);
|
|
615
|
+
return work;
|
|
616
|
+
}
|
|
617
|
+
async function ensureConversationTitleOnce(args) {
|
|
618
|
+
if (!args.conversation.messages.some(isHumanConversationMessage)) {
|
|
619
|
+
return void 0;
|
|
620
|
+
}
|
|
621
|
+
const store = args.conversationStore ?? getConversationStore();
|
|
622
|
+
try {
|
|
623
|
+
const stored = await store.get({ conversationId: args.conversationId });
|
|
624
|
+
if (stored?.title?.trim()) {
|
|
625
|
+
return void 0;
|
|
626
|
+
}
|
|
627
|
+
if (stored?.lineage) {
|
|
628
|
+
return void 0;
|
|
629
|
+
}
|
|
630
|
+
const titleSourceMessage = getThreadTitleSourceMessage(args.conversation);
|
|
631
|
+
const sourceText = titleSourceMessage?.text.trim() ?? "";
|
|
632
|
+
if (!titleSourceMessage || !sourceText) {
|
|
633
|
+
return void 0;
|
|
634
|
+
}
|
|
635
|
+
let title;
|
|
636
|
+
try {
|
|
637
|
+
const generated = await generateShortTitle({
|
|
638
|
+
completeText,
|
|
639
|
+
kind: "conversation",
|
|
640
|
+
sourceText
|
|
641
|
+
});
|
|
642
|
+
title = generated ?? fallbackShortTitle(sourceText, "Conversation");
|
|
643
|
+
} catch (error) {
|
|
644
|
+
logWarn("conversation.title.generation.failed", {
|
|
645
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
646
|
+
});
|
|
647
|
+
title = fallbackShortTitle(sourceText, "Conversation");
|
|
648
|
+
}
|
|
649
|
+
const normalized = title.trim();
|
|
650
|
+
if (!normalized) {
|
|
651
|
+
return void 0;
|
|
652
|
+
}
|
|
653
|
+
const activityAtMs = titleSourceMessage.createdAtMs;
|
|
654
|
+
const nowMs = args.nowMs ?? Date.now();
|
|
655
|
+
try {
|
|
656
|
+
await store.recordActivity({
|
|
657
|
+
activityAtMs,
|
|
658
|
+
conversationId: args.conversationId,
|
|
659
|
+
nowMs,
|
|
660
|
+
title: normalized
|
|
661
|
+
});
|
|
662
|
+
} catch (error) {
|
|
663
|
+
logException(error, "conversation.title.persist.failed");
|
|
664
|
+
return void 0;
|
|
665
|
+
}
|
|
666
|
+
return normalized;
|
|
667
|
+
} catch (error) {
|
|
668
|
+
logException(error, "conversation.title.ensure.failed");
|
|
669
|
+
return void 0;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
function scheduleConversationTitle(args) {
|
|
673
|
+
if (!args.conversationId) {
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
void ensureConversationTitle({
|
|
677
|
+
conversation: args.conversation,
|
|
678
|
+
conversationId: args.conversationId
|
|
679
|
+
}).catch((error) => {
|
|
680
|
+
logException(error, "conversation.title.task.failed");
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
async function resolveConversationTitle(args) {
|
|
684
|
+
const pending = inFlightTitles.get(args.conversationId);
|
|
685
|
+
if (pending) {
|
|
686
|
+
const generated = await pending;
|
|
687
|
+
if (generated?.trim()) {
|
|
688
|
+
return generated.trim();
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
const store = args.conversationStore ?? getConversationStore();
|
|
692
|
+
const stored = await store.get({ conversationId: args.conversationId });
|
|
693
|
+
return stored?.title?.trim() || void 0;
|
|
694
|
+
}
|
|
695
|
+
|
|
185
696
|
// src/chat/conversations/message-summaries.ts
|
|
186
697
|
import { isDeepStrictEqual } from "util";
|
|
187
698
|
function projectConversationMessageSummaries(events) {
|
|
@@ -325,6 +836,10 @@ async function persistConversationMessages(args) {
|
|
|
325
836
|
...args,
|
|
326
837
|
conversationId: args.conversationId
|
|
327
838
|
});
|
|
839
|
+
scheduleConversationTitle({
|
|
840
|
+
conversation: args.conversation,
|
|
841
|
+
conversationId: args.conversationId
|
|
842
|
+
});
|
|
328
843
|
}
|
|
329
844
|
async function appendConversationMessages(eventStore, args) {
|
|
330
845
|
if (args.conversation.messages.length === 0) return;
|
|
@@ -397,6 +912,131 @@ var piContentMessageSchema = z.object({
|
|
|
397
912
|
role: z.string().min(1)
|
|
398
913
|
}).passthrough().transform((value) => value);
|
|
399
914
|
|
|
915
|
+
// src/chat/conversations/structured-events.ts
|
|
916
|
+
import {
|
|
917
|
+
conversationEventPresentationSchema,
|
|
918
|
+
defineConversationEvent
|
|
919
|
+
} from "@sentry/junior-plugin-api";
|
|
920
|
+
import { z as z2 } from "zod";
|
|
921
|
+
var JUNIOR_NATIVE_EVENT_NAMESPACE = "junior";
|
|
922
|
+
var authenticationEventContentSchema = z2.object({
|
|
923
|
+
accountLabel: z2.string().trim().min(1).max(120).optional(),
|
|
924
|
+
actorId: z2.string().min(1),
|
|
925
|
+
authorizationId: z2.string().min(1).optional(),
|
|
926
|
+
provider: z2.string().regex(/^[a-z][a-z0-9-]*$/),
|
|
927
|
+
providerLabel: z2.string().trim().min(1).max(80).optional()
|
|
928
|
+
}).strict();
|
|
929
|
+
var agentsInstructionsUpdatedContentSchema = z2.object({
|
|
930
|
+
action: z2.enum(["loaded", "replaced", "cleared"]),
|
|
931
|
+
directory: z2.string().trim().min(1).max(500).optional(),
|
|
932
|
+
fingerprint: z2.string().trim().min(1).max(128),
|
|
933
|
+
sources: z2.array(
|
|
934
|
+
z2.object({
|
|
935
|
+
content: z2.string().min(1).max(32 * 1024),
|
|
936
|
+
path: z2.string().trim().min(1).max(500)
|
|
937
|
+
}).strict()
|
|
938
|
+
).max(32),
|
|
939
|
+
textBytes: z2.number().int().nonnegative().optional()
|
|
940
|
+
}).strict();
|
|
941
|
+
function providerTitle(content) {
|
|
942
|
+
return content.providerLabel?.trim() || content.provider;
|
|
943
|
+
}
|
|
944
|
+
function agentsInstructionsTitle(action) {
|
|
945
|
+
if (action === "loaded") return "Loaded AGENTS.md";
|
|
946
|
+
if (action === "replaced") return "Updated AGENTS.md";
|
|
947
|
+
return "Cleared AGENTS.md";
|
|
948
|
+
}
|
|
949
|
+
function sourceFilename(sourcePath) {
|
|
950
|
+
return sourcePath.split("/").at(-1) || sourcePath;
|
|
951
|
+
}
|
|
952
|
+
function formatBytes(bytes) {
|
|
953
|
+
if (bytes < 1024) return `${bytes} bytes`;
|
|
954
|
+
const kilobytes = bytes / 1024;
|
|
955
|
+
return `${Number.isInteger(kilobytes) ? kilobytes : kilobytes.toFixed(1)} KB`;
|
|
956
|
+
}
|
|
957
|
+
function agentsInstructionsPreview(content) {
|
|
958
|
+
const source = content.sources[0];
|
|
959
|
+
if (!source) return void 0;
|
|
960
|
+
const filename = sourceFilename(source.path);
|
|
961
|
+
const label = content.sources.length === 1 ? filename : `${content.sources.length} AGENTS.md files`;
|
|
962
|
+
return typeof content.textBytes === "number" ? `${label} \xB7 ${formatBytes(content.textBytes)}` : label;
|
|
963
|
+
}
|
|
964
|
+
var authenticationLinkedEvent = defineConversationEvent({
|
|
965
|
+
name: "authentication_linked",
|
|
966
|
+
version: 1,
|
|
967
|
+
schema: authenticationEventContentSchema,
|
|
968
|
+
renderEvent(event) {
|
|
969
|
+
const provider = providerTitle(event);
|
|
970
|
+
return {
|
|
971
|
+
icon: "link",
|
|
972
|
+
title: `${provider} connected`,
|
|
973
|
+
...event.accountLabel ? { preview: `Connected as \`${event.accountLabel}\`` } : {},
|
|
974
|
+
details: [
|
|
975
|
+
{
|
|
976
|
+
title: `${provider} connected`,
|
|
977
|
+
...event.accountLabel ? { description: `Connected as \`${event.accountLabel}\`` } : {},
|
|
978
|
+
metadata: [event.provider]
|
|
979
|
+
}
|
|
980
|
+
]
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
var authenticationUnlinkedEvent = defineConversationEvent({
|
|
985
|
+
name: "authentication_unlinked",
|
|
986
|
+
version: 1,
|
|
987
|
+
schema: authenticationEventContentSchema,
|
|
988
|
+
renderEvent(event) {
|
|
989
|
+
const provider = providerTitle(event);
|
|
990
|
+
return {
|
|
991
|
+
icon: "key",
|
|
992
|
+
title: `${provider} disconnected`,
|
|
993
|
+
details: [
|
|
994
|
+
{
|
|
995
|
+
title: `${provider} disconnected`,
|
|
996
|
+
metadata: [event.provider]
|
|
997
|
+
}
|
|
998
|
+
]
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
var agentsInstructionsUpdatedEvent = defineConversationEvent({
|
|
1003
|
+
name: "agents_instructions_updated",
|
|
1004
|
+
version: 1,
|
|
1005
|
+
schema: agentsInstructionsUpdatedContentSchema,
|
|
1006
|
+
renderEvent(event) {
|
|
1007
|
+
const title = agentsInstructionsTitle(event.action);
|
|
1008
|
+
const preview = agentsInstructionsPreview(event);
|
|
1009
|
+
return {
|
|
1010
|
+
icon: "brain",
|
|
1011
|
+
title,
|
|
1012
|
+
...preview ? { preview } : {},
|
|
1013
|
+
...event.sources.length > 0 ? {
|
|
1014
|
+
details: event.sources.map((source) => ({
|
|
1015
|
+
title: sourceFilename(source.path),
|
|
1016
|
+
content: source.content
|
|
1017
|
+
}))
|
|
1018
|
+
} : {}
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
var NATIVE_EVENT_DEFINITIONS = [
|
|
1023
|
+
authenticationLinkedEvent,
|
|
1024
|
+
authenticationUnlinkedEvent,
|
|
1025
|
+
agentsInstructionsUpdatedEvent
|
|
1026
|
+
];
|
|
1027
|
+
function getJuniorNativeEventDefinition(args) {
|
|
1028
|
+
return NATIVE_EVENT_DEFINITIONS.find(
|
|
1029
|
+
(definition) => definition.eventName === args.name && definition.version === args.version
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
function renderJuniorNativeConversationEvent(args) {
|
|
1033
|
+
if (args.namespace !== JUNIOR_NATIVE_EVENT_NAMESPACE) return void 0;
|
|
1034
|
+
const definition = getJuniorNativeEventDefinition(args);
|
|
1035
|
+
if (!definition) return void 0;
|
|
1036
|
+
const presentation = definition.renderEvent(definition.parse(args.content));
|
|
1037
|
+
return presentation === void 0 ? void 0 : conversationEventPresentationSchema.parse(presentation);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
400
1040
|
// src/chat/pi/conversation-events.ts
|
|
401
1041
|
function authorizationObservationMessage(data, createdAtMs) {
|
|
402
1042
|
const label = data.kind === "mcp" ? "MCP authorization" : "Authorization";
|
|
@@ -1131,7 +1771,7 @@ async function persistWithRetry(persist) {
|
|
|
1131
1771
|
}
|
|
1132
1772
|
|
|
1133
1773
|
// src/chat/task-execution/turn-cursor.ts
|
|
1134
|
-
import { z as
|
|
1774
|
+
import { z as z3 } from "zod";
|
|
1135
1775
|
|
|
1136
1776
|
// src/chat/repository-instructions.ts
|
|
1137
1777
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -1139,6 +1779,16 @@ import path2 from "path";
|
|
|
1139
1779
|
|
|
1140
1780
|
// src/chat/tools/sandbox/file-utils.ts
|
|
1141
1781
|
import path from "path";
|
|
1782
|
+
|
|
1783
|
+
// src/chat/tools/execution/tool-input-error.ts
|
|
1784
|
+
var ToolInputError = class extends Error {
|
|
1785
|
+
constructor(message, options) {
|
|
1786
|
+
super(message, options);
|
|
1787
|
+
this.name = "ToolInputError";
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
|
|
1791
|
+
// src/chat/tools/sandbox/file-utils.ts
|
|
1142
1792
|
var MAX_TEXT_CHARS = 6e4;
|
|
1143
1793
|
var RIPGREP_EXCLUDED_GLOBS = [
|
|
1144
1794
|
"!**/.git/**",
|
|
@@ -1146,7 +1796,7 @@ var RIPGREP_EXCLUDED_GLOBS = [
|
|
|
1146
1796
|
];
|
|
1147
1797
|
var DEFAULT_SEARCH_COMMAND_TIMEOUT_MS = 3e4;
|
|
1148
1798
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
1149
|
-
function
|
|
1799
|
+
function positiveInteger2(value) {
|
|
1150
1800
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
1151
1801
|
return void 0;
|
|
1152
1802
|
}
|
|
@@ -1524,63 +2174,64 @@ function definedProps(values) {
|
|
|
1524
2174
|
Object.entries(values).filter(([, value]) => value !== void 0)
|
|
1525
2175
|
);
|
|
1526
2176
|
}
|
|
1527
|
-
var turnStatusSchema =
|
|
2177
|
+
var turnStatusSchema = z3.enum([
|
|
1528
2178
|
"running",
|
|
1529
2179
|
"paused",
|
|
1530
2180
|
"completed",
|
|
1531
2181
|
"failed",
|
|
1532
2182
|
"abandoned"
|
|
1533
2183
|
]);
|
|
1534
|
-
var turnSurfaceSchema =
|
|
2184
|
+
var turnSurfaceSchema = z3.enum([
|
|
1535
2185
|
"slack",
|
|
1536
2186
|
"api",
|
|
1537
2187
|
"scheduler",
|
|
1538
2188
|
"internal"
|
|
1539
2189
|
]);
|
|
1540
|
-
var turnPauseReasonSchema =
|
|
2190
|
+
var turnPauseReasonSchema = z3.enum([
|
|
1541
2191
|
"timeout",
|
|
1542
2192
|
"auth",
|
|
1543
2193
|
"yield",
|
|
1544
2194
|
"retry"
|
|
1545
2195
|
]);
|
|
1546
|
-
var nonNegativeNumberSchema =
|
|
1547
|
-
var seqCursorSchema =
|
|
1548
|
-
var storedTurnSummarySchema =
|
|
1549
|
-
schemaVersion:
|
|
1550
|
-
version:
|
|
1551
|
-
conversationId:
|
|
1552
|
-
dispatchId:
|
|
1553
|
-
dispatchOutcome:
|
|
1554
|
-
resultMessageId:
|
|
2196
|
+
var nonNegativeNumberSchema = z3.number().finite().nonnegative();
|
|
2197
|
+
var seqCursorSchema = z3.number().int().min(-1);
|
|
2198
|
+
var storedTurnSummarySchema = z3.object({
|
|
2199
|
+
schemaVersion: z3.literal(TURN_CURSOR_SCHEMA_VERSION),
|
|
2200
|
+
version: z3.number().int().nonnegative(),
|
|
2201
|
+
conversationId: z3.string().min(1),
|
|
2202
|
+
dispatchId: z3.string().min(1).optional(),
|
|
2203
|
+
dispatchOutcome: z3.enum(["blocked", "completed", "failed"]).optional(),
|
|
2204
|
+
resultMessageId: z3.string().min(1).optional(),
|
|
1555
2205
|
resumeReason: turnPauseReasonSchema.optional(),
|
|
1556
|
-
turnId:
|
|
1557
|
-
sliceId:
|
|
2206
|
+
turnId: z3.string().min(1),
|
|
2207
|
+
sliceId: z3.number().int().nonnegative(),
|
|
1558
2208
|
state: turnStatusSchema,
|
|
1559
2209
|
surface: turnSurfaceSchema.optional(),
|
|
1560
2210
|
updatedAtMs: nonNegativeNumberSchema
|
|
1561
2211
|
}).strip();
|
|
1562
|
-
var storedTurnRecordSchema =
|
|
1563
|
-
schemaVersion:
|
|
1564
|
-
version:
|
|
1565
|
-
conversationId:
|
|
1566
|
-
dispatchId:
|
|
1567
|
-
dispatchOutcome:
|
|
1568
|
-
resultMessageId:
|
|
2212
|
+
var storedTurnRecordSchema = z3.object({
|
|
2213
|
+
schemaVersion: z3.literal(TURN_CURSOR_SCHEMA_VERSION),
|
|
2214
|
+
version: z3.number().int().nonnegative(),
|
|
2215
|
+
conversationId: z3.string().min(1),
|
|
2216
|
+
dispatchId: z3.string().min(1).optional(),
|
|
2217
|
+
dispatchOutcome: z3.enum(["blocked", "completed", "failed"]).optional(),
|
|
2218
|
+
resultMessageId: z3.string().min(1).optional(),
|
|
1569
2219
|
lastProgressAtMs: nonNegativeNumberSchema,
|
|
1570
2220
|
resumeReason: turnPauseReasonSchema.optional(),
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
2221
|
+
publishExternally: z3.boolean().optional(),
|
|
2222
|
+
resumedFromSliceId: z3.number().int().nonnegative().optional(),
|
|
2223
|
+
turnId: z3.string().min(1),
|
|
2224
|
+
sliceId: z3.number().int().nonnegative(),
|
|
1574
2225
|
startedAtMs: nonNegativeNumberSchema,
|
|
1575
2226
|
state: turnStatusSchema,
|
|
1576
2227
|
surface: turnSurfaceSchema.optional(),
|
|
1577
|
-
traceId:
|
|
2228
|
+
traceId: z3.string().optional(),
|
|
1578
2229
|
updatedAtMs: nonNegativeNumberSchema,
|
|
1579
2230
|
committedSeq: seqCursorSchema,
|
|
1580
|
-
historyVersion:
|
|
1581
|
-
errorMessage:
|
|
2231
|
+
historyVersion: z3.number().int().nonnegative().optional(),
|
|
2232
|
+
errorMessage: z3.string().optional(),
|
|
1582
2233
|
turnStartSeq: seqCursorSchema.optional(),
|
|
1583
|
-
runtimeContext:
|
|
2234
|
+
runtimeContext: z3.array(piMessageSchema).optional()
|
|
1584
2235
|
}).strip();
|
|
1585
2236
|
function conversationExecutionFromSummary(summary) {
|
|
1586
2237
|
const status = summary.state === "completed" || summary.state === "abandoned" ? "idle" : summary.state;
|
|
@@ -1629,7 +2280,7 @@ async function recordConversationActivityMetadata(args) {
|
|
|
1629
2280
|
});
|
|
1630
2281
|
const isChild = Boolean(conversation?.lineage);
|
|
1631
2282
|
const destination = isChild ? void 0 : args.destination;
|
|
1632
|
-
const activitySource = isChild ? "internal" : destination?.platform === "local" ? "local" : destination ? args.summary.surface : void 0;
|
|
2283
|
+
const activitySource = isChild ? "internal" : args.source?.platform === "web" ? "web" : destination?.platform === "local" ? "local" : destination ? args.summary.surface : void 0;
|
|
1633
2284
|
await conversationStore.recordActivity({
|
|
1634
2285
|
activityAtMs: args.summary.updatedAtMs,
|
|
1635
2286
|
channelName: args.summary.channelName,
|
|
@@ -1681,6 +2332,7 @@ function materializeTurnRecord(stored, piProjection, turnStartMessageIndex, rest
|
|
|
1681
2332
|
dispatchOutcome: stored.dispatchOutcome,
|
|
1682
2333
|
errorMessage: stored.errorMessage,
|
|
1683
2334
|
resumeReason: stored.resumeReason,
|
|
2335
|
+
publishExternally: stored.publishExternally,
|
|
1684
2336
|
resultMessageId: stored.resultMessageId,
|
|
1685
2337
|
resumedFromSliceId: stored.resumedFromSliceId,
|
|
1686
2338
|
surface: stored.surface,
|
|
@@ -1790,6 +2442,7 @@ function buildStoredRecord(args) {
|
|
|
1790
2442
|
errorMessage: args.errorMessage,
|
|
1791
2443
|
historyVersion: args.historyVersion,
|
|
1792
2444
|
resumeReason: args.resumeReason,
|
|
2445
|
+
publishExternally: args.publishExternally,
|
|
1793
2446
|
resultMessageId: args.resultMessageId,
|
|
1794
2447
|
resumedFromSliceId: args.resumedFromSliceId,
|
|
1795
2448
|
runtimeContext: args.runtimeContext && args.runtimeContext.length > 0 ? args.runtimeContext : void 0,
|
|
@@ -1877,6 +2530,7 @@ async function updateTurnState(args) {
|
|
|
1877
2530
|
errorMessage: args.errorMessage ?? args.existing.errorMessage,
|
|
1878
2531
|
historyVersion: parsed.historyVersion,
|
|
1879
2532
|
resumeReason: args.existing.resumeReason,
|
|
2533
|
+
publishExternally: args.existing.publishExternally,
|
|
1880
2534
|
resultMessageId: args.resultMessageId ?? args.existing.resultMessageId,
|
|
1881
2535
|
resumedFromSliceId: args.existing.resumedFromSliceId,
|
|
1882
2536
|
surface: args.existing.surface,
|
|
@@ -1964,6 +2618,7 @@ async function upsertTurnRecordLocked(args, fence) {
|
|
|
1964
2618
|
errorMessage: args.errorMessage,
|
|
1965
2619
|
lastProgressAtMs: args.lastProgressAtMs,
|
|
1966
2620
|
resumeReason: args.resumeReason,
|
|
2621
|
+
publishExternally: args.publishExternally ?? existingRecord?.publishExternally,
|
|
1967
2622
|
resultMessageId: args.resultMessageId ?? existingRecord?.resultMessageId,
|
|
1968
2623
|
resumedFromSliceId: args.resumedFromSliceId,
|
|
1969
2624
|
runtimeContext: args.state === "running" || args.state === "paused" ? retainedRuntimeContext : void 0,
|
|
@@ -2120,6 +2775,96 @@ async function failTurnRecord(args) {
|
|
|
2120
2775
|
);
|
|
2121
2776
|
}
|
|
2122
2777
|
|
|
2778
|
+
// src/chat/usage.ts
|
|
2779
|
+
var agentTurnUsageSchema = usageSchema;
|
|
2780
|
+
var COMPONENT_USAGE_FIELDS = [
|
|
2781
|
+
"inputTokens",
|
|
2782
|
+
"outputTokens",
|
|
2783
|
+
"cachedInputTokens",
|
|
2784
|
+
"cacheCreationTokens"
|
|
2785
|
+
];
|
|
2786
|
+
var COST_COMPONENT_FIELDS = [
|
|
2787
|
+
"input",
|
|
2788
|
+
"output",
|
|
2789
|
+
"cacheRead",
|
|
2790
|
+
"cacheWrite"
|
|
2791
|
+
];
|
|
2792
|
+
function hasAgentTurnUsage(usage) {
|
|
2793
|
+
return Boolean(
|
|
2794
|
+
usage && (Object.entries(usage).some(
|
|
2795
|
+
([field, value]) => field !== "cost" && typeof value === "number" && Number.isFinite(value)
|
|
2796
|
+
) || Object.values(usage.cost ?? {}).some(
|
|
2797
|
+
(value) => typeof value === "number" && Number.isFinite(value)
|
|
2798
|
+
))
|
|
2799
|
+
);
|
|
2800
|
+
}
|
|
2801
|
+
function getFiniteCount(value) {
|
|
2802
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : void 0;
|
|
2803
|
+
}
|
|
2804
|
+
function getFiniteCost(value) {
|
|
2805
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : void 0;
|
|
2806
|
+
}
|
|
2807
|
+
function addCost(left, right) {
|
|
2808
|
+
return Math.round(((left ?? 0) + right) * 1e12) / 1e12;
|
|
2809
|
+
}
|
|
2810
|
+
function getComponentTotal(usage) {
|
|
2811
|
+
let total;
|
|
2812
|
+
for (const field of COMPONENT_USAGE_FIELDS) {
|
|
2813
|
+
const value = getFiniteCount(usage[field]);
|
|
2814
|
+
if (value === void 0) continue;
|
|
2815
|
+
total = (total ?? 0) + value;
|
|
2816
|
+
}
|
|
2817
|
+
return total;
|
|
2818
|
+
}
|
|
2819
|
+
function addAgentTurnUsage(...usages) {
|
|
2820
|
+
const components = {};
|
|
2821
|
+
let componentTotal;
|
|
2822
|
+
let totalOnlyTokens;
|
|
2823
|
+
let reasoningTokens;
|
|
2824
|
+
const cost = {};
|
|
2825
|
+
for (const usage of usages) {
|
|
2826
|
+
if (!usage) continue;
|
|
2827
|
+
const reasoning = getFiniteCount(usage.reasoningTokens);
|
|
2828
|
+
if (reasoning !== void 0) {
|
|
2829
|
+
reasoningTokens = (reasoningTokens ?? 0) + reasoning;
|
|
2830
|
+
}
|
|
2831
|
+
if (usage.cost) {
|
|
2832
|
+
for (const field of [...COST_COMPONENT_FIELDS, "total"]) {
|
|
2833
|
+
const value = getFiniteCost(usage.cost[field]);
|
|
2834
|
+
if (value === void 0) continue;
|
|
2835
|
+
cost[field] = addCost(cost[field], value);
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
const usageComponentTotal = getComponentTotal(usage);
|
|
2839
|
+
if (usageComponentTotal !== void 0) {
|
|
2840
|
+
componentTotal = (componentTotal ?? 0) + usageComponentTotal;
|
|
2841
|
+
for (const field of COMPONENT_USAGE_FIELDS) {
|
|
2842
|
+
const value = getFiniteCount(usage[field]);
|
|
2843
|
+
if (value === void 0) continue;
|
|
2844
|
+
components[field] = (components[field] ?? 0) + value;
|
|
2845
|
+
}
|
|
2846
|
+
continue;
|
|
2847
|
+
}
|
|
2848
|
+
const totalTokens = getFiniteCount(usage.totalTokens);
|
|
2849
|
+
if (totalTokens !== void 0) {
|
|
2850
|
+
totalOnlyTokens = (totalOnlyTokens ?? 0) + totalTokens;
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
if (totalOnlyTokens !== void 0) {
|
|
2854
|
+
return {
|
|
2855
|
+
totalTokens: totalOnlyTokens + (componentTotal ?? 0),
|
|
2856
|
+
...reasoningTokens !== void 0 ? { reasoningTokens } : {},
|
|
2857
|
+
...Object.keys(cost).length > 0 ? { cost } : {}
|
|
2858
|
+
};
|
|
2859
|
+
}
|
|
2860
|
+
const result = {
|
|
2861
|
+
...components,
|
|
2862
|
+
...reasoningTokens !== void 0 ? { reasoningTokens } : {},
|
|
2863
|
+
...Object.keys(cost).length > 0 ? { cost } : {}
|
|
2864
|
+
};
|
|
2865
|
+
return hasAgentTurnUsage(result) ? result : void 0;
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2123
2868
|
// src/chat/services/turn-limit.ts
|
|
2124
2869
|
var TurnSliceLimitExceededError = class extends Error {
|
|
2125
2870
|
constructor(maxSlices) {
|
|
@@ -2180,6 +2925,7 @@ function sharedWrite(args, latest) {
|
|
|
2180
2925
|
destination: args.destination,
|
|
2181
2926
|
destinationVisibility: args.destinationVisibility,
|
|
2182
2927
|
dispatchId: args.dispatchId ?? latest?.dispatchId,
|
|
2928
|
+
publishExternally: args.publishExternally ?? latest?.publishExternally,
|
|
2183
2929
|
source: args.source,
|
|
2184
2930
|
surface: args.surface ?? latest?.surface,
|
|
2185
2931
|
traceId: getActiveTraceId() ?? latest?.traceId,
|
|
@@ -2371,6 +3117,7 @@ function isPendingAuthLatestRequest(conversation, pendingAuth) {
|
|
|
2371
3117
|
}
|
|
2372
3118
|
|
|
2373
3119
|
export {
|
|
3120
|
+
renderJuniorNativeConversationEvent,
|
|
2374
3121
|
TURN_CONTEXT_TAG,
|
|
2375
3122
|
isAssistantMessage,
|
|
2376
3123
|
isToolResultMessage,
|
|
@@ -2388,6 +3135,24 @@ export {
|
|
|
2388
3135
|
stripRuntimeTurnContext,
|
|
2389
3136
|
historyItemFromPiMessage,
|
|
2390
3137
|
piMessageFromHistoryItem,
|
|
3138
|
+
estimateTextTokens,
|
|
3139
|
+
getAgentContextCompactionTriggerTokens,
|
|
3140
|
+
getAgentContextInputLimitTokens,
|
|
3141
|
+
normalizeConversationText,
|
|
3142
|
+
estimateConversationContextTokens,
|
|
3143
|
+
upsertConversationMessage,
|
|
3144
|
+
recordDeliveredAssistantMessage,
|
|
3145
|
+
turnHasReply,
|
|
3146
|
+
markConversationMessage,
|
|
3147
|
+
buildConversationContext,
|
|
3148
|
+
createConversationMemoryService,
|
|
3149
|
+
isHumanConversationMessage,
|
|
3150
|
+
getConversationMessageSlackTs,
|
|
3151
|
+
SHORT_TITLE_MAX_LENGTH,
|
|
3152
|
+
fallbackShortTitle,
|
|
3153
|
+
generateShortTitle,
|
|
3154
|
+
resolveTaskTitle,
|
|
3155
|
+
resolveConversationTitle,
|
|
2391
3156
|
persistConversationMessageSummaries,
|
|
2392
3157
|
hydrateConversationMessages,
|
|
2393
3158
|
persistConversationMessages,
|
|
@@ -2407,10 +3172,11 @@ export {
|
|
|
2407
3172
|
recordTurnRoute,
|
|
2408
3173
|
recordToolExecutionStarted,
|
|
2409
3174
|
recordGuardianActionReviewed,
|
|
3175
|
+
ToolInputError,
|
|
2410
3176
|
MAX_TEXT_CHARS,
|
|
2411
3177
|
RIPGREP_EXCLUDED_GLOBS,
|
|
2412
3178
|
DEFAULT_SEARCH_COMMAND_TIMEOUT_MS,
|
|
2413
|
-
positiveInteger,
|
|
3179
|
+
positiveInteger2 as positiveInteger,
|
|
2414
3180
|
normalizeToLf,
|
|
2415
3181
|
truncateText,
|
|
2416
3182
|
isMissingPathError,
|
|
@@ -2445,6 +3211,9 @@ export {
|
|
|
2445
3211
|
sanitizeAssistantText,
|
|
2446
3212
|
decideReply,
|
|
2447
3213
|
getAssistantReplyText,
|
|
3214
|
+
agentTurnUsageSchema,
|
|
3215
|
+
hasAgentTurnUsage,
|
|
3216
|
+
addAgentTurnUsage,
|
|
2448
3217
|
TurnSliceLimitExceededError,
|
|
2449
3218
|
buildTurnLimitResponse,
|
|
2450
3219
|
persistWithRetry,
|