@sentry/junior 0.185.0 → 0.186.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 (88) hide show
  1. package/dist/{agent-hooks-NGZQLL5O.js → agent-hooks-4B3Z4WRK.js} +11 -11
  2. package/dist/api/schema/conversation.d.ts +8 -0
  3. package/dist/api/schema.js +1 -1
  4. package/dist/api.js +43 -35
  5. package/dist/app.js +1061 -216
  6. package/dist/{catalog-runtime-AAEAO2RL.js → catalog-runtime-AFJCAOHC.js} +4 -4
  7. package/dist/chat/api-turns/mailbox-input.d.ts +7 -0
  8. package/dist/chat/api-turns/routing.d.ts +18 -3
  9. package/dist/chat/conversations/turn-lifecycle.d.ts +2 -0
  10. package/dist/chat/providers/slack/runtime.d.ts +0 -2
  11. package/dist/chat/providers/slack/turn.d.ts +0 -2
  12. package/dist/chat/resource-events/actor.d.ts +7 -2
  13. package/dist/chat/resource-events/app-publisher.d.ts +18 -0
  14. package/dist/chat/resource-events/catalog.d.ts +19 -0
  15. package/dist/chat/resource-events/ingest.d.ts +0 -1
  16. package/dist/chat/resource-events/notification.d.ts +28 -3
  17. package/dist/chat/resource-events/runtime-catalog.d.ts +7 -2
  18. package/dist/chat/resource-events/store.d.ts +1 -13
  19. package/dist/chat/resource-events/workspace.d.ts +7 -3
  20. package/dist/chat/sandbox/egress/credentials.d.ts +5 -4
  21. package/dist/chat/sandbox/egress/session.d.ts +9 -9
  22. package/dist/chat/sandbox/errors.d.ts +1 -1
  23. package/dist/chat/sandbox/ref.d.ts +1 -1
  24. package/dist/chat/sandbox/snapshot/events.d.ts +8 -1
  25. package/dist/chat/sandbox/snapshot/not-ready-error.d.ts +6 -1
  26. package/dist/chat/sentry-links.d.ts +2 -0
  27. package/dist/chat/services/turn-session-routing.d.ts +20 -5
  28. package/dist/chat/task-execution/slack-resource-event.d.ts +47 -0
  29. package/dist/chat/task-execution/slack-work.d.ts +0 -21
  30. package/dist/chat/tools/event-tasks.d.ts +1 -1
  31. package/dist/chat/tools/resource-events.d.ts +1 -1
  32. package/dist/{chunk-D63IUQQE.js → chunk-2IBDVE62.js} +12 -9
  33. package/dist/{chunk-C6TS47CQ.js → chunk-2U7EPTRZ.js} +11 -5
  34. package/dist/{chunk-OMQ2J6F6.js → chunk-3CVEE6LA.js} +1 -1
  35. package/dist/{chunk-ABAX75GG.js → chunk-43LODHJM.js} +17 -3
  36. package/dist/{chunk-7MHNIGHP.js → chunk-64WF2GQ3.js} +1 -1
  37. package/dist/{chunk-X7NCJQAA.js → chunk-7EOWT62G.js} +1 -1
  38. package/dist/{chunk-MWOH6CIK.js → chunk-7EU4YSZ4.js} +201 -57
  39. package/dist/{chunk-4S47VHJR.js → chunk-ACGWTJ74.js} +3 -3
  40. package/dist/{chunk-LRI5IRGY.js → chunk-AD64YMEC.js} +2 -2
  41. package/dist/{chunk-FTVMXDNN.js → chunk-BRKB5R7P.js} +1 -1
  42. package/dist/{chunk-Y5G23T2D.js → chunk-CM6RTYSO.js} +5 -5
  43. package/dist/{chunk-QCT4226Q.js → chunk-CV5CPRVG.js} +3 -3
  44. package/dist/{chunk-QZKHHG3B.js → chunk-DHYZ4VKG.js} +382 -279
  45. package/dist/{chunk-PNYJOEVV.js → chunk-DOP3FIQC.js} +1 -1
  46. package/dist/{chunk-HJPC32TQ.js → chunk-EWRPUXE3.js} +9 -9
  47. package/dist/{chunk-EIJCPJOY.js → chunk-FFYDRLXW.js} +1 -1
  48. package/dist/{chunk-W7GCLNIV.js → chunk-GQMQCY7H.js} +2 -2
  49. package/dist/{chunk-6DOAUXLD.js → chunk-GSB3NTNS.js} +744 -1707
  50. package/dist/{chunk-WLKWN4CD.js → chunk-H7X2G2KS.js} +8 -5
  51. package/dist/{chunk-ATUWN6Z3.js → chunk-HKFLRIBD.js} +2 -2
  52. package/dist/{chunk-EJYP3NQ4.js → chunk-HWXP6RHG.js} +37 -3
  53. package/dist/{chunk-VH4IU3UC.js → chunk-JFPY6XFF.js} +19 -45
  54. package/dist/{chunk-FFHXG2FX.js → chunk-MCLWOBPN.js} +76 -16
  55. package/dist/{chunk-GJTIZQGJ.js → chunk-NRMAOGRS.js} +1 -1
  56. package/dist/{chunk-X2SS6BF7.js → chunk-O6GQO7VP.js} +27 -33
  57. package/dist/{chunk-DAPC2HTM.js → chunk-OZG7E22Y.js} +5 -5
  58. package/dist/{chunk-4K25ODAO.js → chunk-PFAZSRGR.js} +3 -1
  59. package/dist/{chunk-UUULGCKK.js → chunk-PZZOGHVR.js} +14 -4
  60. package/dist/{chunk-TVVAMOLS.js → chunk-QBL2AVFF.js} +1 -1
  61. package/dist/{chunk-4HA36IWS.js → chunk-QU3URVWG.js} +8 -8
  62. package/dist/{chunk-6Q7YZLCL.js → chunk-STOCCPWH.js} +9 -1
  63. package/dist/{chunk-EWEH2PJW.js → chunk-TXLBLGNQ.js} +5 -5
  64. package/dist/{chunk-U4CTAVWN.js → chunk-VOGOTEW7.js} +1 -1
  65. package/dist/{chunk-ZIF2S464.js → chunk-VQIWBJOP.js} +1 -1
  66. package/dist/{chunk-ZKKGFUWM.js → chunk-VQZYIVYN.js} +6 -6
  67. package/dist/{chunk-LVK4WJKM.js → chunk-VXL2LBPK.js} +1 -1
  68. package/dist/{chunk-7GAP2XG4.js → chunk-YXSBZRP7.js} +1 -1
  69. package/dist/cli/chat.js +32 -32
  70. package/dist/cli/check.js +5 -5
  71. package/dist/cli/plugins.js +12 -12
  72. package/dist/cli/snapshot-create.js +9 -9
  73. package/dist/cli/upgrade.js +6 -6
  74. package/dist/{db-TRJ77FAU.js → db-7XL4UPAE.js} +6 -6
  75. package/dist/instrumentation.js +3 -3
  76. package/dist/nitro.js +6 -6
  77. package/dist/{oauth-callback-server-XD5SV3MS.js → oauth-callback-server-RAOYHWDI.js} +27 -27
  78. package/dist/{runner-KFX7NG6D.js → runner-KMPBWRPM.js} +19 -19
  79. package/dist/{skills-J2AH26CW.js → skills-IPCALGLQ.js} +5 -5
  80. package/dist/spawn-OSOWTMBG.js +41 -0
  81. package/dist/task-runner-IQNBA3RY.js +34 -0
  82. package/dist/{validation-O5J4VOPF.js → validation-BSRCCX6N.js} +5 -5
  83. package/dist/version.js +1 -1
  84. package/dist/{work-ECPQTG3U.js → work-T6UFTOJY.js} +20 -20
  85. package/dist/{worker-RS3DXUDO.js → worker-L35OG7VA.js} +10 -10
  86. package/package.json +5 -5
  87. package/dist/spawn-VU3CSRI6.js +0 -41
  88. package/dist/task-runner-5JG3VIIY.js +0 -34
