diff --git a/src/lib/db/models/activeSyncedCatalog.ts b/src/lib/db/models/activeSyncedCatalog.ts index 4e68a17d2b..9c34f685dd 100644 --- a/src/lib/db/models/activeSyncedCatalog.ts +++ b/src/lib/db/models/activeSyncedCatalog.ts @@ -184,10 +184,12 @@ async function unionCustomModels( */ async function loadConnectionCatalog(storedProviderId: string): Promise { const [connections, modelsByConnection] = await Promise.all([ - getRawProviderConnections({ provider: storedProviderId, isActive: true }, undefined, undefined, [ - "id", - "provider", - ]), + getRawProviderConnections( + { provider: storedProviderId, isActive: true }, + undefined, + undefined, + ["id", "provider"] + ), getSyncedAvailableModelsByConnection(storedProviderId), ]); @@ -248,6 +250,18 @@ export async function getActiveSyncedCatalog(providerId: string): Promise`) and demote the + * embedding/rerank registry's canonical `jina-ai/` to a child — the inverse of + * the identity every other specialty model of that provider carries. */ export async function getAllActiveSyncedModels(): Promise> { try { @@ -277,10 +291,7 @@ export async function getAllActiveSyncedModels(): Promise 0) { diff --git a/tests/unit/custom-models-live-catalog-12597.test.ts b/tests/unit/custom-models-live-catalog-12597.test.ts index 4e6bb35068..b81745aeb9 100644 --- a/tests/unit/custom-models-live-catalog-12597.test.ts +++ b/tests/unit/custom-models-live-catalog-12597.test.ts @@ -14,10 +14,14 @@ process.env.DATA_DIR = TEST_DATA_DIR; process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "custom-live-12597-test-secret"; const core = await import("../../src/lib/db/core.ts"); -const { addCustomModel, replaceSyncedAvailableModelsForConnection, getActiveProvidersWithSyncedModel } = - await import("../../src/lib/db/models.ts"); +const { + addCustomModel, + replaceSyncedAvailableModelsForConnection, + getActiveProvidersWithSyncedModel, +} = await import("../../src/lib/db/models.ts"); const { getActiveSyncedCatalog, + getAllActiveSyncedModels, catalogContainsModel, reconcileProvidersWithActiveSyncedCatalog, } = await import("../../src/lib/db/models/activeSyncedCatalog.ts"); @@ -124,6 +128,21 @@ test("#12597 sparse custom overlay does not wipe synced capability fields", asyn assert.deepEqual(match?.supportedThinkingEfforts, ["low", "high"]); }); +test("#12597 the union is dispatch-only — getAllActiveSyncedModels stays live-sync-shaped", async () => { + await addCustomModel(PROVIDER, PICKER_MODEL, "DeepSeek R1 via picker"); + + const allActive = await getAllActiveSyncedModels(); + const ids = (allActive[PROVIDER] ?? []).map((model) => model.id); + + assert.deepEqual( + ids, + [SYNCED_MODEL], + "getAllActiveSyncedModels reports what the provider's live sync returned; its consumers (/v1/models' synced loop, /api/models' exclusive-listing suppression, getSyncedAutoAliases) each handle custom rows on their own" + ); + // The dispatch-time readers still see it — that is what #12597 fixed. + assert.equal(catalogContainsModel(await getActiveSyncedCatalog(PROVIDER), PICKER_MODEL), true); +}); + test("#12597 without a custom row the picker id is still absent (lock the old contract)", async () => { const catalog = await getActiveSyncedCatalog(PROVIDER); assert.equal(catalogContainsModel(catalog, PICKER_MODEL), false);