Files
openclaw/src/plugins/provider-discovery.runtime.ts
2026-04-11 02:46:41 +01:00

89 lines
2.8 KiB
TypeScript

import type { OpenClawConfig } from "../config/types.openclaw.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
import { resolveDiscoveredProviderPluginIds } from "./providers.js";
import { resolvePluginProviders } from "./providers.runtime.js";
import { createPluginSourceLoader } from "./source-loader.js";
import type { ProviderPlugin } from "./types.js";
type ProviderDiscoveryModule =
| ProviderPlugin
| ProviderPlugin[]
| {
default?: ProviderPlugin | ProviderPlugin[];
providers?: ProviderPlugin[];
provider?: ProviderPlugin;
};
function normalizeDiscoveryModule(value: ProviderDiscoveryModule): ProviderPlugin[] {
const resolved =
value && typeof value === "object" && "default" in value && value.default !== undefined
? value.default
: value;
if (Array.isArray(resolved)) {
return resolved;
}
if (resolved && typeof resolved === "object" && "id" in resolved) {
return [resolved];
}
if (value && typeof value === "object" && !Array.isArray(value)) {
const record = value as { providers?: ProviderPlugin[]; provider?: ProviderPlugin };
if (Array.isArray(record.providers)) {
return record.providers;
}
if (record.provider) {
return [record.provider];
}
}
return [];
}
function resolveProviderDiscoveryEntryPlugins(params: {
config?: OpenClawConfig;
workspaceDir?: string;
env?: NodeJS.ProcessEnv;
onlyPluginIds?: string[];
}): ProviderPlugin[] {
const pluginIds = resolveDiscoveredProviderPluginIds(params);
const pluginIdSet = new Set(pluginIds);
const records = loadPluginManifestRegistry(params).plugins.filter(
(plugin) => plugin.providerDiscoverySource && pluginIdSet.has(plugin.id),
);
if (records.length === 0) {
return [];
}
const loadSource = createPluginSourceLoader();
const providers: ProviderPlugin[] = [];
for (const manifest of records) {
try {
const moduleExport = loadSource(manifest.providerDiscoverySource!) as ProviderDiscoveryModule;
providers.push(
...normalizeDiscoveryModule(moduleExport).map((provider) => ({
...provider,
pluginId: manifest.id,
})),
);
} catch {
// Discovery fast path is optional. Fall back to the full plugin loader
// below so existing plugin diagnostics/load behavior remains canonical.
return [];
}
}
return providers;
}
export function resolvePluginDiscoveryProvidersRuntime(params: {
config?: OpenClawConfig;
workspaceDir?: string;
env?: NodeJS.ProcessEnv;
onlyPluginIds?: string[];
}): ProviderPlugin[] {
const entryProviders = resolveProviderDiscoveryEntryPlugins(params);
if (entryProviders.length > 0) {
return entryProviders;
}
return resolvePluginProviders({
...params,
bundledProviderAllowlistCompat: true,
});
}