@@ -19,23 +19,23 @@ import {
19
19
  releaseConversationWork,
20
20
  requestAnotherSlice,
21
21
  startConversationWork
22
- } from "./chunk-D63IUQQE.js";
22
+ } from "./chunk-2IBDVE62.js";
23
23
  import {
24
24
  ConversationQueueMessageRejectedError
25
25
  } from "./chunk-JAL3CH4G.js";
26
26
  import {
27
27
  getTurnRequestDeadline
28
- } from "./chunk-FTVMXDNN.js";
28
+ } from "./chunk-BRKB5R7P.js";
29
29
  import {
30
30
  getChatConfig,
31
31
  isProviderRetryError
32
- } from "./chunk-LRI5IRGY.js";
32
+ } from "./chunk-AD64YMEC.js";
33
33
  import {
34
34
  logException,
35
35
  logInfo,
36
36
  logWarn,
37
37
  withLogContext
38
- } from "./chunk-OMQ2J6F6.js";
38
+ } from "./chunk-3CVEE6LA.js";
39
39
 
40
40
  // src/chat/task-execution/worker.ts
41
41
  var CONVERSATION_WORK_DEFER_DELAY_MS = 15e3;
@@ -276,7 +276,13 @@ async function processConversationWorkInContext(message, options) {
276
276
  }
