@sentry/junior 0.155.0 → 0.156.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 (79) hide show
  1. package/dist/{agent-hooks-AWVTLAV2.js → agent-hooks-CCAR46PQ.js} +10 -10
  2. package/dist/api/locations/detail.d.ts +1 -0
  3. package/dist/api/schema/conversation.d.ts +19 -4
  4. package/dist/api/schema/location.d.ts +1 -0
  5. package/dist/api/schema/person.d.ts +1 -0
  6. package/dist/api/schema.js +1 -1
  7. package/dist/api.js +48 -36
  8. package/dist/app.js +147 -44
  9. package/dist/{catalog-runtime-V6YD6KH5.js → catalog-runtime-3SNKYCBG.js} +5 -5
  10. package/dist/chat/agent/types.d.ts +2 -0
  11. package/dist/chat/attachments/storage.d.ts +12 -0
  12. package/dist/chat/attachments/store.d.ts +52 -0
  13. package/dist/chat/attachments/vercel.d.ts +3 -0
  14. package/dist/chat/conversations/retention.d.ts +4 -0
  15. package/dist/chat/ingress/bot-mention.d.ts +13 -0
  16. package/dist/chat/plugins/unfinished-work.d.ts +6 -0
  17. package/dist/chat/runtime/agent-runner.d.ts +2 -0
  18. package/dist/chat/services/conversation-memory.d.ts +1 -1
  19. package/dist/chat/slack/tools/send-files.d.ts +17 -11
  20. package/dist/chat/state/conversation.d.ts +2 -1
  21. package/dist/chat/tools/types.d.ts +2 -0
  22. package/dist/{chunk-V57LZDHN.js → chunk-3FFUC32L.js} +6 -6
  23. package/dist/{chunk-J2SYI36O.js → chunk-3L2PMOSR.js} +4 -4
  24. package/dist/{chunk-2AHVM3HK.js → chunk-4ZZDTHFC.js} +10 -8
  25. package/dist/{chunk-AENPRXCG.js → chunk-53W3LZEW.js} +381 -55
  26. package/dist/{chunk-ELOTIL5F.js → chunk-6CINHXIL.js} +4 -4
  27. package/dist/{chunk-37G5HJ2X.js → chunk-6JUU7J2B.js} +4 -4
  28. package/dist/{chunk-KBT2I5ER.js → chunk-7RAETIYO.js} +6 -6
  29. package/dist/{chunk-NWSKFYOH.js → chunk-A6WPDFHQ.js} +1 -1
  30. package/dist/{chunk-773XC7P4.js → chunk-AIJRG227.js} +159 -128
  31. package/dist/{chunk-APHDJYN7.js → chunk-CK2H7CFO.js} +1 -1
  32. package/dist/{chunk-Y7ZUBP2K.js → chunk-CN2XSVKF.js} +6 -6
  33. package/dist/{chunk-TVXAN43I.js → chunk-EDJ64P2P.js} +1 -1
  34. package/dist/{chunk-XFZLQANQ.js → chunk-GKC43TLS.js} +2 -2
  35. package/dist/{chunk-UWTXAYBP.js → chunk-GSBPZHLQ.js} +9 -9
  36. package/dist/{chunk-JJX77MB7.js → chunk-IIO5PFZX.js} +3 -3
  37. package/dist/{chunk-RQ62VKM7.js → chunk-IZEBHYI4.js} +1 -1
  38. package/dist/{chunk-J7MWZFFP.js → chunk-JUJR6WTL.js} +4 -4
  39. package/dist/{chunk-JFZBGFNX.js → chunk-KBGMYLSV.js} +2 -1
  40. package/dist/{chunk-LQT3SWFA.js → chunk-KCA5MKHU.js} +5 -5
  41. package/dist/{chunk-SDRJ2LE3.js → chunk-MC57E5U5.js} +1 -1
  42. package/dist/{chunk-2WLJDM23.js → chunk-MJE7XKWP.js} +1 -1
  43. package/dist/{chunk-TKJ7277U.js → chunk-NTNU6T2D.js} +2 -2
  44. package/dist/{chunk-EORR34UB.js → chunk-OGZPRMZA.js} +1 -1
  45. package/dist/{chunk-NKFRRZIT.js → chunk-OMQJB7YN.js} +19 -18
  46. package/dist/{chunk-Y6MVGU7L.js → chunk-PMFGVLDU.js} +10 -10
  47. package/dist/{chunk-KTVHAHUV.js → chunk-SE3D225X.js} +1 -1
  48. package/dist/{chunk-JIC33O5L.js → chunk-SRJA6QLM.js} +2 -2
  49. package/dist/{chunk-4K5N6HTX.js → chunk-TN4LVILT.js} +5 -5
  50. package/dist/{chunk-MLBH7J7J.js → chunk-TNXGMFWV.js} +1 -1
  51. package/dist/{chunk-RN3AWYEP.js → chunk-WD7SEUZO.js} +1 -1
  52. package/dist/{chunk-ZLSFOSDK.js → chunk-X5NZQH5U.js} +2 -1
  53. package/dist/{chunk-7NYEB2TM.js → chunk-X7W45B5G.js} +1 -1
  54. package/dist/{chunk-CPQBTTI6.js → chunk-ZNWRYNCA.js} +5 -5
  55. package/dist/cli/chat.js +30 -30
  56. package/dist/cli/check.js +6 -6
  57. package/dist/cli/plugins.js +13 -13
  58. package/dist/cli/snapshot-create.js +9 -9
  59. package/dist/cli/upgrade.js +7 -7
  60. package/dist/db/schema/attachments.d.ts +178 -0
  61. package/dist/db/schema.d.ts +179 -1
  62. package/dist/{db-WT7P56AH.js → db-TYUUKGJX.js} +7 -7
  63. package/dist/handlers/retention.d.ts +4 -1
  64. package/dist/instrumentation.js +4 -4
  65. package/dist/nitro.js +2 -2
  66. package/dist/{oauth-callback-server-R2PK2MCA.js → oauth-callback-server-AWVDKPR5.js} +23 -23
  67. package/dist/{runner-O7YYUIHT.js → runner-JUQXMACC.js} +13 -13
  68. package/dist/{skills-S6HLQRH7.js → skills-4GZTZX4V.js} +6 -6
  69. package/dist/spawn-32SSRWU4.js +37 -0
  70. package/dist/{validation-46WD2OAR.js → validation-DRLNJRND.js} +6 -6
  71. package/dist/version.js +1 -1
  72. package/dist/{work-YT5QUBS3.js → work-TGIXRRJY.js} +17 -17
  73. package/dist/worker-IFXZOYED.js +24 -0
  74. package/migrations/0027_attachment_storage.sql +16 -0
  75. package/migrations/meta/0027_snapshot.json +2554 -0
  76. package/migrations/meta/_journal.json +8 -1
  77. package/package.json +5 -4
  78. package/dist/spawn-B4SBFFA2.js +0 -37
  79. package/dist/worker-4C5BEDWN.js +0 -24
