@cuylabs/channel-slack 0.10.0 → 0.12.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 (42) hide show
  1. package/README.md +36 -3
  2. package/dist/adapter/index.d.ts +53 -0
  3. package/dist/adapter/index.js +13 -0
  4. package/dist/app-surface.d.ts +86 -0
  5. package/dist/app-surface.js +15 -0
  6. package/dist/app.d.ts +58 -0
  7. package/dist/app.js +86 -0
  8. package/dist/artifacts/index.d.ts +57 -3
  9. package/dist/artifacts/index.js +88 -0
  10. package/dist/assistant/index.d.ts +18 -53
  11. package/dist/assistant/index.js +15 -184
  12. package/dist/bolt-app-BM0tiL7c.d.ts +49 -0
  13. package/dist/{chunk-TWJGVDA2.js → chunk-37RN2YUI.js} +88 -1
  14. package/dist/chunk-LFQCINHI.js +187 -0
  15. package/dist/chunk-Q6YX7HHK.js +1062 -0
  16. package/dist/chunk-RHOIVQLD.js +127 -0
  17. package/dist/chunk-RTDLIYEE.js +446 -0
  18. package/dist/core.d.ts +5 -201
  19. package/dist/core.js +10 -12
  20. package/dist/feedback/index.d.ts +2 -2
  21. package/dist/feedback/index.js +5 -120
  22. package/dist/formatting-C-kwQseI.d.ts +25 -0
  23. package/dist/index.d.ts +6 -3
  24. package/dist/index.js +10 -12
  25. package/dist/interactive/index.d.ts +68 -4
  26. package/dist/interactive/index.js +432 -0
  27. package/dist/options-B0xQCaez.d.ts +221 -0
  28. package/dist/options-DQacQDmD.d.ts +368 -0
  29. package/dist/runtime/index.d.ts +6 -220
  30. package/dist/socket.d.ts +142 -0
  31. package/dist/socket.js +77 -0
  32. package/dist/transports/index.d.ts +2 -1
  33. package/dist/transports/socket/index.d.ts +4 -49
  34. package/dist/turn-BGAXddH_.d.ts +178 -0
  35. package/dist/types-wLZzyI9r.d.ts +375 -0
  36. package/docs/README.md +1 -0
  37. package/docs/concepts/interactive-requests.md +85 -0
  38. package/docs/reference/channel-slack-boundary.md +6 -3
  39. package/docs/reference/exports.md +6 -2
  40. package/docs/reference/source-layout.md +1 -0
  41. package/package.json +23 -3
  42. package/dist/chunk-ISOMBQXE.js +0 -89
package/README.md CHANGED
@@ -4,9 +4,10 @@ Agent-runtime-agnostic Slack channel primitives.
4
4
 
5
5
  This package owns reusable Slack mechanics: event parsing, message admission,
6
6
  history loading, formatting, setup inspection, auth helpers, entrypoint
7
- normalization, artifact publishing, interactive request rendering/storage,
8
- response sink contracts, and HTTP or Socket Mode transport helpers. It does not
9
- create or run an agent, and it does not depend on an agent SDK.
7
+ normalization, artifact publishing, interactive request rendering/storage and
8
+ controller wiring, response sink contracts, Slack Assistant/classic message
9
+ mounting, and HTTP or Socket Mode transport helpers. It does not create or run
10
+ an agent, and it does not depend on an agent SDK.
10
11
 
11
12
  Runtime-specific adapters should compose these primitives with their own turn
12
13
  types, event streams, tools, prompts, and deployment policy.
@@ -58,9 +59,41 @@ Most adapters follow the same shape:
58
59
  4. Run the application-owned runtime.
59
60
  5. Format the response for Slack.
60
61
 
62
+ For a runtime-neutral direct Slack mount, pass a `SlackTurnSource`:
63
+
64
+ ```typescript
65
+ import { mountSlackAppSocket } from "@cuylabs/channel-slack/socket";
66
+
67
+ await mountSlackAppSocket({
68
+ source,
69
+ appToken: process.env.SLACK_APP_TOKEN,
70
+ botToken: process.env.SLACK_BOT_TOKEN,
71
+ });
72
+ ```
73
+
74
+ Add the Slack-native approval/human-input controller from the `interactive`
75
+ subpath when your runtime can pause on interactive request events:
76
+
77
+ ```typescript
78
+ import { createSlackInteractiveController } from "@cuylabs/channel-slack/interactive";
79
+ import { mountSlackAppSocket } from "@cuylabs/channel-slack/socket";
80
+
81
+ const interactive = createSlackInteractiveController({
82
+ namespace: "my_agent_slack",
83
+ });
84
+
85
+ await mountSlackAppSocket({
86
+ source,
87
+ interactive,
88
+ appToken: process.env.SLACK_APP_TOKEN,
89
+ botToken: process.env.SLACK_BOT_TOKEN,
90
+ });
91
+ ```
92
+
61
93
  ## Documentation
