From cfd1e94e61018bccf9bb15b3ccf893123fd23dda Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Fri, 27 Mar 2026 22:36:02 -0500 Subject: [PATCH] fix(regression): auto-enable plugin tool loads --- src/plugins/tools.optional.test.ts | 46 ++++++++++++++++++++++++++++++ src/plugins/tools.ts | 4 ++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/plugins/tools.optional.test.ts b/src/plugins/tools.optional.test.ts index edafeb97a5d..3fd7965157a 100644 --- a/src/plugins/tools.optional.test.ts +++ b/src/plugins/tools.optional.test.ts @@ -8,11 +8,16 @@ type MockRegistryToolEntry = { }; const loadOpenClawPluginsMock = vi.fn(); +const applyPluginAutoEnableMock = vi.fn(); vi.mock("./loader.js", () => ({ loadOpenClawPlugins: (params: unknown) => loadOpenClawPluginsMock(params), })); +vi.mock("../config/plugin-auto-enable.js", () => ({ + applyPluginAutoEnable: (params: unknown) => applyPluginAutoEnableMock(params), +})); + let resolvePluginTools: typeof import("./tools.js").resolvePluginTools; let resetPluginRuntimeStateForTest: typeof import("./runtime.js").resetPluginRuntimeStateForTest; @@ -129,6 +134,11 @@ describe("resolvePluginTools optional tools", () => { beforeEach(async () => { vi.resetModules(); loadOpenClawPluginsMock.mockClear(); + applyPluginAutoEnableMock.mockReset(); + applyPluginAutoEnableMock.mockImplementation(({ config }: { config: unknown }) => ({ + config, + changes: [], + })); ({ resetPluginRuntimeStateForTest } = await import("./runtime.js")); resetPluginRuntimeStateForTest(); ({ resolvePluginTools } = await import("./tools.js")); @@ -227,4 +237,40 @@ describe("resolvePluginTools optional tools", () => { expectLoaderCall(expectedLoaderCall); }); + + it("loads plugin tools from the auto-enabled config snapshot", () => { + setOptionalDemoRegistry(); + const rawContext = createContext(); + const autoEnabledConfig = { + ...rawContext.config, + plugins: { + ...rawContext.config.plugins, + entries: { + "optional-demo": { enabled: true }, + }, + }, + }; + applyPluginAutoEnableMock.mockReturnValue({ config: autoEnabledConfig, changes: [] }); + + resolvePluginTools({ + context: { + ...rawContext, + config: rawContext.config as never, + } as never, + toolAllowlist: ["optional_tool"], + }); + + expect(applyPluginAutoEnableMock).toHaveBeenCalledWith( + expect.objectContaining({ + config: expect.objectContaining({ + plugins: expect.objectContaining({ + allow: rawContext.config.plugins?.allow, + load: rawContext.config.plugins?.load, + }), + }), + env: process.env, + }), + ); + expectLoaderCall({ config: autoEnabledConfig }); + }); }); diff --git a/src/plugins/tools.ts b/src/plugins/tools.ts index 06a2b9446e2..c9d2e3c7cb6 100644 --- a/src/plugins/tools.ts +++ b/src/plugins/tools.ts @@ -1,5 +1,6 @@ import { normalizeToolName } from "../agents/tool-policy.js"; import type { AnyAgentTool } from "../agents/tools/common.js"; +import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { applyTestPluginDefaults, normalizePluginsConfig } from "./config-state.js"; import { loadOpenClawPlugins } from "./loader.js"; @@ -61,7 +62,8 @@ export function resolvePluginTools(params: { // Fast path: when plugins are effectively disabled, avoid discovery/jiti entirely. // This matters a lot for unit tests and for tool construction hot paths. const env = params.env ?? process.env; - const effectiveConfig = applyTestPluginDefaults(params.context.config ?? {}, env); + const baseConfig = applyTestPluginDefaults(params.context.config ?? {}, env); + const effectiveConfig = applyPluginAutoEnable({ config: baseConfig, env }).config; const normalized = normalizePluginsConfig(effectiveConfig.plugins); if (!normalized.enabled) { return [];