@cuylabs/channel-slack-agent-core 0.1.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 (68) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +80 -0
  3. package/dist/adapter-Cmd2C90g.d.ts +31 -0
  4. package/dist/adapter.d.ts +23 -0
  5. package/dist/adapter.js +13 -0
  6. package/dist/app-surface.d.ts +71 -0
  7. package/dist/app-surface.js +12 -0
  8. package/dist/app.d.ts +54 -0
  9. package/dist/app.js +14 -0
  10. package/dist/assistant.d.ts +19 -0
  11. package/dist/assistant.js +16 -0
  12. package/dist/bolt.d.ts +8 -0
  13. package/dist/bolt.js +10 -0
  14. package/dist/chunk-2SUAW6MV.js +12 -0
  15. package/dist/chunk-645NNJIM.js +12 -0
  16. package/dist/chunk-ANIZ5NT4.js +12 -0
  17. package/dist/chunk-BFUPAJON.js +662 -0
  18. package/dist/chunk-CYEBGC6G.js +77 -0
  19. package/dist/chunk-DHPD4XH5.js +827 -0
  20. package/dist/chunk-FDRQOG7Q.js +471 -0
  21. package/dist/chunk-GNXWTKQ6.js +48 -0
  22. package/dist/chunk-HFT2FXJP.js +12 -0
  23. package/dist/chunk-I2KLQ2HA.js +22 -0
  24. package/dist/chunk-IWUYIAY5.js +69 -0
  25. package/dist/chunk-IXY3BXU5.js +689 -0
  26. package/dist/chunk-JMLB7A2V.js +85 -0
  27. package/dist/chunk-K2E6A377.js +12 -0
  28. package/dist/chunk-M64Z6TYL.js +198 -0
  29. package/dist/chunk-NDVXBI7Z.js +12 -0
  30. package/dist/chunk-NIPAN4KA.js +76 -0
  31. package/dist/chunk-PX4RGO3N.js +12 -0
  32. package/dist/chunk-RFHXERNL.js +27 -0
  33. package/dist/chunk-VHGV66M7.js +12 -0
  34. package/dist/chunk-WO4BJMF3.js +82 -0
  35. package/dist/diagnostics.d.ts +1 -0
  36. package/dist/diagnostics.js +10 -0
  37. package/dist/express-assistant.d.ts +102 -0
  38. package/dist/express-assistant.js +12 -0
  39. package/dist/express.d.ts +98 -0
  40. package/dist/express.js +11 -0
  41. package/dist/feedback.d.ts +1 -0
  42. package/dist/feedback.js +10 -0
  43. package/dist/history.d.ts +1 -0
  44. package/dist/history.js +10 -0
  45. package/dist/index.d.ts +32 -0
  46. package/dist/index.js +202 -0
  47. package/dist/interactive-o_NZb-Xg.d.ts +47 -0
  48. package/dist/interactive.d.ts +30 -0
  49. package/dist/interactive.js +25 -0
  50. package/dist/mcp.d.ts +84 -0
  51. package/dist/mcp.js +9 -0
  52. package/dist/options-C7OYeNR-.d.ts +71 -0
  53. package/dist/options-Uf-qmQKN.d.ts +263 -0
  54. package/dist/policy.d.ts +1 -0
  55. package/dist/policy.js +10 -0
  56. package/dist/setup.d.ts +1 -0
  57. package/dist/setup.js +10 -0
  58. package/dist/shared.d.ts +129 -0
  59. package/dist/shared.js +20 -0
  60. package/dist/socket.d.ts +137 -0
  61. package/dist/socket.js +16 -0
  62. package/dist/targets.d.ts +1 -0
  63. package/dist/targets.js +10 -0
  64. package/dist/types-BqRzb_Cd.d.ts +346 -0
  65. package/dist/types-Crpil4kb.d.ts +136 -0
  66. package/dist/users.d.ts +1 -0
  67. package/dist/users.js +10 -0
  68. package/package.json +169 -0
