test: share provider catalog fixtures

This commit is contained in:
Peter Steinberger
2026-04-21 00:29:09 +01:00
parent 3b1ef4354f
commit 883f66eef3
5 changed files with 91 additions and 128 deletions

View File

@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import { resolveProviderPluginChoice } from "../../src/plugins/provider-auth-choice.runtime.js";
import { resolveProviderAuthEnvVarCandidates } from "../../src/secrets/provider-env-vars.js";
import { registerSingleProviderPlugin } from "../../test/helpers/plugins/plugin-registration.js";
import { runSingleProviderCatalog } from "../test-support/provider-model-test-helpers.js";
import arceePlugin from "./index.js";
describe("arcee provider plugin", () => {
@@ -77,28 +78,14 @@ describe("arcee provider plugin", () => {
it("builds the direct Arcee AI model catalog", async () => {
const provider = await registerSingleProviderPlugin(arceePlugin);
expect(provider.catalog).toBeDefined();
const catalog = await provider.catalog!.run({
config: {},
env: {},
resolveProviderApiKey: (id: string) =>
const catalogProvider = await runSingleProviderCatalog(provider, {
resolveProviderApiKey: (id?: string) =>
id === "arcee" ? { apiKey: "test-key" } : { apiKey: undefined },
resolveProviderAuth: () => ({
apiKey: "test-key",
mode: "api_key",
source: "env",
}),
} as never);
});
expect(catalog && "provider" in catalog).toBe(true);
if (!catalog || !("provider" in catalog)) {
throw new Error("expected single-provider catalog");
}
expect(catalog.provider.api).toBe("openai-completions");
expect(catalog.provider.baseUrl).toBe("https://api.arcee.ai/api/v1");
expect(catalog.provider.models?.map((model) => model.id)).toEqual([
expect(catalogProvider.api).toBe("openai-completions");
expect(catalogProvider.baseUrl).toBe("https://api.arcee.ai/api/v1");
expect(catalogProvider.models?.map((model) => model.id)).toEqual([
"trinity-mini",
"trinity-large-preview",
"trinity-large-thinking",
@@ -107,26 +94,18 @@ describe("arcee provider plugin", () => {
it("builds the OpenRouter-backed Arcee AI model catalog", async () => {
const provider = await registerSingleProviderPlugin(arceePlugin);
const catalog = await provider.catalog!.run({
config: {},
env: {},
resolveProviderApiKey: (id: string) =>
const catalogProvider = await runSingleProviderCatalog(provider, {
resolveProviderApiKey: (id?: string) =>
id === "openrouter" ? { apiKey: "sk-or-test" } : { apiKey: undefined },
resolveProviderAuth: () => ({
apiKey: "sk-or-test",
mode: "api_key",
source: "env",
}),
} as never);
});
expect(catalog && "provider" in catalog).toBe(true);
if (!catalog || !("provider" in catalog)) {
throw new Error("expected single-provider catalog");
}
expect(catalog.provider.baseUrl).toBe("https://openrouter.ai/api/v1");
expect(catalog.provider.models?.map((model) => model.id)).toEqual([
expect(catalogProvider.baseUrl).toBe("https://openrouter.ai/api/v1");
expect(catalogProvider.models?.map((model) => model.id)).toEqual([
"arcee/trinity-mini",
"arcee/trinity-large-preview",
"arcee/trinity-large-thinking",

View File

@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";
import { resolveProviderPluginChoice } from "../../src/plugins/provider-auth-choice.runtime.js";
import { registerSingleProviderPlugin } from "../../test/helpers/plugins/plugin-registration.js";
import { runSingleProviderCatalog } from "../test-support/provider-model-test-helpers.js";
import deepseekPlugin from "./index.js";
describe("deepseek provider plugin", () => {
@@ -22,32 +23,16 @@ describe("deepseek provider plugin", () => {
it("builds the static DeepSeek model catalog", async () => {
const provider = await registerSingleProviderPlugin(deepseekPlugin);
expect(provider.catalog).toBeDefined();
const catalogProvider = await runSingleProviderCatalog(provider);
const catalog = await provider.catalog!.run({
config: {},
env: {},
resolveProviderApiKey: () => ({ apiKey: "test-key" }),
resolveProviderAuth: () => ({
apiKey: "test-key",
mode: "api_key",
source: "env",
}),
} as never);
expect(catalog && "provider" in catalog).toBe(true);
if (!catalog || !("provider" in catalog)) {
throw new Error("expected single-provider catalog");
}
expect(catalog.provider.api).toBe("openai-completions");
expect(catalog.provider.baseUrl).toBe("https://api.deepseek.com");
expect(catalog.provider.models?.map((model) => model.id)).toEqual([
expect(catalogProvider.api).toBe("openai-completions");
expect(catalogProvider.baseUrl).toBe("https://api.deepseek.com");
expect(catalogProvider.models?.map((model) => model.id)).toEqual([
"deepseek-chat",
"deepseek-reasoner",
]);
expect(
catalog.provider.models?.find((model) => model.id === "deepseek-reasoner")?.reasoning,
catalogProvider.models?.find((model) => model.id === "deepseek-reasoner")?.reasoning,
).toBe(true);
});

View File

@@ -1,11 +1,11 @@
import type { ModelRegistry } from "@mariozechner/pi-coding-agent";
import type {
ProviderResolveDynamicModelContext,
ProviderRuntimeModel,
} from "openclaw/plugin-sdk/plugin-entry";
import type { ProviderRuntimeModel } from "openclaw/plugin-sdk/plugin-entry";
import { describe, expect, it } from "vitest";
import { resolveProviderPluginChoice } from "../../src/plugins/provider-auth-choice.runtime.js";
import { registerSingleProviderPlugin } from "../../test/helpers/plugins/plugin-registration.js";
import {
createProviderDynamicModelContext,
runSingleProviderCatalog,
} from "../test-support/provider-model-test-helpers.js";
import fireworksPlugin from "./index.js";
import {
FIREWORKS_BASE_URL,
@@ -14,27 +14,6 @@ import {
FIREWORKS_DEFAULT_MODEL_ID,
} from "./provider-catalog.js";
function createDynamicContext(params: {
provider: string;
modelId: string;
models: ProviderRuntimeModel[];
}): ProviderResolveDynamicModelContext {
return {
provider: params.provider,
modelId: params.modelId,
modelRegistry: {
find(providerId: string, modelId: string) {
return (
params.models.find(
(model) =>
model.provider === providerId && model.id.toLowerCase() === modelId.toLowerCase(),
) ?? null
);
},
} as ModelRegistry,
};
}
function createFireworksDefaultRuntimeModel(params: { reasoning: boolean }): ProviderRuntimeModel {
return {
id: FIREWORKS_DEFAULT_MODEL_ID,
@@ -69,26 +48,12 @@ describe("fireworks provider plugin", () => {
it("builds the Fireworks Fire Pass starter catalog", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const catalog = await provider.catalog?.run({
config: {},
env: {},
resolveProviderApiKey: () => ({ apiKey: "test-key" }),
resolveProviderAuth: () => ({
apiKey: "test-key",
mode: "api_key",
source: "env",
}),
} as never);
const catalogProvider = await runSingleProviderCatalog(provider);
expect(catalog && "provider" in catalog).toBe(true);
if (!catalog || !("provider" in catalog)) {
throw new Error("expected single-provider catalog");
}
expect(catalog.provider.api).toBe("openai-completions");
expect(catalog.provider.baseUrl).toBe(FIREWORKS_BASE_URL);
expect(catalog.provider.models?.map((model) => model.id)).toEqual([FIREWORKS_DEFAULT_MODEL_ID]);
expect(catalog.provider.models?.[0]).toMatchObject({
expect(catalogProvider.api).toBe("openai-completions");
expect(catalogProvider.baseUrl).toBe(FIREWORKS_BASE_URL);
expect(catalogProvider.models?.map((model) => model.id)).toEqual([FIREWORKS_DEFAULT_MODEL_ID]);
expect(catalogProvider.models?.[0]).toMatchObject({
reasoning: false,
input: ["text", "image"],
contextWindow: FIREWORKS_DEFAULT_CONTEXT_WINDOW,
@@ -99,7 +64,7 @@ describe("fireworks provider plugin", () => {
it("resolves forward-compat Fireworks model ids from the default template", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const resolved = provider.resolveDynamicModel?.(
createDynamicContext({
createProviderDynamicModelContext({
provider: "fireworks",
modelId: "accounts/fireworks/models/qwen3.6-plus",
models: [createFireworksDefaultRuntimeModel({ reasoning: true })],
@@ -118,7 +83,7 @@ describe("fireworks provider plugin", () => {
it("disables reasoning metadata for Fireworks Kimi dynamic models", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const resolved = provider.resolveDynamicModel?.(
createDynamicContext({
createProviderDynamicModelContext({
provider: "fireworks",
modelId: "accounts/fireworks/models/kimi-k2p5",
models: [createFireworksDefaultRuntimeModel({ reasoning: false })],
@@ -135,7 +100,7 @@ describe("fireworks provider plugin", () => {
it("disables reasoning metadata for Fireworks Kimi k2.5 aliases", async () => {
const provider = await registerSingleProviderPlugin(fireworksPlugin);
const resolved = provider.resolveDynamicModel?.(
createDynamicContext({
createProviderDynamicModelContext({
provider: "fireworks",
modelId: "accounts/fireworks/routers/kimi-k2.5-turbo",
models: [createFireworksDefaultRuntimeModel({ reasoning: false })],

View File

@@ -1,9 +1,6 @@
import type { ModelRegistry } from "@mariozechner/pi-coding-agent";
import type {
ProviderResolveDynamicModelContext,
ProviderRuntimeModel,
} from "openclaw/plugin-sdk/plugin-entry";
import type { ProviderRuntimeModel } from "openclaw/plugin-sdk/plugin-entry";
import { describe, expect, it } from "vitest";
import { createProviderDynamicModelContext as createContext } from "../test-support/provider-model-test-helpers.js";
import { isModernGoogleModel, resolveGoogleGeminiForwardCompatModel } from "./provider-models.js";
function createTemplateModel(
@@ -29,27 +26,6 @@ function createTemplateModel(
} as ProviderRuntimeModel;
}
function createContext(params: {
provider: string;
modelId: string;
models: ProviderRuntimeModel[];
}): ProviderResolveDynamicModelContext {
return {
provider: params.provider,
modelId: params.modelId,
modelRegistry: {
find(providerId: string, modelId: string) {
return (
params.models.find(
(model) =>
model.provider === providerId && model.id.toLowerCase() === modelId.toLowerCase(),
) ?? null
);
},
} as ModelRegistry,
};
}
describe("resolveGoogleGeminiForwardCompatModel", () => {
it("resolves stable gemini 2.5 flash-lite from direct google templates for Gemini CLI when available", () => {
const model = resolveGoogleGeminiForwardCompatModel({

View File

@@ -0,0 +1,58 @@
import type { ModelRegistry } from "@mariozechner/pi-coding-agent";
import type {
ProviderCatalogContext,
ProviderResolveDynamicModelContext,
ProviderRuntimeModel,
} from "openclaw/plugin-sdk/plugin-entry";
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
export function createProviderDynamicModelContext(params: {
provider: string;
modelId: string;
models: ProviderRuntimeModel[];
}): ProviderResolveDynamicModelContext {
return {
provider: params.provider,
modelId: params.modelId,
modelRegistry: {
find(providerId: string, modelId: string) {
return (
params.models.find(
(model) =>
model.provider === providerId && model.id.toLowerCase() === modelId.toLowerCase(),
) ?? null
);
},
} as ModelRegistry,
};
}
export async function runSingleProviderCatalog(
provider: Pick<ProviderPlugin, "catalog">,
params: {
resolveProviderApiKey?: ProviderCatalogContext["resolveProviderApiKey"];
resolveProviderAuth?: ProviderCatalogContext["resolveProviderAuth"];
} = {},
) {
if (!provider.catalog) {
throw new Error("expected provider catalog");
}
const catalog = await provider.catalog.run({
config: {},
env: {},
resolveProviderApiKey: params.resolveProviderApiKey ?? (() => ({ apiKey: "test-key" })),
resolveProviderAuth:
params.resolveProviderAuth ??
(() => ({
apiKey: "test-key",
mode: "api_key",
source: "env",
})),
} as ProviderCatalogContext);
if (!catalog || !("provider" in catalog)) {
throw new Error("expected single-provider catalog");
}
return catalog.provider;
}