@sentry/junior 0.125.0 → 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 (54) hide show
  1. package/dist/{agent-hooks-MF5UZRCO.js → agent-hooks-HDSNWDQM.js} +8 -9
  2. package/dist/api.js +30 -24
  3. package/dist/app.js +49 -37
  4. package/dist/{catalog-runtime-V6SJTUV7.js → catalog-runtime-BDC3UWPG.js} +5 -6
  5. package/dist/chat/agent/request.d.ts +2 -1
  6. package/dist/chat/agent/resume.d.ts +2 -0
  7. package/dist/chat/agent-dispatch/types.d.ts +2 -1
  8. package/dist/chat/conversation-privacy.d.ts +7 -12
  9. package/dist/chat/conversations/destination-visibility.d.ts +7 -0
  10. package/dist/chat/conversations/store.d.ts +3 -3
  11. package/dist/chat/services/turn-session-record.d.ts +4 -1
  12. package/dist/chat/slack/conversation-context.d.ts +4 -7
  13. package/dist/chat/slack/footer.d.ts +10 -1
  14. package/dist/chat/slack/reply.d.ts +9 -2
  15. package/dist/chat/state/turn-session.d.ts +2 -6
  16. package/dist/{chunk-K6MQWEEJ.js → chunk-4PV73JHH.js} +11 -13
  17. package/dist/{chunk-ODB55JM7.js → chunk-6KWO5DU3.js} +9 -9
  18. package/dist/chunk-72SDEHFP.js +102 -0
  19. package/dist/{chunk-CAPBVX4L.js → chunk-ACJZZY5W.js} +2 -2
  20. package/dist/{chunk-XJYGLTYI.js → chunk-APYVVX2Y.js} +1 -1
  21. package/dist/{chunk-2U5CLBYF.js → chunk-EFQX6XBW.js} +1 -1
  22. package/dist/{chunk-Q3UF3K77.js → chunk-EQMSKORN.js} +1 -1
  23. package/dist/{chunk-NM3PMQS6.js → chunk-GHNO2WUH.js} +1 -1
  24. package/dist/{chunk-IHNBJHEP.js → chunk-GK55KLEH.js} +1 -1
  25. package/dist/{chunk-ZXGBLAYQ.js → chunk-JFW62B3Y.js} +1 -1
  26. package/dist/{chunk-MVYNJECP.js → chunk-JP2ZOSQK.js} +15 -5
  27. package/dist/{chunk-LG5TXWXI.js → chunk-KISG7E24.js} +57 -36
  28. package/dist/{chunk-IS4DGI5J.js → chunk-KP7E267S.js} +14 -11
  29. package/dist/{chunk-2R5MASH3.js → chunk-LCRWDMCH.js} +1 -1
  30. package/dist/{chunk-MYKSUTUV.js → chunk-LIDEU7QS.js} +4 -4
  31. package/dist/{chunk-HT7DSLKL.js → chunk-TUHUIBDX.js} +56 -38
  32. package/dist/{chunk-S7G34U75.js → chunk-VUBUFT66.js} +5 -121
  33. package/dist/{chunk-7K57FJXR.js → chunk-WRH7DWFO.js} +13 -11
  34. package/dist/{chunk-KN7QI56S.js → chunk-XLIAQRDI.js} +3 -8
  35. package/dist/{chunk-EXD2Z3YR.js → chunk-XVKJJXHF.js} +16 -14
  36. package/dist/{chunk-JT3YMQR3.js → chunk-YMSVBWBY.js} +8 -8
  37. package/dist/cli/chat.js +23 -23
  38. package/dist/cli/check.js +6 -7
  39. package/dist/cli/plugins.js +11 -12
  40. package/dist/cli/snapshot-create.js +9 -10
  41. package/dist/cli/upgrade.js +6 -7
  42. package/dist/{db-JSDSWK7T.js → db-AZB6AGJL.js} +6 -7
  43. package/dist/instrumentation.js +4 -5
  44. package/dist/nitro.js +2 -2
  45. package/dist/{oauth-callback-server-UMS2T3HN.js → oauth-callback-server-XK4QJLPZ.js} +16 -16
  46. package/dist/{runner-RGOANIRV.js → runner-DSGDSATN.js} +11 -12
  47. package/dist/{skills-GBLPOQOD.js → skills-CO6E3BQJ.js} +6 -7
  48. package/dist/{validation-BMQY6CD4.js → validation-IHLISKM5.js} +6 -7
  49. package/dist/version.js +1 -1
  50. package/migrations/0014_source_visibility.sql +8 -0
  51. package/migrations/meta/0014_snapshot.json +1201 -0
  52. package/migrations/meta/_journal.json +8 -1
  53. package/package.json +5 -5
  54. package/dist/chunk-OB42YVAE.js +0 -16
