Files
openclaw/src/plugins/provider-public-artifacts.ts
2026-05-06 16:17:58 +01:00

115 lines
3.7 KiB
TypeScript

import { normalizeProviderId } from "../agents/provider-id.js";
import type { ModelProviderConfig } from "../config/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resolveBundledPluginsDir } from "./bundled-dir.js";
import { loadPluginManifestRegistry, type PluginManifestRegistry } from "./manifest-registry.js";
import type {
ProviderApplyConfigDefaultsContext,
ProviderNormalizeConfigContext,
ProviderResolveConfigApiKeyContext,
} from "./provider-config-context.types.js";
import type {
ProviderDefaultThinkingPolicyContext,
ProviderThinkingProfile,
} from "./provider-thinking.types.js";
import { loadBundledPluginPublicArtifactModuleSync } from "./public-surface-loader.js";
const PROVIDER_POLICY_ARTIFACT_CANDIDATES = ["provider-policy-api.js"] as const;
export type BundledProviderPolicySurface = {
normalizeConfig?: (ctx: ProviderNormalizeConfigContext) => ModelProviderConfig | null | undefined;
applyConfigDefaults?: (
ctx: ProviderApplyConfigDefaultsContext,
) => OpenClawConfig | null | undefined;
resolveConfigApiKey?: (ctx: ProviderResolveConfigApiKeyContext) => string | null | undefined;
resolveThinkingProfile?: (
ctx: ProviderDefaultThinkingPolicyContext,
) => ProviderThinkingProfile | null | undefined;
};
function hasProviderPolicyHook(
mod: Record<string, unknown>,
): mod is Record<string, unknown> & BundledProviderPolicySurface {
return (
typeof mod.normalizeConfig === "function" ||
typeof mod.applyConfigDefaults === "function" ||
typeof mod.resolveConfigApiKey === "function" ||
typeof mod.resolveThinkingProfile === "function"
);
}
function tryLoadBundledProviderPolicySurface(
pluginId: string,
): BundledProviderPolicySurface | null {
for (const artifactBasename of PROVIDER_POLICY_ARTIFACT_CANDIDATES) {
try {
const mod = loadBundledPluginPublicArtifactModuleSync<Record<string, unknown>>({
dirName: pluginId,
artifactBasename,
});
if (hasProviderPolicyHook(mod)) {
return mod;
}
} catch (error) {
if (
error instanceof Error &&
error.message.startsWith("Unable to resolve bundled plugin public surface ")
) {
continue;
}
throw error;
}
}
return null;
}
function resolveBundledProviderPolicyPluginId(
providerId: string,
options: { manifestRegistry?: Pick<PluginManifestRegistry, "plugins"> } = {},
): string | null {
const normalizedProviderId = normalizeProviderId(providerId);
if (!normalizedProviderId) {
return null;
}
const bundledPluginsDir = resolveBundledPluginsDir();
if (!bundledPluginsDir) {
return null;
}
const registry = options.manifestRegistry ?? loadPluginManifestRegistry();
for (const plugin of registry.plugins.toSorted((left, right) =>
left.id.localeCompare(right.id),
)) {
if (plugin.origin !== "bundled") {
continue;
}
const ownsProvider = plugin.providers.some(
(provider) => normalizeProviderId(provider) === normalizedProviderId,
);
if (ownsProvider) {
return plugin.id;
}
}
return null;
}
export function resolveBundledProviderPolicySurface(
providerId: string,
options: { manifestRegistry?: Pick<PluginManifestRegistry, "plugins"> } = {},
): BundledProviderPolicySurface | null {
const normalizedProviderId = normalizeProviderId(providerId);
if (!normalizedProviderId) {
return null;
}
const directSurface = tryLoadBundledProviderPolicySurface(normalizedProviderId);
if (directSurface) {
return directSurface;
}
const ownerPluginId = resolveBundledProviderPolicyPluginId(normalizedProviderId, options);
if (!ownerPluginId || ownerPluginId === normalizedProviderId) {
return null;
}
return tryLoadBundledProviderPolicySurface(ownerPluginId);
}