mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-17 04:50:51 +00:00
refactor(plugins): derive compat provider ids from manifests
This commit is contained in:
@@ -36,11 +36,6 @@ import {
|
||||
type OpenClawConfig,
|
||||
type ResolvedDiscordAccount,
|
||||
} from "openclaw/plugin-sdk/discord";
|
||||
import {
|
||||
buildAgentSessionKey,
|
||||
resolveThreadSessionKeys,
|
||||
type RoutePeer,
|
||||
} from "openclaw/plugin-sdk/routing";
|
||||
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
|
||||
import { normalizeMessageChannel } from "../../../src/utils/message-channel.js";
|
||||
import {
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
type ChannelPlugin,
|
||||
type ResolvedIMessageAccount,
|
||||
} from "openclaw/plugin-sdk/imessage";
|
||||
import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/routing";
|
||||
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
|
||||
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
|
||||
import { getIMessageRuntime } from "./runtime.js";
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
createScopedAccountConfigAccessors,
|
||||
collectAllowlistProviderRestrictSendersWarnings,
|
||||
} from "openclaw/plugin-sdk/compat";
|
||||
import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/routing";
|
||||
import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/core";
|
||||
import {
|
||||
buildBaseAccountStatusSnapshot,
|
||||
buildBaseChannelStatusSummary,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
buildAgentSessionKey,
|
||||
resolveThreadSessionKeys,
|
||||
type RoutePeer,
|
||||
} from "openclaw/plugin-sdk/routing";
|
||||
} from "openclaw/plugin-sdk/core";
|
||||
import {
|
||||
buildComputedAccountStatusSnapshot,
|
||||
buildChannelConfigSchema,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
buildAgentSessionKey,
|
||||
resolveThreadSessionKeys,
|
||||
type RoutePeer,
|
||||
} from "openclaw/plugin-sdk/routing";
|
||||
} from "openclaw/plugin-sdk/core";
|
||||
import {
|
||||
buildChannelConfigSchema,
|
||||
buildTokenChannelStatusSummary,
|
||||
|
||||
@@ -5,11 +5,16 @@ import { discoverOpenClawPlugins } from "../src/plugins/discovery.js";
|
||||
// Match exact monolithic-root specifier in any code path:
|
||||
// imports/exports, require/dynamic import, and test mocks (vi.mock/jest.mock).
|
||||
const ROOT_IMPORT_PATTERN = /["']openclaw\/plugin-sdk["']/;
|
||||
const LEGACY_ROUTING_IMPORT_PATTERN = /["']openclaw\/plugin-sdk\/routing["']/;
|
||||
|
||||
function hasMonolithicRootImport(content: string): boolean {
|
||||
return ROOT_IMPORT_PATTERN.test(content);
|
||||
}
|
||||
|
||||
function hasLegacyRoutingImport(content: string): boolean {
|
||||
return LEGACY_ROUTING_IMPORT_PATTERN.test(content);
|
||||
}
|
||||
|
||||
function isSourceFile(filePath: string): boolean {
|
||||
if (filePath.endsWith(".d.ts")) {
|
||||
return false;
|
||||
@@ -77,7 +82,8 @@ function main() {
|
||||
filesToCheck.add(sharedFile);
|
||||
}
|
||||
|
||||
const offenders: string[] = [];
|
||||
const monolithicOffenders: string[] = [];
|
||||
const legacyRoutingOffenders: string[] = [];
|
||||
for (const entryFile of filesToCheck) {
|
||||
let content = "";
|
||||
try {
|
||||
@@ -86,19 +92,35 @@ function main() {
|
||||
continue;
|
||||
}
|
||||
if (hasMonolithicRootImport(content)) {
|
||||
offenders.push(entryFile);
|
||||
monolithicOffenders.push(entryFile);
|
||||
}
|
||||
if (hasLegacyRoutingImport(content)) {
|
||||
legacyRoutingOffenders.push(entryFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (offenders.length > 0) {
|
||||
console.error("Bundled plugin source files must not import monolithic openclaw/plugin-sdk.");
|
||||
for (const file of offenders.toSorted()) {
|
||||
const relative = path.relative(process.cwd(), file) || file;
|
||||
console.error(`- ${relative}`);
|
||||
if (monolithicOffenders.length > 0 || legacyRoutingOffenders.length > 0) {
|
||||
if (monolithicOffenders.length > 0) {
|
||||
console.error("Bundled plugin source files must not import monolithic openclaw/plugin-sdk.");
|
||||
for (const file of monolithicOffenders.toSorted()) {
|
||||
const relative = path.relative(process.cwd(), file) || file;
|
||||
console.error(`- ${relative}`);
|
||||
}
|
||||
}
|
||||
if (legacyRoutingOffenders.length > 0) {
|
||||
console.error(
|
||||
"Bundled plugin source files must not import legacy openclaw/plugin-sdk/routing.",
|
||||
);
|
||||
for (const file of legacyRoutingOffenders.toSorted()) {
|
||||
const relative = path.relative(process.cwd(), file) || file;
|
||||
console.error(`- ${relative}`);
|
||||
}
|
||||
}
|
||||
if (monolithicOffenders.length > 0 || legacyRoutingOffenders.length > 0) {
|
||||
console.error(
|
||||
"Use openclaw/plugin-sdk/<channel> for channel plugins, /core for shared routing and startup surfaces, or /compat for broader internals.",
|
||||
);
|
||||
}
|
||||
console.error(
|
||||
"Use openclaw/plugin-sdk/<channel> for channel plugins, /core for startup surfaces, or /compat for broader internals.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,13 @@ describe("resolvePluginProviders", () => {
|
||||
});
|
||||
loadPluginManifestRegistryMock.mockReset();
|
||||
loadPluginManifestRegistryMock.mockReturnValue({
|
||||
plugins: [],
|
||||
plugins: [
|
||||
{ id: "google", providers: ["google"], origin: "bundled" },
|
||||
{ id: "kilocode", providers: ["kilocode"], origin: "bundled" },
|
||||
{ id: "moonshot", providers: ["moonshot"], origin: "bundled" },
|
||||
{ id: "google-gemini-cli-auth", providers: [], origin: "bundled" },
|
||||
{ id: "workspace-provider", providers: ["workspace-provider"], origin: "workspace" },
|
||||
],
|
||||
diagnostics: [],
|
||||
});
|
||||
});
|
||||
@@ -77,7 +83,7 @@ describe("resolvePluginProviders", () => {
|
||||
config: expect.objectContaining({
|
||||
plugins: expect.objectContaining({
|
||||
enabled: true,
|
||||
allow: expect.arrayContaining(["openai", "moonshot", "zai"]),
|
||||
allow: expect.arrayContaining(["google", "moonshot"]),
|
||||
}),
|
||||
}),
|
||||
cache: false,
|
||||
@@ -103,6 +109,22 @@ describe("resolvePluginProviders", () => {
|
||||
expect(allow).not.toContain("google-gemini-cli-auth");
|
||||
});
|
||||
|
||||
it("does not inject non-bundled provider plugin ids into compat allowlists", () => {
|
||||
resolvePluginProviders({
|
||||
config: {
|
||||
plugins: {
|
||||
allow: ["openrouter"],
|
||||
},
|
||||
},
|
||||
bundledProviderAllowlistCompat: true,
|
||||
});
|
||||
|
||||
const call = loadOpenClawPluginsMock.mock.calls.at(-1)?.[0];
|
||||
const allow = call?.config?.plugins?.allow;
|
||||
|
||||
expect(allow).not.toContain("workspace-provider");
|
||||
});
|
||||
|
||||
it("maps provider ids to owning plugin ids via manifests", () => {
|
||||
loadPluginManifestRegistryMock.mockReturnValue({
|
||||
plugins: [
|
||||
|
||||
@@ -7,39 +7,6 @@ import { loadPluginManifestRegistry } from "./manifest-registry.js";
|
||||
import type { ProviderPlugin } from "./types.js";
|
||||
|
||||
const log = createSubsystemLogger("plugins");
|
||||
const BUNDLED_PROVIDER_ALLOWLIST_COMPAT_PLUGIN_IDS = [
|
||||
"anthropic",
|
||||
"byteplus",
|
||||
"cloudflare-ai-gateway",
|
||||
"copilot-proxy",
|
||||
"github-copilot",
|
||||
"google",
|
||||
"huggingface",
|
||||
"kilocode",
|
||||
"kimi-coding",
|
||||
"minimax",
|
||||
"mistral",
|
||||
"modelstudio",
|
||||
"moonshot",
|
||||
"nvidia",
|
||||
"ollama",
|
||||
"openai",
|
||||
"opencode",
|
||||
"opencode-go",
|
||||
"openrouter",
|
||||
"qianfan",
|
||||
"qwen-portal-auth",
|
||||
"sglang",
|
||||
"synthetic",
|
||||
"together",
|
||||
"venice",
|
||||
"vercel-ai-gateway",
|
||||
"volcengine",
|
||||
"xai",
|
||||
"vllm",
|
||||
"xiaomi",
|
||||
"zai",
|
||||
] as const;
|
||||
|
||||
function hasExplicitPluginConfig(config: PluginLoadOptions["config"]): boolean {
|
||||
const plugins = config?.plugins;
|
||||
@@ -69,10 +36,11 @@ function hasExplicitPluginConfig(config: PluginLoadOptions["config"]): boolean {
|
||||
|
||||
function withBundledProviderVitestCompat(params: {
|
||||
config: PluginLoadOptions["config"];
|
||||
pluginIds: readonly string[];
|
||||
env?: PluginLoadOptions["env"];
|
||||
}): PluginLoadOptions["config"] {
|
||||
const env = params.env ?? process.env;
|
||||
if (!env.VITEST || hasExplicitPluginConfig(params.config)) {
|
||||
if (!env.VITEST || hasExplicitPluginConfig(params.config) || params.pluginIds.length === 0) {
|
||||
return params.config;
|
||||
}
|
||||
|
||||
@@ -81,7 +49,7 @@ function withBundledProviderVitestCompat(params: {
|
||||
plugins: {
|
||||
...params.config?.plugins,
|
||||
enabled: true,
|
||||
allow: [...BUNDLED_PROVIDER_ALLOWLIST_COMPAT_PLUGIN_IDS],
|
||||
allow: [...params.pluginIds],
|
||||
slots: {
|
||||
...params.config?.plugins?.slots,
|
||||
memory: "none",
|
||||
@@ -90,6 +58,22 @@ function withBundledProviderVitestCompat(params: {
|
||||
};
|
||||
}
|
||||
|
||||
function resolveBundledProviderCompatPluginIds(params: {
|
||||
config?: PluginLoadOptions["config"];
|
||||
workspaceDir?: string;
|
||||
env?: PluginLoadOptions["env"];
|
||||
}): string[] {
|
||||
const registry = loadPluginManifestRegistry({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
return registry.plugins
|
||||
.filter((plugin) => plugin.origin === "bundled" && plugin.providers.length > 0)
|
||||
.map((plugin) => plugin.id)
|
||||
.toSorted((left, right) => left.localeCompare(right));
|
||||
}
|
||||
|
||||
export function resolveOwningPluginIdsForProvider(params: {
|
||||
provider: string;
|
||||
config?: PluginLoadOptions["config"];
|
||||
@@ -126,15 +110,24 @@ export function resolvePluginProviders(params: {
|
||||
activate?: boolean;
|
||||
cache?: boolean;
|
||||
}): ProviderPlugin[] {
|
||||
const bundledProviderCompatPluginIds =
|
||||
params.bundledProviderAllowlistCompat || params.bundledProviderVitestCompat
|
||||
? resolveBundledProviderCompatPluginIds({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
})
|
||||
: [];
|
||||
const maybeAllowlistCompat = params.bundledProviderAllowlistCompat
|
||||
? withBundledPluginAllowlistCompat({
|
||||
config: params.config,
|
||||
pluginIds: BUNDLED_PROVIDER_ALLOWLIST_COMPAT_PLUGIN_IDS,
|
||||
pluginIds: bundledProviderCompatPluginIds,
|
||||
})
|
||||
: params.config;
|
||||
const config = params.bundledProviderVitestCompat
|
||||
? withBundledProviderVitestCompat({
|
||||
config: maybeAllowlistCompat,
|
||||
pluginIds: bundledProviderCompatPluginIds,
|
||||
env: params.env,
|
||||
})
|
||||
: maybeAllowlistCompat;
|
||||
|
||||
Reference in New Issue
Block a user