@cuylabs/channel-slack-agent-core 0.5.1 → 0.7.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 (89) hide show
  1. package/README.md +20 -39
  2. package/dist/{adapter.d.ts → adapter/index.d.ts} +7 -5
  3. package/dist/adapter/index.js +9 -0
  4. package/dist/{adapter-Cmd2C90g.d.ts → adapter-B3CI611y.d.ts} +1 -1
  5. package/dist/app-surface.d.ts +13 -3
  6. package/dist/app-surface.js +5 -7
  7. package/dist/app.d.ts +9 -4
  8. package/dist/app.js +6 -9
  9. package/dist/artifacts/index.d.ts +57 -0
  10. package/dist/artifacts/index.js +6 -0
  11. package/dist/{assistant.d.ts → assistant/index.d.ts} +6 -4
  12. package/dist/{assistant.js → assistant/index.js} +3 -5
  13. package/dist/{chunk-CYEBGC6G.js → chunk-76SRS54H.js} +5 -5
  14. package/dist/{chunk-M64Z6TYL.js → chunk-7DUO5BMW.js} +16 -6
  15. package/dist/{chunk-NIPAN4KA.js → chunk-A2PLAVW6.js} +2 -3
  16. package/dist/chunk-C7CHMYV6.js +226 -0
  17. package/dist/chunk-C7VSW4ZM.js +548 -0
  18. package/dist/{chunk-JMLB7A2V.js → chunk-DJPKRKGP.js} +5 -5
  19. package/dist/chunk-ELR6MQD7.js +12 -0
  20. package/dist/{chunk-FDRQOG7Q.js → chunk-FQWFB54C.js} +26 -15
  21. package/dist/{chunk-BFUPAJON.js → chunk-MGBNGG4D.js} +59 -37
  22. package/dist/chunk-NNCVHQC4.js +94 -0
  23. package/dist/chunk-P7PFQ3SQ.js +396 -0
  24. package/dist/{chunk-WO4BJMF3.js → chunk-TCNJY7QA.js} +5 -5
  25. package/dist/{chunk-DHPD4XH5.js → chunk-TMADMHBN.js} +210 -29
  26. package/dist/{chunk-IWUYIAY5.js → chunk-VMVQIDNR.js} +5 -7
  27. package/dist/{chunk-IXY3BXU5.js → chunk-X7ILLZZP.js} +359 -2
  28. package/dist/context-fragments-CQEDcjYR.d.ts +30 -0
  29. package/dist/express-assistant.d.ts +6 -3
  30. package/dist/express-assistant.js +4 -7
  31. package/dist/express.d.ts +7 -3
  32. package/dist/express.js +3 -6
  33. package/dist/feedback/index.d.ts +1 -0
  34. package/dist/feedback/index.js +10 -0
  35. package/dist/history/index.d.ts +61 -0
  36. package/dist/history/index.js +8 -0
  37. package/dist/index.d.ts +23 -16
  38. package/dist/index.js +81 -160
  39. package/dist/interactive/index.d.ts +71 -0
  40. package/dist/{interactive.js → interactive/index.js} +9 -4
  41. package/dist/mcp.js +0 -1
  42. package/dist/{options-C7OYeNR-.d.ts → options-BcDReOJv.d.ts} +48 -0
  43. package/dist/{options-Uf-qmQKN.d.ts → options-CdqBABcM.d.ts} +26 -1
  44. package/dist/{shared.d.ts → shared/index.d.ts} +24 -36
  45. package/dist/{shared.js → shared/index.js} +2 -6
  46. package/dist/socket.d.ts +9 -4
  47. package/dist/socket.js +6 -9
  48. package/dist/source/index.d.ts +154 -0
  49. package/dist/source/index.js +38 -0
  50. package/dist/{types-BqRzb_Cd.d.ts → types-CRWzJB5G.d.ts} +35 -0
  51. package/dist/types-CiwGU6zC.d.ts +56 -0
  52. package/dist/views/index.d.ts +8 -0
  53. package/dist/views/index.js +10 -0
  54. package/docs/README.md +18 -0
  55. package/docs/concepts/final-response-artifacts.md +39 -0
  56. package/docs/concepts/interactive-requests.md +43 -0
  57. package/docs/concepts/tool-task-rendering.md +46 -0
  58. package/docs/concepts/view-workflows.md +52 -0
  59. package/docs/reference/boundary.md +22 -0
  60. package/docs/reference/exports.md +26 -0
  61. package/package.json +36 -50
  62. package/dist/adapter.js +0 -13
  63. package/dist/bolt.d.ts +0 -8
  64. package/dist/bolt.js +0 -10
  65. package/dist/chunk-2SUAW6MV.js +0 -12
  66. package/dist/chunk-645NNJIM.js +0 -12
  67. package/dist/chunk-ANIZ5NT4.js +0 -12
  68. package/dist/chunk-GNXWTKQ6.js +0 -48
  69. package/dist/chunk-HFT2FXJP.js +0 -12
  70. package/dist/chunk-I2KLQ2HA.js +0 -22
  71. package/dist/chunk-K2E6A377.js +0 -12
  72. package/dist/chunk-NDVXBI7Z.js +0 -12
  73. package/dist/chunk-PX4RGO3N.js +0 -12
  74. package/dist/chunk-VHGV66M7.js +0 -12
  75. package/dist/diagnostics.d.ts +0 -1
  76. package/dist/diagnostics.js +0 -10
  77. package/dist/feedback.d.ts +0 -1
  78. package/dist/feedback.js +0 -10
  79. package/dist/history.d.ts +0 -1
  80. package/dist/history.js +0 -10
  81. package/dist/interactive.d.ts +0 -30
  82. package/dist/policy.d.ts +0 -1
  83. package/dist/policy.js +0 -10
  84. package/dist/setup.d.ts +0 -1
  85. package/dist/setup.js +0 -10
  86. package/dist/targets.d.ts +0 -1
  87. package/dist/targets.js +0 -10
  88. package/dist/users.d.ts +0 -1
  89. package/dist/users.js +0 -10