277
277
  return { status: "no_work" };
278
278
  }
279
- const destination = initial.destination;
279
+ let destination = initial.destination;
280
+ if (!destination && options.conversationStore) {
281
+ const stored = await options.conversationStore.get({ conversationId });
282
+ if (stored && !stored.lineage) {
283
+ destination = stored.destination;
284
+ }
285
+ }
280
286
  const lease = await startConversationWork({
281
287
  conversationId,
282
288
  conversationStore: options.conversationStore,
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-PEQXYSSE.js";
13
13
  import {
14
14
  JUNIOR_VERSION
15
- } from "./chunk-7GAP2XG4.js";
15
+ } from "./chunk-YXSBZRP7.js";
16
16
 
17
17
  // src/deployment.ts
18
18
  var JUNIOR_HEARTBEAT_ROUTE = "/api/internal/heartbeat";
@@ -8,7 +8,7 @@ import {
8
8
  juniorConversations,
9
9
  juniorIdentities,
10
10
  juniorUsers
11
- } from "./chunk-LVK4WJKM.js";
11
+ } from "./chunk-VXL2LBPK.js";
12
12
  import {
13
13
  conversationEventDataSchema,
14
14
  decodeStoredConversationEvent,
@@ -20,7 +20,7 @@ import {
20
20
  } from "./chunk-VFUK3X5B.js";
21
21
  import {
22
22
  getChatConfig
23
- } from "./chunk-LRI5IRGY.js";
23
+ } from "./chunk-AD64YMEC.js";
24
24
  import {
25
25
  parseActorUserId,
26
26
  parseSlackChannelReferenceId,
@@ -28,7 +28,7 @@ import {
28
28
  } from "./chunk-N7TMSOZH.js";
29
29
  import {
30
30
  normalizeIdentityEmail
31
- } from "./chunk-OMQ2J6F6.js";
31
+ } from "./chunk-3CVEE6LA.js";
32
32
 
33
33
  // src/chat/conversations/sql/store.ts
34
34
  import { randomUUID as randomUUID2 } from "crypto";
