import { Database } from "bun:sqlite"; import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import * as fs from "node:fs/promises"; import * as os from "node:os"; import * as path from "node:path"; import type { Model } from "@oh-my-pi/pi-ai/types"; import { buildModel } from "@oh-my-pi/pi-catalog/build"; import { readModelCache, writeModelCache } from "@oh-my-pi/pi-catalog/model-cache"; const TTL_MS = 24 * 60 * 60 * 1000; function createModel(id: string, name: string): Model<"openai-completions"> { return buildModel({ id, name, api: "openai-completions", provider: "ollama-cloud", baseUrl: "https://ollama.com/v1", reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, }, contextWindow: 4096, maxTokens: 1024, }); } describe("model cache migrations", () => { let tempDir = ""; let dbPath = ""; beforeEach(async () => { tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "pi-ai-model-cache-")); dbPath = path.join(tempDir, "models.db"); }); afterEach(async () => { if (tempDir) { await fs.rm(tempDir, { recursive: true, force: true }); tempDir = ""; dbPath = ""; } }); it("preserves v2 cached models and lets the next discovery overwrite them", () => { const legacyModel = createModel("legacy-cloud-model", "Legacy Cloud Model"); const legacyDb = new Database(dbPath, { create: true }); legacyDb.run(` CREATE TABLE model_cache ( provider_id TEXT PRIMARY KEY, version INTEGER NOT NULL, updated_at INTEGER NOT NULL, authoritative INTEGER NOT NULL DEFAULT 0, models TEXT NOT NULL ) `); legacyDb.run( "INSERT INTO model_cache (provider_id, version, updated_at, authoritative, models) VALUES (?, ?, ?, ?, ?)", ["ollama-cloud", 2, Date.now(), 1, JSON.stringify([legacyModel])], ); legacyDb.close(); const migrated = readModelCache<"openai-completions">("ollama-cloud", TTL_MS, Date.now, dbPath); expect(migrated?.models.map(model => model.id)).toEqual(["legacy-cloud-model"]); expect(migrated?.staticFingerprint).toBe(""); const replacementModel = createModel("fresh-cloud-model", "Fresh Cloud Model"); writeModelCache("ollama-cloud", Date.now(), [replacementModel], true, "static-v3", dbPath); const overwritten = readModelCache<"openai-completions">("ollama-cloud", TTL_MS, Date.now, dbPath); expect(overwritten?.models.map(model => model.id)).toEqual(["fresh-cloud-model"]); expect(overwritten?.staticFingerprint).toBe("static-v3"); }); });