@@ -1,38 +1,13 @@
1
1
  import {
2
- feedback_exports
3
- } from "./chunk-VHGV66M7.js";
4
- import {
5
- extractSlackAuthContext,
6
- resolveSlackMessageFormatter
7
- } from "./chunk-GNXWTKQ6.js";
2
+ SLACK_FEEDBACK_ACTION_ID,
3
+ createSlackFeedbackBlock,
4
+ registerSlackFeedbackAction
5
+ } from "./chunk-ELR6MQD7.js";
8
6
  import {
9
7
  UnsupportedSlackInteractiveRequestError,
10
8
  bridgeAgentEventsToSlack,
11
- resolveSlackEventBridgeOptions,
12
- runWithSlackTurnContext
13
- } from "./chunk-DHPD4XH5.js";
14
-
15
- // src/assistant/message-parser.ts
16
- import {
17
- parseSlackMessageActivityFromMessageEvent
18
- } from "@cuylabs/channel-slack/assistant";
19
-
20
- // src/assistant/session.ts
21
- function resolveAssistantSessionId(message, strategy) {
22
- switch (strategy) {
23
- case "channel-id":
24
- return message.channel;
25
- case "user-per-thread":
26
- return `${message.channel}:${message.threadTs}:${message.userId}`;
27
- default:
28
- return `${message.channel}:${message.threadTs}`;
29
- }
30
- }
31
-
32
- // src/assistant/thread-context-store.ts
33
- import {
34
- createSlackAssistantThreadContextStore
35
- } from "@cuylabs/channel-slack/assistant";
9
+ resolveSlackEventBridgeOptions
10
+ } from "./chunk-TMADMHBN.js";
36
11
 
37
12
  // src/assistant/bridge.ts
38
13
  import { Assistant } from "@slack/bolt";
