From 7d5a90e5896a6c741fa68351e8a124547f4d2bde Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 17 Mar 2026 14:58:22 -0700 Subject: [PATCH] Plugins: add shape compatibility matrix --- src/plugins/contracts/shape.contract.test.ts | 154 +++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/plugins/contracts/shape.contract.test.ts diff --git a/src/plugins/contracts/shape.contract.test.ts b/src/plugins/contracts/shape.contract.test.ts new file mode 100644 index 00000000000..e94961f7e01 --- /dev/null +++ b/src/plugins/contracts/shape.contract.test.ts @@ -0,0 +1,154 @@ +import { describe, expect, it } from "vitest"; +import type { OpenClawConfig } from "../../config/config.js"; +import { createPluginRegistry, type PluginRecord } from "../registry.js"; +import type { PluginRuntime } from "../runtime/types.js"; +import { buildAllPluginInspectReports } from "../status.js"; +import type { OpenClawPluginApi } from "../types.js"; + +function createPluginRecord(id: string, name: string): PluginRecord { + return { + id, + name, + source: `/virtual/${id}/index.ts`, + origin: "workspace", + enabled: true, + status: "loaded", + toolNames: [], + hookNames: [], + channelIds: [], + providerIds: [], + speechProviderIds: [], + mediaUnderstandingProviderIds: [], + imageGenerationProviderIds: [], + webSearchProviderIds: [], + gatewayMethods: [], + cliCommands: [], + services: [], + commands: [], + httpRoutes: 0, + hookCount: 0, + configSchema: false, + }; +} + +function registerTestPlugin(params: { + registry: ReturnType; + config: OpenClawConfig; + record: PluginRecord; + register(api: OpenClawPluginApi): void; +}) { + params.registry.registry.plugins.push(params.record); + params.register( + params.registry.createApi(params.record, { + config: params.config, + }), + ); +} + +describe("plugin shape compatibility matrix", () => { + it("keeps legacy hook-only, plain capability, and hybrid capability shapes explicit", () => { + const config = {} as OpenClawConfig; + const registry = createPluginRegistry({ + logger: { + info() {}, + warn() {}, + error() {}, + debug() {}, + }, + runtime: {} as PluginRuntime, + }); + + registerTestPlugin({ + registry, + config, + record: createPluginRecord("lca-legacy", "LCA Legacy"), + register(api) { + api.on("before_agent_start", () => ({ + prependContext: "legacy", + })); + }, + }); + + registerTestPlugin({ + registry, + config, + record: createPluginRecord("plain-provider", "Plain Provider"), + register(api) { + api.registerProvider({ + id: "plain-provider", + label: "Plain Provider", + auth: [], + }); + }, + }); + + registerTestPlugin({ + registry, + config, + record: createPluginRecord("hybrid-company", "Hybrid Company"), + register(api) { + api.registerProvider({ + id: "hybrid-company", + label: "Hybrid Company", + auth: [], + }); + api.registerWebSearchProvider({ + id: "hybrid-search", + label: "Hybrid Search", + hint: "Search the web", + envVars: ["HYBRID_SEARCH_KEY"], + placeholder: "hsk_...", + signupUrl: "https://example.com/signup", + getCredentialValue: () => "hsk-test", + setCredentialValue(searchConfigTarget, value) { + searchConfigTarget.apiKey = value; + }, + createTool: () => ({ + description: "Hybrid search", + parameters: {}, + execute: async () => ({}), + }), + }); + }, + }); + + const inspect = buildAllPluginInspectReports({ + config, + report: { + workspaceDir: "/virtual-workspace", + ...registry.registry, + }, + }); + + expect( + inspect.map((entry) => ({ + id: entry.plugin.id, + shape: entry.shape, + capabilityMode: entry.capabilityMode, + })), + ).toEqual([ + { + id: "lca-legacy", + shape: "hook-only", + capabilityMode: "none", + }, + { + id: "plain-provider", + shape: "plain-capability", + capabilityMode: "plain", + }, + { + id: "hybrid-company", + shape: "hybrid-capability", + capabilityMode: "hybrid", + }, + ]); + + expect(inspect[0]?.usesLegacyBeforeAgentStart).toBe(true); + expect(inspect[1]?.capabilities.map((entry) => entry.kind)).toEqual(["text-inference"]); + expect(inspect[2]?.capabilities.map((entry) => entry.kind)).toEqual([ + "text-inference", + "web-search", + ]); + }); +});