From d34bca3ce63fedaad1fdfb12846c7f9f3b90067f Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 3 Apr 2026 03:40:24 +0900 Subject: [PATCH] fix(plugins): reuse runtime registry for provider resolution (#59856) * fix(plugins): reuse runtime registry for provider resolution * test(plugins): align provider runtime helper names --- src/plugins/providers.runtime.ts | 7 ++-- src/plugins/providers.test.ts | 60 +++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/plugins/providers.runtime.ts b/src/plugins/providers.runtime.ts index 3e839bbc727..150ce7b7e09 100644 --- a/src/plugins/providers.runtime.ts +++ b/src/plugins/providers.runtime.ts @@ -4,7 +4,7 @@ import { withBundledPluginAllowlistCompat, withBundledPluginEnablementCompat, } from "./bundled-compat.js"; -import { loadOpenClawPlugins, type PluginLoadOptions } from "./loader.js"; +import { resolveRuntimePluginRegistry, type PluginLoadOptions } from "./loader.js"; import { createPluginLoaderLogger } from "./logger.js"; import { resolveEnabledProviderPluginIds, @@ -70,7 +70,7 @@ export function resolvePluginProviders(params: { env, onlyPluginIds: params.onlyPluginIds, }); - const registry = loadOpenClawPlugins({ + const registry = resolveRuntimePluginRegistry({ config, activationSourceConfig: params.config, autoEnabledReasons: autoEnabled?.autoEnabledReasons, @@ -82,6 +82,9 @@ export function resolvePluginProviders(params: { activate: params.activate ?? false, logger: createPluginLoaderLogger(log), }); + if (!registry) { + return []; + } return registry.providers.map((entry) => ({ ...entry.provider, diff --git a/src/plugins/providers.test.ts b/src/plugins/providers.test.ts index 4688e360517..cf9c2251b97 100644 --- a/src/plugins/providers.test.ts +++ b/src/plugins/providers.test.ts @@ -5,12 +5,12 @@ import type { PluginManifestRecord } from "./manifest-registry.js"; import { createEmptyPluginRegistry } from "./registry-empty.js"; import type { ProviderPlugin } from "./types.js"; -type LoadOpenClawPlugins = typeof import("./loader.js").loadOpenClawPlugins; +type ResolveRuntimePluginRegistry = typeof import("./loader.js").resolveRuntimePluginRegistry; type LoadPluginManifestRegistry = typeof import("./manifest-registry.js").loadPluginManifestRegistry; type ApplyPluginAutoEnable = typeof import("../config/plugin-auto-enable.js").applyPluginAutoEnable; -const loadOpenClawPluginsMock = vi.fn(); +const resolveRuntimePluginRegistryMock = vi.fn(); const loadPluginManifestRegistryMock = vi.fn(); const applyPluginAutoEnableMock = vi.fn(); @@ -56,8 +56,8 @@ function setOwningProviderManifestPlugins() { ]); } -function getLastLoadPluginsCall(): Record { - const call = loadOpenClawPluginsMock.mock.calls.at(-1)?.[0]; +function getLastRuntimeRegistryCall(): Record { + const call = resolveRuntimePluginRegistryMock.mock.calls.at(-1)?.[0]; expect(call).toBeDefined(); return (call ?? {}) as Record; } @@ -70,11 +70,11 @@ function expectResolvedProviders(providers: unknown, expected: unknown[]) { expect(providers).toEqual(expected); } -function expectLastLoadPluginsCall(params?: { +function expectLastRuntimeRegistryLoad(params?: { env?: NodeJS.ProcessEnv; onlyPluginIds?: readonly string[]; }) { - expect(loadOpenClawPluginsMock).toHaveBeenCalledWith( + expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith( expect.objectContaining({ cache: false, activate: false, @@ -85,7 +85,7 @@ function expectLastLoadPluginsCall(params?: { } function getLastResolvedPluginConfig() { - return getLastLoadPluginsCall().config as + return getLastRuntimeRegistryCall().config as | { plugins?: { allow?: string[]; @@ -127,7 +127,7 @@ function expectAutoEnabledProviderLoad(params: { rawConfig: unknown; autoEnabled config: params.rawConfig, env: process.env, }); - expectBundledProviderLoad({ config: params.autoEnabledConfig }); + expectProviderRuntimeRegistryLoad({ config: params.autoEnabledConfig }); } function expectResolvedAllowlistState(params?: { @@ -136,7 +136,7 @@ function expectResolvedAllowlistState(params?: { expectedEntries?: Record; expectedOnlyPluginIds?: readonly string[]; }) { - expectLastLoadPluginsCall( + expectLastRuntimeRegistryLoad( params?.expectedOnlyPluginIds ? { onlyPluginIds: params.expectedOnlyPluginIds } : undefined, ); @@ -158,8 +158,8 @@ function expectOwningPluginIds(provider: string, expectedPluginIds?: readonly st expect(resolveOwningPluginIdsForProvider({ provider })).toEqual(expectedPluginIds); } -function expectBundledProviderLoad(params?: { config?: unknown; env?: NodeJS.ProcessEnv }) { - expect(loadOpenClawPluginsMock).toHaveBeenCalledWith( +function expectProviderRuntimeRegistryLoad(params?: { config?: unknown; env?: NodeJS.ProcessEnv }) { + expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith( expect.objectContaining({ ...(params?.config ? { config: params.config } : {}), ...(params?.env ? { env: params.env } : {}), @@ -171,8 +171,8 @@ describe("resolvePluginProviders", () => { beforeAll(async () => { vi.resetModules(); vi.doMock("./loader.js", () => ({ - loadOpenClawPlugins: (...args: Parameters) => - loadOpenClawPluginsMock(...args), + resolveRuntimePluginRegistry: (...args: Parameters) => + resolveRuntimePluginRegistryMock(...args), })); vi.doMock("../config/plugin-auto-enable.js", () => ({ applyPluginAutoEnable: (...args: Parameters) => @@ -187,7 +187,7 @@ describe("resolvePluginProviders", () => { }); beforeEach(() => { - loadOpenClawPluginsMock.mockReset(); + resolveRuntimePluginRegistryMock.mockReset(); const provider: ProviderPlugin = { id: "demo-provider", label: "Demo Provider", @@ -195,7 +195,7 @@ describe("resolvePluginProviders", () => { }; const registry = createEmptyPluginRegistry(); registry.providers.push({ pluginId: "google", provider, source: "bundled" }); - loadOpenClawPluginsMock.mockReturnValue(registry); + resolveRuntimePluginRegistryMock.mockReturnValue(registry); loadPluginManifestRegistryMock.mockReset(); applyPluginAutoEnableMock.mockReset(); applyPluginAutoEnableMock.mockImplementation( @@ -230,7 +230,7 @@ describe("resolvePluginProviders", () => { expectResolvedProviders(providers, [ { id: "demo-provider", label: "Demo Provider", auth: [], pluginId: "google" }, ]); - expect(loadOpenClawPluginsMock).toHaveBeenCalledWith( + expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith( expect.objectContaining({ workspaceDir: "/workspace/explicit", env, @@ -293,7 +293,7 @@ describe("resolvePluginProviders", () => { bundledProviderVitestCompat: true, }); - expectLastLoadPluginsCall(); + expectLastRuntimeRegistryLoad(); expect(getLastResolvedPluginConfig()).toEqual( expect.objectContaining({ plugins: expect.objectContaining({ @@ -317,7 +317,7 @@ describe("resolvePluginProviders", () => { onlyPluginIds: ["google"], }); - expectLastLoadPluginsCall({ + expectLastRuntimeRegistryLoad({ onlyPluginIds: ["google"], }); expect(getLastResolvedPluginConfig()).toEqual( @@ -349,7 +349,7 @@ describe("resolvePluginProviders", () => { bundledProviderVitestCompat: true, }); - expect(loadOpenClawPluginsMock).toHaveBeenCalledWith( + expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith( expect.objectContaining({ config: undefined, env: {}, @@ -369,7 +369,7 @@ describe("resolvePluginProviders", () => { bundledProviderAllowlistCompat: true, }); - expectLastLoadPluginsCall({ + expectLastRuntimeRegistryLoad({ onlyPluginIds: ["google", "kilocode", "moonshot"], }); }); @@ -392,6 +392,26 @@ describe("resolvePluginProviders", () => { }); }); + it("routes provider runtime resolution through the compatible active-registry seam", () => { + resolvePluginProviders({ + config: { + plugins: { + allow: ["google"], + }, + }, + onlyPluginIds: ["google"], + workspaceDir: "/workspace/runtime", + }); + + expect(resolveRuntimePluginRegistryMock).toHaveBeenCalledWith( + expect.objectContaining({ + workspaceDir: "/workspace/runtime", + cache: false, + activate: false, + }), + ); + }); + it.each([ { provider: "minimax-portal",