@cuylabs/channel-slack-agent-core 0.6.0 → 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 (49) hide show
  1. package/README.md +7 -0
  2. package/dist/adapter/index.d.ts +6 -3
  3. package/dist/adapter/index.js +2 -2
  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 +4 -4
  7. package/dist/app.d.ts +7 -3
  8. package/dist/app.js +5 -5
  9. package/dist/artifacts/index.d.ts +57 -0
  10. package/dist/artifacts/index.js +6 -0
  11. package/dist/assistant/index.d.ts +5 -3
  12. package/dist/assistant/index.js +2 -2
  13. package/dist/{chunk-FNT4TXNQ.js → chunk-76SRS54H.js} +1 -1
  14. package/dist/{chunk-P7KK5GQG.js → chunk-7DUO5BMW.js} +11 -2
  15. package/dist/chunk-C7CHMYV6.js +226 -0
  16. package/dist/{chunk-5NQYLOAW.js → chunk-DJPKRKGP.js} +1 -1
  17. package/dist/{chunk-TIQGJ52F.js → chunk-FQWFB54C.js} +14 -2
  18. package/dist/{chunk-ZDVD46RT.js → chunk-MGBNGG4D.js} +23 -1
  19. package/dist/chunk-NNCVHQC4.js +94 -0
  20. package/dist/{chunk-VCXPNQRB.js → chunk-TCNJY7QA.js} +1 -1
  21. package/dist/{chunk-NOVWLAVP.js → chunk-TMADMHBN.js} +209 -20
  22. package/dist/{chunk-QEJ7TAZJ.js → chunk-VMVQIDNR.js} +2 -2
  23. package/dist/{chunk-J6CW2RGO.js → chunk-X7ILLZZP.js} +359 -2
  24. package/dist/express-assistant.d.ts +4 -2
  25. package/dist/express-assistant.js +3 -3
  26. package/dist/express.d.ts +5 -2
  27. package/dist/express.js +3 -3
  28. package/dist/history/index.d.ts +7 -3
  29. package/dist/index.d.ts +12 -6
  30. package/dist/index.js +28 -10
  31. package/dist/interactive/index.d.ts +43 -2
  32. package/dist/interactive/index.js +9 -3
  33. package/dist/{options-C7OYeNR-.d.ts → options-BcDReOJv.d.ts} +48 -0
  34. package/dist/{options-Uf-qmQKN.d.ts → options-CdqBABcM.d.ts} +26 -1
  35. package/dist/shared/index.d.ts +20 -6
  36. package/dist/shared/index.js +1 -1
  37. package/dist/socket.d.ts +7 -3
  38. package/dist/socket.js +5 -5
  39. package/dist/{types-BqRzb_Cd.d.ts → types-CRWzJB5G.d.ts} +35 -0
  40. package/dist/types-CiwGU6zC.d.ts +56 -0
  41. package/dist/views/index.d.ts +8 -0
  42. package/dist/views/index.js +10 -0
  43. package/docs/README.md +7 -0
  44. package/docs/concepts/final-response-artifacts.md +39 -0
  45. package/docs/concepts/interactive-requests.md +43 -0
  46. package/docs/concepts/tool-task-rendering.md +46 -0
  47. package/docs/concepts/view-workflows.md +52 -0
  48. package/docs/reference/exports.md +18 -16
  49. package/package.json +14 -4
@@ -1,5 +1,6 @@
1
1
  import { i as SlackInteractiveRequestRecord, k as SlackInteractiveRequestStore, b as SlackInteractiveApprovalRequest, S as SlackInteractiveActionIds, e as SlackInteractiveHumanInputRequest, m as SlackInteractiveResolution, d as SlackInteractiveControllerOptions, c as SlackInteractiveController } from '../types-Crpil4kb.js';
2
2
  export { a as SlackInteractiveActor, f as SlackInteractiveMessageTarget, g as SlackInteractivePendingWaiter, h as SlackInteractivePostedMessage, j as SlackInteractiveRequestStatus, l as SlackInteractiveRequestWaitOptions, n as SlackInteractiveStoredRequest } from '../types-Crpil4kb.js';
3
+ import { View } from '@slack/types';
3
4
  import '@cuylabs/agent-core';
4
5
  import '@slack/bolt';
5
6
  import '../interactive-o_NZb-Xg.js';
@@ -9,6 +10,46 @@ declare function createInMemorySlackInteractiveRequestStore(): SlackInteractiveR
9
10
  declare function nowIso(): string;
10
11
  declare function cloneRecord(record: SlackInteractiveRequestRecord): SlackInteractiveRequestRecord;
11
12
 
