@sentry/junior 0.124.2 → 0.126.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 (87) hide show
  1. package/dist/{agent-hooks-HJQTURNC.js → agent-hooks-HDSNWDQM.js} +9 -10
  2. package/dist/api/conversations/auxiliary-costs.d.ts +6 -0
  3. package/dist/api/conversations/detail.d.ts +10 -0
  4. package/dist/api/conversations/list.d.ts +11 -0
  5. package/dist/api/conversations/projection.d.ts +2 -1
  6. package/dist/api/locations/detail.d.ts +20 -0
  7. package/dist/api/people/profile.d.ts +10 -0
  8. package/dist/api/people/shared.d.ts +36 -0
  9. package/dist/api/plugin-reports.d.ts +1 -0
  10. package/dist/api/schema/conversation.d.ts +40 -0
  11. package/dist/api/schema/location.d.ts +10 -0
  12. package/dist/api/schema/person.d.ts +10 -0
  13. package/dist/api/schema.d.ts +2 -2
  14. package/dist/api/schema.js +4 -2
  15. package/dist/api.js +339 -180
  16. package/dist/app.js +52 -41
  17. package/dist/{catalog-runtime-F356WNZS.js → catalog-runtime-BDC3UWPG.js} +5 -6
  18. package/dist/chat/agent/prompt.d.ts +1 -0
  19. package/dist/chat/agent/request.d.ts +2 -1
  20. package/dist/chat/agent/resume.d.ts +2 -0
  21. package/dist/chat/agent-dispatch/types.d.ts +2 -1
  22. package/dist/chat/conversation-privacy.d.ts +7 -12
  23. package/dist/chat/conversations/destination-visibility.d.ts +7 -0
  24. package/dist/chat/conversations/history.d.ts +4 -2
  25. package/dist/chat/conversations/sql/conversation-row.d.ts +7 -4
  26. package/dist/chat/conversations/sql/store.d.ts +2 -1
  27. package/dist/chat/conversations/store.d.ts +12 -4
  28. package/dist/chat/pi/client.d.ts +1 -0
  29. package/dist/chat/plugins/agent-hooks.d.ts +1 -0
  30. package/dist/chat/plugins/conversation-event-stats.d.ts +3 -0
  31. package/dist/chat/plugins/conversation-events.d.ts +1 -1
  32. package/dist/chat/services/turn-session-record.d.ts +4 -1
  33. package/dist/chat/slack/conversation-context.d.ts +4 -7
  34. package/dist/chat/slack/footer.d.ts +10 -1
  35. package/dist/chat/slack/reply.d.ts +9 -2
  36. package/dist/chat/slack/source-link.d.ts +5 -0
  37. package/dist/chat/source.d.ts +16 -0
  38. package/dist/chat/state/turn-session.d.ts +2 -6
  39. package/dist/{chunk-L7EZRQ2J.js → chunk-4PV73JHH.js} +11 -13
  40. package/dist/{chunk-IXTIJQ7Z.js → chunk-6KWO5DU3.js} +167 -20
  41. package/dist/{chunk-AYQZCJZJ.js → chunk-6ZBSTNYN.js} +14 -0
  42. package/dist/chunk-72SDEHFP.js +102 -0
  43. package/dist/{chunk-SMTAXLX4.js → chunk-ACJZZY5W.js} +2 -2
  44. package/dist/{chunk-KYKLQYSU.js → chunk-APYVVX2Y.js} +1 -1
  45. package/dist/{chunk-EOSC6JOC.js → chunk-EFQX6XBW.js} +1 -1
  46. package/dist/{chunk-IMLJE2NY.js → chunk-EQMSKORN.js} +2 -2
  47. package/dist/{chunk-ZO6E537B.js → chunk-GHNO2WUH.js} +1 -1
  48. package/dist/{chunk-WKBPFZ25.js → chunk-GK55KLEH.js} +1 -1
  49. package/dist/{chunk-PR3M62LK.js → chunk-HX236W2U.js} +6 -4
  50. package/dist/{chunk-7LDOW4QA.js → chunk-JFW62B3Y.js} +1 -1
  51. package/dist/{chunk-ASK74NM6.js → chunk-JP2ZOSQK.js} +15 -5
  52. package/dist/{chunk-NNKVDYXN.js → chunk-KISG7E24.js} +57 -36
  53. package/dist/{chunk-DW6SLS5F.js → chunk-KP7E267S.js} +83 -24
  54. package/dist/{chunk-VMRKIKGO.js → chunk-LCRWDMCH.js} +1 -1
  55. package/dist/{chunk-AQKVWIPR.js → chunk-LIDEU7QS.js} +4 -4
  56. package/dist/{chunk-GCGJGSQL.js → chunk-S4PUICSB.js} +2 -0
  57. package/dist/{chunk-SS7MAJF5.js → chunk-TUHUIBDX.js} +60 -40
  58. package/dist/{chunk-PE44LDDQ.js → chunk-UTL3MHPC.js} +1 -0
  59. package/dist/{chunk-S7G34U75.js → chunk-VUBUFT66.js} +5 -121
  60. package/dist/{chunk-CMYDYVOD.js → chunk-WRH7DWFO.js} +15 -12
  61. package/dist/{chunk-574YK7QW.js → chunk-XLIAQRDI.js} +25 -10
  62. package/dist/{chunk-7P7YVJKH.js → chunk-XVKJJXHF.js} +17 -15
  63. package/dist/{chunk-4JW3YNQZ.js → chunk-YMSVBWBY.js} +9 -11
  64. package/dist/cli/chat.js +25 -25
  65. package/dist/cli/check.js +6 -7
  66. package/dist/cli/plugins.js +12 -13
  67. package/dist/cli/snapshot-create.js +9 -10
  68. package/dist/cli/upgrade.js +7 -8
  69. package/dist/db/schema/conversations.d.ts +20 -0
  70. package/dist/db/schema.d.ts +19 -0
  71. package/dist/{db-4SU2HJSV.js → db-AZB6AGJL.js} +7 -8
  72. package/dist/instrumentation.js +4 -5
  73. package/dist/nitro.js +2 -2
  74. package/dist/{oauth-callback-server-MMCH5QV6.js → oauth-callback-server-XK4QJLPZ.js} +18 -19
  75. package/dist/reporting-schema.d.ts +2 -0
  76. package/dist/{runner-ZDSNVGYA.js → runner-DSGDSATN.js} +13 -15
  77. package/dist/{skills-7G7LBHLK.js → skills-CO6E3BQJ.js} +6 -7
  78. package/dist/{validation-2ETDADPB.js → validation-IHLISKM5.js} +6 -7
  79. package/dist/version.js +1 -1
  80. package/migrations/0013_conversation_session_source.sql +38 -0
  81. package/migrations/0014_source_visibility.sql +8 -0
  82. package/migrations/meta/0013_snapshot.json +1250 -0
  83. package/migrations/meta/0014_snapshot.json +1201 -0
  84. package/migrations/meta/_journal.json +14 -0
  85. package/package.json +6 -6
  86. package/dist/chunk-BA5KHLPQ.js +0 -55
  87. package/dist/chunk-OB42YVAE.js +0 -16
