mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-15 11:11:09 +00:00
160 lines
4.6 KiB
TypeScript
160 lines
4.6 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { configureOpenAICompatibleSelfHostedProviderNonInteractive } from "./provider-self-hosted-setup.js";
|
|
import type { ProviderAuthMethodNonInteractiveContext } from "./types.js";
|
|
|
|
const upsertAuthProfileWithLock = vi.hoisted(() => vi.fn(async () => null));
|
|
vi.mock("../agents/auth-profiles/upsert-with-lock.js", () => ({
|
|
upsertAuthProfileWithLock,
|
|
}));
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
function createRuntime() {
|
|
return {
|
|
error: vi.fn(),
|
|
exit: vi.fn(),
|
|
log: vi.fn(),
|
|
};
|
|
}
|
|
|
|
function createContext(params: {
|
|
providerId: string;
|
|
baseUrl?: string;
|
|
apiKey?: string;
|
|
modelId?: string;
|
|
}): ProviderAuthMethodNonInteractiveContext {
|
|
const resolved = {
|
|
key: params.apiKey ?? "self-hosted-test-key",
|
|
source: "flag" as const,
|
|
};
|
|
return {
|
|
authChoice: params.providerId,
|
|
config: { agents: { defaults: {} } },
|
|
baseConfig: { agents: { defaults: {} } },
|
|
opts: {
|
|
customBaseUrl: params.baseUrl,
|
|
customApiKey: params.apiKey,
|
|
customModelId: params.modelId,
|
|
},
|
|
runtime: createRuntime() as never,
|
|
agentDir: "/tmp/openclaw-self-hosted-test-agent",
|
|
resolveApiKey: vi.fn<ProviderAuthMethodNonInteractiveContext["resolveApiKey"]>(
|
|
async () => resolved,
|
|
),
|
|
toApiKeyCredential: vi.fn<ProviderAuthMethodNonInteractiveContext["toApiKeyCredential"]>(
|
|
({ provider, resolved: apiKeyResult }) => ({
|
|
type: "api_key",
|
|
provider,
|
|
key: apiKeyResult.key,
|
|
}),
|
|
),
|
|
};
|
|
}
|
|
|
|
function readPrimaryModel(config: Awaited<ReturnType<typeof configureSelfHostedTestProvider>>) {
|
|
const model = config?.agents?.defaults?.model;
|
|
return model && typeof model === "object" ? model.primary : undefined;
|
|
}
|
|
|
|
async function configureSelfHostedTestProvider(params: {
|
|
ctx: ProviderAuthMethodNonInteractiveContext;
|
|
providerId: string;
|
|
providerLabel: string;
|
|
envVar: string;
|
|
}) {
|
|
return await configureOpenAICompatibleSelfHostedProviderNonInteractive({
|
|
ctx: params.ctx,
|
|
providerId: params.providerId,
|
|
providerLabel: params.providerLabel,
|
|
defaultBaseUrl: "http://127.0.0.1:8000/v1",
|
|
defaultApiKeyEnvVar: params.envVar,
|
|
modelPlaceholder: "Qwen/Qwen3-32B",
|
|
});
|
|
}
|
|
|
|
describe("configureOpenAICompatibleSelfHostedProviderNonInteractive", () => {
|
|
it.each([
|
|
{
|
|
providerId: "vllm",
|
|
providerLabel: "vLLM",
|
|
envVar: "VLLM_API_KEY",
|
|
baseUrl: "http://127.0.0.1:8100/v1/",
|
|
apiKey: "vllm-test-key",
|
|
modelId: "Qwen/Qwen3-8B",
|
|
},
|
|
{
|
|
providerId: "sglang",
|
|
providerLabel: "SGLang",
|
|
envVar: "SGLANG_API_KEY",
|
|
baseUrl: "http://127.0.0.1:31000/v1",
|
|
apiKey: "sglang-test-key",
|
|
modelId: "Qwen/Qwen3-32B",
|
|
},
|
|
])("configures $providerLabel config and auth profile", async (params) => {
|
|
const ctx = createContext(params);
|
|
|
|
const cfg = await configureSelfHostedTestProvider({
|
|
ctx,
|
|
providerId: params.providerId,
|
|
providerLabel: params.providerLabel,
|
|
envVar: params.envVar,
|
|
});
|
|
|
|
const profileId = `${params.providerId}:default`;
|
|
expect(cfg?.auth?.profiles?.[profileId]).toEqual({
|
|
provider: params.providerId,
|
|
mode: "api_key",
|
|
});
|
|
expect(cfg?.models?.providers?.[params.providerId]).toEqual({
|
|
baseUrl: params.baseUrl.replace(/\/+$/, ""),
|
|
api: "openai-completions",
|
|
apiKey: params.envVar,
|
|
models: [
|
|
expect.objectContaining({
|
|
id: params.modelId,
|
|
}),
|
|
],
|
|
});
|
|
expect(readPrimaryModel(cfg)).toBe(`${params.providerId}/${params.modelId}`);
|
|
expect(ctx.resolveApiKey).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
flagName: "--custom-api-key",
|
|
envVar: params.envVar,
|
|
}),
|
|
);
|
|
expect(upsertAuthProfileWithLock).toHaveBeenCalledWith({
|
|
profileId,
|
|
agentDir: ctx.agentDir,
|
|
credential: {
|
|
type: "api_key",
|
|
provider: params.providerId,
|
|
key: params.apiKey,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("exits without touching auth when custom model id is missing", async () => {
|
|
const ctx = createContext({
|
|
providerId: "vllm",
|
|
apiKey: "vllm-test-key",
|
|
});
|
|
|
|
const cfg = await configureSelfHostedTestProvider({
|
|
ctx,
|
|
providerId: "vllm",
|
|
providerLabel: "vLLM",
|
|
envVar: "VLLM_API_KEY",
|
|
});
|
|
|
|
expect(cfg).toBeNull();
|
|
expect(ctx.runtime.error).toHaveBeenCalledWith(
|
|
expect.stringContaining("Missing --custom-model-id for --auth-choice vllm."),
|
|
);
|
|
expect(ctx.runtime.exit).toHaveBeenCalledWith(1);
|
|
expect(ctx.resolveApiKey).not.toHaveBeenCalled();
|
|
expect(upsertAuthProfileWithLock).not.toHaveBeenCalled();
|
|
});
|
|
});
|