@sentry/junior 0.85.0 → 0.87.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 (49) hide show
  1. package/dist/{agent-hooks-AV7CHLUO.js → agent-hooks-NWOUB3UR.js} +7 -7
  2. package/dist/app.js +779 -356
  3. package/dist/chat/conversation-privacy.d.ts +12 -2
  4. package/dist/chat/conversations/sql/migrations.d.ts +1 -1
  5. package/dist/chat/conversations/sql/store.d.ts +9 -1
  6. package/dist/chat/conversations/store.d.ts +13 -0
  7. package/dist/chat/ingress/message-changed.d.ts +2 -0
  8. package/dist/chat/no-reply.d.ts +7 -0
  9. package/dist/chat/respond.d.ts +7 -1
  10. package/dist/chat/runtime/reply-executor.d.ts +2 -10
  11. package/dist/chat/runtime/slack-runtime.d.ts +5 -4
  12. package/dist/chat/runtime/turn.d.ts +7 -0
  13. package/dist/chat/services/persist-retry.d.ts +2 -0
  14. package/dist/chat/services/reply-delivery-plan.d.ts +0 -4
  15. package/dist/chat/services/turn-session-record.d.ts +31 -2
  16. package/dist/chat/slack/client.d.ts +33 -2
  17. package/dist/chat/slack/conversation-context.d.ts +15 -0
  18. package/dist/chat/state/turn-session.d.ts +9 -0
  19. package/dist/chat/task-execution/queue.d.ts +1 -1
  20. package/dist/chat/task-execution/slack-work.d.ts +10 -2
  21. package/dist/chat/task-execution/state.d.ts +44 -4
  22. package/dist/chat/task-execution/store.d.ts +21 -4
  23. package/dist/chat/task-execution/worker.d.ts +11 -4
  24. package/dist/chat/tools/slack/channel-access.d.ts +29 -0
  25. package/dist/chat/tools/slack/thread-read.d.ts +4 -1
  26. package/dist/{chunk-UVNV67EC.js → chunk-2NFV5FMB.js} +4 -4
  27. package/dist/{chunk-QTTTRBNB.js → chunk-6I6HBOQM.js} +80 -15
  28. package/dist/{chunk-ENEWQMRJ.js → chunk-6O5UI3RG.js} +1 -1
  29. package/dist/{chunk-GY7L6VCT.js → chunk-ACJJJEGG.js} +35 -17
  30. package/dist/{chunk-MHEV3T2Y.js → chunk-B6FQPS7A.js} +953 -795
  31. package/dist/{chunk-MTE5NRPJ.js → chunk-BRSQQRG6.js} +1 -1
  32. package/dist/{chunk-EENOFKDN.js → chunk-ENPSU7L7.js} +165 -27
  33. package/dist/{chunk-RUB77TGS.js → chunk-GB5DFM4D.js} +1 -1
  34. package/dist/{chunk-C2PSUWK3.js → chunk-GGD6WK6V.js} +124 -25
  35. package/dist/{chunk-SSUEWAVS.js → chunk-JRXCSSSU.js} +19 -4
  36. package/dist/{chunk-DR75T7J3.js → chunk-L7OHKDOX.js} +9 -5
  37. package/dist/{chunk-FYPO4K7C.js → chunk-RIB3M6YA.js} +2 -2
  38. package/dist/{chunk-BU2AWPEN.js → chunk-ZU2ALUVQ.js} +3 -2
  39. package/dist/cli/chat.js +4 -4
  40. package/dist/cli/plugins.js +7 -7
  41. package/dist/cli/snapshot-warmup.js +4 -4
  42. package/dist/cli/upgrade.js +10 -7
  43. package/dist/{db-S3HYBLUS.js → db-SZVUU7RB.js} +4 -4
  44. package/dist/instrumentation.js +1 -1
  45. package/dist/nitro.js +4 -4
  46. package/dist/reporting/conversations.d.ts +2 -1
  47. package/dist/reporting.js +95 -30
  48. package/dist/{runner-IMQH6V2B.js → runner-DMP3IQNM.js} +27 -13
  49. package/package.json +6 -6
