@sentry/junior 0.138.0 → 0.139.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 (71) hide show
  1. package/dist/{agent-hooks-SCR74Q3E.js → agent-hooks-MJXMD7JP.js} +10 -10
  2. package/dist/api/schema/task.d.ts +100 -1
  3. package/dist/api/schema.d.ts +2 -2
  4. package/dist/api/schema.js +9 -1
  5. package/dist/api.js +198 -54
  6. package/dist/app.js +288 -602
  7. package/dist/{catalog-runtime-IU3QF4GG.js → catalog-runtime-GCCFYPIK.js} +6 -6
  8. package/dist/chat/agent/request.d.ts +12 -2
  9. package/dist/chat/credentials/context.d.ts +14 -0
  10. package/dist/chat/resource-events/actor.d.ts +23 -0
  11. package/dist/chat/state/turn-session.d.ts +1 -3
  12. package/dist/chat/tasks/execution-stats.d.ts +34 -3
  13. package/dist/chat/tasks/read.d.ts +3 -1
  14. package/dist/{chunk-JNNJZURV.js → chunk-2ECYPYKP.js} +1 -1
  15. package/dist/chunk-3T2JAGRH.js +115 -0
  16. package/dist/{chunk-PB3CXNVL.js → chunk-4V4QIYJH.js} +1 -1
  17. package/dist/{chunk-FEUNPTGV.js → chunk-5GSZWRE2.js} +434 -12
  18. package/dist/{chunk-QS527AV5.js → chunk-6OHTDR4F.js} +1 -1
  19. package/dist/{chunk-TCS76X5D.js → chunk-6SU2DT27.js} +2 -2
  20. package/dist/{chunk-BYW4B4PR.js → chunk-75I3UBIL.js} +2 -2
  21. package/dist/{chunk-ZBSMCXKV.js → chunk-AEQISMMU.js} +7 -6
  22. package/dist/{chunk-KDCHVT25.js → chunk-C2N6MNO4.js} +9 -2
  23. package/dist/{chunk-KFRHRSCJ.js → chunk-CXH25EL4.js} +2 -2
  24. package/dist/{chunk-TDJCLNDH.js → chunk-DW4PMHNW.js} +3 -3
  25. package/dist/{chunk-A7WCHXZV.js → chunk-G52UXKGO.js} +4 -4
  26. package/dist/chunk-GI52BW74.js +207 -0
  27. package/dist/{chunk-ZXNTJJIE.js → chunk-GWQSZT4C.js} +2 -2
  28. package/dist/{chunk-EPBBYMNE.js → chunk-HUO3UTAQ.js} +1 -1
  29. package/dist/{chunk-5MXWHTCK.js → chunk-IIESAYDL.js} +6 -6
  30. package/dist/{chunk-YU5QUF67.js → chunk-J3S57AXY.js} +1 -1
  31. package/dist/{chunk-E5UYAIKJ.js → chunk-J6EJQCHY.js} +17 -19
  32. package/dist/{chunk-5LTJ4ITU.js → chunk-MQ5RYATN.js} +4 -4
  33. package/dist/{chunk-BOLJOV5T.js → chunk-MXTVUV3I.js} +1 -1
  34. package/dist/{chunk-FNLBTB4K.js → chunk-MXVD2BDS.js} +1 -1
  35. package/dist/{chunk-TUUDXEXU.js → chunk-PJW6U46K.js} +12 -15
  36. package/dist/{chunk-SIPKWSXK.js → chunk-QTBKPZDA.js} +3 -3
  37. package/dist/{chunk-77VDLF3Z.js → chunk-RUIXF3YQ.js} +10 -0
  38. package/dist/{chunk-SD3OFRWY.js → chunk-U27DSXKB.js} +6 -6
  39. package/dist/{chunk-C7ZVPO4Z.js → chunk-U7CMWQ7Z.js} +1 -1
  40. package/dist/{chunk-DCLLQGS6.js → chunk-UDBUS533.js} +8 -3
  41. package/dist/{chunk-HIWJWWMT.js → chunk-WQRX57EA.js} +3 -3
  42. package/dist/{chunk-LPVUNO2W.js → chunk-WZH4JV7R.js} +7 -7
  43. package/dist/{chunk-HCIVH3JS.js → chunk-YCTDA7BD.js} +28 -0
  44. package/dist/{chunk-VPZFVJND.js → chunk-YGZ2OLXL.js} +1 -1
  45. package/dist/{chunk-N7WARMC6.js → chunk-ZQCGQMF2.js} +7 -7
  46. package/dist/{chunk-RZIBSCYC.js → chunk-ZYQSPQYR.js} +25 -22
  47. package/dist/cli/chat.js +33 -33
  48. package/dist/cli/check.js +7 -7
  49. package/dist/cli/plugins.js +14 -14
  50. package/dist/cli/snapshot-create.js +10 -10
  51. package/dist/cli/upgrade.js +8 -8
  52. package/dist/db/schema/task-executions.d.ts +23 -2
  53. package/dist/db/schema.d.ts +20 -1
  54. package/dist/{db-UO2IWXGA.js → db-UXPPGHDF.js} +7 -7
  55. package/dist/instrumentation.js +4 -4
  56. package/dist/nitro.js +2 -2
  57. package/dist/{oauth-callback-server-MAQI43LX.js → oauth-callback-server-4ZYMD5UA.js} +22 -21
  58. package/dist/{runner-PIUQEXKE.js → runner-MZSEONRZ.js} +18 -16
  59. package/dist/{sandbox-egress-signals-A5HWIQH4.js → sandbox-egress-signals-EKPAVWQL.js} +2 -2
  60. package/dist/{skills-4ARJADHQ.js → skills-IMVPXSQ7.js} +7 -7
  61. package/dist/spawn-S5LSVOCE.js +38 -0
  62. package/dist/{validation-S3EE3HWL.js → validation-ZKCY2BVR.js} +7 -7
  63. package/dist/version.js +1 -1
  64. package/dist/{work-UARRUAW3.js → work-GG3XDYRX.js} +18 -18
  65. package/dist/{worker-DOCIRVD3.js → worker-23AUELCJ.js} +10 -10
  66. package/migrations/0022_task_execution_status.sql +3 -0
  67. package/migrations/meta/0022_snapshot.json +2186 -0
  68. package/migrations/meta/_journal.json +7 -0
  69. package/package.json +5 -5
  70. package/dist/chunk-ELKW5FIB.js +0 -233
  71. package/dist/spawn-G2AWPMCT.js +0 -38
package/dist/app.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  processConversationWork
3
- } from "./chunk-HIWJWWMT.js";
3
+ } from "./chunk-WQRX57EA.js";
4
4
  import {
5
5
  bindSpawnAgent
6
- } from "./chunk-PB3CXNVL.js";
6
+ } from "./chunk-4V4QIYJH.js";
7
7
  import {
8
8
  createAgentInvocationWorker,
9
9
  enqueueAgentInvocation,
10
10
  listPendingAgentInvocationMailboxAppends,
11
11
  routeAgentInvocationWork
12
- } from "./chunk-ZBSMCXKV.js";
12
+ } from "./chunk-AEQISMMU.js";
13
13
  import {
14
14
  GET as GET2,
15
15
  GET2 as GET3,
@@ -39,7 +39,7 @@ import {
39
39
  splitSlackReplyText,
40
40
  startSlackProcessingReaction,
41
41
  stripLeadingBotMention
42
- } from "./chunk-E5UYAIKJ.js";
42
+ } from "./chunk-J6EJQCHY.js";
43
43
  import "./chunk-FA6POGLH.js";
