import { sortUniqueStrings } from "../shared/string-normalization.js"; import { withActivatedPluginIds } from "./activation-context.js"; import { resolveBundledPluginCompatibleActivationInputs } from "./activation-context.js"; import { resolveManifestActivationPluginIds } from "./activation-planner.js"; import { getLoadedRuntimePluginRegistry } from "./active-runtime-registry.js"; import { extractPluginInstallRecordsFromInstalledPluginIndex } from "./installed-plugin-index-install-records.js"; import { getRuntimePluginRegistryForLoadOptions, isPluginRegistryLoadInFlight, loadOpenClawPlugins, type PluginLoadOptions, } from "./loader.js"; import { loadPluginMetadataSnapshot } from "./plugin-metadata-snapshot.js"; import type { PluginMetadataRegistryView } from "./plugin-metadata-snapshot.types.js"; import { hasExplicitPluginIdScope } from "./plugin-scope.js"; import { resolveProviderConfigApiOwnerHint } from "./provider-config-owner.js"; import { resolveActivatableProviderOwnerPluginIds, resolveDiscoverableProviderOwnerPluginIds, resolveDiscoveredProviderPluginIds, resolveEnabledProviderPluginIds, resolveBundledProviderCompatPluginIds, resolveOwningPluginIdsForModelRefs, resolveOwningPluginIdsForProviderRef, withBundledProviderVitestCompat, } from "./providers.js"; import { getActivePluginRegistryWorkspaceDir } from "./runtime.js"; import { buildPluginRuntimeLoadOptionsFromValues, createPluginRuntimeLoaderLogger, } from "./runtime/load-context.js"; import type { ProviderPlugin } from "./types.js"; function dedupeSortedPluginIds(values: Iterable): string[] { return sortUniqueStrings(values); } function resolveExplicitProviderOwnerPluginIds( params: { providerRefs: readonly string[]; config?: PluginLoadOptions["config"]; workspaceDir?: string; env?: PluginLoadOptions["env"]; }, snapshot: PluginMetadataRegistryView, ): string[] { return dedupeSortedPluginIds( params.providerRefs.flatMap((provider) => { const plannedPluginIds = resolveManifestActivationPluginIds({ trigger: { kind: "provider", provider, }, config: params.config, workspaceDir: params.workspaceDir, env: params.env, manifestRecords: snapshot.manifestRegistry.plugins, }); if (plannedPluginIds.length > 0) { return plannedPluginIds; } const apiOwnerHint = resolveProviderConfigApiOwnerHint({ provider, config: params.config, }); if (apiOwnerHint) { const apiOwnerPluginIds = resolveManifestActivationPluginIds({ trigger: { kind: "provider", provider: apiOwnerHint, }, config: params.config, workspaceDir: params.workspaceDir, env: params.env, manifestRecords: snapshot.manifestRegistry.plugins, }); if (apiOwnerPluginIds.length > 0) { return apiOwnerPluginIds; } } return ( resolveOwningPluginIdsForProviderRef({ provider, config: params.config, workspaceDir: params.workspaceDir, env: params.env, manifestRegistry: snapshot.manifestRegistry, }) ?? [] ); }), ); } function mergeExplicitOwnerPluginIds( providerPluginIds: readonly string[], explicitOwnerPluginIds: readonly string[], ): string[] { if (explicitOwnerPluginIds.length === 0) { return [...providerPluginIds]; } return dedupeSortedPluginIds([...providerPluginIds, ...explicitOwnerPluginIds]); } function resolvePluginProviderLoadBase( params: { config?: PluginLoadOptions["config"]; workspaceDir?: string; env?: PluginLoadOptions["env"]; onlyPluginIds?: string[]; providerRefs?: readonly string[]; modelRefs?: readonly string[]; }, snapshot: PluginMetadataRegistryView, ) { const env = params.env ?? process.env; const workspaceDir = params.workspaceDir ?? getActivePluginRegistryWorkspaceDir(); const providerOwnedPluginIds = params.providerRefs?.length ? resolveExplicitProviderOwnerPluginIds( { providerRefs: params.providerRefs, config: params.config, workspaceDir, env, }, snapshot, ) : []; const modelOwnedPluginIds = params.modelRefs?.length ? resolveOwningPluginIdsForModelRefs({ models: params.modelRefs, config: params.config, workspaceDir, env, manifestRegistry: snapshot.manifestRegistry, }) : []; const requestedPluginIds = hasExplicitPluginIdScope(params.onlyPluginIds) || params.providerRefs?.length || params.modelRefs?.length || providerOwnedPluginIds.length > 0 || modelOwnedPluginIds.length > 0 ? dedupeSortedPluginIds([ ...(params.onlyPluginIds ?? []), ...providerOwnedPluginIds, ...modelOwnedPluginIds, ]) : undefined; const explicitOwnerPluginIds = dedupeSortedPluginIds([ ...providerOwnedPluginIds, ...modelOwnedPluginIds, ]); return { env, workspaceDir, requestedPluginIds, explicitOwnerPluginIds, rawConfig: params.config, }; } function resolveSetupProviderPluginLoadState( params: Parameters[0], base: ReturnType, snapshot: PluginMetadataRegistryView, ) { const providerPluginIds = resolveDiscoveredProviderPluginIds({ config: params.config, workspaceDir: base.workspaceDir, env: base.env, onlyPluginIds: base.requestedPluginIds, includeUntrustedWorkspacePlugins: params.includeUntrustedWorkspacePlugins, registry: snapshot.index, manifestRegistry: snapshot.manifestRegistry, }); const explicitOwnerPluginIds = resolveDiscoverableProviderOwnerPluginIds({ pluginIds: base.explicitOwnerPluginIds, config: params.config, workspaceDir: base.workspaceDir, env: base.env, includeUntrustedWorkspacePlugins: params.includeUntrustedWorkspacePlugins, registry: snapshot.index, manifestRegistry: snapshot.manifestRegistry, }); const setupPluginIds = mergeExplicitOwnerPluginIds(providerPluginIds, explicitOwnerPluginIds); if (setupPluginIds.length === 0) { return undefined; } const setupConfig = withActivatedPluginIds({ config: base.rawConfig, pluginIds: setupPluginIds, }); const loadOptions = buildPluginRuntimeLoadOptionsFromValues( { config: setupConfig, activationSourceConfig: setupConfig, autoEnabledReasons: {}, workspaceDir: base.workspaceDir, env: base.env, logger: createPluginRuntimeLoaderLogger(), manifestRegistry: snapshot.manifestRegistry, installRecords: extractPluginInstallRecordsFromInstalledPluginIndex(snapshot.index), }, { onlyPluginIds: setupPluginIds, pluginSdkResolution: params.pluginSdkResolution, cache: params.cache ?? false, activate: params.activate ?? false, }, ); return { loadOptions }; } function resolveRuntimeProviderPluginLoadState( params: Parameters[0], base: ReturnType, snapshot: PluginMetadataRegistryView, ) { const explicitOwnerPluginIds = resolveActivatableProviderOwnerPluginIds({ pluginIds: base.explicitOwnerPluginIds, config: base.rawConfig, workspaceDir: base.workspaceDir, env: base.env, includeUntrustedWorkspacePlugins: params.includeUntrustedWorkspacePlugins, registry: snapshot.index, manifestRegistry: snapshot.manifestRegistry, }); const runtimeRequestedPluginIds = base.requestedPluginIds !== undefined ? dedupeSortedPluginIds([...(params.onlyPluginIds ?? []), ...explicitOwnerPluginIds]) : undefined; const requestConfig = withActivatedPluginIds({ config: base.rawConfig, pluginIds: explicitOwnerPluginIds, }); const activation = resolveBundledPluginCompatibleActivationInputs({ rawConfig: requestConfig, env: base.env, workspaceDir: base.workspaceDir, onlyPluginIds: runtimeRequestedPluginIds, applyAutoEnable: params.applyAutoEnable ?? true, compatMode: { vitest: params.bundledProviderVitestCompat, }, resolveCompatPluginIds: (compatParams) => resolveBundledProviderCompatPluginIds({ ...compatParams, manifestRegistry: snapshot.manifestRegistry, }), }); const config = params.bundledProviderVitestCompat ? withBundledProviderVitestCompat({ config: activation.config, pluginIds: activation.compatPluginIds, env: base.env, }) : activation.config; const providerPluginIds = mergeExplicitOwnerPluginIds( resolveEnabledProviderPluginIds({ config, workspaceDir: base.workspaceDir, env: base.env, onlyPluginIds: runtimeRequestedPluginIds, registry: snapshot.index, manifestRegistry: snapshot.manifestRegistry, }), explicitOwnerPluginIds, ); const loadOptions = buildPluginRuntimeLoadOptionsFromValues( { config, activationSourceConfig: activation.activationSourceConfig, autoEnabledReasons: activation.autoEnabledReasons, workspaceDir: base.workspaceDir, env: base.env, logger: createPluginRuntimeLoaderLogger(), manifestRegistry: snapshot.manifestRegistry, installRecords: extractPluginInstallRecordsFromInstalledPluginIndex(snapshot.index), }, { onlyPluginIds: providerPluginIds, pluginSdkResolution: params.pluginSdkResolution, cache: params.cache ?? true, activate: params.activate ?? false, }, ); return { loadOptions }; } export function isPluginProvidersLoadInFlight( params: Parameters[0], ): boolean { const env = params.env ?? process.env; const workspaceDir = params.workspaceDir ?? getActivePluginRegistryWorkspaceDir(); const snapshot = params.pluginMetadataSnapshot ?? loadPluginMetadataSnapshot({ config: params.config ?? {}, workspaceDir, env, }); const base = resolvePluginProviderLoadBase({ ...params, workspaceDir, env }, snapshot); const loadState = params.mode === "setup" ? resolveSetupProviderPluginLoadState(params, base, snapshot) : resolveRuntimeProviderPluginLoadState(params, base, snapshot); if (!loadState) { return false; } return isPluginRegistryLoadInFlight(loadState.loadOptions); } export function resolvePluginProviders(params: { config?: PluginLoadOptions["config"]; workspaceDir?: string; /** Use an explicit env when plugin roots should resolve independently from process.env. */ env?: PluginLoadOptions["env"]; bundledProviderVitestCompat?: boolean; onlyPluginIds?: string[]; providerRefs?: readonly string[]; modelRefs?: readonly string[]; activate?: boolean; cache?: boolean; applyAutoEnable?: boolean; pluginSdkResolution?: PluginLoadOptions["pluginSdkResolution"]; mode?: "runtime" | "setup"; includeUntrustedWorkspacePlugins?: boolean; pluginMetadataSnapshot?: PluginMetadataRegistryView; }): ProviderPlugin[] { const env = params.env ?? process.env; const workspaceDir = params.workspaceDir ?? getActivePluginRegistryWorkspaceDir(); const snapshot = params.pluginMetadataSnapshot ?? loadPluginMetadataSnapshot({ config: params.config ?? {}, workspaceDir, env, }); const base = resolvePluginProviderLoadBase({ ...params, workspaceDir, env }, snapshot); if (params.mode === "setup") { const loadState = resolveSetupProviderPluginLoadState(params, base, snapshot); if (!loadState) { return []; } const registry = loadOpenClawPlugins(loadState.loadOptions); return registry.providers.map((entry) => Object.assign({}, entry.provider, { pluginId: entry.pluginId }), ); } const loadState = resolveRuntimeProviderPluginLoadState(params, base, snapshot); const registry = loadState.loadOptions.onlyPluginIds?.length === 0 ? undefined : (getLoadedRuntimePluginRegistry({ env: base.env, loadOptions: loadState.loadOptions, workspaceDir: base.workspaceDir, requiredPluginIds: loadState.loadOptions.onlyPluginIds, }) ?? getRuntimePluginRegistryForLoadOptions(loadState.loadOptions)); if (!registry) { return []; } return registry.providers.map((entry) => Object.assign({}, entry.provider, { pluginId: entry.pluginId }), ); }