@@ -1,7 +1,12 @@
1
+ import type { ReplyAttribution } from "@sentry/junior-plugin-api";
1
2
  interface SlackMrkdwnTextObject {
2
3
  text: string;
3
4
  type: "mrkdwn";
4
5
  }
6
+ interface SlackPlainTextObject {
7
+ text: string;
8
+ type: "plain_text";
9
+ }
5
10
  /** Slack-flavored Markdown block — accepts a standard Markdown subset and Slack renders it natively. */
6
11
  interface SlackMarkdownBlock {
7
12
  text: string;
@@ -12,7 +17,7 @@ interface SlackSectionBlock {
12
17
  type: "section";
13
18
  }
14
19
  interface SlackContextBlock {
15
- elements: SlackMrkdwnTextObject[];
20
+ elements: Array<SlackMrkdwnTextObject | SlackPlainTextObject>;
16
21
  type: "context";
17
22
  }
18
23
  export type SlackMessageBlock = SlackMarkdownBlock | SlackSectionBlock | SlackContextBlock;
@@ -22,8 +27,11 @@ interface SlackReplyFooterItem {
22
27
  value: string;
23
28
  }
24
29
  export interface SlackReplyFooter {
30
+ attribution?: ReplyAttribution;
25
31
  items: SlackReplyFooterItem[];
26
32
  }
33
+ /** Render compact reply attribution for the Slack footer. */
34
+ export declare function formatReplyAttribution(attribution: ReplyAttribution): string;
27
35
  /**
28
36
  * Build the compact conversation footer for visible Slack reply surfaces.
29
37
  *
@@ -31,6 +39,7 @@ export interface SlackReplyFooter {
31
39
  */
32
40
  export declare function buildSlackReplyFooter(args: {
33
41
  conversationId?: string;
42
+ replyAttribution?: ReplyAttribution;
34
43
  }): SlackReplyFooter | undefined;
35
44
  /** Build Slack blocks for a reply chunk using the Slack-flavored markdown block for the body. */
36
45
  export declare function buildSlackReplyBlocks(text: string, footer: SlackReplyFooter | undefined): SlackMessageBlock[] | undefined;
@@ -1,12 +1,19 @@
1
+ /**
2
+ * Destination-visible Slack reply delivery.
3
+ *
4
+ * Owns chunking, conversation footer attachment, and outbound posting.
5
+ */
6
+ import type { ReplyAttribution } from "@sentry/junior-plugin-api";
1
7
  /**
2
8
  * Send one destination-visible Slack reply.
3
9
  *
4
- * Chunks oversized text, builds the conversation footer from
5
- * `conversationId`, and posts through the shared Slack outbound boundary.
10
+ * Chunks oversized text, builds compact attribution and conversation footer
11
+ * context, and posts through the shared Slack outbound boundary.
6
12
  */
7
13
  export declare function sendSlackReply(args: {
8
14
  channelId: string;
9
15
  conversationId: string;
16
+ replyAttribution?: ReplyAttribution;
10
17
  text: string;
11
18
  threadTs?: string;
12
19
  }): Promise<string | undefined>;
@@ -75,7 +75,7 @@ export declare function upsertAgentTurnSessionRecord(args: {
75
75
  dispatchId?: string;
76
76
  dispatchOutcome?: AgentDispatchOutcome;
77
77
  resultMessageId?: string;
78
- /** Source-confirmed destination visibility from the current event's signal. */
78
+ /** Confirmed destination visibility; omit when unavailable. */
79
79
  destinationVisibility?: ConversationPrivacy;
80
80
  source?: Source;
81
81
  lastProgressAtMs?: number;
@@ -110,11 +110,7 @@ export declare function recordAgentTurnSessionSummary(args: {
110
110
  dispatchId?: string;
111
111
  dispatchOutcome?: AgentDispatchOutcome;
112
112
  resultMessageId?: string;
113
- /**
114
- * Source-confirmed destination visibility from the current event's signal
115
- * (Slack `channel_type`). Leave unset when no live signal exists so an
116
- * existing destination visibility is not overwritten.
117
- */
113
+ /** Confirmed destination visibility; omit when unavailable. */
118
114
  destinationVisibility?: ConversationPrivacy;
119
115
  source?: Source;
120
116
  lastProgressAtMs?: number;
@@ -6,36 +6,34 @@ import {
6
6
  isDmChannel,
7
7
  normalizeSlackConversationId,
8
8
  withSlackRetries
9
- } from "./chunk-ODB55JM7.js";
9
+ } from "./chunk-6KWO5DU3.js";
10
10
  import {
11
11
  getDb,
12
12
  parseDestination
13
- } from "./chunk-IS4DGI5J.js";
13
+ } from "./chunk-KP7E267S.js";
14
14
  import {
15
15
  acquireActiveLock,
16
16
  getStateAdapter,
17
17
  sleep
18
- } from "./chunk-XJYGLTYI.js";
18
+ } from "./chunk-APYVVX2Y.js";
19
19
  import {
20
20
  normalizeSlackEmojiName
21
- } from "./chunk-KN7QI56S.js";
21
+ } from "./chunk-XLIAQRDI.js";
22
22
  import {
23
23
  pluginCatalogRuntime
24
- } from "./chunk-NM3PMQS6.js";
24
+ } from "./chunk-GHNO2WUH.js";
25
25
  import {
26
26
  fetchWithBoundedOAuthErrorBodies
27
- } from "./chunk-2U5CLBYF.js";
28
- import {
29
- logInfo,
30
- logWarn
31
- } from "./chunk-MVYNJECP.js";
32
- import {
33
- isRecord
34
- } from "./chunk-OB42YVAE.js";
27
+ } from "./chunk-EFQX6XBW.js";
35
28
  import {
36
29
  parseSlackMessageTs,
37
30
  parseSlackUserId
38
31
  } from "./chunk-F3B2YJ76.js";
