( options: GetModelsOptions | ProviderName, )
| 431 | * @returns Models from memory cache, disk cache, or undefined if not cached. |
| 432 | */ |
| 433 | export function getModelsFromCache( |
| 434 | options: GetModelsOptions | ProviderName, |
| 435 | ): ModelRecord | undefined { |
| 436 | // Auth-scoped providers (e.g. zoo-gateway) must never be served from cache -- |
| 437 | // their model lists are user-specific and a stale file left over from a previous |
| 438 | // session could leak another user's list. Mirror the guards in getModels/refreshModels. |
| 439 | const providerName = typeof options === "string" ? options : options.provider |
| 440 | if (isAuthScopedProvider(providerName as RouterName)) { |
| 441 | return undefined |
| 442 | } |
| 443 | |
| 444 | const cacheKey = typeof options === "string" ? options : getCacheKey(options) |
| 445 | // Check memory cache first (fast) |
| 446 | const memoryModels = memoryCache.get<ModelRecord>(cacheKey) |
| 447 | if (memoryModels) { |
| 448 | return memoryModels |
| 449 | } |
| 450 | |
| 451 | // Memory cache miss - try to load from disk synchronously |
| 452 | // This is acceptable because it only happens on cold start or after cache expiry |
| 453 | try { |
| 454 | const filename = `${cacheKeyToFilename(cacheKey)}_models.json` |
| 455 | const cacheDir = getCacheDirectoryPathSync() |
| 456 | if (!cacheDir) { |
| 457 | return undefined |
| 458 | } |
| 459 | |
| 460 | const filePath = path.join(cacheDir, filename) |
| 461 | |
| 462 | // Use synchronous fs to avoid async complexity in getModel() callers |
| 463 | if (fsSync.existsSync(filePath)) { |
| 464 | const data = fsSync.readFileSync(filePath, "utf8") |
| 465 | const models = JSON.parse(data) |
| 466 | |
| 467 | // Validate the disk cache data structure using Zod schema |
| 468 | // This ensures the data conforms to ModelRecord = Record<string, ModelInfo> |
| 469 | const validation = modelRecordSchema.safeParse(models) |
| 470 | if (!validation.success) { |
| 471 | console.error( |
| 472 | `[MODEL_CACHE] Invalid disk cache data structure for ${cacheKey}:`, |
| 473 | validation.error.format(), |
| 474 | ) |
| 475 | return undefined |
| 476 | } |
| 477 | |
| 478 | // Populate memory cache for future fast access |
| 479 | memoryCache.set(cacheKey, validation.data) |
| 480 | |
| 481 | return validation.data |
| 482 | } |
| 483 | } catch (error) { |
| 484 | console.error(`[MODEL_CACHE] Error loading ${cacheKey} models from disk:`, error) |
| 485 | } |
| 486 | |
| 487 | return undefined |
| 488 | } |
| 489 | |
| 490 | /** |
no test coverage detected