@sentry/junior 0.141.0 → 0.143.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.
Files changed (70) hide show
  1. package/dist/{agent-hooks-HIRVKUQJ.js → agent-hooks-2EP3QS47.js} +10 -10
  2. package/dist/api/schema/task.d.ts +8 -0
  3. package/dist/api/schema.js +1 -1
  4. package/dist/api.js +34 -22
  5. package/dist/app.js +62 -91
  6. package/dist/{catalog-runtime-XVLED5UH.js → catalog-runtime-IAVW4W3B.js} +5 -5
  7. package/dist/chat/event-tasks/types.d.ts +7 -1
  8. package/dist/chat/runtime/turn.d.ts +0 -4
  9. package/dist/chat/scheduled-tasks/tools/create.d.ts +1 -0
  10. package/dist/chat/scheduled-tasks/types.d.ts +5 -0
  11. package/dist/chat/services/conversation-memory.d.ts +2 -1
  12. package/dist/chat/services/short-title.d.ts +25 -0
  13. package/dist/chat/state/conversation.d.ts +6 -17
  14. package/dist/chat/tools/create-event-task.d.ts +1 -0
  15. package/dist/{chunk-3H42HMA2.js → chunk-2KLMGRRQ.js} +5 -1
  16. package/dist/{chunk-HN4UZTG7.js → chunk-2T5CHXRZ.js} +2 -2
  17. package/dist/{chunk-PGJUJCOQ.js → chunk-5YJBS4I5.js} +1 -1
  18. package/dist/{chunk-BBLO66XT.js → chunk-7GVX5SOG.js} +2 -2
  19. package/dist/{chunk-2DOVDDZJ.js → chunk-A3XPSABC.js} +3 -3
  20. package/dist/{chunk-FZFJZZR3.js → chunk-AEFJN7OK.js} +4 -4
  21. package/dist/{chunk-DK3GQWJK.js → chunk-ANG7IWAI.js} +6 -6
  22. package/dist/{chunk-LMGKSDO4.js → chunk-BJ6ISBOA.js} +1 -1
  23. package/dist/{chunk-H4WNQFBH.js → chunk-F6RWNJBK.js} +5 -5
  24. package/dist/{chunk-UFEU4UX6.js → chunk-GZRWULXF.js} +1 -1
  25. package/dist/{chunk-DVIJ6DP6.js → chunk-I25V3XRN.js} +2 -2
  26. package/dist/{chunk-A2O7SGK5.js → chunk-I4NQNZVW.js} +6 -6
  27. package/dist/{chunk-DKH4WGZU.js → chunk-I5PIM72M.js} +341 -16
  28. package/dist/{chunk-FWXSPJRN.js → chunk-LSBQHDI2.js} +1 -1
  29. package/dist/{chunk-6U44QGXL.js → chunk-M2T7MHQJ.js} +1 -1
  30. package/dist/{chunk-5MFCEKR6.js → chunk-NAINBOZQ.js} +3 -3
  31. package/dist/{chunk-EYD523BV.js → chunk-NVFVM67W.js} +1 -1
  32. package/dist/{chunk-43OPSFUY.js → chunk-OB7ZJK7Y.js} +1 -1
  33. package/dist/{chunk-HQAFIN6O.js → chunk-OG5JQHKR.js} +1 -1
  34. package/dist/{chunk-YWM6MJT4.js → chunk-OGQGJAD7.js} +2 -0
  35. package/dist/{chunk-PIQKV7IR.js → chunk-PBV7VXUA.js} +10 -451
  36. package/dist/{chunk-LIVSCWI5.js → chunk-QFWXGUAH.js} +23 -26
  37. package/dist/{chunk-UONUDOJP.js → chunk-RABHACKG.js} +7 -7
  38. package/dist/{chunk-7ULXCNOZ.js → chunk-SNBTWIQO.js} +6 -6
  39. package/dist/chunk-STX5WIH6.js +75 -0
  40. package/dist/{chunk-44NWPKY3.js → chunk-TPJK6AVJ.js} +1 -1
  41. package/dist/{chunk-6FRAWWGR.js → chunk-U5ATCOHE.js} +2 -2
  42. package/dist/{chunk-5LPWHC7Q.js → chunk-UFCA4EZB.js} +80 -46
  43. package/dist/chunk-WJHWOAVZ.js +67 -0
  44. package/dist/{chunk-NFL4FRIU.js → chunk-WM4PRM7W.js} +4 -4
  45. package/dist/{chunk-OFQBDHVG.js → chunk-WSWVWP2V.js} +1 -1
  46. package/dist/{chunk-DBKS7JR2.js → chunk-X5SC2UGE.js} +3 -3
  47. package/dist/{chunk-OHO46E7F.js → chunk-XYJNNZYR.js} +88 -36
  48. package/dist/cli/chat.js +32 -30
  49. package/dist/cli/check.js +6 -6
  50. package/dist/cli/plugins.js +13 -13
  51. package/dist/cli/snapshot-create.js +9 -9
  52. package/dist/cli/upgrade.js +7 -7
  53. package/dist/db/schema/event-tasks.d.ts +20 -52
  54. package/dist/db/schema/scheduled-tasks.d.ts +17 -0
  55. package/dist/db/schema.d.ts +36 -52
  56. package/dist/{db-PSMQZR4P.js → db-RBXBVEVO.js} +7 -7
  57. package/dist/instrumentation.js +4 -4
  58. package/dist/nitro.js +2 -2
  59. package/dist/{oauth-callback-server-XZUK2AT6.js → oauth-callback-server-LRB6BX6C.js} +23 -21
  60. package/dist/{runner-5EKJCQWP.js → runner-WK5VUOW6.js} +24 -25
  61. package/dist/{skills-2PRM42SE.js → skills-MJWRME3A.js} +6 -6
  62. package/dist/{spawn-UGTLRTFP.js → spawn-ZCW6UOAA.js} +17 -17
  63. package/dist/{validation-XLXAIRTR.js → validation-556WSWVU.js} +6 -6
  64. package/dist/version.js +1 -1
  65. package/dist/{work-CNTNEQ2Q.js → work-W6IXSPY3.js} +16 -16
  66. package/dist/{worker-BGW7CKZ7.js → worker-5KM346HH.js} +10 -10
  67. package/migrations/0023_task_title_columns.sql +2 -0
  68. package/migrations/meta/0023_snapshot.json +2198 -0
  69. package/migrations/meta/_journal.json +7 -0
  70. package/package.json +5 -5
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DEFAULT_SQL_STATEMENT_TIMEOUT_MS
3
- } from "./chunk-BBLO66XT.js";
3
+ } from "./chunk-7GVX5SOG.js";
4
4
  import {
5
5
  juniorDestinations,
6
6
  timestamptz
@@ -379,6 +379,8 @@ var juniorEventTasks = pgTable9(
379
379
  namespace: text9("namespace").notNull(),
380
380
  identifier: text9("identifier").notNull(),
381
381
  createdAtMs: bigint("created_at_ms", { mode: "number" }).notNull(),
382
+ /** Short display title generated from the task instruction. */
383
+ title: text9("title"),
382
384
  task: jsonb6("task_json").$type().notNull()
383
385
  },
384
386
  (table) => [
@@ -487,6 +489,8 @@ var juniorSchedulerTasks = pgTable12(
487
489
  nextRunAtMs: bigint3("next_run_at_ms", { mode: "number" }),
488
490
  runNowAtMs: bigint3("run_now_at_ms", { mode: "number" }),
489
491
  createdAtMs: bigint3("created_at_ms", { mode: "number" }).notNull(),
492
+ /** Short display title generated from the task instruction. */
493
+ title: text12("title"),
490
494
  record: jsonb7("record").$type().notNull()
491
495
  },
492
496
  (table) => [
@@ -3,10 +3,10 @@ import {
3
3
  } from "./chunk-UTL3MHPC.js";
4
4
  import {
5
5
  parseSlackThreadId
6
- } from "./chunk-HQAFIN6O.js";
6
+ } from "./chunk-OG5JQHKR.js";
7
7
  import {
8
8
  normalizeSlackConversationId
9
- } from "./chunk-DVIJ6DP6.js";
9
+ } from "./chunk-I25V3XRN.js";
10
10
 
11
11
  // src/handlers/health.ts
12
12
  function readHealthReport() {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logWarn
3
- } from "./chunk-UFEU4UX6.js";
3
+ } from "./chunk-GZRWULXF.js";
4
4
 