32
+ import {
33
+ isRecord,
34
+ logInfo,
35
+ logWarn
36
+ } from "./chunk-JP2ZOSQK.js";
39
37
 
40
38
  // src/chat/capabilities/router.ts
41
39
  var ProviderCredentialRouter = class {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getConversationEventStore,
3
3
  getDb
4
- } from "./chunk-IS4DGI5J.js";
4
+ } from "./chunk-KP7E267S.js";
5
5
  import {
6
6
  juniorConversationAnnotations,
7
7
  juniorConversationEvents,
@@ -12,18 +12,23 @@ import {
12
12
  SANDBOX_WORKSPACE_ROOT,
13
13
  getStateAdapter,
14
14
  sleep
15
- } from "./chunk-XJYGLTYI.js";
15
+ } from "./chunk-APYVVX2Y.js";
16
16
  import {
17
17
  botConfig,
18
18
  completeObject,
19
19
  embedTexts,
20
20
  getSlackBotToken,
21
21
  standardModelId
22
- } from "./chunk-KN7QI56S.js";
22
+ } from "./chunk-XLIAQRDI.js";
23
23
  import {
24
24
  isActorUserId,
25
25
  parseActorUserId
26
26
  } from "./chunk-HZF5P5UN.js";
27
+ import {
28
+ parseSlackChannelReferenceId,
29
+ parseSlackMessageTs,
30
+ parseSlackTeamId
31
+ } from "./chunk-F3B2YJ76.js";
27
32
  import {
28
33
  logException,
29
34
  logInfo,
@@ -32,12 +37,7 @@ import {
32
37
  setSpanAttributes,
33
38
  setSpanStatus,
34
39
  withSpan
35
- } from "./chunk-MVYNJECP.js";
36
- import {
37
- parseSlackChannelReferenceId,
38
- parseSlackMessageTs,
39
- parseSlackTeamId
40
- } from "./chunk-F3B2YJ76.js";
40
+ } from "./chunk-JP2ZOSQK.js";
41
41
 
42
42
  // src/chat/plugins/agent-hooks.ts