@@ -777,6 +777,9 @@ var SqlStore = class {
777
777
  await this.withConversationMutation(args.conversationId, async () => {
778
778
  const existingRow = await this.readConversationRow(args.conversationId);
779
779
  const existing = existingRow ? conversationFromRow(existingRow) : void 0;
780
+ if (!existing && !args.destination) {
781
+ return;
782
+ }
780
783
  const incomingExecutionAt = args.execution.updatedAtMs ?? args.updatedAtMs;
781
784
  const existingExecutionAt = existing?.execution.updatedAtMs ?? existing?.updatedAtMs ?? 0;
782
785
  const incomingIsFresh = incomingExecutionAt >= existingExecutionAt;
@@ -790,6 +793,7 @@ var SqlStore = class {
790
793
  createdAtMs: args.createdAtMs,
791
794
  lastActivityAtMs: args.lastActivityAtMs,
792
795
  updatedAtMs: args.updatedAtMs,
796
+ ...existing?.lineage ? { lineage: existing.lineage } : void 0,
793
797
  ...args.channelName ? { channelName: args.channelName } : void 0,
794
798
  ...args.destination ? { destination: args.destination } : void 0,
795
799
  ...args.actor ? { actor: args.actor } : void 0,
@@ -917,6 +921,16 @@ var SqlStore = class {
917
921
  /** Upsert the conversation row while preserving previously discovered nullable metadata fields. */
918
922
  async upsertConversation(args) {
919
923
  const { conversation } = args;
924
+ if (!conversation.lineage && !conversation.destination) {
925
+ const existing = await this.get({
926
+ conversationId: conversation.conversationId
927
+ });
928
+ if (!existing) {
929
+ throw new Error(
930
+ `Conversation ${conversation.conversationId} requires a destination at create`
931
+ );
932
+ }
933
+ }
920
934
  const incomingExecutionVersion = sql3`coalesce(excluded.execution_updated_at, excluded.updated_at)`;
921
935
  const currentExecutionVersion = sql3`coalesce(${juniorConversations.executionUpdatedAt}, ${juniorConversations.updatedAt})`;
922
936
  const incomingExecutionIsFresh = sql3`${incomingExecutionVersion} >= ${currentExecutionVersion}`;
@@ -12,7 +12,7 @@ import {
12
12
  logInfo,
13
13
  logWarn,
14
14
  setSpanAttributes
15
- } from "./chunk-OMQ2J6F6.js";
15
+ } from "./chunk-3CVEE6LA.js";
16
16
 
17
17
  // src/chat/plugins/manifest.ts
18
18
  import { z } from "zod";
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-N7TMSOZH.js";
6
6
  import {
7
7
  toOptionalString
8
- } from "./chunk-OMQ2J6F6.js";
8
+ } from "./chunk-3CVEE6LA.js";
9
9
 
10
10
  // src/chat/slack/context.ts
11
11
  import { z } from "zod";
@@ -1,40 +1,45 @@
1
1
  import {
2
2
  createWebAuthorization,
3
3
  deleteWebAuthorization
4
- } from "./chunk-UUULGCKK.js";
4
+ } from "./chunk-PZZOGHVR.js";
5
5
  import {
6
6
  AgentRunError,
7
7
  executeTurn
8
- } from "./chunk-W7GCLNIV.js";
8
+ } from "./chunk-GQMQCY7H.js";
9
9
  import {
10
10
  buildDeliveredTurnStatePatch,
11
11
  completeAuthPauseTurn,
12
12
  finalizeFailedTurnReplyWithEvent,
13
13
  getTurnUserMessage
14
- } from "./chunk-DAPC2HTM.js";
14
+ } from "./chunk-OZG7E22Y.js";
15
15
  import {
16
16
  processPluginTask,
17
17
  scheduleSessionCompletedPluginTasks
18
- } from "./chunk-FFHXG2FX.js";
18
+ } from "./chunk-MCLWOBPN.js";
19
19
  import {
20
20
  ConversationTurnLifecycleService
21
- } from "./chunk-6Q7YZLCL.js";
21
+ } from "./chunk-STOCCPWH.js";
22
22
  import {
23
23
  coerceThreadConversationState,
24
24
  getPersistedSandboxState,
25
25
  getPersistedThreadState,
26
26
  persistThreadStateById
27
- } from "./chunk-Y5G23T2D.js";
27
+ } from "./chunk-CM6RTYSO.js";
28
28
  import {
29
29
  healthReportSchema
30
30
  } from "./chunk-UTL3MHPC.js";
31
+ import {
32
+ RESOURCE_EVENT_AUTHOR_ID,
33
+ isResourceEventConversationMessage,
34
+ isResourceEventMailboxMetadata
35
+ } from "./chunk-DHYZ4VKG.js";
31
36
  import {
32
37
  parseSlackThreadId
33
- } from "./chunk-X7NCJQAA.js";
38
+ } from "./chunk-7EOWT62G.js";
34
39
  import {
35
40
  appendAndEnqueueExclusiveInboundMessage,
36
41
  appendAndEnqueueInboundMessage
37
- } from "./chunk-D63IUQQE.js";
42
+ } from "./chunk-2IBDVE62.js";
38
43
  import {
39
44
  TurnInputCommitLostError,
40
45
  buildDeterministicTurnId,
@@ -45,7 +50,7 @@ import {
45
50
  markTurnClosed,
46
51
  markTurnFailed,
47
52
  startActiveTurn
48
- } from "./chunk-U4CTAVWN.js";
53
+ } from "./chunk-VOGOTEW7.js";
49
54
  import {
50
55
  abandonTurnRecord,
51
56
  buildConversationContext,
@@ -61,35 +66,39 @@ import {
61
66
  recordDeliveredAssistantMessage,
62
67
  saveTurnCheckpoint,
63
68
  upsertConversationMessage
64
- } from "./chunk-WLKWN4CD.js";
69
+ } from "./chunk-H7X2G2KS.js";
65
70
  import {
66
71
  normalizeSlackConversationId
67
- } from "./chunk-VH4IU3UC.js";
72
+ } from "./chunk-JFPY6XFF.js";
68
73
  import {
69
74
  getConversationEventStore,
70
75
  getConversationStore,
71
76
  getDb
72
- } from "./chunk-ABAX75GG.js";
77
+ } from "./chunk-43LODHJM.js";
73
78
  import {
74
79
  juniorConversationParticipants,
75
80
  juniorConversations,
76
81
  juniorIdentities,
77
82
  juniorUsers
78
- } from "./chunk-LVK4WJKM.js";
83
+ } from "./chunk-VXL2LBPK.js";
79
84
  import {
80
85
  juniorDestinations
81
86
  } from "./chunk-VFUK3X5B.js";