13
+ interface SlackInteractivePostgresClient {
14
+ end?: () => Promise<void>;
15
+ query<T = unknown>(sql: string, values?: readonly unknown[]): Promise<{
16
+ rows: T[];
17
+ rowCount?: number | null;
18
+ }>;
19
+ }
20
+ interface PostgresSlackInteractiveRequestStoreOptions {
21
+ client?: SlackInteractivePostgresClient;
22
+ connectionString?: string;
23
+ ensureSchema?: boolean;
24
+ onPruneError?: (error: unknown) => void;
25
+ pruneBatchSize?: number;
26
+ pruneIntervalMs?: number;
27
+ retentionMs?: number;
28
+ schema?: string;
29
+ tableName?: string;
30
+ }
31
+ interface PostgresSlackInteractiveRequestStore extends SlackInteractiveRequestStore {
32
+ close(): Promise<void>;
33
+ prune(): Promise<PostgresSlackInteractiveRequestPruneResult>;
34
+ }
35
+ interface PostgresSlackInteractiveRequestPruneResult {
36
+ deleted: number;
37
+ }
38
+ declare function createPostgresSlackInteractiveRequestStore({ client, connectionString, ensureSchema, onPruneError, pruneBatchSize, pruneIntervalMs, retentionMs, schema, tableName, }: PostgresSlackInteractiveRequestStoreOptions): PostgresSlackInteractiveRequestStore;
39
+ declare function initializePostgresSlackInteractiveRequestStore({ client, ensureSchema, schema, tableName, }: {
40
+ client: SlackInteractivePostgresClient;
41
+ ensureSchema?: boolean;
42
+ schema?: string;
43
+ tableName?: string;
44
+ }): Promise<void>;
45
+ declare function prunePostgresSlackInteractiveRequestStore({ client, pruneBatchSize, retentionMs, schema, tableName, }: {
46
+ client: SlackInteractivePostgresClient;
47
+ pruneBatchSize?: number;
48
+ retentionMs?: number;
49
+ schema?: string;
50
+ tableName?: string;
51
+ }): Promise<PostgresSlackInteractiveRequestPruneResult>;
52
+
12
53
  declare function buildApprovalRequestMessage(request: SlackInteractiveApprovalRequest, actionIds: SlackInteractiveActionIds): {
13
54
  text: string;
14
55
  blocks: unknown[];
@@ -21,10 +62,10 @@ declare function buildResolvedMessage(label: string, resolution: SlackInteractiv
21
62
  text: string;
22
63
  blocks: unknown[];
23
64
  };
24
- declare function buildHumanInputModal(request: SlackInteractiveHumanInputRequest, actionIds: SlackInteractiveActionIds): Record<string, unknown>;
65
+ declare function buildHumanInputModal(request: SlackInteractiveHumanInputRequest, actionIds: SlackInteractiveActionIds): View;
25
66
  declare function encodeActionValue(payload: Record<string, unknown>): string;
26
67
  declare function decodeActionValue(value: unknown): Record<string, unknown>;
27
68
 
28
69
  declare function createSlackInteractiveController(options?: SlackInteractiveControllerOptions): SlackInteractiveController;
29
70
 
30
- export { SlackInteractiveActionIds, SlackInteractiveApprovalRequest, SlackInteractiveController, SlackInteractiveControllerOptions, SlackInteractiveHumanInputRequest, SlackInteractiveRequestRecord, SlackInteractiveRequestStore, SlackInteractiveResolution, buildApprovalRequestMessage, buildHumanInputModal, buildHumanInputRequestMessage, buildResolvedMessage, cloneRecord, createInMemorySlackInteractiveRequestStore, createSlackInteractiveController, decodeActionValue, encodeActionValue, nowIso };
71
+ export { type PostgresSlackInteractiveRequestPruneResult, type PostgresSlackInteractiveRequestStore, type PostgresSlackInteractiveRequestStoreOptions, SlackInteractiveActionIds, SlackInteractiveApprovalRequest, SlackInteractiveController, SlackInteractiveControllerOptions, SlackInteractiveHumanInputRequest, type SlackInteractivePostgresClient, SlackInteractiveRequestRecord, SlackInteractiveRequestStore, SlackInteractiveResolution, buildApprovalRequestMessage, buildHumanInputModal, buildHumanInputRequestMessage, buildResolvedMessage, cloneRecord, createInMemorySlackInteractiveRequestStore, createPostgresSlackInteractiveRequestStore, createSlackInteractiveController, decodeActionValue, encodeActionValue, initializePostgresSlackInteractiveRequestStore, nowIso, prunePostgresSlackInteractiveRequestStore };
@@ -5,11 +5,14 @@ import {
5
5
  buildResolvedMessage,
6
6
  cloneRecord,
7
7
  createInMemorySlackInteractiveRequestStore,
8
+ createPostgresSlackInteractiveRequestStore,
8
9
  createSlackInteractiveController,
9
10
  decodeActionValue,
10
11
  encodeActionValue,
11
- nowIso
12
- } from "../chunk-J6CW2RGO.js";
12
+ initializePostgresSlackInteractiveRequestStore,
13
+ nowIso,
14
+ prunePostgresSlackInteractiveRequestStore
15
+ } from "../chunk-X7ILLZZP.js";
13
16
  export {
14
17
  buildApprovalRequestMessage,
15
18
  buildHumanInputModal,
@@ -17,8 +20,11 @@ export {
17
20
  buildResolvedMessage,
18
21
  cloneRecord,
19
22
  createInMemorySlackInteractiveRequestStore,
23
+ createPostgresSlackInteractiveRequestStore,
20
24
  createSlackInteractiveController,
21
25
  decodeActionValue,
22
26
  encodeActionValue,
23
- nowIso
27
+ initializePostgresSlackInteractiveRequestStore,
28
+ nowIso,
29
+ prunePostgresSlackInteractiveRequestStore
24
30
  };
@@ -1,4 +1,5 @@
1
1
  import { AgentEvent, ApprovalEvent } from '@cuylabs/agent-core';
2
+ import { SlackFinalResponseArtifactPublisher, SlackFinalResponseArtifactDeliveryMode, SlackFinalResponseArtifactContext, SlackFinalResponseArtifactResult } from './artifacts/index.js';
2
3
  import { a as SlackEventInteractiveRequestHandler } from './interactive-o_NZb-Xg.js';
3
4
 
4
5
  /**
@@ -13,6 +14,9 @@ type HumanInputEvent = Extract<AgentEvent, {
13
14
  type ToolStartEvent = Extract<AgentEvent, {
14
15
  type: "tool-start";
15
16
  }>;
17
+ type ToolResultEvent = Extract<AgentEvent, {
18
+ type: "tool-result";
19
+ }>;
16
20
  interface SlackEventBridgeOptions {
17
21
  showReasoning: boolean;
18
22
  /** Render root-agent tool rows/status updates. */
@@ -24,6 +28,13 @@ interface SlackEventBridgeOptions {
24
28
  formatToolTitle?: (toolName: string) => string;
25
29
  formatToolUpdate: (toolName: string) => string;
26
30
  formatToolDetails?: (event: ToolStartEvent) => string | undefined;
31
+ /**
32
+ * Format the completed tool output shown in Slack task rows.
33
+ *
34
+ * Return `undefined` to use the default generic formatter. Return `null` to
35
+ * intentionally omit task-row output for this tool result.
36
+ */
37
+ formatToolResultOutput?: (event: ToolResultEvent) => string | null | undefined;
27
38
  formatToolError: (toolName: string, error: string) => string;
28
39
  formatReasoningUpdate: () => string;
29
40
  formatMessageText: (text: string) => string;
@@ -65,6 +76,43 @@ interface SlackEventBridgeOptions {
65
76
  chatStreamFinalArgs?: {
66
77
  blocks?: unknown[];
67
78
  } & Record<string, unknown>;
79
+ /**
80
+ * Optional post-processing hook for publishing a rich artifact from the final
81
+ * accumulated response, such as a Slack Canvas for long answers.
82
+ */
83
+ publishFinalResponseArtifact?: SlackFinalResponseArtifactPublisher;
84
+ /**
85
+ * Controls whether artifact publication is additive or becomes the primary
86
+ * final-answer surface.
87
+ *
88
+ * - `supplemental`: finalize the Slack text normally, then publish artifact.
89
+ * - `replace`: publish artifact first and use a compact Slack final message.
90
+ *
91
+ * @default "supplemental"
92
+ */
93
+ finalResponseArtifactMode?: SlackFinalResponseArtifactDeliveryMode;
94
+ /**
95
+ * When replacement mode is active, continue streaming text up to this many
96
+ * raw characters, then suppress further text deltas and publish the full
97
+ * answer as an artifact at completion. This preserves normal short-answer
98
+ * streaming without flooding Slack for long answers.
99
+ *
100
+ * @default 4000
101
+ */
102
+ finalResponseArtifactStreamThreshold?: number;
103
+ /**
104
+ * Notice appended when replacement mode suppresses the remaining text stream.
105
+ */
106
+ formatFinalResponseArtifactContinuationNotice?: (context: Pick<SlackFinalResponseArtifactContext, "text" | "formattedText">) => string;
107
+ /**
108
+ * Final compact message used when an artifact replaces the full Slack text.
109
+ */
110
+ formatFinalResponseArtifactMessage?: (result: SlackFinalResponseArtifactResult, context: SlackFinalResponseArtifactContext) => string;
111
+ /**
112
+ * Called when `publishFinalResponseArtifact` throws. Errors from this hook
113
+ * are swallowed so artifact publication cannot break a completed turn.
114
+ */
115
+ onFinalResponseArtifactError?: (error: unknown, context: SlackFinalResponseArtifactContext) => void | Promise<void>;
68
116
  }
69
117
  declare function resolveSlackEventBridgeOptions(partial: Partial<SlackEventBridgeOptions>): SlackEventBridgeOptions;
70
118
 
@@ -3,7 +3,7 @@ import { AssistantUserMessageMiddleware, AssistantThreadStartedMiddleware, Assis
3
3
  import { WebClient } from '@slack/web-api';
4
4
  import { SlackAuthContext, SlackAssistantThreadContext, SlackAssistantUtilities, SlackTurnPreparation, SlackAssistantTaskDisplayMode, SlackAssistantStatusUpdate, SlackAssistantSuggestedPrompts, SlackChatStreamStartArgs, SlackMessageFormattingOptions } from '@cuylabs/channel-slack/core';
5
5
  import { h as SlackInteractiveRequestHandler } from './interactive-o_NZb-Xg.js';
6
- import { S as SlackEventBridgeOptions } from './options-C7OYeNR-.js';
6
+ import { S as SlackEventBridgeOptions } from './options-BcDReOJv.js';
7
7
  import { SlackFeedbackBlockOptions, SlackFeedbackHandler } from '@cuylabs/channel-slack/feedback';
8
8
  import { ParsedAssistantUserMessage } from '@cuylabs/channel-slack/assistant';
9
9
 
@@ -201,6 +201,7 @@ interface CreateSlackAssistantBridgeOptions {
201
201
  formatToolTitle?: (toolName: string) => string;
202
202
  formatToolUpdate?: (toolName: string) => string;
203
203
  formatToolDetails?: SlackEventBridgeOptions["formatToolDetails"];
204
+ formatToolResultOutput?: SlackEventBridgeOptions["formatToolResultOutput"];
204
205
  formatToolError?: (toolName: string, error: string) => string;
205
206
  formatReasoningUpdate?: () => string;
206
207
  chatStreamBufferSize?: number;
@@ -223,6 +224,30 @@ interface CreateSlackAssistantBridgeOptions {
223
224
  * blocks.
224
225
  */
225
226
  chatStreamFinalArgs?: SlackEventBridgeOptions["chatStreamFinalArgs"];
227
+ /**
228
+ * Optional publisher for rich artifacts derived from the final accumulated
229
+ * answer, such as creating a Slack Canvas for long responses.
230
+ */
231
+ publishFinalResponseArtifact?: SlackEventBridgeOptions["publishFinalResponseArtifact"];
232
+ /**
233
+ * Controls whether final-response artifacts are supplemental or replace long
234
+ * Slack text with a compact artifact pointer.
235
+ *
236
+ * @default "supplemental"
237
+ */
238
+ finalResponseArtifactMode?: SlackEventBridgeOptions["finalResponseArtifactMode"];
239
+ /**
240
+ * Raw-character threshold for replacement-mode streaming suppression.
241
+ *
242
+ * @default 4000
243
+ */
244
+ finalResponseArtifactStreamThreshold?: SlackEventBridgeOptions["finalResponseArtifactStreamThreshold"];
245
+ /** Notice emitted when replacement mode moves the remaining response to an artifact. */
246
+ formatFinalResponseArtifactContinuationNotice?: SlackEventBridgeOptions["formatFinalResponseArtifactContinuationNotice"];
247
+ /** Compact final Slack message emitted after artifact publication succeeds. */
248
+ formatFinalResponseArtifactMessage?: SlackEventBridgeOptions["formatFinalResponseArtifactMessage"];
249
+ /** Diagnostics hook for final-response artifact publishing failures. */
250
+ onFinalResponseArtifactError?: SlackEventBridgeOptions["onFinalResponseArtifactError"];
226
251
  formatChatMarkdown?: SlackMessageFormattingOptions;
227
252
  formatStreamError?: (error: Error) => string;
228
253
  /**
@@ -1,9 +1,11 @@
1
1
  export { D as DEFAULT_SLACK_CONTEXT_FRAGMENT_KEY, S as SlackContextFragmentMiddlewareOptions, a as SlackContextFragmentPayload, b as SlackContextFragmentResolver, c as SlackContextFragmentResolverContext, d as createSlackContextFragmentMiddleware } from '../context-fragments-CQEDcjYR.js';
2
2
  import { AgentEvent } from '@cuylabs/agent-core';
3
- import { S as SlackEventBridgeOptions } from '../options-C7OYeNR-.js';
4
- export { r as resolveSlackEventBridgeOptions } from '../options-C7OYeNR-.js';
3
+ import { S as SlackEventBridgeOptions } from '../options-BcDReOJv.js';
4
+ export { r as resolveSlackEventBridgeOptions } from '../options-BcDReOJv.js';
5
+ import { SlackArtifactClient } from '@cuylabs/channel-slack/artifacts';
5
6
  export { S as SlackApprovalRequest, a as SlackEventInteractiveRequestHandler, b as SlackHumanInputRequest, c as SlackInteractiveMessage, d as SlackInteractiveMessageRef, e as SlackInteractiveRequest, f as SlackInteractiveRequestBaseContext, g as SlackInteractiveRequestContext, h as SlackInteractiveRequestHandler, i as SlackInteractiveRequestKind, j as SlackInteractiveResponder } from '../interactive-o_NZb-Xg.js';
6
7
  import '@cuylabs/channel-slack/core';
8
+ import '../artifacts/index.js';
7
9
 
8
10
  /**
9
11
  * Slack response-sink contracts consumed by the event bridge.
@@ -13,6 +15,7 @@ import '@cuylabs/channel-slack/core';
13
15
  * interface separate makes the bridge testable without a live Slack
14
16
  * connection.
15
17
  */
18
+
16
19
  type SlackStreamTaskStatus = "pending" | "in_progress" | "complete" | "error";
17
20
  type SlackStreamChunk = {
18
21
  type: "markdown_text";
@@ -41,7 +44,19 @@ interface SlackChatStream {
41
44
  /**
42
45
  * Minimal Slack posting interface consumed by the event bridge.
43
46
  */
47
+ interface SlackArtifactPublicationTarget {
48
+ channelId: string;
49
+ threadTs?: string;
50
+ }
44
51
  interface SlackResponseSink {
52
+ /**
53
+ * Slack Web API surface used by optional artifact publishers.
54
+ */
55
+ artifactClient?: SlackArtifactClient;
56
+ /**
57
+ * Channel/thread target used by optional artifact publishers.
58
+ */
59
+ artifactTarget?: SlackArtifactPublicationTarget;
45
60
  /**
46
61
  * Post a new message to the channel / thread.
47
62
  * Returns the channel ID and message timestamp needed for updates.
@@ -90,9 +105,8 @@ declare function bridgeAgentEventsToSlack(events: AsyncGenerator<AgentEvent>, si
90
105
  * `human-input-request` event reaches the Slack transport in a mode that
91
106
  * does not support in-channel resolution.
92
107
  *
93
- * Hosts can catch this error to fall back to message-and-error mode or to
94
- * route the request through a custom block / view flow. Future work will
95
- * add a first-class Slack rendering path here.
108
+ * Hosts can catch this error to fall back to message-and-error mode, or install
109
+ * `createSlackInteractiveController` to render and resolve requests in Slack.
96
110
  */
97
111
  declare class UnsupportedSlackInteractiveRequestError extends Error {
98
112
  readonly kind: "approval" | "human-input";
@@ -100,4 +114,4 @@ declare class UnsupportedSlackInteractiveRequestError extends Error {
100
114
  constructor(kind: "approval" | "human-input", requestId: string, message: string);
101
115
  }
102
116
 
103
- export { type SlackChatStream, SlackEventBridgeOptions, type SlackResponseSink, type SlackStreamChunk, type SlackStreamTaskStatus, UnsupportedSlackInteractiveRequestError, bridgeAgentEventsToSlack };
117
+ export { type SlackArtifactPublicationTarget, type SlackChatStream, SlackEventBridgeOptions, type SlackResponseSink, type SlackStreamChunk, type SlackStreamTaskStatus, UnsupportedSlackInteractiveRequestError, bridgeAgentEventsToSlack };
@@ -6,7 +6,7 @@ import {
6
6
  UnsupportedSlackInteractiveRequestError,
7
7
  bridgeAgentEventsToSlack,
8
8
  resolveSlackEventBridgeOptions
9
- } from "../chunk-NOVWLAVP.js";
9
+ } from "../chunk-TMADMHBN.js";
10
10
  export {
11
11
  DEFAULT_SLACK_CONTEXT_FRAGMENT_KEY,
12
12
  UnsupportedSlackInteractiveRequestError,
package/dist/socket.d.ts CHANGED
@@ -1,17 +1,21 @@
1
1
  import { App } from '@slack/bolt';
2
2
  import { CreateSlackSocketBoltAppOptions } from '@cuylabs/channel-slack/transports/socket';
3
3
  import { SlackDirectAuthOptions, SlackDirectAuthMode } from '@cuylabs/channel-slack/auth';
4
- import { S as SlackAssistantBridge, C as CreateSlackAssistantBridgeOptions, b as SlackAssistantFeedbackConfig } from './options-Uf-qmQKN.js';
4
+ import { S as SlackAssistantBridge, C as CreateSlackAssistantBridgeOptions, b as SlackAssistantFeedbackConfig } from './options-CdqBABcM.js';
5
5
  import { SlackAgentAppSurfaceOptions } from './app-surface.js';
6
6
  import { SlackFeedbackHandler } from '@cuylabs/channel-slack/feedback';
7
7
  import '@cuylabs/agent-core';
8
8
  import '@slack/web-api';
9
9
  import '@cuylabs/channel-slack/core';
10
10
  import './interactive-o_NZb-Xg.js';
11
- import './options-C7OYeNR-.js';
11
+ import './options-BcDReOJv.js';
12
+ import './artifacts/index.js';
13
+ import '@cuylabs/channel-slack/artifacts';
12
14
  import '@cuylabs/channel-slack/assistant';
13
- import './types-BqRzb_Cd.js';
15
+ import './types-CRWzJB5G.js';
14
16
  import './types-Crpil4kb.js';
17
+ import './types-CiwGU6zC.js';
18
+ import '@cuylabs/channel-slack/views';
15
19
 
16
20
  /**
17
21
  * Socket Mode helpers for direct Slack.
package/dist/socket.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  mountSlackAgentAppSocket,
3
3
  mountSlackAssistantAgentSocket
4
- } from "./chunk-QEJ7TAZJ.js";
5
- import "./chunk-P7KK5GQG.js";
6
- import "./chunk-ZDVD46RT.js";
4
+ } from "./chunk-VMVQIDNR.js";
5
+ import "./chunk-7DUO5BMW.js";
6
+ import "./chunk-MGBNGG4D.js";
7
7
  import "./chunk-ELR6MQD7.js";
8
- import "./chunk-TIQGJ52F.js";
9
- import "./chunk-NOVWLAVP.js";
8
+ import "./chunk-FQWFB54C.js";
9
+ import "./chunk-TMADMHBN.js";
10
10
  export {
11
11
  mountSlackAgentAppSocket,
12
12
  mountSlackAssistantAgentSocket
@@ -1,5 +1,6 @@
1
1
  import { Agent, AgentTurnSource, AgentEvent, ApprovalEvent, Logger } from '@cuylabs/agent-core';
2
2
  import { SlackActivityInfo, SlackTurnRequestContext, SlackAssistantStatusUpdate, SlackChatStreamStartArgs, SlackUserIdentity, SlackTurnPreparation } from '@cuylabs/channel-slack/core';
3
+ import { S as SlackEventBridgeOptions } from './options-BcDReOJv.js';
3
4
  import { h as SlackInteractiveRequestHandler } from './interactive-o_NZb-Xg.js';
4
5
 
5
6
  /**
@@ -13,6 +14,9 @@ type HumanInputEvent = Extract<AgentEvent, {
13
14
  type SlackToolStartEvent = Extract<AgentEvent, {
14
15
  type: "tool-start";
15
16
  }>;
17
+ type SlackToolResultEvent = Extract<AgentEvent, {
18
+ type: "tool-result";
19
+ }>;
16
20
  type MaybePromise<T> = T | Promise<T>;
17
21
  /**
18
22
  * Session mapping strategy.
@@ -125,6 +129,13 @@ interface SlackChannelOptions {
125
129
  * @default details use the tool-start status text
126
130
  */
127
131
  formatToolDetails?: (event: SlackToolStartEvent) => string | undefined;
132
+ /**
133
+ * Format completed tool output shown in Slack task cards.
134
+ *
135
+ * Return `undefined` to use the default generic formatter. Return `null` to
136
+ * intentionally omit output for this result.
137
+ */
138
+ formatToolResultOutput?: (event: SlackToolResultEvent) => string | null | undefined;
128
139
  /**
129
140
  * Format the tool-error status text.
130
141
  * @default (toolName) => `⚠️ Tool ${toolName} encountered an error`
@@ -235,6 +246,30 @@ interface SlackChannelOptions {
235
246
  chatStreamFinalArgs?: {
236
247
  blocks?: unknown[];
237
248
  } & Record<string, unknown>;
249
+ /**
250
+ * Optional publisher for rich artifacts derived from the final accumulated
251
+ * answer, such as creating a Slack Canvas for long responses.
252
+ */
253
+ publishFinalResponseArtifact?: SlackEventBridgeOptions["publishFinalResponseArtifact"];
254
+ /**
255
+ * Controls whether final-response artifacts are supplemental or replace long
256
+ * Slack text with a compact artifact pointer.
257
+ *
258
+ * @default "supplemental"
259
+ */
260
+ finalResponseArtifactMode?: SlackEventBridgeOptions["finalResponseArtifactMode"];
261
+ /**
262
+ * Raw-character threshold for replacement-mode streaming suppression.
263
+ *
264
+ * @default 4000
265
+ */
266
+ finalResponseArtifactStreamThreshold?: SlackEventBridgeOptions["finalResponseArtifactStreamThreshold"];
267
+ /** Notice emitted when replacement mode moves the remaining response to an artifact. */
268
+ formatFinalResponseArtifactContinuationNotice?: SlackEventBridgeOptions["formatFinalResponseArtifactContinuationNotice"];
269
+ /** Compact final Slack message emitted after artifact publication succeeds. */
270
+ formatFinalResponseArtifactMessage?: SlackEventBridgeOptions["formatFinalResponseArtifactMessage"];
271
+ /** Diagnostics hook for final-response artifact publishing failures. */
272
+ onFinalResponseArtifactError?: SlackEventBridgeOptions["onFinalResponseArtifactError"];
238
273
  /**
239
274
  * Convert common markdown constructs emitted by models into Slack mrkdwn.
240
275
  *
@@ -0,0 +1,56 @@
1
+ import { App } from '@slack/bolt';
2
+ import { SlackViewPayload, RegisterSlackViewWorkflowOptions, SlackViewWorkflowContext, SlackViewSubmissionAckResponse } from '@cuylabs/channel-slack/views';
3
+
4
+ type SlackAgentViewStateValue = string | string[] | boolean | number | Record<string, unknown> | undefined;
5
+ type SlackAgentViewStateValues = Record<string, Record<string, SlackAgentViewStateValue>>;
6
+ declare function extractSlackAgentViewStateValues(viewOrState: SlackViewPayload | unknown): SlackAgentViewStateValues;
7
+ declare function readSlackAgentViewStateValue(valuesOrView: SlackAgentViewStateValues | SlackViewPayload | unknown, blockId: string, actionId: string): SlackAgentViewStateValue;
8
+
9
+ interface SlackAgentViewWorkflow {
10
+ id: string;
11
+ callbackId: string;
12
+ }
13
+ interface SlackAgentViewWorkflowContext<TMetadata = unknown> extends SlackViewWorkflowContext<TMetadata> {
14
+ workflow: SlackAgentViewWorkflow;
15
+ stateValues: SlackAgentViewStateValues;
16
+ getStateValue(blockId: string, actionId: string): SlackAgentViewStateValue;
17
+ }
18
+ interface SlackAgentViewWorkflowDefinition<TMetadata = unknown> {
19
+ /**
20
+ * Stable product/agent workflow id. Used to derive the default Slack
21
+ * callback id as `${namespace}_${id}`.
22
+ */
23
+ id: string;
24
+ /**
25
+ * Explicit Slack view callback id. Prefer this only when integrating with an
26
+ * existing Slack app surface.
27
+ */
28
+ callbackId?: string;
29
+ decodePrivateMetadata?: RegisterSlackViewWorkflowOptions<TMetadata>["decodePrivateMetadata"];
30
+ onSubmission?: (context: SlackAgentViewWorkflowContext<TMetadata>) => SlackViewSubmissionAckResponse | void | Promise<SlackViewSubmissionAckResponse | void>;
31
+ onClose?: (context: SlackAgentViewWorkflowContext<TMetadata>) => void | Promise<void>;
32
+ onError?: (error: unknown, context: Omit<SlackAgentViewWorkflowContext<TMetadata>, "metadata"> & {
33
+ metadata?: TMetadata | undefined;
34
+ }) => void | Promise<void>;
35
+ }
36
+ interface CreateSlackAgentViewWorkflowControllerOptions {
37
+ /**
38
+ * Namespace for derived Slack callback ids.
39
+ *
40
+ * @default "agent_slack_view"
41
+ */
42
+ namespace?: string;
43
+ workflows?: readonly SlackAgentViewWorkflowDefinition[];
44
+ onError?: (error: unknown, context: Omit<SlackAgentViewWorkflowContext, "metadata"> & {
45
+ metadata?: unknown;
46
+ }) => void | Promise<void>;
47
+ }
48
+ interface SlackAgentViewWorkflowController {
49
+ readonly namespace: string;
50
+ register<TMetadata = unknown>(workflow: SlackAgentViewWorkflowDefinition<TMetadata>): string;
51
+ callbackIdFor(workflowId: string): string;
52
+ list(): SlackAgentViewWorkflow[];
53
+ install(app: App): void;
54
+ }
55
+
56
+ export { type CreateSlackAgentViewWorkflowControllerOptions as C, type SlackAgentViewStateValue as S, type SlackAgentViewStateValues as a, type SlackAgentViewWorkflow as b, type SlackAgentViewWorkflowContext as c, type SlackAgentViewWorkflowController as d, type SlackAgentViewWorkflowDefinition as e, extractSlackAgentViewStateValues as f, readSlackAgentViewStateValue as r };
@@ -0,0 +1,8 @@
1
+ import { C as CreateSlackAgentViewWorkflowControllerOptions, d as SlackAgentViewWorkflowController } from '../types-CiwGU6zC.js';
2
+ export { S as SlackAgentViewStateValue, a as SlackAgentViewStateValues, b as SlackAgentViewWorkflow, c as SlackAgentViewWorkflowContext, e as SlackAgentViewWorkflowDefinition, f as extractSlackAgentViewStateValues, r as readSlackAgentViewStateValue } from '../types-CiwGU6zC.js';
3
+ import '@slack/bolt';
4
+ import '@cuylabs/channel-slack/views';
5
+
6
+ declare function createSlackAgentViewWorkflowController({ namespace, workflows, onError, }?: CreateSlackAgentViewWorkflowControllerOptions): SlackAgentViewWorkflowController;
7
+
8
+ export { CreateSlackAgentViewWorkflowControllerOptions, SlackAgentViewWorkflowController, createSlackAgentViewWorkflowController };
@@ -0,0 +1,10 @@
1
+ import {
2
+ createSlackAgentViewWorkflowController,
3
+ extractSlackAgentViewStateValues,
4
+ readSlackAgentViewStateValue
5
+ } from "../chunk-C7CHMYV6.js";
6
+ export {
7
+ createSlackAgentViewWorkflowController,
8
+ extractSlackAgentViewStateValues,
9
+ readSlackAgentViewStateValue
10
+ };
package/docs/README.md CHANGED
@@ -9,3 +9,10 @@ and human-input requests.
9
9
 
10
10
  - [Package boundary](reference/boundary.md)
11
11
  - [Exports and peer expectations](reference/exports.md)
12
+
13
+ ## Concepts
14
+
15
+ - [Final response artifacts](concepts/final-response-artifacts.md)
16
+ - [Interactive requests](concepts/interactive-requests.md)
17
+ - [Tool task rendering](concepts/tool-task-rendering.md)
18
+ - [View workflows](concepts/view-workflows.md)
@@ -0,0 +1,39 @@
1
+ # Final Response Artifacts
2
+
3
+ Final response artifacts let a Slack host publish a rich surface from the
4
+ completed Agent Core response. The first built-in publisher creates a Slack
5
+ Canvas for long answers and can fall back to a text file when Canvas
6
+ publication is unavailable.
7
+
8
+ ```typescript
9
+ import { createSlackFinalResponseArtifactPublisher } from "@cuylabs/channel-slack-agent-core/artifacts";
10
+
11
+ const publishFinalResponseArtifact = createSlackFinalResponseArtifactPublisher({
12
+ minCharacters: 4000,
13
+ title: "Agent response",
14
+ fallback: "file",
15
+ });
16
+
17
+ await mountSlackAgentApp({
18
+ source,
19
+ publishFinalResponseArtifact,
20
+ finalResponseArtifactMode: "replace",
21
+ finalResponseArtifactStreamThreshold: 4000,
22
+ });
23
+ ```
24
+
25
+ By default, `finalResponseArtifactMode` is `"supplemental"`: the Slack response
26
+ is finalized normally, then the artifact is published as an extra surface.
27
+
28
+ Use `"replace"` when long answers should move to the artifact instead of being
29
+ duplicated in chat. In chat-stream mode, the bridge streams text until
30
+ `finalResponseArtifactStreamThreshold`, appends a continuation notice, and then
31
+ publishes the full final text as a Canvas/file at completion. If publication
32
+ does not produce an artifact, the bridge falls back to the full Slack text.
33
+
34
+ The publisher receives the raw final text, formatted Slack text, the Slack Web
35
+ API client, and the target channel/thread. Short responses are skipped.
36
+
37
+ Canvas and file publication use `@cuylabs/channel-slack/artifacts`, so the
38
+ required Slack scopes are the same: `canvases:write` for Canvas and
39
+ `files:write` for file fallback.
@@ -0,0 +1,43 @@
1
+ # Interactive Requests
2
+
3
+ Slack interactive requests render Agent Core approval and human-input requests
4
+ as Slack buttons and modals.
5
+
6
+ ```typescript
7
+ import {
8
+ createPostgresSlackInteractiveRequestStore,
9
+ createSlackInteractiveController,
10
+ } from "@cuylabs/channel-slack-agent-core/interactive";
11
+
12
+ const interactiveStore = createPostgresSlackInteractiveRequestStore({
13
+ connectionString: process.env.DATABASE_URL,
14
+ schema: "agent",
15
+ });
16
+
17
+ const interactive = createSlackInteractiveController({
18
+ store: interactiveStore,
19
+ namespace: "my_agent_slack",
20
+ requestTimeoutMs: 5 * 60 * 1000,
21
+ });
22
+
23
+ // Wire these into the Agent Core runtime:
24
+ // approval: { onRequest: interactive.approval.onRequest }
25
+ // humanInput: { onRequest: interactive.humanInput.onRequest }
26
+
27
+ // Wire the controller into the Slack app surface:
28
+ // installSlackAgentAppSurface(boltApp, { source, interactive, ... })
29
+ ```
30
+
31
+ ## Store Choices
32
+
33
+ - `createInMemorySlackInteractiveRequestStore` is useful for tests and local
34
+ single-process apps.
35
+ - `createPostgresSlackInteractiveRequestStore` persists pending requests across
36
+ restarts and lets multiple Slack workers resolve the same request safely.
37
+
38
+ The Postgres store uses one table keyed by request ID. `resolve(...)` is
39
+ idempotent: the first resolution wins, and later duplicate button clicks return
40
+ the original resolution without overwriting it.
41
+
42
+ Call `close()` during shutdown when the store owns its `pg` pool. Call
43
+ `prune()` manually when you disable the background prune timer.
@@ -0,0 +1,46 @@
1
+ # Tool Task Rendering
2
+
3
+ `chat-stream` mode can render Agent Core tool activity as Slack task updates.
4
+ The bridge owns the generic event-to-Slack mapping, while applications can
5
+ format titles, in-progress details, and completed output.
6
+
7
+ Use these hooks when a tool result has structured metadata that should be shown
8
+ more cleanly than the generic stringified result:
9
+
10
+ - `formatToolTitle(toolName)` controls the Slack task title.
11
+ - `formatToolDetails(event)` controls the in-progress task details for a
12
+ `tool-start` event.
13
+ - `formatToolResultOutput(event)` controls the completed task output for a
14
+ `tool-result` event.
15
+
16
+ `formatToolResultOutput` receives the full `tool-result` event, including
17
+ `toolName`, `toolCallId`, `result`, and any tool metadata preserved by Agent
18
+ Core. Return `undefined` to use the default formatter. Return `null` to omit the
19
+ completed task output intentionally.
20
+
21
+ ```ts
22
+ createSlackChannelAdapter({
23
+ source,
24
+ streamingMode: "chat-stream",
25
+ formatToolTitle: (toolName) => (toolName === "plan" ? "Plan" : toolName),
26
+ formatToolResultOutput: (event) => {
27
+ if (event.toolName !== "plan") {
28
+ return undefined;
29
+ }
30
+
31
+ const entries = readPlanEntries(event.metadata);
32
+ if (!entries) {
33
+ return undefined;
34
+ }
35
+
36
+ return entries
37
+ .map(
38
+ (entry) => `${entry.status === "done" ? "[x]" : "[ ]"} ${entry.title}`,
39
+ )
40
+ .join("\n");
41
+ },
42
+ });
43
+ ```
44
+
45
+ Keep task rows compact. Slack task updates are a visible progress projection for
46
+ the current turn, not a durable audit log or replacement for the final answer.