@cuylabs/channel-slack-agent-core 0.11.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.
- package/README.md +7 -3
- package/dist/index.d.ts +1 -4
- package/dist/index.js +0 -4
- package/dist/shared/index.d.ts +28 -5
- package/docs/README.md +2 -3
- package/docs/concepts/interactive-requests.md +31 -26
- package/docs/reference/boundary.md +6 -4
- package/docs/reference/exports.md +12 -8
- package/package.json +4 -9
- package/dist/chunk-OP27SSZU.js +0 -409
- package/dist/interactive/index.d.ts +0 -90
- package/dist/interactive/index.js +0 -6
- package/dist/interactive-BigrPKnu.d.ts +0 -30
package/README.md
CHANGED
|
@@ -5,11 +5,15 @@ Slack adapter for `@cuylabs/agent-core`, built on
|
|
|
5
5
|
|
|
6
6
|
Use this package when an Agent Core application needs Agent Core-specific Slack
|
|
7
7
|
bindings: event mapping, source adaptation, context fragments, history helpers,
|
|
8
|
-
MCP token bridging
|
|
8
|
+
or MCP token bridging.
|
|
9
9
|
|
|
10
10
|
Generic Slack mechanics, mounts, Assistant rendering, classic message routing,
|
|
11
|
-
feedback, artifacts, interactive
|
|
12
|
-
transports live in `@cuylabs/channel-slack`.
|
|
11
|
+
feedback, artifacts, interactive request rendering/storage and controller
|
|
12
|
+
wiring, response sinks, and transports live in `@cuylabs/channel-slack`.
|
|
13
|
+
|
|
14
|
+
For Slack-native approvals and human input, import the controller from
|
|
15
|
+
`@cuylabs/channel-slack/interactive`; this package does not provide an
|
|
16
|
+
`interactive` subpath.
|
|
13
17
|
|
|
14
18
|
## Install
|
|
15
19
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
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
|
-
export { SlackEventBridgeOptions, UnsupportedSlackInteractiveRequestError, adaptAgentTurnSourceToSlackTurnSource, bridgeAgentEventsToSlack, mapAgentEventToSlackTurnEvent, mapAgentSlackEventBridgeOptionsToRuntimeOptions, resolveSlackEventBridgeOptions } from './shared/index.js';
|
|
3
|
-
export { S as SlackApprovalRequest, a as SlackEventInteractiveRequestHandler, b as SlackHumanInputRequest, c as SlackInteractiveRequest, d as SlackInteractiveRequestBaseContext, e as SlackInteractiveRequestContext, f as SlackInteractiveRequestHandler } from './interactive-BigrPKnu.js';
|
|
2
|
+
export { SlackApprovalRequest, SlackEventBridgeOptions, SlackEventInteractiveRequestHandler, SlackHumanInputRequest, SlackInteractiveRequest, SlackInteractiveRequestBaseContext, SlackInteractiveRequestContext, SlackInteractiveRequestHandler, UnsupportedSlackInteractiveRequestError, adaptAgentTurnSourceToSlackTurnSource, bridgeAgentEventsToSlack, mapAgentEventToSlackTurnEvent, mapAgentSlackEventBridgeOptionsToRuntimeOptions, resolveSlackEventBridgeOptions } from './shared/index.js';
|
|
4
3
|
export { LoadSlackAgentTurnHistoryContextOptions, SlackAgentTurnHistoryContextResult, SlackAgentTurnHistoryOptions, SlackAgentTurnHistoryProfileResolver, emptySlackAgentTurnHistoryContextResult, loadSlackAgentTurnHistoryContext } from './history/index.js';
|
|
5
|
-
export { SlackInteractiveApprovalRequest, SlackInteractiveController, SlackInteractiveControllerOptions, SlackInteractiveHumanInputRequest, SlackInteractivePendingWaiter, SlackInteractivePostedMessage, SlackInteractiveRequestWaitOptions, SlackInteractiveResolution, createSlackInteractiveController } from './interactive/index.js';
|
|
6
4
|
export { InspectSlackTurnStatusVisibilityOptions, ResolvedSlackTurnStatusVisibilityOptions, RouteSlackAgentEventOptions, SlackActiveToolCall, SlackAgentEventQueue, SlackAgentEventQueueState, SlackSubagentCompletionMessage, SlackSubagentCompletionMessageFormatterOptions, SlackSubagentCompletionNotifierOptions, SlackSubagentCompletionPoster, SlackSubagentCompletionRun, SlackSubagentCompletionSlackContext, SlackSubagentCompletionTurnContext, SlackTurnActivityState, SlackTurnPhase, SlackTurnStatusVisibilityOptions, SlackTurnStatusVisibilityState, SlackTurnStatusVisibilityWarning, SlackTypedApprovalAction, coalesceSlackAgentEvents, createSlackSubagentCompletionNotifier, formatDefaultSlackSubagentCompletionMessage, immediateSlackTextResponse, inspectSlackTurnStatusVisibility, isAbortLikeError, isRunningAgentTurnError, isSlackCancelMessage, isSlackSubagentTerminalEvent, isSlackTerminalTurnPhase, isSlackWaitingForHumanTurnPhase, recordSlackTurnActivity, resolveSlackTurnStatusVisibilityOptions, resolveSlackTypedApprovalAction, routeSlackAgentEvent, shouldInspectSlackTurnStatusVisibility, shouldQueueSlackAgentEvent } from './source/index.js';
|
|
7
5
|
export { CreateSlackMcpServerConfigOptions, SLACK_MCP_URL, createSlackMcpServerConfig } from './mcp.js';
|
|
8
6
|
import '@cuylabs/agent-core';
|
|
@@ -12,6 +10,5 @@ import '@cuylabs/channel-slack/runtime';
|
|
|
12
10
|
import '@cuylabs/channel-slack/interactive';
|
|
13
11
|
import '@cuylabs/channel-slack/history';
|
|
14
12
|
import '@slack/web-api';
|
|
15
|
-
import '@slack/bolt';
|
|
16
13
|
import '@cuylabs/agent-core/dispatch';
|
|
17
14
|
import '@cuylabs/agent-core/mcp';
|
package/dist/index.js
CHANGED
|
@@ -6,9 +6,6 @@ import {
|
|
|
6
6
|
emptySlackAgentTurnHistoryContextResult,
|
|
7
7
|
loadSlackAgentTurnHistoryContext
|
|
8
8
|
} from "./chunk-P7PFQ3SQ.js";
|
|
9
|
-
import {
|
|
10
|
-
createSlackInteractiveController
|
|
11
|
-
} from "./chunk-OP27SSZU.js";
|
|
12
9
|
import {
|
|
13
10
|
DEFAULT_SLACK_CONTEXT_FRAGMENT_KEY,
|
|
14
11
|
UnsupportedSlackInteractiveRequestError,
|
|
@@ -46,7 +43,6 @@ export {
|
|
|
46
43
|
bridgeAgentEventsToSlack,
|
|
47
44
|
coalesceSlackAgentEvents,
|
|
48
45
|
createSlackContextFragmentMiddleware,
|
|
49
|
-
createSlackInteractiveController,
|
|
50
46
|
createSlackMcpServerConfig,
|
|
51
47
|
createSlackSubagentCompletionNotifier,
|
|
52
48
|
emptySlackAgentTurnHistoryContextResult,
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -2,10 +2,33 @@ export { D as DEFAULT_SLACK_CONTEXT_FRAGMENT_KEY, S as SlackContextFragmentMiddl
|
|
|
2
2
|
import { AgentEvent, ApprovalEvent, AgentTurnSource } from '@cuylabs/agent-core';
|
|
3
3
|
import { SlackResponseSink } from '@cuylabs/channel-slack/responses';
|
|
4
4
|
import { SlackFinalResponseArtifactPublisher, SlackFinalResponseArtifactDeliveryMode, SlackFinalResponseArtifactContext, SlackFinalResponseArtifactResult, SlackTurnEvent, SlackEventBridgeOptions as SlackEventBridgeOptions$1, SlackTurnSource } from '@cuylabs/channel-slack/runtime';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import { SlackInteractiveRequestBaseContext as SlackInteractiveRequestBaseContext$1, SlackInteractiveRequestContext as SlackInteractiveRequestContext$1 } from '@cuylabs/channel-slack/interactive';
|
|
6
|
+
import { SlackActivityInfo, SlackUserIdentity } from '@cuylabs/channel-slack/core';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Agent Core interactive request contracts for the Slack event bridge.
|
|
10
|
+
*
|
|
11
|
+
* Generic Slack message/responder primitives live in `@cuylabs/channel-slack`.
|
|
12
|
+
* This module narrows the request payloads to Agent Core events.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
type SlackApprovalRequest = Extract<AgentEvent, {
|
|
16
|
+
type: "approval-request";
|
|
17
|
+
}>["request"];
|
|
18
|
+
type SlackHumanInputRequest = Extract<AgentEvent, {
|
|
19
|
+
type: "human-input-request";
|
|
20
|
+
}>["request"];
|
|
21
|
+
type SlackInteractiveRequest = SlackApprovalRequest | SlackHumanInputRequest;
|
|
22
|
+
interface SlackInteractiveRequestBaseContext extends Omit<SlackInteractiveRequestBaseContext$1, "request"> {
|
|
23
|
+
request: SlackInteractiveRequest;
|
|
24
|
+
}
|
|
25
|
+
interface SlackInteractiveRequestContext extends Omit<SlackInteractiveRequestContext$1, "request"> {
|
|
26
|
+
slackActivity: SlackActivityInfo;
|
|
27
|
+
user: SlackUserIdentity;
|
|
28
|
+
request: SlackInteractiveRequest;
|
|
29
|
+
}
|
|
30
|
+
type SlackInteractiveRequestHandler = (context: SlackInteractiveRequestContext) => boolean | void | Promise<boolean | void>;
|
|
31
|
+
type SlackEventInteractiveRequestHandler = (context: SlackInteractiveRequestBaseContext) => boolean | void | Promise<boolean | void>;
|
|
9
32
|
|
|
10
33
|
/**
|
|
11
34
|
* Event-bridge configuration. The bridge is mode-aware (progressive,
|
|
@@ -170,4 +193,4 @@ declare class UnsupportedSlackInteractiveRequestError extends Error {
|
|
|
170
193
|
|
|
171
194
|
declare function adaptAgentTurnSourceToSlackTurnSource(source: AgentTurnSource): SlackTurnSource;
|
|
172
195
|
|
|
173
|
-
export { type SlackEventBridgeOptions, SlackEventInteractiveRequestHandler, UnsupportedSlackInteractiveRequestError, adaptAgentTurnSourceToSlackTurnSource, bridgeAgentEventsToSlack, mapAgentEventToSlackTurnEvent, mapAgentSlackEventBridgeOptionsToRuntimeOptions, resolveSlackEventBridgeOptions };
|
|
196
|
+
export { type SlackApprovalRequest, type SlackEventBridgeOptions, type SlackEventInteractiveRequestHandler, type SlackHumanInputRequest, type SlackInteractiveRequest, type SlackInteractiveRequestBaseContext, type SlackInteractiveRequestContext, type SlackInteractiveRequestHandler, UnsupportedSlackInteractiveRequestError, adaptAgentTurnSourceToSlackTurnSource, bridgeAgentEventsToSlack, mapAgentEventToSlackTurnEvent, mapAgentSlackEventBridgeOptionsToRuntimeOptions, resolveSlackEventBridgeOptions };
|
package/docs/README.md
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`@cuylabs/channel-slack-agent-core` is the `@cuylabs/agent-core` runtime binding
|
|
4
4
|
for direct Slack traffic. It composes `@cuylabs/channel-slack` primitives with
|
|
5
|
-
Agent Core turn sources, event streams, scopes, context fragments
|
|
6
|
-
and human-input requests.
|
|
5
|
+
Agent Core turn sources, event streams, scopes, and context fragments.
|
|
7
6
|
|
|
8
7
|
## Reference
|
|
9
8
|
|
|
@@ -12,6 +11,6 @@ and human-input requests.
|
|
|
12
11
|
|
|
13
12
|
## Concepts
|
|
14
13
|
|
|
15
|
-
- [Final response artifacts](concepts/final-response-artifacts.md)
|
|
16
14
|
- [Interactive requests](concepts/interactive-requests.md)
|
|
15
|
+
- [Final response artifacts](concepts/final-response-artifacts.md)
|
|
17
16
|
- [Tool task rendering](concepts/tool-task-rendering.md)
|
|
@@ -1,43 +1,48 @@
|
|
|
1
1
|
# Interactive Requests
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Agent Core approval and human-input events are mapped into the runtime-neutral
|
|
4
|
+
Slack event stream by `adaptAgentTurnSourceToSlackTurnSource`. The Slack-native
|
|
5
|
+
controller lives in `@cuylabs/channel-slack/interactive`; do not import it from
|
|
6
|
+
`@cuylabs/channel-slack-agent-core/interactive`.
|
|
5
7
|
|
|
6
8
|
```typescript
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
});
|
|
9
|
+
import {
|
|
10
|
+
createPostgresSlackInteractiveRequestStore,
|
|
11
|
+
createSlackInteractiveController,
|
|
12
|
+
} from "@cuylabs/channel-slack/interactive";
|
|
13
|
+
import { mountSlackAppSocket } from "@cuylabs/channel-slack/socket";
|
|
14
|
+
import { adaptAgentTurnSourceToSlackTurnSource } from "@cuylabs/channel-slack-agent-core";
|
|
14
15
|
|
|
15
16
|
const interactive = createSlackInteractiveController({
|
|
16
|
-
store:
|
|
17
|
+
store: createPostgresSlackInteractiveRequestStore({
|
|
18
|
+
connectionString: process.env.DATABASE_URL,
|
|
19
|
+
schema: "agent",
|
|
20
|
+
}),
|
|
17
21
|
namespace: "my_agent_slack",
|
|
18
22
|
requestTimeoutMs: 5 * 60 * 1000,
|
|
19
23
|
});
|
|
20
24
|
|
|
21
|
-
// Wire these into the Agent Core runtime:
|
|
25
|
+
// Wire these into the Agent Core runtime that owns the pause/resume decision:
|
|
22
26
|
// approval: { onRequest: interactive.approval.onRequest }
|
|
23
27
|
// humanInput: { onRequest: interactive.humanInput.onRequest }
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
await mountSlackAppSocket({
|
|
30
|
+
source: adaptAgentTurnSourceToSlackTurnSource(agent),
|
|
31
|
+
interactive,
|
|
32
|
+
appToken: process.env.SLACK_APP_TOKEN,
|
|
33
|
+
botToken: process.env.SLACK_BOT_TOKEN,
|
|
34
|
+
});
|
|
27
35
|
```
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
`@cuylabs/channel-slack/interactive` is useful for tests and local
|
|
33
|
-
single-process apps.
|
|
34
|
-
- `createPostgresSlackInteractiveRequestStore` from
|
|
35
|
-
`@cuylabs/channel-slack/interactive` persists pending requests across restarts
|
|
36
|
-
and lets multiple Slack workers resolve the same request safely.
|
|
37
|
+
`mountSlackApp` and `mountSlackAppSocket` install the controller on the Bolt app
|
|
38
|
+
and route interactive request events from the Slack renderer to
|
|
39
|
+
`interactive.handleInteractiveRequest`.
|
|
37
40
|
|
|
38
|
-
The
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
The controller persists pending requests before rendering Slack buttons. It uses
|
|
42
|
+
first-wins resolution semantics, so duplicate Slack clicks return the stored
|
|
43
|
+
resolution instead of overwriting it. Request IDs must be unique across pending
|
|
44
|
+
approval and human-input requests.
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
`
|
|
46
|
+
By default, only the Slack user who triggered the original turn can resolve the
|
|
47
|
+
request. Pass `authorize(record, actor)` to the controller to allow delegated
|
|
48
|
+
approvers or workspace policy.
|
|
@@ -7,17 +7,19 @@ This package owns only the `@cuylabs/agent-core` Slack binding.
|
|
|
7
7
|
- Mapping Slack turns to `AgentTurnSource.chat(...)`.
|
|
8
8
|
- Creating Agent Core scopes and context fragments.
|
|
9
9
|
- Converting `AgentEvent` streams through Slack response sink contracts.
|
|
10
|
-
-
|
|
10
|
+
- Adapting Agent Core sources for the runtime-neutral Express Events API and
|
|
11
|
+
Socket Mode mounts in `@cuylabs/channel-slack`.
|
|
11
12
|
- Binding Slack Assistant lifecycle handlers to Agent Core turns.
|
|
12
|
-
-
|
|
13
|
-
|
|
13
|
+
- Mapping Agent Core approval and human-input events into the runtime-neutral
|
|
14
|
+
Slack event stream.
|
|
14
15
|
- Agent Core helpers for Slack history context fragments and source events.
|
|
15
16
|
|
|
16
17
|
## Outside This Package
|
|
17
18
|
|
|
18
19
|
- Generic Slack activity parsing, formatting, setup, auth, policy, history,
|
|
19
20
|
targets, users, entrypoints, artifacts, response sink contracts, interactive
|
|
20
|
-
request builders/stores, and transport factories.
|
|
21
|
+
request builders/stores/controllers, and transport factories.
|
|
22
|
+
- Slack-native rendering and resolution of approvals or human input.
|
|
21
23
|
- Product prompts, tools, audit policy, privacy rules, and deployment policy.
|
|
22
24
|
- Slack app configuration outside the reusable setup helpers.
|
|
23
25
|
|
|
@@ -3,14 +3,18 @@
|
|
|
3
3
|
Use feature subpaths when you only need one Agent Core binding. Generic Slack
|
|
4
4
|
mounts and primitives must be imported from `@cuylabs/channel-slack` directly.
|
|
5
5
|
|
|
6
|
-
| Export | Depends on
|
|
7
|
-
| ------------------------------------------- |
|
|
8
|
-
| `@cuylabs/channel-slack-agent-core` | `@cuylabs/agent-core`
|
|
9
|
-
| `@cuylabs/channel-slack-agent-core/history` | `@slack/web-api`, `@cuylabs/agent-core` types
|
|
10
|
-
| `@cuylabs/channel-slack-agent-core/
|
|
11
|
-
| `@cuylabs/channel-slack-agent-core/
|
|
12
|
-
| `@cuylabs/channel-slack-agent-core/
|
|
13
|
-
|
|
6
|
+
| Export | Depends on | Notes |
|
|
7
|
+
| ------------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------- |
|
|
8
|
+
| `@cuylabs/channel-slack-agent-core` | `@cuylabs/agent-core` | Agent Core event bridge, context fragments, history, source, and MCP |
|
|
9
|
+
| `@cuylabs/channel-slack-agent-core/history` | `@slack/web-api`, `@cuylabs/agent-core` types | Agent Core turn history context fragment assembly |
|
|
10
|
+
| `@cuylabs/channel-slack-agent-core/mcp` | `@cuylabs/agent-core/mcp` types | Slack OAuth token bridge for Agent Core MCP setup |
|
|
11
|
+
| `@cuylabs/channel-slack-agent-core/shared` | `@cuylabs/agent-core` types | Context fragments, Agent Core event mapping, and source adaptation |
|
|
12
|
+
| `@cuylabs/channel-slack-agent-core/source` | `@cuylabs/agent-core` types | Agent Core event queue, response helpers, and status visibility helpers |
|
|
13
|
+
|
|
14
|
+
There is intentionally no
|
|
15
|
+
`@cuylabs/channel-slack-agent-core/interactive` export. Use
|
|
16
|
+
`@cuylabs/channel-slack/interactive` for Slack-native approval and human-input
|
|
17
|
+
controllers.
|
|
14
18
|
|
|
15
19
|
For generic Slack package exports, see
|
|
16
20
|
`@cuylabs/channel-slack/docs/reference/exports.md`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cuylabs/channel-slack-agent-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Slack adapter for @cuylabs/agent-core built on @cuylabs/channel-slack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,11 +16,6 @@
|
|
|
16
16
|
"import": "./dist/history/index.js",
|
|
17
17
|
"default": "./dist/history/index.js"
|
|
18
18
|
},
|
|
19
|
-
"./interactive": {
|
|
20
|
-
"types": "./dist/interactive/index.d.ts",
|
|
21
|
-
"import": "./dist/interactive/index.js",
|
|
22
|
-
"default": "./dist/interactive/index.js"
|
|
23
|
-
},
|
|
24
19
|
"./mcp": {
|
|
25
20
|
"types": "./dist/mcp.d.ts",
|
|
26
21
|
"import": "./dist/mcp.js",
|
|
@@ -44,7 +39,7 @@
|
|
|
44
39
|
],
|
|
45
40
|
"dependencies": {
|
|
46
41
|
"@cuylabs/agent-core": "^7.2.0",
|
|
47
|
-
"@cuylabs/channel-slack": "^0.
|
|
42
|
+
"@cuylabs/channel-slack": "^0.12.0"
|
|
48
43
|
},
|
|
49
44
|
"peerDependencies": {
|
|
50
45
|
"@slack/bolt": ">=4.7.3",
|
|
@@ -94,9 +89,9 @@
|
|
|
94
89
|
"node": ">=20"
|
|
95
90
|
},
|
|
96
91
|
"scripts": {
|
|
97
|
-
"build": "tsup src/index.ts src/shared/index.ts src/history/index.ts src/
|
|
92
|
+
"build": "tsup src/index.ts src/shared/index.ts src/history/index.ts src/mcp.ts src/source/index.ts --format esm --dts --clean",
|
|
98
93
|
"clean": "rm -rf dist",
|
|
99
|
-
"dev": "tsup src/index.ts src/shared/index.ts src/history/index.ts src/
|
|
94
|
+
"dev": "tsup src/index.ts src/shared/index.ts src/history/index.ts src/mcp.ts src/source/index.ts --format esm --dts --watch",
|
|
100
95
|
"lint": "eslint \"src/**/*.{ts,tsx}\" \"tests/**/*.{ts,tsx}\" --max-warnings=0",
|
|
101
96
|
"test": "vitest run",
|
|
102
97
|
"test:watch": "vitest",
|
package/dist/chunk-OP27SSZU.js
DELETED
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
// src/interactive/controller.ts
|
|
2
|
-
import {
|
|
3
|
-
buildApprovalRequestMessage,
|
|
4
|
-
buildHumanInputModal,
|
|
5
|
-
buildHumanInputRequestMessage,
|
|
6
|
-
buildResolvedMessage,
|
|
7
|
-
createInMemorySlackInteractiveRequestStore,
|
|
8
|
-
decodeActionValue,
|
|
9
|
-
nowIso
|
|
10
|
-
} from "@cuylabs/channel-slack/interactive";
|
|
11
|
-
import { openSlackModal } from "@cuylabs/channel-slack/views";
|
|
12
|
-
var DEFAULT_NAMESPACE = "agent_slack";
|
|
13
|
-
var DEFAULT_REQUEST_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
14
|
-
var installedActionIds = /* @__PURE__ */ new WeakMap();
|
|
15
|
-
function createSlackInteractiveController(options = {}) {
|
|
16
|
-
const store = options.store ?? createInMemorySlackInteractiveRequestStore();
|
|
17
|
-
const actionIds = resolveActionIds(
|
|
18
|
-
options.namespace ?? DEFAULT_NAMESPACE,
|
|
19
|
-
options.actionIds
|
|
20
|
-
);
|
|
21
|
-
const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
22
|
-
const waiters = /* @__PURE__ */ new Map();
|
|
23
|
-
const pendingIds = /* @__PURE__ */ new Set();
|
|
24
|
-
async function ensurePending(kind, request) {
|
|
25
|
-
const existing = await store.get(request.id);
|
|
26
|
-
if (existing) {
|
|
27
|
-
pendingIds.add(request.id);
|
|
28
|
-
return existing;
|
|
29
|
-
}
|
|
30
|
-
const createdAt = nowIso();
|
|
31
|
-
const record = await store.upsert({
|
|
32
|
-
id: request.id,
|
|
33
|
-
kind,
|
|
34
|
-
request,
|
|
35
|
-
status: "pending",
|
|
36
|
-
createdAt,
|
|
37
|
-
updatedAt: createdAt
|
|
38
|
-
});
|
|
39
|
-
pendingIds.add(request.id);
|
|
40
|
-
return record;
|
|
41
|
-
}
|
|
42
|
-
async function waitForResolution(kind, request, waitOptions = {}) {
|
|
43
|
-
const existing = await ensurePending(kind, request);
|
|
44
|
-
if (existing.status === "resolved" && existing.resolution) {
|
|
45
|
-
return toAgentCoreResolution(existing.resolution);
|
|
46
|
-
}
|
|
47
|
-
if (waiters.has(request.id)) {
|
|
48
|
-
throw new Error(
|
|
49
|
-
`Slack interactive request is already waiting: ${request.id}. Resolve or cancel the in-flight request before requesting again.`
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
return await new Promise((resolve, reject) => {
|
|
53
|
-
const cleanupCallbacks = [];
|
|
54
|
-
const timeoutMs = waitOptions.timeoutMs ?? requestTimeoutMs;
|
|
55
|
-
if (timeoutMs > 0) {
|
|
56
|
-
const timeoutId = setTimeout(() => {
|
|
57
|
-
void cancel(request.id, "Slack interactive request timed out.");
|
|
58
|
-
}, timeoutMs);
|
|
59
|
-
cleanupCallbacks.push(() => clearTimeout(timeoutId));
|
|
60
|
-
}
|
|
61
|
-
let abortImmediately = false;
|
|
62
|
-
if (waitOptions.signal) {
|
|
63
|
-
const onAbort = () => {
|
|
64
|
-
void cancel(request.id, "Slack interactive request aborted.");
|
|
65
|
-
};
|
|
66
|
-
if (waitOptions.signal.aborted) {
|
|
67
|
-
abortImmediately = true;
|
|
68
|
-
} else {
|
|
69
|
-
waitOptions.signal.addEventListener("abort", onAbort, {
|
|
70
|
-
once: true
|
|
71
|
-
});
|
|
72
|
-
cleanupCallbacks.push(
|
|
73
|
-
() => waitOptions.signal?.removeEventListener("abort", onAbort)
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
waiters.set(request.id, {
|
|
78
|
-
resolve,
|
|
79
|
-
reject,
|
|
80
|
-
cleanup: () => {
|
|
81
|
-
for (const cleanup of cleanupCallbacks.splice(0)) {
|
|
82
|
-
cleanup();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
if (abortImmediately) {
|
|
87
|
-
void cancel(request.id, "Slack interactive request aborted.");
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
async function resolveRequest(requestId, resolution) {
|
|
92
|
-
const record = await store.resolve(requestId, resolution);
|
|
93
|
-
const waiter = waiters.get(requestId);
|
|
94
|
-
if (waiter) {
|
|
95
|
-
waiters.delete(requestId);
|
|
96
|
-
waiter.cleanup();
|
|
97
|
-
waiter.resolve(resolution);
|
|
98
|
-
}
|
|
99
|
-
if (record) {
|
|
100
|
-
pendingIds.delete(requestId);
|
|
101
|
-
await options.onResolve?.(requestId, resolution);
|
|
102
|
-
}
|
|
103
|
-
return record;
|
|
104
|
-
}
|
|
105
|
-
async function cancel(requestId, reason = "Cancelled") {
|
|
106
|
-
const waiter = waiters.get(requestId);
|
|
107
|
-
if (waiter) {
|
|
108
|
-
waiters.delete(requestId);
|
|
109
|
-
waiter.cleanup();
|
|
110
|
-
waiter.reject(new Error(reason));
|
|
111
|
-
}
|
|
112
|
-
const existing = await store.get(requestId);
|
|
113
|
-
if (existing?.status === "pending") {
|
|
114
|
-
await store.delete(requestId);
|
|
115
|
-
pendingIds.delete(requestId);
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
pendingIds.delete(requestId);
|
|
119
|
-
return Boolean(waiter);
|
|
120
|
-
}
|
|
121
|
-
async function cancelAll(reason = "Cancelled") {
|
|
122
|
-
await Promise.all(
|
|
123
|
-
[...pendingIds].map((requestId) => cancel(requestId, reason))
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
async function handleInteractiveRequest(context) {
|
|
127
|
-
const request = context.request;
|
|
128
|
-
const record = await ensurePending(context.kind, request);
|
|
129
|
-
if (record.target) {
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
const message = context.kind === "approval" ? buildApprovalRequestMessage(
|
|
133
|
-
request,
|
|
134
|
-
actionIds
|
|
135
|
-
) : buildHumanInputRequestMessage(
|
|
136
|
-
request,
|
|
137
|
-
actionIds
|
|
138
|
-
);
|
|
139
|
-
const ref = await context.responder.postMessage(message);
|
|
140
|
-
await store.attachTarget(request.id, {
|
|
141
|
-
channel: ref.channel,
|
|
142
|
-
ts: ref.ts,
|
|
143
|
-
userId: context.user.userId,
|
|
144
|
-
teamId: context.user.teamId,
|
|
145
|
-
...context.slackActivity.threadTs ? { threadTs: context.slackActivity.threadTs } : {}
|
|
146
|
-
});
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
149
|
-
function install(app) {
|
|
150
|
-
assertActionIdsCanInstall(app, actionIds);
|
|
151
|
-
app.action(actionIds.approvalAllow, async (args) => {
|
|
152
|
-
await handleAction(args, {
|
|
153
|
-
kind: "approval",
|
|
154
|
-
action: "allow"
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
app.action(actionIds.approvalDeny, async (args) => {
|
|
158
|
-
await handleAction(args, {
|
|
159
|
-
kind: "approval",
|
|
160
|
-
action: "deny"
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
app.action(actionIds.approvalRemember, async (args) => {
|
|
164
|
-
const value = firstActionValue(args);
|
|
165
|
-
const rememberScope = typeof value.rememberScope === "string" ? value.rememberScope : void 0;
|
|
166
|
-
await handleAction(args, {
|
|
167
|
-
kind: "approval",
|
|
168
|
-
action: "remember",
|
|
169
|
-
...rememberScope ? { rememberScope } : {}
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
app.action(actionIds.humanConfirm, async (args) => {
|
|
173
|
-
await handleAction(args, {
|
|
174
|
-
kind: "human-input",
|
|
175
|
-
response: { kind: "confirm", confirmed: true, text: "Confirmed" }
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
app.action(actionIds.humanDeny, async (args) => {
|
|
179
|
-
await handleAction(args, {
|
|
180
|
-
kind: "human-input",
|
|
181
|
-
response: { kind: "confirm", confirmed: false, text: "Cancelled" }
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
app.action(actionIds.humanOpen, async (args) => {
|
|
185
|
-
await openHumanInputModal(args);
|
|
186
|
-
});
|
|
187
|
-
app.view(actionIds.humanSubmit, async (args) => {
|
|
188
|
-
await submitHumanInputModal(args);
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
async function handleAction(args, resolutionInput) {
|
|
192
|
-
const actionArgs = args;
|
|
193
|
-
await actionArgs.ack();
|
|
194
|
-
const requestId = extractRequestId(firstActionValue(args));
|
|
195
|
-
if (!requestId) return;
|
|
196
|
-
const record = await store.get(requestId);
|
|
197
|
-
if (!record || record.status === "resolved") {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
const actor = extractActor(actionArgs.body);
|
|
201
|
-
if (!await isAuthorized(record, actor)) {
|
|
202
|
-
await postEphemeral(
|
|
203
|
-
actionArgs,
|
|
204
|
-
"Only the original requester can resolve this request."
|
|
205
|
-
);
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
const resolution = resolutionInput;
|
|
209
|
-
const resolved = await resolveRequest(requestId, resolution);
|
|
210
|
-
if (resolved?.target) {
|
|
211
|
-
await updateOriginalMessage(actionArgs, resolved, resolution);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
async function openHumanInputModal(args) {
|
|
215
|
-
const actionArgs = args;
|
|
216
|
-
await actionArgs.ack();
|
|
217
|
-
const requestId = extractRequestId(firstActionValue(args));
|
|
218
|
-
if (!requestId || !actionArgs.body.trigger_id) return;
|
|
219
|
-
const record = await store.get(requestId);
|
|
220
|
-
if (!record || record.kind !== "human-input") return;
|
|
221
|
-
const actor = extractActor(actionArgs.body);
|
|
222
|
-
if (!await isAuthorized(record, actor)) {
|
|
223
|
-
await postEphemeral(
|
|
224
|
-
actionArgs,
|
|
225
|
-
"Only the original requester can answer this request."
|
|
226
|
-
);
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
await openSlackModal({
|
|
230
|
-
client: actionArgs.client,
|
|
231
|
-
triggerId: actionArgs.body.trigger_id,
|
|
232
|
-
view: buildHumanInputModal(
|
|
233
|
-
record.request,
|
|
234
|
-
actionIds
|
|
235
|
-
)
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
async function submitHumanInputModal(args) {
|
|
239
|
-
const viewArgs = args;
|
|
240
|
-
await viewArgs.ack();
|
|
241
|
-
const requestId = extractRequestIdFromView(viewArgs.view);
|
|
242
|
-
if (!requestId) return;
|
|
243
|
-
const record = await store.get(requestId);
|
|
244
|
-
if (!record || record.kind !== "human-input" || record.status === "resolved") {
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
const actor = extractActor(viewArgs.body);
|
|
248
|
-
if (!await isAuthorized(record, actor)) {
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
const response = responseFromView(
|
|
252
|
-
record.request,
|
|
253
|
-
viewArgs.view
|
|
254
|
-
);
|
|
255
|
-
const resolution = {
|
|
256
|
-
kind: "human-input",
|
|
257
|
-
response
|
|
258
|
-
};
|
|
259
|
-
const resolved = await resolveRequest(requestId, resolution);
|
|
260
|
-
if (resolved?.target) {
|
|
261
|
-
await viewArgs.client.chat.update({
|
|
262
|
-
channel: resolved.target.channel,
|
|
263
|
-
ts: resolved.target.ts,
|
|
264
|
-
...buildResolvedMessage("Slack response received.", resolution)
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
async function isAuthorized(record, actor) {
|
|
269
|
-
if (options.authorize) {
|
|
270
|
-
return await options.authorize(record, actor);
|
|
271
|
-
}
|
|
272
|
-
return record.target?.userId === actor.userId;
|
|
273
|
-
}
|
|
274
|
-
async function updateOriginalMessage(args, record, resolution) {
|
|
275
|
-
const target = record.target;
|
|
276
|
-
if (!target) return;
|
|
277
|
-
const label = resolution.kind === "approval" ? `${resolution.action} selected.` : resolution.response.text;
|
|
278
|
-
await args.client.chat.update({
|
|
279
|
-
channel: target.channel,
|
|
280
|
-
ts: target.ts,
|
|
281
|
-
...buildResolvedMessage(label, resolution)
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
return {
|
|
285
|
-
actionIds,
|
|
286
|
-
store,
|
|
287
|
-
approval: {
|
|
288
|
-
async onRequest(request, options2) {
|
|
289
|
-
const resolution = await waitForResolution(
|
|
290
|
-
"approval",
|
|
291
|
-
request,
|
|
292
|
-
options2
|
|
293
|
-
);
|
|
294
|
-
if (resolution.kind !== "approval") {
|
|
295
|
-
throw new Error(
|
|
296
|
-
`Unexpected human-input resolution for ${request.id}.`
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
return {
|
|
300
|
-
action: resolution.action,
|
|
301
|
-
...resolution.feedback ? { feedback: resolution.feedback } : {},
|
|
302
|
-
...resolution.rememberScope ? { rememberScope: resolution.rememberScope } : {}
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
},
|
|
306
|
-
humanInput: {
|
|
307
|
-
async onRequest(request, options2) {
|
|
308
|
-
const resolution = await waitForResolution(
|
|
309
|
-
"human-input",
|
|
310
|
-
request,
|
|
311
|
-
options2
|
|
312
|
-
);
|
|
313
|
-
if (resolution.kind !== "human-input") {
|
|
314
|
-
throw new Error(`Unexpected approval resolution for ${request.id}.`);
|
|
315
|
-
}
|
|
316
|
-
return resolution.response;
|
|
317
|
-
}
|
|
318
|
-
},
|
|
319
|
-
cancel,
|
|
320
|
-
cancelAll,
|
|
321
|
-
handleInteractiveRequest,
|
|
322
|
-
install
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
function toAgentCoreResolution(resolution) {
|
|
326
|
-
return resolution;
|
|
327
|
-
}
|
|
328
|
-
function resolveActionIds(namespace, overrides) {
|
|
329
|
-
const prefix = normalizeActionIdNamespace(namespace);
|
|
330
|
-
return {
|
|
331
|
-
approvalAllow: `${prefix}_approval_allow`,
|
|
332
|
-
approvalDeny: `${prefix}_approval_deny`,
|
|
333
|
-
approvalRemember: `${prefix}_approval_remember`,
|
|
334
|
-
humanConfirm: `${prefix}_human_confirm`,
|
|
335
|
-
humanDeny: `${prefix}_human_deny`,
|
|
336
|
-
humanOpen: `${prefix}_human_open`,
|
|
337
|
-
humanSubmit: `${prefix}_human_submit`,
|
|
338
|
-
...overrides ?? {}
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
function normalizeActionIdNamespace(namespace) {
|
|
342
|
-
const trimmed = namespace.trim();
|
|
343
|
-
if (!trimmed) {
|
|
344
|
-
throw new Error("Slack interactive action namespace cannot be empty.");
|
|
345
|
-
}
|
|
346
|
-
return trimmed;
|
|
347
|
-
}
|
|
348
|
-
function assertActionIdsCanInstall(app, actionIds) {
|
|
349
|
-
const ids = Object.values(actionIds);
|
|
350
|
-
const duplicateWithinController = ids.find(
|
|
351
|
-
(id, index) => ids.indexOf(id) !== index
|
|
352
|
-
);
|
|
353
|
-
if (duplicateWithinController) {
|
|
354
|
-
throw new Error(
|
|
355
|
-
`Duplicate Slack interactive action id configured: ${duplicateWithinController}`
|
|
356
|
-
);
|
|
357
|
-
}
|
|
358
|
-
const appKey = app;
|
|
359
|
-
const installed = installedActionIds.get(appKey) ?? /* @__PURE__ */ new Set();
|
|
360
|
-
const duplicate = ids.find((id) => installed.has(id));
|
|
361
|
-
if (duplicate) {
|
|
362
|
-
throw new Error(
|
|
363
|
-
`Slack interactive action id '${duplicate}' is already installed on this Bolt app. Provide a unique createSlackInteractiveController({ namespace }) or actionIds config.`
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
for (const id of ids) {
|
|
367
|
-
installed.add(id);
|
|
368
|
-
}
|
|
369
|
-
installedActionIds.set(appKey, installed);
|
|
370
|
-
}
|
|
371
|
-
function firstActionValue(args) {
|
|
372
|
-
const body = args.body;
|
|
373
|
-
return decodeActionValue(body.actions?.[0]?.value);
|
|
374
|
-
}
|
|
375
|
-
function extractRequestId(value) {
|
|
376
|
-
return typeof value.requestId === "string" && value.requestId.length > 0 ? value.requestId : void 0;
|
|
377
|
-
}
|
|
378
|
-
function extractRequestIdFromView(view) {
|
|
379
|
-
return extractRequestId(decodeActionValue(view.private_metadata));
|
|
380
|
-
}
|
|
381
|
-
function extractActor(body) {
|
|
382
|
-
return {
|
|
383
|
-
userId: body.user?.id ?? "unknown",
|
|
384
|
-
...body.user?.team_id ?? body.team?.id ? { teamId: body.user?.team_id ?? body.team?.id } : {}
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
async function postEphemeral(args, text) {
|
|
388
|
-
const channel = args.body.channel?.id;
|
|
389
|
-
const user = args.body.user?.id;
|
|
390
|
-
if (!channel || !user || !args.client.chat.postEphemeral) return;
|
|
391
|
-
await args.client.chat.postEphemeral({ channel, user, text });
|
|
392
|
-
}
|
|
393
|
-
function responseFromView(request, view) {
|
|
394
|
-
const input = view.state?.values?.input?.value;
|
|
395
|
-
if (request.kind === "choice") {
|
|
396
|
-
const selected = input?.selected_options?.map((option) => option.value ?? "").filter(Boolean) ?? (input?.selected_option?.value ? [input.selected_option.value] : []);
|
|
397
|
-
return {
|
|
398
|
-
kind: "choice",
|
|
399
|
-
selected,
|
|
400
|
-
text: selected.join(", ")
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
const text = input?.value ?? "";
|
|
404
|
-
return { kind: "text", text };
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
export {
|
|
408
|
-
createSlackInteractiveController
|
|
409
|
-
};
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { ApprovalRequest, ApprovalResolution, HumanInputRequest, HumanInputResponse, ApprovalAction, ApprovalRememberScope } from '@cuylabs/agent-core';
|
|
2
|
-
import { SlackInteractiveActionIds, SlackInteractiveRequestStore, SlackInteractiveRequestRecord, SlackInteractiveActor, SlackInteractiveHumanInputRequest as SlackInteractiveHumanInputRequest$1, SlackInteractiveMessageRef } from '@cuylabs/channel-slack/interactive';
|
|
3
|
-
import { App } from '@slack/bolt';
|
|
4
|
-
import { e as SlackInteractiveRequestContext } from '../interactive-BigrPKnu.js';
|
|
5
|
-
import '@cuylabs/channel-slack/core';
|
|
6
|
-
|
|
7
|
-
type SlackInteractiveApprovalRequest = ApprovalRequest;
|
|
8
|
-
type SlackInteractiveHumanInputRequest = SlackInteractiveHumanInputRequest$1 & Partial<Pick<HumanInputRequest, "sessionId" | "timestamp" | "toolCallId">>;
|
|
9
|
-
type SlackInteractiveResolution = {
|
|
10
|
-
kind: "approval";
|
|
11
|
-
action: ApprovalAction;
|
|
12
|
-
feedback?: string;
|
|
13
|
-
rememberScope?: ApprovalRememberScope;
|
|
14
|
-
} | {
|
|
15
|
-
kind: "human-input";
|
|
16
|
-
response: HumanInputResponse;
|
|
17
|
-
};
|
|
18
|
-
interface SlackInteractiveRequestWaitOptions {
|
|
19
|
-
/**
|
|
20
|
-
* Abort waiting for this request. The controller removes its local waiter and
|
|
21
|
-
* deletes the pending store record when the signal fires.
|
|
22
|
-
*/
|
|
23
|
-
signal?: AbortSignal;
|
|
24
|
-
/**
|
|
25
|
-
* Override the controller-level request timeout for this request. Use `0` to
|
|
26
|
-
* disable timeout cleanup for this request.
|
|
27
|
-
*/
|
|
28
|
-
timeoutMs?: number;
|
|
29
|
-
}
|
|
30
|
-
interface SlackInteractiveControllerOptions {
|
|
31
|
-
store?: SlackInteractiveRequestStore;
|
|
32
|
-
/**
|
|
33
|
-
* Stable namespace for default Slack action IDs. Use this when installing
|
|
34
|
-
* multiple interactive controllers in the same Slack app.
|
|
35
|
-
*
|
|
36
|
-
* @default "agent_slack"
|
|
37
|
-
*/
|
|
38
|
-
namespace?: string;
|
|
39
|
-
actionIds?: Partial<SlackInteractiveActionIds>;
|
|
40
|
-
/**
|
|
41
|
-
* Default timeout for local waiters and pending store records. This should
|
|
42
|
-
* usually match the agent-core approval/human-input timeout.
|
|
43
|
-
*
|
|
44
|
-
* @default 300000
|
|
45
|
-
*/
|
|
46
|
-
requestTimeoutMs?: number;
|
|
47
|
-
/**
|
|
48
|
-
* Called on every successful Slack resolution after the local waiter, if
|
|
49
|
-
* present, is resolved. Use this to fan out decisions to agent-server or
|
|
50
|
-
* another runtime that owns the turn.
|
|
51
|
-
*/
|
|
52
|
-
onResolve?: (requestId: string, resolution: SlackInteractiveResolution) => void | Promise<void>;
|
|
53
|
-
/**
|
|
54
|
-
* Authorization hook for approving/responding to pending requests.
|
|
55
|
-
*
|
|
56
|
-
* Defaults to the original Slack requester only. Return `true` for delegated
|
|
57
|
-
* approvers, channel owners, or admin policy checks.
|
|
58
|
-
*/
|
|
59
|
-
authorize?: (record: SlackInteractiveRequestRecord, actor: SlackInteractiveActor) => boolean | Promise<boolean>;
|
|
60
|
-
}
|
|
61
|
-
interface SlackInteractiveController {
|
|
62
|
-
readonly actionIds: SlackInteractiveActionIds;
|
|
63
|
-
readonly store: SlackInteractiveRequestStore;
|
|
64
|
-
approval: {
|
|
65
|
-
onRequest(request: ApprovalRequest, options?: SlackInteractiveRequestWaitOptions): Promise<ApprovalResolution>;
|
|
66
|
-
};
|
|
67
|
-
humanInput: {
|
|
68
|
-
onRequest(request: HumanInputRequest, options?: SlackInteractiveRequestWaitOptions): Promise<HumanInputResponse>;
|
|
69
|
-
};
|
|
70
|
-
/** Reject one pending in-process waiter and delete its pending store record. */
|
|
71
|
-
cancel(requestId: string, reason?: string): Promise<boolean>;
|
|
72
|
-
/** Shutdown helper: cancel every pending request created by this controller. */
|
|
73
|
-
cancelAll(reason?: string): Promise<void>;
|
|
74
|
-
handleInteractiveRequest(context: SlackInteractiveRequestContext): Promise<boolean>;
|
|
75
|
-
install(app: App): void;
|
|
76
|
-
}
|
|
77
|
-
type SlackInteractivePendingWaiter = {
|
|
78
|
-
resolve: (resolution: SlackInteractiveResolution) => void;
|
|
79
|
-
reject: (error: Error) => void;
|
|
80
|
-
cleanup: () => void;
|
|
81
|
-
};
|
|
82
|
-
interface SlackInteractivePostedMessage {
|
|
83
|
-
text: string;
|
|
84
|
-
blocks: unknown[];
|
|
85
|
-
ref: SlackInteractiveMessageRef;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
declare function createSlackInteractiveController(options?: SlackInteractiveControllerOptions): SlackInteractiveController;
|
|
89
|
-
|
|
90
|
-
export { type SlackInteractiveApprovalRequest, type SlackInteractiveController, type SlackInteractiveControllerOptions, type SlackInteractiveHumanInputRequest, type SlackInteractivePendingWaiter, type SlackInteractivePostedMessage, type SlackInteractiveRequestWaitOptions, type SlackInteractiveResolution, createSlackInteractiveController };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { AgentEvent } from '@cuylabs/agent-core';
|
|
2
|
-
import { SlackInteractiveRequestBaseContext as SlackInteractiveRequestBaseContext$1, SlackInteractiveRequestContext as SlackInteractiveRequestContext$1 } from '@cuylabs/channel-slack/interactive';
|
|
3
|
-
import { SlackActivityInfo, SlackUserIdentity } from '@cuylabs/channel-slack/core';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Agent Core interactive request contracts for the Slack event bridge.
|
|
7
|
-
*
|
|
8
|
-
* Generic Slack message/responder primitives live in `@cuylabs/channel-slack`.
|
|
9
|
-
* This module narrows the request payloads to Agent Core events.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
type SlackApprovalRequest = Extract<AgentEvent, {
|
|
13
|
-
type: "approval-request";
|
|
14
|
-
}>["request"];
|
|
15
|
-
type SlackHumanInputRequest = Extract<AgentEvent, {
|
|
16
|
-
type: "human-input-request";
|
|
17
|
-
}>["request"];
|
|
18
|
-
type SlackInteractiveRequest = SlackApprovalRequest | SlackHumanInputRequest;
|
|
19
|
-
interface SlackInteractiveRequestBaseContext extends Omit<SlackInteractiveRequestBaseContext$1, "request"> {
|
|
20
|
-
request: SlackInteractiveRequest;
|
|
21
|
-
}
|
|
22
|
-
interface SlackInteractiveRequestContext extends Omit<SlackInteractiveRequestContext$1, "request"> {
|
|
23
|
-
slackActivity: SlackActivityInfo;
|
|
24
|
-
user: SlackUserIdentity;
|
|
25
|
-
request: SlackInteractiveRequest;
|
|
26
|
-
}
|
|
27
|
-
type SlackInteractiveRequestHandler = (context: SlackInteractiveRequestContext) => boolean | void | Promise<boolean | void>;
|
|
28
|
-
type SlackEventInteractiveRequestHandler = (context: SlackInteractiveRequestBaseContext) => boolean | void | Promise<boolean | void>;
|
|
29
|
-
|
|
30
|
-
export type { SlackApprovalRequest as S, SlackEventInteractiveRequestHandler as a, SlackHumanInputRequest as b, SlackInteractiveRequest as c, SlackInteractiveRequestBaseContext as d, SlackInteractiveRequestContext as e, SlackInteractiveRequestHandler as f };
|