@sentry/junior 0.86.0 → 0.88.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 (61) hide show
  1. package/dist/{agent-hooks-NWOUB3UR.js → agent-hooks-RIJ5TSWP.js} +8 -8
  2. package/dist/api/people/list.d.ts +4 -0
  3. package/dist/api/people/list.js +83 -0
  4. package/dist/api/people/list.query.d.ts +4 -0
  5. package/dist/api/people/profile.d.ts +4 -0
  6. package/dist/api/people/profile.js +131 -0
  7. package/dist/api/people/profile.query.d.ts +4 -0
  8. package/dist/api/people/shared.d.ts +76 -0
  9. package/dist/api/people/types.d.ts +85 -0
  10. package/dist/app.js +45 -74
  11. package/dist/{catalog-runtime-XOD7YPRS.js → catalog-runtime-MW7XERSU.js} +3 -3
  12. package/dist/chat/conversations/sql/migrations.d.ts +1 -1
  13. package/dist/chat/conversations/sql/schema/identities.d.ts +54 -3
  14. package/dist/chat/conversations/sql/schema/users.d.ts +109 -0
  15. package/dist/chat/conversations/sql/schema.d.ts +164 -3
  16. package/dist/chat/conversations/sql/store.d.ts +0 -1
  17. package/dist/chat/identities/identity.d.ts +18 -0
  18. package/dist/chat/identities/sql.d.ts +4 -0
  19. package/dist/chat/no-reply.d.ts +7 -0
  20. package/dist/chat/runtime/processing-reaction.d.ts +2 -1
  21. package/dist/chat/runtime/slack-resume.d.ts +3 -2
  22. package/dist/chat/runtime/thread-context.d.ts +3 -1
  23. package/dist/chat/runtime/turn-user-message.d.ts +2 -1
  24. package/dist/chat/services/conversation-memory.d.ts +3 -1
  25. package/dist/chat/services/reply-delivery-plan.d.ts +0 -4
  26. package/dist/chat/slack/message.d.ts +2 -1
  27. package/dist/chat/slack/outbound.d.ts +5 -4
  28. package/dist/chat/slack/timestamp.d.ts +6 -0
  29. package/dist/chat/sql/schema.d.ts +163 -3
  30. package/dist/chat/tools/slack/context.d.ts +2 -1
  31. package/dist/{chunk-ENPSU7L7.js → chunk-2DPZRS3B.js} +4 -4
  32. package/dist/{chunk-6I6HBOQM.js → chunk-4IXHIV37.js} +413 -157
  33. package/dist/{chunk-JRXCSSSU.js → chunk-6UPQ5GTJ.js} +3 -3
  34. package/dist/{chunk-64ACM6AP.js → chunk-7ES37H6U.js} +2 -2
  35. package/dist/{chunk-GGD6WK6V.js → chunk-AHLSXMOU.js} +2 -2
  36. package/dist/{chunk-2TAIGJPQ.js → chunk-C5NCV3OB.js} +1 -1
  37. package/dist/{chunk-6O5UI3RG.js → chunk-F22AM3OW.js} +1 -1
  38. package/dist/{chunk-BRSQQRG6.js → chunk-IATAYWFU.js} +2 -2
  39. package/dist/{chunk-BQ3ITJA6.js → chunk-KBFQXJL4.js} +2 -2
  40. package/dist/{chunk-37B2R2QJ.js → chunk-KBSLCOGE.js} +28 -15
  41. package/dist/{chunk-IXTBFABZ.js → chunk-KQKIA4CU.js} +1 -1
  42. package/dist/{chunk-FPHA6GCQ.js → chunk-NYJLQI42.js} +95 -92
  43. package/dist/chunk-PBV4ZIVM.js +261 -0
  44. package/dist/{chunk-ZU2ALUVQ.js → chunk-S35CPNPT.js} +1 -1
  45. package/dist/{chunk-RIB3M6YA.js → chunk-V6XDCS3X.js} +4 -4
  46. package/dist/{chunk-KF7522P3.js → chunk-VMBZFPZM.js} +11 -1
  47. package/dist/{chunk-2NFV5FMB.js → chunk-XS6NLQPA.js} +21 -12
  48. package/dist/{chunk-GB5DFM4D.js → chunk-YPAE5RH3.js} +1 -1
  49. package/dist/cli/chat.js +6 -6
  50. package/dist/cli/check.js +4 -4
  51. package/dist/cli/plugins.js +11 -11
  52. package/dist/cli/snapshot-warmup.js +6 -6
  53. package/dist/cli/upgrade.js +12 -12
  54. package/dist/{db-SZVUU7RB.js → db-37HOGLI7.js} +5 -5
  55. package/dist/nitro.js +4 -4
  56. package/dist/reporting/conversations.d.ts +0 -56
  57. package/dist/reporting.d.ts +2 -8
  58. package/dist/reporting.js +14 -290
  59. package/dist/{runner-HEBRPNN2.js → runner-BCRF2FCI.js} +13 -13
  60. package/dist/{validation-MBNJKWPQ.js → validation-FMJO3L5P.js} +4 -4
  61. package/package.json +14 -6
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  getStateAdapter
3
- } from "./chunk-GB5DFM4D.js";
3
+ } from "./chunk-YPAE5RH3.js";
4
4
  import {
5
5
  normalizeSlackConversationId
6
- } from "./chunk-GGD6WK6V.js";
6
+ } from "./chunk-AHLSXMOU.js";
7
7
  import {
8
8
  parseSlackThreadId
9
9
  } from "./chunk-L7OHKDOX.js";