@@ -190,6 +165,24 @@ function createThreadContextChangedHandler() {
190
165
  import {
191
166
  withinScope
192
167
  } from "@cuylabs/agent-core";
168
+ import {
169
+ extractSlackAuthContext,
170
+ resolveSlackMessageFormatter,
171
+ runWithSlackTurnContext
172
+ } from "@cuylabs/channel-slack/core";
173
+ import { parseSlackMessageActivityFromMessageEvent } from "@cuylabs/channel-slack/assistant";
174
+
175
+ // src/assistant/session.ts
176
+ function resolveAssistantSessionId(message, strategy) {
177
+ switch (strategy) {
178
+ case "channel-id":
179
+ return message.channel;
180
+ case "user-per-thread":
181
+ return `${message.channel}:${message.threadTs}:${message.userId}`;
182
+ default:
183
+ return `${message.channel}:${message.threadTs}`;
184
+ }
185
+ }
193
186
 
194
187
  // src/assistant/scope-attributes.ts
195
188
  function buildAssistantScopeAttributes(message, auth, threadContext, prep) {
@@ -246,6 +239,11 @@ function createAssistantSink(params) {
246
239
  return stream;
247
240
  }
248
241
  return {
242
+ artifactClient: params.client,
243
+ artifactTarget: {
244
+ channelId: params.channel,
245
+ threadTs: params.threadTs
246
+ },
249
247
  async postMessage() {
250
248
  throw new Error(
251
249
  "Assistant bridge uses chat-stream mode and does not support postMessage."
@@ -434,6 +432,7 @@ function createUserMessageHandler(deps) {
434
432
  ...options.formatToolTitle ? { formatToolTitle: options.formatToolTitle } : {},
435
433
  ...options.formatToolUpdate ? { formatToolUpdate: options.formatToolUpdate } : {},
436
434
  ...options.formatToolDetails ? { formatToolDetails: options.formatToolDetails } : {},
435
+ ...options.formatToolResultOutput ? { formatToolResultOutput: options.formatToolResultOutput } : {},
437
436
  ...options.formatToolError ? { formatToolError: options.formatToolError } : {},
438
437
  ...options.formatReasoningUpdate ? { formatReasoningUpdate: options.formatReasoningUpdate } : {},
439
438
  ...options.chatStreamBufferSize !== void 0 ? { chatStreamBufferSize: options.chatStreamBufferSize } : {},
@@ -441,6 +440,22 @@ function createUserMessageHandler(deps) {
441
440
  ...options.maxTaskUpdateTextChars !== void 0 ? { maxTaskUpdateTextChars: options.maxTaskUpdateTextChars } : {},
442
441
  ...options.maxTaskUpdateFieldChars !== void 0 ? { maxTaskUpdateFieldChars: options.maxTaskUpdateFieldChars } : {},
443
442
  ...chatStreamFinalArgs ? { chatStreamFinalArgs } : {},
443
+ ...options.publishFinalResponseArtifact ? {
444
+ publishFinalResponseArtifact: options.publishFinalResponseArtifact
445
+ } : {},
446
+ ...options.finalResponseArtifactMode ? { finalResponseArtifactMode: options.finalResponseArtifactMode } : {},
447
+ ...options.finalResponseArtifactStreamThreshold !== void 0 ? {
448
+ finalResponseArtifactStreamThreshold: options.finalResponseArtifactStreamThreshold
449
+ } : {},
450
+ ...options.formatFinalResponseArtifactContinuationNotice ? {
451
+ formatFinalResponseArtifactContinuationNotice: options.formatFinalResponseArtifactContinuationNotice
452
+ } : {},
453
+ ...options.formatFinalResponseArtifactMessage ? {
454
+ formatFinalResponseArtifactMessage: options.formatFinalResponseArtifactMessage
455
+ } : {},
456
+ ...options.onFinalResponseArtifactError ? {
457
+ onFinalResponseArtifactError: options.onFinalResponseArtifactError
458
+ } : {},
444
459
  formatMessageText: messageFormatter,
445
460
  onStatusChange: async (label, event) => {
446
461
  const update = await resolveStatusUpdate(
@@ -603,6 +618,7 @@ ${formatStreamError(translatedError)}`
603
618
  }
604
619
 
605
620
  // src/assistant/bridge.ts
621
+ import { createSlackAssistantThreadContextStore } from "@cuylabs/channel-slack/assistant";
606
622
  function createSlackAssistantBridge(options) {
607
623
  if (!options.source || typeof options.source.chat !== "function") {
608
624
  throw new Error(
@@ -616,8 +632,8 @@ function createSlackAssistantBridge(options) {
616
632
  }
617
633
  const sessionStrategy = options.sessionStrategy ?? "thread-aware";
618
634
  const feedbackConfig = options.feedback === false ? void 0 : options.feedback ?? {};
619
- const feedbackBlock = feedbackConfig ? (0, feedback_exports.createSlackFeedbackBlock)(feedbackConfig) : void 0;
620
- const feedbackActionId = feedbackConfig?.actionId ?? feedback_exports.SLACK_FEEDBACK_ACTION_ID;
635
+ const feedbackBlock = feedbackConfig ? createSlackFeedbackBlock(feedbackConfig) : void 0;
636
+ const feedbackActionId = feedbackConfig?.actionId ?? SLACK_FEEDBACK_ACTION_ID;
621
637
  const threadStarted = createThreadStartedHandler(options);
622
638
  const threadContextChanged = createThreadContextChangedHandler();
623
639
  const threadContextStore = options.threadContextStore ?? createSlackAssistantThreadContextStore();
@@ -639,7 +655,7 @@ function createSlackAssistantBridge(options) {
639
655
  function install(app) {
640
656
  app.assistant(assistant);
641
657
  if (feedbackConfig) {
642
- (0, feedback_exports.registerSlackFeedbackAction)(app, {
658
+ registerSlackFeedbackAction(app, {
643
659
  ...feedbackConfig,
644
660
  resolveSessionId: (context) => resolveFeedbackSessionId(context, sessionStrategy),
645
661
  onFeedback: feedbackConfig.onFeedback ?? (async (_ctx) => {
@@ -654,9 +670,15 @@ function createSlackAssistantBridge(options) {
654
670
  };
655
671
  }
656
672
 
673
+ // src/assistant/index.ts
674
+ import {
675
+ createSlackAssistantThreadContextStore as createSlackAssistantThreadContextStore2,
676
+ parseSlackMessageActivityFromMessageEvent as parseSlackMessageActivityFromMessageEvent2
677
+ } from "@cuylabs/channel-slack/assistant";
678
+
657
679
  export {
658
- parseSlackMessageActivityFromMessageEvent,
659
680
  resolveAssistantSessionId,
660
- createSlackAssistantThreadContextStore,
661
- createSlackAssistantBridge
681
+ createSlackAssistantBridge,
682
+ createSlackAssistantThreadContextStore2 as createSlackAssistantThreadContextStore,
683
+ parseSlackMessageActivityFromMessageEvent2 as parseSlackMessageActivityFromMessageEvent
662
684
  };
@@ -0,0 +1,94 @@
1
+ // src/artifacts/final-response.ts
2
+ import {
3
+ publishSlackCanvasArtifact,
4
+ publishSlackTextArtifact
5
+ } from "@cuylabs/channel-slack/artifacts";
6
+ var DEFAULT_MIN_CHARACTERS = 4e3;
7
+ var DEFAULT_TITLE = "Agent response";
8
+ function createSlackFinalResponseArtifactPublisher({
9
+ minCharacters = DEFAULT_MIN_CHARACTERS,
10
+ title = DEFAULT_TITLE,
11
+ summary,
12
+ channelCanvas = true,
13
+ fallback = "file",
14
+ onPublished,
15
+ onError
16
+ } = {}) {
17
+ const configuredThreshold = Math.floor(minCharacters);
18
+ const threshold = Number.isFinite(configuredThreshold) && configuredThreshold > 0 ? configuredThreshold : DEFAULT_MIN_CHARACTERS;
19
+ return async (context) => {
20
+ const text = context.text.trim();
21
+ if (text.length < threshold) {
22
+ return void 0;
23
+ }
24
+ const resolvedTitle = normalizeText(await resolveValue(title, context)) ?? DEFAULT_TITLE;
25
+ const resolvedSummary = normalizeText(await resolveValue(summary, context));
26
+ let lastError;
27
+ try {
28
+ const publication = await publishSlackCanvasArtifact({
29
+ client: context.client,
30
+ channelId: context.channelId,
31
+ ...context.threadTs ? { threadTs: context.threadTs } : {},
32
+ artifact: {
33
+ kind: "canvas",
34
+ title: resolvedTitle,
35
+ markdown: text,
36
+ channelCanvas,
37
+ ...resolvedSummary ? { summary: resolvedSummary } : {},
38
+ metadata: {
39
+ source: "slack-final-response",
40
+ characterCount: text.length
41
+ }
42
+ }
43
+ });
44
+ const result = { publication };
45
+ await onPublished?.(result, context);
46
+ return result;
47
+ } catch (error) {
48
+ lastError = error;
49
+ }
50
+ if (fallback === "file") {
51
+ try {
52
+ const publication = await publishSlackTextArtifact({
53
+ client: context.client,
54
+ channelId: context.channelId,
55
+ ...context.threadTs ? { threadTs: context.threadTs } : {},
56
+ artifact: {
57
+ kind: "text",
58
+ title: resolvedTitle,
59
+ text,
60
+ filename: filenameFromTitle(resolvedTitle),
61
+ ...resolvedSummary ? { summary: resolvedSummary } : {},
62
+ metadata: {
63
+ source: "slack-final-response",
64
+ characterCount: text.length,
65
+ canvasFallback: true
66
+ }
67
+ }
68
+ });
69
+ const result = { publication };
70
+ await onPublished?.(result, context);
71
+ return result;
72
+ } catch (error) {
73
+ lastError = error;
74
+ }
75
+ }
76
+ await onError?.(lastError, context);
77
+ return void 0;
78
+ };
79
+ }
80
+ async function resolveValue(value, context) {
81
+ return typeof value === "function" ? await value(context) : value;
82
+ }
83
+ function normalizeText(value) {
84
+ const trimmed = value?.trim();
85
+ return trimmed ? trimmed : void 0;
86
+ }
87
+ function filenameFromTitle(title) {
88
+ const slug = title.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
89
+ return `${slug || "agent-response"}.txt`;
90
+ }
91
+
92
+ export {
93
+ createSlackFinalResponseArtifactPublisher
94
+ };
@@ -0,0 +1,396 @@
1
+ // src/history/turn-context.ts
2
+ import {
3
+ createSlackSupplementalHistoryVisibilityPolicy,
4
+ loadSlackTurnHistoryContext
5
+ } from "@cuylabs/channel-slack/history";
6
+ import { enrichSlackUserMentions } from "@cuylabs/channel-slack/users";
7
+ import { WebClient } from "@slack/web-api";
8
+ async function loadSlackAgentTurnHistoryContext({
9
+ history,
10
+ logger,
11
+ originChannelId: providedOriginChannelId,
12
+ profileResolver,
13
+ request
14
+ }) {
15
+ const originChannelId = providedOriginChannelId ?? resolveOriginChannelId(request);
16
+ const client = resolveSlackHistoryClient(request);
17
+ if (!history.enabled) {
18
+ logger?.debug?.("Slack context history disabled", {
19
+ channelId: request.slackActivity.channelId,
20
+ threadTs: request.slackActivity.threadTs
21
+ });
22
+ return emptySlackAgentTurnHistoryContextResult();
23
+ }
24
+ if (!client) {
25
+ logger?.warn?.("Slack context history enabled without a Slack WebClient", {
26
+ channelId: request.slackActivity.channelId,
27
+ threadTs: request.slackActivity.threadTs
28
+ });
29
+ return emptySlackAgentTurnHistoryContextResult();
30
+ }
31
+ const teamId = request.slackActivity.teamId ?? request.user.teamId ?? request.auth?.teamId;
32
+ const threadTs = request.slackActivity.threadTs ?? request.slackActivity.messageTs;
33
+ const resolveAuthor = profileResolver ? createSlackAgentHistoryAuthorResolver({
34
+ botToken: request.auth?.botToken,
35
+ logger,
36
+ profileResolver,
37
+ teamId
38
+ }) : void 0;
39
+ const loaded = await loadSlackTurnHistoryContext({
40
+ activity: request.slackActivity,
41
+ botUserId: request.auth?.botUserId,
42
+ client,
43
+ includeTopLevelChannelFallback: request.slackActivity.channelType !== "dm",
44
+ limit: history.limit,
45
+ maxCharacters: history.maxCharacters,
46
+ token: request.auth?.botToken,
47
+ ...teamId ? { teamId } : {},
48
+ ...originChannelId ? { originChannelId } : {},
49
+ visibilityPolicy: createSlackSupplementalHistoryVisibilityPolicy({
50
+ allowedUserIds: history.visibilityAllowedUserIds ?? [],
51
+ mode: history.visibilityMode ?? "all"
52
+ }),
53
+ onVisibilityPolicyError: ({ channelId, error, source, teamId: teamId2 }) => {
54
+ logger?.warn?.("Slack supplemental history visibility policy failed", {
55
+ channelId,
56
+ source,
57
+ ...teamId2 ? { teamId: teamId2 } : {},
58
+ error: formatHistoryError(error)
59
+ });
60
+ },
61
+ ...request.assistant ? {
62
+ assistantSurfaceThreadRootUser: {
63
+ userId: request.slackActivity.userId
64
+ },
65
+ onAssistantSurfaceThreadRootNormalized: ({
66
+ action,
67
+ channelId,
68
+ teamId: normalizedTeamId,
69
+ threadTs: threadTs2,
70
+ userId
71
+ }) => {
72
+ logger?.debug?.(
73
+ action === "removed-duplicate" ? "Slack assistant surface duplicate thread root removed" : "Slack assistant surface thread root author corrected",
74
+ {
75
+ channelId,
76
+ ...normalizedTeamId ? { teamId: normalizedTeamId } : {},
77
+ threadTs: threadTs2,
78
+ userId
79
+ }
80
+ );
81
+ }
82
+ } : {},
83
+ headers: {
84
+ channel: "Recent Slack channel history before the current message:",
85
+ ...originChannelId ? {
86
+ originChannel: `Recent Slack channel context from ${originChannelId}:`
87
+ } : {},
88
+ thread: "Recent Slack thread history before the current message:"
89
+ },
90
+ ...resolveAuthor ? { resolveAuthor } : {},
91
+ ...resolveAuthor ? {
92
+ onResolveAuthorError: ({
93
+ channelId,
94
+ error,
95
+ source,
96
+ teamId: errorTeamId,
97
+ userId
98
+ }) => {
99
+ logger?.debug?.("Slack history author attribution failed", {
100
+ channelId,
101
+ source,
102
+ ...errorTeamId ? { teamId: errorTeamId } : {},
103
+ ...userId ? { userId } : {},
104
+ error: formatHistoryError(error)
105
+ });
106
+ }
107
+ } : {}
108
+ });
109
+ const unavailableReasons = summarizeUnavailable(loaded.unavailable);
110
+ for (const issue of loaded.unavailable) {
111
+ logSlackAgentHistoryUnavailable(logger, issue);
112
+ }
113
+ const loadedPrompt = await enrichSlackAgentHistoryMentions({
114
+ botToken: request.auth?.botToken,
115
+ logger,
116
+ profileResolver,
117
+ prompt: loaded.prompt,
118
+ teamId
119
+ });
120
+ const prompt = truncateHistoryPrompt(
121
+ [
122
+ loadedPrompt,
123
+ ...loaded.unavailable.map(
124
+ (issue) => (history.unavailableNoteFormatter ?? formatSlackAgentHistoryUnavailableNote)(issue)
125
+ )
126
+ ].filter(Boolean).join("\n\n"),
127
+ history
128
+ );
129
+ const fragment = prompt ? createSlackAgentHistoryFragment({
130
+ history,
131
+ loadedFragment: loaded.fragment,
132
+ prompt,
133
+ unavailableReasons
134
+ }) : void 0;
135
+ logger?.debug?.("Slack context history loaded", {
136
+ channelId: request.slackActivity.channelId,
137
+ included: Boolean(prompt),
138
+ maxCharacters: history.maxCharacters,
139
+ maxMessages: history.limit,
140
+ originChannelId,
141
+ originChannelMessageCount: loaded.originChannelMessageCount,
142
+ originChannelUnavailableReason: unavailableReasons.originChannelUnavailableReason,
143
+ promptChars: prompt?.length ?? 0,
144
+ threadMessageCount: loaded.threadMessageCount,
145
+ threadTs,
146
+ threadUnavailableReason: unavailableReasons.threadUnavailableReason,
147
+ topLevelChannelMessageCount: loaded.topLevelChannelMessageCount,
148
+ topLevelChannelUnavailableReason: unavailableReasons.topLevelChannelUnavailableReason
149
+ });
150
+ return {
151
+ ...fragment ? { fragment } : {},
152
+ ...prompt ? { prompt } : {},
153
+ originChannelMessageCount: loaded.originChannelMessageCount,
154
+ originChannelVisibilityOmittedMessageCount: loaded.originChannelVisibilityOmittedMessageCount,
155
+ threadMessageCount: loaded.threadMessageCount,
156
+ threadVisibilityOmittedMessageCount: loaded.threadVisibilityOmittedMessageCount,
157
+ topLevelChannelMessageCount: loaded.topLevelChannelMessageCount,
158
+ topLevelChannelVisibilityOmittedMessageCount: loaded.topLevelChannelVisibilityOmittedMessageCount,
159
+ visibilityOmittedMessageCount: loaded.visibilityOmittedMessageCount,
160
+ ...unavailableReasons.originChannelUnavailableReason ? {
161
+ originChannelUnavailableReason: unavailableReasons.originChannelUnavailableReason
162
+ } : {},
163
+ ...unavailableReasons.threadUnavailableReason ? { threadUnavailableReason: unavailableReasons.threadUnavailableReason } : {},
164
+ ...unavailableReasons.topLevelChannelUnavailableReason ? {
165
+ topLevelChannelUnavailableReason: unavailableReasons.topLevelChannelUnavailableReason
166
+ } : {}
167
+ };
168
+ }
169
+ function emptySlackAgentTurnHistoryContextResult() {
170
+ return {
171
+ originChannelMessageCount: 0,
172
+ originChannelVisibilityOmittedMessageCount: 0,
173
+ threadMessageCount: 0,
174
+ threadVisibilityOmittedMessageCount: 0,
175
+ topLevelChannelMessageCount: 0,
176
+ topLevelChannelVisibilityOmittedMessageCount: 0,
177
+ visibilityOmittedMessageCount: 0
178
+ };
179
+ }
180
+ async function enrichSlackAgentHistoryMentions({
181
+ botToken,
182
+ logger,
183
+ profileResolver,
184
+ prompt,
185
+ teamId
186
+ }) {
187
+ if (!prompt || !profileResolver) {
188
+ return prompt;
189
+ }
190
+ const result = await enrichSlackUserMentions(
191
+ {
192
+ text: prompt,
193
+ ...botToken ? { botToken } : {},
194
+ ...teamId ? { teamId } : {}
195
+ },
196
+ {
197
+ concurrency: 4,
198
+ formatLabel: ({ mention, profile }) => profile.displayName ? `${mention} (${profile.displayName})` : void 0,
199
+ maxLookups: 20,
200
+ onResolveError: ({ error, teamId: errorTeamId, userId }) => {
201
+ logger?.debug?.("Slack history mention enrichment failed", {
202
+ ...errorTeamId ? { teamId: errorTeamId } : {},
203
+ error: formatHistoryError(error),
204
+ userId
205
+ });
206
+ },
207
+ profileResolver: {
208
+ resolve: async (input) => ({
209
+ userId: input.userId,
210
+ ...await profileResolver.resolve({
211
+ botToken: input.botToken,
212
+ teamId: input.teamId,
213
+ userId: input.userId
214
+ })
215
+ })
216
+ }
217
+ }
218
+ );
219
+ return result.text;
220
+ }
221
+ function createSlackAgentHistoryAuthorResolver({
222
+ botToken,
223
+ logger,
224
+ profileResolver,
225
+ teamId
226
+ }) {
227
+ return async (message, context) => {
228
+ if (message.role === "assistant") {
229
+ return "Assistant";
230
+ }
231
+ if (message.role === "bot") {
232
+ return "Bot";
233
+ }
234
+ if (!message.userId) {
235
+ return void 0;
236
+ }
237
+ try {
238
+ const profile = await profileResolver.resolve({
239
+ botToken,
240
+ teamId: context.teamId ?? teamId,
241
+ userId: message.userId
242
+ });
243
+ return formatSlackHistoryUserAuthor(message.userId, profile.displayName);
244
+ } catch (error) {
245
+ logger?.debug?.("Slack history profile lookup failed", {
246
+ channelId: context.channelId,
247
+ error: formatHistoryError(error),
248
+ source: context.source,
249
+ teamId: context.teamId ?? teamId,
250
+ userId: message.userId
251
+ });
252
+ return formatSlackHistoryUserAuthor(message.userId);
253
+ }
254
+ };
255
+ }
256
+ function formatSlackHistoryUserAuthor(userId, displayName) {
257
+ return displayName ? `${displayName} (${userId})` : `Slack user ${userId}`;
258
+ }
259
+ function createSlackAgentHistoryFragment({
260
+ history,
261
+ loadedFragment,
262
+ prompt,
263
+ unavailableReasons
264
+ }) {
265
+ return {
266
+ ...loadedFragment,
267
+ budgetBehavior: loadedFragment?.budgetBehavior ?? "droppable",
268
+ content: prompt,
269
+ kind: loadedFragment?.kind ?? "slack-context",
270
+ lifetime: loadedFragment?.lifetime ?? "turn",
271
+ maxChars: loadedFragment?.maxChars ?? history.maxCharacters,
272
+ metadata: {
273
+ ...loadedFragment?.metadata,
274
+ ...unavailableReasons.originChannelUnavailableReason ? {
275
+ originChannelUnavailableReason: unavailableReasons.originChannelUnavailableReason
276
+ } : {},
277
+ ...unavailableReasons.threadUnavailableReason ? {
278
+ threadUnavailableReason: unavailableReasons.threadUnavailableReason
279
+ } : {},
280
+ ...unavailableReasons.topLevelChannelUnavailableReason ? {
281
+ topLevelChannelUnavailableReason: unavailableReasons.topLevelChannelUnavailableReason
282
+ } : {}
283
+ },
284
+ placement: loadedFragment?.placement ?? "after-latest-user",
285
+ role: loadedFragment?.role ?? "user",
286
+ source: loadedFragment?.source ?? "slack",
287
+ title: loadedFragment?.title ?? "Slack Conversation History"
288
+ };
289
+ }
290
+ function logSlackAgentHistoryUnavailable(logger, issue) {
291
+ const fields = {
292
+ channelId: issue.channelId,
293
+ error: issue.message,
294
+ expected: issue.expected,
295
+ ...normalizedHistoryHint(issue) ? { hint: normalizedHistoryHint(issue) } : {},
296
+ method: issue.method,
297
+ slackError: normalizedHistoryErrorCode(issue) ?? "unknown",
298
+ source: issue.source
299
+ };
300
+ if (issue.expected) {
301
+ logger?.info?.("Slack context history unavailable", fields);
302
+ } else {
303
+ logger?.warn?.("Slack context history unavailable", fields);
304
+ }
305
+ }
306
+ function formatSlackAgentHistoryUnavailableNote(issue) {
307
+ const reason = normalizedHistoryErrorCode(issue) ?? "unknown_error";
308
+ const hint = normalizedHistoryHint(issue);
309
+ return [
310
+ `${historyScopeLabel(issue)} context is unavailable to the app for this turn (${reason}).`,
311
+ `If the user asks about that Slack context, say that you cannot read it yet and explain the needed access.${hint ? ` ${normalizeHistoryHint(hint)}` : ""}`
312
+ ].join(" ");
313
+ }
314
+ function historyScopeLabel(issue) {
315
+ switch (issue.source) {
316
+ case "thread":
317
+ return "current assistant thread";
318
+ case "channel":
319
+ return `current Slack channel ${issue.channelId}`;
320
+ case "origin-channel":
321
+ return `origin Slack channel ${issue.channelId}`;
322
+ }
323
+ }
324
+ function normalizeHistoryHint(hint) {
325
+ return hint.endsWith(".") ? hint : `${hint}.`;
326
+ }
327
+ function summarizeUnavailable(unavailable) {
328
+ return {
329
+ originChannelUnavailableReason: unavailableReason(
330
+ unavailable,
331
+ "origin-channel"
332
+ ),
333
+ threadUnavailableReason: unavailableReason(unavailable, "thread"),
334
+ topLevelChannelUnavailableReason: unavailableReason(unavailable, "channel")
335
+ };
336
+ }
337
+ function unavailableReason(unavailable, source) {
338
+ const issue = unavailable.find((entry) => entry.source === source);
339
+ return issue ? normalizedHistoryErrorCode(issue) ?? issue.message : void 0;
340
+ }
341
+ function normalizedHistoryErrorCode(issue) {
342
+ if (issue.errorCode) {
343
+ return issue.errorCode;
344
+ }
345
+ const failedMatch = issue.message.match(/failed:\s*([a-z_]+)/i);
346
+ if (failedMatch?.[1]) {
347
+ return failedMatch[1];
348
+ }
349
+ const apiMatch = issue.message.match(/API error occurred:\s*([a-z_]+)/i);
350
+ return apiMatch?.[1];
351
+ }
352
+ function normalizedHistoryHint(issue) {
353
+ if (issue.hint) {
354
+ return issue.hint;
355
+ }
356
+ switch (normalizedHistoryErrorCode(issue)) {
357
+ case "not_in_channel":
358
+ return "Invite the app to the channel, then retry.";
359
+ case "channel_not_found":
360
+ return "Slack did not expose a readable channel for this bot token.";
361
+ case "no_permission":
362
+ case "access_denied":
363
+ return "The bot token cannot read this conversation.";
364
+ case "missing_scope":
365
+ return "Add the matching Slack history scope and reinstall the app.";
366
+ default:
367
+ return void 0;
368
+ }
369
+ }
370
+ function resolveSlackHistoryClient(request) {
371
+ if (request.client) {
372
+ return request.client;
373
+ }
374
+ return request.auth?.botToken ? new WebClient(request.auth.botToken) : void 0;
375
+ }
376
+ function resolveOriginChannelId(request) {
377
+ return request.threadContext?.channel_id && request.threadContext.channel_id !== request.slackActivity.channelId ? request.threadContext.channel_id : void 0;
378
+ }
379
+ function truncateHistoryPrompt(value, history) {
380
+ const trimmed = value.trim();
381
+ if (!trimmed) {
382
+ return void 0;
383
+ }
384
+ if (trimmed.length <= history.maxCharacters) {
385
+ return trimmed;
386
+ }
387
+ return trimmed.slice(0, history.maxCharacters).trimEnd();
388
+ }
389
+ function formatHistoryError(error) {
390
+ return error instanceof Error ? error.stack ?? error.message : String(error);
391
+ }
392
+
393
+ export {
394
+ loadSlackAgentTurnHistoryContext,
395
+ emptySlackAgentTurnHistoryContextResult
396
+ };
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createSlackChannelAdapter
3
- } from "./chunk-FDRQOG7Q.js";
4
- import {
5
- bolt_exports
6
- } from "./chunk-ANIZ5NT4.js";
3
+ } from "./chunk-FQWFB54C.js";
7
4
 
8
5
  // src/express.ts
6
+ import {
7
+ createSlackBoltApp
8
+ } from "@cuylabs/channel-slack/transports/http";
9
9
  async function mountSlackAgent(source, options = {}) {
10
10
  const {
11
11
  botToken: providedToken,
@@ -27,7 +27,7 @@ async function mountSlackAgent(source, options = {}) {
27
27
  app: expressApp,
28
28
  authMode,
29
29
  routePath
30
- } = await (0, bolt_exports.createSlackBoltApp)({
30
+ } = await createSlackBoltApp({
31
31
  signingSecret,
32
32
  path,
33
33
  botToken: providedToken,