44
44
  import {
45
45
  CONVERSATION_WORK_STALE_ENQUEUE_MS,
@@ -51,32 +51,50 @@ import {
51
51
  isInvalidConversationRecordError,
52
52
  listActiveConversationIds,
53
53
  removeActiveConversation
54
- } from "./chunk-5LTJ4ITU.js";
54
+ } from "./chunk-MQ5RYATN.js";
55
55
  import {
56
56
  buildDeliveredTurnStatePatch,
57
+ claimDispatchMailboxAppend,
57
58
  completeAuthPauseTurn,
59
+ confirmDispatchMailboxAppend,
60
+ createOrGetDispatch,
58
61
  finalizeFailedTurnReplyWithEvent,
59
62
  getAgentTurnDiagnosticsAttributes,
63
+ getDispatchConversationId,
64
+ getDispatchInputMessageId,
65
+ getDispatchInputMessageIds,
66
+ getDispatchRecord,
67
+ getDispatchTurnId,
68
+ getPluginDispatchProjection,
60
69
  getTurnUserMessage,
61
70
  getTurnUserReplyAttachmentContext,
62
71
  getTurnUserSlackMessageTs,
72
+ isTerminalDispatchStatus,
73
+ listPendingDispatchMailboxAppends,
74
+ markDispatchAwaitingResume,
75
+ markDispatchBlocked,
76
+ markDispatchCompleted,
77
+ markDispatchFailed,
78
+ markDispatchRunning,
63
79
  persistAuthPauseTurnState,
64
80
  processPluginTask,
65
81
  requireTurnFailureEventId,
66
82
  resolveTurnSessionRouting,
67
83
  scheduleSessionCompletedPluginTasks
68
- } from "./chunk-FEUNPTGV.js";
84
+ } from "./chunk-5GSZWRE2.js";
69
85
  import {
70
86
  ConversationTurnLifecycleService
71
87
  } from "./chunk-Q6QZTTLS.js";
72
88
  import {
73
89
  GET,
74
90
  conversationVisibilityFromSlackChannelType,
75
- recordTaskExecution,
76
91
  resolveSlackChannelTypeFromMessage,
77
92
  resolveSlackConversationContext
78
- } from "./chunk-ELKW5FIB.js";
93
+ } from "./chunk-3T2JAGRH.js";
79
94
  import "./chunk-4CODA7P5.js";
95
+ import {
96
+ recordTaskExecution
97
+ } from "./chunk-GI52BW74.js";
80
98
  import "./chunk-UTL3MHPC.js";
81
99
  import {
82
100
  getVercelConversationWorkQueue,
@@ -95,7 +113,7 @@ import {
95
113
  import {
96
114
  validatePluginEgressCredentialHooks,
97
115
  validatePluginRegistrations
98
- } from "./chunk-YU5QUF67.js";
116
+ } from "./chunk-J3S57AXY.js";
99
117
  import {
100
118
  defineJuniorPlugins,
101
119
  pluginCatalogConfigFromEnv,
@@ -128,18 +146,18 @@ import {
128
146
  setConfigDefaults,
129
147
  shouldEmitDevAgentTrace,
130
148
  shouldPropagateSandboxEgressTrace
131
- } from "./chunk-RZIBSCYC.js";
149
+ } from "./chunk-ZYQSPQYR.js";
132
150
  import {
133
151
  AuthorizationFlowDisabledError,
134
152
  PluginCredentialFailureError
135
- } from "./chunk-LPVUNO2W.js";
153
+ } from "./chunk-WZH4JV7R.js";
136
154
  import "./chunk-DIB4GX3G.js";
137
155
  import {
138
156
  createUserTokenStore,
139
157
  deleteMcpAuthSessionsForUserProvider,
140
158
  deleteMcpServerSessionId,
141
159
  deleteMcpStoredOAuthCredentials
142
- } from "./chunk-N7WARMC6.js";
160
+ } from "./chunk-ZQCGQMF2.js";
143
161
  import {
144
162
  RetryableDeliveryError
145
163
  } from "./chunk-R776HKPK.js";
@@ -147,7 +165,7 @@ import {
147
165
  formatProviderLabel,
148
166
  postSlackMessage,
149
167
  startOAuthFlow
150
- } from "./chunk-SD3OFRWY.js";
168
+ } from "./chunk-U27DSXKB.js";
151
169
  import {
152
170
  ConversationTurnBoundaryError,
153
171
  CooperativeTurnYieldError,
@@ -203,11 +221,9 @@ import {
203
221
  trimTrailingAssistantMessages,
204
222
  updateConversationStats,
205
223
  upsertConversationMessage
206
- } from "./chunk-TUUDXEXU.js";
207
- import {
208
- JUNIOR_THREAD_STATE_TTL_MS
209
- } from "./chunk-3Y47VMHV.js";
210
- import "./chunk-EPBBYMNE.js";
224
+ } from "./chunk-PJW6U46K.js";
225
+ import "./chunk-3Y47VMHV.js";
226
+ import "./chunk-HUO3UTAQ.js";
211
227
  import {
212
228
  getExperimentalFeatures,
213
229
  setExperimentalFeatures
@@ -215,14 +231,14 @@ import {
215
231
  import {
216
232
  getSandboxResourceConfig,
217
233
  setSandboxResourceConfig
218
- } from "./chunk-A7WCHXZV.js";
234
+ } from "./chunk-G52UXKGO.js";
219
235
  import {
220
236
  createSchedulerSqlStore,
221
237
  findMatchingEventTasks
222
- } from "./chunk-TDJCLNDH.js";
238
+ } from "./chunk-DW4PMHNW.js";
223
239
  import {
224
240
  parseSlackThreadId
225
- } from "./chunk-FNLBTB4K.js";
241
+ } from "./chunk-MXVD2BDS.js";
226
242
  import "./chunk-CDQ4YIZM.js";
227
243
  import "./chunk-PDO5BLNM.js";
228
244
  import "./chunk-UIE3R5XU.js";
@@ -242,7 +258,7 @@ import {
242
258
  verifyEventTaskCredentialSubject,
243
259
  verifyScheduledTaskCredentialSubject,
244
260
  verifySlackDirectCredentialSubject
245
- } from "./chunk-5MXWHTCK.js";
261
+ } from "./chunk-IIESAYDL.js";
246
262
  import {
247
263
  SlackActionError,
248
264
  downloadPrivateSlackFile,
@@ -252,7 +268,7 @@ import {
252
268
  normalizeSlackConversationId,
253
269
  runWithSlackInstallationToken,
254
270
  runWithWorkspaceTeamId
255
- } from "./chunk-TCS76X5D.js";
271
+ } from "./chunk-6SU2DT27.js";
256
272
  import {
257
273
  contextProvenance,
258
274
  createSlackDestination,
@@ -264,20 +280,20 @@ import {
264
280
  requireSlackDestination,
265
281
  withConversationEventLock,
266
282
  withConversationMutationLock
267
- } from "./chunk-SIPKWSXK.js";
283
+ } from "./chunk-QTBKPZDA.js";
268
284
  import {
269
285
  juniorAgentBindings,
270
286
  juniorAgentInvocations,
271
287
  juniorConversationEvents,
272
288
  juniorConversations
273
- } from "./chunk-DCLLQGS6.js";
289
+ } from "./chunk-UDBUS533.js";
274
290
  import {
275
291
  sleep
276
292
  } from "./chunk-EM225ITJ.js";
277
293
  import {
278
294
  acquireActiveLock,
279
295
  getStateAdapter
280
- } from "./chunk-BOLJOV5T.js";
296
+ } from "./chunk-MXTVUV3I.js";
281
297
  import {
282
298
  STANDARD_MODEL_PROFILE,
283
299
  botConfig,
@@ -295,19 +311,19 @@ import {
295
311
  modelIdForProfile,
296
312
  setSlackReactionConfig,
297
313
  standardModelId
298
- } from "./chunk-BYW4B4PR.js";
314
+ } from "./chunk-75I3UBIL.js";
299
315
  import {
300
316
  juniorDestinations
301
317
  } from "./chunk-VFUK3X5B.js";
302
- import "./chunk-VPZFVJND.js";
303
- import "./chunk-ZXNTJJIE.js";
318
+ import "./chunk-YGZ2OLXL.js";
319
+ import "./chunk-GWQSZT4C.js";
304
320
  import {
305
321
  pluginCatalogRuntime
306
- } from "./chunk-QS527AV5.js";
307
- import "./chunk-KFRHRSCJ.js";
322
+ } from "./chunk-6OHTDR4F.js";
323
+ import "./chunk-CXH25EL4.js";
308
324
  import {
309
- credentialSubjectSchema
310
- } from "./chunk-77VDLF3Z.js";
325
+ credentialContextForActor
326
+ } from "./chunk-RUIXF3YQ.js";
311
327
  import {
312
328
  createActor,
313
329
  createSlackActor,
@@ -336,7 +352,7 @@ import {
336
352
  withContext,
337
353
  withLogContext,
338
354
  withSpan
339
- } from "./chunk-JNNJZURV.js";
355
+ } from "./chunk-2ECYPYKP.js";
340
356
  import {
341
357
  continueTrace
342
358
  } from "./chunk-6GWA276C.js";
@@ -344,10 +360,10 @@ import "./chunk-OOUNJNMR.js";
344
360
  import "./chunk-H4HBKISO.js";