87
+ import {
88
+ getSlackBotToken
89
+ } from "./chunk-AD64YMEC.js";
82
90
  import {
83
91
  canExposeConversationPayload
84
- } from "./chunk-EIJCPJOY.js";
92
+ } from "./chunk-FFYDRLXW.js";
85
93
  import {
86
94
  credentialContextForActor
87
95
  } from "./chunk-CEMMLV5L.js";
88
96
  import {
89
97
  logException,
98
+ logWarn,
90
99
  setTags,
91
100
  withLogContext
92
- } from "./chunk-OMQ2J6F6.js";
101
+ } from "./chunk-3CVEE6LA.js";
93
102
 
94
103
  // src/handlers/health.ts
95
104
  function readHealthReport() {
@@ -179,11 +188,33 @@ function parseApiTurnMessages(messages) {
179
188
  return { message: entry.message, metadata: entry.metadata.data };
180
189
  });
181
190
  }
191
+ function parseLocalResourceEventMessages(messages) {
192
+ if (messages.length === 0) {
193
+ return [];
194
+ }
195
+ if (!messages.every(
196
+ (message) => message.source === "resource_event" && isResourceEventMailboxMetadata(message.input.metadata)
197
+ )) {
198
+ return [];
199
+ }
200
+ return messages.map((message) => ({
201
+ message,
202
+ kind: "resource_event"
203
+ }));
204
+ }
182
205
  async function resolveApiTurnWork(context) {
183
206
  const batch = parseApiTurnMessages(context.attempt.messages);
184
207
  if (batch.length > 0) {
185
208
  return { kind: "mailbox", batch };
186
209
  }
210
+ if (context.destination?.platform === "local") {
211
+ const resourceBatch = parseLocalResourceEventMessages(
212
+ context.attempt.messages
213
+ );
214
+ if (resourceBatch.length > 0) {
215
+ return { kind: "resource_event", batch: resourceBatch };
216
+ }
217
+ }
187
218
  if (context.attempt.messages.length > 0) {
188
219
  return void 0;
189
220
  }
@@ -197,6 +228,7 @@ async function isApiTurnWork(context) {
197
228
  // src/chat/api-turns/work.ts
198
229
  import { createHash } from "crypto";
199
230
  import {
231
+ createLocalSource,
200
232
  createWebSource,
201
233
  localDestinationSchema
202
234
  } from "@sentry/junior-plugin-api";
@@ -329,6 +361,19 @@ async function completeCancelledApiTurn(args) {
329
361
  await args.acknowledge();
330
362
  }
331
363
 
364
+ // src/chat/api-turns/mailbox-input.ts
365
+ function joinMailboxText(messages) {
366
+ return messages.map((message) => message.input.text.trim()).filter(Boolean).join("\n\n");
367
+ }
368
+ function localResourceEventActor() {
369
+ return {
370
+ platform: "local",
371
+ userId: RESOURCE_EVENT_AUTHOR_ID,
372
+ userName: "junior-event",
373
+ fullName: "Junior event"
374
+ };
375
+ }
376
+
332
377
  // src/chat/api-turns/work.ts
333
378
  function normalizeEmail(email) {
334
379
  return email.trim().toLowerCase();
@@ -557,51 +602,80 @@ function createApiTurnWorker(agentRunner, cancellation) {
557
602
  getConversationEventStore()
558
603
  );
559
604
  const isResume = resolved.kind === "resume";
605
+ let isResourceEvent = resolved.kind === "resource_event";
560
606
  let actor;
561
- let text;
562
- let turnId;
563
- let userMessageId;
564
- let startedAtMs;
565
- let inputMessageIds;
607
+ let text = "";
608
+ let turnId = "";
609
+ let userMessageId = "";
610
+ let startedAtMs = Date.now();
611
+ let inputMessageIds = [];
566
612
  const storedConversation = await getConversationStore().get({
567
613
  conversationId: context.conversationId
568
614
  });
615
+ const mailboxDestination = resolved.kind === "mailbox" || resolved.kind === "resource_event" ? resolved.batch[0]?.message.destination : void 0;
616
+ const destination = resolveApiTurnDestination({
617
+ conversationId: context.conversationId,
618
+ existing: context.destination ?? mailboxDestination ?? storedConversation?.destination
619
+ });
620
+ const sourceFor = (resourceEvent) => resourceEvent ? createLocalSource(context.conversationId) : webSourceForConversation({
621
+ conversationId: context.conversationId,
622
+ visibility: storedConversation?.visibility
623
+ });
624
+ let source = sourceFor(isResourceEvent);
569
625
  if (resolved.kind === "mailbox") {
570
626
  const first = resolved.batch[0];
571
- text = resolved.batch.map((entry) => entry.message.input.text.trim()).filter(Boolean).join("\n\n");
627
+ text = joinMailboxText(resolved.batch.map((entry) => entry.message));
572
628
  actor = actorFromMetadata(first.metadata);
573
629
  turnId = apiTurnIdForMessage(first.metadata.messageId);
574
630
  userMessageId = first.metadata.messageId;
575
631
  startedAtMs = first.message.createdAtMs;
576
632
  inputMessageIds = resolved.batch.map((entry) => entry.metadata.messageId);
633
+ } else if (resolved.kind === "resource_event") {
634
+ const first = resolved.batch[0];
635
+ text = joinMailboxText(resolved.batch.map((entry) => entry.message));
636
+ actor = localResourceEventActor();
637
+ turnId = apiTurnIdForMessage(first.message.inboundMessageId);
638
+ userMessageId = first.message.inboundMessageId;
639
+ startedAtMs = first.message.createdAtMs;
640
+ inputMessageIds = resolved.batch.map(
641
+ (entry) => entry.message.inboundMessageId
642
+ );
577
643
  } else {
578
644
  turnId = resolved.turnId;
579
- const resumedActor = actorFromStoredConversation(
580
- storedConversation?.actor
581
- );
582
- if (!resumedActor) {
645
+ actor = actorFromStoredConversation(storedConversation?.actor);
646
+ }
647
+ const persisted = await getPersistedThreadState(context.conversationId);
648
+ const conversation = coerceThreadConversationState(persisted);
649
+ await hydrateConversationMessages({
650
+ conversation,
651
+ conversationId: context.conversationId
652
+ });
653
+ if (isResume) {
654
+ const userMessage = getTurnUserMessage(conversation, turnId);
655
+ if (!userMessage) {
583
656
  throw new Error(
584
- `Conversation API resume missing actor for ${context.conversationId}`
657
+ `Unable to locate the persisted user message for Turn "${turnId}"`
585
658
  );
586
659
  }
587
- actor = resumedActor;
588
- text = "";
589
- userMessageId = "";
590
- startedAtMs = Date.now();
591
- inputMessageIds = [];
660
+ if (isResourceEventConversationMessage(userMessage)) {
661
+ isResourceEvent = true;
662
+ actor = localResourceEventActor();
663
+ source = sourceFor(true);
664
+ }
665
+ userMessageId = userMessage.id;
666
+ text = userMessage.text;
667
+ startedAtMs = userMessage.createdAtMs;
668
+ inputMessageIds = [userMessageId];
669
+ }
670
+ if (!actor) {
671
+ throw new Error(
672
+ `Conversation API resume missing actor for ${context.conversationId}`
673
+ );
592
674
  }
593
- const destination = resolveApiTurnDestination({
594
- conversationId: context.conversationId,
595
- existing: context.destination ?? (resolved.kind === "mailbox" ? resolved.batch[0]?.message.destination : void 0) ?? storedConversation?.destination
596
- });
597
- const source = webSourceForConversation({
598
- conversationId: context.conversationId,
599
- visibility: storedConversation?.visibility
600
- });
601
675
  return await withLogContext(
602
676
  {
603
677
  conversationId: context.conversationId,
604
- platform: "web",
678
+ platform: isResourceEvent ? "local" : "web",
605
679
  userId: actor.userId,
606
680
  ...actor.userName ? { userName: actor.userName } : void 0
607
681
  },
@@ -620,12 +694,6 @@ function createApiTurnWorker(agentRunner, cancellation) {
620
694
  }
621
695
  acknowledged = true;
622
696
  };
623
- const persisted = await getPersistedThreadState(context.conversationId);
624
- const conversation = coerceThreadConversationState(persisted);
625
- await hydrateConversationMessages({
626
- conversation,
627
- conversationId: context.conversationId
628
- });
629
697
  let sandboxRef = getPersistedSandboxState(persisted);
630
698
  const initialSandboxRef = sandboxRef;
631
699
  const appSignal = cancellation?.signal(context.conversationId);
@@ -658,16 +726,6 @@ function createApiTurnWorker(agentRunner, cancellation) {
658
726
  return { status: "completed" };
659
727
  };
660
728
  if (isResume) {
661
- const userMessage = getTurnUserMessage(conversation, turnId);
662
- if (!userMessage) {
663
- throw new Error(
664
- `Unable to locate the persisted user message for Turn "${turnId}"`
665
- );
666
- }
667
- userMessageId = userMessage.id;
668
- text = userMessage.text;
669
- startedAtMs = userMessage.createdAtMs;
670
- inputMessageIds = [userMessageId];
671
729
  if (cancellationSignal?.aborted) {
672
730
  return await completeCancelledTurn();
673
731
  }
@@ -686,7 +744,7 @@ function createApiTurnWorker(agentRunner, cancellation) {
686
744
  meta: {
687
745
  explicitMention: true,
688
746
  replied: false,
689
- source: "web"
747
+ ...isResourceEvent ? void 0 : { source: "web" }
690
748
  }
691
749
  });
692
750
  await persistConversationMessages({
@@ -1227,6 +1285,91 @@ async function readConversationAccessFromSql(db, conversationIds, viewer) {
1227
1285
  );
1228
1286
  }
1229
1287
 
1288
+ // src/chat/slack/user.ts
1289
+ import { z as z2 } from "zod";
1290
+ var slackUserInfoSchema = z2.object({
1291
+ ok: z2.literal(true),
1292
+ user: z2.object({
1293
+ name: z2.string().nullish(),
1294
+ profile: z2.object({
1295
+ email: z2.string().nullish(),
1296
+ real_name: z2.string().nullish()
1297
+ }).optional()
1298
+ })
1299
+ });
1300
+ var USER_CACHE_TTL_MS = 5 * 60 * 1e3;
1301
+ var userCache = /* @__PURE__ */ new Map();
1302
+ function userCacheKey(teamId, userId) {
1303
+ return `${teamId}:${userId}`;
1304
+ }
1305
+ function readFromCache(teamId, userId) {
1306
+ const hit = userCache.get(userCacheKey(teamId, userId));
1307
+ if (!hit) return null;
1308
+ if (hit.expiresAt < Date.now()) {
1309
+ userCache.delete(userCacheKey(teamId, userId));
1310
+ return null;
1311
+ }
1312
+ return hit.value;
1313
+ }
1314
+ function writeToCache(teamId, userId, value) {
1315
+ userCache.set(userCacheKey(teamId, userId), {
1316
+ value,
1317
+ expiresAt: Date.now() + USER_CACHE_TTL_MS
1318
+ });
1319
+ }
1320
+ async function lookupSlackUser(teamId, userId) {
1321
+ if (!teamId || !userId) {
1322
+ return null;
1323
+ }
1324
+ const cached = readFromCache(teamId, userId);
1325
+ if (cached) {
1326
+ return cached;
1327
+ }
1328
+ const token = getSlackBotToken();
1329
+ if (!token) {
1330
+ return null;
1331
+ }
1332
+ try {
1333
+ const response = await fetch(
1334
+ `https://slack.com/api/users.info?user=${encodeURIComponent(userId)}`,
1335
+ {
1336
+ headers: {
1337
+ authorization: `Bearer ${token}`
1338
+ }
1339
+ }
1340
+ );
1341
+ if (!response.ok) {
1342
+ logWarn("slack.user.lookup.failed", {
1343
+ "enduser.id": userId,
1344
+ "app.slack.team_id": teamId,
1345
+ "http.response.status_code": response.status
1346
+ });
1347
+ return null;
1348
+ }
1349
+ const parsed = slackUserInfoSchema.safeParse(await response.json());
1350
+ if (!parsed.success) {
1351
+ return null;
1352
+ }
1353
+ const payload = parsed.data;
1354
+ const userName = payload.user.name?.trim() || void 0;
1355
+ const fullName = payload.user.profile?.real_name?.trim() || void 0;
1356
+ const result = {
1357
+ userName,
1358
+ fullName,
1359
+ email: payload.user.profile?.email?.trim() || void 0
1360
+ };
1361
+ writeToCache(teamId, userId, result);
1362
+ return result;
1363
+ } catch (error) {
1364
+ logWarn("slack.user.lookup.failed", {
1365
+ "enduser.id": userId,
1366
+ "app.slack.team_id": teamId,
1367
+ "exception.message": error instanceof Error ? error.message : String(error)
1368
+ });
1369
+ return null;
1370
+ }
1371
+ }
1372
+
1230
1373
  // src/chat/slack/conversation-context.ts
1231
1374
  function normalizeConversationName(type, channelName) {
1232
1375
  const trimmed = channelName?.trim();
@@ -1315,6 +1458,7 @@ export {
1315
1458
  readHealthReport,
1316
1459
  GET,
1317
1460
  createVercelAttachmentStorage,
1461
+ lookupSlackUser,
1318
1462
  conversationVisibilityFromSlackChannelType,
1319
1463
  resolveSlackChannelTypeFromMessage,
1320
1464
  resolveSlackConversationContext,
@@ -6,10 +6,10 @@ import {
6
6
  } from "./chunk-7H2VZTWN.js";
7
7
  import {
8
8
  runWithTurnRequestDeadline
9
- } from "./chunk-FTVMXDNN.js";
9
+ } from "./chunk-BRKB5R7P.js";
10
10
  import {
11
11
  logWarn
12
- } from "./chunk-OMQ2J6F6.js";
12
+ } from "./chunk-3CVEE6LA.js";
13
13
 
14
14
  // src/chat/plugins/task-queue.ts
15
15
  import { createHash } from "crypto";
@@ -129,7 +129,7 @@ function pluginTaskCallback() {
129
129
  onRejected: logPluginTaskQueueMessageRejected,
130
130
  // Load the runner on first use so this module can send without a cycle.
131
131
  run: async (message) => {
132
- const { processPluginTask } = await import("./task-runner-5JG3VIIY.js");
132
+ const { processPluginTask } = await import("./task-runner-IQNBA3RY.js");
133
133
  await processPluginTask(message);
134
134
  },
135
135
  topic: PLUGIN_TASK_QUEUE_TOPIC,
@@ -7,7 +7,7 @@ import {
7
7
  toCanonicalInputMessage,
8
8
  toCanonicalOutputMessage,
9
9
  toGenAiMessagesTraceAttributes
10
- } from "./chunk-EIJCPJOY.js";
10
+ } from "./chunk-FFYDRLXW.js";
11
11
  import {
12
12
  extractGenAiUsageAttributes,
13
13
  logException,
@@ -15,7 +15,7 @@ import {
15
15
  normalizeGenAiFinishReason,
16
16
  serializeGenAiAttribute,
17
17
  withSpan
18
- } from "./chunk-OMQ2J6F6.js";
18
+ } from "./chunk-3CVEE6LA.js";
19
19
 
20
20
  // src/chat/services/provider-error.ts
21
21
  var ProviderError = class extends Error {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
3
3
  getChatConfig
4
- } from "./chunk-LRI5IRGY.js";
4
+ } from "./chunk-AD64YMEC.js";
5
5
 
6
6
  // src/chat/runtime/request-deadline.ts
7
7
  import { AsyncLocalStorage } from "async_hooks";
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  persistConversationMessages
3
- } from "./chunk-WLKWN4CD.js";
3
+ } from "./chunk-H7X2G2KS.js";
4
4
  import {
5
5
  JUNIOR_THREAD_STATE_TTL_MS
6
6
  } from "./chunk-3Y47VMHV.js";
7
7
  import {
8
8
  getDb
9
- } from "./chunk-ABAX75GG.js";
9
+ } from "./chunk-43LODHJM.js";
10
10
  import {
11
11
  juniorLocationConfigurations
12
- } from "./chunk-LVK4WJKM.js";
12
+ } from "./chunk-VXL2LBPK.js";
13
13
  import {
14
14
  getStateAdapter
15
- } from "./chunk-PNYJOEVV.js";
15
+ } from "./chunk-DOP3FIQC.js";
16
16
  import {
17
17
  juniorDestinations
18
18
  } from "./chunk-VFUK3X5B.js";
@@ -20,7 +20,7 @@ import {
20
20
  isRecord,
21
21
  toOptionalNumber,
22
22
  toOptionalString
23
- } from "./chunk-OMQ2J6F6.js";
23
+ } from "./chunk-3CVEE6LA.js";
24
24
 
25
25
  // src/chat/state/conversation.ts
26
26
  function defaultConversationState() {
@@ -6,14 +6,14 @@ import {
6
6
  isStale,
7
7
  runNonInteractiveCommand,
8
8
  sleep
9
- } from "./chunk-EJYP3NQ4.js";
9
+ } from "./chunk-HWXP6RHG.js";
10
10
  import {
11
11
  getStateAdapter
12
- } from "./chunk-PNYJOEVV.js";
12
+ } from "./chunk-DOP3FIQC.js";
13
13
  import {
14
14
  setSpanAttributes,
15
15
  withSpan
16
- } from "./chunk-OMQ2J6F6.js";
16
+ } from "./chunk-3CVEE6LA.js";
17
17
 
18
18
  // src/chat/sandbox/resources.ts
19
19
  var configuredResources;