diff --git a/extensions/feishu/src/channel.ts b/extensions/feishu/src/channel.ts index ded06f97f53..da5cd8e4382 100644 --- a/extensions/feishu/src/channel.ts +++ b/extensions/feishu/src/channel.ts @@ -1,8 +1,14 @@ import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from"; import { mapAllowFromEntries } from "openclaw/plugin-sdk/channel-config-helpers"; import { collectAllowlistProviderRestrictSendersWarnings } from "openclaw/plugin-sdk/channel-policy"; -import { createMessageToolCardSchema } from "openclaw/plugin-sdk/channel-runtime"; -import type { ChannelMessageActionAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import { + createLegacyMessageToolDiscoveryMethods, + createMessageToolCardSchema, +} from "openclaw/plugin-sdk/channel-runtime"; +import type { + ChannelMessageActionAdapter, + ChannelMessageToolDiscovery, +} from "openclaw/plugin-sdk/channel-runtime"; import type { ChannelMeta, ChannelPlugin, ClawdbotConfig } from "openclaw/plugin-sdk/feishu"; import { buildChannelConfigSchema, @@ -49,6 +55,56 @@ const loadFeishuChannelRuntime = createLazyRuntimeNamedExport( "feishuChannelRuntime", ); +function describeFeishuMessageTool({ + cfg, +}: Parameters< + NonNullable +>[0]): ChannelMessageToolDiscovery { + const enabled = + cfg.channels?.feishu?.enabled !== false && + Boolean(resolveFeishuCredentials(cfg.channels?.feishu as FeishuConfig | undefined)); + if (listEnabledFeishuAccounts(cfg).length === 0) { + return { + actions: [], + capabilities: enabled ? ["cards"] : [], + schema: enabled + ? { + properties: { + card: createMessageToolCardSchema(), + }, + } + : null, + }; + } + const actions = new Set([ + "send", + "read", + "edit", + "thread-reply", + "pin", + "list-pins", + "unpin", + "member-info", + "channel-info", + "channel-list", + ]); + if (areAnyFeishuReactionActionsEnabled(cfg)) { + actions.add("react"); + actions.add("reactions"); + } + return { + actions: Array.from(actions), + capabilities: enabled ? ["cards"] : [], + schema: enabled + ? { + properties: { + card: createMessageToolCardSchema(), + }, + } + : null, + }; +} + function setFeishuNamedAccountEnabled( cfg: ClawdbotConfig, accountId: string, @@ -396,53 +452,8 @@ export const feishuPlugin: ChannelPlugin = { formatAllowFrom: ({ allowFrom }) => formatAllowFromLowercase({ allowFrom }), }, actions: { - describeMessageTool: ({ - cfg, - }: Parameters>[0]) => { - const enabled = - cfg.channels?.feishu?.enabled !== false && - Boolean(resolveFeishuCredentials(cfg.channels?.feishu as FeishuConfig | undefined)); - if (listEnabledFeishuAccounts(cfg).length === 0) { - return { - actions: [], - capabilities: enabled ? ["cards"] : [], - schema: enabled - ? { - properties: { - card: createMessageToolCardSchema(), - }, - } - : null, - }; - } - const actions = new Set([ - "send", - "read", - "edit", - "thread-reply", - "pin", - "list-pins", - "unpin", - "member-info", - "channel-info", - "channel-list", - ]); - if (areAnyFeishuReactionActionsEnabled(cfg)) { - actions.add("react"); - actions.add("reactions"); - } - return { - actions: Array.from(actions), - capabilities: enabled ? ["cards"] : [], - schema: enabled - ? { - properties: { - card: createMessageToolCardSchema(), - }, - } - : null, - }; - }, + describeMessageTool: describeFeishuMessageTool, + ...createLegacyMessageToolDiscoveryMethods(describeFeishuMessageTool), handleAction: async (ctx) => { const account = resolveFeishuAccount({ cfg: ctx.cfg, accountId: ctx.accountId ?? undefined }); if ( diff --git a/extensions/mattermost/src/channel.ts b/extensions/mattermost/src/channel.ts index 90c7b718639..5688e13d8ae 100644 --- a/extensions/mattermost/src/channel.ts +++ b/extensions/mattermost/src/channel.ts @@ -4,7 +4,11 @@ import { buildAccountScopedDmSecurityPolicy, collectAllowlistProviderRestrictSendersWarnings, } from "openclaw/plugin-sdk/channel-policy"; -import { createMessageToolButtonsSchema } from "openclaw/plugin-sdk/channel-runtime"; +import { + createLegacyMessageToolDiscoveryMethods, + createMessageToolButtonsSchema, +} from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelMessageToolDiscovery } from "openclaw/plugin-sdk/channel-runtime"; import { buildComputedAccountStatusSnapshot, buildChannelConfigSchema, @@ -42,46 +46,49 @@ import { getMattermostRuntime } from "./runtime.js"; import { mattermostSetupAdapter } from "./setup-core.js"; import { mattermostSetupWizard } from "./setup-surface.js"; +function describeMattermostMessageTool({ + cfg, +}: Parameters< + NonNullable +>[0]): ChannelMessageToolDiscovery { + const enabledAccounts = listMattermostAccountIds(cfg) + .map((accountId) => resolveMattermostAccount({ cfg, accountId })) + .filter((account) => account.enabled) + .filter((account) => Boolean(account.botToken?.trim() && account.baseUrl?.trim())); + + const actions: ChannelMessageActionName[] = []; + + if (enabledAccounts.length > 0) { + actions.push("send"); + } + + const actionsConfig = cfg.channels?.mattermost?.actions as { reactions?: boolean } | undefined; + const baseReactions = actionsConfig?.reactions; + const hasReactionCapableAccount = enabledAccounts.some((account) => { + const accountActions = account.config.actions as { reactions?: boolean } | undefined; + return (accountActions?.reactions ?? baseReactions ?? true) !== false; + }); + if (hasReactionCapableAccount) { + actions.push("react"); + } + + return { + actions, + capabilities: enabledAccounts.length > 0 ? ["buttons"] : [], + schema: + enabledAccounts.length > 0 + ? { + properties: { + buttons: createMessageToolButtonsSchema(), + }, + } + : null, + }; +} + const mattermostMessageActions: ChannelMessageActionAdapter = { - describeMessageTool: ({ - cfg, - }: Parameters>[0]) => { - const enabledAccounts = listMattermostAccountIds(cfg) - .map((accountId) => resolveMattermostAccount({ cfg, accountId })) - .filter((account) => account.enabled) - .filter((account) => Boolean(account.botToken?.trim() && account.baseUrl?.trim())); - - const actions: ChannelMessageActionName[] = []; - - // Send (buttons) is available whenever there's at least one enabled account - if (enabledAccounts.length > 0) { - actions.push("send"); - } - - // React requires per-account reactions config check - const actionsConfig = cfg.channels?.mattermost?.actions as { reactions?: boolean } | undefined; - const baseReactions = actionsConfig?.reactions; - const hasReactionCapableAccount = enabledAccounts.some((account) => { - const accountActions = account.config.actions as { reactions?: boolean } | undefined; - return (accountActions?.reactions ?? baseReactions ?? true) !== false; - }); - if (hasReactionCapableAccount) { - actions.push("react"); - } - - return { - actions, - capabilities: enabledAccounts.length > 0 ? ["buttons"] : [], - schema: - enabledAccounts.length > 0 - ? { - properties: { - buttons: createMessageToolButtonsSchema(), - }, - } - : null, - }; - }, + describeMessageTool: describeMattermostMessageTool, + ...createLegacyMessageToolDiscoveryMethods(describeMattermostMessageTool), supportsAction: ({ action }) => { return action === "send" || action === "react"; }, diff --git a/extensions/msteams/src/channel.ts b/extensions/msteams/src/channel.ts index 827507c24f2..7458389efb1 100644 --- a/extensions/msteams/src/channel.ts +++ b/extensions/msteams/src/channel.ts @@ -1,7 +1,13 @@ import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from"; import { collectAllowlistProviderRestrictSendersWarnings } from "openclaw/plugin-sdk/channel-policy"; -import { createMessageToolCardSchema } from "openclaw/plugin-sdk/channel-runtime"; -import type { ChannelMessageActionAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import { + createLegacyMessageToolDiscoveryMethods, + createMessageToolCardSchema, +} from "openclaw/plugin-sdk/channel-runtime"; +import type { + ChannelMessageActionAdapter, + ChannelMessageToolDiscovery, +} from "openclaw/plugin-sdk/channel-runtime"; import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime"; import type { ChannelMessageActionName, @@ -64,6 +70,27 @@ const loadMSTeamsChannelRuntime = createLazyRuntimeNamedExport( "msTeamsChannelRuntime", ); +function describeMSTeamsMessageTool({ + cfg, +}: Parameters< + NonNullable +>[0]): ChannelMessageToolDiscovery { + const enabled = + cfg.channels?.msteams?.enabled !== false && + Boolean(resolveMSTeamsCredentials(cfg.channels?.msteams)); + return { + actions: enabled ? (["poll"] satisfies ChannelMessageActionName[]) : [], + capabilities: enabled ? ["cards"] : [], + schema: enabled + ? { + properties: { + card: createMessageToolCardSchema(), + }, + } + : null, + }; +} + export const msteamsPlugin: ChannelPlugin = { id: "msteams", meta: { @@ -370,24 +397,8 @@ export const msteamsPlugin: ChannelPlugin = { }, }, actions: { - describeMessageTool: ({ - cfg, - }: Parameters>[0]) => { - const enabled = - cfg.channels?.msteams?.enabled !== false && - Boolean(resolveMSTeamsCredentials(cfg.channels?.msteams)); - return { - actions: enabled ? (["poll"] satisfies ChannelMessageActionName[]) : [], - capabilities: enabled ? ["cards"] : [], - schema: enabled - ? { - properties: { - card: createMessageToolCardSchema(), - }, - } - : null, - }; - }, + describeMessageTool: describeMSTeamsMessageTool, + ...createLegacyMessageToolDiscoveryMethods(describeMSTeamsMessageTool), handleAction: async (ctx) => { // Handle send action with card parameter if (ctx.action === "send" && ctx.params.card) { diff --git a/src/channels/plugins/message-tool-legacy.ts b/src/channels/plugins/message-tool-legacy.ts new file mode 100644 index 00000000000..2c74213439f --- /dev/null +++ b/src/channels/plugins/message-tool-legacy.ts @@ -0,0 +1,13 @@ +import type { ChannelMessageActionAdapter } from "./types.js"; + +export function createLegacyMessageToolDiscoveryMethods( + describeMessageTool: NonNullable, +): Pick { + const describe = (ctx: Parameters[0]) => + describeMessageTool(ctx) ?? null; + return { + listActions: (ctx) => [...(describe(ctx)?.actions ?? [])], + getCapabilities: (ctx) => [...(describe(ctx)?.capabilities ?? [])], + getToolSchema: (ctx) => describe(ctx)?.schema ?? null, + }; +} diff --git a/src/plugin-sdk/channel-runtime.ts b/src/plugin-sdk/channel-runtime.ts index 089e10609af..1460acba87d 100644 --- a/src/plugin-sdk/channel-runtime.ts +++ b/src/plugin-sdk/channel-runtime.ts @@ -34,6 +34,7 @@ export type * from "../channels/plugins/types.js"; export * from "../channels/plugins/config-writes.js"; export * from "../channels/plugins/directory-config.js"; export * from "../channels/plugins/media-payload.js"; +export * from "../channels/plugins/message-tool-legacy.js"; export * from "../channels/plugins/message-tool-schema.js"; export * from "../channels/plugins/normalize/signal.js"; export * from "../channels/plugins/normalize/whatsapp.js";