@@ -0,0 +1,662 @@
1
+ import {
2
+ feedback_exports
3
+ } from "./chunk-VHGV66M7.js";
4
+ import {
5
+ extractSlackAuthContext,
6
+ resolveSlackMessageFormatter
7
+ } from "./chunk-GNXWTKQ6.js";
8
+ import {
9
+ UnsupportedSlackInteractiveRequestError,
10
+ 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";
36
+
37
+ // src/assistant/bridge.ts
38
+ import { Assistant } from "@slack/bolt";
39
+
40
+ // src/assistant/options.ts
41
+ var DEFAULT_INITIAL_REPLY = "Hi, how can I help?";
42
+ var DEFAULT_INITIAL_STATUS = {
43
+ status: "Thinking..."
44
+ };
45
+ var DEFAULT_STREAM_ERROR_MESSAGE = "I ran into an error while preparing this answer. Please try again.";
46
+
47
+ // src/assistant/helpers.ts
48
+ function toError(value) {
49
+ return value instanceof Error ? value : new Error(String(value));
50
+ }
51
+ function formatErrorForLog(error) {
52
+ if (error instanceof Error) {
53
+ return error.stack ?? error.message;
54
+ }
55
+ return String(error);
56
+ }
57
+ async function safeGetThreadContext(getThreadContext, logger) {
58
+ try {
59
+ const value = await getThreadContext();
60
+ if (value && typeof value === "object") {
61
+ return value;
62
+ }
63
+ } catch (error) {
64
+ logger.warn?.("getThreadContext failed", {
65
+ error: formatErrorForLog(error)
66
+ });
67
+ }
68
+ return {};
69
+ }
70
+ async function resolveInitialReply(resolver, context) {
71
+ if (resolver === void 0) {
72
+ return DEFAULT_INITIAL_REPLY;
73
+ }
74
+ const value = await resolver(context);
75
+ if (value === false) {
76
+ return void 0;
77
+ }
78
+ return value ?? void 0;
79
+ }
80
+ async function resolveInitialStatus(resolver, request) {
81
+ if (resolver === void 0) {
82
+ return DEFAULT_INITIAL_STATUS;
83
+ }
84
+ if (typeof resolver === "function") {
85
+ return await resolver(request) ?? void 0;
86
+ }
87
+ return resolver;
88
+ }
89
+ async function resolveStatusUpdate(resolver, label, event, rawArgs) {
90
+ if (!resolver) {
91
+ return label ? { status: label } : { status: "" };
92
+ }
93
+ if (!event) {
94
+ return void 0;
95
+ }
96
+ return await resolver({ event, rawArgs }) ?? void 0;
97
+ }
98
+ function resolveFeedbackSessionId(context, strategy) {
99
+ const threadTs = context.threadTs ?? context.messageTs;
100
+ switch (strategy) {
101
+ case "channel-id":
102
+ return context.channelId;
103
+ case "user-per-thread":
104
+ return `${context.channelId}:${threadTs}:${context.userId}`;
105
+ default:
106
+ return `${context.channelId}:${threadTs}`;
107
+ }
108
+ }
109
+
110
+ // src/assistant/lifecycle/thread-started.ts
111
+ function createThreadStartedHandler(options) {
112
+ return async (args) => {
113
+ const {
114
+ event,
115
+ context,
116
+ client,
117
+ logger,
118
+ say,
119
+ setSuggestedPrompts,
120
+ saveThreadContext
121
+ } = args;
122
+ const threadCtx = {
123
+ event,
124
+ context,
125
+ client,
126
+ logger
127
+ };
128
+ let savedThreadContext = false;
129
+ const saveContext = async () => {
130
+ if (savedThreadContext) return;
131
+ try {
132
+ await saveThreadContext();
133
+ savedThreadContext = true;
134
+ } catch (error) {
135
+ logger.error(
136
+ `[channel-slack-agent-core] saveThreadContext failed: ${error instanceof Error ? error.message : String(error)}`
137
+ );
138
+ }
139
+ };
140
+ try {
141
+ const initialReply = await resolveInitialReply(
142
+ options.getInitialReply,
143
+ threadCtx
144
+ );
145
+ if (initialReply) {
146
+ await say(initialReply);
147
+ }
148
+ } catch (error) {
149
+ logger.error(
150
+ `[channel-slack-agent-core] initial assistant reply failed: ${error instanceof Error ? error.message : String(error)}`
151
+ );
152
+ }
153
+ await saveContext();
154
+ try {
155
+ const prompts = await options.getSuggestedPrompts?.(threadCtx);
156
+ if (prompts && prompts.prompts.length > 0) {
157
+ await setSuggestedPrompts({
158
+ ...prompts.title ? { title: prompts.title } : {},
159
+ prompts: prompts.prompts
160
+ });
161
+ }
162
+ } catch (error) {
163
+ logger.error(
164
+ `[channel-slack-agent-core] setSuggestedPrompts failed: ${error instanceof Error ? error.message : String(error)}`
165
+ );
166
+ }
167
+ };
168
+ }
169
+
170
+ // src/assistant/lifecycle/thread-context-changed.ts
171
+ function createThreadContextChangedHandler() {
172
+ return async ({ event, saveThreadContext, logger }) => {
173
+ try {
174
+ await saveThreadContext();
175
+ logger.info("[channel-slack-agent-core] thread context changed saved", {
176
+ channelId: event.assistant_thread.channel_id,
177
+ threadTs: event.assistant_thread.thread_ts,
178
+ originChannelId: event.assistant_thread.context.channel_id,
179
+ teamId: event.assistant_thread.context.team_id
180
+ });
181
+ } catch (error) {
182
+ logger.error(
183
+ `[channel-slack-agent-core] threadContextChanged failed: ${error instanceof Error ? error.message : String(error)}`
184
+ );
185
+ }
186
+ };
187
+ }
188
+
189
+ // src/assistant/lifecycle/user-message.ts
190
+ import {
191
+ withinScope
192
+ } from "@cuylabs/agent-core";
193
+
194
+ // src/assistant/scope-attributes.ts
195
+ function buildAssistantScopeAttributes(message, auth, threadContext, prep) {
196
+ return {
197
+ slackChannelId: message.channelId,
198
+ slackChannelType: message.channelType,
199
+ slackUserId: message.userId,
200
+ slackTeamId: message.teamId ?? auth.teamId,
201
+ slackEnterpriseId: auth.enterpriseId,
202
+ slackThreadTs: message.threadTs,
203
+ slackMessageTs: message.messageTs,
204
+ slackAssistantOriginChannelId: threadContext.channel_id,
205
+ ...prep.scopeAttributes ?? {}
206
+ };
207
+ }
208
+
209
+ // src/assistant/sink.ts
210
+ function createAssistantSink(params) {
211
+ let stream;
212
+ let stopped = false;
213
+ function ensureStream(bufferSize) {
214
+ if (stream) return stream;
215
+ const streamArgs = {
216
+ ...params.chatStreamStartArgs ?? {},
217
+ task_display_mode: params.taskDisplayMode,
218
+ buffer_size: bufferSize
219
+ };
220
+ let created;
221
+ if (typeof params.sayStream === "function") {
222
+ created = params.sayStream(streamArgs);
223
+ } else {
224
+ const clientWithStream = params.client;
225
+ if (typeof clientWithStream.chatStream !== "function") {
226
+ throw new Error(
227
+ "Slack client does not expose chatStream; ensure @slack/web-api >=7.16.0 is installed."
228
+ );
229
+ }
230
+ created = clientWithStream.chatStream({
231
+ channel: params.channel,
232
+ thread_ts: params.threadTs,
233
+ ...params.teamId ? { recipient_team_id: params.teamId } : {},
234
+ ...params.userId ? { recipient_user_id: params.userId } : {},
235
+ ...streamArgs
236
+ });
237
+ }
238
+ stream = {
239
+ append: (args) => created.append(args),
240
+ stop: async (args) => {
241
+ if (stopped) return void 0;
242
+ stopped = true;
243
+ return created.stop(args);
244
+ }
245
+ };
246
+ return stream;
247
+ }
248
+ return {
249
+ async postMessage() {
250
+ throw new Error(
251
+ "Assistant bridge uses chat-stream mode and does not support postMessage."
252
+ );
253
+ },
254
+ async updateMessage() {
255
+ },
256
+ createChatStream: ({ bufferSize }) => ensureStream(bufferSize),
257
+ async appendError(text) {
258
+ if (stopped) return;
259
+ const target = ensureStream(256);
260
+ await target.append({ markdown_text: `
261
+
262
+ ${text}` });
263
+ },
264
+ async finalize() {
265
+ if (stopped || !stream) return;
266
+ await stream.stop();
267
+ }
268
+ };
269
+ }
270
+ function createAssistantInteractiveResponder(params) {
271
+ return {
272
+ async postMessage(message) {
273
+ const result = await params.client.chat.postMessage({
274
+ channel: params.channel,
275
+ thread_ts: params.threadTs,
276
+ text: message.text,
277
+ ...message.blocks ? { blocks: message.blocks } : {}
278
+ });
279
+ if (!result.channel || !result.ts) {
280
+ throw new Error(
281
+ "Slack chat.postMessage response did not include channel and ts."
282
+ );
283
+ }
284
+ return { channel: result.channel, ts: result.ts };
285
+ },
286
+ async updateMessage(ref, message) {
287
+ await params.client.chat.update({
288
+ channel: ref.channel,
289
+ ts: ref.ts,
290
+ text: message.text,
291
+ ...message.blocks ? { blocks: message.blocks } : {}
292
+ });
293
+ }
294
+ };
295
+ }
296
+
297
+ // src/assistant/lifecycle/user-message.ts
298
+ function createUserMessageHandler(deps) {
299
+ const { options, feedbackBlock, sessionStrategy } = deps;
300
+ const taskDisplayMode = options.taskDisplayMode ?? "timeline";
301
+ const messageFormatter = resolveSlackMessageFormatter(
302
+ options.formatChatMarkdown ?? {}
303
+ );
304
+ const formatStreamError = options.formatStreamError ?? (() => DEFAULT_STREAM_ERROR_MESSAGE);
305
+ const showReasoning = options.showReasoning ?? false;
306
+ const showToolUsage = options.showToolUsage ?? true;
307
+ const showSubagentToolUsage = options.showSubagentToolUsage ?? false;
308
+ const showSubagentResultInTask = options.showSubagentResultInTask ?? false;
309
+ const timeoutMs = options.timeoutMs ?? 12e4;
310
+ return async (args) => {
311
+ const {
312
+ message,
313
+ client,
314
+ context,
315
+ logger,
316
+ sayStream,
317
+ setStatus,
318
+ setSuggestedPrompts,
319
+ setTitle,
320
+ getThreadContext,
321
+ saveThreadContext
322
+ } = args;
323
+ const parsed = parseSlackMessageActivityFromMessageEvent(message);
324
+ if (!parsed) {
325
+ return;
326
+ }
327
+ const { channel, threadTs, text, userId } = parsed;
328
+ const teamId = context.teamId ?? context.enterpriseId;
329
+ if (!channel || !threadTs || !text) {
330
+ return;
331
+ }
332
+ const diagnosticsLogger = options.logger ?? logger;
333
+ const auth = extractSlackAuthContext(context, userId);
334
+ const threadContext = await safeGetThreadContext(
335
+ getThreadContext,
336
+ diagnosticsLogger
337
+ );
338
+ const assistantUtilities = {
339
+ setStatus: async (update) => {
340
+ await setStatus(update);
341
+ },
342
+ setSuggestedPrompts: async (prompts) => {
343
+ await setSuggestedPrompts({
344
+ ...prompts.title ? { title: prompts.title } : {},
345
+ prompts: prompts.prompts
346
+ });
347
+ },
348
+ setTitle: async (title) => {
349
+ await setTitle(title);
350
+ },
351
+ getThreadContext: () => getThreadContext(),
352
+ saveThreadContext: () => saveThreadContext()
353
+ };
354
+ const initialSessionId = resolveAssistantSessionId(parsed, sessionStrategy);
355
+ const baseRequest = {
356
+ message: parsed,
357
+ sessionId: initialSessionId,
358
+ client,
359
+ rawArgs: args,
360
+ auth,
361
+ threadContext,
362
+ assistant: assistantUtilities
363
+ };
364
+ const sink = createAssistantSink({
365
+ client,
366
+ sayStream,
367
+ channel,
368
+ threadTs,
369
+ teamId,
370
+ userId,
371
+ taskDisplayMode,
372
+ ...options.chatStreamStartArgs ? { chatStreamStartArgs: options.chatStreamStartArgs } : {}
373
+ });
374
+ let translatedError;
375
+ let unsupportedInteractive;
376
+ let timeoutId;
377
+ try {
378
+ const initialStatus = await resolveInitialStatus(
379
+ options.initialStatus,
380
+ baseRequest
381
+ );
382
+ if (initialStatus) {
383
+ try {
384
+ await setStatus(initialStatus);
385
+ } catch (error) {
386
+ diagnosticsLogger.warn?.("setStatus failed", {
387
+ error: formatErrorForLog(error)
388
+ });
389
+ }
390
+ }
391
+ let sessionId = initialSessionId;
392
+ if (options.resolveSession) {
393
+ const resolved = await options.resolveSession(baseRequest);
394
+ if (resolved && resolved.length > 0) {
395
+ sessionId = resolved;
396
+ }
397
+ }
398
+ const turnPrep = await options.prepareTurn?.({ ...baseRequest, sessionId }) ?? {};
399
+ if (turnPrep.sessionId && turnPrep.sessionId.length > 0) {
400
+ sessionId = turnPrep.sessionId;
401
+ }
402
+ const turnMessage = turnPrep.message ?? text;
403
+ const userMessageRequest = {
404
+ ...baseRequest,
405
+ sessionId,
406
+ message: { ...parsed, text: turnMessage }
407
+ };
408
+ if (options.formatThreadTitle) {
409
+ try {
410
+ const title = await options.formatThreadTitle(userMessageRequest);
411
+ if (title) {
412
+ await setTitle(title);
413
+ }
414
+ } catch (error) {
415
+ diagnosticsLogger.warn?.("setTitle failed", {
416
+ error: formatErrorForLog(error)
417
+ });
418
+ }
419
+ }
420
+ const configuredFinalBlocks = Array.isArray(
421
+ options.chatStreamFinalArgs?.blocks
422
+ ) ? options.chatStreamFinalArgs.blocks : [];
423
+ const finalBlocks = feedbackBlock ? [...configuredFinalBlocks, feedbackBlock] : configuredFinalBlocks;
424
+ const chatStreamFinalArgs = options.chatStreamFinalArgs || finalBlocks.length > 0 ? {
425
+ ...options.chatStreamFinalArgs ?? {},
426
+ ...finalBlocks.length > 0 ? { blocks: finalBlocks } : {}
427
+ } : void 0;
428
+ const bridgeOptions = resolveSlackEventBridgeOptions({
429
+ streamingMode: "chat-stream",
430
+ showReasoning,
431
+ showToolUsage,
432
+ showSubagentToolUsage,
433
+ showSubagentResultInTask,
434
+ ...options.formatToolTitle ? { formatToolTitle: options.formatToolTitle } : {},
435
+ ...options.formatToolUpdate ? { formatToolUpdate: options.formatToolUpdate } : {},
436
+ ...options.formatToolDetails ? { formatToolDetails: options.formatToolDetails } : {},
437
+ ...options.formatToolError ? { formatToolError: options.formatToolError } : {},
438
+ ...options.formatReasoningUpdate ? { formatReasoningUpdate: options.formatReasoningUpdate } : {},
439
+ ...options.chatStreamBufferSize !== void 0 ? { chatStreamBufferSize: options.chatStreamBufferSize } : {},
440
+ ...options.maxTaskUpdates !== void 0 ? { maxTaskUpdates: options.maxTaskUpdates } : {},
441
+ ...options.maxTaskUpdateTextChars !== void 0 ? { maxTaskUpdateTextChars: options.maxTaskUpdateTextChars } : {},
442
+ ...options.maxTaskUpdateFieldChars !== void 0 ? { maxTaskUpdateFieldChars: options.maxTaskUpdateFieldChars } : {},
443
+ ...chatStreamFinalArgs ? { chatStreamFinalArgs } : {},
444
+ formatMessageText: messageFormatter,
445
+ onStatusChange: async (label, event) => {
446
+ const update = await resolveStatusUpdate(
447
+ options.formatStatus,
448
+ label,
449
+ event,
450
+ args
451
+ );
452
+ if (update) {
453
+ try {
454
+ await setStatus(update);
455
+ } catch (error) {
456
+ diagnosticsLogger.warn?.("setStatus failed", {
457
+ error: formatErrorForLog(error)
458
+ });
459
+ }
460
+ }
461
+ },
462
+ ...options.handleInteractiveRequest ? {
463
+ handleInteractiveRequest: (interactive) => options.handleInteractiveRequest({
464
+ ...interactive,
465
+ slackActivity: parsed,
466
+ user: {
467
+ userId: userId ?? "unknown",
468
+ channelId: channel,
469
+ ...teamId ? { teamId } : {},
470
+ threadTs,
471
+ ...parsed.messageTs ? { messageTs: parsed.messageTs } : {}
472
+ },
473
+ sessionId,
474
+ message: turnMessage,
475
+ responder: createAssistantInteractiveResponder({
476
+ client,
477
+ channel,
478
+ threadTs
479
+ })
480
+ })
481
+ } : {}
482
+ });
483
+ const abortController = new AbortController();
484
+ timeoutId = timeoutMs > 0 ? setTimeout(() => abortController.abort(), timeoutMs) : void 0;
485
+ await runWithSlackTurnContext(
486
+ {
487
+ slackActivity: parsed,
488
+ user: {
489
+ userId: userId ?? "unknown",
490
+ channelId: channel,
491
+ ...teamId ? { teamId } : {},
492
+ threadTs
493
+ },
494
+ sessionId,
495
+ message: turnMessage,
496
+ auth,
497
+ threadContext,
498
+ assistant: assistantUtilities,
499
+ ...turnPrep.context ? { context: turnPrep.context } : {}
500
+ },
501
+ () => withinScope(
502
+ {
503
+ kind: "activity",
504
+ name: turnPrep.scopeName?.trim() || "slack-assistant-activity",
505
+ sessionId,
506
+ attributes: buildAssistantScopeAttributes(
507
+ parsed,
508
+ auth,
509
+ threadContext,
510
+ turnPrep
511
+ )
512
+ },
513
+ async () => {
514
+ const events = options.source.chat(sessionId, turnMessage, {
515
+ abort: abortController.signal,
516
+ ...turnPrep.system ? { system: turnPrep.system } : {}
517
+ });
518
+ const translated = (async function* () {
519
+ try {
520
+ for await (const event of events) {
521
+ if (event.type === "error") {
522
+ translatedError = toError(
523
+ event.error
524
+ );
525
+ yield {
526
+ type: "text-delta",
527
+ text: `
528
+
529
+ ${formatStreamError(translatedError)}`
530
+ };
531
+ yield { type: "complete" };
532
+ return;
533
+ }
534
+ yield event;
535
+ }
536
+ } catch (error) {
537
+ if (error instanceof UnsupportedSlackInteractiveRequestError) {
538
+ unsupportedInteractive = error;
539
+ throw error;
540
+ }
541
+ translatedError = toError(error);
542
+ yield {
543
+ type: "text-delta",
544
+ text: `
545
+
546
+ ${formatStreamError(translatedError)}`
547
+ };
548
+ yield { type: "complete" };
549
+ }
550
+ })();
551
+ const finalText = await bridgeAgentEventsToSlack(
552
+ translated,
553
+ sink,
554
+ bridgeOptions
555
+ );
556
+ if (!translatedError && options.getFollowUpPrompts) {
557
+ try {
558
+ const followUps = await options.getFollowUpPrompts({
559
+ ...userMessageRequest,
560
+ finalText
561
+ });
562
+ if (followUps && followUps.prompts.length > 0) {
563
+ await assistantUtilities.setSuggestedPrompts(followUps);
564
+ }
565
+ } catch (error) {
566
+ diagnosticsLogger.warn?.("getFollowUpPrompts failed", {
567
+ error: formatErrorForLog(error)
568
+ });
569
+ }
570
+ }
571
+ }
572
+ )
573
+ );
574
+ } catch (error) {
575
+ if (error instanceof UnsupportedSlackInteractiveRequestError && !unsupportedInteractive) {
576
+ unsupportedInteractive = error;
577
+ }
578
+ if (!unsupportedInteractive) {
579
+ try {
580
+ await sink.appendError(formatStreamError(toError(error)));
581
+ } catch {
582
+ }
583
+ }
584
+ try {
585
+ await sink.finalize();
586
+ } catch {
587
+ }
588
+ } finally {
589
+ if (timeoutId) {
590
+ clearTimeout(timeoutId);
591
+ }
592
+ try {
593
+ await setStatus({ status: "" });
594
+ } catch {
595
+ }
596
+ if (translatedError) {
597
+ logger.error(
598
+ `[channel-slack-agent-core] userMessage error surfaced to user: ${translatedError.message}`
599
+ );
600
+ }
601
+ }
602
+ };
603
+ }
604
+
605
+ // src/assistant/bridge.ts
606
+ function createSlackAssistantBridge(options) {
607
+ if (!options.source || typeof options.source.chat !== "function") {
608
+ throw new Error(
609
+ "createSlackAssistantBridge: options.source must implement AgentTurnSource"
610
+ );
611
+ }
612
+ if (options.timeoutMs !== void 0 && (!Number.isFinite(options.timeoutMs) || options.timeoutMs < 0)) {
613
+ throw new Error(
614
+ "createSlackAssistantBridge: timeoutMs must be a finite non-negative number"
615
+ );
616
+ }
617
+ const sessionStrategy = options.sessionStrategy ?? "thread-aware";
618
+ 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;
621
+ const threadStarted = createThreadStartedHandler(options);
622
+ const threadContextChanged = createThreadContextChangedHandler();
623
+ const threadContextStore = options.threadContextStore ?? createSlackAssistantThreadContextStore();
624
+ const userMessage = createUserMessageHandler({
625
+ options,
626
+ feedbackBlock,
627
+ sessionStrategy
628
+ });
629
+ const config = {
630
+ threadStarted,
631
+ threadContextChanged,
632
+ userMessage,
633
+ // The store shape must match Bolt's `AssistantThreadContextStore` exactly.
634
+ // We accept the structural alias above and cast here so callers don't
635
+ // need to import Bolt's internal types in their own code.
636
+ threadContextStore
637
+ };
638
+ const assistant = new Assistant(config);
639
+ function install(app) {
640
+ app.assistant(assistant);
641
+ if (feedbackConfig) {
642
+ (0, feedback_exports.registerSlackFeedbackAction)(app, {
643
+ ...feedbackConfig,
644
+ resolveSessionId: (context) => resolveFeedbackSessionId(context, sessionStrategy),
645
+ onFeedback: feedbackConfig.onFeedback ?? (async (_ctx) => {
646
+ })
647
+ });
648
+ }
649
+ }
650
+ return {
651
+ assistant,
652
+ install,
653
+ ...feedbackConfig ? { feedbackActionId } : {}
654
+ };
655
+ }
656
+
657
+ export {
658
+ parseSlackMessageActivityFromMessageEvent,
659
+ resolveAssistantSessionId,
660
+ createSlackAssistantThreadContextStore,
661
+ createSlackAssistantBridge
662
+ };