@@ -0,0 +1,29 @@
1
+ import type { ConversationPrivacy } from "@/chat/conversation-privacy";
2
+ /** Minimal persisted-visibility port for cross-conversation read gates. */
3
+ export interface DestinationVisibilityReader {
4
+ getDestinationVisibility(args: {
5
+ provider: string;
6
+ providerDestinationId: string;
7
+ providerTenantId?: string;
8
+ }): Promise<ConversationPrivacy | undefined>;
9
+ }
10
+ export type SlackChannelReadAccess = {
11
+ allowed: true;
12
+ } | {
13
+ allowed: false;
14
+ error: string;
15
+ };
16
+ /**
17
+ * Decide whether the model may read Slack content from a target channel.
18
+ *
19
+ * The current conversation is always readable. Any other channel requires
20
+ * persisted `public` visibility in the same workspace: channel-id prefixes
21
+ * cannot prove a channel public (modern Slack private channels also use `C`
22
+ * ids), so missing or private destinations fail closed.
23
+ */
24
+ export declare function checkSlackChannelReadAccess(args: {
25
+ currentChannelIds: Array<string | undefined>;
26
+ store?: DestinationVisibilityReader;
27
+ targetChannelId: string;
28
+ teamId: string;
29
+ }): Promise<SlackChannelReadAccess>;
@@ -1,6 +1,9 @@
1
+ import { type DestinationVisibilityReader } from "@/chat/tools/slack/channel-access";
1
2
  import type { SlackToolContext } from "@/chat/tools/slack/context";
2
3
  /** Create a tool that reads a Slack thread from a shared message URL or explicit coordinates. */
3
- export declare function createSlackThreadReadTool(context: SlackToolContext): import("@/chat/tools/definition").ToolDefinition<import("@sinclair/typebox").TObject<{
4
+ export declare function createSlackThreadReadTool(context: SlackToolContext, deps?: {
5
+ visibilityStore?: DestinationVisibilityReader;
6
+ }): import("@/chat/tools/definition").ToolDefinition<import("@sinclair/typebox").TObject<{
4
7
  url: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
5
8
  channel_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
6
9
  ts: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createPluginLogger,
3
3
  createPluginState
4
- } from "./chunk-MTE5NRPJ.js";
4
+ } from "./chunk-BRSQQRG6.js";
5
5
  import {
6
6
  getDb
7
- } from "./chunk-QTTTRBNB.js";
7
+ } from "./chunk-6I6HBOQM.js";
8
8
  import {
9
9
  SANDBOX_WORKSPACE_ROOT
10
10
  } from "./chunk-G3E7SCME.js";
@@ -13,12 +13,12 @@ import {
13
13
  isConversationScopedChannel,
14
14
  isDmChannel,
15
15
  normalizeSlackConversationId
16
- } from "./chunk-C2PSUWK3.js";
16
+ } from "./chunk-GGD6WK6V.js";
17
17
  import {
18
18
  botConfig,
19
19
  completeObject,
20
20
  embedTexts
21
- } from "./chunk-BU2AWPEN.js";
21
+ } from "./chunk-ZU2ALUVQ.js";
22
22
  import {
23
23
  isActorUserId,
24
24
  parseActorUserId
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  parseDestination,
3
3
  sameDestination
4
- } from "./chunk-C2PSUWK3.js";
4
+ } from "./chunk-GGD6WK6V.js";
5
5
  import {
6
6
  getChatConfig
7
- } from "./chunk-BU2AWPEN.js";
7
+ } from "./chunk-ZU2ALUVQ.js";
8
8
  import {
9
9
  parseStoredSlackRequester
10
10
  } from "./chunk-IXTBFABZ.js";
11
11
 
12
12
  // src/chat/conversations/sql/store.ts
13
13
  import { randomUUID } from "crypto";
14
- import { asc, desc, eq, sql as sql2 } from "drizzle-orm";
14
+ import { and, asc, desc, eq, sql as sql2 } from "drizzle-orm";
15
15
 
16
16
  // src/chat/conversations/sql/migrations.ts
17
17
  import { createHash } from "crypto";
@@ -298,8 +298,20 @@ CREATE INDEX IF NOT EXISTS junior_conversations_origin_idx
298
298
  ON junior_conversations (origin_type, origin_id, last_activity_at DESC)
