mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-06 06:41:08 +00:00
test(contracts): isolate action registry
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe } from "vitest";
|
||||
import { getActionContractRegistry, getPluginContractRegistry } from "./registry.js";
|
||||
import { getActionContractRegistry } from "./registry-actions.js";
|
||||
import { getPluginContractRegistry } from "./registry.js";
|
||||
import { installChannelActionsContractSuite, installChannelPluginContractSuite } from "./suites.js";
|
||||
|
||||
for (const entry of getPluginContractRegistry()) {
|
||||
|
||||
213
src/channels/plugins/contracts/registry-actions.ts
Normal file
213
src/channels/plugins/contracts/registry-actions.ts
Normal file
@@ -0,0 +1,213 @@
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import { requireBundledChannelPlugin } from "../bundled.js";
|
||||
import type { ChannelPlugin } from "../types.js";
|
||||
|
||||
type ActionsContractEntry = {
|
||||
id: string;
|
||||
plugin: Pick<ChannelPlugin, "id" | "actions">;
|
||||
unsupportedAction?: string;
|
||||
cases: Array<{
|
||||
name: string;
|
||||
cfg: OpenClawConfig;
|
||||
expectedActions: string[];
|
||||
expectedCapabilities?: string[];
|
||||
beforeTest?: () => void;
|
||||
}>;
|
||||
};
|
||||
|
||||
let actionContractRegistryCache: ActionsContractEntry[] | undefined;
|
||||
|
||||
export function getActionContractRegistry(): ActionsContractEntry[] {
|
||||
actionContractRegistryCache ??= [
|
||||
{
|
||||
id: "slack",
|
||||
plugin: requireBundledChannelPlugin("slack"),
|
||||
unsupportedAction: "poll",
|
||||
cases: [
|
||||
{
|
||||
name: "configured account exposes default Slack actions",
|
||||
cfg: {
|
||||
channels: {
|
||||
slack: {
|
||||
botToken: "xoxb-test",
|
||||
appToken: "xapp-test",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [
|
||||
"send",
|
||||
"react",
|
||||
"reactions",
|
||||
"read",
|
||||
"edit",
|
||||
"delete",
|
||||
"download-file",
|
||||
"upload-file",
|
||||
"pin",
|
||||
"unpin",
|
||||
"list-pins",
|
||||
"member-info",
|
||||
"emoji-list",
|
||||
],
|
||||
expectedCapabilities: ["blocks"],
|
||||
},
|
||||
{
|
||||
name: "interactive replies add the shared interactive capability",
|
||||
cfg: {
|
||||
channels: {
|
||||
slack: {
|
||||
botToken: "xoxb-test",
|
||||
appToken: "xapp-test",
|
||||
capabilities: {
|
||||
interactiveReplies: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [
|
||||
"send",
|
||||
"react",
|
||||
"reactions",
|
||||
"read",
|
||||
"edit",
|
||||
"delete",
|
||||
"download-file",
|
||||
"upload-file",
|
||||
"pin",
|
||||
"unpin",
|
||||
"list-pins",
|
||||
"member-info",
|
||||
"emoji-list",
|
||||
],
|
||||
expectedCapabilities: ["blocks", "interactive"],
|
||||
},
|
||||
{
|
||||
name: "missing tokens disables the actions surface",
|
||||
cfg: {
|
||||
channels: {
|
||||
slack: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [],
|
||||
expectedCapabilities: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "mattermost",
|
||||
plugin: requireBundledChannelPlugin("mattermost"),
|
||||
unsupportedAction: "poll",
|
||||
cases: [
|
||||
{
|
||||
name: "configured account exposes send and react",
|
||||
cfg: {
|
||||
channels: {
|
||||
mattermost: {
|
||||
enabled: true,
|
||||
botToken: "test-token",
|
||||
baseUrl: "https://chat.example.com",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: ["send", "react"],
|
||||
expectedCapabilities: ["buttons"],
|
||||
},
|
||||
{
|
||||
name: "reactions can be disabled while send stays available",
|
||||
cfg: {
|
||||
channels: {
|
||||
mattermost: {
|
||||
enabled: true,
|
||||
botToken: "test-token",
|
||||
baseUrl: "https://chat.example.com",
|
||||
actions: { reactions: false },
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: ["send"],
|
||||
expectedCapabilities: ["buttons"],
|
||||
},
|
||||
{
|
||||
name: "missing bot credentials disables the actions surface",
|
||||
cfg: {
|
||||
channels: {
|
||||
mattermost: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [],
|
||||
expectedCapabilities: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "telegram",
|
||||
plugin: requireBundledChannelPlugin("telegram"),
|
||||
cases: [
|
||||
{
|
||||
name: "exposes configured Telegram actions and capabilities",
|
||||
cfg: {
|
||||
channels: {
|
||||
telegram: {
|
||||
botToken: "123:telegram-test-token",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [
|
||||
"send",
|
||||
"poll",
|
||||
"react",
|
||||
"delete",
|
||||
"edit",
|
||||
"topic-create",
|
||||
"topic-edit",
|
||||
],
|
||||
expectedCapabilities: ["interactive", "buttons"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "discord",
|
||||
plugin: requireBundledChannelPlugin("discord"),
|
||||
cases: [
|
||||
{
|
||||
name: "describes configured Discord actions and capabilities",
|
||||
cfg: {
|
||||
channels: {
|
||||
discord: {
|
||||
token: "Bot token-main",
|
||||
actions: {
|
||||
polls: true,
|
||||
reactions: true,
|
||||
permissions: false,
|
||||
messages: false,
|
||||
pins: false,
|
||||
threads: false,
|
||||
search: false,
|
||||
stickers: false,
|
||||
memberInfo: false,
|
||||
roleInfo: false,
|
||||
emojiUploads: false,
|
||||
stickerUploads: false,
|
||||
channelInfo: false,
|
||||
channels: false,
|
||||
voiceStatus: false,
|
||||
events: false,
|
||||
roles: false,
|
||||
moderation: false,
|
||||
presence: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: ["send", "poll", "react", "reactions", "emoji-list"],
|
||||
expectedCapabilities: ["interactive", "components"],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
return actionContractRegistryCache;
|
||||
}
|
||||
@@ -1,15 +1,10 @@
|
||||
import { vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import {
|
||||
listLineAccountIds,
|
||||
resolveDefaultLineAccountId,
|
||||
resolveLineAccount,
|
||||
} from "../../../plugin-sdk/line.js";
|
||||
import {
|
||||
listBundledChannelPlugins,
|
||||
requireBundledChannelPlugin,
|
||||
setBundledChannelRuntime,
|
||||
} from "../bundled.js";
|
||||
import { listBundledChannelPlugins, setBundledChannelRuntime } from "../bundled.js";
|
||||
import type { ChannelPlugin } from "../types.js";
|
||||
import { channelPluginSurfaceKeys, type ChannelPluginSurface } from "./manifest.js";
|
||||
|
||||
@@ -22,19 +17,6 @@ type PluginContractEntry = {
|
||||
plugin: Pick<ChannelPlugin, "id" | "meta" | "capabilities" | "config">;
|
||||
};
|
||||
|
||||
type ActionsContractEntry = {
|
||||
id: string;
|
||||
plugin: Pick<ChannelPlugin, "id" | "actions">;
|
||||
unsupportedAction?: string;
|
||||
cases: Array<{
|
||||
name: string;
|
||||
cfg: OpenClawConfig;
|
||||
expectedActions: string[];
|
||||
expectedCapabilities?: string[];
|
||||
beforeTest?: () => void;
|
||||
}>;
|
||||
};
|
||||
|
||||
type SurfaceContractEntry = {
|
||||
id: string;
|
||||
plugin: Pick<
|
||||
@@ -93,7 +75,6 @@ vi.mock(buildBundledPluginModuleId("matrix", "runtime-api.js"), async () => {
|
||||
});
|
||||
|
||||
let pluginContractRegistryCache: PluginContractEntry[] | undefined;
|
||||
let actionContractRegistryCache: ActionsContractEntry[] | undefined;
|
||||
let surfaceContractRegistryCache: SurfaceContractEntry[] | undefined;
|
||||
let threadingContractRegistryCache: ThreadingContractEntry[] | undefined;
|
||||
let directoryContractRegistryCache: DirectoryContractEntry[] | undefined;
|
||||
@@ -106,201 +87,6 @@ export function getPluginContractRegistry(): PluginContractEntry[] {
|
||||
return pluginContractRegistryCache;
|
||||
}
|
||||
|
||||
export function getActionContractRegistry(): ActionsContractEntry[] {
|
||||
actionContractRegistryCache ??= [
|
||||
{
|
||||
id: "slack",
|
||||
plugin: requireBundledChannelPlugin("slack"),
|
||||
unsupportedAction: "poll",
|
||||
cases: [
|
||||
{
|
||||
name: "configured account exposes default Slack actions",
|
||||
cfg: {
|
||||
channels: {
|
||||
slack: {
|
||||
botToken: "xoxb-test",
|
||||
appToken: "xapp-test",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [
|
||||
"send",
|
||||
"react",
|
||||
"reactions",
|
||||
"read",
|
||||
"edit",
|
||||
"delete",
|
||||
"download-file",
|
||||
"upload-file",
|
||||
"pin",
|
||||
"unpin",
|
||||
"list-pins",
|
||||
"member-info",
|
||||
"emoji-list",
|
||||
],
|
||||
expectedCapabilities: ["blocks"],
|
||||
},
|
||||
{
|
||||
name: "interactive replies add the shared interactive capability",
|
||||
cfg: {
|
||||
channels: {
|
||||
slack: {
|
||||
botToken: "xoxb-test",
|
||||
appToken: "xapp-test",
|
||||
capabilities: {
|
||||
interactiveReplies: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [
|
||||
"send",
|
||||
"react",
|
||||
"reactions",
|
||||
"read",
|
||||
"edit",
|
||||
"delete",
|
||||
"download-file",
|
||||
"upload-file",
|
||||
"pin",
|
||||
"unpin",
|
||||
"list-pins",
|
||||
"member-info",
|
||||
"emoji-list",
|
||||
],
|
||||
expectedCapabilities: ["blocks", "interactive"],
|
||||
},
|
||||
{
|
||||
name: "missing tokens disables the actions surface",
|
||||
cfg: {
|
||||
channels: {
|
||||
slack: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [],
|
||||
expectedCapabilities: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "mattermost",
|
||||
plugin: requireBundledChannelPlugin("mattermost"),
|
||||
unsupportedAction: "poll",
|
||||
cases: [
|
||||
{
|
||||
name: "configured account exposes send and react",
|
||||
cfg: {
|
||||
channels: {
|
||||
mattermost: {
|
||||
enabled: true,
|
||||
botToken: "test-token",
|
||||
baseUrl: "https://chat.example.com",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: ["send", "react"],
|
||||
expectedCapabilities: ["buttons"],
|
||||
},
|
||||
{
|
||||
name: "reactions can be disabled while send stays available",
|
||||
cfg: {
|
||||
channels: {
|
||||
mattermost: {
|
||||
enabled: true,
|
||||
botToken: "test-token",
|
||||
baseUrl: "https://chat.example.com",
|
||||
actions: { reactions: false },
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: ["send"],
|
||||
expectedCapabilities: ["buttons"],
|
||||
},
|
||||
{
|
||||
name: "missing bot credentials disables the actions surface",
|
||||
cfg: {
|
||||
channels: {
|
||||
mattermost: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [],
|
||||
expectedCapabilities: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "telegram",
|
||||
plugin: requireBundledChannelPlugin("telegram"),
|
||||
cases: [
|
||||
{
|
||||
name: "exposes configured Telegram actions and capabilities",
|
||||
cfg: {
|
||||
channels: {
|
||||
telegram: {
|
||||
botToken: "123:telegram-test-token",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [
|
||||
"send",
|
||||
"poll",
|
||||
"react",
|
||||
"delete",
|
||||
"edit",
|
||||
"topic-create",
|
||||
"topic-edit",
|
||||
],
|
||||
expectedCapabilities: ["interactive", "buttons"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "discord",
|
||||
plugin: requireBundledChannelPlugin("discord"),
|
||||
cases: [
|
||||
{
|
||||
name: "describes configured Discord actions and capabilities",
|
||||
cfg: {
|
||||
channels: {
|
||||
discord: {
|
||||
token: "Bot token-main",
|
||||
actions: {
|
||||
polls: true,
|
||||
reactions: true,
|
||||
permissions: false,
|
||||
messages: false,
|
||||
pins: false,
|
||||
threads: false,
|
||||
search: false,
|
||||
stickers: false,
|
||||
memberInfo: false,
|
||||
roleInfo: false,
|
||||
emojiUploads: false,
|
||||
stickerUploads: false,
|
||||
channelInfo: false,
|
||||
channels: false,
|
||||
voiceStatus: false,
|
||||
events: false,
|
||||
roles: false,
|
||||
moderation: false,
|
||||
presence: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: ["send", "poll", "react", "reactions", "emoji-list"],
|
||||
expectedCapabilities: ["interactive", "components"],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
return actionContractRegistryCache;
|
||||
}
|
||||
|
||||
export function getSurfaceContractRegistry(): SurfaceContractEntry[] {
|
||||
surfaceContractRegistryCache ??= listBundledChannelPlugins().map((plugin) => ({
|
||||
id: plugin.id,
|
||||
|
||||
Reference in New Issue
Block a user