package/dist/app.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  processConversationWork
3
- } from "./chunk-J7MWZFFP.js";
3
+ } from "./chunk-JUJR6WTL.js";
4
4
  import {
5
5
  bindSpawnAgent
6
- } from "./chunk-RQ62VKM7.js";
6
+ } from "./chunk-IZEBHYI4.js";
7
7
  import {
8
8
  createAgentInvocationWorker,
9
9
  enqueueAgentInvocation,
10
10
  listPendingAgentInvocationMailboxAppends,
11
11
  routeAgentInvocationWork
12
- } from "./chunk-Y7ZUBP2K.js";
12
+ } from "./chunk-CN2XSVKF.js";
13
13
  import {
14
14
  GET as GET2,
15
15
  GET2 as GET3,
@@ -36,12 +36,12 @@ import {
36
36
  startSlackProcessingReaction,
37
37
  stripLeadingBotMention,
38
38
  wakePausedTurn
39
- } from "./chunk-NKFRRZIT.js";
39
+ } from "./chunk-OMQJB7YN.js";
40
40
  import "./chunk-FA6POGLH.js";
41
41
  import {
42
42
  getTurnRequestDeadline,
43
43
  runWithTurnRequestDeadline
44
- } from "./chunk-NWSKFYOH.js";
44
+ } from "./chunk-A6WPDFHQ.js";
45
45
  import {
46
46
  GET,
47
47
  conversationVisibilityFromSlackChannelType,
@@ -50,8 +50,8 @@ import {
50
50
  resolveSlackChannelTypeFromMessage,
51
51
  resolveSlackConversationContext,
52
52
  routeApiTurnWork
53
- } from "./chunk-Y6MVGU7L.js";
54
- import "./chunk-KTVHAHUV.js";
53
+ } from "./chunk-PMFGVLDU.js";
54
+ import "./chunk-SE3D225X.js";
55
55
  import {
56
56
  CONVERSATION_WORK_STALE_ENQUEUE_MS,
57
57
  appendAndEnqueueInboundMessage,
@@ -62,7 +62,7 @@ import {
62
62
  isInvalidConversationRecordError,
63
63
  listActiveConversationIds,
64
64
  removeActiveConversation
65
- } from "./chunk-ELOTIL5F.js";
65
+ } from "./chunk-6CINHXIL.js";
66
66
  import {
67
67
  buildDeliveredTurnStatePatch,
68
68
  claimDispatchMailboxAppend,
@@ -93,7 +93,7 @@ import {
93
93
  requireTurnFailureEventId,
94
94
  resolveTurnSessionRouting,
95
95
  scheduleSessionCompletedPluginTasks
96
- } from "./chunk-UWTXAYBP.js";
96
+ } from "./chunk-GSBPZHLQ.js";
97
97
  import {
98
98
  ConversationTurnLifecycleService,
99
99
  coerceThreadConversationState,
@@ -103,7 +103,7 @@ import {
103
103
  persistThreadRuntimeState,
104
104
  persistThreadState,
105
105
  persistThreadStateById
106
- } from "./chunk-4K5N6HTX.js";
106
+ } from "./chunk-TN4LVILT.js";
107
107
  import "./chunk-UTL3MHPC.js";