299
299
  `
300
300
  ];
301
+ var destinationVisibilityBackfillStatements = [
302
+ `
303
+ UPDATE junior_destinations
304
+ SET visibility = 'private'
305
+ WHERE provider = 'slack'
306
+ AND visibility = 'public'
307
+ `
308
+ ];
301
309
  var migrations = [
302
- defineMigration("0001_conversation_core", coreMetadataStatements)
310
+ defineMigration("0001_conversation_core", coreMetadataStatements),
311
+ defineMigration(
312
+ "0002_slack_destination_visibility_backfill",
313
+ destinationVisibilityBackfillStatements
314
+ )
303
315
  ];
304
316
  function parseStoredMigrationRecord(value) {
305
317
  return migrationRecordSchema.parse(value);
@@ -436,13 +448,13 @@ function destinationUpsertFromDestination(args) {
436
448
  if (destination.platform === "slack") {
437
449
  const channelId = destination.channelId;
438
450
  const channelKind = channelId.startsWith("D") ? "dm" : channelId.startsWith("G") ? "group" : "channel";
439
- const visibility = channelId.startsWith("D") ? "direct" : channelId.startsWith("G") ? "private" : "public";
440
451
  return {
441
452
  kind: channelKind,
442
453
  provider: "slack",
443
454
  providerTenantId: destination.teamId,
444
455
  providerDestinationId: channelId,
445
- visibility,
456
+ refreshVisibility: args.visibility !== void 0,
457
+ visibility: args.visibility ?? "private",
446
458
  ...args.channelName ? { displayName: args.channelName } : {},
447
459
  metadata: { platform: "slack" }
448
460
  };
@@ -452,6 +464,7 @@ function destinationUpsertFromDestination(args) {
452
464
  provider: "local",
453
465
  providerTenantId: localWorkspaceFromConversationId(destination.conversationId) ?? localWorkspaceFromConversationId(args.conversationId ?? ""),
454
466
  providerDestinationId: destination.conversationId,
467
+ refreshVisibility: true,
455
468
  visibility: "direct",
456
469
  metadata: { platform: "local" }
457
470
  };
@@ -462,7 +475,15 @@ function executionStatusFromValue(value) {
462
475
  }
463
476
  throw new Error("Conversation record execution status is invalid");
464
477
  }
465
- function conversationFromRow(row) {
478
+ function privacyFromRow(row) {
479
+ if (row.destinationVisibility === null) {
480
+ return void 0;
481
+ }
482
+ return row.destinationVisibility === "public" ? "public" : "private";
483
+ }
484
+ function conversationFromRow(readRow) {
485
+ const row = readRow.conversation;
486
+ const visibility = privacyFromRow(readRow);
466
487
  if (row.schemaVersion !== 1) {
467
488
  throw new Error("Conversation record schema version is invalid");
468
489
  }
@@ -496,7 +517,8 @@ function conversationFromRow(row) {
496
517
  ...requester ? { requester } : {},
497
518
  ...row.channelName ? { channelName: row.channelName } : {},
498
519
  ...source ? { source } : {},
499
- ...row.title ? { title: row.title } : {}
520
+ ...row.title ? { title: row.title } : {},
521
+ ...visibility ? { visibility } : {}
500
522
  };
501
523
  }
502
524
  function emptyConversation(args) {
@@ -572,9 +594,10 @@ var SqlStore = class {
572
594
  nowMs,
573
595
  source: args.source
574
596
  });
597
+ const { visibility: _persisted, ...currentWithoutVisibility } = current2;
575
598
  await this.upsertConversation({
576
599
  conversation: {
577
- ...current2,
600
+ ...currentWithoutVisibility,
578
601
  destination: current2.destination ?? args.destination,
579
602
  source: current2.source ?? args.source,
580
603
  channelName: current2.channelName ?? args.channelName,
@@ -585,7 +608,8 @@ var SqlStore = class {
585
608
  execution: {
586
609
  ...current2.execution,
587
610
  updatedAtMs: current2.execution.updatedAtMs ?? nowMs
588
- }
611
+ },
612
+ ...args.visibility ? { visibility: args.visibility } : {}
589
613
  }
590
614
  });
591
615
  });
@@ -604,13 +628,15 @@ var SqlStore = class {
604
628
  ...args.requester ? { requester: args.requester } : {},
605
629
  ...args.source ? { source: args.source } : {},
606
630
  ...args.title ? { title: args.title } : {},
631
+ ...args.visibility ? { visibility: args.visibility } : {},
607
632
  execution: args.execution
608
633
  }
609
634
  });
610
635
  });
611
636
  }
612
637
  /** Copy one conversation record into SQL during backfill. */
613
- async backfillConversation(conversation) {
638
+ async backfillConversation(sourceConversation) {
639
+ const { visibility: _visibility, ...conversation } = sourceConversation;
614
640
  await this.withConversationMutation(
615
641
  conversation.conversationId,
616
642
  async () => {
@@ -646,7 +672,13 @@ var SqlStore = class {
646
672
  );
647
673
  }
648
674
  async listByActivity(args = {}) {
649
- const rows = await this.executor.db().select().from(juniorConversations).orderBy(
675
+ const rows = await this.executor.db().select({
676
+ conversation: juniorConversations,
677
+ destinationVisibility: juniorDestinations.visibility
678
+ }).from(juniorConversations).leftJoin(
679
+ juniorDestinations,
680
+ eq(juniorDestinations.id, juniorConversations.destinationId)
681
+ ).orderBy(
650
682
  desc(juniorConversations.lastActivityAt),
651
683
  asc(juniorConversations.conversationId)
652
684
  ).limit(Math.max(0, args.limit ?? 1e4)).offset(Math.max(0, args.offset ?? 0));
@@ -656,6 +688,28 @@ var SqlStore = class {
656
688
  }
657
689
  return conversations;
658
690
  }
691
+ async getDestinationVisibility(args) {
692
+ const rows = await this.executor.db().select({
693
+ visibility: juniorDestinations.visibility
694
+ }).from(juniorDestinations).where(
695
+ and(
696
+ eq(juniorDestinations.provider, args.provider),
697
+ eq(
698
+ juniorDestinations.providerTenantId,
699
+ tenantId(args.providerTenantId)
700
+ ),
701
+ eq(
702
+ juniorDestinations.providerDestinationId,
703
+ args.providerDestinationId
704
+ )
705
+ )
706
+ );
707
+ const row = rows[0];
708
+ if (!row) {
709
+ return void 0;
710
+ }
711
+ return row.visibility === "public" ? "public" : "private";
712
+ }
659
713
  /** Serialize all durable mutations for one conversation inside a SQL transaction. */
660
714
  async withConversationMutation(conversationId, callback) {
661
715
  return await this.executor.withLock(
@@ -664,7 +718,13 @@ var SqlStore = class {
664
718
  );
665
719
  }
666
720
  async readConversationRow(conversationId) {
667
- const rows = await this.executor.db().select().from(juniorConversations).where(eq(juniorConversations.conversationId, conversationId));
721
+ const rows = await this.executor.db().select({
722
+ conversation: juniorConversations,
723
+ destinationVisibility: juniorDestinations.visibility
724
+ }).from(juniorConversations).leftJoin(
725
+ juniorDestinations,
726
+ eq(juniorDestinations.id, juniorConversations.destinationId)
727
+ ).where(eq(juniorConversations.conversationId, conversationId));
668
728
  return rows[0];
669
729
  }
670
730
  /** Upsert the conversation row while preserving previously discovered nullable metadata fields. */
@@ -677,7 +737,8 @@ var SqlStore = class {
677
737
  destinationUpsertFromDestination({
678
738
  channelName: conversation.channelName,
679
739
  conversationId: conversation.conversationId,
680
- destination: conversation.destination
740
+ destination: conversation.destination,
741
+ ...conversation.visibility ? { visibility: conversation.visibility } : {}
681
742
  }),
682
743
  conversation.updatedAtMs
683
744
  );
@@ -779,6 +840,7 @@ var SqlStore = class {
779
840
  if (!destination) {
780
841
  return void 0;
781
842
  }
843
+ const visibilityUpdate = destination.refreshVisibility ? sql2`excluded.visibility` : juniorDestinations.visibility;
782
844
  const rows = await this.executor.db().insert(juniorDestinations).values({
783
845
  id: randomUUID(),
784
846
  provider: destination.provider,
@@ -800,7 +862,10 @@ var SqlStore = class {
800
862
  set: {
801
863
  kind: sql2`excluded.kind`,
802
864
  displayName: sql2`coalesce(excluded.display_name, ${juniorDestinations.displayName})`,
803
- visibility: sql2`excluded.visibility`,
865
+ // Signal-less writes insert as private but must not clobber an
866
+ // existing public/private value. Live source signals refresh this
867
+ // field so converted channels converge on the next message.
868
+ visibility: visibilityUpdate,
804
869
  metadata: sql2`coalesce(excluded.metadata_json, ${juniorDestinations.metadata})`,
805
870
  updatedAt: sql2`excluded.updated_at`
806
871
  }
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  destinationKey,
6
6
  parseDestination
7
- } from "./chunk-C2PSUWK3.js";
7
+ } from "./chunk-GGD6WK6V.js";
8
8
 
9
9
  // src/chat/task-execution/queue-signing.ts
10
10
  import { createHmac, timingSafeEqual } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getConversationStore
3
- } from "./chunk-QTTTRBNB.js";
3
+ } from "./chunk-6I6HBOQM.js";
4
4
  import {
5
5
  SANDBOX_DATA_ROOT,
6
6
  SANDBOX_WORKSPACE_ROOT,
@@ -9,16 +9,16 @@ import {
9
9
  import {
10
10
  getConnectedStateContext,
11
11
  getStateAdapter
12
- } from "./chunk-RUB77TGS.js";
12
+ } from "./chunk-GB5DFM4D.js";
13
13
  import {
14
14
  parseDestination
15
- } from "./chunk-C2PSUWK3.js";
15
+ } from "./chunk-GGD6WK6V.js";
16
16
  import {
17
17
  TURN_CONTEXT_TAG,
18
18
  botConfig,
19
19
  escapeXml,
20
20
  getChatConfig
21
- } from "./chunk-BU2AWPEN.js";
21
+ } from "./chunk-ZU2ALUVQ.js";
22
22
  import {
23
23
  parseRequester,
24
24
  storedSlackRequesterSchema,
@@ -659,16 +659,28 @@ async function commitMessages(args) {
659
659
  };
660
660
  }
661
661
 
662
- // src/chat/prompt.ts
663
- import fs from "fs";
664
- import path from "path";
665
-
666
662
  // src/chat/interruption-marker.ts
667
663
  var INTERRUPTED_MARKER = "\n\n[Response interrupted before completion]";
668
664
  function getInterruptionMarker() {
669
665
  return INTERRUPTED_MARKER;
670
666
  }
671
667
 
668
+ // src/chat/prompt.ts
669
+ import fs from "fs";
670
+ import path from "path";
671
+
672
+ // src/chat/no-reply.ts
673
+ var NO_REPLY_MARKER = "[[NO_REPLY]]";
674
+ function isNoReplyMarker(text) {
675
+ return text.trim() === NO_REPLY_MARKER;
676
+ }
677
+ function containsNoReplyMarker(text) {
678
+ return text.includes(NO_REPLY_MARKER);
679
+ }
680
+ function stripNoReplyMarker(text) {
681
+ return text.replaceAll(NO_REPLY_MARKER, "").trim();
682
+ }
683
+
672
684
  // src/chat/slack/status-format.ts
673
685
  var SLACK_STATUS_MAX_LENGTH = 50;
674
686
  function truncateStatusText(text) {
@@ -1360,12 +1372,10 @@ var CONVERSATION_RULES = [
1360
1372
  "- Runtime owns continuation and authorization notices; on resumed turns, answer with the final requested content only."
1361
1373
  ];
1362
1374
  var SLACK_ACTION_RULES = [
1363
- "- Context-bound Slack tools use runtime-owned targets; do not invent channel, canvas, list, or message IDs.",
1364
- "- Use first-class Slack tools for Slack side effects; do not use bash, curl, or provider APIs to bypass Slack tool targeting.",
1365
- "- Use channel-post and emoji-reaction tools only when the user explicitly asks for that Slack side effect.",
1366
- "- For explicit channel-post or emoji-reaction requests, skip a duplicate thread text reply when the tool result already satisfies the request.",
1367
- "- Do not claim an attachment, canvas, channel post, list update, or reaction succeeded unless the tool returned success this turn; when it did, include any link the tool returned.",
1368
- "- Do not use reactions as progress indicators."
1375
+ "- Slack tools target the current runtime context; if the requested Slack target differs, explain the limitation instead of calling the tool.",
1376
+ "- Use channel-post and emoji-reaction tools only for explicit user-requested Slack side effects.",
1377
+ "- Ambient reaction requests target the current inbound message; do not ask for a message reference.",
1378
+ `- Side-effect-only completion for channel posts or reactions: call the requested tool first; if it succeeds and fully satisfies the request, final message must be exactly ${NO_REPLY_MARKER}.`
1369
1379
  ];
1370
1380
  var SAFETY_RULES = [
1371
1381
  "- Stay within the user's request and the runtime's available capabilities; do not pursue independent goals, persistence, replication, credential gathering, or access expansion.",
@@ -1416,7 +1426,7 @@ function buildOutputSection(platform) {
1416
1426
  "- Use Slack-flavored Markdown: **bold** section labels, `code`, [text](url) links, bullet lists, and fenced code blocks. No hash-prefixed headings and no tables. When the answer primarily lists several URLs, show each URL bare instead of as a labeled link.",
1417
1427
  "- Keep replies brief and scannable; use bullets or short code blocks when helpful, and one compact thread reply when it fits.",
1418
1428
  "- When a research or document-style answer would benefit from continuation, multiple sections, or future reference value, create a Slack canvas and keep the thread reply to one or two short sentences plus the link; do not recap the canvas contents.",
1419
- "- Unless a successful Slack side-effect tool intentionally satisfied the request by itself, end every turn with a final user-facing markdown response.",
1429
+ "- End every turn with a final user-facing markdown response unless the Slack action rules allow a side-effect-only completion.",
1420
1430
  "</output>"
1421
1431
  ].join("\n");
1422
1432
  }
@@ -1847,7 +1857,8 @@ async function recordConversationActivityMetadata(args) {
1847
1857
  destination: args.summary.destination,
1848
1858
  nowMs: args.nowMs,
1849
1859
  requester: sessionLogRequester(args.summary.requester),
1850
- source
1860
+ source,
1861
+ visibility: args.destinationVisibility
1851
1862
  });
1852
1863
  await conversationStore.recordExecution({
1853
1864
  channelName: args.summary.channelName,
@@ -1858,7 +1869,8 @@ async function recordConversationActivityMetadata(args) {
1858
1869
  lastActivityAtMs: args.summary.updatedAtMs,
1859
1870
  requester: sessionLogRequester(args.summary.requester),
1860
1871
  source,
1861
- updatedAtMs: args.nowMs
1872
+ updatedAtMs: args.nowMs,
1873
+ visibility: args.destinationVisibility
1862
1874
  });
1863
1875
  } catch (error) {
1864
1876
  logWarn(
@@ -1998,6 +2010,7 @@ async function setStoredRecord(args) {
1998
2010
  await appendAgentTurnSessionSummary(summary, args.ttlMs);
1999
2011
  await recordConversationActivityMetadata({
2000
2012
  conversationStore: args.conversationStore,
2013
+ destinationVisibility: args.destinationVisibility,
2001
2014
  nowMs: Date.now(),
2002
2015
  summary
2003
2016
  });
@@ -2054,6 +2067,7 @@ async function upsertAgentTurnSessionRecord(args) {
2054
2067
  });
2055
2068
  return await setStoredRecord({
2056
2069
  conversationStore: args.conversationStore,
2070
+ destinationVisibility: args.destinationVisibility,
2057
2071
  piMessages: args.piMessages,
2058
2072
  ttlMs,
2059
2073
  record: buildStoredRecord({
@@ -2118,6 +2132,7 @@ async function recordAgentTurnSessionSummary(args) {
2118
2132
  await appendAgentTurnSessionSummary(summary, ttlMs);
2119
2133
  await recordConversationActivityMetadata({
2120
2134
  conversationStore: args.conversationStore,
2135
+ destinationVisibility: args.destinationVisibility,
2121
2136
  nowMs,
2122
2137
  summary
2123
2138
  });
@@ -2180,6 +2195,9 @@ async function failAgentTurnSessionRecord(args) {
2180
2195
  }
2181
2196
 
2182
2197
  export {
2198
+ isNoReplyMarker,
2199
+ containsNoReplyMarker,
2200
+ stripNoReplyMarker,
2183
2201
  getInterruptionMarker,
2184
2202
  truncateStatusText,
2185
2203
  normalizeSlackStatusText,