62
94
 
63
95
  - [Package boundary](docs/reference/channel-slack-boundary.md)
96
+ - [Interactive requests](docs/concepts/interactive-requests.md)
64
97
  - [Exports and peer expectations](docs/reference/exports.md)
65
98
  - [Source layout](docs/reference/source-layout.md)
66
99
  - [Docs index](docs/README.md)
@@ -0,0 +1,53 @@
1
+ import { a as SlackChannelOptions, S as SlackChannelAdapter } from '../types-wLZzyI9r.js';
2
+ export { b as SlackSessionStrategy, c as SlackStreamingMode, d as SlackToolStartEvent } from '../types-wLZzyI9r.js';
3
+ import { S as SlackActivityInfo } from '../activity-ByrD9Ftr.js';
4
+ import '../turn-BGAXddH_.js';
5
+ import '../interactive-CbKYkkc_.js';
6
+ import '../options-B0xQCaez.js';
7
+ import '../types-C8nkPuD4.js';
8
+ import '../types-Cywfj8Mj.js';
9
+ import '../logging-Bl3HfcC8.js';
10
+
11
+ /**
12
+ * Slack Channel Adapter
13
+ *
14
+ * Creates a configured Bolt handler that bridges a `SlackTurnSource` to Slack
15
+ * via @slack/bolt.
16
+ *
17
+ * The adapter mounts message/event handlers on a Bolt `App` instance and
18
+ * processes each turn by:
19
+ * 1. Parsing the Slack event into a `SlackActivityInfo`.
20
+ * 2. Resolving a session ID via the configured session strategy.
21
+ * 3. Calling `source.chat()` with the user message.
22
+ * 4. Streaming the response back to Slack via progressive updates or a
23
+ * single final post.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { App } from "@slack/bolt";
28
+ * import { createSlackChannelAdapter } from "@cuylabs/channel-slack/adapter";
29
+ *
30
+ * const app = new App({ token: process.env.SLACK_BOT_TOKEN, signingSecret: process.env.SLACK_SIGNING_SECRET });
31
+ * const adapter = createSlackChannelAdapter({ source });
32
+ * adapter.mount(app);
33
+ * await app.start(3000);
34
+ * ```
35
+ */
36
+
37
+ declare function createSlackChannelAdapter(options: SlackChannelOptions): SlackChannelAdapter;
38
+
39
+ /**
40
+ * Session mapping — Slack activity info to runtime session IDs.
41
+ *
42
+ * The default strategy (`"thread-aware"`) produces natural conversation
43
+ * groupings by using the thread timestamp when present and falling back to
44
+ * the channel ID for DMs and top-level messages.
45
+ */
46
+
47
+ interface SlackSessionMap {
48
+ /** Resolve (or create) a session ID for the given Slack activity. */
49
+ resolve(info: SlackActivityInfo): string | Promise<string>;
50
+ }
51
+ declare function createSlackSessionMap(options: SlackChannelOptions): SlackSessionMap;
52
+
53
+ export { SlackChannelAdapter, SlackChannelOptions, type SlackSessionMap, createSlackChannelAdapter, createSlackSessionMap };
@@ -0,0 +1,13 @@
1
+ import {
2
+ createSlackChannelAdapter,
3
+ createSlackSessionMap
4
+ } from "../chunk-RTDLIYEE.js";
5
+ import "../chunk-IAQXQESO.js";
6
+ import "../chunk-37RN2YUI.js";
7
+ import "../chunk-3KP3CBCC.js";
8
+ import "../chunk-FPCE5V5Y.js";
9
+ import "../chunk-6WHFQUYQ.js";
10
+ export {
11
+ createSlackChannelAdapter,
12
+ createSlackSessionMap
13
+ };
@@ -0,0 +1,86 @@
1
+ import { App } from '@slack/bolt';
2
+ import { WebClient } from '@slack/web-api';
3
+ import { k as SlackTurnRequestContext, e as SlackAssistantUtilities, j as SlackTurnPreparation } from './turn-BGAXddH_.js';
4
+ import { C as CreateSlackAssistantBridgeOptions, d as SlackAssistantFeedbackConfig, S as SlackAssistantBridge } from './options-DQacQDmD.js';
5
+ import { L as Logger } from './logging-Bl3HfcC8.js';
6
+ import { o as SlackTurnSource } from './options-B0xQCaez.js';
7
+ import { a as SlackChannelOptions } from './types-wLZzyI9r.js';
8
+ import { SlackFeedbackHandler } from './feedback/index.js';
9
+ import { h as SlackInteractiveRequestHandler } from './types-Cywfj8Mj.js';
10
+ import './activity-ByrD9Ftr.js';
11
+ import './interactive-CbKYkkc_.js';
12
+ import './formatting-C-kwQseI.js';
13
+ import './types-C8nkPuD4.js';
14
+ import '@slack/types';
15
+
16
+ /**
17
+ * Shared installer for the direct Slack app surfaces.
18
+ *
19
+ * HTTP Events API and Socket Mode differ only in how Bolt receives inbound
20
+ * events. The Assistant pane, app_mention, DM/channel routing, feedback, and
21
+ * interactive request wiring are mounted here so both transports behave the
22
+ * same.
23
+ */
24
+
25
+ interface MountSlackAppTurnRequestContext extends SlackTurnRequestContext {
26
+ /** Present only for Assistant-pane turns. */
27
+ assistant?: SlackAssistantUtilities;
28
+ /** Present for Assistant-pane turns; use direct history helpers for Slack API context. */
29
+ client?: WebClient;
30
+ /** Raw Bolt assistant args for advanced hosts. */
31
+ rawArgs?: unknown;
32
+ }
33
+ interface SlackAppSurfaceInteractiveController {
34
+ handleInteractiveRequest: SlackInteractiveRequestHandler;
35
+ install(app: App): void;
36
+ }
37
+ interface SlackAppSurfaceViewWorkflowController {
38
+ install(app: App): void;
39
+ }
40
+ interface SlackAppSurfaceOptions extends Omit<CreateSlackAssistantBridgeOptions, "feedback" | "source" | "prepareTurn" | "resolveSession" | "handleInteractiveRequest"> {
41
+ /** Source of Slack turns. */
42
+ source: SlackTurnSource;
43
+ /**
44
+ * Prepare a Slack turn for every direct Slack surface registered by this
45
+ * mount: Assistant pane, @mentions, and DMs.
46
+ */
47
+ prepareTurn?: (request: MountSlackAppTurnRequestContext) => SlackTurnPreparation | Promise<SlackTurnPreparation>;
48
+ /**
49
+ * Resolve the runtime session for every direct Slack surface. Returning
50
+ * `undefined` falls back to the configured session strategy.
51
+ */
52
+ resolveSession?: (request: MountSlackAppTurnRequestContext) => string | undefined | Promise<string | undefined>;
53
+ /** Register `app.event("app_mention", ...)`. @default true */
54
+ respondToMentions?: boolean;
55
+ /** Register `app.message(...)` for DMs. @default true */
56
+ respondToMessages?: boolean;
57
+ /** Forward plain channel/group messages too. @default false */
58
+ respondToChannelMessages?: boolean;
59
+ /** Resolve or skip classic Slack channel-adapter messages. Return undefined to skip. */
60
+ resolveMessage?: SlackChannelOptions["resolveMessage"];
61
+ /** Feedback config. Pass `false` to omit feedback blocks. */
62
+ feedback?: SlackAssistantFeedbackConfig | false;
63
+ /** Convenience feedback handler. Ignored when `feedback` is set. */
64
+ onFeedback?: SlackFeedbackHandler;
65
+ /** Maximum turn runtime in ms. Set `0` to disable. @default 120_000 */
66
+ timeoutMs?: number;
67
+ /** Optional logger for diagnostics. */
68
+ logger?: Logger;
69
+ /**
70
+ * Slack-native approval/human-input controller. Pair this with a runtime
71
+ * that can pause on interactive request events.
72
+ */
73
+ interactive?: SlackAppSurfaceInteractiveController;
74
+ /**
75
+ * Product/runtime Slack modal workflow controller. Use this for workflows that
76
+ * are richer than approval/human-input, such as incident triage forms or
77
+ * report-generation setup modals.
78
+ */
79
+ viewWorkflows?: SlackAppSurfaceViewWorkflowController;
80
+ }
81
+ interface SlackAppSurfaceResult {
82
+ bridge: SlackAssistantBridge;
83
+ }
84
+ declare function installSlackAppSurface(boltApp: App, options: SlackAppSurfaceOptions): SlackAppSurfaceResult;
85
+
86
+ export { type MountSlackAppTurnRequestContext, type SlackAppSurfaceInteractiveController, type SlackAppSurfaceOptions, type SlackAppSurfaceResult, type SlackAppSurfaceViewWorkflowController, installSlackAppSurface };
@@ -0,0 +1,15 @@
1
+ import {
2
+ installSlackAppSurface
3
+ } from "./chunk-LFQCINHI.js";
4
+ import "./chunk-Q6YX7HHK.js";
5
+ import "./chunk-RHOIVQLD.js";
6
+ import "./chunk-IRFKUPJN.js";
7
+ import "./chunk-RTDLIYEE.js";
8
+ import "./chunk-IAQXQESO.js";
9
+ import "./chunk-37RN2YUI.js";
10
+ import "./chunk-3KP3CBCC.js";
11
+ import "./chunk-FPCE5V5Y.js";
12
+ import "./chunk-6WHFQUYQ.js";
13
+ export {
14
+ installSlackAppSurface
15
+ };
package/dist/app.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ import { Server } from 'node:http';
2
+ import { Application } from 'express';
3
+ import { App, ExpressReceiver } from '@slack/bolt';
4
+ import { CreateSlackBoltAppOptions } from './transports/http/index.js';
5
+ import { e as SlackDirectAuthOptions, d as SlackDirectAuthMode } from './types-B9NfCVrk.js';
6
+ import { SlackAppSurfaceOptions } from './app-surface.js';
7
+ export { MountSlackAppTurnRequestContext } from './app-surface.js';
8
+ import { S as SlackAssistantBridge } from './options-DQacQDmD.js';
9
+ import '@slack/web-api';
10
+ import './turn-BGAXddH_.js';
11
+ import './activity-ByrD9Ftr.js';
12
+ import './logging-Bl3HfcC8.js';
13
+ import './options-B0xQCaez.js';
14
+ import './types-C8nkPuD4.js';
15
+ import './types-Cywfj8Mj.js';
16
+ import './interactive-CbKYkkc_.js';
17
+ import './types-wLZzyI9r.js';
18
+ import './feedback/index.js';
19
+ import '@slack/types';
20
+ import './formatting-C-kwQseI.js';
21
+
22
+ /**
23
+ * Unified Slack app over the HTTP Events API.
24
+ *
25
+ * This file owns only the HTTP/Bolt receiver lifecycle. The actual Slack
26
+ * surfaces (Assistant pane, app mentions, DMs/channel messages, feedback, and
27
+ * interactive requests) are mounted by `installSlackAppSurface` so Socket
28
+ * Mode gets the exact same behavior.
29
+ */
30
+
31
+ interface MountSlackAppOptions extends SlackAppSurfaceOptions, Omit<CreateSlackBoltAppOptions, "app" | "path" | "botToken" | "signingSecret" | "auth"> {
32
+ /** Slack bot token (`xoxb-...`). @default process.env.SLACK_BOT_TOKEN */
33
+ botToken?: string;
34
+ /** Slack signing secret. @default process.env.SLACK_SIGNING_SECRET */
35
+ signingSecret?: string;
36
+ /** Direct-mode auth config (single-workspace, OAuth, custom). */
37
+ auth?: SlackDirectAuthOptions;
38
+ /** Slack Events API callback path. @default "/slack/events" */
39
+ path?: string;
40
+ /** Port to listen on. @default process.env.PORT || 3000 */
41
+ port?: number | null;
42
+ /** Optional host for `app.listen(port, host)`. */
43
+ host?: string;
44
+ /** Pre-existing Express app. */
45
+ app?: Application;
46
+ }
47
+ interface MountSlackAppResult {
48
+ app: Application;
49
+ boltApp: App;
50
+ receiver: ExpressReceiver;
51
+ authMode: SlackDirectAuthMode;
52
+ routePath: string;
53
+ bridge: SlackAssistantBridge;
54
+ server?: Server;
55
+ }
56
+ declare function mountSlackApp(options: MountSlackAppOptions): Promise<MountSlackAppResult>;
57
+
58
+ export { type MountSlackAppOptions, type MountSlackAppResult, mountSlackApp };
package/dist/app.js ADDED
@@ -0,0 +1,86 @@
1
+ import {
2
+ createSlackBoltApp
3
+ } from "./chunk-QJYCHWN6.js";
4
+ import "./chunk-S3SWPYXJ.js";
5
+ import {
6
+ installSlackAppSurface
7
+ } from "./chunk-LFQCINHI.js";
8
+ import "./chunk-Q6YX7HHK.js";
9
+ import "./chunk-RHOIVQLD.js";
10
+ import "./chunk-IRFKUPJN.js";
11
+ import "./chunk-RTDLIYEE.js";
12
+ import "./chunk-IAQXQESO.js";
13
+ import "./chunk-37RN2YUI.js";
14
+ import "./chunk-3KP3CBCC.js";
15
+ import "./chunk-FPCE5V5Y.js";
16
+ import "./chunk-6WHFQUYQ.js";
17
+
18
+ // src/app.ts
19
+ async function mountSlackApp(options) {
20
+ const {
21
+ botToken,
22
+ signingSecret,
23
+ auth,
24
+ path,
25
+ processBeforeResponse,
26
+ signatureVerification,
27
+ boltAppOptions,
28
+ receiverOptions,
29
+ port: portOption,
30
+ host,
31
+ app: providedApp,
32
+ ...surfaceOptions
33
+ } = options;
34
+ const {
35
+ boltApp,
36
+ receiver,
37
+ app: expressApp,
38
+ authMode,
39
+ routePath
40
+ } = await createSlackBoltApp({
41
+ signingSecret,
42
+ path,
43
+ botToken,
44
+ auth,
45
+ app: providedApp,
46
+ processBeforeResponse,
47
+ signatureVerification,
48
+ boltAppOptions,
49
+ receiverOptions
50
+ });
51
+ const { bridge } = installSlackAppSurface(boltApp, surfaceOptions);
52
+ expressApp.use(
53
+ receiver.router
54
+ );
55
+ const port = portOption === void 0 ? resolvePort(process.env.PORT) : portOption;
56
+ let server;
57
+ if (!providedApp && port !== null) {
58
+ const onListen = () => {
59
+ process.stdout.write(
60
+ `Slack app listening on port ${port} at ${routePath}
61
+ `
62
+ );
63
+ };
64
+ server = host ? expressApp.listen(port, host, onListen) : expressApp.listen(port, onListen);
65
+ }
66
+ return {
67
+ app: expressApp,
68
+ boltApp,
69
+ receiver,
70
+ authMode,
71
+ routePath,
72
+ bridge,
73
+ ...server ? { server } : {}
74
+ };
75
+ }
76
+ function resolvePort(port) {
77
+ if (!port) return 3e3;
78
+ const parsed = Number(port);
79
+ if (!Number.isInteger(parsed) || parsed < 0) {
80
+ throw new Error(`Invalid PORT value: ${port}`);
81
+ }
82
+ return parsed;
83
+ }
84
+ export {
85
+ mountSlackApp
86
+ };
@@ -1,5 +1,5 @@
1
- import { S as SlackArtifact, l as SlackLinkArtifact, P as PublishSlackArtifactOptions, g as SlackArtifactPublication, i as SlackCanvasArtifact, j as SlackFileArtifact, k as SlackImageArtifact, m as SlackTextArtifact } from '../types-C8nkPuD4.js';
2
- export { a as SlackArtifactBase, b as SlackArtifactBinaryData, c as SlackArtifactCanvasResponse, d as SlackArtifactClient, e as SlackArtifactFileUploadResponse, f as SlackArtifactPostMessageResponse, h as SlackArtifactPublishMethod } from '../types-C8nkPuD4.js';
1
+ import { S as SlackArtifact, l as SlackLinkArtifact, P as PublishSlackArtifactOptions, g as SlackArtifactPublication, i as SlackCanvasArtifact, j as SlackFileArtifact, k as SlackImageArtifact, m as SlackTextArtifact, d as SlackArtifactClient } from '../types-C8nkPuD4.js';
2
+ export { a as SlackArtifactBase, b as SlackArtifactBinaryData, c as SlackArtifactCanvasResponse, e as SlackArtifactFileUploadResponse, f as SlackArtifactPostMessageResponse, h as SlackArtifactPublishMethod } from '../types-C8nkPuD4.js';
3
3
 