10
10
  import {
11
11
  parseStoredSlackRequester
12
- } from "./chunk-IXTBFABZ.js";
12
+ } from "./chunk-KQKIA4CU.js";
13
13
  import {
14
14
  isRecord,
15
15
  toOptionalNumber
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-BQ3ITJA6.js";
3
+ } from "./chunk-KBFQXJL4.js";
4
4
  import {
5
5
  skillRoots
6
6
  } from "./chunk-6APU57E6.js";
7
7
  import {
8
8
  logWarn
9
- } from "./chunk-KF7522P3.js";
9
+ } from "./chunk-VMBZFPZM.js";
10
10
 
11
11
  // src/chat/skills.ts
12
12
  import fs from "fs/promises";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getSlackBotToken
3
- } from "./chunk-ZU2ALUVQ.js";
3
+ } from "./chunk-S35CPNPT.js";
4
4
  import {
5
5
  isSlackConversationId,
6
6
  isSlackTeamId,
@@ -8,7 +8,7 @@ import {
8
8
  setSpanAttributes,
9
9
  setSpanStatus,
10
10
  withSpan
11
- } from "./chunk-KF7522P3.js";
11
+ } from "./chunk-VMBZFPZM.js";
12
12
 
13
13
  // src/chat/slack/client.ts
14
14
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-BQ3ITJA6.js";
3
+ } from "./chunk-KBFQXJL4.js";
4
4
 
5
5
  // src/chat/plugins/validation.ts
6
6
  import { isDeepStrictEqual } from "util";
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  destinationKey,
6
6
  parseDestination
7
- } from "./chunk-GGD6WK6V.js";
7
+ } from "./chunk-AHLSXMOU.js";
8
8
 
9
9
  // src/chat/task-execution/queue-signing.ts
10
10
  import { createHmac, timingSafeEqual } from "crypto";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  getStateAdapter
3
- } from "./chunk-GB5DFM4D.js";
3
+ } from "./chunk-YPAE5RH3.js";
4
4
  import {
5
5
  logException,
6
6
  logInfo,
7
7
  logWarn
8
- } from "./chunk-KF7522P3.js";
8
+ } from "./chunk-VMBZFPZM.js";
9
9
 
10
10
  // src/chat/plugins/logging.ts
11
11
  function createPluginLogger(plugin) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseActorUserId
3
- } from "./chunk-IXTBFABZ.js";
3
+ } from "./chunk-KQKIA4CU.js";
4
4
  import {
5
5
  discoverInstalledPluginPackageContent,
6
6
  normalizePluginPackageNames,
@@ -10,7 +10,7 @@ import {
10
10
  logInfo,
11
11
  logWarn,
12
12
  setSpanAttributes
13
- } from "./chunk-KF7522P3.js";
13
+ } from "./chunk-VMBZFPZM.js";
14
14
 
