@poolzin/pool-bot 2026.3.25 → 2026.3.27
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/dist/agents/model-fallback.js +5 -4
- package/dist/agents/tools/common.js +16 -201
- package/dist/auto-reply/auto-reply/reply/agent-runner-execution.js +502 -0
- package/dist/auto-reply/auto-reply/reply/agent-runner-helpers.js +65 -0
- package/dist/auto-reply/auto-reply/reply/agent-runner-memory.js +160 -0
- package/dist/auto-reply/auto-reply/reply/agent-runner-payloads.js +85 -0
- package/dist/auto-reply/auto-reply/reply/agent-runner-utils.js +101 -0
- package/dist/auto-reply/auto-reply/reply/bash-command.js +338 -0
- package/dist/auto-reply/auto-reply/reply/block-streaming.js +91 -0
- package/dist/auto-reply/auto-reply/reply/commands-approve.js +88 -0
- package/dist/auto-reply/auto-reply/reply/commands-bash.js +26 -0
- package/dist/auto-reply/auto-reply/reply/commands-compact.js +107 -0
- package/dist/auto-reply/auto-reply/reply/commands-config.js +241 -0
- package/dist/auto-reply/auto-reply/reply/commands-context-report.js +295 -0
- package/dist/auto-reply/auto-reply/reply/commands-context.js +30 -0
- package/dist/auto-reply/auto-reply/reply/commands-core.js +151 -0
- package/dist/auto-reply/auto-reply/reply/commands-export-session.js +163 -0
- package/dist/auto-reply/auto-reply/reply/commands-info.js +184 -0
- package/dist/auto-reply/auto-reply/reply/commands-models.js +299 -0
- package/dist/auto-reply/auto-reply/reply/commands-plugin.js +35 -0
- package/dist/auto-reply/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/auto-reply/reply/commands-setunset-standard.js +13 -0
- package/dist/auto-reply/auto-reply/reply/commands-setunset.js +73 -0
- package/dist/auto-reply/auto-reply/reply/commands-slash-parse.js +31 -0
- package/dist/auto-reply/auto-reply/reply/commands-status.js +178 -0
- package/dist/auto-reply/auto-reply/reply/commands-subagents.js +73 -0
- package/dist/auto-reply/auto-reply/reply/commands-system-prompt.js +117 -0
- package/dist/auto-reply/auto-reply/reply/commands-tts.js +231 -0
- package/dist/auto-reply/auto-reply/reply/directive-handling.impl.js +380 -0
- package/dist/auto-reply/auto-reply/reply/followup-runner.js +227 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-directives-apply.js +201 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-directives-utils.js +54 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-directives.js +332 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-inline-actions.js +258 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-run.js +297 -0
- package/dist/auto-reply/auto-reply/reply/groups.js +102 -0
- package/dist/auto-reply/auto-reply/reply/mentions.js +129 -0
- package/dist/auto-reply/auto-reply/reply/reply-delivery.js +92 -0
- package/dist/auto-reply/auto-reply/reply/reply-directives.js +30 -0
- package/dist/auto-reply/auto-reply/reply/reply-dispatcher.js +152 -0
- package/dist/auto-reply/auto-reply/reply/reply-elevated.js +166 -0
- package/dist/auto-reply/auto-reply/reply/reply-inline.js +28 -0
- package/dist/auto-reply/auto-reply/reply/reply-payloads.js +114 -0
- package/dist/auto-reply/auto-reply/reply/reply-reference.js +36 -0
- package/dist/auto-reply/auto-reply/reply/reply-tags.js +13 -0
- package/dist/auto-reply/auto-reply/reply/reply-threading.js +41 -0
- package/dist/auto-reply/auto-reply/reply/session-updates.js +233 -0
- package/dist/auto-reply/auto-reply/reply/stage-sandbox-media.js +146 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/canvas-host/a2ui/a2ui.bundle.js +2 -17772
- package/dist/canvas-host/a2ui/index.html +1 -307
- package/dist/channels/channels/directory-config.js +185 -0
- package/dist/channels/channels/discord/handle-action.guild-admin.js +332 -0
- package/dist/channels/channels/discord/handle-action.js +165 -0
- package/dist/channels/channels/discord.js +413 -0
- package/dist/channels/channels/dock.js +436 -0
- package/dist/channels/channels/index.js +51 -0
- package/dist/channels/channels/plugins/outbound/discord.js +101 -0
- package/dist/channels/channels/whatsapp.js +17 -0
- package/dist/channels/plugins/types.js +1 -1
- package/dist/channels/run-state-machine.js +7 -0
- package/dist/commands/models/auth.js +47 -1
- package/dist/commands-subagents/action-agents.js +44 -0
- package/dist/commands-subagents/action-focus.js +64 -0
- package/dist/commands-subagents/action-help.js +4 -0
- package/dist/commands-subagents/action-info.js +45 -0
- package/dist/commands-subagents/action-kill.js +60 -0
- package/dist/commands-subagents/action-list.js +44 -0
- package/dist/commands-subagents/action-log.js +29 -0
- package/dist/commands-subagents/action-send.js +119 -0
- package/dist/commands-subagents/action-spawn.js +52 -0
- package/dist/commands-subagents/action-unfocus.js +30 -0
- package/dist/commands-subagents/shared.js +303 -0
- package/dist/config/config.js +1 -8
- package/dist/config/types.secrets.js +61 -0
- package/dist/control-ui/assets/{index-D7shnQwQ.js → index-umCsvrWy.js} +884 -741
- package/dist/control-ui/assets/index-umCsvrWy.js.map +1 -0
- package/dist/control-ui/assets/pt-BR-DedEVAvY.js +2 -0
- package/dist/control-ui/assets/pt-BR-DedEVAvY.js.map +1 -0
- package/dist/control-ui/assets/zh-CN-CDzeklK-.js +2 -0
- package/dist/control-ui/assets/zh-CN-CDzeklK-.js.map +1 -0
- package/dist/control-ui/assets/zh-TW-BJCRYNWH.js +2 -0
- package/dist/control-ui/assets/zh-TW-BJCRYNWH.js.map +1 -0
- package/dist/control-ui/index.html +1 -1
- package/dist/gateway/method-scopes.js +9 -1
- package/dist/gateway/node-pending-work.js +142 -0
- package/dist/gateway/protocol/index.js +5 -1
- package/dist/gateway/protocol/schema/nodes.js +18 -0
- package/dist/gateway/server-methods/nodes-pending.js +96 -0
- package/dist/gateway/server-methods-list.js +4 -0
- package/dist/gateway/server-methods.js +2 -0
- package/dist/imessage/channel.js +253 -0
- package/dist/imessage/monitor/echo-cache.js +70 -0
- package/dist/imessage/monitor/loop-rate-limiter.js +51 -0
- package/dist/imessage/monitor/reflection-guard.js +50 -0
- package/dist/imessage/monitor/sanitize-outbound.js +25 -0
- package/dist/imessage/monitor/self-chat-cache.js +75 -0
- package/dist/imessage/runtime.js +3 -0
- package/dist/infra/exec-approval-reply.js +7 -0
- package/dist/infra/tmp-openclaw-dir.js +84 -0
- package/dist/pairing/pairing-challenge.js +15 -0
- package/dist/plugin-sdk/account-id.d.ts +1 -0
- package/dist/plugin-sdk/agent-media-payload.d.ts +12 -0
- package/dist/plugin-sdk/allow-from.d.ts +27 -0
- package/dist/plugin-sdk/command-auth.d.ts +25 -0
- package/dist/plugin-sdk/command-auth.js +3 -1
- package/dist/plugin-sdk/config-paths.d.ts +6 -0
- package/dist/plugin-sdk/file-lock.d.ts +16 -0
- package/dist/plugin-sdk/index.d.ts +428 -0
- package/dist/plugin-sdk/index.js +237 -103
- package/dist/plugin-sdk/json-store.d.ts +5 -0
- package/dist/plugin-sdk/keyed-async-queue.d.ts +12 -0
- package/dist/plugin-sdk/onboarding.d.ts +11 -0
- package/dist/plugin-sdk/provider-auth-result.d.ts +14 -0
- package/dist/plugin-sdk/slack-message-actions.d.ts +11 -0
- package/dist/plugin-sdk/status-helpers.d.ts +25 -0
- package/dist/plugin-sdk/temp-path.d.ts +12 -0
- package/dist/plugin-sdk/text-chunking.d.ts +1 -0
- package/dist/plugin-sdk/tool-send.d.ts +4 -0
- package/dist/plugin-sdk/webhook-path.d.ts +6 -0
- package/dist/plugin-sdk/webhook-targets.d.ts +23 -0
- package/dist/plugin-sdk/windows-spawn.d.ts +39 -0
- package/dist/plugin-sdk-internal/accounts.js +6 -0
- package/dist/plugin-sdk-internal/discord.js +23 -0
- package/dist/plugin-sdk-internal/imessage.js +13 -0
- package/dist/plugin-sdk-internal/setup.js +9 -0
- package/dist/plugin-sdk-internal/signal.js +13 -0
- package/dist/plugin-sdk-internal/slack.js +22 -0
- package/dist/plugin-sdk-internal/telegram.js +32 -0
- package/dist/plugin-sdk-internal/whatsapp.js +29 -0
- package/dist/routing/session-key.js +4 -185
- package/dist/shared/pid-alive.js +2 -61
- package/dist/shared/process-scoped-map.js +5 -7
- package/dist/signal/channel.js +264 -0
- package/dist/signal/monitor/access-policy.js +60 -0
- package/dist/signal/runtime.js +3 -0
- package/dist/slack/account-inspect.js +135 -0
- package/dist/slack/blocks-input.js +7 -38
- package/dist/slack/channel.js +394 -0
- package/dist/slack/interactive-replies.js +28 -0
- package/dist/slack/monitor/channel-type.js +31 -0
- package/dist/slack/monitor/dm-auth.js +49 -0
- package/dist/slack/monitor/events/interactions.modal.js +137 -0
- package/dist/slack/monitor/events/message-subtype-handlers.js +68 -0
- package/dist/slack/monitor/events/system-event-context.js +29 -0
- package/dist/slack/monitor/events/system-event-test-harness.js +41 -0
- package/dist/slack/monitor/external-arg-menu-store.js +46 -0
- package/dist/slack/monitor/message-handler/prepare-content.js +69 -0
- package/dist/slack/monitor/message-handler/prepare-thread-context.js +91 -0
- package/dist/slack/monitor/message-handler/prepare.test-helpers.js +55 -0
- package/dist/slack/monitor/reconnect-policy.js +78 -0
- package/dist/slack/monitor/slash-commands.runtime.js +1 -0
- package/dist/slack/monitor/slash-dispatch.runtime.js +9 -0
- package/dist/slack/monitor/slash-skill-commands.runtime.js +1 -0
- package/dist/slack/resolve-allowlist-common.js +36 -0
- package/dist/slack/runtime.js +3 -0
- package/dist/slack/sent-thread-cache.js +61 -0
- package/dist/slack/truncate.js +10 -0
- package/dist/telegram/account-inspect.js +175 -0
- package/dist/telegram/allow-from.js +10 -0
- package/dist/telegram/api-fetch.js +18 -0
- package/dist/telegram/approval-buttons.js +30 -0
- package/dist/telegram/audit-membership-runtime.js +61 -0
- package/dist/telegram/bot/delivery.replies.js +508 -0
- package/dist/telegram/bot/delivery.resolve-media.js +227 -0
- package/dist/telegram/bot/delivery.send.js +132 -0
- package/dist/telegram/bot/reply-threading.js +46 -0
- package/dist/telegram/bot-message-context.body.js +186 -0
- package/dist/telegram/bot-message-context.session.js +207 -0
- package/dist/telegram/bot-message-context.types.js +1 -0
- package/dist/telegram/bot-native-commands.test-helpers.js +117 -0
- package/dist/telegram/bot.media.e2e-harness.js +81 -0
- package/dist/telegram/bot.media.test-utils.js +81 -0
- package/dist/telegram/channel-actions.js +225 -0
- package/dist/telegram/channel.js +515 -0
- package/dist/telegram/conversation-route.js +107 -0
- package/dist/telegram/delivery.js +2 -0
- package/dist/telegram/delivery.replies.js +508 -0
- package/dist/telegram/dm-access.js +86 -0
- package/dist/telegram/draft-stream.test-helpers.js +62 -0
- package/dist/telegram/exec-approvals-handler.js +281 -0
- package/dist/telegram/exec-approvals.js +62 -0
- package/dist/telegram/forum-service-message.js +22 -0
- package/dist/telegram/group-config-helpers.js +10 -0
- package/dist/telegram/lane-delivery-state.js +19 -0
- package/dist/telegram/lane-delivery-text-deliverer.js +357 -0
- package/dist/telegram/lane-delivery.js +2 -0
- package/dist/telegram/normalize.js +37 -0
- package/dist/telegram/onboarding.js +192 -0
- package/dist/telegram/outbound-adapter.js +100 -0
- package/dist/telegram/polling-session.js +275 -0
- package/dist/telegram/runtime.js +3 -0
- package/dist/telegram/sendchataction-401-backoff.js +71 -0
- package/dist/telegram/sequential-key.js +46 -0
- package/dist/telegram/status-issues.js +105 -0
- package/dist/telegram/target-writeback.js +165 -0
- package/dist/telegram/thread-bindings.js +560 -0
- package/dist/utils.js +32 -257
- package/dist/wizard/prompts.js +5 -5
- package/extensions/feishu/src/policy.ts +1 -1
- package/extensions/firecrawl/index.test.ts +82 -0
- package/extensions/firecrawl/index.ts +20 -0
- package/extensions/firecrawl/openclaw.plugin.json +8 -0
- package/extensions/firecrawl/package.json +12 -0
- package/extensions/firecrawl/src/config.ts +159 -0
- package/extensions/firecrawl/src/firecrawl-client.ts +446 -0
- package/extensions/firecrawl/src/firecrawl-scrape-tool.ts +89 -0
- package/extensions/firecrawl/src/firecrawl-search-provider.ts +63 -0
- package/extensions/firecrawl/src/firecrawl-search-tool.ts +76 -0
- package/package.json +1 -1
- package/dist/.buildstamp +0 -1
- package/dist/acp/bindings-store.js +0 -209
- package/dist/acp/control-plane/runtime-cache.js +0 -54
- package/dist/acp/control-plane/runtime-options.js +0 -215
- package/dist/acp/control-plane/session-actor-queue.js +0 -36
- package/dist/acp/index.js +0 -2
- package/dist/acp/runtime/errors.js +0 -47
- package/dist/acp/runtime/registry.js +0 -86
- package/dist/acp/secret-file.js +0 -22
- package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +0 -23
- package/dist/agents/bash-process-registry.test-helpers.js +0 -29
- package/dist/agents/bash-tools.exec-approval-request.js +0 -20
- package/dist/agents/bash-tools.exec-host-gateway.js +0 -240
- package/dist/agents/bash-tools.exec-host-node.js +0 -235
- package/dist/agents/checkpoint-manager.js +0 -290
- package/dist/agents/claude-cli-runner.js +0 -3
- package/dist/agents/error-classifier.js +0 -251
- package/dist/agents/live-model-filter.js +0 -84
- package/dist/agents/nvidia-models.js +0 -228
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +0 -34
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +0 -156
- package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +0 -30
- package/dist/agents/provider/config-loader.js +0 -76
- package/dist/agents/provider/index.js +0 -15
- package/dist/agents/provider/models-dev.js +0 -129
- package/dist/agents/provider/session-binding.js +0 -376
- package/dist/agents/queued-file-writer.js +0 -22
- package/dist/agents/skills/bundled-context.js +0 -23
- package/dist/agents/skills/security.js +0 -211
- package/dist/agents/skills/tools-dir.js +0 -9
- package/dist/agents/skills-install-download.js +0 -290
- package/dist/agents/skills-install-output.js +0 -30
- package/dist/agents/skills-install.download-test-utils.js +0 -36
- package/dist/agents/skills.test-helpers.js +0 -13
- package/dist/agents/subagent-announce-reliability.js +0 -160
- package/dist/agents/subagent-registry.mocks.shared.js +0 -12
- package/dist/agents/test-helpers/assistant-message-fixtures.js +0 -29
- package/dist/agents/test-helpers/fast-coding-tools.js +0 -1
- package/dist/agents/test-helpers/fast-core-tools.js +0 -8
- package/dist/agents/test-helpers/fast-tool-stubs.js +0 -18
- package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +0 -74
- package/dist/agents/test-helpers/pi-tools-sandbox-context.js +0 -27
- package/dist/agents/tool-display-common.js +0 -915
- package/dist/agents/tool-policy-shared.js +0 -108
- package/dist/agents/tool-policy.conformance.js +0 -14
- package/dist/agents/tool-result-truncation.js +0 -299
- package/dist/agents/tools/cron-tool.test-helpers.js +0 -12
- package/dist/agents/tools/discord-actions-moderation-shared.js +0 -27
- package/dist/agents/tools/discord-actions-presence.js +0 -78
- package/dist/control-ui/assets/index-D7shnQwQ.js.map +0 -1
- package/dist/discord/discord-improvements.js +0 -167
- package/dist/discord/index.js +0 -2
- package/dist/hooks/bundled/boot-md/HOOK.md +0 -19
- package/dist/hooks/bundled/command-logger/HOOK.md +0 -122
- package/dist/hooks/bundled/session-memory/HOOK.md +0 -86
- package/dist/hooks/bundled/soul-evil/HOOK.md +0 -71
- package/dist/whatsapp/normalize.js +0 -66
- package/dist/whatsapp/resolve-outbound-target.js +0 -42
- /package/dist/{acp/runtime/types.js → auto-reply/auto-reply/reply/commands-types.js} +0 -0
- /package/dist/{agents/pi-embedded-payloads.js → slack/account-surface-fields.js} +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function inferSlackChannelType(channelId) {
|
|
2
|
+
const trimmed = channelId?.trim();
|
|
3
|
+
if (!trimmed) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
if (trimmed.startsWith("D")) {
|
|
7
|
+
return "im";
|
|
8
|
+
}
|
|
9
|
+
if (trimmed.startsWith("C")) {
|
|
10
|
+
return "channel";
|
|
11
|
+
}
|
|
12
|
+
if (trimmed.startsWith("G")) {
|
|
13
|
+
return "group";
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
export function normalizeSlackChannelType(channelType, channelId) {
|
|
18
|
+
const normalized = channelType?.trim().toLowerCase();
|
|
19
|
+
const inferred = inferSlackChannelType(channelId);
|
|
20
|
+
if (normalized === "im" ||
|
|
21
|
+
normalized === "mpim" ||
|
|
22
|
+
normalized === "channel" ||
|
|
23
|
+
normalized === "group") {
|
|
24
|
+
// D-prefix channel IDs are always DMs — override a contradicting channel_type.
|
|
25
|
+
if (inferred === "im" && normalized !== "im") {
|
|
26
|
+
return "im";
|
|
27
|
+
}
|
|
28
|
+
return normalized;
|
|
29
|
+
}
|
|
30
|
+
return inferred ?? "channel";
|
|
31
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { formatAllowlistMatchMeta } from "../../../../src/channels/allowlist-match.js";
|
|
2
|
+
import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js";
|
|
3
|
+
import { upsertChannelPairingRequest } from "../../../../src/pairing/pairing-store.js";
|
|
4
|
+
import { resolveSlackAllowListMatch } from "./allow-list.js";
|
|
5
|
+
export async function authorizeSlackDirectMessage(params) {
|
|
6
|
+
if (!params.ctx.dmEnabled || params.ctx.dmPolicy === "disabled") {
|
|
7
|
+
await params.onDisabled();
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
if (params.ctx.dmPolicy === "open") {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
const sender = await params.resolveSenderName(params.senderId);
|
|
14
|
+
const senderName = sender?.name ?? undefined;
|
|
15
|
+
const allowMatch = resolveSlackAllowListMatch({
|
|
16
|
+
allowList: params.allowFromLower,
|
|
17
|
+
id: params.senderId,
|
|
18
|
+
name: senderName,
|
|
19
|
+
allowNameMatching: params.ctx.allowNameMatching,
|
|
20
|
+
});
|
|
21
|
+
const allowMatchMeta = formatAllowlistMatchMeta(allowMatch);
|
|
22
|
+
if (allowMatch.allowed) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
if (params.ctx.dmPolicy === "pairing") {
|
|
26
|
+
await issuePairingChallenge({
|
|
27
|
+
channel: "slack",
|
|
28
|
+
senderId: params.senderId,
|
|
29
|
+
senderIdLine: `Your Slack user id: ${params.senderId}`,
|
|
30
|
+
meta: { name: senderName },
|
|
31
|
+
upsertPairingRequest: async ({ id, meta }) => await upsertChannelPairingRequest({
|
|
32
|
+
channel: "slack",
|
|
33
|
+
id,
|
|
34
|
+
accountId: params.accountId,
|
|
35
|
+
meta,
|
|
36
|
+
}),
|
|
37
|
+
sendPairingReply: params.sendPairingReply,
|
|
38
|
+
onCreated: () => {
|
|
39
|
+
params.log(`slack pairing request sender=${params.senderId} name=${senderName ?? "unknown"} (${allowMatchMeta})`);
|
|
40
|
+
},
|
|
41
|
+
onReplyError: (err) => {
|
|
42
|
+
params.log(`slack pairing reply failed for ${params.senderId}: ${String(err)}`);
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
await params.onUnauthorized({ allowMatchMeta, senderName });
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { enqueueSystemEvent } from "../../../../../src/infra/system-events.js";
|
|
2
|
+
import { parseSlackModalPrivateMetadata } from "../../modal-metadata.js";
|
|
3
|
+
import { authorizeSlackSystemEventSender } from "../auth.js";
|
|
4
|
+
function resolveModalSessionRouting(params) {
|
|
5
|
+
const metadata = params.metadata;
|
|
6
|
+
if (metadata.sessionKey) {
|
|
7
|
+
return {
|
|
8
|
+
sessionKey: metadata.sessionKey,
|
|
9
|
+
channelId: metadata.channelId,
|
|
10
|
+
channelType: metadata.channelType,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
if (metadata.channelId) {
|
|
14
|
+
return {
|
|
15
|
+
sessionKey: params.ctx.resolveSlackSystemEventSessionKey({
|
|
16
|
+
channelId: metadata.channelId,
|
|
17
|
+
channelType: metadata.channelType,
|
|
18
|
+
senderId: params.userId,
|
|
19
|
+
}),
|
|
20
|
+
channelId: metadata.channelId,
|
|
21
|
+
channelType: metadata.channelType,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
sessionKey: params.ctx.resolveSlackSystemEventSessionKey({}),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function summarizeSlackViewLifecycleContext(view) {
|
|
29
|
+
const rootViewId = view.root_view_id;
|
|
30
|
+
const previousViewId = view.previous_view_id;
|
|
31
|
+
const externalId = view.external_id;
|
|
32
|
+
const viewHash = view.hash;
|
|
33
|
+
return {
|
|
34
|
+
rootViewId,
|
|
35
|
+
previousViewId,
|
|
36
|
+
externalId,
|
|
37
|
+
viewHash,
|
|
38
|
+
isStackedView: Boolean(previousViewId),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function resolveSlackModalEventBase(params) {
|
|
42
|
+
const metadata = parseSlackModalPrivateMetadata(params.body.view?.private_metadata);
|
|
43
|
+
const callbackId = params.body.view?.callback_id ?? "unknown";
|
|
44
|
+
const userId = params.body.user?.id ?? "unknown";
|
|
45
|
+
const viewId = params.body.view?.id;
|
|
46
|
+
const inputs = params.summarizeViewState(params.body.view?.state?.values);
|
|
47
|
+
const sessionRouting = resolveModalSessionRouting({
|
|
48
|
+
ctx: params.ctx,
|
|
49
|
+
metadata,
|
|
50
|
+
userId,
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
callbackId,
|
|
54
|
+
userId,
|
|
55
|
+
expectedUserId: metadata.userId,
|
|
56
|
+
viewId,
|
|
57
|
+
sessionRouting,
|
|
58
|
+
payload: {
|
|
59
|
+
actionId: `view:${callbackId}`,
|
|
60
|
+
callbackId,
|
|
61
|
+
viewId,
|
|
62
|
+
userId,
|
|
63
|
+
teamId: params.body.team?.id,
|
|
64
|
+
...summarizeSlackViewLifecycleContext({
|
|
65
|
+
root_view_id: params.body.view?.root_view_id,
|
|
66
|
+
previous_view_id: params.body.view?.previous_view_id,
|
|
67
|
+
external_id: params.body.view?.external_id,
|
|
68
|
+
hash: params.body.view?.hash,
|
|
69
|
+
}),
|
|
70
|
+
privateMetadata: params.body.view?.private_metadata,
|
|
71
|
+
routedChannelId: sessionRouting.channelId,
|
|
72
|
+
routedChannelType: sessionRouting.channelType,
|
|
73
|
+
inputs,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export async function emitSlackModalLifecycleEvent(params) {
|
|
78
|
+
const { callbackId, userId, expectedUserId, viewId, sessionRouting, payload } = resolveSlackModalEventBase({
|
|
79
|
+
ctx: params.ctx,
|
|
80
|
+
body: params.body,
|
|
81
|
+
summarizeViewState: params.summarizeViewState,
|
|
82
|
+
});
|
|
83
|
+
const isViewClosed = params.interactionType === "view_closed";
|
|
84
|
+
const isCleared = params.body.is_cleared === true;
|
|
85
|
+
const eventPayload = isViewClosed
|
|
86
|
+
? {
|
|
87
|
+
interactionType: params.interactionType,
|
|
88
|
+
...payload,
|
|
89
|
+
isCleared,
|
|
90
|
+
}
|
|
91
|
+
: {
|
|
92
|
+
interactionType: params.interactionType,
|
|
93
|
+
...payload,
|
|
94
|
+
};
|
|
95
|
+
if (isViewClosed) {
|
|
96
|
+
params.ctx.runtime.log?.(`slack:interaction view_closed callback=${callbackId} user=${userId} cleared=${isCleared}`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
params.ctx.runtime.log?.(`slack:interaction view_submission callback=${callbackId} user=${userId} inputs=${payload.inputs.length}`);
|
|
100
|
+
}
|
|
101
|
+
if (!expectedUserId) {
|
|
102
|
+
params.ctx.runtime.log?.(`slack:interaction drop modal callback=${callbackId} user=${userId} reason=missing-expected-user`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const auth = await authorizeSlackSystemEventSender({
|
|
106
|
+
ctx: params.ctx,
|
|
107
|
+
senderId: userId,
|
|
108
|
+
channelId: sessionRouting.channelId,
|
|
109
|
+
channelType: sessionRouting.channelType,
|
|
110
|
+
expectedSenderId: expectedUserId,
|
|
111
|
+
});
|
|
112
|
+
if (!auth.allowed) {
|
|
113
|
+
params.ctx.runtime.log?.(`slack:interaction drop modal callback=${callbackId} user=${userId} reason=${auth.reason ?? "unauthorized"}`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
enqueueSystemEvent(params.formatSystemEvent(eventPayload), {
|
|
117
|
+
sessionKey: sessionRouting.sessionKey,
|
|
118
|
+
contextKey: [params.contextPrefix, callbackId, viewId, userId].filter(Boolean).join(":"),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
export function registerModalLifecycleHandler(params) {
|
|
122
|
+
params.register(params.matcher, async ({ ack, body }) => {
|
|
123
|
+
await ack();
|
|
124
|
+
if (params.ctx.shouldDropMismatchedSlackEvent?.(body)) {
|
|
125
|
+
params.ctx.runtime.log?.(`slack:interaction drop ${params.interactionType} payload (mismatched app/team)`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
await emitSlackModalLifecycleEvent({
|
|
129
|
+
ctx: params.ctx,
|
|
130
|
+
body: body,
|
|
131
|
+
interactionType: params.interactionType,
|
|
132
|
+
contextPrefix: params.contextPrefix,
|
|
133
|
+
summarizeViewState: params.summarizeViewState,
|
|
134
|
+
formatSystemEvent: params.formatSystemEvent,
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const changedHandler = {
|
|
2
|
+
subtype: "message_changed",
|
|
3
|
+
eventKind: "message_changed",
|
|
4
|
+
describe: (channelLabel) => `Slack message edited in ${channelLabel}.`,
|
|
5
|
+
contextKey: (event) => {
|
|
6
|
+
const changed = event;
|
|
7
|
+
const channelId = changed.channel ?? "unknown";
|
|
8
|
+
const messageId = changed.message?.ts ?? changed.previous_message?.ts ?? changed.event_ts ?? "unknown";
|
|
9
|
+
return `slack:message:changed:${channelId}:${messageId}`;
|
|
10
|
+
},
|
|
11
|
+
resolveSenderId: (event) => {
|
|
12
|
+
const changed = event;
|
|
13
|
+
return (changed.message?.user ??
|
|
14
|
+
changed.previous_message?.user ??
|
|
15
|
+
changed.message?.bot_id ??
|
|
16
|
+
changed.previous_message?.bot_id);
|
|
17
|
+
},
|
|
18
|
+
resolveChannelId: (event) => event.channel,
|
|
19
|
+
resolveChannelType: () => undefined,
|
|
20
|
+
};
|
|
21
|
+
const deletedHandler = {
|
|
22
|
+
subtype: "message_deleted",
|
|
23
|
+
eventKind: "message_deleted",
|
|
24
|
+
describe: (channelLabel) => `Slack message deleted in ${channelLabel}.`,
|
|
25
|
+
contextKey: (event) => {
|
|
26
|
+
const deleted = event;
|
|
27
|
+
const channelId = deleted.channel ?? "unknown";
|
|
28
|
+
const messageId = deleted.deleted_ts ?? deleted.event_ts ?? "unknown";
|
|
29
|
+
return `slack:message:deleted:${channelId}:${messageId}`;
|
|
30
|
+
},
|
|
31
|
+
resolveSenderId: (event) => {
|
|
32
|
+
const deleted = event;
|
|
33
|
+
return deleted.previous_message?.user ?? deleted.previous_message?.bot_id;
|
|
34
|
+
},
|
|
35
|
+
resolveChannelId: (event) => event.channel,
|
|
36
|
+
resolveChannelType: () => undefined,
|
|
37
|
+
};
|
|
38
|
+
const threadBroadcastHandler = {
|
|
39
|
+
subtype: "thread_broadcast",
|
|
40
|
+
eventKind: "thread_broadcast",
|
|
41
|
+
describe: (channelLabel) => `Slack thread reply broadcast in ${channelLabel}.`,
|
|
42
|
+
contextKey: (event) => {
|
|
43
|
+
const thread = event;
|
|
44
|
+
const channelId = thread.channel ?? "unknown";
|
|
45
|
+
const messageId = thread.message?.ts ?? thread.event_ts ?? "unknown";
|
|
46
|
+
return `slack:thread:broadcast:${channelId}:${messageId}`;
|
|
47
|
+
},
|
|
48
|
+
resolveSenderId: (event) => {
|
|
49
|
+
const thread = event;
|
|
50
|
+
return thread.user ?? thread.message?.user ?? thread.message?.bot_id;
|
|
51
|
+
},
|
|
52
|
+
resolveChannelId: (event) => event.channel,
|
|
53
|
+
resolveChannelType: () => undefined,
|
|
54
|
+
};
|
|
55
|
+
const SUBTYPE_HANDLER_REGISTRY = {
|
|
56
|
+
message_changed: changedHandler,
|
|
57
|
+
message_deleted: deletedHandler,
|
|
58
|
+
thread_broadcast: threadBroadcastHandler,
|
|
59
|
+
};
|
|
60
|
+
export function resolveSlackMessageSubtypeHandler(event) {
|
|
61
|
+
const subtype = event.subtype;
|
|
62
|
+
if (subtype !== "message_changed" &&
|
|
63
|
+
subtype !== "message_deleted" &&
|
|
64
|
+
subtype !== "thread_broadcast") {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
return SUBTYPE_HANDLER_REGISTRY[subtype];
|
|
68
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { logVerbose } from "../../../../../src/globals.js";
|
|
2
|
+
import { authorizeSlackSystemEventSender } from "../auth.js";
|
|
3
|
+
import { resolveSlackChannelLabel } from "../channel-config.js";
|
|
4
|
+
export async function authorizeAndResolveSlackSystemEventContext(params) {
|
|
5
|
+
const { ctx, senderId, channelId, channelType, eventKind } = params;
|
|
6
|
+
const auth = await authorizeSlackSystemEventSender({
|
|
7
|
+
ctx,
|
|
8
|
+
senderId,
|
|
9
|
+
channelId,
|
|
10
|
+
channelType,
|
|
11
|
+
});
|
|
12
|
+
if (!auth.allowed) {
|
|
13
|
+
logVerbose(`slack: drop ${eventKind} sender ${senderId ?? "unknown"} channel=${channelId ?? "unknown"} reason=${auth.reason ?? "unauthorized"}`);
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const channelLabel = resolveSlackChannelLabel({
|
|
17
|
+
channelId,
|
|
18
|
+
channelName: auth.channelName,
|
|
19
|
+
});
|
|
20
|
+
const sessionKey = ctx.resolveSlackSystemEventSessionKey({
|
|
21
|
+
channelId,
|
|
22
|
+
channelType: auth.channelType,
|
|
23
|
+
senderId,
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
channelLabel,
|
|
27
|
+
sessionKey,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export function createSlackSystemEventTestHarness(overrides) {
|
|
2
|
+
const handlers = {};
|
|
3
|
+
const channelType = overrides?.channelType ?? "im";
|
|
4
|
+
const app = {
|
|
5
|
+
event: (name, handler) => {
|
|
6
|
+
handlers[name] = handler;
|
|
7
|
+
},
|
|
8
|
+
};
|
|
9
|
+
const ctx = {
|
|
10
|
+
app,
|
|
11
|
+
runtime: { error: () => { } },
|
|
12
|
+
dmEnabled: true,
|
|
13
|
+
dmPolicy: overrides?.dmPolicy ?? "open",
|
|
14
|
+
defaultRequireMention: true,
|
|
15
|
+
channelsConfig: overrides?.channelUsers
|
|
16
|
+
? {
|
|
17
|
+
C1: {
|
|
18
|
+
users: overrides.channelUsers,
|
|
19
|
+
allow: true,
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
: undefined,
|
|
23
|
+
groupPolicy: "open",
|
|
24
|
+
allowFrom: overrides?.allowFrom ?? [],
|
|
25
|
+
allowNameMatching: false,
|
|
26
|
+
shouldDropMismatchedSlackEvent: () => false,
|
|
27
|
+
isChannelAllowed: () => true,
|
|
28
|
+
resolveChannelName: async () => ({
|
|
29
|
+
name: channelType === "im" ? "direct" : "general",
|
|
30
|
+
type: channelType,
|
|
31
|
+
}),
|
|
32
|
+
resolveUserName: async () => ({ name: "alice" }),
|
|
33
|
+
resolveSlackSystemEventSessionKey: () => "agent:main:main",
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
ctx,
|
|
37
|
+
getHandler(name) {
|
|
38
|
+
return handlers[name] ?? null;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { generateSecureToken } from "../../../../src/infra/secure-random.js";
|
|
2
|
+
const SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES = 18;
|
|
3
|
+
const SLACK_EXTERNAL_ARG_MENU_TOKEN_LENGTH = Math.ceil((SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES * 8) / 6);
|
|
4
|
+
const SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN = new RegExp(`^[A-Za-z0-9_-]{${SLACK_EXTERNAL_ARG_MENU_TOKEN_LENGTH}}$`);
|
|
5
|
+
const SLACK_EXTERNAL_ARG_MENU_TTL_MS = 10 * 60 * 1000;
|
|
6
|
+
export const SLACK_EXTERNAL_ARG_MENU_PREFIX = "openclaw_cmdarg_ext:";
|
|
7
|
+
function pruneSlackExternalArgMenuStore(store, now) {
|
|
8
|
+
for (const [token, entry] of store.entries()) {
|
|
9
|
+
if (entry.expiresAt <= now) {
|
|
10
|
+
store.delete(token);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function createSlackExternalArgMenuToken(store) {
|
|
15
|
+
let token = "";
|
|
16
|
+
do {
|
|
17
|
+
token = generateSecureToken(SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES);
|
|
18
|
+
} while (store.has(token));
|
|
19
|
+
return token;
|
|
20
|
+
}
|
|
21
|
+
export function createSlackExternalArgMenuStore() {
|
|
22
|
+
const store = new Map();
|
|
23
|
+
return {
|
|
24
|
+
create(params, now = Date.now()) {
|
|
25
|
+
pruneSlackExternalArgMenuStore(store, now);
|
|
26
|
+
const token = createSlackExternalArgMenuToken(store);
|
|
27
|
+
store.set(token, {
|
|
28
|
+
choices: params.choices,
|
|
29
|
+
userId: params.userId,
|
|
30
|
+
expiresAt: now + SLACK_EXTERNAL_ARG_MENU_TTL_MS,
|
|
31
|
+
});
|
|
32
|
+
return token;
|
|
33
|
+
},
|
|
34
|
+
readToken(raw) {
|
|
35
|
+
if (typeof raw !== "string" || !raw.startsWith(SLACK_EXTERNAL_ARG_MENU_PREFIX)) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const token = raw.slice(SLACK_EXTERNAL_ARG_MENU_PREFIX.length).trim();
|
|
39
|
+
return SLACK_EXTERNAL_ARG_MENU_TOKEN_PATTERN.test(token) ? token : undefined;
|
|
40
|
+
},
|
|
41
|
+
get(token, now = Date.now()) {
|
|
42
|
+
pruneSlackExternalArgMenuStore(store, now);
|
|
43
|
+
return store.get(token);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { logVerbose } from "../../../../../src/globals.js";
|
|
2
|
+
import { MAX_SLACK_MEDIA_FILES, resolveSlackAttachmentContent, resolveSlackMedia, } from "../media.js";
|
|
3
|
+
function filterInheritedParentFiles(params) {
|
|
4
|
+
const { files, isThreadReply, threadStarter } = params;
|
|
5
|
+
if (!isThreadReply || !files?.length) {
|
|
6
|
+
return files;
|
|
7
|
+
}
|
|
8
|
+
if (!threadStarter?.files?.length) {
|
|
9
|
+
return files;
|
|
10
|
+
}
|
|
11
|
+
const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
|
|
12
|
+
const filtered = files.filter((file) => !file.id || !starterFileIds.has(file.id));
|
|
13
|
+
if (filtered.length < files.length) {
|
|
14
|
+
logVerbose(`slack: filtered ${files.length - filtered.length} inherited parent file(s) from thread reply`);
|
|
15
|
+
}
|
|
16
|
+
return filtered.length > 0 ? filtered : undefined;
|
|
17
|
+
}
|
|
18
|
+
export async function resolveSlackMessageContent(params) {
|
|
19
|
+
const ownFiles = filterInheritedParentFiles({
|
|
20
|
+
files: params.message.files,
|
|
21
|
+
isThreadReply: params.isThreadReply,
|
|
22
|
+
threadStarter: params.threadStarter,
|
|
23
|
+
});
|
|
24
|
+
const media = await resolveSlackMedia({
|
|
25
|
+
files: ownFiles,
|
|
26
|
+
token: params.botToken,
|
|
27
|
+
maxBytes: params.mediaMaxBytes,
|
|
28
|
+
});
|
|
29
|
+
const attachmentContent = await resolveSlackAttachmentContent({
|
|
30
|
+
attachments: params.message.attachments,
|
|
31
|
+
token: params.botToken,
|
|
32
|
+
maxBytes: params.mediaMaxBytes,
|
|
33
|
+
});
|
|
34
|
+
const mergedMedia = [...(media ?? []), ...(attachmentContent?.media ?? [])];
|
|
35
|
+
const effectiveDirectMedia = mergedMedia.length > 0 ? mergedMedia : null;
|
|
36
|
+
const mediaPlaceholder = effectiveDirectMedia
|
|
37
|
+
? effectiveDirectMedia.map((item) => item.placeholder).join(" ")
|
|
38
|
+
: undefined;
|
|
39
|
+
const fallbackFiles = ownFiles ?? [];
|
|
40
|
+
const fileOnlyFallback = !mediaPlaceholder && fallbackFiles.length > 0
|
|
41
|
+
? fallbackFiles
|
|
42
|
+
.slice(0, MAX_SLACK_MEDIA_FILES)
|
|
43
|
+
.map((file) => file.name?.trim() || "file")
|
|
44
|
+
.join(", ")
|
|
45
|
+
: undefined;
|
|
46
|
+
const fileOnlyPlaceholder = fileOnlyFallback ? `[Slack file: ${fileOnlyFallback}]` : undefined;
|
|
47
|
+
const botAttachmentText = params.isBotMessage && !attachmentContent?.text
|
|
48
|
+
? (params.message.attachments ?? [])
|
|
49
|
+
.map((attachment) => attachment.text?.trim() || attachment.fallback?.trim())
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.join("\n")
|
|
52
|
+
: undefined;
|
|
53
|
+
const rawBody = [
|
|
54
|
+
(params.message.text ?? "").trim(),
|
|
55
|
+
attachmentContent?.text,
|
|
56
|
+
botAttachmentText,
|
|
57
|
+
mediaPlaceholder,
|
|
58
|
+
fileOnlyPlaceholder,
|
|
59
|
+
]
|
|
60
|
+
.filter(Boolean)
|
|
61
|
+
.join("\n") || "";
|
|
62
|
+
if (!rawBody) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
rawBody,
|
|
67
|
+
effectiveDirectMedia,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { formatInboundEnvelope } from "../../../../../src/auto-reply/envelope.js";
|
|
2
|
+
import { readSessionUpdatedAt } from "../../../../../src/config/sessions.js";
|
|
3
|
+
import { logVerbose } from "../../../../../src/globals.js";
|
|
4
|
+
import { resolveSlackMedia, resolveSlackThreadHistory, } from "../media.js";
|
|
5
|
+
export async function resolveSlackThreadContextData(params) {
|
|
6
|
+
let threadStarterBody;
|
|
7
|
+
let threadHistoryBody;
|
|
8
|
+
let threadSessionPreviousTimestamp;
|
|
9
|
+
let threadLabel;
|
|
10
|
+
let threadStarterMedia = null;
|
|
11
|
+
if (!params.isThreadReply || !params.threadTs) {
|
|
12
|
+
return {
|
|
13
|
+
threadStarterBody,
|
|
14
|
+
threadHistoryBody,
|
|
15
|
+
threadSessionPreviousTimestamp,
|
|
16
|
+
threadLabel,
|
|
17
|
+
threadStarterMedia,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const starter = params.threadStarter;
|
|
21
|
+
if (starter?.text) {
|
|
22
|
+
threadStarterBody = starter.text;
|
|
23
|
+
const snippet = starter.text.replace(/\s+/g, " ").slice(0, 80);
|
|
24
|
+
threadLabel = `Slack thread ${params.roomLabel}${snippet ? `: ${snippet}` : ""}`;
|
|
25
|
+
if (!params.effectiveDirectMedia && starter.files && starter.files.length > 0) {
|
|
26
|
+
threadStarterMedia = await resolveSlackMedia({
|
|
27
|
+
files: starter.files,
|
|
28
|
+
token: params.ctx.botToken,
|
|
29
|
+
maxBytes: params.ctx.mediaMaxBytes,
|
|
30
|
+
});
|
|
31
|
+
if (threadStarterMedia) {
|
|
32
|
+
const starterPlaceholders = threadStarterMedia.map((item) => item.placeholder).join(", ");
|
|
33
|
+
logVerbose(`slack: hydrated thread starter file ${starterPlaceholders} from root message`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
threadLabel = `Slack thread ${params.roomLabel}`;
|
|
39
|
+
}
|
|
40
|
+
const threadInitialHistoryLimit = params.account.config?.thread?.initialHistoryLimit ?? 20;
|
|
41
|
+
threadSessionPreviousTimestamp = readSessionUpdatedAt({
|
|
42
|
+
storePath: params.storePath,
|
|
43
|
+
sessionKey: params.sessionKey,
|
|
44
|
+
});
|
|
45
|
+
if (threadInitialHistoryLimit > 0 && !threadSessionPreviousTimestamp) {
|
|
46
|
+
const threadHistory = await resolveSlackThreadHistory({
|
|
47
|
+
channelId: params.message.channel,
|
|
48
|
+
threadTs: params.threadTs,
|
|
49
|
+
client: params.ctx.app.client,
|
|
50
|
+
currentMessageTs: params.message.ts,
|
|
51
|
+
limit: threadInitialHistoryLimit,
|
|
52
|
+
});
|
|
53
|
+
if (threadHistory.length > 0) {
|
|
54
|
+
const uniqueUserIds = [
|
|
55
|
+
...new Set(threadHistory.map((item) => item.userId).filter((id) => Boolean(id))),
|
|
56
|
+
];
|
|
57
|
+
const userMap = new Map();
|
|
58
|
+
await Promise.all(uniqueUserIds.map(async (id) => {
|
|
59
|
+
const user = await params.ctx.resolveUserName(id);
|
|
60
|
+
if (user) {
|
|
61
|
+
userMap.set(id, user);
|
|
62
|
+
}
|
|
63
|
+
}));
|
|
64
|
+
const historyParts = [];
|
|
65
|
+
for (const historyMsg of threadHistory) {
|
|
66
|
+
const msgUser = historyMsg.userId ? userMap.get(historyMsg.userId) : null;
|
|
67
|
+
const msgSenderName = msgUser?.name ?? (historyMsg.botId ? `Bot (${historyMsg.botId})` : "Unknown");
|
|
68
|
+
const isBot = Boolean(historyMsg.botId);
|
|
69
|
+
const role = isBot ? "assistant" : "user";
|
|
70
|
+
const msgWithId = `${historyMsg.text}\n[slack message id: ${historyMsg.ts ?? "unknown"} channel: ${params.message.channel}]`;
|
|
71
|
+
historyParts.push(formatInboundEnvelope({
|
|
72
|
+
channel: "Slack",
|
|
73
|
+
from: `${msgSenderName} (${role})`,
|
|
74
|
+
timestamp: historyMsg.ts ? Math.round(Number(historyMsg.ts) * 1000) : undefined,
|
|
75
|
+
body: msgWithId,
|
|
76
|
+
chatType: "channel",
|
|
77
|
+
envelope: params.envelopeOptions,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
threadHistoryBody = historyParts.join("\n\n");
|
|
81
|
+
logVerbose(`slack: populated thread history with ${threadHistory.length} messages for new session`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
threadStarterBody,
|
|
86
|
+
threadHistoryBody,
|
|
87
|
+
threadSessionPreviousTimestamp,
|
|
88
|
+
threadLabel,
|
|
89
|
+
threadStarterMedia,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createSlackMonitorContext } from "../context.js";
|
|
2
|
+
export function createInboundSlackTestContext(params) {
|
|
3
|
+
return createSlackMonitorContext({
|
|
4
|
+
cfg: params.cfg,
|
|
5
|
+
accountId: "default",
|
|
6
|
+
botToken: "token",
|
|
7
|
+
app: { client: params.appClient ?? {} },
|
|
8
|
+
runtime: {},
|
|
9
|
+
botUserId: "B1",
|
|
10
|
+
teamId: "T1",
|
|
11
|
+
apiAppId: "A1",
|
|
12
|
+
historyLimit: 0,
|
|
13
|
+
sessionScope: "per-sender",
|
|
14
|
+
mainKey: "main",
|
|
15
|
+
dmEnabled: true,
|
|
16
|
+
dmPolicy: "open",
|
|
17
|
+
allowFrom: [],
|
|
18
|
+
allowNameMatching: false,
|
|
19
|
+
groupDmEnabled: true,
|
|
20
|
+
groupDmChannels: [],
|
|
21
|
+
defaultRequireMention: params.defaultRequireMention ?? true,
|
|
22
|
+
channelsConfig: params.channelsConfig,
|
|
23
|
+
groupPolicy: "open",
|
|
24
|
+
useAccessGroups: false,
|
|
25
|
+
reactionMode: "off",
|
|
26
|
+
reactionAllowlist: [],
|
|
27
|
+
replyToMode: params.replyToMode ?? "off",
|
|
28
|
+
threadHistoryScope: "thread",
|
|
29
|
+
threadInheritParent: false,
|
|
30
|
+
slashCommand: {
|
|
31
|
+
enabled: false,
|
|
32
|
+
name: "openclaw",
|
|
33
|
+
sessionPrefix: "slack:slash",
|
|
34
|
+
ephemeral: true,
|
|
35
|
+
},
|
|
36
|
+
textLimit: 4000,
|
|
37
|
+
ackReactionScope: "group-mentions",
|
|
38
|
+
typingReaction: "",
|
|
39
|
+
mediaMaxBytes: 1024,
|
|
40
|
+
removeAckAfterReply: false,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export function createSlackTestAccount(config = {}) {
|
|
44
|
+
return {
|
|
45
|
+
accountId: "default",
|
|
46
|
+
enabled: true,
|
|
47
|
+
botTokenSource: "config",
|
|
48
|
+
appTokenSource: "config",
|
|
49
|
+
userTokenSource: "none",
|
|
50
|
+
config,
|
|
51
|
+
replyToMode: config.replyToMode,
|
|
52
|
+
replyToModeByChatType: config.replyToModeByChatType,
|
|
53
|
+
dm: config.dm,
|
|
54
|
+
};
|
|
55
|
+
}
|