5
5
  // src/chat/conversation-privacy.ts
6
6
  import { AsyncLocalStorage } from "async_hooks";
@@ -3,7 +3,7 @@ import {
3
3
  toCanonicalInputMessage,
4
4
  toCanonicalOutputMessage,
5
5
  toGenAiMessagesTraceAttributes
6
- } from "./chunk-PGJUJCOQ.js";
6
+ } from "./chunk-5YJBS4I5.js";
7
7
  import {
8
8
  extractGenAiUsageAttributes,
9
9
  logException,
@@ -11,7 +11,7 @@ import {
11
11
  normalizeGenAiFinishReason,
12
12
  serializeGenAiAttribute,
13
13
  withSpan
14
- } from "./chunk-UFEU4UX6.js";
14
+ } from "./chunk-GZRWULXF.js";
15
15
 
16
16
  // src/chat/services/provider-error.ts
17
17
  var ProviderError = class extends Error {
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  getDb
3
- } from "./chunk-5MFCEKR6.js";
3
+ } from "./chunk-NAINBOZQ.js";
4
4
  import {
5
5
  juniorConversations,
6
6
  juniorTaskExecutions
7
- } from "./chunk-3H42HMA2.js";
7
+ } from "./chunk-2KLMGRRQ.js";
8
8
  import {
9
9
  logWarn
10
- } from "./chunk-UFEU4UX6.js";
10
+ } from "./chunk-GZRWULXF.js";
11
11
 