43
43
  import {
@@ -0,0 +1,102 @@
1
+ import {
2
+ parseSlackChannelId,
3
+ parseSlackMessageTs,
4
+ parseSlackTeamId
5
+ } from "./chunk-F3B2YJ76.js";
6
+ import {
7
+ toOptionalString
8
+ } from "./chunk-JP2ZOSQK.js";
9
+
10
+ // src/chat/slack/context.ts
11
+ import { z } from "zod";
12
+ function toTrimmedSlackString(value) {
13
+ const normalized = toOptionalString(value);
14
+ return normalized?.trim() || void 0;
15
+ }
16
+ var slackMessageEnvelopeSchema = z.object({
17
+ raw: z.unknown().optional()
18
+ });
19
+ var rawSlackMessageSchema = z.object({
20
+ channel: z.unknown().optional(),
21
+ message: z.unknown().optional(),
22
+ team: z.unknown().optional(),
23
+ team_id: z.unknown().optional(),
24
+ thread_ts: z.unknown().optional(),
25
+ ts: z.unknown().optional(),
26
+ user_team: z.unknown().optional()
27
+ });
28
+ var nestedRawSlackMessageSchema = z.object({
29
+ ts: z.unknown().optional()
30
+ });
31
+ function readSlackRawMessageContext(message) {
32
+ const envelope = slackMessageEnvelopeSchema.safeParse(message);
33
+ if (!envelope.success) {
34
+ return void 0;
35
+ }
36
+ const raw = rawSlackMessageSchema.safeParse(envelope.data.raw);
37
+ if (!raw.success) {
38
+ return void 0;
39
+ }
40
+ const nestedMessage = nestedRawSlackMessageSchema.safeParse(raw.data.message);
41
+ const channelId = parseSlackChannelId(raw.data.channel);
42
+ const threadTs = parseSlackMessageTs(raw.data.thread_ts);
43
+ const messageTs = parseSlackMessageTs(raw.data.ts);
44
+ const nestedMessageTs = nestedMessage.success && parseSlackMessageTs(nestedMessage.data.ts);
45
+ const teamId = parseSlackTeamId(raw.data.team_id) ?? parseSlackTeamId(raw.data.team);
46
+ const authorTeamId = parseSlackTeamId(raw.data.user_team);
47
+ return {
48
+ ...channelId ? { channelId } : {},
49
+ ...threadTs ? { threadTs } : {},
50
+ ...messageTs ? { messageTs } : {},
51
+ ...nestedMessageTs ? { nestedMessageTs } : {},
52
+ ...teamId ? { teamId } : {},
53
+ ...authorTeamId ? { authorTeamId } : {}
54
+ };
55
+ }
56
+ function parseSlackThreadId(threadId) {
57
+ const normalizedThreadId = toTrimmedSlackString(threadId);
58
+ if (!normalizedThreadId) {
59
+ return void 0;
60
+ }
61
+ const parts = normalizedThreadId.split(":");
62
+ if (parts.length !== 3 || parts[0] !== "slack") {
63
+ return void 0;
64
+ }
65
+ const channelId = parseSlackChannelId(parts[1]);
66
+ const threadTs = parseSlackMessageTs(parts[2]);
67
+ if (!channelId || !threadTs) {
68
+ return void 0;
69
+ }
70
+ return { channelId, threadTs };
71
+ }
72
+ function resolveSlackChannelIdFromThreadId(threadId) {
73
+ return parseSlackThreadId(threadId)?.channelId;
74
+ }
75
+ function resolveSlackChannelIdFromMessage(message) {
76
+ const messageChannelId = parseSlackChannelId(
77
+ message.channelId
78
+ );
79
+ if (messageChannelId) {
80
+ return messageChannelId;
81
+ }
82
+ const raw = message.raw;
83
+ if (raw && typeof raw === "object") {
84
+ const rawChannel = parseSlackChannelId(
85
+ raw.channel
86
+ );
87
+ if (rawChannel) {
88
+ return rawChannel;
89
+ }
90
+ }
91
+ const threadId = toTrimmedSlackString(
92
+ message.threadId
93
+ );
94
+ return resolveSlackChannelIdFromThreadId(threadId);
95
+ }
96
+
97
+ export {
98
+ readSlackRawMessageContext,
99
+ parseSlackThreadId,
100
+ resolveSlackChannelIdFromThreadId,
101
+ resolveSlackChannelIdFromMessage
102
+ };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-NM3PMQS6.js";
3
+ } from "./chunk-GHNO2WUH.js";
4
4
  import {
5
5
  logWarn
6
- } from "./chunk-MVYNJECP.js";
6
+ } from "./chunk-JP2ZOSQK.js";
7
7
  import {
8
8
  skillRoots
9
9
  } from "./chunk-H4HBKISO.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getChatConfig