@@ -13,7 +13,7 @@ import {
13
13
  persistAuthPauseTurnState,
14
14
  requireTurnFailureEventId,
15
15
  scheduleSessionCompletedPluginTasks
16
- } from "./chunk-4JW3YNQZ.js";
16
+ } from "./chunk-YMSVBWBY.js";
17
17
  import {
18
18
  buildSentryConversationUrl
19
19
  } from "./chunk-4CODA7P5.js";
@@ -40,7 +40,7 @@ import {
40
40
  resolveBaseUrl,
41
41
  resolvePluginOAuthAccount,
42
42
  truncateStatusText
43
- } from "./chunk-L7EZRQ2J.js";
43
+ } from "./chunk-4PV73JHH.js";
44
44
  import {
45
45
  JUNIOR_THREAD_STATE_TTL_MS,
46
46
  TurnSliceLimitExceededError,
@@ -73,7 +73,13 @@ import {
73
73
  recordDeliveredAssistantMessage,
74
74
  turnHasReply,
75
75
  updateConversationStats
76
- } from "./chunk-CMYDYVOD.js";
76
+ } from "./chunk-WRH7DWFO.js";
77
+ import {
78
+ parseSlackThreadId,
79
+ readSlackRawMessageContext,
80
+ resolveSlackChannelIdFromMessage,
81
+ resolveSlackChannelIdFromThreadId
82
+ } from "./chunk-72SDEHFP.js";
77
83
  import {
78
84
  SlackActionError,
79
85
  getDashboardConversationLink,
@@ -82,19 +88,19 @@ import {
82
88
  getSlackClient,
83
89
  isDmChannel,
84
90
  normalizeSlackConversationId
85
- } from "./chunk-IXTIJQ7Z.js";
91
+ } from "./chunk-6KWO5DU3.js";
86
92
  import {
87
93
  getConversationEventStore,
88
94
  getConversationStore,
89
95
  parseDestination,
90
96
  requireSlackDestination,
91
97
  sameDestination
92
- } from "./chunk-DW6SLS5F.js";
98
+ } from "./chunk-KP7E267S.js";
93
99
  import {
94
100
  acquireActiveLock,
95
101
  getDefaultRedisStateAdapterFor,
96
102
  getStateAdapter
97
- } from "./chunk-KYKLQYSU.js";
103
+ } from "./chunk-APYVVX2Y.js";
98
104
  import {
99
105
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
100
106
  botConfig,
@@ -103,45 +109,37 @@ import {
103
109
  getRuntimeMetadata,
104
110
  normalizeSlackEmojiName,
105
111
  standardModelId
106
- } from "./chunk-574YK7QW.js";
107
- import {
108
- parseSlackThreadId,
109
- readSlackRawMessageContext,
110
- resolveSlackChannelIdFromMessage,
111
- resolveSlackChannelIdFromThreadId
112
- } from "./chunk-S7G34U75.js";
112
+ } from "./chunk-XLIAQRDI.js";
113
113
  import {
114
114
  discoverSkills
115
- } from "./chunk-SMTAXLX4.js";
115
+ } from "./chunk-ACJZZY5W.js";
116
116
  import {
117
117
  pluginCatalogRuntime
118
- } from "./chunk-ZO6E537B.js";
118
+ } from "./chunk-GHNO2WUH.js";
119
119
  import {
120
120
  buildOAuthTokenRequest,
121
121
  hasRequiredOAuthScope,
122
122
  parseOAuthTokenResponse
123
- } from "./chunk-EOSC6JOC.js";
123
+ } from "./chunk-EFQX6XBW.js";
124
124
  import {
125
125
  createSlackResumeActor,
126
126
  isUserActor,
127
127
  parseStoredSlackActor
128
128
  } from "./chunk-HZF5P5UN.js";