108
108
  import {
109
109
  getVercelConversationWorkQueue,
@@ -122,7 +122,7 @@ import {
122
122
  import {
123
123
  validatePluginEgressCredentialHooks,
124
124
  validatePluginRegistrations
125
- } from "./chunk-MLBH7J7J.js";
125
+ } from "./chunk-TNXGMFWV.js";
126
126
  import {
127
127
  defineJuniorPlugins,
128
128
  pluginCatalogConfigFromEnv,
@@ -134,6 +134,7 @@ import {
134
134
  buildSteeringPiMessage,
135
135
  cancelSubscriptions,
136
136
  clearSandboxEgressSignals,
137
+ collectAttachmentGarbage,
137
138
  consumeSandboxEgressAuthRequiredSignal,
138
139
  consumeSandboxEgressPermissionDeniedSignal,
139
140
  createContextCompactor,
@@ -148,17 +149,18 @@ import {
148
149
  parseSandboxEgressCredentialToken,
149
150
  renderAttachmentText,
150
151
  renderBlockText,
152
+ requestAttachmentDeletion,
151
153
  resolveDestinationVisibility,
152
154
  resolveSandboxEgressProviderForHost,
153
155
  sanitizeScheduledTaskPrincipal,
154
156
  setConfigDefaults,
155
157
  shouldEmitDevAgentTrace,
156
158
  shouldPropagateSandboxEgressTrace
157
- } from "./chunk-AENPRXCG.js";
159
+ } from "./chunk-53W3LZEW.js";
158
160
  import {
159
161
  AuthorizationFlowDisabledError,
160
162
  PluginCredentialFailureError
161
- } from "./chunk-CPQBTTI6.js";
163
+ } from "./chunk-ZNWRYNCA.js";
162
164
  import "./chunk-DIB4GX3G.js";
163
165
  import {
164
166
  createAgentRunner,
@@ -166,7 +168,7 @@ import {
166
168
  deleteMcpAuthSessionsForUserProvider,
167
169
  deleteMcpServerSessionId,
168
170
  deleteMcpStoredOAuthCredentials
169
- } from "./chunk-2AHVM3HK.js";
171
+ } from "./chunk-4ZZDTHFC.js";
170
172
  import {
171
173
  RetryableDeliveryError
172
174
  } from "./chunk-RF6J3DIO.js";
@@ -174,7 +176,7 @@ import {
174
176
  formatProviderLabel,
175
177
  postSlackMessage,
176
178
  startOAuthFlow
177
- } from "./chunk-KBT2I5ER.js";
179
+ } from "./chunk-7RAETIYO.js";
178
180
  import "./chunk-7MA4HV4W.js";
179
181
  import {
180
182
  getExperimentalFeatures,
@@ -183,16 +185,16 @@ import {
183
185
  import {
184
186
  getSandboxResourceConfig,
185
187
  setSandboxResourceConfig
186
- } from "./chunk-37G5HJ2X.js";
188
+ } from "./chunk-6JUU7J2B.js";
187
189
  import {
188
190
  createSchedulerSqlStore,
189
191
  findMatchingEventTasks,
190
192
  logScheduledTaskRunSkipped,
191
193
  scheduledTaskRunAttributes
192
- } from "./chunk-LQT3SWFA.js";
194
+ } from "./chunk-KCA5MKHU.js";
193
195
  import {
194
196
  parseSlackThreadId
195
- } from "./chunk-APHDJYN7.js";
197
+ } from "./chunk-CK2H7CFO.js";
196
198
  import {
197
199
  ConversationTurnBoundaryError,
198
200
  CooperativeTurnYieldError,
@@ -242,7 +244,7 @@ import {
242
244
  trimTrailingAssistantMessages,
243
245
  turnHasReply,
244
246
  upsertConversationMessage
245
- } from "./chunk-J2SYI36O.js";
247
+ } from "./chunk-3L2PMOSR.js";
246
248
  import "./chunk-3Y47VMHV.js";
247
249
  import "./chunk-PDO5BLNM.js";
248
250
  import "./chunk-UIE3R5XU.js";