345
361
  import {
346
362
  JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
347
- } from "./chunk-KDCHVT25.js";
363
+ } from "./chunk-C2N6MNO4.js";
348
364
  import {
349
365
  JUNIOR_VERSION
350
- } from "./chunk-C7ZVPO4Z.js";
366
+ } from "./chunk-U7CMWQ7Z.js";
351
367
  import "./chunk-MLKGABMK.js";
352
368
 
353
369
  // src/app.ts
@@ -409,400 +425,20 @@ async function verifyDispatchCallbackRequest(request) {
409
425
  }
410
426
  }
411
427
 
412
- // src/chat/agent-dispatch/store.ts
413
- import { createHash } from "crypto";
414
- import {
415
- destinationSchema,
416
- destinationVisibilitySchema,
417
- isSlackDestination,
418
- replyAttributionSchema,
419
- sourceSchema
420
- } from "@sentry/junior-plugin-api";
421
- import { z as z2 } from "zod";
422
- var DISPATCH_PREFIX = "junior:agent_dispatch";
423
- var DISPATCH_LOCK_TTL_MS = 10 * 60 * 1e3;
424
- var DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS = 1e4;
425
- var DISPATCH_MAILBOX_APPEND_INDEX_MAX_LENGTH = 1e4;
426
- var nonEmptyExactStringSchema = z2.string().min(1).refine(
427
- (value) => value === value.trim() && value.toLowerCase() !== "unknown"
428
- );
429
- var pendingDispatchMailboxAppendIndexSchema = z2.array(
430
- nonEmptyExactStringSchema
431
- );
432
- var dispatchStatusSchema = z2.enum([
433
- "pending",
434
- "running",
435
- "awaiting_resume",
436
- "completed",
437
- "failed",
438
- "blocked"
439
- ]);
440
- var dispatchActorSchema = z2.object({
441
- platform: z2.literal("system"),
442
- name: nonEmptyExactStringSchema
443
- }).strict();
444
- var dispatchRecordSchema = z2.object({
445
- actor: dispatchActorSchema,
446
- createdAtMs: z2.number().finite(),
447
- credentialSubject: credentialSubjectSchema.optional(),
448
- destination: destinationSchema,
449
- destinationVisibility: destinationVisibilitySchema,
450
- errorMessage: z2.string().optional(),
451
- id: nonEmptyExactStringSchema,
452
- idempotencyKey: z2.string().min(1),
453
- input: z2.string().min(1),
454
- metadata: z2.record(z2.string(), z2.string()).optional(),
455
- plugin: nonEmptyExactStringSchema,
456
- replyAttribution: replyAttributionSchema.optional(),
457
- resultMessageTs: z2.string().optional(),
458
- source: sourceSchema,
459
- status: dispatchStatusSchema,
460
- updatedAtMs: z2.number().finite()
461
- }).strict().superRefine((record, ctx) => {
462
- if (!isSlackDestination(record.destination)) {
463
- ctx.addIssue({
464
- code: z2.ZodIssueCode.custom,
465
- message: "Dispatch destination platform must be slack",
466
- path: ["destination"]
467
- });
468
- return;
469
- }
470
- const subject = record.credentialSubject;
471
- if (!subject) {
472
- return;
473
- }
474
- if (subject.allowedWhen === "private-direct-conversation") {
475
- if (!record.destination.channelId.startsWith("D")) {
476
- ctx.addIssue({
477
- code: z2.ZodIssueCode.custom,
478
- message: "Dispatch credentialSubject requires a private direct Slack destination",
479
- path: ["credentialSubject"]
480
- });
481
- return;
482
- }
483
- if (subject.binding.type !== "slack-direct-conversation" || subject.binding.teamId !== record.destination.teamId || subject.binding.channelId !== record.destination.channelId) {
484
- ctx.addIssue({
485
- code: z2.ZodIssueCode.custom,
486
- message: "Dispatch credentialSubject binding must match destination",
487
- path: ["credentialSubject", "binding"]
488
- });
489
- }
490
- return;
491
- }
492
- if (subject.binding.type !== subject.allowedWhen || subject.binding.plugin !== record.plugin || subject.binding.taskId !== subject.taskId) {
493
- ctx.addIssue({
494
- code: z2.ZodIssueCode.custom,
495
- message: "Dispatch credentialSubject binding must match task",
496
- path: ["credentialSubject", "binding"]
497
- });
498
- }
499
- });
500
- var storedDispatchRecordSchema = dispatchRecordSchema.extend({
501
- attempt: z2.number().int().nonnegative().optional(),
502
- lastCallbackAtMs: z2.number().finite().optional(),
503
- leaseExpiresAtMs: z2.number().finite().optional(),
504
- maxAttempts: z2.number().int().positive().optional(),
505
- version: z2.number().int().positive().optional()
506
- });
507
- function getDispatchStorageKey(id) {
508
- return `${DISPATCH_PREFIX}:record:${id}`;
509
- }
510
- function dispatchLockKey(id) {
511
- return `${DISPATCH_PREFIX}:lock:${id}`;
512
- }
513
- function pendingDispatchMailboxAppendIndexKey() {
514
- return `${DISPATCH_PREFIX}:incomplete`;
515
- }
516
- function pendingDispatchMailboxAppendIndexLockKey() {
517
- return `${DISPATCH_PREFIX}:incomplete:lock`;
518
- }
519
- function normalizeMetadata(metadata) {
520
- if (!metadata) {
521
- return void 0;
522
- }
523
- const entries = Object.entries(metadata).filter(
524
- (entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
525
- );
526
- return entries.length > 0 ? Object.fromEntries(entries) : void 0;
527
- }
528
- function buildDispatchId(plugin, idempotencyKey) {
529
- const digest = createHash("sha256").update(plugin).update("\0").update(idempotencyKey).digest("hex").slice(0, 32);
530
- return `dispatch_${digest}`;
531
- }
532
- function parseDispatchRecord(value) {
533
- const parsed = parseStoredDispatchRecord(value);
534
- return parsed?.record;
535
- }
536
- function parseStoredDispatchRecord(value) {
537
- const parsed = storedDispatchRecordSchema.safeParse(value);
538
- if (!parsed.success) {
539
- return void 0;
540
- }
541
- const {
542
- attempt: _attempt,
543
- lastCallbackAtMs: _lastCallbackAtMs,
544
- leaseExpiresAtMs: _leaseExpiresAtMs,
545
- maxAttempts: _maxAttempts,
546
- version: _version,
547
- ...record
548
- } = parsed.data;
549
- return {
550
- ...typeof parsed.data.leaseExpiresAtMs === "number" ? { legacyLeaseExpiresAtMs: parsed.data.leaseExpiresAtMs } : {},
551
- record
552
- };
553
- }
554
- function getDispatchConversationId(dispatch2) {
555
- return `agent-dispatch:${dispatch2.id}`;
556
- }
557
- function getDispatchInputMessageId(dispatchId) {
558
- return `agent-dispatch:${dispatchId}`;
559
- }
560
- function getLegacyDispatchInputMessageId(dispatchId) {
561
- return `dispatch:${dispatchId}:user`;
562
- }
563
- function getDispatchInputMessageIds(dispatchId) {
564
- return [
565
- getDispatchInputMessageId(dispatchId),
566
- getLegacyDispatchInputMessageId(dispatchId)
567
- ];
568
- }
569
- function getDispatchTurnId(dispatchId) {
570
- return `dispatch:${dispatchId}`;
571
- }
572
- function toDispatchProjection(record) {
573
- return {
574
- id: record.id,
575
- status: record.status,
576
- ...record.resultMessageTs ? { resultMessageTs: record.resultMessageTs } : {},
577
- ...record.errorMessage ? { errorMessage: record.errorMessage } : {}
578
- };
579
- }
580
- function isTerminalDispatchStatus(status) {
581
- return status === "completed" || status === "failed" || status === "blocked";
582
- }
583
- async function withDispatchLock(dispatchId, task) {
584
- const state = getStateAdapter();
585
- await state.connect();
586
- const lock = await state.acquireLock(
587
- dispatchLockKey(dispatchId),
588
- DISPATCH_LOCK_TTL_MS
589
- );
590
- if (!lock) {
591
- throw new Error(`Could not acquire dispatch lock for ${dispatchId}`);
592
- }
593
- try {
594
- return await task(state);
595
- } finally {
596
- await state.releaseLock(lock);
597
- }
598
- }
599
- async function putRecord(state, record) {
600
- const parsed = dispatchRecordSchema.safeParse(record);
601
- if (!parsed.success) {
602
- throw new Error(
603
- `Dispatch record is invalid: ${parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"} ${issue.message}`).join("; ")}`
604
- );
605
- }
606
- const next = parsed.data;
607
- await state.set(
608
- getDispatchStorageKey(next.id),
609
- next,
610
- JUNIOR_THREAD_STATE_TTL_MS
611
- );
612
- }
613
- async function updatePendingDispatchMailboxAppendIndex(state, update) {
614
- const lock = await state.acquireLock(
615
- pendingDispatchMailboxAppendIndexLockKey(),
616
- DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS
617
- );
618
- if (!lock) {
619
- throw new Error("Could not acquire dispatch mailbox append index lock");
620
- }
621
- try {
622
- const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
623
- const ids = stored === void 0 || stored === null ? [] : pendingDispatchMailboxAppendIndexSchema.parse(stored);
624
- const next = [...new Set(update([...new Set(ids)]))].slice(
625
- -DISPATCH_MAILBOX_APPEND_INDEX_MAX_LENGTH
626
- );
627
- if (next.length === ids.length && next.every((id, index) => id === ids[index])) {
628
- return;
629
- }
630
- await state.set(
631
- pendingDispatchMailboxAppendIndexKey(),
632
- next,
633
- JUNIOR_THREAD_STATE_TTL_MS
634
- );
635
- } finally {
636
- await state.releaseLock(lock);
637
- }
638
- }
639
- async function getDispatchRecord(id) {
640
- const state = getStateAdapter();
641
- await state.connect();
642
- return parseDispatchRecord(await state.get(getDispatchStorageKey(id)));
643
- }
644
- async function createOrGetDispatch(args) {
645
- const id = buildDispatchId(args.plugin, args.options.idempotencyKey);
646
- return await withDispatchLock(id, async (state) => {
647
- const existing = parseDispatchRecord(
648
- await state.get(getDispatchStorageKey(id))
649
- );
650
- if (existing) {
651
- return { record: existing, status: "already_exists" };
652
- }
653
- const metadata = normalizeMetadata(args.options.metadata);
654
- const record = {
655
- actor: { platform: "system", name: args.plugin },
656
- createdAtMs: args.nowMs,
657
- ...args.options.credentialSubject ? { credentialSubject: args.options.credentialSubject } : {},
658
- destination: args.options.destination,
659
- destinationVisibility: args.options.destinationVisibility,
660
- id,
661
- idempotencyKey: args.options.idempotencyKey,
662
- input: args.options.input,
663
- ...metadata ? { metadata } : {},
664
- plugin: args.plugin,
665
- ...args.options.replyAttribution ? { replyAttribution: args.options.replyAttribution } : {},
666
- status: "pending",
667
- source: args.options.source,
668
- updatedAtMs: args.nowMs
669
- };
670
- await updatePendingDispatchMailboxAppendIndex(
671
- state,
672
- (ids) => ids.includes(id) ? ids : [...ids, id]
673
- );
674
- await putRecord(state, record);
675
- return { record, status: "created" };
676
- });
677
- }
678
- async function transitionDispatch(id, transition) {
679
- return await withDispatchLock(id, async (state) => {
680
- const current = parseDispatchRecord(
681
- await state.get(getDispatchStorageKey(id))
682
- );
683
- if (!current) {
684
- return void 0;
685
- }
686
- const transitioned = transition(current);
687
- if (transitioned === current) {
688
- return current;
689
- }
690
- const next = {
691
- ...transitioned,
692
- updatedAtMs: Date.now()
693
- };
694
- await putRecord(state, next);
695
- return next;
696
- });
697
- }
698
- async function markDispatchRunning(id) {
699
- return await transitionDispatch(
700
- id,
701
- (record) => isTerminalDispatchStatus(record.status) ? record : { ...record, status: "running", errorMessage: void 0 }
702
- );
703
- }
704
- async function markDispatchAwaitingResume(id) {
705
- return await transitionDispatch(
706
- id,
707
- (record) => isTerminalDispatchStatus(record.status) ? record : {
708
- ...record,
709
- status: "awaiting_resume"
710
- }
711
- );
712
- }
713
- async function markDispatchBlocked(id, errorMessage, resultMessageTs) {
714
- return await transitionDispatch(
715
- id,
716
- (record) => isTerminalDispatchStatus(record.status) ? record : {
717
- ...record,
718
- errorMessage,
719
- ...resultMessageTs ? { resultMessageTs } : {},
720
- status: "blocked"
721
- }
722
- );
723
- }
724
- async function markDispatchCompleted(id, resultMessageTs) {
725
- const previous = await getDispatchRecord(id);
726
- const next = await transitionDispatch(
727
- id,
728
- (record) => isTerminalDispatchStatus(record.status) ? record : {
729
- ...record,
730
- errorMessage: void 0,
731
- ...resultMessageTs ? { resultMessageTs } : {},
732
- status: "completed"
733
- }
734
- );
735
- if (next?.status === "completed" && previous?.status !== "completed" && next.plugin === "junior") {
736
- const eventTaskId = next.metadata?.eventTaskId;
737
- if (eventTaskId) {
738
- await recordTaskExecution("event", eventTaskId, {
739
- conversationId: getDispatchConversationId(next),
740
- executionId: next.id,
741
- nowMs: next.updatedAtMs
742
- });
743
- }
744
- }
745
- return next;
746
- }
747
- async function markDispatchFailed(id, errorMessage, resultMessageTs) {
748
- return await transitionDispatch(
749
- id,
750
- (record) => isTerminalDispatchStatus(record.status) ? record : {
751
- ...record,
752
- errorMessage,
753
- ...resultMessageTs ? { resultMessageTs } : {},
754
- status: "failed"
755
- }
756
- );
757
- }
758
- async function confirmDispatchMailboxAppend(id) {
759
- const state = getStateAdapter();
760
- await state.connect();
761
- await updatePendingDispatchMailboxAppendIndex(
762
- state,
763
- (ids) => ids.filter((candidate) => candidate !== id)
764
- );
765
- }
766
- async function listPendingDispatchMailboxAppends() {
767
- const state = getStateAdapter();
768
- await state.connect();
769
- const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
770
- return stored === void 0 || stored === null ? [] : [...new Set(pendingDispatchMailboxAppendIndexSchema.parse(stored))];
771
- }
772
- async function claimDispatchMailboxAppend(id, nowMs) {
773
- return await withDispatchLock(id, async (state) => {
774
- const stored = parseStoredDispatchRecord(
775
- await state.get(getDispatchStorageKey(id))
776
- );
777
- if (!stored || stored.legacyLeaseExpiresAtMs && stored.legacyLeaseExpiresAtMs > nowMs) {
778
- return void 0;
779
- }
780
- await putRecord(state, stored.record);
781
- return stored.record;
782
- });
783
- }
784
- async function getPluginDispatchProjection(args) {
785
- const record = await getDispatchRecord(args.id);
786
- if (!record || record.plugin !== args.plugin) {
787
- return void 0;
788
- }
789
- return toDispatchProjection(record);
790
- }
791
-
792
428
  // src/chat/agent-dispatch/work.ts
793
- import { z as z3 } from "zod";
794
- var agentDispatchMailboxMetadataSchema = z3.object({
795
- dispatchId: z3.string().min(1),
796
- kind: z3.literal("agent_dispatch")
429
+ import { z as z2 } from "zod";
430
+ var agentDispatchMailboxMetadataSchema = z2.object({
431
+ dispatchId: z2.string().min(1),
432
+ kind: z2.literal("agent_dispatch")
797
433
  }).strict();
798
434
  var AGENT_DISPATCH_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
799
435
  function buildDispatchRoutingContext(dispatch2) {
800
436
  return {
801
437
  actor: dispatch2.actor,
802
- credentialContext: {
803
- actor: dispatch2.actor,
804
- ...dispatch2.credentialSubject ? { subject: dispatch2.credentialSubject } : {}
805
- },
438
+ credentialContext: credentialContextForActor(
439
+ dispatch2.actor,
440
+ dispatch2.credentialSubject
441
+ ),
806
442
  destinationVisibility: dispatch2.destinationVisibility,
807
443
  dispatch: {
808
444
  actor: dispatch2.actor,
@@ -1301,7 +937,7 @@ import {
1301
937
  // src/chat/agent-dispatch/validation.ts
1302
938
  import {
1303
939
  dispatchOptionsSchema,
1304
- isSlackDestination as isSlackDestination2
940
+ isSlackDestination
1305
941
  } from "@sentry/junior-plugin-api";
1306
942
  function hasIssueAtPath(issues, path) {
1307
943
  return issues.some(
@@ -1398,7 +1034,7 @@ function validateDispatchOptions(options) {
1398
1034
  }
1399
1035
  const candidate = parsed.data;
1400
1036
  const { credentialSubject, destination } = candidate;
1401
- if (!isSlackDestination2(destination)) {
1037
+ if (!isSlackDestination(destination)) {
1402
1038
  throw new Error("Dispatch destination platform must be slack");
1403
1039
  }
1404
1040
  if (credentialSubject !== void 0) {
@@ -1623,6 +1259,15 @@ function shouldSkipRun(task, run) {
1623
1259
  }
1624
1260
  return void 0;
1625
1261
  }
1262
+ async function recordScheduledExecution(args) {
1263
+ const dispatchId = args.run.dispatchId;
1264
+ await recordTaskExecution("scheduled", args.run.taskId, {
1265
+ ...dispatchId ? { conversationId: getDispatchConversationId({ id: dispatchId }) } : {},
1266
+ executionId: args.run.id,
1267
+ nowMs: args.nowMs,
1268
+ status: args.status
1269
+ });
1270
+ }
1626
1271
  async function applyDispatchResult(args) {
1627
1272
  if (args.dispatch.status === "completed") {
1628
1273
  const completed = await args.store.markRunCompleted({
@@ -1637,14 +1282,11 @@ async function applyDispatchResult(args) {
1637
1282
  run: args.run,
1638
1283
  status: "completed"
1639
1284
  });
1640
- const dispatchId = args.run.dispatchId;
1641
- if (dispatchId) {
1642
- await recordTaskExecution("scheduled", args.run.taskId, {
1643
- conversationId: getDispatchConversationId({ id: dispatchId }),
1644
- executionId: args.run.id,
1645
- nowMs: args.nowMs
1646
- });
1647
- }
1285
+ await recordScheduledExecution({
1286
+ nowMs: args.nowMs,
1287
+ run: args.run,
1288
+ status: "completed"
1289
+ });
1648
1290
  return true;
1649
1291
  }
1650
1292
  if (args.dispatch.status === "blocked") {
@@ -1661,6 +1303,11 @@ async function applyDispatchResult(args) {
1661
1303
  run: args.run,
1662
1304
  status: "blocked"
1663
1305
  });
1306
+ await recordScheduledExecution({
1307
+ nowMs: args.nowMs,
1308
+ run: args.run,
1309
+ status: "blocked"
1310
+ });
1664
1311
  return true;
1665
1312
  }
1666
1313
  if (args.dispatch.status === "failed") {
@@ -1677,6 +1324,11 @@ async function applyDispatchResult(args) {
1677
1324
  run: args.run,
1678
1325
  status: "failed"
1679
1326
  });
1327
+ await recordScheduledExecution({
1328
+ nowMs: args.nowMs,
1329
+ run: args.run,
1330
+ status: "failed"
1331
+ });
1680
1332
  return true;
1681
1333
  }
1682
1334
  return false;
@@ -1699,6 +1351,11 @@ async function finishClaimedRun(args) {
1699
1351
  run: args.run,
1700
1352
  status: args.status
1701
1353
  });
1354
+ await recordScheduledExecution({
1355
+ nowMs: args.nowMs,
1356
+ run: args.run,
1357
+ status: args.status
1358
+ });
1702
1359
  }
1703
1360
  async function runScheduledTaskHeartbeat(args) {
1704
1361
  const store = createSchedulerSqlStore(getDb());
@@ -2658,7 +2315,7 @@ import {
2658
2315
  Message,
2659
2316
  ThreadImpl
2660
2317
  } from "chat";
2661
- import { z as z5 } from "zod";
2318
+ import { z as z4 } from "zod";
2662
2319
 
2663
2320
  // src/chat/ingress/message-router.ts
2664
2321
  function normalizeIncomingSlackThreadId(threadId, message) {
@@ -2829,14 +2486,14 @@ async function ensureSlackMessageActorIdentity(message, teamId, lookupSlackUser2
2829
2486
  }
2830
2487
 
2831
2488
  // src/chat/slack/user.ts
2832
- import { z as z4 } from "zod";
2833
- var slackUserInfoSchema = z4.object({
2834
- ok: z4.literal(true),
2835
- user: z4.object({
2836
- name: z4.string().nullish(),
2837
- profile: z4.object({
2838
- email: z4.string().nullish(),
2839
- real_name: z4.string().nullish()
2489
+ import { z as z3 } from "zod";
2490
+ var slackUserInfoSchema = z3.object({
2491
+ ok: z3.literal(true),
2492
+ user: z3.object({
2493
+ name: z3.string().nullish(),
2494
+ profile: z3.object({
2495
+ email: z3.string().nullish(),
2496
+ real_name: z3.string().nullish()
2840
2497
  }).optional()
2841
2498
  })
2842
2499
  });
@@ -2913,6 +2570,20 @@ async function lookupSlackUser(teamId, userId) {
2913
2570
  }
2914
2571
  }
2915
2572
 
2573
+ // src/chat/resource-events/actor.ts
2574
+ var RESOURCE_EVENT_SLACK_AUTHOR_ID = "UJRNEVENT";
2575
+ var RESOURCE_EVENT_SYSTEM_ACTOR = {
2576
+ platform: "system",
2577
+ name: "resource-event"
2578
+ };
2579
+ function isResourceEventConversationMessage(message) {
2580
+ return Boolean(message.meta?.eventType) || message.author?.userId === RESOURCE_EVENT_SLACK_AUTHOR_ID;
2581
+ }
2582
+ function isResourceEventSlackMessage(message) {
2583
+ const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
2584
+ return raw?.event_type === "resource_event";
2585
+ }
2586
+
2916
2587
  // src/chat/slack/message-control.ts
2917
2588
  var LEADING_MENTION_BEFORE_STEERING_RE = /^(\s*(?:<@[^>]+>|@[A-Za-z0-9._-]+\b)[\s,:-]*)!!\s*/;
2918
2589
  function stripLeadingSteeringOverride(text) {
@@ -2920,17 +2591,17 @@ function stripLeadingSteeringOverride(text) {
2920
2591
  }
2921
2592
 
2922
2593
  // src/chat/task-execution/slack-work.ts
2923
- var slackConversationRouteSchema = z5.enum(["mention", "subscribed"]);
2594
+ var slackConversationRouteSchema = z4.enum(["mention", "subscribed"]);
2924
2595
  function hasSteeringOverride(text) {
2925
2596
  return stripLeadingSteeringOverride(text) !== text;
2926
2597
  }
2927
- var serializedDateSchema = z5.iso.datetime();
2928
- var mdastPointSchema = z5.object({
2929
- column: z5.number().int().positive(),
2930
- line: z5.number().int().positive(),
2931
- offset: z5.number().int().nonnegative().optional()
2598
+ var serializedDateSchema = z4.iso.datetime();
2599
+ var mdastPointSchema = z4.object({
2600
+ column: z4.number().int().positive(),
2601
+ line: z4.number().int().positive(),
2602
+ offset: z4.number().int().nonnegative().optional()
2932
2603
  }).strict();
2933
- var mdastPositionSchema = z5.object({
2604
+ var mdastPositionSchema = z4.object({
2934
2605
  end: mdastPointSchema,
2935
2606
  start: mdastPointSchema
2936
2607
  }).strict();
@@ -3042,7 +2713,7 @@ function isFormattedContentNode(value) {
3042
2713
  return false;
3043
2714
  }
3044
2715
  }
3045
- var formattedContentSchema = z5.custom(
2716
+ var formattedContentSchema = z4.custom(
3046
2717
  (value) => {
3047
2718
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
3048
2719
  return false;
@@ -3052,79 +2723,79 @@ var formattedContentSchema = z5.custom(
3052
2723
  },
3053
2724
  "must be a valid formatted-content root"
3054
2725
  );
3055
- var serializedMessageSchema = z5.object({
3056
- _type: z5.literal("chat:Message"),
3057
- attachments: z5.array(
3058
- z5.object({
3059
- type: z5.enum(["image", "file", "video", "audio"]),
3060
- url: z5.string().optional(),
3061
- name: z5.string().optional(),
3062
- mimeType: z5.string().optional(),
3063
- size: z5.number().finite().optional(),
3064
- width: z5.number().finite().optional(),
3065
- height: z5.number().finite().optional(),
3066
- fetchMetadata: z5.record(z5.string(), z5.string()).optional()
2726
+ var serializedMessageSchema = z4.object({
2727
+ _type: z4.literal("chat:Message"),
2728
+ attachments: z4.array(
2729
+ z4.object({
2730
+ type: z4.enum(["image", "file", "video", "audio"]),
2731
+ url: z4.string().optional(),
2732
+ name: z4.string().optional(),
2733
+ mimeType: z4.string().optional(),
2734
+ size: z4.number().finite().optional(),
2735
+ width: z4.number().finite().optional(),
2736
+ height: z4.number().finite().optional(),
2737
+ fetchMetadata: z4.record(z4.string(), z4.string()).optional()
3067
2738
  }).strict()
3068
2739
  ),
3069
- author: z5.object({
3070
- userId: z5.string(),
3071
- userName: z5.string(),
3072
- fullName: z5.string(),
3073
- isBot: z5.union([z5.boolean(), z5.literal("unknown")]),
3074
- isMe: z5.boolean()
2740
+ author: z4.object({
2741
+ userId: z4.string(),
2742
+ userName: z4.string(),
2743
+ fullName: z4.string(),
2744
+ isBot: z4.union([z4.boolean(), z4.literal("unknown")]),
2745
+ isMe: z4.boolean()
3075
2746
  }).strict(),
3076
2747
  formatted: formattedContentSchema,
3077
- id: z5.string().min(1),
3078
- isMention: z5.boolean().optional(),
3079
- links: z5.array(
3080
- z5.object({
3081
- url: z5.string(),
3082
- title: z5.string().optional(),
3083
- description: z5.string().optional(),
3084
- imageUrl: z5.string().optional(),
3085
- siteName: z5.string().optional()
2748
+ id: z4.string().min(1),
2749
+ isMention: z4.boolean().optional(),
2750
+ links: z4.array(
2751
+ z4.object({
2752
+ url: z4.string(),
2753
+ title: z4.string().optional(),
2754
+ description: z4.string().optional(),
2755
+ imageUrl: z4.string().optional(),
2756
+ siteName: z4.string().optional()
3086
2757
  }).strict()
3087
2758
  ).optional(),
3088
- metadata: z5.object({
2759
+ metadata: z4.object({
3089
2760
  dateSent: serializedDateSchema,
3090
- edited: z5.boolean(),
2761
+ edited: z4.boolean(),
3091
2762
  editedAt: serializedDateSchema.optional()
3092
2763
  }).strict(),
3093
- raw: z5.unknown(),
3094
- text: z5.string(),
3095
- threadId: z5.string().min(1)
2764
+ raw: z4.unknown(),
2765
+ text: z4.string(),
2766
+ threadId: z4.string().min(1)
3096
2767
  }).strict();
3097
- var serializedThreadSchema = z5.object({
3098
- _type: z5.literal("chat:Thread"),
3099
- adapterName: z5.literal("slack"),
3100
- channelId: z5.string().min(1),
3101
- channelVisibility: z5.enum(["private", "workspace", "external", "unknown"]).optional(),
2768
+ var serializedThreadSchema = z4.object({
2769
+ _type: z4.literal("chat:Thread"),
2770
+ adapterName: z4.literal("slack"),
2771
+ channelId: z4.string().min(1),
2772
+ channelVisibility: z4.enum(["private", "workspace", "external", "unknown"]).optional(),
3102
2773
  currentMessage: serializedMessageSchema.optional(),
3103
- id: z5.string().min(1),
3104
- isDM: z5.boolean()
2774
+ id: z4.string().min(1),
2775
+ isDM: z4.boolean()
3105
2776
  }).strict();
3106
- var slackInstallationSchema = z5.object({
3107
- enterpriseId: z5.string().optional(),
3108
- isEnterpriseInstall: z5.boolean().optional(),
3109
- teamId: z5.string().optional()
2777
+ var slackInstallationSchema = z4.object({
2778
+ enterpriseId: z4.string().optional(),
2779
+ isEnterpriseInstall: z4.boolean().optional(),
2780
+ teamId: z4.string().optional()
3110
2781
  }).strict();
3111
- var slackConversationMessageMetadataBaseSchema = z5.object({
2782
+ var slackConversationMessageMetadataBaseSchema = z4.object({
3112
2783
  installation: slackInstallationSchema.optional(),
3113
2784
  message: serializedMessageSchema,
3114
- platform: z5.literal("slack"),
2785
+ platform: z4.literal("slack"),
3115
2786
  route: slackConversationRouteSchema,
3116
2787
  thread: serializedThreadSchema
3117
2788
  });
3118
- var slackConversationMessageMetadataSchema = z5.union([
2789
+ var slackConversationMessageMetadataSchema = z4.union([
3119
2790
  slackConversationMessageMetadataBaseSchema.strict(),
3120
2791
  slackConversationMessageMetadataBaseSchema.extend({
3121
- kind: z5.literal("resource_event"),
3122
- resourceEvent: z5.object({
3123
- eventKey: z5.string(),
3124
- eventType: z5.string(),
3125
- namespace: z5.string(),
3126
- identifier: z5.string(),
3127
- subscriptionId: z5.string()
2792
+ kind: z4.literal("resource_event"),
2793
+ resourceEvent: z4.object({
2794
+ eventKey: z4.string(),
2795
+ eventType: z4.string(),
2796
+ namespace: z4.string(),
2797
+ identifier: z4.string(),
2798
+ subscriptionId: z4.string()
3128
2799
  }).strict()
3129
2800
  }).strict()
3130
2801
  ]);
@@ -3157,7 +2828,7 @@ function slackSerializedResourceEventMessage(input) {
3157
2828
  _type: "chat:Message",
3158
2829
  attachments: [],
3159
2830
  author: {
3160
- userId: "UJRNEVENT",
2831
+ userId: RESOURCE_EVENT_SLACK_AUTHOR_ID,
3161
2832
  userName: "junior-event",
3162
2833
  fullName: "Junior event",
3163
2834
  isBot: true,
@@ -3175,7 +2846,7 @@ function slackSerializedResourceEventMessage(input) {
3175
2846
  resource_event_type: input.eventType,
3176
2847
  thread_ts: input.threadTs,
3177
2848
  type: "message",
3178
- user: "UJRNEVENT"
2849
+ user: RESOURCE_EVENT_SLACK_AUTHOR_ID
3179
2850
  },
3180
2851
  text: input.text,
3181
2852
  threadId: `slack:${input.channelId}:${input.threadTs}`
@@ -3219,7 +2890,7 @@ function createSlackResourceEventInboundMessage(input) {
3219
2890
  receivedAtMs: Date.now(),
3220
2891
  input: {
3221
2892
  text: input.text,
3222
- authorId: "UJRNEVENT",
2893
+ authorId: RESOURCE_EVENT_SLACK_AUTHOR_ID,
3223
2894
  metadata: {
3224
2895
  kind: "resource_event",
3225
2896
  installation: {
@@ -3259,10 +2930,6 @@ function routeForRecords(records) {
3259
2930
  return metadata.route === "mention";
3260
2931
  }) ? "mention" : "subscribed";
3261
2932
  }
3262
- function isResourceEventNotificationMessage(message) {
3263
- const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
3264
- return raw?.event_type === "resource_event";
3265
- }
3266
2933
  function restoreMessage(args) {
3267
2934
  const metadata = parseSlackMetadata(args.record.input.metadata);
3268
2935
  if (!metadata) {
@@ -3278,7 +2945,7 @@ function restoreMessage(args) {
3278
2945
  async function bindSlackActorIdentities(args) {
3279
2946
  const byAuthorId = /* @__PURE__ */ new Map();
3280
2947
  for (const message of args.messages) {
3281
- if (isResourceEventNotificationMessage(message)) {
2948
+ if (isResourceEventSlackMessage(message)) {
3282
2949
  continue;
3283
2950
  }
3284
2951
  const authorId = requireSlackAuthorId(message);
@@ -4497,7 +4164,7 @@ function registerVercelPluginTaskDevConsumer() {
4497
4164
  }
4498
4165
 
4499
4166
  // src/chat/services/subscribed-decision.ts
4500
- import { z as z6 } from "zod";
4167
+ import { z as z5 } from "zod";
4501
4168
 
4502
4169
  // src/chat/services/subscribed-reply-router-policy.ts
4503
4170
  function buildSubscribedReplyRouterPolicy(assistantName) {
@@ -4542,13 +4209,13 @@ Assess conversation floor ownership and whether the latest message continues wor
4542
4209
  }
4543
4210
 
4544
4211
  // src/chat/services/subscribed-decision.ts
4545
- var replyDecisionSchema = z6.object({
4546
- should_reply: z6.boolean().describe("Whether Junior should respond to this thread message."),
4547
- should_unsubscribe: z6.boolean().describe(
4212
+ var replyDecisionSchema = z5.object({
4213
+ should_reply: z5.boolean().describe("Whether Junior should respond to this thread message."),
4214
+ should_unsubscribe: z5.boolean().describe(
4548
4215
  "Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
4549
4216
  ),
4550
- confidence: z6.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
4551
- reason: z6.string().describe("Short reason for the decision; use an empty string if none.")
4217
+ confidence: z5.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
4218
+ reason: z5.string().describe("Short reason for the decision; use an empty string if none.")
4552
4219
  }).strict();
4553
4220
  var ROUTER_CONFIDENCE_THRESHOLD = 0.7;
4554
4221
  var ROUTER_CLASSIFIER_MAX_TOKENS = 400;
@@ -5003,10 +4670,6 @@ function buildLogContext(deps, args) {
5003
4670
  function actorUserName(message) {
5004
4671
  return getMessageActorIdentity(message)?.userName;
5005
4672
  }
5006
- function isResourceEventNotificationMessage2(message) {
5007
- const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
5008
- return raw?.event_type === "resource_event";
5009
- }
5010
4673
  function createSlackTurnRuntime(deps) {
5011
4674
  const logContext = (args) => buildLogContext(deps, args);
5012
4675
  const maybeHandleThreadOptOutDecision = async (args) => {
@@ -5427,7 +5090,7 @@ function createSlackTurnRuntime(deps) {
5427
5090
  const threadId = deps.getThreadId(thread, message);
5428
5091
  const channelId = deps.getChannelId(thread, message);
5429
5092
  const runId = deps.getRunId(thread, message);
5430
- const isResourceEventNotification = isResourceEventNotificationMessage2(message);
5093
+ const isResourceEventNotification = isResourceEventSlackMessage(message);
5431
5094
  const actorId = isResourceEventNotification ? void 0 : message.author.userId;
5432
5095
  const turnContext = logContext({
5433
5096
  threadId,
@@ -6225,11 +5888,11 @@ function createJuniorRuntimeServices(overrides = {}) {
6225
5888
  import { createSlackSource as createSlackSource2 } from "@sentry/junior-plugin-api";
6226
5889
 
6227
5890
  // src/chat/slack/action-token.ts
6228
- import { z as z7 } from "zod";
6229
- var slackActionTokenSchema = z7.string().trim().min(1).brand();
6230
- var slackMessageEnvelopeSchema = z7.object({
6231
- raw: z7.object({
6232
- action_token: z7.unknown().optional()
5891
+ import { z as z6 } from "zod";
5892
+ var slackActionTokenSchema = z6.string().trim().min(1).brand();
5893
+ var slackMessageEnvelopeSchema = z6.object({
5894
+ raw: z6.object({
5895
+ action_token: z6.unknown().optional()
6233
5896
  }).optional()
6234
5897
  });
6235
5898
  function readSlackActionToken(message) {
@@ -6393,7 +6056,7 @@ function queuedInstructionActor(queued) {
6393
6056
  };
6394
6057
  }
6395
6058
  function queuedInstructionProvenance(queued, teamId) {
6396
- if (isResourceEventMessage(queued.message)) {
6059
+ if (isResourceEventSlackMessage(queued.message)) {
6397
6060
  return contextProvenance;
6398
6061
  }
6399
6062
  const identity = getMessageActorIdentity(queued.message);
@@ -6407,13 +6070,6 @@ function queuedInstructionProvenance(queued, teamId) {
6407
6070
  );
6408
6071
  return instructionProvenanceFor(author);
6409
6072
  }
6410
- function isResourceEventMessage(message) {
6411
- const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
6412
- return raw?.event_type === "resource_event";
6413
- }
6414
- function resourceEventCredentialContext(message) {
6415
- return isResourceEventMessage(message) ? { actor: { platform: "system", name: "resource-event" } } : void 0;
6416
- }
6417
6073
  async function resolveChannelName(thread) {
6418
6074
  const existingName = thread.channel.name?.trim();
6419
6075
  if (existingName) {
@@ -6542,7 +6198,7 @@ function createReplyToThread(deps) {
6542
6198
  )
6543
6199
  };
6544
6200
  await Promise.all(
6545
- (options.queuedMessages ?? []).filter((queued) => !isResourceEventMessage(queued.message)).map(
6201
+ (options.queuedMessages ?? []).filter((queued) => !isResourceEventSlackMessage(queued.message)).map(
6546
6202
  (queued) => ensureSlackMessageActorIdentity(
6547
6203
  queued.message,
6548
6204
  teamId,
@@ -6551,15 +6207,28 @@ function createReplyToThread(deps) {
6551
6207
  )
6552
6208
  );
6553
6209
  const effectiveUserText = currentText.userText;
6554
- const credentialContext = options.execution?.credentialContext ?? resourceEventCredentialContext(message) ?? {
6555
- actor: { type: "user", userId: message.author.userId }
6556
- };
6557
- const actor = "type" in credentialContext.actor ? await ensureSlackMessageActorIdentity(
6558
- message,
6559
- teamId,
6560
- deps.services.lookupSlackUser
6561
- ) : void 0;
6562
- const executionActor = "type" in credentialContext.actor ? actor : credentialContext.actor;
6210
+ let executionActor;
6211
+ let credentialContext;
6212
+ if (options.execution) {
6213
+ executionActor = options.execution.dispatch.actor;
6214
+ credentialContext = options.execution.credentialContext;
6215
+ } else if (isResourceEventSlackMessage(message)) {
6216
+ executionActor = RESOURCE_EVENT_SYSTEM_ACTOR;
6217
+ credentialContext = credentialContextForActor(executionActor);
6218
+ } else {
6219
+ executionActor = await ensureSlackMessageActorIdentity(
6220
+ message,
6221
+ teamId,
6222
+ deps.services.lookupSlackUser
6223
+ );
6224
+ if (executionActor) {
6225
+ credentialContext = credentialContextForActor(executionActor);
6226
+ }
6227
+ }
6228
+ if (!executionActor || !credentialContext) {
6229
+ throw new Error("Slack reply execution requires an actor");
6230
+ }
6231
+ const actor = "userId" in executionActor ? executionActor : void 0;
6563
6232
  const slackActorId = actor?.userId;
6564
6233
  const preparedState = options.preparedState ?? await deps.prepareTurnState({
6565
6234
  thread,
@@ -6633,7 +6302,7 @@ function createReplyToThread(deps) {
6633
6302
  attachments,
6634
6303
  {
6635
6304
  threadId,
6636
- actorId: isResourceEventMessage(queued.message) ? void 0 : queued.message.author.userId,
6305
+ actorId: isResourceEventSlackMessage(queued.message) ? void 0 : queued.message.author.userId,
6637
6306
  channelId,
6638
6307
  runId,
6639
6308
  conversation: preparedState.conversation,
@@ -7208,7 +6877,9 @@ function createReplyToThread(deps) {
7208
6877
  },
7209
6878
  routing: {
7210
6879
  credentialContext,
7211
- actor: options.execution ? executionActor : actor,
6880
+ // Always set the execution actor when known. Resource-event turns
6881
+ // carry the system principal; interactive turns carry the Slack user.
6882
+ actor: executionActor,
7212
6883
  slackConversation,
7213
6884
  source,
7214
6885
  destination,
@@ -8236,27 +7907,57 @@ async function failContinuationStartup(args) {
8236
7907
  );
8237
7908
  }
8238
7909
  }
8239
- async function resolveContinuationActor(args) {
8240
- const stored = args.sessionRecordActor;
8241
- if (stored?.platform === "slack" && stored.teamId === args.teamId && stored.userId === args.userId) {
7910
+ async function resolveSlackResumeUserActor(args) {
7911
+ try {
7912
+ const work = await getConversationWorkState({
7913
+ conversationId: args.conversationId
7914
+ });
7915
+ const workActor = work?.actor;
7916
+ if (workActor?.teamId === args.teamId && workActor.slackUserId === args.userId) {
7917
+ try {
7918
+ return createSlackActor(args.teamId, args.userId, {
7919
+ email: workActor.email,
7920
+ fullName: workActor.fullName,
7921
+ userName: workActor.slackUserName
7922
+ });
7923
+ } catch {
7924
+ }
7925
+ }
7926
+ } catch {
7927
+ }
7928
+ try {
8242
7929
  return createSlackResumeActor({
8243
- actor: stored,
8244
7930
  teamId: args.teamId,
8245
7931
  userId: args.userId
8246
7932
  });
7933
+ } catch {
7934
+ return void 0;
8247
7935
  }
8248
- const work = await getConversationWorkState({
8249
- conversationId: args.conversationId
8250
- });
8251
- const workActor = work?.actor;
8252
- if (workActor && workActor.teamId === args.teamId && workActor.slackUserId === args.userId) {
8253
- return createSlackActor(args.teamId, args.userId, {
8254
- email: workActor.email,
8255
- fullName: workActor.fullName,
8256
- userName: workActor.slackUserName
7936
+ }
7937
+ async function resolveResumeExecutionIdentity(args) {
7938
+ const routing = args.routingContext;
7939
+ if (routing?.credentialContext) {
7940
+ const actor2 = routing.dispatch?.actor ?? routing.actor ?? (!("type" in routing.credentialContext.actor) ? routing.credentialContext.actor : void 0);
7941
+ return actor2 ? { actor: actor2, credentialContext: routing.credentialContext } : void 0;
7942
+ }
7943
+ let actor = routing?.actor;
7944
+ if (!actor && isResourceEventConversationMessage(args.userMessage)) {
7945
+ actor = RESOURCE_EVENT_SYSTEM_ACTOR;
7946
+ }
7947
+ if (!actor && args.userMessage.author?.userId) {
7948
+ actor = await resolveSlackResumeUserActor({
7949
+ conversationId: args.conversationId,
7950
+ teamId: args.teamId,
7951
+ userId: args.userMessage.author.userId
8257
7952
  });
8258
7953
  }
8259
- return void 0;
7954
+ if (!actor) {
7955
+ return void 0;
7956
+ }
7957
+ return {
7958
+ actor,
7959
+ credentialContext: credentialContextForActor(actor)
7960
+ };
8260
7961
  }
8261
7962
  function isContinuationResume(summary) {
8262
7963
  return summary.state === "awaiting_resume" && (summary.resumeReason === "timeout" || summary.resumeReason === "yield" || summary.resumeReason === "retry");
@@ -8274,7 +7975,6 @@ async function failUnresumableContinuation(args) {
8274
7975
  conversationId: args.conversationId
8275
7976
  });
8276
7977
  await recordAgentTurnSessionSummary({
8277
- actor: args.summary.actor,
8278
7978
  conversationId: args.conversationId,
8279
7979
  destination: routing.destination,
8280
7980
  dispatchId: args.summary.dispatchId,
@@ -8341,16 +8041,32 @@ async function continueSlackAgentRunInContext(payload, options, runOptions) {
8341
8041
  (message) => message.role === "user" && options.inputMessageIds?.includes(message.id)
8342
8042
  ) : void 0;
8343
8043
  const userMessage = getTurnUserMessage(conversation, payload.sessionId) ?? dispatchUserMessage;
8344
- const systemActor = activeSessionRecord.actor?.platform === "system" ? activeSessionRecord.actor : void 0;
8345
- const userActorId = userMessage?.author?.userId;
8346
- if (!userMessage || !systemActor && !userActorId) {
8347
- throw new Error(
8348
- `Unable to locate the persisted user message for agent continuation session "${payload.sessionId}"`
8349
- );
8044
+ if (!userMessage) {
8045
+ await failStrandedSessionWithFallback({
8046
+ conversationId: payload.conversationId,
8047
+ errorMessage: `Unable to locate the persisted user message for agent continuation session "${payload.sessionId}"`,
8048
+ sessionRecord: activeSessionRecord
8049
+ });
8050
+ return false;
8350
8051
  }
8351
8052
  if (conversation.processing.activeTurnId !== payload.sessionId) {
8352
8053
  return false;
8353
8054
  }
8055
+ const identity = await resolveResumeExecutionIdentity({
8056
+ conversationId: payload.conversationId,
8057
+ routingContext: options.routingContext,
8058
+ teamId: destination.teamId,
8059
+ userMessage
8060
+ });
8061
+ if (!identity) {
8062
+ await failStrandedSessionWithFallback({
8063
+ conversationId: payload.conversationId,
8064
+ errorMessage: "Unable to rebuild Slack actor for continuation",
8065
+ sessionRecord: activeSessionRecord
8066
+ });
8067
+ return false;
8068
+ }
8069
+ const { actor, credentialContext } = identity;
8354
8070
  const channelConfiguration = getChannelConfigurationServiceById(
8355
8071
  destination.channelId
8356
8072
  );
@@ -8358,34 +8074,6 @@ async function continueSlackAgentRunInContext(payload, options, runOptions) {
8358
8074
  excludeMessageId: userMessage.id
8359
8075
  });
8360
8076
  const sandboxRef = getPersistedSandboxState(currentState);
8361
- let actor;
8362
- let credentialContext;
8363
- if (options.routingContext?.credentialContext) {
8364
- credentialContext = options.routingContext.credentialContext;
8365
- } else if (systemActor) {
8366
- credentialContext = { actor: systemActor };
8367
- } else {
8368
- actor = await resolveContinuationActor({
8369
- conversationId: payload.conversationId,
8370
- sessionRecordActor: activeSessionRecord.actor,
8371
- teamId: destination.teamId,
8372
- userId: userActorId
8373
- });
8374
- if (!actor) {
8375
- await failStrandedSessionWithFallback({
8376
- conversationId: payload.conversationId,
8377
- errorMessage: "Stored Slack actor missing for continuation",
8378
- sessionRecord: activeSessionRecord
8379
- });
8380
- return false;
8381
- }
8382
- credentialContext = {
8383
- actor: {
8384
- type: "user",
8385
- userId: actor.userId
8386
- }
8387
- };
8388
- }
8389
8077
  const routing = await resolveTurnSessionRouting({
8390
8078
  conversationId: payload.conversationId
8391
8079
  });
@@ -8433,7 +8121,7 @@ async function continueSlackAgentRunInContext(payload, options, runOptions) {
8433
8121
  routing: {
8434
8122
  ...options.routingContext,
8435
8123
  credentialContext,
8436
- ...options.routingContext?.actor ?? actor ? { actor: options.routingContext?.actor ?? actor } : {},
8124
+ actor,
8437
8125
  destination: routingDestination,
8438
8126
  source,
8439
8127
  toolChannelId: artifacts.assistantContextChannelId ?? destination.channelId
@@ -8554,7 +8242,6 @@ async function failStrandedSessionWithFallback(args) {
8554
8242
  }
8555
8243
  if (args.sessionRecord.dispatchId) {
8556
8244
  await recordAgentTurnSessionSummary({
8557
- actor: args.sessionRecord.actor,
8558
8245
  conversationId: args.conversationId,
8559
8246
  destination: routing.destination,
8560
8247
  dispatchId: args.sessionRecord.dispatchId,
@@ -8619,7 +8306,6 @@ async function recoverStrandedRunningSession(args) {
8619
8306
  messages: sessionRecord.piMessages,
8620
8307
  errorMessage: "Recovered running session after hard worker death",
8621
8308
  modelId,
8622
- actor: sessionRecord.actor,
8623
8309
  surface: sessionRecord.surface
8624
8310
  });
8625
8311
  if (!parked) {
@@ -8949,7 +8635,7 @@ async function ingestResourceEvent(input, options) {
8949
8635
  }
8950
8636
 
8951
8637
  // src/chat/event-tasks/ingest.ts
8952
- import { createHash as createHash2 } from "crypto";
8638
+ import { createHash } from "crypto";
8953
8639
  import {
8954
8640
  createSlackSource as createSlackSource3,
8955
8641
  RESOURCE_EVENT_SUMMARY_MAX_LENGTH,
@@ -8957,7 +8643,7 @@ import {
8957
8643
  resourceEventSchema as resourceEventSchema2
8958
8644
  } from "@sentry/junior-plugin-api";
8959
8645
  function eventTaskDispatchKey(taskId, namespace, eventKey) {
8960
- return `event-task:${createHash2("sha256").update(`${taskId}\0${namespace}\0${eventKey}`).digest("hex").slice(0, 32)}`;
8646
+ return `event-task:${createHash("sha256").update(`${taskId}\0${namespace}\0${eventKey}`).digest("hex").slice(0, 32)}`;
8961
8647
  }
8962
8648
  function oneLine(value) {
8963
8649
  return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 512);