import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs"; import { homedir } from "node:os"; import { dirname, join } from "node:path"; export const NIM_CACHE_PATH = join(homedir(), ".pi", "nvidia-nim-cache.json"); export const NIM_BASE_URL = "https://integrate.api.nvidia.com/v1"; export const CACHE_TTL_MS = 24 * 60 * 60 * 1000; export interface NimCacheFile { fetchedAt: string; models: Array<{ id: string; owned_by?: string }>; } export function readCache(): NimCacheFile | null { try { if (!existsSync(NIM_CACHE_PATH)) return null; return JSON.parse(readFileSync(NIM_CACHE_PATH, "utf8")) as NimCacheFile; } catch { return null; } } export function writeCache(data: NimCacheFile): void { const dir = dirname(NIM_CACHE_PATH); if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); writeFileSync(NIM_CACHE_PATH, JSON.stringify(data, null, 2), "utf8"); } export function isCacheFresh(cache: NimCacheFile | null, now = Date.now()): boolean { if (!cache?.fetchedAt) return false; const age = now - Date.parse(cache.fetchedAt); return Number.isFinite(age) && age >= 0 && age < CACHE_TTL_MS; } export async function fetchNimModelIds(apiKey?: string): Promise { const key = apiKey ?? process.env.NVIDIA_NIM_API_KEY ?? process.env.NVIDIA_API_KEY; if (!key) { throw new Error("NVIDIA API key required (NVIDIA_NIM_API_KEY or NVIDIA_API_KEY)"); } const res = await fetch(`${NIM_BASE_URL}/models`, { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(15_000), }); if (!res.ok) { throw new Error(`NIM /models returned HTTP ${res.status}`); } const body = (await res.json()) as { data?: Array<{ id: string }> }; return (body.data ?? []).map((m) => m.id).filter(Boolean); } export async function refreshCacheIfStale(force = false): Promise { const existing = readCache(); if (!force && isCacheFresh(existing)) return existing; try { const ids = await fetchNimModelIds(); const next: NimCacheFile = { fetchedAt: new Date().toISOString(), models: ids.map((id) => ({ id })), }; writeCache(next); return next; } catch { return existing; } }