From 4d7c6519fc11da38cdc41b2b19c03425519c22ee Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:23:13 -0500 Subject: [PATCH] fix(regression): enable owning plugins for provider onboarding --- .../auth-choice.plugin-providers.test.ts | 40 ++++++++++++++++++ .../local/auth-choice.plugin-providers.ts | 41 +++++++++++-------- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.test.ts b/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.test.ts index bea20a66764..1bb23a6a19e 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.test.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.test.ts @@ -66,4 +66,44 @@ describe("applyNonInteractivePluginProviderChoice", () => { expect(runNonInteractive).toHaveBeenCalledOnce(); expect(result).toEqual({ plugins: { allow: ["vllm"] } }); }); + + it("enables owning plugin ids when they differ from the provider id", async () => { + const runtime = createRuntime(); + const runNonInteractive = vi.fn(async () => ({ plugins: { allow: ["demo-plugin"] } })); + resolveOwningPluginIdsForProvider.mockReturnValue(["demo-plugin"] as never); + resolvePluginProviders.mockReturnValue([ + { id: "demo-provider", pluginId: "demo-plugin" }, + ] as never); + resolveProviderPluginChoice.mockReturnValue({ + provider: { id: "demo-provider", pluginId: "demo-plugin", label: "Demo Provider" }, + method: { runNonInteractive }, + }); + + const result = await applyNonInteractivePluginProviderChoice({ + nextConfig: { agents: { defaults: {} } } as OpenClawConfig, + authChoice: "provider-plugin:demo-provider:custom", + opts: {} as never, + runtime: runtime as never, + baseConfig: { agents: { defaults: {} } } as OpenClawConfig, + resolveApiKey: vi.fn(), + toApiKeyCredential: vi.fn(), + }); + + expect(resolvePluginProviders).toHaveBeenCalledWith( + expect.objectContaining({ + config: expect.objectContaining({ + plugins: expect.objectContaining({ + allow: expect.arrayContaining(["demo-provider", "demo-plugin"]), + entries: expect.objectContaining({ + "demo-provider": expect.objectContaining({ enabled: true }), + "demo-plugin": expect.objectContaining({ enabled: true }), + }), + }), + }), + onlyPluginIds: ["demo-plugin"], + }), + ); + expect(runNonInteractive).toHaveBeenCalledOnce(); + expect(result).toEqual({ plugins: { allow: ["demo-plugin"] } }); + }); }); diff --git a/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.ts b/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.ts index ad6cb853955..1cafa003486 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.ts @@ -30,25 +30,34 @@ const loadAuthChoicePluginProvidersRuntime = createLazyRuntimeSurface( function buildIsolatedProviderResolutionConfig( cfg: OpenClawConfig, - providerId: string | undefined, + ids: Iterable, ): OpenClawConfig { - if (!providerId) { + const allow = new Set(cfg.plugins?.allow ?? []); + const entries = { + ...cfg.plugins?.entries, + }; + let changed = false; + for (const rawId of ids) { + const id = rawId?.trim(); + if (!id) { + continue; + } + allow.add(id); + entries[id] = { + ...cfg.plugins?.entries?.[id], + enabled: true, + }; + changed = true; + } + if (!changed) { return cfg; } - const allow = new Set(cfg.plugins?.allow ?? []); - allow.add(providerId); return { ...cfg, plugins: { ...cfg.plugins, allow: Array.from(allow), - entries: { - ...cfg.plugins?.entries, - [providerId]: { - ...cfg.plugins?.entries?.[providerId], - enabled: true, - }, - }, + entries, }, }; } @@ -82,19 +91,19 @@ export async function applyNonInteractivePluginProviderChoice(params: { config: params.nextConfig, workspaceDir, })); - const resolutionConfig = buildIsolatedProviderResolutionConfig( - params.nextConfig, - preferredProviderId, - ); const { resolveOwningPluginIdsForProvider, resolveProviderPluginChoice, resolvePluginProviders } = await loadAuthChoicePluginProvidersRuntime(); const owningPluginIds = preferredProviderId ? resolveOwningPluginIdsForProvider({ provider: preferredProviderId, - config: resolutionConfig, + config: params.nextConfig, workspaceDir, }) : undefined; + const resolutionConfig = buildIsolatedProviderResolutionConfig(params.nextConfig, [ + preferredProviderId, + ...(owningPluginIds ?? []), + ]); const providerChoice = resolveProviderPluginChoice({ providers: resolvePluginProviders({ config: resolutionConfig,