15
15
  // src/chat/plugins/registry.ts
16
16
  import { readFileSync, readdirSync, statSync } from "fs";
@@ -1,6 +1,3 @@
1
- import {
2
- getConversationStore
3
- } from "./chunk-6I6HBOQM.js";
4
1
  import {
5
2
  SANDBOX_DATA_ROOT,
6
3
  SANDBOX_WORKSPACE_ROOT,
@@ -9,21 +6,24 @@ import {
9
6
  import {
10
7
  getConnectedStateContext,
11
8
  getStateAdapter
12
- } from "./chunk-GB5DFM4D.js";
9
+ } from "./chunk-YPAE5RH3.js";
10
+ import {
11
+ getConversationStore
12
+ } from "./chunk-4IXHIV37.js";
13
13
  import {
14
14
  parseDestination
15
- } from "./chunk-GGD6WK6V.js";
15
+ } from "./chunk-AHLSXMOU.js";
16
16
  import {
17
17
  TURN_CONTEXT_TAG,
18
18
  botConfig,
19
19
  escapeXml,
20
20
  getChatConfig
21
- } from "./chunk-ZU2ALUVQ.js";
21
+ } from "./chunk-S35CPNPT.js";
22
22
  import {
23
23
  parseRequester,
24
24
  storedSlackRequesterSchema,
25
25
  toStoredSlackRequester
26
- } from "./chunk-IXTBFABZ.js";
26
+ } from "./chunk-KQKIA4CU.js";
27
27
  import {
28
28
  listReferenceFiles,
29
29
  soulPathCandidates,
@@ -32,7 +32,7 @@ import {
32
32
  import {
33
33
  logInfo,
34
34
  logWarn
35
- } from "./chunk-KF7522P3.js";
35
+ } from "./chunk-VMBZFPZM.js";
36
36
  import {
37
37
  isRecord
38
38
  } from "./chunk-FTMXFBDC.js";
@@ -669,6 +669,18 @@ function getInterruptionMarker() {
669
669
  import fs from "fs";
670
670
  import path from "path";
671
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
  }
@@ -2185,6 +2195,9 @@ async function failAgentTurnSessionRecord(args) {
2185
2195
  }
2186
2196
 
2187
2197
  export {
2198
+ isNoReplyMarker,
2199
+ containsNoReplyMarker,
2200
+ stripNoReplyMarker,
2188
2201
  getInterruptionMarker,
2189
2202
  truncateStatusText,
2190
2203
  normalizeSlackStatusText,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isSlackTeamId
3
- } from "./chunk-KF7522P3.js";
3
+ } from "./chunk-VMBZFPZM.js";
4
4
 
5
5
  // src/chat/requester.ts
6
6
  import { z } from "zod";
