@sentry/junior 0.107.0 → 0.108.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 (28) hide show
  1. package/dist/{agent-hooks-ICPIJAFY.js → agent-hooks-NU5HK3PS.js} +4 -4
  2. package/dist/api/conversations/list.d.ts +1 -0
  3. package/dist/api.js +11 -8
  4. package/dist/app.js +270 -48
  5. package/dist/chat/conversations/history.d.ts +16 -5
  6. package/dist/chat/conversations/message-projection.d.ts +3 -5
  7. package/dist/chat/resource-events/store.d.ts +6 -0
  8. package/dist/chat/runtime/slack-runtime.d.ts +3 -0
  9. package/dist/chat/task-execution/slack-work.d.ts +237 -10
  10. package/dist/chat/tool-support/turn-deadline-result.d.ts +3 -0
  11. package/dist/{chunk-YFQ7CQDE.js → chunk-3RGQLX2F.js} +10 -16
  12. package/dist/{chunk-CQ7KSO2B.js → chunk-A5CO2EHL.js} +6 -6
  13. package/dist/{chunk-AUUOHQAT.js → chunk-AHJR2IFF.js} +1 -1
  14. package/dist/{chunk-SPUAJVVH.js → chunk-B5I5LMSP.js} +1 -1
  15. package/dist/{chunk-B2Z2H66D.js → chunk-H3QYZL7K.js} +32 -2
  16. package/dist/{chunk-4YF7Z6IA.js → chunk-J3B3FPP2.js} +2 -2
  17. package/dist/{chunk-EDLNHZH3.js → chunk-KPMPQ6AA.js} +143 -98
  18. package/dist/{chunk-NVOTGWYX.js → chunk-TE4QHJH4.js} +25 -10
  19. package/dist/{chunk-YNP2ATQX.js → chunk-TWINAEZQ.js} +6 -5
  20. package/dist/{chunk-RMVOAJRL.js → chunk-UD6THJ2I.js} +2 -2
  21. package/dist/{chunk-IGHMVDWI.js → chunk-XKB7LGIW.js} +1 -1
  22. package/dist/cli/chat.js +11 -11
  23. package/dist/cli/plugins.js +4 -4
  24. package/dist/cli/snapshot-warmup.js +2 -2
  25. package/dist/cli/upgrade.js +6 -11
  26. package/dist/{db-DIGO4TGW.js → db-AMRBAT5D.js} +1 -1
  27. package/dist/{runner-ACR2HAIC.js → runner-TQH5GAJ4.js} +7 -7
  28. package/package.json +7 -7
@@ -11,12 +11,12 @@ import {
11
11
  getPlugins,
12
12
  setPlugins,
13
13
  validatePlugins
14
- } from "./chunk-RMVOAJRL.js";
15
- import "./chunk-AUUOHQAT.js";
14
+ } from "./chunk-UD6THJ2I.js";
15
+ import "./chunk-AHJR2IFF.js";
16
16
  import "./chunk-G3E7SCME.js";
17
- import "./chunk-B2Z2H66D.js";
17
+ import "./chunk-H3QYZL7K.js";
18
18
  import "./chunk-VH6KWKG2.js";
19
- import "./chunk-NVOTGWYX.js";
19
+ import "./chunk-TE4QHJH4.js";
20
20
  import "./chunk-4ZNGQH7C.js";
21
21
  import "./chunk-SS67LUOK.js";
22
22
  import "./chunk-VFUK3X5B.js";
@@ -84,6 +84,7 @@ declare function conversationRows(db: JuniorDatabase, limit: number, actorEmail?
84
84
  identityProvider: string | null;
85
85
  identitySubjectId: string | null;
86
86
  identityTenantId: string | null;
87
+ userDisplayName: string | null;
87
88
  }[]>;
88
89
  type ConversationRow = Awaited<ReturnType<typeof conversationRows>>[number];
89
90
  /** Read one normalized conversation record directly from its SQL row. */
package/dist/api.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  readConversationEventPrivacySnapshot,
20
20
  readHealthReport,
21
21
  resolveSlackConversationContextFromThreadId
22
- } from "./chunk-IGHMVDWI.js";
22
+ } from "./chunk-XKB7LGIW.js";
23
23
  import {
24
24
  pluginOperationalReportFeedSchema,
25
25
  pluginReportsSchema,
@@ -40,7 +40,7 @@ import {
40
40
  juniorConversations,
41
41
  juniorIdentities,
42
42
  juniorUsers
43
- } from "./chunk-NVOTGWYX.js";
43
+ } from "./chunk-TE4QHJH4.js";
44
44
  import "./chunk-4ZNGQH7C.js";
45
45
  import "./chunk-SS67LUOK.js";
