import type { Api, Model } from "@earendil-works/pi-ai"; import { getBuiltinModel, getBuiltinModels, } from "@earendil-works/pi-ai/providers/all"; import { describe, expect, it } from "vitest"; import { isProjectableClaudeModel, modelsSignature, projectBuiltinModels, projectModel, projectModels, } from "../src/models"; function anthropic(modelId: string): Model { const model = getBuiltinModel("anthropic", modelId); if (!model) throw new Error(`missing builtin anthropic model ${modelId}`); return model; } describe("Klaus model projection", () => { it("projects every non-dated builtin Claude catalog model", () => { const builtin = getBuiltinModels("anthropic"); const expected = builtin .filter((model) => isProjectableClaudeModel(model)) .map((model) => model.id); expect(projectBuiltinModels().map((model) => model.id)).toEqual( expect.arrayContaining(expected), ); expect(projectBuiltinModels()).toHaveLength(expected.length); for (const model of builtin) { if (/-\d{8}$/.test(model.id) || model.id.endsWith("-latest")) expect(projectBuiltinModels().some((m) => m.id === model.id)).toBe( false, ); } }); it("keeps the curated alias table inside the projected catalog", () => { const ids = projectBuiltinModels().map((model) => model.id); for (const id of [ "claude-fable-5-1", "claude-haiku-4-5", "claude-opus-5", "claude-sonnet-5", "claude-sonnet-4-6", ]) expect(ids).toContain(id); }); it("filters foreign providers from a registry enumeration", () => { const openai = { ...anthropic("claude-sonnet-5"), provider: "openrouter" }; expect(projectModels([openai])).toEqual([]); }); it("copies Pi catalog metadata without transport fields", () => { const source = anthropic("claude-sonnet-5"); const projected = projectModel(source); expect(projected).toEqual({ id: source.id, name: source.name, reasoning: source.reasoning, thinkingLevelMap: source.thinkingLevelMap, input: [...source.input], cost: source.cost, compat: source.compat, contextWindow: source.contextWindow, maxTokens: source.maxTokens, }); expect(projected).not.toHaveProperty("api"); expect(projected).not.toHaveProperty("baseUrl"); expect(projected).not.toHaveProperty("headers"); expect(projected).not.toHaveProperty("samplingParams"); }); it("inherits user overrides that stay within the builtin baseline", () => { const baseline = anthropic("claude-opus-5"); const projected = projectModel({ ...baseline, name: "Opus (work account)", cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: baseline.contextWindow - 1000, maxTokens: baseline.maxTokens - 1000, }); expect(projected.name).toBe("Opus (work account)"); expect(projected.cost).toEqual({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0, }); expect(projected.contextWindow).toBe(baseline.contextWindow - 1000); expect(projected.maxTokens).toBe(baseline.maxTokens - 1000); }); it("clamps overrides that exceed what the Agent SDK path can deliver", () => { const baseline = anthropic("claude-haiku-4-5"); const projected = projectModel({ ...baseline, contextWindow: 1_000_000, maxTokens: baseline.maxTokens * 4, }); expect(projected.contextWindow).toBe(baseline.contextWindow); expect(projected.maxTokens).toBe(baseline.maxTokens); }); it("keeps Fable fallback models priced from the builtin catalog", () => { const projected = projectModel(anthropic("claude-fable-5-1")); expect(projected.compat).toMatchObject({ allowedFallbackModels: [ { provider: "anthropic", model: "claude-opus-4-8", cost: anthropic("claude-opus-4-8").cost, }, { provider: "anthropic", model: "claude-opus-5", cost: anthropic("claude-opus-5").cost, }, ], }); }); it("does not mutate the Pi catalog entry it projects", () => { const source = anthropic("claude-fable-5-1"); const before = structuredClone(source); const projected = projectModel(source); projected.cost.input = 999; projected.input.push("image"); expect(source).toEqual(before); }); it("filters the enumeration it is given without touching other models", () => { const catalog = getBuiltinModels("anthropic"); const models = projectModels( catalog.filter((model) => model.id !== "claude-haiku-4-5"), ); expect(models.map((model) => model.id)).not.toContain("claude-haiku-4-5"); expect(models).toHaveLength( catalog.filter(isProjectableClaudeModel).length - 1, ); }); it("signs identical projections identically", () => { expect(modelsSignature(projectBuiltinModels())).toBe( modelsSignature(projectBuiltinModels()), ); expect(modelsSignature(projectBuiltinModels())).not.toBe( modelsSignature( projectModels( getBuiltinModels("anthropic").map((model) => model.id === "claude-opus-5" ? { ...model, name: "renamed" } : model, ), ), ), ); }); });