129
+ import {
130
+ parseSlackMessageTs
131
+ } from "./chunk-F3B2YJ76.js";
129
132
  import {
130
133
  buildTurnFailureResponse,
134
+ isRecord,
131
135
  logException,
132
136
  logInfo,
133
137
  logWarn,
134
138
  setTags,
135
- withLogContext
136
- } from "./chunk-ASK74NM6.js";
137
- import {
138
- isRecord,
139
139
  toOptionalNumber,
140
- toOptionalString
141
- } from "./chunk-OB42YVAE.js";
142
- import {
143
- parseSlackMessageTs
144
- } from "./chunk-F3B2YJ76.js";
140
+ toOptionalString,
141
+ withLogContext
142
+ } from "./chunk-JP2ZOSQK.js";
145
143
  import {
146
144
  homeDir
147
145
  } from "./chunk-H4HBKISO.js";
@@ -508,6 +506,9 @@ function createSlackWebApiAssistantStatusSession(args) {
508
506
  }
509
507
 
510
508
  // src/chat/slack/footer.ts
509
+ function formatReplyAttribution(attribution) {
510
+ return attribution.detail ? `${attribution.label} \xB7 ${attribution.detail}` : attribution.label;
511
+ }
511
512
  function buildSlackReplyFooter(args) {
512
513
  const items = [];
513
514
  const conversationId = args.conversationId?.trim();
@@ -522,7 +523,10 @@ function buildSlackReplyFooter(args) {
522
523
  }
523
524
  items.push(idItem);
524
525
  }