3
- } from "./chunk-KN7QI56S.js";
3
+ } from "./chunk-XLIAQRDI.js";
4
4
 
5
5
  // src/chat/state/adapter.ts
6
6
  import { createMemoryState } from "@chat-adapter/state-memory";
@@ -5,7 +5,7 @@ import {
5
5
  logInfo,
6
6
  logWarn,
7
7
  setSpanAttributes
8
- } from "./chunk-MVYNJECP.js";
8
+ } from "./chunk-JP2ZOSQK.js";
9
9
  import {
10
10
  discoverInstalledPluginPackageContent,
11
11
  normalizePluginPackageNames
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDb
3
- } from "./chunk-IS4DGI5J.js";
3
+ } from "./chunk-KP7E267S.js";
4
4
  import {
5
5
  juniorStats
6
6
  } from "./chunk-S4PUICSB.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createPluginCatalogRuntime
3
- } from "./chunk-2U5CLBYF.js";
3
+ } from "./chunk-EFQX6XBW.js";
4
4
 
5
5
  // src/chat/plugins/catalog-runtime.ts
6
6
  var pluginCatalogRuntime = createPluginCatalogRuntime();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-NM3PMQS6.js";
3
+ } from "./chunk-GHNO2WUH.js";
4
4
 
5
5
  // src/chat/plugins/validation.ts
6
6
  import { isDeepStrictEqual } from "util";
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "@sentry/junior",
4
- version: "0.125.0",
4
+ version: "0.126.0",
5
5
  private: false,
6
6
  publishConfig: {
7
7
  access: "public"
@@ -1,7 +1,3 @@
1
- import {
2
- toOptionalNumber,
3
- toOptionalString
4
- } from "./chunk-OB42YVAE.js";
5
1
  import {
6
2
  captureException,
7
3
  getActiveSpan,
@@ -13,7 +9,7 @@ import {
13
9
  } from "./chunk-6GWA276C.js";
14
10
  import {
15
11
  getDeploymentTelemetryAttributes
16
- } from "./chunk-2R5MASH3.js";
12
+ } from "./chunk-LCRWDMCH.js";
17
13
 
18
14
  // src/chat/logging.ts
19
15
  import path from "path";
@@ -25,6 +21,17 @@ import {
25
21
  getLogger
26
22
  } from "@logtape/logtape";
27
23
 
24
+ // src/chat/coerce.ts
25
+ function toOptionalString(value) {
26
+ return typeof value === "string" && value.trim() ? value : void 0;
27
+ }
28
+ function toOptionalNumber(value) {
29
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
30
+ }
31
+ function isRecord(value) {
32
+ return typeof value === "object" && value !== null;
33
+ }
34
+
28
35
  // src/chat/log-context.ts
29
36
  import { AsyncLocalStorage } from "async_hooks";
30
37
  var logContextStorage = new AsyncLocalStorage();
@@ -1455,6 +1462,9 @@ function extractGenAiUsageAttributes(...sources) {
1455
1462
  }
1456
1463
 
1457
1464
  export {
1465
+ toOptionalString,
1466
+ toOptionalNumber,
1467
+ isRecord,
1458
1468
  normalizeIdentityEmail,
1459
1469
  normalizeGenAiFinishReason,
1460
1470
  summarizeMessageText,
@@ -13,7 +13,7 @@ import {
13
13
  persistAuthPauseTurnState,
14
14
  requireTurnFailureEventId,
15
15
  scheduleSessionCompletedPluginTasks
16
- } from "./chunk-JT3YMQR3.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-K6MQWEEJ.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-7K57FJXR.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-ODB55JM7.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-IS4DGI5J.js";
98
+ } from "./chunk-KP7E267S.js";
93
99
  import {
94
100
  acquireActiveLock,
95
101
  getDefaultRedisStateAdapterFor,
96
102
  getStateAdapter
97
- } from "./chunk-XJYGLTYI.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-KN7QI56S.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-CAPBVX4L.js";
115
+ } from "./chunk-ACJZZY5W.js";
116
116
  import {
117
117
  pluginCatalogRuntime
118
- } from "./chunk-NM3PMQS6.js";
118
+ } from "./chunk-GHNO2WUH.js";
119
119
  import {
120
120
  buildOAuthTokenRequest,
121
121
  hasRequiredOAuthScope,
122
122
  parseOAuthTokenResponse
123
- } from "./chunk-2U5CLBYF.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-MVYNJECP.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;