@@ -262,7 +264,7 @@ import {
262
264
  verifyEventTaskCredentialSubject,
263
265
  verifyScheduledTaskCredentialSubject,
264
266
  verifySlackDirectCredentialSubject
265
- } from "./chunk-V57LZDHN.js";
267
+ } from "./chunk-3FFUC32L.js";
266
268
  import {
267
269
  SlackActionError,
268
270
  downloadPrivateSlackFile,
@@ -272,7 +274,7 @@ import {
272
274
  normalizeSlackConversationId,
273
275
  runWithSlackInstallationToken,
274
276
  runWithWorkspaceTeamId
275
- } from "./chunk-TKJ7277U.js";
277
+ } from "./chunk-NTNU6T2D.js";
276
278
  import {
277
279
  contextProvenance,
278
280
  createSlackDestination,
@@ -285,19 +287,19 @@ import {
285
287
  requireSlackDestination,
286
288
  withConversationEventLock,
287
289
  withConversationMutationLock
288
- } from "./chunk-JJX77MB7.js";
290
+ } from "./chunk-IIO5PFZX.js";
289
291
  import {
290
292
  juniorAgentBindings,
291
293
  juniorAgentInvocations,
292
294
  juniorConversationEvents,
293
295
  juniorConversations
294
- } from "./chunk-773XC7P4.js";
296
+ } from "./chunk-AIJRG227.js";
295
297
  import "./chunk-EM225ITJ.js";
296
298
  import {
297
299
  acquireActiveLock,
298
300
  getStateAdapter,
299
301
  withActiveLock
300
- } from "./chunk-SDRJ2LE3.js";
302
+ } from "./chunk-MC57E5U5.js";
301
303
  import {
302
304
  STANDARD_MODEL_PROFILE,
303
305
  botConfig,
@@ -315,16 +317,16 @@ import {
315
317
  modelIdForProfile,
316
318
  setSlackReactionConfig,
317
319
  standardModelId
318
- } from "./chunk-XFZLQANQ.js";
320
+ } from "./chunk-GKC43TLS.js";
319
321
  import {
320
322
  juniorDestinations
321
323
  } from "./chunk-VFUK3X5B.js";
322
- import "./chunk-2WLJDM23.js";
323
- import "./chunk-JIC33O5L.js";
324
+ import "./chunk-MJE7XKWP.js";
325
+ import "./chunk-SRJA6QLM.js";
324
326
  import {
325
327
  pluginCatalogRuntime
326
- } from "./chunk-TVXAN43I.js";
327
- import "./chunk-RN3AWYEP.js";
328
+ } from "./chunk-EDJ64P2P.js";
329
+ import "./chunk-WD7SEUZO.js";
328
330
  import {
329
331
  credentialContextForActor
330
332
  } from "./chunk-BDUENQD3.js";
@@ -356,7 +358,7 @@ import {
356
358
  withContext,
357
359
  withLogContext,
358
360
  withSpan
359
- } from "./chunk-7NYEB2TM.js";
361
+ } from "./chunk-X7W45B5G.js";
360
362
  import {
361
363
  continueTrace
362
364
  } from "./chunk-6GWA276C.js";
@@ -364,10 +366,10 @@ import "./chunk-OOUNJNMR.js";
364
366
  import "./chunk-H4HBKISO.js";
365
367
  import {
366
368
  JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
367
- } from "./chunk-EORR34UB.js";
369
+ } from "./chunk-OGZPRMZA.js";
368
370
  import {
369
371
  JUNIOR_VERSION
370
- } from "./chunk-JFZBGFNX.js";
372
+ } from "./chunk-KBGMYLSV.js";
371
373
  import "./chunk-MLKGABMK.js";
372
374
 
373
375
  // src/app.ts
@@ -1938,6 +1940,7 @@ async function purgeConversationTree(executor, args) {
1938
1940
  inArray(juniorAgentBindings.childConversationId, ids)
1939
1941
  )
1940
1942
  );
1943
+ await requestAttachmentDeletion(executor, ids, args.nowMs);
1941
1944
  await executor.db().update(juniorConversations).set({
1942
1945
  transcriptPurgedAt: new Date(args.nowMs),
1943
1946
  ...(args.retention ? !isPublic : resolvedScrubMetadata) ? { title: null, channelName: null, actor: null } : {}
@@ -1989,14 +1992,46 @@ async function runRetentionPurge(executor, args) {
1989
1992
  }
1990
1993
  });
1991
1994
  }
1995
+ const attachmentResult = args.attachmentStorage ? await collectAttachmentGarbage({
1996
+ db: executor,
1997
+ nowMs: args.nowMs,
1998
+ storage: args.attachmentStorage
1999
+ }) : { deleted: 0 };
1992
2000
  logInfo("retention.purge.completed", {
2001
+ "app.retention.attachments": attachmentResult.deleted,
1993
2002
  "app.retention.scanned": roots.length,
1994
2003
  "app.retention.purged": purged,
1995
2004
  "app.retention.failed": failed,
1996
2005
  "app.retention.conversations": conversations,
1997
2006
  "app.retention.duration_ms": Date.now() - startedAtMs
1998
2007
  });