@@ -10,7 +10,7 @@ import {
10
10
  isSnapshotMissingError,
11
11
  resolveRuntimeDependencySnapshot,
12
12
  runNonInteractiveCommand
13
- } from "./chunk-RIB3M6YA.js";
13
+ } from "./chunk-V6XDCS3X.js";
14
14
  import {
15
15
  pluginTaskId,
16
16
  pluginTaskParamsSchema,
@@ -22,16 +22,19 @@ import {
22
22
  buildPluginSystemPromptContributions,
23
23
  buildSystemPrompt,
24
24
  buildTurnContextPrompt,
25
+ containsNoReplyMarker,
25
26
  getAgentTurnSessionRecord,
26
27
  getInterruptionMarker,
28
+ isNoReplyMarker,
27
29
  loadConnectedMcpProviders,
28
30
  recordAuthorizationRequested,
29
31
  recordMcpProviderConnected,
30
32
  recordSubagentEnded,
31
33
  recordSubagentStarted,
32
34
  recordToolExecutionStarted,
35
+ stripNoReplyMarker,
33
36
  upsertAgentTurnSessionRecord
34
- } from "./chunk-37B2R2QJ.js";
37
+ } from "./chunk-KBSLCOGE.js";
35
38
  import {
36
39
  createPluginEmbedder,
37
40
  createPluginHookRunner,
@@ -41,16 +44,13 @@ import {
41
44
  getPluginUserPromptContributions,
42
45
  getPlugins,
43
46
  getSlackToolContext,
47
+ parseSlackMessageTs,
44
48
  resolveChannelCapabilities
45
- } from "./chunk-2NFV5FMB.js";
49
+ } from "./chunk-XS6NLQPA.js";
46
50
  import {
47
51
  createPluginLogger,
48
52
  createPluginState
49
- } from "./chunk-BRSQQRG6.js";
50
- import {
51
- getConversationStore,
52
- getDb
53
- } from "./chunk-6I6HBOQM.js";
53
+ } from "./chunk-IATAYWFU.js";
54
54
  import {
55
55
  SANDBOX_DATA_ROOT,
56
56
  SANDBOX_SKILLS_ROOT,
@@ -61,7 +61,11 @@ import {
61
61
  import {
62
62
  acquireActiveLock,
63
63
  getStateAdapter
64
- } from "./chunk-GB5DFM4D.js";
64
+ } from "./chunk-YPAE5RH3.js";
65
+ import {
66
+ getConversationStore,
67
+ getDb
68
+ } from "./chunk-4IXHIV37.js";
65
69
  import {
66
70
  SlackActionError,
67
71
  downloadPrivateSlackFile,
@@ -72,7 +76,7 @@ import {
72
76
  normalizeSlackConversationId,
73
77
  parseDestination,
74
78
  withSlackRetries
75
- } from "./chunk-GGD6WK6V.js";
79
+ } from "./chunk-AHLSXMOU.js";
76
80
  import {
77
81
  GEN_AI_PROVIDER_NAME,
78
82
  GEN_AI_SERVER_ADDRESS,
@@ -108,7 +112,7 @@ import {
108
112
  toObservablePromptPart,
109
113
  trimTrailingAssistantMessages,
110
114
  upsertActiveSkill
111
- } from "./chunk-ZU2ALUVQ.js";
115
+ } from "./chunk-S35CPNPT.js";
112
116
  import {
113
117
  parseSlackThreadId,
114
118
  resolveConversationPrivacy,
@@ -124,18 +128,18 @@ import {
124
128
  findSkillByName,
125
129
  loadSkillsByName,
126
130
  parseSkillInvocation
127
- } from "./chunk-64ACM6AP.js";
131
+ } from "./chunk-7ES37H6U.js";
128
132
  import {
129
133
  CredentialUnavailableError,
130
134
  credentialContextSchema,
131
135
  pluginCatalogRuntime,
132
136
  resolveAuthTokenPlaceholder,
133
137
  resolvePluginCommandEnv
134
- } from "./chunk-BQ3ITJA6.js";
138
+ } from "./chunk-KBFQXJL4.js";
135
139
  import {
136
140
  createRequester,
137
141
  parseActorUserId
138
- } from "./chunk-IXTBFABZ.js";
142
+ } from "./chunk-KQKIA4CU.js";
139
143
  import {
140
144
  listReferenceFiles
141
145
  } from "./chunk-6APU57E6.js";
@@ -156,7 +160,7 @@ import {
156
160
  setSpanStatus,
157
161
  setTags,
158
162
  withSpan
159
- } from "./chunk-KF7522P3.js";
163
+ } from "./chunk-VMBZFPZM.js";
160
164
  import {
161
165
  isRecord,
162
166
  toOptionalString
@@ -4863,7 +4867,7 @@ function requireSlackThreadTimestamp(threadTs, action) {
4863
4867
  return normalized;
4864
4868
  }
4865
4869
  function requireSlackMessageTimestamp(timestamp, action) {
4866
- const normalized = timestamp.trim();
4870
+ const normalized = parseSlackMessageTs(timestamp);
4867
4871
  if (!normalized) {
4868
4872
  throw new Error(`${action} requires a target message timestamp`);
4869
4873
  }
@@ -4930,44 +4934,20 @@ async function postSlackMessage(input) {
4930
4934
  }
4931
4935
  }
4932
4936
  );