12
12
  // src/chat/tasks/execution-stats.ts
13
13
  import { and, asc, count, desc, eq, gte, inArray, lte, max, sql } from "drizzle-orm";
@@ -4,18 +4,18 @@ import {
4
4
  } from "./chunk-EM225ITJ.js";
5
5
  import {
6
6
  getStateAdapter
7
- } from "./chunk-6U44QGXL.js";
7
+ } from "./chunk-M2T7MHQJ.js";
8
8
  import {
9
9
  toOptionalTrimmed
10
- } from "./chunk-BBLO66XT.js";
10
+ } from "./chunk-7GVX5SOG.js";
11
11
  import {
12
12
  pluginCatalogRuntime
13
- } from "./chunk-EYD523BV.js";
13
+ } from "./chunk-NVFVM67W.js";
14
14
  import {
15
15
  setSpanAttributes,
16
16
  setSpanStatus,
17
17
  withSpan
18
- } from "./chunk-UFEU4UX6.js";
18
+ } from "./chunk-GZRWULXF.js";
19
19
 
20
20
  // src/chat/sandbox/resources.ts
21
21
  var configuredResources;
@@ -4,19 +4,19 @@ import {
4
4
  isDmChannel,
5
5
  normalizeSlackConversationId,
6
6
  withSlackRetries
7
- } from "./chunk-DVIJ6DP6.js";
7
+ } from "./chunk-I25V3XRN.js";
8
8
  import {
9
9
  parseDestination
10
- } from "./chunk-5MFCEKR6.js";
10
+ } from "./chunk-NAINBOZQ.js";
11
11
  import {
12
12
  getStateAdapter
13
- } from "./chunk-6U44QGXL.js";
13
+ } from "./chunk-M2T7MHQJ.js";
14
14
  import {
15
15
  normalizeSlackEmojiName
16
- } from "./chunk-BBLO66XT.js";
16
+ } from "./chunk-7GVX5SOG.js";
17
17
  import {
18
18
  pluginCatalogRuntime
19
- } from "./chunk-EYD523BV.js";
19
+ } from "./chunk-NVFVM67W.js";
20
20
  import {
21
21
  parseSlackMessageTs,
22
22
  parseSlackUserId
@@ -25,7 +25,7 @@ import {
25
25
  isRecord,
26
26
  logInfo,
27
27
  logWarn
28
- } from "./chunk-UFEU4UX6.js";
28
+ } from "./chunk-GZRWULXF.js";
29
29
 
30
30
  // src/chat/slack/outbound.ts
31
31
  var MAX_SLACK_MESSAGE_TEXT_CHARS = 4e4;
@@ -5,7 +5,7 @@ import {
5
5
  logInfo,
6
6
  logWarn,
7
7
  setSpanAttributes
8
- } from "./chunk-UFEU4UX6.js";
8
+ } from "./chunk-GZRWULXF.js";
9
9
  import {
10
10
  discoverInstalledPluginPackageContent,
11
11
  normalizePluginPackageNames
@@ -4,24 +4,24 @@ import {
4
4
  import {
5
5
  formatProviderLabel,
6
6
  startOAuthFlow
7
- } from "./chunk-DK3GQWJK.js";
7
+ } from "./chunk-ANG7IWAI.js";
8
8
  import {
9
9
  abandonReplacedPendingAuth,
10
10
  canReusePendingAuthLink,
11
11
  recordAuthorizationRequested
12
- } from "./chunk-PIQKV7IR.js";
12
+ } from "./chunk-PBV7VXUA.js";
13
13
  import {
14
14
  parseSandboxEgressAuthRequiredSignal
15
15
  } from "./chunk-HUO3UTAQ.js";
16
16
  import {
17
17
  AGENT_INVOCATION_MAILBOX_STATUSES
18
- } from "./chunk-3H42HMA2.js";
18
+ } from "./chunk-2KLMGRRQ.js";
19
19
  import {
20
20
  TURN_REASONING_LEVELS
21
- } from "./chunk-BBLO66XT.js";
21
+ } from "./chunk-7GVX5SOG.js";
22
22
  import {
23
23
  pluginCatalogRuntime
24
- } from "./chunk-EYD523BV.js";
24
+ } from "./chunk-NVFVM67W.js";
25
25
  import {
26
26
  credentialContextSchema
27
27
  } from "./chunk-RUIXF3YQ.js";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-6GWA276C.js";
