refactor(slack): share plugin base config

This commit is contained in:
Peter Steinberger
2026-03-17 04:55:07 +00:00
parent 21bc5a90ec
commit f3da292097
2 changed files with 17 additions and 99 deletions

View File

@@ -1,57 +1,12 @@
import {
buildChannelConfigSchema,
getChatChannelMeta,
SlackConfigSchema,
type ChannelPlugin,
} from "openclaw/plugin-sdk/slack";
import { type ChannelPlugin } from "openclaw/plugin-sdk/slack";
import { type ResolvedSlackAccount } from "./accounts.js";
import { isSlackInteractiveRepliesEnabled } from "./interactive-replies.js";
import { slackSetupAdapter } from "./setup-core.js";
import { slackSetupWizard } from "./setup-surface.js";
import { isSlackPluginAccountConfigured, slackConfigAccessors, slackConfigBase } from "./shared.js";
import { createSlackPluginBase } from "./shared.js";
export const slackSetupPlugin: ChannelPlugin<ResolvedSlackAccount> = {
id: "slack",
meta: {
...getChatChannelMeta("slack"),
preferSessionLookupForAnnounceTarget: true,
},
setupWizard: slackSetupWizard,
capabilities: {
chatTypes: ["direct", "channel", "thread"],
reactions: true,
threads: true,
media: true,
nativeCommands: true,
},
agentPrompt: {
messageToolHints: ({ cfg, accountId }) =>
isSlackInteractiveRepliesEnabled({ cfg, accountId })
? [
"- Slack interactive replies: use `[[slack_buttons: Label:value, Other:other]]` to add action buttons that route clicks back as Slack interaction system events.",
"- Slack selects: use `[[slack_select: Placeholder | Label:value, Other:other]]` to add a static select menu that routes the chosen value back as a Slack interaction system event.",
]
: [
"- Slack interactive replies are disabled. If needed, ask to set `channels.slack.capabilities.interactiveReplies=true` (or the same under `channels.slack.accounts.<account>.capabilities`).",
],
},
streaming: {
blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
},
reload: { configPrefixes: ["channels.slack"] },
configSchema: buildChannelConfigSchema(SlackConfigSchema),
config: {
...slackConfigBase,
isConfigured: (account) => isSlackPluginAccountConfigured(account),
describeAccount: (account) => ({
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: isSlackPluginAccountConfigured(account),
botTokenSource: account.botTokenSource,
appTokenSource: account.appTokenSource,
}),
...slackConfigAccessors,
},
setup: slackSetupAdapter,
...createSlackPluginBase({
setupWizard: slackSetupWizard,
setup: slackSetupAdapter,
}),
};

View File

@@ -15,9 +15,7 @@ import {
} from "openclaw/plugin-sdk/core";
import {
buildComputedAccountStatusSnapshot,
buildChannelConfigSchema,
DEFAULT_ACCOUNT_ID,
getChatChannelMeta,
listSlackDirectoryGroupsFromConfig,
listSlackDirectoryPeersFromConfig,
looksLikeSlackTargetId,
@@ -27,7 +25,6 @@ import {
resolveConfiguredFromRequiredCredentialStatuses,
resolveSlackGroupRequireMention,
resolveSlackGroupToolPolicy,
SlackConfigSchema,
type ChannelPlugin,
type OpenClawConfig,
} from "openclaw/plugin-sdk/slack";
@@ -50,11 +47,15 @@ import { getSlackRuntime } from "./runtime.js";
import { fetchSlackScopes } from "./scopes.js";
import { slackSetupAdapter } from "./setup-core.js";
import { slackSetupWizard } from "./setup-surface.js";
import { isSlackPluginAccountConfigured, slackConfigAccessors, slackConfigBase } from "./shared.js";
import {
createSlackPluginBase,
isSlackPluginAccountConfigured,
slackConfigAccessors,
SLACK_CHANNEL,
} from "./shared.js";
import { parseSlackTarget } from "./targets.js";
import { buildSlackThreadingToolContext } from "./threading-tool-context.js";
const meta = getChatChannelMeta("slack");
const SLACK_CHANNEL_TYPE_CACHE = new Map<string, "channel" | "group" | "dm" | "unknown">();
// Select the appropriate Slack token for read/write operations.
@@ -329,12 +330,10 @@ async function resolveSlackAllowlistNames(params: {
}
export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
id: "slack",
meta: {
...meta,
preferSessionLookupForAnnounceTarget: true,
},
setupWizard: slackSetupWizard,
...createSlackPluginBase({
setupWizard: slackSetupWizard,
setup: slackSetupAdapter,
}),
pairing: {
idLabel: "slackUserId",
normalizeAllowEntry: (entry) => entry.replace(/^(slack|user):/i, ""),
@@ -363,42 +362,6 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
}
},
},
capabilities: {
chatTypes: ["direct", "channel", "thread"],
reactions: true,
threads: true,
media: true,
nativeCommands: true,
},
agentPrompt: {
messageToolHints: ({ cfg, accountId }) =>
isSlackInteractiveRepliesEnabled({ cfg, accountId })
? [
"- Slack interactive replies: use `[[slack_buttons: Label:value, Other:other]]` to add action buttons that route clicks back as Slack interaction system events.",
"- Slack selects: use `[[slack_select: Placeholder | Label:value, Other:other]]` to add a static select menu that routes the chosen value back as a Slack interaction system event.",
]
: [
"- Slack interactive replies are disabled. If needed, ask to set `channels.slack.capabilities.interactiveReplies=true` (or the same under `channels.slack.accounts.<account>.capabilities`).",
],
},
streaming: {
blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 },
},
reload: { configPrefixes: ["channels.slack"] },
configSchema: buildChannelConfigSchema(SlackConfigSchema),
config: {
...slackConfigBase,
isConfigured: (account) => isSlackPluginAccountConfigured(account),
describeAccount: (account) => ({
accountId: account.accountId,
name: account.name,
enabled: account.enabled,
configured: isSlackPluginAccountConfigured(account),
botTokenSource: account.botTokenSource,
appTokenSource: account.appTokenSource,
}),
...slackConfigAccessors,
},
allowlist: {
supportsScope: ({ scope }) => scope === "dm",
readConfig: ({ cfg, accountId }) =>
@@ -561,7 +524,7 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
extractToolSend: ({ args }) => extractSlackToolSend(args),
handleAction: async (ctx) =>
await handleSlackMessageAction({
providerId: meta.id,
providerId: SLACK_CHANNEL,
ctx,
includeReadThreadId: true,
invoke: async (action, cfg, toolContext) =>