| |
| |
| |
| |
| |
|
|
| import { describe, it, before, after } from "node:test"; |
| import assert from "node:assert/strict"; |
| import { unlinkSync, existsSync } from "node:fs"; |
|
|
| |
| const TEST_DB = "/tmp/omniroute-test-modelsdev.sqlite"; |
|
|
| before(() => { |
| if (existsSync(TEST_DB)) unlinkSync(TEST_DB); |
| process.env.DATA_DIR = "/tmp"; |
| process.env.DB_FILE = TEST_DB; |
| }); |
|
|
| after(() => { |
| if (existsSync(TEST_DB)) unlinkSync(TEST_DB); |
| }); |
|
|
| describe("modelsDevSync — integration: live fetch → DB → retrieve", () => { |
| it("fetches, saves pricing, and retrieves from DB", async () => { |
| const { |
| syncModelsDev, |
| getModelsDevPricing, |
| getSyncedCapabilities, |
| clearModelsDevPricing, |
| clearModelsDevCapabilities, |
| } = await import("../../src/lib/modelsDevSync.ts"); |
|
|
| |
| const result = await syncModelsDev({ dryRun: false, syncCapabilities: true }); |
| assert.equal(result.success, true, `sync should succeed: ${result.error || ""}`); |
| assert.ok(result.modelCount > 0, `should have pricing entries, got ${result.modelCount}`); |
| assert.ok(result.providerCount > 0, `should have providers, got ${result.providerCount}`); |
| assert.ok( |
| result.capabilityCount > 0, |
| `should have capabilities, got ${result.capabilityCount}` |
| ); |
|
|
| |
| const pricing = getModelsDevPricing(); |
| assert.ok(Object.keys(pricing).length > 0, "should have pricing in DB"); |
|
|
| |
| assert.ok(pricing.openai, "openai pricing should exist"); |
| assert.ok(pricing.openai["gpt-4o"], "gpt-4o pricing should exist in openai"); |
| assert.ok(pricing.openai["gpt-4o"].input > 0, "gpt-4o input price should be > 0"); |
| assert.ok(pricing.openai["gpt-4o"].output > 0, "gpt-4o output price should be > 0"); |
|
|
| assert.ok(pricing.anthropic, "anthropic pricing should exist"); |
| const claudeModels = Object.keys(pricing.anthropic).filter((m) => m.includes("claude")); |
| assert.ok(claudeModels.length > 0, "should have claude pricing entries"); |
|
|
| assert.ok(pricing.deepseek, "deepseek pricing should exist"); |
| assert.ok(pricing.if, "if (Qoder) pricing should exist (mapped from deepseek)"); |
|
|
| |
| const caps = getSyncedCapabilities(); |
| assert.ok(Object.keys(caps).length > 0, "should have capabilities in DB"); |
|
|
| assert.ok(caps.openai, "openai capabilities should exist"); |
| assert.ok(caps.openai["gpt-4o"], "gpt-4o capabilities should exist"); |
| assert.equal(caps.openai["gpt-4o"].tool_call, true); |
| assert.equal(caps.openai["gpt-4o"].reasoning, false); |
| assert.equal(caps.openai["gpt-4o"].attachment, true); |
|
|
| |
| const specificCaps = getSyncedCapabilities("openai", "gpt-4o"); |
| assert.ok(specificCaps.openai, "specific query should return openai"); |
| assert.ok(specificCaps.openai["gpt-4o"], "specific query should return gpt-4o"); |
| assert.equal(specificCaps.openai["gpt-4o"].limit_context, 128000); |
|
|
| |
| clearModelsDevPricing(); |
| clearModelsDevCapabilities(); |
|
|
| const afterPricing = getModelsDevPricing(); |
| assert.equal(Object.keys(afterPricing).length, 0, "pricing should be cleared"); |
|
|
| const afterCaps = getSyncedCapabilities(); |
| assert.equal(Object.keys(afterCaps).length, 0, "capabilities should be cleared"); |
| }); |
|
|
| it("dryRun returns data without saving to DB", async () => { |
| const { syncModelsDev, getModelsDevPricing, clearModelsDevPricing } = |
| await import("../../src/lib/modelsDevSync.ts"); |
|
|
| |
| clearModelsDevPricing(); |
|
|
| const result = await syncModelsDev({ dryRun: true, syncCapabilities: false }); |
| assert.equal(result.success, true); |
| assert.ok(result.data, "dryRun should return data"); |
| assert.ok(result.data.pricing, "dryRun should return pricing data"); |
|
|
| |
| const pricing = getModelsDevPricing(); |
| assert.equal(Object.keys(pricing).length, 0, "dryRun should not save to DB"); |
| }); |
|
|
| it("sync without capabilities only saves pricing", async () => { |
| const { |
| syncModelsDev, |
| getModelsDevPricing, |
| getSyncedCapabilities, |
| clearModelsDevPricing, |
| clearModelsDevCapabilities, |
| } = await import("../../src/lib/modelsDevSync.ts"); |
|
|
| clearModelsDevPricing(); |
| clearModelsDevCapabilities(); |
|
|
| const result = await syncModelsDev({ dryRun: false, syncCapabilities: false }); |
| assert.equal(result.success, true); |
| assert.ok(result.modelCount > 0, "should have pricing entries"); |
| assert.equal(result.capabilityCount, 0, "capabilityCount should be 0 when disabled"); |
|
|
| |
| const pricing = getModelsDevPricing(); |
| assert.ok(Object.keys(pricing).length > 0, "pricing should be saved"); |
|
|
| |
| const caps = getSyncedCapabilities(); |
| assert.equal(Object.keys(caps).length, 0, "capabilities should not be saved"); |
|
|
| clearModelsDevPricing(); |
| }); |
| }); |
|
|
| describe("modelsDevSync — resolution order: user > models.dev > LiteLLM > default", () => { |
| it("returns models.dev pricing when no user override exists", async () => { |
| const { syncModelsDev, getModelsDevPricing, clearModelsDevPricing } = |
| await import("../../src/lib/modelsDevSync.ts"); |
|
|
| clearModelsDevPricing(); |
| await syncModelsDev({ dryRun: false, syncCapabilities: false }); |
|
|
| const pricing = getModelsDevPricing(); |
| assert.ok(pricing.openai, "openai pricing should exist"); |
| assert.ok(pricing.openai["gpt-4o"], "gpt-4o should have models.dev pricing"); |
|
|
| clearModelsDevPricing(); |
| }); |
|
|
| it("getPricing() merges all layers correctly", async () => { |
| const { getPricing } = await import("../../src/lib/db/settings.ts"); |
| const { syncModelsDev, clearModelsDevPricing, saveModelsDevPricing } = |
| await import("../../src/lib/modelsDevSync.ts"); |
| const { updatePricing, resetPricing } = await import("../../src/lib/db/settings.ts"); |
|
|
| |
| clearModelsDevPricing(); |
|
|
| |
| await syncModelsDev({ dryRun: false, syncCapabilities: false }); |
|
|
| |
| const merged = await getPricing(); |
|
|
| |
| assert.ok(merged.openai || merged.cx, "should have openai/cx pricing in merged result"); |
|
|
| |
| await updatePricing({ |
| openai: { |
| "gpt-4o": { input: 999, output: 999 }, |
| }, |
| }); |
|
|
| |
| const mergedWithOverride = await getPricing(); |
| assert.equal( |
| mergedWithOverride.openai?.["gpt-4o"]?.input, |
| 999, |
| "user override should win over models.dev" |
| ); |
|
|
| |
| await resetPricing("openai", "gpt-4o"); |
| clearModelsDevPricing(); |
| }); |
| }); |
|
|