mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-22 23:41:07 +00:00
Commands: lazy-load non-interactive plugin provider runtime (#47593)
* Commands: lazy-load non-interactive plugin provider runtime * Tests: cover non-interactive plugin provider ordering * Update src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.runtime.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
export {
|
||||
resolveProviderPluginChoice,
|
||||
} from "../../../plugins/provider-wizard.js";
|
||||
export { resolvePluginProviders } from "../../../plugins/providers.js";
|
||||
@@ -0,0 +1,54 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import { applyNonInteractivePluginProviderChoice } from "./auth-choice.plugin-providers.js";
|
||||
|
||||
const resolvePreferredProviderForAuthChoice = vi.hoisted(() => vi.fn(async () => undefined));
|
||||
vi.mock("../../auth-choice.preferred-provider.js", () => ({
|
||||
resolvePreferredProviderForAuthChoice,
|
||||
}));
|
||||
|
||||
const resolveProviderPluginChoice = vi.hoisted(() => vi.fn());
|
||||
const resolvePluginProviders = vi.hoisted(() => vi.fn(() => []));
|
||||
vi.mock("./auth-choice.plugin-providers.runtime.js", () => ({
|
||||
resolveProviderPluginChoice,
|
||||
resolvePluginProviders,
|
||||
PROVIDER_PLUGIN_CHOICE_PREFIX: "provider-plugin:",
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
function createRuntime() {
|
||||
return {
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
}
|
||||
|
||||
describe("applyNonInteractivePluginProviderChoice", () => {
|
||||
it("loads plugin providers for provider-plugin auth choices", async () => {
|
||||
const runtime = createRuntime();
|
||||
const runNonInteractive = vi.fn(async () => ({ plugins: { allow: ["vllm"] } }));
|
||||
resolvePluginProviders.mockReturnValue([{ id: "vllm", pluginId: "vllm" }] as never);
|
||||
resolveProviderPluginChoice.mockReturnValue({
|
||||
provider: { id: "vllm", pluginId: "vllm", label: "vLLM" },
|
||||
method: { runNonInteractive },
|
||||
});
|
||||
|
||||
const result = await applyNonInteractivePluginProviderChoice({
|
||||
nextConfig: { agents: { defaults: {} } } as OpenClawConfig,
|
||||
authChoice: "provider-plugin:vllm:custom",
|
||||
opts: {} as never,
|
||||
runtime: runtime as never,
|
||||
baseConfig: { agents: { defaults: {} } } as OpenClawConfig,
|
||||
resolveApiKey: vi.fn(),
|
||||
toApiKeyCredential: vi.fn(),
|
||||
});
|
||||
|
||||
expect(resolvePluginProviders).toHaveBeenCalledOnce();
|
||||
expect(resolveProviderPluginChoice).toHaveBeenCalledOnce();
|
||||
expect(runNonInteractive).toHaveBeenCalledOnce();
|
||||
expect(result).toEqual({ plugins: { allow: ["vllm"] } });
|
||||
});
|
||||
});
|
||||
@@ -3,11 +3,6 @@ import type { ApiKeyCredential } from "../../../agents/auth-profiles/types.js";
|
||||
import { resolveDefaultAgentWorkspaceDir } from "../../../agents/workspace.js";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import { enablePluginInConfig } from "../../../plugins/enable.js";
|
||||
import {
|
||||
PROVIDER_PLUGIN_CHOICE_PREFIX,
|
||||
resolveProviderPluginChoice,
|
||||
} from "../../../plugins/provider-wizard.js";
|
||||
import { resolvePluginProviders } from "../../../plugins/providers.js";
|
||||
import type {
|
||||
ProviderNonInteractiveApiKeyCredentialParams,
|
||||
ProviderResolveNonInteractiveApiKeyParams,
|
||||
@@ -16,6 +11,12 @@ import type { RuntimeEnv } from "../../../runtime.js";
|
||||
import { resolvePreferredProviderForAuthChoice } from "../../auth-choice.preferred-provider.js";
|
||||
import type { OnboardOptions } from "../../onboard-types.js";
|
||||
|
||||
const PROVIDER_PLUGIN_CHOICE_PREFIX = "provider-plugin:";
|
||||
|
||||
async function loadPluginProviderRuntime() {
|
||||
return import("./auth-choice.plugin-providers.runtime.js");
|
||||
}
|
||||
|
||||
function buildIsolatedProviderResolutionConfig(
|
||||
cfg: OpenClawConfig,
|
||||
providerId: string | undefined,
|
||||
@@ -73,6 +74,7 @@ export async function applyNonInteractivePluginProviderChoice(params: {
|
||||
params.nextConfig,
|
||||
preferredProviderId,
|
||||
);
|
||||
const { resolveProviderPluginChoice, resolvePluginProviders } = await loadPluginProviderRuntime();
|
||||
const providerChoice = resolveProviderPluginChoice({
|
||||
providers: resolvePluginProviders({
|
||||
config: resolutionConfig,
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../../config/config.js";
|
||||
import { applyNonInteractiveAuthChoice } from "./auth-choice.js";
|
||||
|
||||
const applySimpleNonInteractiveApiKeyChoice = vi.hoisted(() =>
|
||||
vi.fn<() => Promise<OpenClawConfig | null | undefined>>(async () => undefined),
|
||||
);
|
||||
vi.mock("./auth-choice.api-key-providers.js", () => ({
|
||||
applySimpleNonInteractiveApiKeyChoice,
|
||||
}));
|
||||
|
||||
const applyNonInteractivePluginProviderChoice = vi.hoisted(() => vi.fn(async () => undefined));
|
||||
vi.mock("./auth-choice.plugin-providers.js", () => ({
|
||||
applyNonInteractivePluginProviderChoice,
|
||||
}));
|
||||
|
||||
const resolveNonInteractiveApiKey = vi.hoisted(() => vi.fn());
|
||||
vi.mock("../api-keys.js", () => ({
|
||||
resolveNonInteractiveApiKey,
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
function createRuntime() {
|
||||
return {
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
log: vi.fn(),
|
||||
};
|
||||
}
|
||||
|
||||
describe("applyNonInteractiveAuthChoice", () => {
|
||||
it("resolves builtin API key auth before plugin provider resolution", async () => {
|
||||
const runtime = createRuntime();
|
||||
const nextConfig = { agents: { defaults: {} } } as OpenClawConfig;
|
||||
const resolvedConfig = { auth: { profiles: { "openai:default": { mode: "api_key" } } } };
|
||||
applySimpleNonInteractiveApiKeyChoice.mockResolvedValueOnce(resolvedConfig as never);
|
||||
|
||||
const result = await applyNonInteractiveAuthChoice({
|
||||
nextConfig,
|
||||
authChoice: "openai-api-key",
|
||||
opts: {} as never,
|
||||
runtime: runtime as never,
|
||||
baseConfig: nextConfig,
|
||||
});
|
||||
|
||||
expect(result).toBe(resolvedConfig);
|
||||
expect(applySimpleNonInteractiveApiKeyChoice).toHaveBeenCalledOnce();
|
||||
expect(applyNonInteractivePluginProviderChoice).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -161,24 +161,6 @@ export async function applyNonInteractiveAuthChoice(params: {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pluginProviderChoice = await applyNonInteractivePluginProviderChoice({
|
||||
nextConfig,
|
||||
authChoice,
|
||||
opts,
|
||||
runtime,
|
||||
baseConfig,
|
||||
resolveApiKey: (input) =>
|
||||
resolveApiKey({
|
||||
...input,
|
||||
cfg: baseConfig,
|
||||
runtime,
|
||||
}),
|
||||
toApiKeyCredential,
|
||||
});
|
||||
if (pluginProviderChoice !== undefined) {
|
||||
return pluginProviderChoice;
|
||||
}
|
||||
|
||||
if (authChoice === "token") {
|
||||
const providerRaw = opts.tokenProvider?.trim();
|
||||
if (!providerRaw) {
|
||||
@@ -484,6 +466,24 @@ export async function applyNonInteractiveAuthChoice(params: {
|
||||
}
|
||||
}
|
||||
|
||||
const pluginProviderChoice = await applyNonInteractivePluginProviderChoice({
|
||||
nextConfig,
|
||||
authChoice,
|
||||
opts,
|
||||
runtime,
|
||||
baseConfig,
|
||||
resolveApiKey: (input) =>
|
||||
resolveApiKey({
|
||||
...input,
|
||||
cfg: baseConfig,
|
||||
runtime,
|
||||
}),
|
||||
toApiKeyCredential,
|
||||
});
|
||||
if (pluginProviderChoice !== undefined) {
|
||||
return pluginProviderChoice;
|
||||
}
|
||||
|
||||
if (
|
||||
authChoice === "oauth" ||
|
||||
authChoice === "chutes" ||
|
||||
|
||||
Reference in New Issue
Block a user