4
4
  interface SlackArtifactBlockKitMessage {
5
5
  text: string;
@@ -25,4 +25,58 @@ declare function publishSlackCanvasArtifact(options: PublishSlackArtifactOptions
25
25
  artifact: SlackCanvasArtifact;
26
26
  }): Promise<SlackArtifactPublication>;
27
27
 
28
- export { PublishSlackArtifactOptions, SlackArtifact, type SlackArtifactBlockKitMessage, SlackArtifactPublication, SlackCanvasArtifact, SlackFileArtifact, SlackImageArtifact, SlackLinkArtifact, SlackTextArtifact, createSlackArtifactBlocks, createSlackLinkArtifactBlocks, publishSlackArtifact, publishSlackCanvasArtifact, publishSlackFileArtifact, publishSlackImageArtifact, publishSlackLinkArtifact, publishSlackTextArtifact };
28
+ interface SlackFinalResponseArtifactContext {
29
+ text: string;
30
+ formattedText: string;
31
+ client: SlackArtifactClient;
32
+ channelId: string;
33
+ threadTs?: string;
34
+ }
35
+ interface SlackFinalResponseArtifactResult {
36
+ publication: SlackArtifactPublication;
37
+ }
38
+ type SlackFinalResponseArtifactDeliveryMode = "supplemental" | "replace";
39
+ type SlackFinalResponseArtifactPublisher = (context: SlackFinalResponseArtifactContext) => Promise<SlackFinalResponseArtifactResult | undefined>;
40
+ type SlackFinalResponseArtifactValueResolver<T> = T | ((context: SlackFinalResponseArtifactContext) => T | Promise<T>);
41
+ interface CreateSlackFinalResponseArtifactPublisherOptions {
42
+ /**
43
+ * Minimum raw-response characters required before publishing an artifact.
44
+ *
45
+ * @default 4000
46
+ */
47
+ minCharacters?: number;
48
+ /**
49
+ * Canvas/file title.
50
+ *
51
+ * @default "Agent response"
52
+ */
53
+ title?: SlackFinalResponseArtifactValueResolver<string | undefined>;
54
+ /**
55
+ * Optional Slack artifact summary.
56
+ */
57
+ summary?: SlackFinalResponseArtifactValueResolver<string | undefined>;
58
+ /**
59
+ * Prefer creating a channel canvas when the Slack client exposes
60
+ * `conversations.canvases.create`.
61
+ *
62
+ * @default true
63
+ */
64
+ channelCanvas?: boolean;
65
+ /**
66
+ * Fallback when Canvas publication fails.
67
+ *
68
+ * @default "file"
69
+ */
70
+ fallback?: "file" | "none";
71
+ /**
72
+ * Called after a Canvas or fallback file is published.
73
+ */
74
+ onPublished?: (result: SlackFinalResponseArtifactResult, context: SlackFinalResponseArtifactContext) => void | Promise<void>;
75
+ /**
76
+ * Called when Canvas publication fails and no fallback publication succeeds.
77
+ */
78
+ onError?: (error: unknown, context: SlackFinalResponseArtifactContext) => void | Promise<void>;
79
+ }
80
+ declare function createSlackFinalResponseArtifactPublisher({ minCharacters, title, summary, channelCanvas, fallback, onPublished, onError, }?: CreateSlackFinalResponseArtifactPublisherOptions): SlackFinalResponseArtifactPublisher;
81
+
82
+ export { type CreateSlackFinalResponseArtifactPublisherOptions, PublishSlackArtifactOptions, SlackArtifact, type SlackArtifactBlockKitMessage, SlackArtifactClient, SlackArtifactPublication, SlackCanvasArtifact, SlackFileArtifact, type SlackFinalResponseArtifactContext, type SlackFinalResponseArtifactDeliveryMode, type SlackFinalResponseArtifactPublisher, type SlackFinalResponseArtifactResult, type SlackFinalResponseArtifactValueResolver, SlackImageArtifact, SlackLinkArtifact, SlackTextArtifact, createSlackArtifactBlocks, createSlackFinalResponseArtifactPublisher, createSlackLinkArtifactBlocks, publishSlackArtifact, publishSlackCanvasArtifact, publishSlackFileArtifact, publishSlackImageArtifact, publishSlackLinkArtifact, publishSlackTextArtifact };
@@ -287,8 +287,96 @@ function readUploadedFileId(response) {
287
287
  function readString(value) {
288
288
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
289
289
  }
290
+
291
+ // src/artifacts/final-response.ts
292
+ var DEFAULT_MIN_CHARACTERS = 4e3;
293
+ var DEFAULT_TITLE = "Agent response";
294
+ function createSlackFinalResponseArtifactPublisher({
295
+ minCharacters = DEFAULT_MIN_CHARACTERS,
296
+ title = DEFAULT_TITLE,
297
+ summary,
298
+ channelCanvas = true,
299
+ fallback = "file",
300
+ onPublished,
301
+ onError
302
+ } = {}) {
303
+ const configuredThreshold = Math.floor(minCharacters);
304
+ const threshold = Number.isFinite(configuredThreshold) && configuredThreshold > 0 ? configuredThreshold : DEFAULT_MIN_CHARACTERS;
305
+ return async (context) => {
306
+ const text = context.text.trim();
307
+ if (text.length < threshold) {
308
+ return void 0;
309
+ }
310
+ const resolvedTitle = normalizeText2(await resolveValue(title, context)) ?? DEFAULT_TITLE;
311
+ const resolvedSummary = normalizeText2(await resolveValue(summary, context));
312
+ let lastError;
313
+ try {
314
+ const publication = await publishSlackCanvasArtifact({
315
+ client: context.client,
316
+ channelId: context.channelId,
317
+ ...context.threadTs ? { threadTs: context.threadTs } : {},
318
+ artifact: {
319
+ kind: "canvas",
320
+ title: resolvedTitle,
321
+ markdown: text,
322
+ channelCanvas,
323
+ ...resolvedSummary ? { summary: resolvedSummary } : {},
324
+ metadata: {
325
+ source: "slack-final-response",
326
+ characterCount: text.length
327
+ }
328
+ }
329
+ });
330
+ const result = { publication };
331
+ await onPublished?.(result, context);
332
+ return result;
333
+ } catch (error) {
334
+ lastError = error;
335
+ }
336
+ if (fallback === "file") {
337
+ try {
338
+ const publication = await publishSlackTextArtifact({
339
+ client: context.client,
340
+ channelId: context.channelId,
341
+ ...context.threadTs ? { threadTs: context.threadTs } : {},
342
+ artifact: {
343
+ kind: "text",
344
+ title: resolvedTitle,
345
+ text,
346
+ filename: filenameFromTitle2(resolvedTitle),
347
+ ...resolvedSummary ? { summary: resolvedSummary } : {},
348
+ metadata: {
349
+ source: "slack-final-response",
350
+ characterCount: text.length,
351
+ canvasFallback: true
352
+ }
353
+ }
354
+ });
355
+ const result = { publication };
356
+ await onPublished?.(result, context);
357
+ return result;
358
+ } catch (error) {
359
+ lastError = error;
360
+ }
361
+ }
362
+ await onError?.(lastError, context);
363
+ return void 0;
364
+ };
365
+ }
366
+ async function resolveValue(value, context) {
367
+ return typeof value === "function" ? await value(context) : value;
368
+ }
369
+ function normalizeText2(value) {
370
+ const trimmed = value?.trim();
371
+ return trimmed ? trimmed : void 0;
372
+ }
373
+ function filenameFromTitle2(title) {
374
+ const slug = title.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
375
+ return `${slug || "agent-response"}.txt`;
376
+ }
290
377
  export {
291
378
  createSlackArtifactBlocks,
379
+ createSlackFinalResponseArtifactPublisher,
292
380
  createSlackLinkArtifactBlocks,
293
381
  publishSlackArtifact,
294
382
  publishSlackCanvasArtifact,
@@ -1,58 +1,23 @@
1
- import { S as SlackActivityInfo } from '../activity-ByrD9Ftr.js';
1
+ import { C as CreateSlackAssistantBridgeOptions, S as SlackAssistantBridge } from '../options-DQacQDmD.js';
2
+ export { A as AssistantLifecycleArgs, a as AssistantThreadStartedArgs, M as MaybePromise, P as ParsedAssistantUserMessage, b as SlackAssistantCancelControlOptions, c as SlackAssistantCancelControlVisibleWhen, d as SlackAssistantFeedbackConfig, e as SlackAssistantSessionStrategy, f as SlackAssistantStatusContext, g as SlackAssistantThreadContextStoreLike, h as SlackAssistantThreadStartedContext, i as SlackAssistantTurnCancelContext, j as SlackAssistantTurnControlsOptions, k as SlackAssistantTurnPreparation, l as SlackAssistantUserMessageContext, m as createSlackAssistantThreadContextStore, p as parseSlackMessageActivityFromMessageEvent, r as resolveAssistantSessionId } from '../options-DQacQDmD.js';
3
+ import '@slack/bolt';
4
+ import '@slack/web-api';
5
+ import '../turn-BGAXddH_.js';
6
+ import '../activity-ByrD9Ftr.js';
7
+ import '../interactive-CbKYkkc_.js';
8
+ import '../formatting-C-kwQseI.js';
9
+ import '../options-B0xQCaez.js';
10
+ import '../types-C8nkPuD4.js';
11
+ import '../types-Cywfj8Mj.js';
12
+ import '../feedback/index.js';
13
+ import '@slack/types';
14
+ import '../logging-Bl3HfcC8.js';
2
15
 
3
16
  /**
4
- * Per-thread Assistant context store.
5
- *
6
- * Bolt's default store persists context in message metadata, but also keeps a
7
- * single process-local cached context. That cache is not keyed by thread, so a
8
- * multi-user app can read the wrong channel-of-origin context after another
9
- * assistant thread changes it. This store keeps the same metadata persistence
10
- * model while caching by Slack channel/thread.
17
+ * `createSlackAssistantBridge` factory assembles the three lifecycle
18
+ * middlewares into a Bolt `Assistant` and wires the feedback action handler.
11
19
  */
12
- type ThreadStoreArgs = {
13
- context?: {
14
- botUserId?: string;
15
- };
16
- client?: {
17
- conversations?: {
18
- replies?: (args: Record<string, unknown>) => Promise<{
19
- messages?: unknown[];
20
- }>;
21
- };
22
- chat?: {
23
- update?: (args: Record<string, unknown>) => Promise<unknown>;
24
- };
25
- };
26
- logger?: {
27
- debug?: (...args: unknown[]) => void;
28
- };
29
- payload?: unknown;
30
- };
31
- interface SlackAssistantThreadContextStoreLike {
32
- get: (args: ThreadStoreArgs) => Promise<unknown>;
33
- save: (args: ThreadStoreArgs) => Promise<void>;
34
- }
35
- declare function createSlackAssistantThreadContextStore(): SlackAssistantThreadContextStoreLike;
36
20
 
37
- /**
38
- * Parse the `message` payload delivered to a Bolt assistant `userMessage`
39
- * handler into the same shape as `parseSlackMessageActivity`.
40
- *
41
- * Bolt routes a fairly wide message event to assistant handlers, so we keep
42
- * the input typed loosely and inspect only the fields we need.
43
- */
44
-
45
- interface ParsedAssistantUserMessage extends SlackActivityInfo {
46
- /** Slack `channel` identifier, always present after parsing. */
47
- channel: string;
48
- /** Slack `thread_ts` identifier — the assistant API requires a thread. */
49
- threadTs: string;
50
- }
51
- /**
52
- * Returns `undefined` when the event is not a parseable user message — bolt
53
- * delivers join/leave/edit/delete subtypes through the same handler, and the
54
- * caller should ignore them.
55
- */
56
- declare function parseSlackMessageActivityFromMessageEvent(message: unknown): ParsedAssistantUserMessage | undefined;
21
+ declare function createSlackAssistantBridge(options: CreateSlackAssistantBridgeOptions): SlackAssistantBridge;
57
22
 
58
- export { type ParsedAssistantUserMessage, type SlackAssistantThreadContextStoreLike, createSlackAssistantThreadContextStore, parseSlackMessageActivityFromMessageEvent };
23
+ export { CreateSlackAssistantBridgeOptions, SlackAssistantBridge, createSlackAssistantBridge };