46
46
  import {
@@ -516,14 +516,15 @@ async function conversationRows(db, limit, actorEmail) {
516
516
  identityHandle: juniorIdentities.handle,
517
517
  identityProvider: juniorIdentities.provider,
518
518
  identitySubjectId: juniorIdentities.providerSubjectId,
519
- identityTenantId: juniorIdentities.providerTenantId
519
+ identityTenantId: juniorIdentities.providerTenantId,
520
+ userDisplayName: juniorUsers.displayName
520
521
  }).from(juniorConversations).leftJoin(
521
522
  juniorDestinations,
522
523
  eq3(juniorDestinations.id, juniorConversations.destinationId)
523
524
  ).leftJoin(
524
525
  juniorIdentities,
525
526
  eq3(juniorIdentities.id, juniorConversations.actorIdentityId)
526
- ).where(
527
+ ).leftJoin(juniorUsers, eq3(juniorUsers.id, juniorIdentities.userId)).where(
527
528
  and3(
528
529
  isNull(juniorConversations.parentConversationId),
529
530
  isNull(juniorConversations.archivedAt),
@@ -539,10 +540,11 @@ async function conversationRows(db, limit, actorEmail) {
539
540
  }
540
541
  function conversationFromRow(row) {
541
542
  const value = row.conversation;
543
+ const actorFullName = row.userDisplayName?.trim() ? row.userDisplayName : row.identityDisplayName;
542
544
  const actor = row.identityProvider === "slack" ? {
543
545
  platform: "slack",
544
546
  ...row.identityEmail ? { email: row.identityEmail } : {},
545
- ...row.identityDisplayName ? { fullName: row.identityDisplayName } : {},
547
+ ...actorFullName ? { fullName: actorFullName } : {},
546
548
  ...row.identitySubjectId ? { slackUserId: row.identitySubjectId } : {},
547
549
  ...row.identityHandle ? { slackUserName: row.identityHandle } : {},
548
550
  ...row.identityTenantId ? { teamId: row.identityTenantId } : {}
@@ -580,14 +582,15 @@ async function readConversationRecordFromSql(conversationId) {
580
582
  identityHandle: juniorIdentities.handle,
581
583
  identityProvider: juniorIdentities.provider,
582
584
  identitySubjectId: juniorIdentities.providerSubjectId,
583
- identityTenantId: juniorIdentities.providerTenantId
585
+ identityTenantId: juniorIdentities.providerTenantId,
586
+ userDisplayName: juniorUsers.displayName
584
587
  }).from(juniorConversations).leftJoin(
585
588
  juniorDestinations,
586
589
  eq3(juniorDestinations.id, juniorConversations.destinationId)
587
590
  ).leftJoin(
588
591
  juniorIdentities,
589
592
  eq3(juniorIdentities.id, juniorConversations.actorIdentityId)
590
- ).where(eq3(juniorConversations.conversationId, conversationId)).limit(1);
593
+ ).leftJoin(juniorUsers, eq3(juniorUsers.id, juniorIdentities.userId)).where(eq3(juniorConversations.conversationId, conversationId)).limit(1);
591
594
  const row = rows[0];
592
595
  return row ? {
593
596
  conversation: conversationFromRow(row),
@@ -1848,7 +1851,7 @@ async function readRuntimeInfoReport() {
1848
1851
  }
1849
1852
  async function readPluginOperationalReportFeed() {
1850
1853
  const nowMs = Date.now();
1851
- const { getPluginOperationalReports } = await import("./agent-hooks-ICPIJAFY.js");
1854
+ const { getPluginOperationalReports } = await import("./agent-hooks-NU5HK3PS.js");
1852
1855
  return pluginOperationalReportFeedSchema.parse({
1853
1856
  source: "plugins",
1854
1857
  generatedAt: new Date(nowMs).toISOString(),
package/dist/app.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  processPluginTask,
7
7
  requireTurnFailureEventId,
8
8
  scheduleSessionCompletedPluginTasks
9
- } from "./chunk-CQ7KSO2B.js";
9
+ } from "./chunk-A5CO2EHL.js";
10
10
  import {
11
11
  CONVERSATION_WORK_CHECK_IN_INTERVAL_MS,
12
12
  CONVERSATION_WORK_STALE_ENQUEUE_MS,
@@ -30,7 +30,7 @@ import {
30
30
  requestConversationContinuation,
31
31
  requestConversationWork,
32
32
  startConversationWork
33
- } from "./chunk-YNP2ATQX.js";
33
+ } from "./chunk-TWINAEZQ.js";
34
34
  import {
35
35
  GET,
36
36
  buildSentryConversationUrl,
@@ -38,7 +38,7 @@ import {
38
38
  resolveRootVisibility,
39
39
  resolveSlackChannelTypeFromMessage,
40
40
  resolveSlackConversationContext
41
- } from "./chunk-IGHMVDWI.js";
41
+ } from "./chunk-XKB7LGIW.js";
42
42
  import "./chunk-CEA3A3UA.js";
43
43
  import {
44
44
  getVercelConversationWorkQueue,
@@ -69,6 +69,7 @@ import {
69
69
  appendSlackLegacyAttachmentText,
70
70
  buildSlackOutputMessage,
71
71
  buildSteeringPiMessage,
72
+ cancelSubscriptions,
72
73
  createAgentRunner,
73
74
  createContextCompactor,
74
75
  createUserTokenStore,
@@ -105,7 +106,7 @@ import {
105
106
  splitSlackReplyText,
106
107
  startOAuthFlow,
107
108
  truncateStatusText
108
- } from "./chunk-EDLNHZH3.js";
109
+ } from "./chunk-KPMPQ6AA.js";
109
110
  import {
110
111
  ConversationTurnBoundaryError,
111
112
  CooperativeTurnYieldError,
@@ -152,7 +153,7 @@ import {
152
153
  turnHasReply,
153
154
  updateConversationStats,
154
155
  upsertConversationMessage
155
- } from "./chunk-YFQ7CQDE.js";
156
+ } from "./chunk-3RGQLX2F.js";
156
157
  import {
157
158
  JUNIOR_THREAD_STATE_TTL_MS,
158
159
  abandonAgentTurnSessionRecord,
@@ -166,8 +167,8 @@ import {
166
167
  loadProjection,
167
168
  recordAgentTurnSessionSummary,
168
169
  recordAuthorizationCompleted
169
- } from "./chunk-4YF7Z6IA.js";
170
- import "./chunk-SPUAJVVH.js";
170
+ } from "./chunk-J3B3FPP2.js";
171
+ import "./chunk-B5I5LMSP.js";
171
172
  import "./chunk-MU6HHZEN.js";
172
173
  import "./chunk-PDO5BLNM.js";
173
174
  import "./chunk-UIE3R5XU.js";
@@ -184,16 +185,16 @@ import {
184
185
  validatePlugins,
185
186
  verifyScheduledTaskCredentialSubject,
186
187
  verifySlackDirectCredentialSubject
187
- } from "./chunk-RMVOAJRL.js";
188
+ } from "./chunk-UD6THJ2I.js";
188
189
  import {
189
190
  createPluginLogger,
190
191
  createPluginState
191
- } from "./chunk-AUUOHQAT.js";
192
+ } from "./chunk-AHJR2IFF.js";
192
193
  import "./chunk-G3E7SCME.js";
193
194
  import {
194
195
  acquireActiveLock,
195
196
  getStateAdapter
196
- } from "./chunk-B2Z2H66D.js";
197
+ } from "./chunk-H3QYZL7K.js";
197
198
  import {
198
199
  SlackActionError,
199
200
  downloadPrivateSlackFile,
@@ -215,7 +216,7 @@ import {
215
216
  juniorConversationEvents,
216
217
  juniorConversations,
217
218
  withConversationEventLock
218
- } from "./chunk-NVOTGWYX.js";
219
+ } from "./chunk-TE4QHJH4.js";
219
220
  import {
220
221
  sleep
221
222
  } from "./chunk-4ZNGQH7C.js";
@@ -583,6 +584,7 @@ var DEFAULT_MAX_ATTEMPTS = 5;
583
584
  var nonEmptyExactStringSchema = z.string().min(1).refine(
584
585
  (value) => value === value.trim() && value.toLowerCase() !== "unknown"
585
586
  );
587
+ var incompleteDispatchIndexSchema = z.array(nonEmptyExactStringSchema);
586
588
  var dispatchStatusSchema = z.enum([
587
589
  "pending",
588
590
  "running",
@@ -664,6 +666,9 @@ function incompleteDispatchIndexKey() {
664
666
  function incompleteDispatchIndexLockKey() {
665
667
  return `${DISPATCH_PREFIX}:incomplete:lock`;
666
668
  }
669
+ function parseIncompleteDispatchIndex(value) {
670
+ return value === void 0 || value === null ? [] : incompleteDispatchIndexSchema.parse(value);
671
+ }
667
672
  function dispatchLockKey(id) {
668
673
  return `${DISPATCH_PREFIX}:lock:${id}`;
669
674
  }
@@ -736,9 +741,12 @@ async function withIncompleteDispatchIndexLock(state, callback) {
736
741
  }
737
742
  async function syncIncompleteDispatchIndex(state, record) {
738
743
  await withIncompleteDispatchIndexLock(state, async () => {
739
- const existing = await state.get(incompleteDispatchIndexKey()) ?? [];
740
744
  const ids = [
741
- ...new Set(existing.filter((id) => typeof id === "string"))
745
+ ...new Set(
746
+ parseIncompleteDispatchIndex(
747
+ await state.get(incompleteDispatchIndexKey())
748
+ )
749
+ )
742
750
  ];
743
751
  const next = isTerminalDispatchStatus(record.status) ? ids.filter((id) => id !== record.id) : ids.includes(record.id) ? ids : [...ids, record.id];
744
752
  if (next.length === ids.length && next.every((id, index) => id === ids[index])) {
@@ -815,8 +823,13 @@ async function updateDispatchRecord(state, record) {
815
823
  async function listIncompleteDispatchIds() {
816
824
  const state = getStateAdapter();
817
825
  await state.connect();
818
- const ids = await state.get(incompleteDispatchIndexKey()) ?? [];
819
- return [...new Set(ids.filter((id) => typeof id === "string"))];
826
+ return [
827
+ ...new Set(
828
+ parseIncompleteDispatchIndex(
829
+ await state.get(incompleteDispatchIndexKey())
830
+ )
831
+ )
832
+ ];
820
833
  }
821
834
  async function getPluginDispatchProjection(args) {
822
835
  const record = await getDispatchRecord(args.id);
@@ -5188,6 +5201,7 @@ import {
5188
5201
  Message,
5189
5202
  ThreadImpl
5190
5203
  } from "chat";
5204
+ import { z as z3 } from "zod";
5191
5205
 
5192
5206
  // src/chat/ingress/message-router.ts
5193
5207
  function normalizeIncomingSlackThreadId(threadId, message) {
@@ -5453,6 +5467,211 @@ async function lookupSlackUser(teamId, userId) {
5453
5467
  }
5454
5468
 
5455
5469
  // src/chat/task-execution/slack-work.ts
5470
+ var slackConversationRouteSchema = z3.enum(["mention", "subscribed"]);
5471
+ var serializedDateSchema = z3.iso.datetime();
5472
+ var mdastPointSchema = z3.object({
5473
+ column: z3.number().int().positive(),
5474
+ line: z3.number().int().positive(),
5475
+ offset: z3.number().int().nonnegative().optional()
5476
+ }).strict();
5477
+ var mdastPositionSchema = z3.object({
5478
+ end: mdastPointSchema,
5479
+ start: mdastPointSchema
5480
+ }).strict();
5481
+ function isOptionalNullableString(value) {
5482
+ return value === void 0 || value === null || typeof value === "string";
5483
+ }
5484
+ function isOptionalNullableBoolean(value) {
5485
+ return value === void 0 || value === null || typeof value === "boolean";
5486
+ }
5487
+ function hasValidMdastBase(node, fields) {
5488
+ const allowed = /* @__PURE__ */ new Set(["data", "position", "type", ...fields]);
5489
+ return Object.keys(node).every((key) => allowed.has(key)) && (node.data === void 0 || typeof node.data === "object" && node.data !== null && !Array.isArray(node.data)) && (node.position === void 0 || mdastPositionSchema.safeParse(node.position).success);
5490
+ }
5491
+ var mdastPhrasingTypes = /* @__PURE__ */ new Set([
5492
+ "break",
5493
+ "delete",
5494
+ "emphasis",
5495
+ "footnoteReference",
5496
+ "html",
5497
+ "image",
5498
+ "imageReference",
5499
+ "inlineCode",
5500
+ "link",
5501
+ "linkReference",
5502
+ "strong",
5503
+ "text"
5504
+ ]);
5505
+ var mdastBlockOrDefinitionTypes = /* @__PURE__ */ new Set([
5506
+ "blockquote",
5507
+ "code",
5508
+ "definition",
5509
+ "footnoteDefinition",
5510
+ "heading",
5511
+ "html",
5512
+ "list",
5513
+ "paragraph",
5514
+ "table",
5515
+ "thematicBreak"
5516
+ ]);
5517
+ var mdastListItemTypes = /* @__PURE__ */ new Set(["listItem"]);
5518
+ var mdastTableCellTypes = /* @__PURE__ */ new Set(["tableCell"]);
5519
+ var mdastTableRowTypes = /* @__PURE__ */ new Set(["tableRow"]);
5520
+ function hasMdastChildren(node, allowedTypes) {
5521
+ return Array.isArray(node.children) && node.children.every(
5522
+ (child) => isFormattedContentNode(child) && (!allowedTypes || typeof child === "object" && child !== null && !Array.isArray(child) && allowedTypes.has(String(child.type)))
5523
+ );
5524
+ }
5525
+ function isFormattedContentNode(value) {
5526
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
5527
+ return false;
5528
+ }
5529
+ const node = value;
5530
+ switch (node.type) {
5531
+ case "break":
5532
+ case "thematicBreak":
5533
+ return hasValidMdastBase(node, []);
5534
+ case "html":
5535
+ case "inlineCode":
5536
+ case "text":
5537
+ case "yaml":
5538
+ return hasValidMdastBase(node, ["value"]) && typeof node.value === "string";
5539
+ case "code":
5540
+ return hasValidMdastBase(node, ["lang", "meta", "value"]) && typeof node.value === "string" && isOptionalNullableString(node.lang) && isOptionalNullableString(node.meta);
5541
+ case "delete":
5542
+ case "emphasis":
5543
+ case "paragraph":
5544
+ case "strong":
5545
+ case "tableCell":
5546
+ return hasValidMdastBase(node, ["children"]) && hasMdastChildren(node, mdastPhrasingTypes);
5547
+ case "blockquote":
5548
+ return hasValidMdastBase(node, ["children"]) && hasMdastChildren(node, mdastBlockOrDefinitionTypes);
5549
+ case "tableRow":
5550
+ return hasValidMdastBase(node, ["children"]) && hasMdastChildren(node, mdastTableCellTypes);
5551
+ case "heading":
5552
+ return hasValidMdastBase(node, ["children", "depth"]) && hasMdastChildren(node, mdastPhrasingTypes) && Number.isInteger(node.depth) && Number(node.depth) >= 1 && Number(node.depth) <= 6;
5553
+ case "list":
5554
+ return hasValidMdastBase(node, ["children", "ordered", "spread", "start"]) && hasMdastChildren(node, mdastListItemTypes) && isOptionalNullableBoolean(node.ordered) && isOptionalNullableBoolean(node.spread) && (node.start === void 0 || node.start === null || typeof node.start === "number" && Number.isFinite(node.start));
5555
+ case "listItem":
5556
+ return hasValidMdastBase(node, ["checked", "children", "spread"]) && hasMdastChildren(node, mdastBlockOrDefinitionTypes) && isOptionalNullableBoolean(node.checked) && isOptionalNullableBoolean(node.spread);
5557
+ case "table":
5558
+ return hasValidMdastBase(node, ["align", "children"]) && hasMdastChildren(node, mdastTableRowTypes) && (node.align === void 0 || node.align === null || Array.isArray(node.align) && node.align.every(
5559
+ (align) => align === null || align === "center" || align === "left" || align === "right"
5560
+ ));
5561
+ case "definition":
5562
+ return hasValidMdastBase(node, ["identifier", "label", "title", "url"]) && typeof node.identifier === "string" && typeof node.url === "string" && isOptionalNullableString(node.label) && isOptionalNullableString(node.title);
5563
+ case "footnoteDefinition":
5564
+ return hasValidMdastBase(node, ["children", "identifier", "label"]) && hasMdastChildren(node, mdastBlockOrDefinitionTypes) && typeof node.identifier === "string" && isOptionalNullableString(node.label);
5565
+ case "footnoteReference":
5566
+ return hasValidMdastBase(node, ["identifier", "label"]) && typeof node.identifier === "string" && isOptionalNullableString(node.label);
5567
+ case "image":
5568
+ return hasValidMdastBase(node, ["alt", "title", "url"]) && typeof node.url === "string" && isOptionalNullableString(node.alt) && isOptionalNullableString(node.title);
5569
+ case "imageReference":
5570
+ return hasValidMdastBase(node, [
5571
+ "alt",
5572
+ "identifier",
5573
+ "label",
5574
+ "referenceType"
5575
+ ]) && typeof node.identifier === "string" && isOptionalNullableString(node.alt) && isOptionalNullableString(node.label) && (node.referenceType === "collapsed" || node.referenceType === "full" || node.referenceType === "shortcut");
5576
+ case "link":
5577
+ return hasValidMdastBase(node, ["children", "title", "url"]) && hasMdastChildren(node, mdastPhrasingTypes) && typeof node.url === "string" && isOptionalNullableString(node.title);
5578
+ case "linkReference":
5579
+ return hasValidMdastBase(node, [
5580
+ "children",
5581
+ "identifier",
5582
+ "label",
5583
+ "referenceType"
5584
+ ]) && hasMdastChildren(node, mdastPhrasingTypes) && typeof node.identifier === "string" && isOptionalNullableString(node.label) && (node.referenceType === "collapsed" || node.referenceType === "full" || node.referenceType === "shortcut");
5585
+ default:
5586
+ return false;
5587
+ }
5588
+ }
5589
+ var formattedContentSchema = z3.custom(
5590
+ (value) => {
5591
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
5592
+ return false;
5593
+ }
5594
+ const root = value;
5595
+ return root.type === "root" && hasValidMdastBase(root, ["children"]) && hasMdastChildren(root);
5596
+ },
5597
+ "must be a valid formatted-content root"
5598
+ );
5599
+ var serializedMessageSchema = z3.object({
5600
+ _type: z3.literal("chat:Message"),
5601
+ attachments: z3.array(
5602
+ z3.object({
5603
+ type: z3.enum(["image", "file", "video", "audio"]),
5604
+ url: z3.string().optional(),
5605
+ name: z3.string().optional(),
5606
+ mimeType: z3.string().optional(),
5607
+ size: z3.number().finite().optional(),
5608
+ width: z3.number().finite().optional(),
5609
+ height: z3.number().finite().optional(),
5610
+ fetchMetadata: z3.record(z3.string(), z3.string()).optional()
5611
+ }).strict()
5612
+ ),
5613
+ author: z3.object({
5614
+ userId: z3.string(),
5615
+ userName: z3.string(),
5616
+ fullName: z3.string(),
5617
+ isBot: z3.union([z3.boolean(), z3.literal("unknown")]),
5618
+ isMe: z3.boolean()
5619
+ }).strict(),
5620
+ formatted: formattedContentSchema,
5621
+ id: z3.string().min(1),
5622
+ isMention: z3.boolean().optional(),
5623
+ links: z3.array(
5624
+ z3.object({
5625
+ url: z3.string(),
5626
+ title: z3.string().optional(),
5627
+ description: z3.string().optional(),
5628
+ imageUrl: z3.string().optional(),
5629
+ siteName: z3.string().optional()
5630
+ }).strict()
5631
+ ).optional(),
5632
+ metadata: z3.object({
5633
+ dateSent: serializedDateSchema,
5634
+ edited: z3.boolean(),
5635
+ editedAt: serializedDateSchema.optional()
5636
+ }).strict(),
5637
+ raw: z3.unknown(),
5638
+ text: z3.string(),
5639
+ threadId: z3.string().min(1)
5640
+ }).strict();
5641
+ var serializedThreadSchema = z3.object({
5642
+ _type: z3.literal("chat:Thread"),
5643
+ adapterName: z3.literal("slack"),
5644
+ channelId: z3.string().min(1),
5645
+ channelVisibility: z3.enum(["private", "workspace", "external", "unknown"]).optional(),
5646
+ currentMessage: serializedMessageSchema.optional(),
5647
+ id: z3.string().min(1),
5648
+ isDM: z3.boolean()
5649
+ }).strict();
5650
+ var slackInstallationSchema = z3.object({
5651
+ enterpriseId: z3.string().optional(),
5652
+ isEnterpriseInstall: z3.boolean().optional(),
5653
+ teamId: z3.string().optional()
5654
+ }).strict();
5655
+ var slackConversationMessageMetadataBaseSchema = z3.object({
5656
+ installation: slackInstallationSchema.optional(),
5657
+ message: serializedMessageSchema,
5658
+ platform: z3.literal("slack"),
5659
+ route: slackConversationRouteSchema,
5660
+ thread: serializedThreadSchema
5661
+ });
5662
+ var slackConversationMessageMetadataSchema = z3.union([
5663
+ slackConversationMessageMetadataBaseSchema.strict(),
5664
+ slackConversationMessageMetadataBaseSchema.extend({
5665
+ kind: z3.literal("resource_event"),
5666
+ resourceEvent: z3.object({
5667
+ eventKey: z3.string(),
5668
+ eventType: z3.string(),
5669
+ provider: z3.string(),
5670
+ resourceRef: z3.string(),
5671
+ subscriptionId: z3.string()
5672
+ }).strict()
5673
+ }).strict()
5674
+ ]);
5456
5675
  function requireSlackAuthorId(message) {
5457
5676
  const authorId = parseActorUserId(message.author.userId);
5458
5677
  if (!authorId) {
@@ -5565,16 +5784,17 @@ function createSlackResourceEventInboundMessage(input) {
5565
5784
  function getConnectedState2(stateAdapter) {
5566
5785
  return stateAdapter ?? getStateAdapter();
5567
5786
  }
5568
- function isSlackMetadata(value) {
5569
- return Boolean(value) && value?.platform === "slack" && (value.route === "mention" || value.route === "subscribed") && Boolean(value.thread) && Boolean(value.message);
5787
+ function parseSlackMetadata(value) {
5788
+ const parsed = slackConversationMessageMetadataSchema.safeParse(value);
5789
+ return parsed.success ? parsed.data : void 0;
5570
5790
  }
5571
5791
  function compareInboundMessages(left, right) {
5572
5792
  return left.createdAtMs - right.createdAtMs || left.receivedAtMs - right.receivedAtMs || left.inboundMessageId.localeCompare(right.inboundMessageId);
5573
5793
  }
5574
5794
  function routeForRecords(records) {
5575
5795
  return records.some((record) => {
5576
- const metadata = record.input.metadata;
5577
- if (!isSlackMetadata(metadata)) {
5796
+ const metadata = parseSlackMetadata(record.input.metadata);
5797
+ if (!metadata) {
5578
5798
  throw new Error("Conversation mailbox record is not Slack metadata");
5579
5799
  }
5580
5800
  return metadata.route === "mention";
@@ -5589,8 +5809,8 @@ function isResourceEventNotificationMessage(message) {
5589
5809
  return raw?.event_type === "resource_event";
5590
5810
  }
5591
5811
  function restoreMessage(args) {
5592
- const metadata = args.record.input.metadata;
5593
- if (!isSlackMetadata(metadata)) {
5812
+ const metadata = parseSlackMetadata(args.record.input.metadata);
5813
+ if (!metadata) {
5594
5814
  throw new Error("Conversation mailbox record is not a Slack message");
5595
5815
  }
5596
5816
  const message = Message.fromJSON(metadata.message);
@@ -5646,8 +5866,8 @@ function restoreThread(args) {
5646
5866
  }
5647
5867
  function getInstallation(records) {
5648
5868
  for (let index = records.length - 1; index >= 0; index -= 1) {
5649
- const metadata = records[index]?.input.metadata;
5650
- if (isSlackMetadata(metadata) && metadata.installation) {
5869
+ const metadata = parseSlackMetadata(records[index]?.input.metadata);
5870
+ if (metadata?.installation) {
5651
5871
  return metadata.installation;
5652
5872
  }
5653
5873
  }
@@ -5687,8 +5907,8 @@ function createSlackConversationWorker(options) {
5687
5907
  if (!latestRecord) {
5688
5908
  return { status: "completed" };
5689
5909
  }
5690
- const latestMetadata = latestRecord.input.metadata;
5691
- if (!isSlackMetadata(latestMetadata)) {
5910
+ const latestMetadata = parseSlackMetadata(latestRecord.input.metadata);
5911
+ if (!latestMetadata) {
5692
5912
  throw new Error(
5693
5913
  "Latest conversation mailbox record is not Slack metadata"
5694
5914
  );
@@ -5747,8 +5967,8 @@ function createSlackConversationWorker(options) {
5747
5967
  const drainSteeringMessages = async (accept) => {
5748
5968
  await context.attempt.drain(async (pendingRecords) => {
5749
5969
  const messages2 = pendingRecords.map((record) => {
5750
- const metadata = record.input.metadata;
5751
- if (!isSlackMetadata(metadata)) {
5970
+ const metadata = parseSlackMetadata(record.input.metadata);
5971
+ if (!metadata) {
5752
5972
  throw new Error(
5753
5973
  "Conversation mailbox record is not Slack metadata"
5754
5974
  );
@@ -5832,7 +6052,7 @@ function buildSlackInboundMessage(args) {
5832
6052
  platform: "slack",
5833
6053
  route: args.route,
5834
6054
  installation: args.installation,
5835
- thread: args.thread.toJSON(),
6055
+ thread: serializedThreadSchema.parse(args.thread.toJSON()),
5836
6056
  message: args.message.toJSON()
5837
6057
  }
5838
6058
  }
@@ -7279,14 +7499,14 @@ function registerVercelPluginTaskDevConsumer() {
7279
7499
  }
7280
7500
 
7281
7501
  // src/chat/services/subscribed-decision.ts
7282
- import { z as z3 } from "zod";
7283
- var replyDecisionSchema = z3.object({
7284
- should_reply: z3.boolean().describe("Whether Junior should respond to this thread message."),
7285
- should_unsubscribe: z3.boolean().describe(
7502
+ import { z as z4 } from "zod";
7503
+ var replyDecisionSchema = z4.object({
7504
+ should_reply: z4.boolean().describe("Whether Junior should respond to this thread message."),
7505
+ should_unsubscribe: z4.boolean().describe(
7286
7506
  "Whether Junior should unsubscribe from this thread because the user clearly asked it to stop participating."
7287
7507
  ),
7288
- confidence: z3.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
7289
- reason: z3.string().describe("Short reason for the decision; use an empty string if none.")
7508
+ confidence: z4.number().min(0).max(1).describe("Classifier confidence from 0 to 1."),
7509
+ reason: z4.string().describe("Short reason for the decision; use an empty string if none.")
7290
7510
  }).strict();
7291
7511
  var ROUTER_CONFIDENCE_THRESHOLD = 0.8;
7292
7512
  var ROUTER_CLASSIFIER_MAX_TOKENS = 240;
@@ -7632,15 +7852,6 @@ var THREAD_OPTOUT_ACK = "Understood. I'll stay out of this thread unless someone
7632
7852
  function shouldRethrowTurnControlError(error) {
7633
7853
  return isCooperativeTurnYieldError(error) || isTurnInputCommitLostError(error) || isTurnInputDeferredError(error) || isProviderRetryError(error);
7634
7854
  }
7635
- async function maybeHandleThreadOptOutDecision(args) {
7636
- if (!args.decision?.shouldUnsubscribe) {
7637
- return false;
7638
- }
7639
- await args.thread.unsubscribe();
7640
- await args.beforeFirstResponsePost?.();
7641
- await args.thread.post(THREAD_OPTOUT_ACK);
7642
- return true;
7643
- }
7644
7855
  function getQueuedMessages(context, options) {
7645
7856
  return (context?.skipped ?? []).map((message) => {
7646
7857
  const stripped = options.stripLeadingBotMention(message.text, {
@@ -7705,6 +7916,16 @@ function isResourceEventNotificationMessage2(message) {
7705
7916
  }
7706
7917
  function createSlackTurnRuntime(deps) {
7707
7918
  const logContext = (args) => buildLogContext(deps, args);
7919
+ const maybeHandleThreadOptOutDecision = async (args) => {
7920
+ if (!args.decision?.shouldUnsubscribe) {
7921
+ return false;
7922
+ }
7923
+ await deps.cancelEventSubscriptions({ conversationId: args.thread.id });
7924
+ await args.thread.unsubscribe();
7925
+ await args.beforeFirstResponsePost?.();
7926
+ await args.thread.post(THREAD_OPTOUT_ACK);
7927
+ return true;
7928
+ };
7708
7929
  const failConversationTurn = async (args) => {
7709
7930
  const conversationId = deps.getThreadId(args.thread, args.message) ?? deps.getRunId(args.thread, args.message);
7710
7931
  if (!conversationId) {
@@ -9052,11 +9273,11 @@ function getSlackMessageTs(message) {
9052
9273
  }
9053
9274
 
9054
9275
  // src/chat/slack/action-token.ts
9055
- import { z as z4 } from "zod";
9056
- var slackActionTokenSchema = z4.string().trim().min(1).brand();
9057
- var slackMessageEnvelopeSchema = z4.object({
9058
- raw: z4.object({
9059
- action_token: z4.unknown().optional()
9276
+ import { z as z5 } from "zod";
9277
+ var slackActionTokenSchema = z5.string().trim().min(1).brand();
9278
+ var slackMessageEnvelopeSchema = z5.object({
9279
+ raw: z5.object({
9280
+ action_token: z5.unknown().optional()
9060
9281
  }).optional()
9061
9282
  });
9062
9283
  function readSlackActionToken(message) {
@@ -10766,6 +10987,7 @@ function createSlackRuntime(options) {
10766
10987
  });
10767
10988
  return createSlackTurnRuntime({
10768
10989
  assistantUserName: botConfig.userName,
10990
+ cancelEventSubscriptions: cancelSubscriptions,
10769
10991
  modelId: standardModelId(botConfig),
10770
10992
  now: options.now ?? (() => Date.now()),
10771
10993
  getThreadId,
@@ -596,6 +596,20 @@ export declare const conversationEventSchema: z.ZodUnion<readonly [z.ZodObject<{
596
596
  }, z.core.$strict>]>;
597
597
  /** One versioned event read from the durable conversation log. */
598
598
  export type ConversationEvent = z.output<typeof conversationEventSchema>;
599
+ /** A decoded message-summary event and its readable history boundary. */
600
+ export type MessagesSummarizedEvent = Omit<Extract<ConversationEvent, {
601
+ schemaVersion: 1;
602
+ }>, "data"> & {
603
+ data: Extract<ConversationEventData, {
604
+ type: "messages_summarized";
605
+ }>;
606
+ };
607
+ /** Projection-ready message events paired with their authoritative boundary. */
608
+ export interface MessageHistory {
609
+ events: ConversationEvent[];
610
+ compaction: MessagesSummarizedEvent | undefined;
611
+ historyFromSeq: number;
612
+ }
599
613
  declare const storedConversationEventSchema: z.ZodObject<{
600
614
  schemaVersion: z.ZodNumber;
601
615
  seq: z.ZodNumber;
@@ -746,11 +760,8 @@ export interface ConversationEventStore {
746
760
  loadCurrentHistory(conversationId: string): Promise<ConversationEvent[]>;
747
761
  /** Events in the history version containing `seq`, when it exists. */
748
762
  loadHistoryContaining(conversationId: string, seq: number, throughSeq?: number): Promise<ConversationEvent[] | undefined>;
749
- /** Current source/destination messages and their latest summary snapshot. */
750
- loadMessageHistory(conversationId: string): Promise<{
751
- events: ConversationEvent[];
752
- compaction: ConversationEvent | undefined;
753
- }>;
763
+ /** Projection-ready message suffix, summary snapshot, and readable boundary. */
764
+ loadMessageHistory(conversationId: string): Promise<MessageHistory>;
754
765
  /** All events across every history version in `seq` order. */
755
766
  loadHistory(conversationId: string): Promise<ConversationEvent[]>;
756
767
  }
@@ -1,6 +1,4 @@
1
- import type { ConversationEvent } from "./history";
1
+ import type { MessageHistory } from "./history";
2
2
  import type { ConversationMessage } from "@/chat/state/conversation";
3
- /** Reduce canonical message facts into destination-facing history. */
4
- export declare function projectConversationMessages(events: ConversationEvent[], options?: {
5
- historyFromSeq?: number;
6
- }): ConversationMessage[];
3
+ /** Reduce a boundary-bearing message-history suffix into destination history. */
4
+ export declare function projectConversationMessages(history: Pick<MessageHistory, "events" | "historyFromSeq">): ConversationMessage[];
@@ -57,6 +57,12 @@ export declare function cancelResourceEventSubscription(input: {
57
57
  nowMs?: number;
58
58
  state?: StateAdapter;
59
59
  }): Promise<ResourceEventSubscription | undefined>;
60
+ /** Cancel every active resource event subscription bound to one conversation. */
61
+ export declare function cancelSubscriptions(input: {
62
+ conversationId: string;
63
+ nowMs?: number;
64
+ state?: StateAdapter;
65
+ }): Promise<void>;
60
66
  /** Find active subscriptions interested in a normalized provider event. */
61
67
  export declare function findMatchingResourceEventSubscriptions(input: {
62
68
  eventType: string;