import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; import type { ModelProviderConfig } from "../config/types.models.js"; import { buildPairedProviderApiKeyCatalog, buildSingleProviderApiKeyCatalog, findCatalogTemplate, } from "./provider-catalog.js"; import type { ProviderCatalogContext } from "./types.js"; function createProviderConfig(overrides: Partial = {}): ModelProviderConfig { return { api: "openai-completions", baseUrl: "https://default.example/v1", models: [], ...overrides, }; } function createCatalogContext(params: { config?: OpenClawConfig; apiKeys?: Record; }): ProviderCatalogContext { return { config: params.config ?? {}, env: {}, resolveProviderApiKey: (providerId) => ({ apiKey: providerId ? params.apiKeys?.[providerId] : undefined, }), resolveProviderAuth: (providerId) => ({ apiKey: providerId ? params.apiKeys?.[providerId] : undefined, mode: providerId && params.apiKeys?.[providerId] ? "api_key" : "none", source: providerId && params.apiKeys?.[providerId] ? "env" : "none", }), }; } describe("buildSingleProviderApiKeyCatalog", () => { it("matches provider templates case-insensitively", () => { const result = findCatalogTemplate({ entries: [ { provider: "OpenAI", id: "gpt-5.2" }, { provider: "other", id: "fallback" }, ], providerId: "openai", templateIds: ["missing", "GPT-5.2"], }); expect(result).toEqual({ provider: "OpenAI", id: "gpt-5.2" }); }); it("returns null when api key is missing", async () => { const result = await buildSingleProviderApiKeyCatalog({ ctx: createCatalogContext({}), providerId: "test-provider", buildProvider: () => createProviderConfig(), }); expect(result).toBeNull(); }); it("adds api key to the built provider", async () => { const result = await buildSingleProviderApiKeyCatalog({ ctx: createCatalogContext({ apiKeys: { "test-provider": "secret-key" }, }), providerId: "test-provider", buildProvider: async () => createProviderConfig(), }); expect(result).toEqual({ provider: { api: "openai-completions", baseUrl: "https://default.example/v1", models: [], apiKey: "secret-key", }, }); }); it("prefers explicit base url when allowed", async () => { const result = await buildSingleProviderApiKeyCatalog({ ctx: createCatalogContext({ apiKeys: { "test-provider": "secret-key" }, config: { models: { providers: { "test-provider": { baseUrl: " https://override.example/v1/ ", models: [], }, }, }, }, }), providerId: "test-provider", buildProvider: () => createProviderConfig(), allowExplicitBaseUrl: true, }); expect(result).toEqual({ provider: { api: "openai-completions", baseUrl: "https://override.example/v1/", models: [], apiKey: "secret-key", }, }); }); it("adds api key to each paired provider", async () => { const result = await buildPairedProviderApiKeyCatalog({ ctx: createCatalogContext({ apiKeys: { "test-provider": "secret-key" }, }), providerId: "test-provider", buildProviders: async () => ({ alpha: createProviderConfig(), beta: createProviderConfig(), }), }); expect(result).toEqual({ providers: { alpha: { api: "openai-completions", baseUrl: "https://default.example/v1", models: [], apiKey: "secret-key", }, beta: { api: "openai-completions", baseUrl: "https://default.example/v1", models: [], apiKey: "secret-key", }, }, }); }); });