4933
- if (!response.ts) {
4937
+ const messageTs = parseSlackMessageTs(response.ts);
4938
+ if (!messageTs) {
4934
4939
  throw new Error("Slack message posted without ts");
4935
4940
  }
4936
4941
  return {
4937
- ts: response.ts,
4942
+ ts: messageTs,
4938
4943
  ...input.includePermalink ? {
4939
4944
  permalink: await getPermalinkBestEffort({
4940
4945
  channelId,
4941
- messageTs: response.ts
4946
+ messageTs
4942
4947
  })
4943
4948
  } : {}
4944
4949
  };
4945
4950
  }
4946
- async function deleteSlackMessage(input) {
4947
- const channelId = requireSlackConversationId(
4948
- input.channelId,
4949
- "Slack message deletion"
4950
- );
4951
- const timestamp = requireSlackMessageTimestamp(
4952
- input.timestamp,
4953
- "Slack message deletion"
4954
- );
4955
- await withSlackRetries(
4956
- () => getSlackClient().chat.delete({
4957
- channel: channelId,
4958
- ts: timestamp
4959
- }),
4960
- 3,
4961
- {
4962
- action: "chat.delete",
4963
- idempotent: true,
4964
- spanAttributes: {
4965
- "app.slack.channel_id": channelId,
4966
- "app.slack.message_ts": timestamp
4967
- }
4968
- }
4969
- );
4970
- }
4971
4951
  async function postSlackEphemeralMessage(input) {
4972
4952
  const channelId = requireSlackConversationId(
4973
4953
  input.channelId,
@@ -5144,7 +5124,7 @@ function createOperationKey(toolName, input) {
5144
5124
  // src/chat/tools/slack/channel-post-message.ts
5145
5125
  function createSlackChannelPostMessageTool(context, state) {
5146
5126
  return tool({
5147
- description: "Post a new top-level message to the current Slack channel. Use only when the user explicitly asks to post/send/share/say something to the channel. Do not use for thread replies, inline @mentions, or pinging mentioned users.",
5127
+ description: "Post a new top-level message to the current Slack channel. Use only when the user explicitly asks to post/send/share/say something to the current channel. Do not use for other named channels, thread replies, inline @mentions, or pinging mentioned users.",
5148
5128
  inputSchema: Type15.Object({
5149
5129
  text: Type15.String({
5150
5130
  minLength: 1,
@@ -5189,7 +5169,7 @@ function createSlackChannelPostMessageTool(context, state) {
5189
5169
  import { Type as Type16 } from "@sinclair/typebox";
5190
5170
  function createSlackMessageAddReactionTool(context, state) {
5191
5171
  return tool({
5192
- description: "Add an emoji reaction to the current inbound Slack message. Use sparingly for lightweight acknowledgements. Provide a Slack emoji alias name (for example `thumbsup`, `white_check_mark`, or `thumbsup::skin-tone-6`), not a unicode emoji glyph. The target message is injected by runtime context; do not use this for arbitrary historical messages.",
5172
+ description: "Add an emoji reaction to the current inbound Slack message. Use when the user asks for a reaction on the current message without another target. Provide a Slack emoji alias name (for example `thumbsup`, `white_check_mark`, or `thumbsup::skin-tone-6`), not a unicode emoji glyph. The target message is injected by runtime context; do not use this for arbitrary historical messages.",
5193
5173
  inputSchema: Type16.Object({
5194
5174
  emoji: Type16.String({
5195
5175
  minLength: 1,
@@ -5201,17 +5181,15 @@ function createSlackMessageAddReactionTool(context, state) {
5201
5181
  const targetChannelId = context.sourceChannelId;
5202
5182
  const targetMessageTs = context.messageTs;
5203
5183
  if (!targetMessageTs) {
5204
- return {
5205
- ok: false,
5206
- error: "No active message timestamp is available for reactions"
5207
- };
5184
+ throw new ToolInputError(
5185
+ "No active message timestamp is available for reactions."
5186
+ );
5208
5187
  }
5209
5188
  const normalizedEmoji = normalizeSlackEmojiName(emoji);
5210
5189
  if (!normalizedEmoji) {
5211
- return {
5212
- ok: false,
5213
- error: "Emoji must be a valid Slack emoji alias name (for example `thumbsup` or `thumbsup::skin-tone-6`)"
5214
- };
5190
+ throw new ToolInputError(
5191
+ "Emoji must be a valid Slack emoji alias name (for example `thumbsup` or `thumbsup::skin-tone-6`)."
5192
+ );
5215
5193
  }
5216
5194
  const operationKey = createOperationKey("slackMessageAddReaction", {
5217
5195
  channel_id: targetChannelId,
@@ -10955,33 +10933,6 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
10955
10933
  }
10956
10934
 
10957
10935
  // src/chat/services/reply-delivery-plan.ts
10958
- var REACTION_ONLY_ACK_RE = /^(?::[a-z0-9_+-]+:|[\p{Extended_Pictographic}\uFE0F\u200D]+)$/u;
10959
- var REDUNDANT_REACTION_ACK_TEXT = ["done", "got it", "ok", "okay"];
10960
- var REACTION_INTENT_RE = /\b(react|reaction|emoji|thumbs?\s*up|acknowledge)\b/i;
10961
- var REACTION_WITH_REPLY_INTENT_RE = /\b(confirm|explain|reply|respond|say|tell|summari[sz]e|why)\b/i;
10962
- function normalizeReactionAckText(text) {
10963
- return text.trim().toLowerCase().replace(/[!.]+$/g, "");
10964
- }
10965
- function isRedundantReactionAckText(text) {
10966
- const trimmed = text.trim();
10967
- if (!trimmed) {
10968
- return false;
10969
- }
10970
- if (REACTION_ONLY_ACK_RE.test(trimmed)) {
10971
- return true;
10972
- }
10973
- const normalized = normalizeReactionAckText(text);
10974
- return REDUNDANT_REACTION_ACK_TEXT.includes(
10975
- normalized
10976
- );
10977
- }
10978
- function isReactionOnlyIntent(text) {
10979
- const normalized = text.trim();
10980
- if (!normalized) {
10981
- return false;
10982
- }
10983
- return REACTION_INTENT_RE.test(normalized) && !REACTION_WITH_REPLY_INTENT_RE.test(normalized);
10984
- }
10985
10936
  function buildReplyDeliveryPlan(args) {
10986
10937
  const mode = args.explicitChannelPostIntent && args.channelPostPerformed ? "channel_only" : "thread";
10987
10938
  let attachFiles = "none";
@@ -11095,9 +11046,12 @@ function buildTurnResult(input) {
11095
11046
  const toolResults = newMessages.filter(isToolResultMessage);
11096
11047
  const assistantMessages = newMessages.filter(isAssistantMessage);
11097
11048
  const terminalAssistantMessages = getTerminalAssistantMessages(newMessages);
11098
- const primaryText = stripThinkingXmlBlocks(
11049
+ const rawPrimaryText = stripThinkingXmlBlocks(
11099
11050
  terminalAssistantMessages.map((message) => extractAssistantText(message)).join("\n\n")
11100
11051
  ).trim();
11052
+ const exactNoReplyMarker = isNoReplyMarker(rawPrimaryText);
11053
+ const mixedNoReplyMarker = !exactNoReplyMarker && containsNoReplyMarker(rawPrimaryText);
11054
+ const primaryText = exactNoReplyMarker ? "" : mixedNoReplyMarker ? stripNoReplyMarker(rawPrimaryText) : rawPrimaryText;
11101
11055
  const toolErrorCount = toolResults.filter((result) => result.isError).length;
11102
11056
  const explicitChannelPostIntent = isExplicitChannelPostIntent(userInput);
11103
11057
  const successfulToolNames = new Set(
@@ -11108,17 +11062,67 @@ function buildTurnResult(input) {
11108
11062
  );
11109
11063
  const canvasCreated = successfulToolNames.has("slackCanvasCreate");
11110
11064
  const reactionPerformed = successfulToolNames.has("slackMessageAddReaction");
11065
+ const markerSideEffectSuccess = exactNoReplyMarker && toolErrorCount === 0 && (reactionPerformed || channelPostPerformed || replyFiles.length > 0);
11066
+ const fileOnlySuccess = !rawPrimaryText && toolErrorCount === 0 && replyFiles.length > 0;
11067
+ const sideEffectOnlySuccess = markerSideEffectSuccess || fileOnlySuccess;
11111
11068
  const baseDeliveryPlan = buildReplyDeliveryPlan({
11112
- explicitChannelPostIntent,
11069
+ explicitChannelPostIntent: exactNoReplyMarker && explicitChannelPostIntent,
11113
11070
  channelPostPerformed,
11114
11071
  hasFiles: replyFiles.length > 0
11115
11072
  });
11116
- const sideEffectOnlySuccess = !primaryText && toolErrorCount === 0 && (reactionPerformed || channelPostPerformed || replyFiles.length > 0);
11117
11073
  const lastAssistant = terminalAssistantMessages.at(-1);
11118
11074
  const stopReason = typeof lastAssistant?.stopReason === "string" ? lastAssistant.stopReason : void 0;
11119
11075
  const errorMessage = typeof lastAssistant?.errorMessage === "string" ? lastAssistant.errorMessage : void 0;
11120
11076
  const isProviderError = stopReason === "error";
11121
- if (!primaryText && !sideEffectOnlySuccess && !isProviderError) {
11077
+ if (exactNoReplyMarker) {
11078
+ const markerCategory = reactionPerformed ? "reaction" : channelPostPerformed ? "channel_post" : replyFiles.length > 0 ? "file" : "none";
11079
+ const markerContext = {
11080
+ slackThreadId: correlation?.threadId,
11081
+ slackUserId: correlation?.requesterId,
11082
+ slackChannelId: correlation?.channelId,
11083
+ runId: correlation?.runId,
11084
+ assistantUserName,
11085
+ modelId: botConfig.modelId
11086
+ };
11087
+ const markerAttributes = {
11088
+ "app.ai.no_reply_marker": true,
11089
+ "app.ai.no_reply_marker_category": markerCategory,
11090
+ "app.ai.no_reply_marker_accepted": sideEffectOnlySuccess && !isProviderError
11091
+ };
11092
+ if (sideEffectOnlySuccess && !isProviderError) {
11093
+ logInfo(
11094
+ "ai_no_reply_marker_accepted",
11095
+ markerContext,
11096
+ markerAttributes,
11097
+ "No-reply marker suppressed visible thread text"
11098
+ );
11099
+ } else if (!isProviderError) {
11100
+ logWarn(
11101
+ "ai_no_reply_marker_rejected",
11102
+ markerContext,
11103
+ markerAttributes,
11104
+ "No-reply marker requires a successful visible side effect"
11105
+ );
11106
+ }
11107
+ } else if (mixedNoReplyMarker) {
11108
+ logWarn(
11109
+ "ai_no_reply_marker_mixed_text",
11110
+ {
11111
+ slackThreadId: correlation?.threadId,
11112
+ slackUserId: correlation?.requesterId,
11113
+ slackChannelId: correlation?.channelId,
11114
+ runId: correlation?.runId,
11115
+ assistantUserName,
11116
+ modelId: botConfig.modelId
11117
+ },
11118
+ {
11119
+ "app.ai.no_reply_marker": true,
11120
+ "app.ai.no_reply_marker_mode": "mixed"
11121
+ },
11122
+ "No-reply marker appeared with visible assistant text"
11123
+ );
11124
+ }
11125
+ if (!primaryText && !sideEffectOnlySuccess && !isProviderError && !exactNoReplyMarker) {
11122
11126
  logWarn(
11123
11127
  "ai_model_response_empty",
11124
11128
  {
@@ -11137,7 +11141,7 @@ function buildTurnResult(input) {
11137
11141
  "Model returned empty text response"
11138
11142
  );
11139
11143
  }
11140
- const usedPrimaryText = Boolean(primaryText);
11144
+ const usedPrimaryText = Boolean(rawPrimaryText);
11141
11145
  let outcome;
11142
11146
  if (isProviderError) {
11143
11147
  outcome = "provider_error";
@@ -11146,8 +11150,7 @@ function buildTurnResult(input) {
11146
11150
  } else {
11147
11151
  outcome = "execution_failure";
11148
11152
  }
11149
- const suppressReactionOnlyText = reactionPerformed && !channelPostPerformed && replyFiles.length === 0 && Boolean(primaryText) && isReactionOnlyIntent(userInput);
11150
- const rawResponseText = suppressReactionOnlyText ? "" : primaryText;
11153
+ const rawResponseText = primaryText;
11151
11154
  const responseText = canvasCreated && isVerbosePostCanvasReply(rawResponseText) ? buildBriefPostCanvasReply(artifactStatePatch) : rawResponseText;
11152
11155
  const escapedOrRawPayload = Boolean(primaryText) && (isExecutionEscapeResponse(primaryText) || isRawToolPayloadResponse(primaryText));
11153
11156
  const resolvedText = escapedOrRawPayload ? "" : enforceAttachmentClaimTruth(responseText, replyFiles.length > 0);
@@ -14627,7 +14630,7 @@ function isHumanConversationMessage(message) {
14627
14630
  return message.role === "user" && message.author?.isBot !== true;
14628
14631
  }
14629
14632
  function getConversationMessageSlackTs(message) {
14630
- return message.meta?.slackTs ?? toOptionalString(message.id);
14633
+ return parseSlackMessageTs(message.meta?.slackTs);
14631
14634
  }
14632
14635
 
14633
14636
  // src/chat/services/turn-failure-response.ts
@@ -14911,6 +14914,7 @@ async function processPluginTask(message, options = {}) {
14911
14914
  }
14912
14915
 
14913
14916
  // src/chat/runtime/delivered-turn-state.ts
14917
+ var NO_VISIBLE_REPLY_CONVERSATION_TEXT = "[no visible reply]";
14914
14918
  function buildDeliveredTurnStatePatch(args) {
14915
14919
  const conversation = structuredClone(args.conversation);
14916
14920
  const artifactStatePatch = {
@@ -14919,6 +14923,7 @@ function buildDeliveredTurnStatePatch(args) {
14919
14923
  };
14920
14924
  const artifacts = Object.keys(artifactStatePatch).length > 0 ? mergeArtifactsState(args.artifacts, artifactStatePatch) : void 0;
14921
14925
  clearPendingAuth(conversation, args.sessionId);
14926
+ const assistantText = normalizeConversationText(args.reply.text) || (args.reply.deliveryPlan?.postThreadText === false ? NO_VISIBLE_REPLY_CONVERSATION_TEXT : "[empty response]");
14922
14927
  markConversationMessage(conversation, args.userMessageId, {
14923
14928
  replied: true,
14924
14929
  skippedReason: void 0
@@ -14926,7 +14931,7 @@ function buildDeliveredTurnStatePatch(args) {
14926
14931
  upsertConversationMessage(conversation, {
14927
14932
  id: generateConversationId("assistant"),
14928
14933
  role: "assistant",
14929
- text: normalizeConversationText(args.reply.text) || "[empty response]",
14934
+ text: assistantText,
14930
14935
  createdAtMs: Date.now(),
14931
14936
  author: {
14932
14937
  userName: botConfig.userName,
@@ -14958,7 +14963,6 @@ export {
14958
14963
  deliverResourceEventSubscription,
14959
14964
  listThreadReplies,
14960
14965
  postSlackMessage,
14961
- deleteSlackMessage,
14962
14966
  uploadFilesToThread,
14963
14967
  addReactionToMessage,
14964
14968
  removeReactionFromMessage,
@@ -15002,7 +15006,6 @@ export {
15002
15006
  startActiveTurn,
15003
15007
  markTurnClosed,
15004
15008
  markTurnFailed,
15005
- isRedundantReactionAckText,
15006
15009
  persistCompletedSessionRecord,
15007
15010
  completeDeliveredTurn,
15008
15011
  persistYieldSessionRecord,