process.env.OPENROUTER_API_URL = "http://127.0.0.1:1"; import { describe, it, expect } from "bun:test"; import { MIN_OUTPUT, kandidatenBauen, billigsterUeberSchwelle, type Model, } from "../src/openrouter-auswahl.ts"; const modelle: Model[] = [ { id: "anthropic/claude-haiku-4.5", context_length: 131072, pricing: { prompt: "0.01", completion: "0.01" }, supported_parameters: ["tools"], benchmarks: { artificial_analysis: { intelligence_index: 90 }, }, top_provider: { max_completion_tokens: 131072 }, }, { id: "inclusionai/ling-3.0-flash", context_length: 32768, pricing: { prompt: "0.001", completion: "0.001" }, supported_parameters: ["tools"], benchmarks: { artificial_analysis: { intelligence_index: 50 }, }, top_provider: { max_completion_tokens: 32768 }, }, { id: "z-ai/glm-5.3-flash", context_length: 131072, pricing: { prompt: "0.002", completion: "0.002" }, supported_parameters: ["tools"], benchmarks: { artificial_analysis: { intelligence_index: 55 }, }, top_provider: { max_completion_tokens: 131072 }, }, { id: "foo/ohne-angabe", context_length: 131072, pricing: { prompt: "0.0015", completion: "0.0015" }, supported_parameters: ["tools"], benchmarks: { artificial_analysis: { intelligence_index: 60 }, }, }, ]; describe("MIN_OUTPUT", () => { it("ist genau 65536", () => { expect(MIN_OUTPUT).toBe(65536); }); }); describe("kandidatenBauen", () => { it("fuellt maxOutput", () => { const { alle } = kandidatenBauen({ voll: modelle, konto: null }); expect(alle.get("inclusionai/ling-3.0-flash")?.maxOutput).toBe(32768); expect(alle.get("anthropic/claude-haiku-4.5")?.maxOutput).toBe(131072); expect(alle.get("foo/ohne-angabe")?.maxOutput).toBe(0); }); }); describe("billigsterUeberSchwelle", () => { it("wahlt glm-5.3-flash und lehnt ling sowie foo ab", async () => { const { alle } = kandidatenBauen({ voll: modelle, konto: null }); const abgelehnt: Array<{ id: string; grund: string }> = []; const ablehnen = (id: string, grund: string) => { abgelehnt.push({ id, grund }); }; const result = await billigsterUeberSchwelle( 40, 0, alle, undefined, ablehnen, new Map(), { varianten: [] }, ); expect(result.auswahl?.candidate.id).toBe("z-ai/glm-5.3-flash"); const ling = abgelehnt.find((e) => e.id === "inclusionai/ling-3.0-flash"); expect(ling).toBeDefined(); expect(ling!.grund).toContain("max_output"); expect(ling!.grund).toContain("32768"); const foo = abgelehnt.find((e) => e.id === "foo/ohne-angabe"); expect(foo).toBeDefined(); expect(foo!.grund).toBe("max_output unbekannt"); }); }); describe("Grenze maxOutput", () => { it("ein Kandidat mit maxOutput genau 65536 bleibt infrage", async () => { const grenzwert: Model[] = [ { id: "bar/grenzwertig", context_length: 131072, pricing: { prompt: "0.001", completion: "0.001" }, supported_parameters: ["tools"], benchmarks: { artificial_analysis: { intelligence_index: 70 }, }, top_provider: { max_completion_tokens: 65536 }, }, ]; const { alle } = kandidatenBauen({ voll: grenzwert, konto: null }); const abgelehnt: Array<{ id: string; grund: string }> = []; const ablehnen = (id: string, grund: string) => { abgelehnt.push({ id, grund }); }; const result = await billigsterUeberSchwelle( 0, 0, alle, undefined, ablehnen, new Map(), { varianten: [] }, ); expect(result.auswahl?.candidate.id).toBe("bar/grenzwertig"); expect(abgelehnt).toHaveLength(0); }); }); describe("minOutput je Profil", () => { it("32768 laesst ling als billigsten Kandidaten zu, Default tut es nicht", async () => { const { alle } = kandidatenBauen({ voll: modelle, konto: null }); const mitGate = await billigsterUeberSchwelle(40, 0, alle, undefined, undefined, new Map(), { varianten: [] }); expect(mitGate.auswahl?.candidate.id).toBe("z-ai/glm-5.3-flash"); const ohneGate = await billigsterUeberSchwelle(40, 0, alle, undefined, undefined, new Map(), { varianten: [], minOutput: 32768 }); expect(ohneGate.auswahl?.candidate.id).toBe("inclusionai/ling-3.0-flash"); }); it("bekannte Ablehnung traegt den wirksamen Grenzwert", async () => { const { alle } = kandidatenBauen({ voll: modelle, konto: null }); const abgelehnt: Array<{ id: string; grund: string }> = []; await billigsterUeberSchwelle(40, 0, alle, undefined, (id, grund) => abgelehnt.push({ id, grund }), new Map(), { varianten: [], minOutput: 65536 }); const ling = abgelehnt.find((e) => e.id === "inclusionai/ling-3.0-flash"); expect(ling?.grund).toContain("65536"); }); it("max_output unbekannt bleibt abgelehnt, auch mit herabgesetztem minOutput", async () => { const { alle } = kandidatenBauen({ voll: modelle, konto: null }); const abgelehnt: Array<{ id: string; grund: string }> = []; await billigsterUeberSchwelle(40, 0, alle, undefined, (id, grund) => abgelehnt.push({ id, grund }), new Map(), { varianten: [], minOutput: 1 }); const foo = abgelehnt.find((e) => e.id === "foo/ohne-angabe"); expect(foo).toBeDefined(); expect(foo!.grund).toBe("max_output unbekannt"); }); });