525
- return items.length > 0 ? { items } : void 0;
526
+ return items.length > 0 || args.replyAttribution ? {
527
+ ...args.replyAttribution ? { attribution: args.replyAttribution } : {},
528
+ items
529
+ } : void 0;
526
530
  }
527
531
  function buildSlackReplyBlocks(text, footer) {
528
532
  if (!text.trim()) {
@@ -534,13 +538,22 @@ function buildSlackReplyBlocks(text, footer) {
534
538
  text
535
539
  }
536
540
  ];
537
- if (footer?.items.length) {
541
+ if (footer && (footer.attribution || footer.items.length > 0)) {
542
+ const attributionElements = footer.attribution ? [
543
+ {
544
+ type: "plain_text",
545
+ text: formatReplyAttribution(footer.attribution)
546
+ }
547
+ ] : [];
538
548
  blocks.push({
539
549
  type: "context",
540
- elements: footer.items.map((item) => ({
541
- type: "mrkdwn",
542
- text: item.url ? `*${escapeSlackMrkdwnText(item.label)}:* ${formatSlackLink(item.url, item.value)}` : `*${escapeSlackMrkdwnText(item.label)}:* ${escapeSlackMrkdwnText(item.value)}`
543
- }))
550
+ elements: [
551
+ ...attributionElements,
552
+ ...footer.items.map((item) => ({
553
+ type: "mrkdwn",
554
+ text: item.url ? `*${escapeSlackMrkdwnText(item.label)}:* ${formatSlackLink(item.url, item.value)}` : `*${escapeSlackMrkdwnText(item.label)}:* ${escapeSlackMrkdwnText(item.value)}`
555
+ }))
556
+ ]
544
557
  });
545
558
  }
546
559
  return blocks;
@@ -754,18 +767,23 @@ function buildSlackOutputMessage(text) {
754
767
  async function sendSlackReply(args) {
755
768
  const chunks = splitSlackReplyText(args.text);
756
769
  const footer = buildSlackReplyFooter({
757
- conversationId: args.conversationId
770
+ conversationId: args.conversationId,
771
+ replyAttribution: args.replyAttribution
758
772
  });
759
773
  let lastMessageTs;
760
774
  for (const [index, text] of chunks.entries()) {
775
+ const isFinalChunk = index === chunks.length - 1;
761
776
  const blocks = buildSlackReplyBlocks(
762
777
  text,
763
- index === chunks.length - 1 ? footer : void 0
778
+ isFinalChunk ? footer : void 0
764
779
  );
780
+ const fallbackText = isFinalChunk && args.replyAttribution ? `${text}
781
+
782
+ ${escapeSlackMrkdwnText(formatReplyAttribution(args.replyAttribution))}` : text;
765
783
  const response = await postSlackMessage({
766
784
  channelId: args.channelId,
767
785
  threadTs: args.threadTs,
768
- text,
786
+ text: fallbackText,
769
787
  ...blocks ? { blocks } : {}
770
788
  });
771
789
  lastMessageTs = response.ts;
@@ -1085,12 +1103,13 @@ function resolveReplyTimeoutMs(explicitTimeoutMs) {
1085
1103
  const parsed = Number.parseInt(raw, 10);
1086
1104
  return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
1087
1105
  }
1088
- async function postSlackMessageBestEffort(channelId, threadTs, text, conversationId) {
1106
+ async function postSlackMessageBestEffort(channelId, threadTs, text, conversationId, replyAttribution) {
1089
1107
  try {
1090
1108
  if (conversationId) {
1091
1109
  await sendSlackReply({
1092
1110
  channelId,
1093
1111
  conversationId,
1112
+ replyAttribution,
1094
1113
  text,
1095
1114
  threadTs
1096
1115
  });
@@ -1408,6 +1427,7 @@ async function resumeSlackTurnInContext(args) {
1408
1427
  messageTs = await sendSlackReply({
1409
1428
  channelId: runArgs.channelId,
1410
1429
  conversationId: runArgs.conversationId,
1430
+ replyAttribution: runArgs.replyContext?.routing.dispatch?.replyAttribution,
1411
1431
  text,
1412
1432
  threadTs: runArgs.threadTs
1413
1433
  });
@@ -1683,7 +1703,8 @@ async function resumeSlackTurnInContext(args) {
1683
1703
  deferredAuthInfo.providerDisplayName,
1684
1704
  deferredAuthInfo.requestText
1685
1705
  ),
1686
- runArgs.conversationId
1706
+ runArgs.conversationId,
1707
+ runArgs.replyContext?.routing.dispatch?.replyAttribution
1687
1708
  );
1688
1709
  }
1689
1710
  return true;
@@ -4,22 +4,22 @@ import {
4
4
  juniorConversations,
5
5
  juniorIdentities,
6
6
  juniorUsers
7
- } from "./chunk-GCGJGSQL.js";
7
+ } from "./chunk-S4PUICSB.js";
8
8
  import {
9
9
  TURN_REASONING_LEVELS,
10
10
  getChatConfig,
11
11
  modelProfileSchema
12
- } from "./chunk-574YK7QW.js";
12
+ } from "./chunk-XLIAQRDI.js";
13
13
  import {
14
14
  juniorDestinations
15
15
  } from "./chunk-VFUK3X5B.js";
16
- import {
17
- normalizeIdentityEmail
18
- } from "./chunk-ASK74NM6.js";
19
16
  import {
20
17
  parseSlackChannelReferenceId,
21
18
  parseSlackTeamId
22
19
  } from "./chunk-F3B2YJ76.js";
20
+ import {
21
+ normalizeIdentityEmail
22
+ } from "./chunk-JP2ZOSQK.js";
23
23
 
24
24
  // src/chat/conversations/sql/store.ts
25
25
  import { randomUUID as randomUUID2 } from "crypto";
@@ -167,6 +167,36 @@ async function upsertIdentity(executor, identity, nowMs = Date.now()) {
167
167
  };
168
168
  }
169
169
 
170
+ // src/chat/source.ts
171
+ import { sourceSchema } from "@sentry/junior-plugin-api";
172
+ function normalizeSessionSource(value) {
173
+ if (!value) {
174
+ return void 0;
175
+ }
176
+ if (value.platform === "local") {
177
+ return {
178
+ platform: "local",
179
+ visibility: "private",
180
+ conversationId: value.conversationId
181
+ };
182
+ }
183
+ const threadTs = value.threadTs?.trim();
184
+ if (!threadTs) {
185
+ return void 0;
186
+ }
187
+ return {
188
+ platform: "slack",
189
+ visibility: value.visibility,
190
+ teamId: value.teamId,
191
+ channelId: value.channelId,
192
+ threadTs
193
+ };
194
+ }
195
+ function parseSessionSource(value) {
196
+ const parsed = sourceSchema.safeParse(value);
197
+ return parsed.success ? normalizeSessionSource(parsed.data) : void 0;
198
+ }
199
+
170
200
  // src/chat/conversations/sql/store.ts
171
201
  var CONVERSATION_MUTATION_LOCK_PREFIX = "junior_conversation";
172
202
  function now() {
@@ -264,7 +294,7 @@ function destinationUpsertFromDestination(args) {
264
294
  providerTenantId: destination.teamId,
265
295
  providerDestinationId: channelId,
266
296
  refreshVisibility: args.visibility !== void 0,
267
- visibility: args.visibility ?? "private",
297
+ visibility: args.visibility ?? "unknown",
268
298
  ...args.channelName ? { displayName: args.channelName } : {},
269
299
  metadata: { platform: "slack" }
270
300
  };
@@ -343,6 +373,10 @@ function conversationFromRow(readRow) {
343
373
  if (row.source !== void 0 && row.source !== null && !source) {
344
374
  throw new Error("Conversation record source is invalid");
345
375
  }
376
+ const sessionSource = row.sessionSource === void 0 || row.sessionSource === null ? void 0 : parseSessionSource(row.sessionSource);
377
+ if (row.sessionSource !== void 0 && row.sessionSource !== null && !sessionSource) {
378
+ throw new Error("Conversation record session source is invalid");
379
+ }
346
380
  const execution = {
347
381
  status: executionStatusFromValue(row.executionStatus),
348
382
  lastCheckpointAtMs: msFromDate(row.lastCheckpointAt),
@@ -367,6 +401,7 @@ function conversationFromRow(readRow) {
367
401
  ...msFromDate(row.archivedAt) !== void 0 ? { archivedAtMs: msFromDate(row.archivedAt) } : {},
368
402
  ...row.channelName ? { channelName: row.channelName } : {},
369
403
  ...source ? { source } : {},
404
+ ...sessionSource ? { sessionSource } : {},
370
405
  ...row.title ? { title: row.title } : {},
371
406
  ...msFromDate(row.transcriptPurgedAt) !== void 0 ? { transcriptPurgedAtMs: msFromDate(row.transcriptPurgedAt) } : {},
372
407
  ...visibility ? { visibility } : {}
@@ -381,6 +416,7 @@ function emptyConversation(args) {
381
416
  updatedAtMs: args.nowMs,
382
417
  ...args.destination ? { destination: args.destination } : {},
383
418
  ...args.source ? { source: args.source } : {},
419
+ ...args.sessionSource ? { sessionSource: args.sessionSource } : {},
384
420
  execution: {
385
421
  status: "idle",
386
422
  updatedAtMs: args.nowMs
@@ -461,6 +497,7 @@ var SqlStore = class {
461
497
  async recordActivity(args) {
462
498
  const nowMs = args.nowMs ?? now();
463
499
  const activityAtMs = args.activityAtMs ?? nowMs;
500
+ const sessionSource = normalizeSessionSource(args.sessionSource);
464
501
  await this.withConversationMutation(args.conversationId, async () => {
465
502
  const existing = await this.get({
466
503
  conversationId: args.conversationId
@@ -476,14 +513,20 @@ var SqlStore = class {
476
513
  conversationId: args.conversationId,
477
514
  destination: args.destination,
478
515
  nowMs,
479
- source: args.source
516
+ source: args.source,
517
+ ...sessionSource ? { sessionSource } : {}
480
518
  });
481
- const { visibility: _persisted, ...currentWithoutVisibility } = current2;
519
+ const {
520
+ sessionSource: _persistedSessionSource,
521
+ visibility: _persistedVisibility,
522
+ ...currentWithoutPersistedSignals
523
+ } = current2;
482
524
  await this.upsertConversation({
483
525
  conversation: {
484
- ...currentWithoutVisibility,
526
+ ...currentWithoutPersistedSignals,
485
527
  destination: current2.destination ?? args.destination,
486
528
  source: current2.source ?? args.source,
529
+ ...sessionSource ? { sessionSource } : {},
487
530
  channelName: current2.channelName ?? args.channelName,
488
531
  actor: mergeActor(current2.actor, args.actor),
489
532
  title: current2.title ?? args.title,
@@ -583,7 +626,10 @@ var SqlStore = class {
583
626
  if (!row) {
584
627
  return void 0;
585
628
  }
586
- return row.visibility === "public" ? "public" : "private";
629
+ if (row.visibility === "public" || row.visibility === "private") {
630
+ return row.visibility;
631
+ }
632
+ return void 0;
587
633
  }
588
634
  /** Serialize all durable mutations for one conversation inside a SQL transaction. */
589
635
  async withConversationMutation(conversationId, callback) {
@@ -637,6 +683,7 @@ var SqlStore = class {
637
683
  conversationId: conversation.conversationId,
638
684
  schemaVersion: 1,
639
685
  source: conversation.source ?? null,
686
+ sessionSource: conversation.sessionSource ?? null,
640
687
  originType: originTypeFromSource(conversation.source) ?? null,
641
688
  originId: null,
642
689
  originRunId: null,
@@ -662,6 +709,7 @@ var SqlStore = class {
662
709
  target: juniorConversations.conversationId,
663
710
  set: {
664
711
  source: sql2`coalesce(excluded.source, ${juniorConversations.source})`,
712
+ sessionSource: sql2`coalesce(${juniorConversations.sessionSource}, excluded.source_json)`,
665
713
  originType: sql2`coalesce(excluded.origin_type, ${juniorConversations.originType})`,
666
714
  originId: sql2`coalesce(excluded.origin_id, ${juniorConversations.originId})`,
667
715
  originRunId: sql2`coalesce(excluded.origin_run_id, ${juniorConversations.originRunId})`,
@@ -714,9 +762,9 @@ var SqlStore = class {
714
762
  set: {
715
763
  kind: sql2`excluded.kind`,
716
764
  displayName: sql2`coalesce(excluded.display_name, ${juniorDestinations.displayName})`,
717
- // Signal-less writes insert as private but must not clobber an
718
- // existing public/private value. Live source signals refresh this
719
- // field so converted channels converge on the next message.
765
+ // Signal-less writes remain unknown and must not clobber an existing
766
+ // public/private value. Live source signals refresh this field so
767
+ // converted channels converge on the next message.
720
768
  visibility: visibilityUpdate,
721
769
  metadata: sql2`coalesce(excluded.metadata_json, ${juniorDestinations.metadata})`,
722
770
  updatedAt: sql2`excluded.updated_at`
@@ -1099,15 +1147,22 @@ var newConversationEventSchema = z2.object({
1099
1147
 
1100
1148
  // src/chat/conversations/sql/conversation-row.ts
1101
1149
  import { sql as sql3 } from "drizzle-orm";
1102
- async function ensureConversationRow(executor, conversationId, atMs) {
1150
+ async function ensureConversationRow(executor, conversationId, atMs, options = {}) {
1103
1151
  const at = new Date(atMs);
1104
- await executor.db().insert(juniorConversations).values({
1152
+ const insert = executor.db().insert(juniorConversations).values({
1105
1153
  conversationId,
1106
1154
  createdAt: at,
1107
1155
  lastActivityAt: at,
1108
1156
  updatedAt: at,
1109
1157
  executionStatus: "idle"
1110
- }).onConflictDoUpdate({
1158
+ });
1159
+ if (options.activity === "preserve") {
1160
+ await insert.onConflictDoNothing({
1161
+ target: juniorConversations.conversationId
1162
+ });
1163
+ return;
1164
+ }
1165
+ await insert.onConflictDoUpdate({
1111
1166
  target: juniorConversations.conversationId,
1112
1167
  set: {
1113
1168
  lastActivityAt: sql3`greatest(${juniorConversations.lastActivityAt}, excluded.last_activity_at)`,
@@ -1192,7 +1247,7 @@ var SqlConversationEventStore = class {
1192
1247
  this.executor = executor;
1193
1248
  }
1194
1249
  executor;
1195
- async append(conversationId, events) {
1250
+ async append(conversationId, events, options = {}) {
1196
1251
  const parsed = events.map(
1197
1252
  (event) => newConversationEventSchema.parse(event)
1198
1253
  );
@@ -1231,14 +1286,17 @@ var SqlConversationEventStore = class {
1231
1286
  await ensureConversationRow(
1232
1287
  this.executor,
1233
1288
  conversationId,
1234
- newestCreatedAtMs
1235
- );
1236
- await this.executor.db().update(juniorConversations).set({ archivedAt: null }).where(
1237
- and3(
1238
- eq3(juniorConversations.conversationId, conversationId),
1239
- isNotNull(juniorConversations.archivedAt)
1240
- )
1289
+ newestCreatedAtMs,
1290
+ options
1241
1291
  );
1292
+ if (options.activity !== "preserve") {
1293
+ await this.executor.db().update(juniorConversations).set({ archivedAt: null }).where(
1294
+ and3(
1295
+ eq3(juniorConversations.conversationId, conversationId),
1296
+ isNotNull(juniorConversations.archivedAt)
1297
+ )
1298
+ );
1299
+ }
1242
1300
  const cursor = await this.readCursor(conversationId);
1243
1301
  const historyVersion = cursor.maxHistoryVersion ?? 0;
1244
1302
  let seq = cursor.nextSeq;
@@ -1540,6 +1598,7 @@ export {
1540
1598
  parseDestination,
1541
1599
  requireSlackDestination,
1542
1600
  sameDestination,
1601
+ parseSessionSource,
1543
1602
  instructionProvenanceFor,
1544
1603
  contextProvenance,
1545
1604
  sameActorIdentity,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  JUNIOR_VERSION
3
- } from "./chunk-7LDOW4QA.js";
3
+ } from "./chunk-JFW62B3Y.js";
4
4
 
5
5
  // src/deployment.ts
6
6
  var JUNIOR_HEARTBEAT_ROUTE = "/api/internal/heartbeat";
@@ -2,18 +2,18 @@ import {
2
2
  SANDBOX_WORKSPACE_ROOT,
3
3
  getStateAdapter,
4
4
  sleep
5
- } from "./chunk-KYKLQYSU.js";
5
+ } from "./chunk-APYVVX2Y.js";
6
6
  import {
7
7
  toOptionalTrimmed
8
- } from "./chunk-574YK7QW.js";
8
+ } from "./chunk-XLIAQRDI.js";
9
9
  import {
10
10
  pluginCatalogRuntime
11
- } from "./chunk-ZO6E537B.js";
11
+ } from "./chunk-GHNO2WUH.js";
12
12
  import {
13
13
  setSpanAttributes,
14
14
  setSpanStatus,
15
15
  withSpan
16
- } from "./chunk-ASK74NM6.js";
16
+ } from "./chunk-JP2ZOSQK.js";
17
17
 
18
18
  // src/chat/sandbox/snapshot/profile.ts
19
19
  import { createHash } from "crypto";
@@ -101,6 +101,8 @@ var juniorConversations = pgTable3(
101
101
  conversationId: text3("conversation_id").primaryKey(),
102
102
  schemaVersion: integer("schema_version").notNull().default(1),
103
103
  source: text3("source").$type(),
104
+ /** Structured session Source locator; set-once on the conversation root. */
105
+ sessionSource: jsonb2("source_json").$type(),
104
106
  originType: text3("origin_type"),
105
107
  originId: text3("origin_id"),
106
108
  originRunId: text3("origin_run_id"),