From ab9501efaf376f7b3168449b5d15548e48521057 Mon Sep 17 00:00:00 2001 From: Automation Date: Sat, 23 May 2026 18:06:40 +0200 Subject: [PATCH] fix(catalog): skip static PROVIDER_MODELS when synced models exist When auto-sync fetches models from a provider's API, the static hardcoded PROVIDER_MODELS entries in providerRegistry.ts remained in the catalog output alongside the up-to-date synced list. This left stale/deprecated models visible in the model listing. Fix: hoist getAllSyncedAvailableModels() before the PROVIDER_MODELS loop and skip static entries for any provider that has a non-empty synced model list. The synced list is the authoritative source when auto-sync is active. Changes in src/app/api/v1/models/catalog.ts: - Import SyncedAvailableModel type - Load synced models + build providersWithSyncedModels Set before iterating PROVIDER_MODELS - Skip static models when providersWithSyncedModels has the provider - Remove const redeclaration of syncedModelsByProvider in the existing synced models section (uses hoisted variable) Review feedback addressed: - Add error logging to catch block (was silent) - Replace redundant DB fetch with comment (data already loaded) --- src/app/api/v1/models/catalog.ts | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/app/api/v1/models/catalog.ts b/src/app/api/v1/models/catalog.ts index cee4614b4331..8f634c1b8383 100644 --- a/src/app/api/v1/models/catalog.ts +++ b/src/app/api/v1/models/catalog.ts @@ -18,7 +18,7 @@ import { getAllMusicModels } from "@omniroute/open-sse/config/musicRegistry"; import { REGISTRY } from "@omniroute/open-sse/config/providerRegistry"; import { CODEX_NATIVE_UNPREFIXED_MODELS } from "@omniroute/open-sse/services/model"; import { resolveNestedComboTargets } from "@omniroute/open-sse/services/combo"; -import { getAllSyncedAvailableModels } from "@/lib/db/models"; +import { getAllSyncedAvailableModels, type SyncedAvailableModel } from "@/lib/db/models"; import { getCompatibleFallbackModels } from "@/lib/providers/managedAvailableModels"; import { hasEligibleConnectionForModel } from "@/domain/connectionModelRules"; import { @@ -596,6 +596,22 @@ export async function getUnifiedModelsResponse( }); } + // Resolve synced available models (from auto-sync) — used to skip static + // PROVIDER_MODELS entries for providers that have a live, API-fresh list. + let syncedModelsByProvider: Record = {}; + try { + syncedModelsByProvider = await getAllSyncedAvailableModels(); + } catch (e) { + // DB unavailable — log and fall through; static models remain as defaults. + console.log("[catalog] Could not fetch synced available models:", e); + } + const providersWithSyncedModels = new Set( + Object.keys(syncedModelsByProvider).filter((pid) => { + const models = syncedModelsByProvider[pid]; + return Array.isArray(models) && models.length > 0; + }) + ); + // Add provider models (chat) for (const [alias, providerModels] of Object.entries(PROVIDER_MODELS)) { const providerId = aliasToProviderId[alias] || alias; @@ -609,6 +625,10 @@ export async function getUnifiedModelsResponse( continue; } + // Skip static models for providers that have synced available models + // (auto-sync provides the authoritative, up-to-date list from the API). + if (providersWithSyncedModels.has(canonicalProviderId)) continue; + for (const model of providerModels) { if (!providerSupportsModel(canonicalProviderId, model.id)) continue; const aliasId = `${alias}/${model.id}`; @@ -676,7 +696,8 @@ export async function getUnifiedModelsResponse( } try { - const syncedModelsByProvider = await getAllSyncedAvailableModels(); + // Data already loaded above into syncedModelsByProvider; the try block + // here protects the for-loop / model processing from unexpected errors. for (const [providerId, syncedModels] of Object.entries(syncedModelsByProvider)) { if (!Array.isArray(syncedModels) || syncedModels.length === 0) continue; if (blockedProviders.has(providerId)) continue;