1999
- return { scanned: roots.length, purged, failed, conversations };
2008
+ return {
2009
+ scanned: roots.length,
2010
+ purged,
2011
+ failed,
2012
+ conversations,
2013
+ attachments: attachmentResult.deleted
2014
+ };
2015
+ }
2016
+
2017
+ // src/chat/attachments/vercel.ts
2018
+ import { del, put } from "@vercel/blob";
2019
+ function createVercelAttachmentStorage() {
2020
+ return {
2021
+ provider: "vercel-blob",
2022
+ async put(input) {
2023
+ await put(input.key, input.body, {
2024
+ access: "private",
2025
+ addRandomSuffix: false,
2026
+ allowOverwrite: true,
2027
+ contentType: input.contentType
2028
+ });
2029
+ },
2030
+ async delete(keys) {
2031
+ if (keys.length === 0) return;
2032
+ await del(keys);
2033
+ }
2034
+ };
2000
2035
  }
2001
2036
 
2002
2037
  // src/handlers/retention.ts
@@ -2016,12 +2051,13 @@ function verifyRetentionRequest(request) {
2016
2051
  const expected = Buffer.from(secret);
2017
2052
  return actual.length === expected.length && timingSafeEqual3(actual, expected);
2018
2053
  }
2019
- async function GET5(request) {
2054
+ async function GET5(request, options = {}) {
2020
2055
  if (!verifyRetentionRequest(request)) {
2021
2056
  return new Response("Unauthorized", { status: 401 });
2022
2057
  }
2023
2058
  try {
2024
2059
  const result = await runRetentionPurge(getSqlExecutor(), {
2060
+ attachmentStorage: options.attachmentStorage ?? createVercelAttachmentStorage(),
2025
2061
  nowMs: Date.now()
2026
2062
  });
2027
2063
  return Response.json(result, { status: 200 });
@@ -3209,6 +3245,71 @@ function buildSlackInboundMessage(args) {
3209
3245
  };
3210
3246
  }
3211
3247
 
3248
+ // src/chat/ingress/bot-mention.ts
3249
+ function escapeRegExp(value) {
3250
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3251
+ }
3252
+ function stripInlineCode(line) {
3253
+ return line.replace(/(`+)(?:(?!\1)[^\n])*\1/g, " ");
3254
+ }
3255
+ function fenceMarkerLength(trimmed) {
3256
+ let n = 0;
3257
+ while (trimmed[n] === "`") {
3258
+ n += 1;
3259
+ }
3260
+ return n;
3261
+ }
3262
+ function singleLineFenceSuffix(trimmed) {
3263
+ const openLen = fenceMarkerLength(trimmed);
3264
+ if (openLen < 3) {
3265
+ return void 0;
3266
+ }
3267
+ const afterOpen = trimmed.slice(openLen);
3268
+ const closeRel = afterOpen.indexOf("`".repeat(openLen));
3269
+ if (closeRel === -1) {
3270
+ return void 0;
3271
+ }
3272
+ return afterOpen.slice(closeRel + openLen);
3273
+ }
3274
+ function textOutsideCode(text) {
3275
+ const lines = text.split("\n");
3276
+ const out = [];
3277
+ let inFence = false;
3278
+ for (const line of lines) {
3279
+ const trimmed = line.trimStart();
3280
+ if (trimmed.startsWith("```")) {
3281
+ if (inFence) {
3282
+ inFence = false;
3283
+ const suffix2 = trimmed.slice(fenceMarkerLength(trimmed));
3284
+ if (suffix2.length > 0) {
3285
+ out.push(stripInlineCode(suffix2));
3286
+ }
3287
+ continue;
3288
+ }
3289
+ const suffix = singleLineFenceSuffix(trimmed);
3290
+ if (suffix !== void 0) {
3291
+ out.push(stripInlineCode(suffix));
3292
+ continue;
3293
+ }
3294
+ inFence = true;
3295
+ continue;
3296
+ }
3297
+ if (inFence) {
3298
+ continue;
3299
+ }
3300
+ out.push(stripInlineCode(line));
3301
+ }
3302
+ return out.join("\n");
3303
+ }
3304
+ function textMentionsBot(text, botUserId) {
3305
+ if (!botUserId || !text) {
3306
+ return false;
3307
+ }
3308
+ const outside = textOutsideCode(text);
3309
+ const id = escapeRegExp(botUserId);
3310
+ return new RegExp(`<@${id}(?:\\|[^>]+)?>`).test(outside);
3311
+ }
3312
+
3212
3313
  // src/chat/ingress/message-changed.ts
3213
3314
  import { Message as Message2 } from "chat";
3214
3315
  function getEditedMentionMessageId(messageTs) {
@@ -3222,9 +3323,6 @@ function isMessageChangedEnvelope(value) {
3222
3323
  if (!event || typeof event !== "object") return false;
3223
3324
  return event.type === "message" && event.subtype === "message_changed" && typeof event.channel === "string" && typeof event.message === "object" && event.message !== null && typeof event.previous_message === "object" && event.previous_message !== null;
3224
3325
  }
3225
- function textMentionsBot(text, botUserId) {
3226
- return text.includes(`<@${botUserId}>`);
3227
- }
3228
3326
  function getAttachmentType(mimeType) {
3229
3327
  if (mimeType?.startsWith("image/")) {
3230
3328
  return "image";
@@ -3507,9 +3605,6 @@ function installationFromEnvelope(body) {
3507
3605
  function isDmEvent(event) {
3508
3606
  return event.channel_type === "im" || event.channel?.startsWith("D") === true;
3509
3607
  }
3510
- function textMentionsBot2(event, botUserId) {
3511
- return Boolean(botUserId && event.text?.includes(`<@${botUserId}>`));
3512
- }
3513
3608
  function shouldIgnoreMessageSubtype(event) {
3514
3609
  return Boolean(event.subtype && IGNORED_MESSAGE_SUBTYPES.has(event.subtype));
3515
3610
  }
@@ -3591,7 +3686,10 @@ async function routeParsedMessage(args) {
3591
3686
  conversationStore: args.conversationStore,
3592
3687
  installation: args.installation
3593
3688
  });
3594
- const isMention = args.event.type === "app_mention" || textMentionsBot2(args.event, args.adapter.botUserId);
3689
+ const botUserId = args.adapter.botUserId;
3690
+ const isMention = Boolean(
3691
+ botUserId && textMentionsBot(args.event.text ?? "", botUserId)
3692
+ );
3595
3693
  if (isMention) {
3596
3694
  args.message.isMention = true;
3597
3695
  }
@@ -4281,11 +4379,11 @@ var THREAD_OPTOUT_PATTERNS = [
4281
4379
  var ACKNOWLEDGMENT_ONLY_RE = /^(?:thanks(?: you)?|thank you|thx|ty|got it|sounds good|sgtm|lgtm|ok(?:ay)?|cool|nice|perfect|awesome|great|makes sense|understood|roger|yep|yup|kk|on it|will do)(?:[.!]+)?$/i;
4282
4380
  var DIRECTED_FOLLOW_UP_CUE_RE = /\b(?:you said|you just said|your last response|your last answer|what did you just say|what do you mean|what did you mean|explain(?: that| this| it| more)?|clarify(?: that| this| it)?|expand(?: on)?(?: that| this| it)?|elaborate(?: on)?(?: that| this| it)?|say more)\b/i;
4283
4381
  var TERSE_CLARIFICATION_RE = /^(?:which one|which ones|why|how so|what do you mean|what did you mean|say more|explain that|clarify that|expand on that|elaborate on that)\??$/i;
4284
- function escapeRegExp(value) {
4382
+ function escapeRegExp2(value) {
4285
4383
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4286
4384
  }
4287
4385
  function containsAssistantInvocation(text, botUserName) {
4288
- const escapedUserName = escapeRegExp(botUserName);
4386
+ const escapedUserName = escapeRegExp2(botUserName);
4289
4387
  const plainNameMentionRe = new RegExp(`(^|\\s)@${escapedUserName}\\b`, "i");
4290
4388
  const labeledEntityMentionRe = new RegExp(
4291
4389
  `<@[^>|]+\\|${escapedUserName}>`,
@@ -6529,7 +6627,8 @@ function createReplyToThread(deps) {
6529
6627
  isBot: true
6530
6628
  },
6531
6629
  meta: {
6532
- replied: true
6630
+ replied: true,
6631
+ source: "slack"
6533
6632
  }
6534
6633
  });
6535
6634
  await persistThreadState(thread, {
@@ -6717,6 +6816,7 @@ function createReplyToThread(deps) {
6717
6816
  const recordedMessageId = recordDeliveredAssistantMessage({
6718
6817
  conversation: preparedState.conversation,
6719
6818
  sessionId: turnId,
6819
+ source: "slack",
6720
6820
  text,
6721
6821
  userMessageId: preparedState.userMessageId
6722
6822
  });
@@ -7372,6 +7472,7 @@ function toConversationMessage(args) {
7372
7472
  explicitMention: args.explicitMention,
7373
7473
  imageAttachmentCount: imageAttachmentCount > 0 ? imageAttachmentCount : void 0,
7374
7474
  imagesHydrated: !messageHasPotentialImageAttachment,
7475
+ source: "slack",
7375
7476
  ...slackTs ? { slackTs } : {}
7376
7477
  }
7377
7478
  };
@@ -9060,7 +9161,9 @@ async function createApp(options) {
9060
9161
  const waitUntil = options?.waitUntil ?? await defaultWaitUntil();
9061
9162
  const tracePropagation = { domains: sandboxEgressTracePropagationDomains };
9062
9163
  const conversationWorkQueue = getVercelConversationWorkQueue();
9164
+ const attachmentStorage = createVercelAttachmentStorage();
9063
9165
  const agentRunner = createAgentRunner(executeAgentRun, {
9166
+ attachmentStorage,
9064
9167
  bindSpawnAgent: (request) => bindSpawnAgent(request, { queue: conversationWorkQueue }),
9065
9168
  tracePropagation
9066
9169
  });
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-TVXAN43I.js";
4
- import "./chunk-RN3AWYEP.js";
3
+ } from "./chunk-EDJ64P2P.js";
4
+ import "./chunk-WD7SEUZO.js";
5
5
  import "./chunk-BDUENQD3.js";
6
6
  import "./chunk-V7YE4WCP.js";
7
- import "./chunk-7NYEB2TM.js";
7
+ import "./chunk-X7W45B5G.js";
8
8
  import "./chunk-6GWA276C.js";
9
9
  import "./chunk-OOUNJNMR.js";
10
10
  import "./chunk-H4HBKISO.js";
11
- import "./chunk-EORR34UB.js";
12
- import "./chunk-JFZBGFNX.js";
11
+ import "./chunk-OGZPRMZA.js";
12
+ import "./chunk-KBGMYLSV.js";
13
13
  import "./chunk-MLKGABMK.js";
14
14
  export {
15
15
  pluginCatalogRuntime
@@ -24,6 +24,7 @@ import type { SlackActionToken } from "@/chat/slack/action-token";
24
24
  import type { TurnReasoningLevel } from "@/chat/reasoning-level";
25
25
  import type { ImageGenerateToolDeps, ViewImageToolDeps, WebFetchToolDeps, WebSearchToolDeps } from "@/chat/tools/types";
26
26
  import type { AssistantMessage } from "@earendil-works/pi-ai";
27
+ import type { AttachmentStorage } from "@/chat/attachments/storage";
27
28
  /** One attachment the model may see for the current instruction. */
28
29
  export type AgentAttachment = {
29
30
  data?: Buffer;
@@ -136,6 +137,7 @@ export type AgentEvent = {
136
137
  };
137
138
  /** Resolved environment and optional per-run tool test overrides. */
138
139
  export type AgentEnvironment = {
140
+ attachmentStorage?: AttachmentStorage;
139
141
  configuration?: Record<string, unknown>;
140
142
  locationConfiguration?: LocationConfigurationService;
141
143
  skillDirs?: string[];
@@ -0,0 +1,12 @@
1
+ /** Bytes and metadata written to attachment object storage. */
2
+ export interface AttachmentWrite {
3
+ body: Buffer;
4
+ contentType: string;
5
+ key: string;
6
+ }
7
+ /** Small object-storage capability used by conversation attachments. */
8
+ export interface AttachmentStorage {
9
+ readonly provider: string;
10
+ put(input: AttachmentWrite): Promise<void>;
11
+ delete(keys: string[]): Promise<void>;
12
+ }
@@ -0,0 +1,52 @@
1
+ import type { JuniorSqlDatabase } from "@/db/db";
2
+ import type { SandboxFileUpload } from "@/chat/tools/sandbox/file-uploads";
3
+ import type { AttachmentStorage } from "./storage";
4
+ export interface StoredAttachment {
5
+ id: string;
6
+ }
7
+ export interface AttachmentGarbageCollectionResult {
8
+ deleted: number;
9
+ }
10
+ /**
11
+ * Persist one conversation-owned file.
12
+ *
13
+ * Identity is content-stable under the conversation. Object storage is written
14
+ * first under a unique key; the SQL row is created only after that write
15
+ * succeeds. A row means the attachment is durable. Retries reuse an existing
16
+ * live row. A purge-marked row is revived by writing a new object and pointing
17
+ * the row at it, unless the conversation is still purged. If the SQL write
18
+ * fails after object storage accepts the bytes, this path deletes that unique
19
+ * object. A process crash between those steps can leave an unreferenced unique
20
+ * object with no SQL row.
21
+ */
22
+ export declare function storeAttachment(args: {
23
+ conversationId: string;
24
+ db: JuniorSqlDatabase;
25
+ file: SandboxFileUpload;
26
+ nowMs?: number;
27
+ storage: AttachmentStorage;
28
+ }): Promise<StoredAttachment>;
29
+ /** Persist many conversation-owned files. */
30
+ export declare function storeAttachments(args: {
31
+ conversationId: string;
32
+ db: JuniorSqlDatabase;
33
+ files: SandboxFileUpload[];
34
+ nowMs?: number;
35
+ storage: AttachmentStorage;
36
+ }): Promise<StoredAttachment[]>;
37
+ /** Mark attachments unavailable when their conversation content is purged. */
38
+ export declare function requestAttachmentDeletion(db: JuniorSqlDatabase, conversationIds: string[], nowMs: number): Promise<void>;
39
+ /**
40
+ * Delete purged attachments in one bounded batch.
41
+ *
42
+ * Eligible rows are explicitly purge-marked, or owned by a conversation whose
43
+ * transcript is already purged. That second path covers a concurrent store that
44
+ * inserted after purge marked existing rows. Delete object keys first, then
45
+ * remove rows that are still eligible so a failed blob delete remains retryable.
46
+ */
47
+ export declare function collectAttachmentGarbage(args: {
48
+ db: JuniorSqlDatabase;
49
+ nowMs: number;
50
+ storage: AttachmentStorage;
51
+ limit?: number;
52
+ }): Promise<AttachmentGarbageCollectionResult>;
@@ -0,0 +1,3 @@
1
+ import type { AttachmentStorage } from "./storage";
2
+ /** Store private conversation attachments in Vercel Blob. */
3
+ export declare function createVercelAttachmentStorage(): AttachmentStorage;
@@ -1,3 +1,4 @@
1
+ import type { AttachmentStorage } from "@/chat/attachments/storage";
1
2
  import type { JuniorSqlDatabase } from "@/db/db";
2
3
  /** Content retention windows keyed by resolved conversation visibility. */
3
4
  export declare const CONTENT_RETENTION_MS: {
@@ -6,6 +7,8 @@ export declare const CONTENT_RETENTION_MS: {
6
7
  };
7
8
  /** Aggregate outcome of one bounded retention purge batch. */
8
9
  export interface RetentionPurgeResult {
10
+ /** Attachment blobs removed after conversation content was purged. */
11
+ attachments: number;
9
12
  /** Root conversations examined and attempted this run. */
10
13
  scanned: number;
11
14
  /** Root trees successfully purged. */
@@ -22,6 +25,7 @@ export interface RetentionPurgeResult {
22
25
  * remainder of an over-limit backlog is left for the next run.
23
26
  */
24
27
  export declare function runRetentionPurge(executor: JuniorSqlDatabase, args: {
28
+ attachmentStorage?: AttachmentStorage;
25
29
  nowMs: number;
26
30
  limit?: number;
27
31
  }): Promise<RetentionPurgeResult>;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Detect Slack bot @mentions that should activate Junior.
3
+ *
4
+ * Mentions inside inline code or fenced code blocks are display-only
5
+ * references. Slack can still deliver `app_mention` for those tokens, so
6
+ * both `message` and `app_mention` paths must use this check.
7
+ */
8
+ /**
9
+ * Return true when `text` contains a Slack bot mention token outside code.
10
+ *
11
+ * Slack encodes user mentions as `<@UXXXXXXXX>` or `<@UXXXXXXXX|label>`.
12
+ */
13
+ export declare function textMentionsBot(text: string, botUserId: string): boolean;
@@ -1,2 +1,8 @@
1
+ export type ConversationWork = {
2
+ assignedIds: string[];
3
+ unfinishedIds: string[];
4
+ };
5
+ /** Return assigned and unfinished plugin work for the candidate conversations. */
6
+ export declare function listConversationWork(conversationIds: string[]): Promise<ConversationWork>;
1
7
  /** Return candidate conversations that have unfinished plugin work. */
2
8
  export declare function listUnfinishedWork(conversationIds: string[]): Promise<string[]>;
@@ -2,12 +2,14 @@ import type { StreamFn } from "@earendil-works/pi-agent-core";
2
2
  import { type AgentRun, type SpawnAgent } from "@/chat/agent/types";
3
3
  import type { AgentRunOutcome } from "@/chat/runtime/agent-run-outcome";
4
4
  import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
5
+ import type { AttachmentStorage } from "@/chat/attachments/storage";
5
6
  /** Run one agent-run slice behind runtime-owned orchestration boundaries. */
6
7
  export interface AgentRunner {
7
8
  run(run: AgentRun): Promise<AgentRunOutcome>;
8
9
  }
9
10
  /** Compose the agent executor with stable host dependencies. */
10
11
  export declare function createAgentRunner(execute: (run: AgentRun, streamFn?: StreamFn) => Promise<AgentRunOutcome>, options?: {
12
+ attachmentStorage?: AttachmentStorage;
11
13
  bindSpawnAgent?: (run: AgentRun) => SpawnAgent | undefined;
12
14
  streamFn?: StreamFn;
13
15
  tracePropagation?: SandboxEgressTracePropagationConfig;
@@ -22,7 +22,7 @@ export declare function upsertConversationMessage(conversation: ThreadConversati
22
22
  export declare function recordDeliveredAssistantMessage(args: {
23
23
  conversation: ThreadConversationState;
24
24
  sessionId: string;
25
- source?: "web";
25
+ source?: "slack" | "web";
26
26
  text: string;
27
27
  userMessageId?: string;
28
28
  }): string;