10
10
  import {
11
11
  getDeploymentTelemetryAttributes
12
- } from "./chunk-OFQBDHVG.js";
12
+ } from "./chunk-WSWVWP2V.js";
13
13
 
14
14
  // src/chat/logging.ts
15
15
  import path from "path";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-EM225ITJ.js";
4
4
  import {
5
5
  getSlackBotToken
6
- } from "./chunk-BBLO66XT.js";
6
+ } from "./chunk-7GVX5SOG.js";
7
7
  import {
8
8
  parseSlackChannelReferenceId
9
9
  } from "./chunk-F3B2YJ76.js";
@@ -12,7 +12,7 @@ import {
12
12
  setSpanAttributes,
13
13
  setSpanStatus,
14
14
  withSpan
15
- } from "./chunk-UFEU4UX6.js";
15
+ } from "./chunk-GZRWULXF.js";
16
16
 
17
17
  // src/chat/slack/client.ts
18
18
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  appendAndEnqueueInboundMessage
3
- } from "./chunk-NFL4FRIU.js";
3
+ } from "./chunk-WM4PRM7W.js";
4
4
  import {
5
5
  ConversationTurnLifecycleService
6
6
  } from "./chunk-Q6QZTTLS.js";
@@ -12,7 +12,7 @@ import {
12
12
  agentBindingSchema,
13
13
  agentInvocationSchema,
14
14
  createAgentInvocationSchema
15
- } from "./chunk-H4WNQFBH.js";
15
+ } from "./chunk-F6RWNJBK.js";
16
16
  import {
17
17
  TurnInputCommitLostError,
18
18
  coerceThreadArtifactsState,
@@ -28,20 +28,20 @@ import {
28
28
  persistCompletedSessionRecord,
29
29
  persistThreadStateById,
30
30
  persistYieldSessionRecord
31
- } from "./chunk-PIQKV7IR.js";
31
+ } from "./chunk-PBV7VXUA.js";
32
32
  import {
33
33
  getConversationEventStore,
34
34
  getConversationStore,
35
35
  getSqlExecutor
36
- } from "./chunk-5MFCEKR6.js";
36
+ } from "./chunk-NAINBOZQ.js";
37
37
  import {
38
38
  juniorAgentBindings,
39
39
  juniorAgentInvocations
40
- } from "./chunk-3H42HMA2.js";
40
+ } from "./chunk-2KLMGRRQ.js";
41
41
  import {
42
42
  botConfig,
43
43
  modelIdForProfile
44
- } from "./chunk-BBLO66XT.js";
44
+ } from "./chunk-7GVX5SOG.js";
45
45
 
46
46
  // src/chat/agent-invocations/work.ts
47
47
  import { z } from "zod";
@@ -1,11 +1,16 @@
1
1
  import {
2
2
  recordTaskExecution
3
- } from "./chunk-2DOVDDZJ.js";
3
+ } from "./chunk-A3XPSABC.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-WJHWOAVZ.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
- updateConversationStats
28
- } from "./chunk-PIQKV7IR.js";
30
+ stripRuntimeTurnContext
31
+ } from "./chunk-PBV7VXUA.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-STX5WIH6.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-7ULXCNOZ.js";
46
+ } from "./chunk-SNBTWIQO.js";
40
47
  import {
41
48
  getConversationStore,
42
49
  getDb,
43
50
  sameActorIdentity
44
- } from "./chunk-5MFCEKR6.js";
51
+ } from "./chunk-NAINBOZQ.js";
45
52
  import {
46
53
  getStateAdapter
47
- } from "./chunk-6U44QGXL.js";
54
+ } from "./chunk-M2T7MHQJ.js";
48
55
  import {
49
56
  ProviderError,
57
+ botConfig,
58
+ escapeXml,
50
59
  findProviderError,
51
60
  getProviderErrorAttributes,
52
61
  getProviderErrorUserMessage
53
- } from "./chunk-BBLO66XT.js";
62
+ } from "./chunk-7GVX5SOG.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
- } from "./chunk-UFEU4UX6.js";
70
+ buildTurnFailureResponse,
71
+ logWarn,
72
+ setSpanAttributes
73
+ } from "./chunk-GZRWULXF.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-PSMQZR4P.js")).getConversationStore();
413
+ const conversationStore = args.conversationStore ?? (await import("./db-RBXBVEVO.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,