fix: reconcile active live model catalogs (#9294)

Validated in post-merge-train sweep (boards clean on release/v3.8.50 tip)
This commit is contained in:
Aman
2026-08-06 08:08:23 -06:00
committed by GitHub
parent a598fbb090
commit d69f521491
11 changed files with 658 additions and 54 deletions

View File

@@ -180,6 +180,24 @@ export function getRegistryEntry(provider: string): RegistryEntry | null {
return REGISTRY[provider] || _byAlias.get(provider) || null;
}
/**
* Decide whether a non-empty live catalog may exclude omitted static models
* during request routing and wildcard expansion.
*
* Live discovery is authoritative by default, including for dynamic providers.
* Providers with intentionally partial discovery must explicitly opt out in
* their registry entry.
*/
export function providerUsesAuthoritativeLiveCatalog(provider: string): boolean {
const entry = getRegistryEntry(provider);
if (entry && typeof entry.liveCatalogAuthoritative === "boolean") {
return entry.liveCatalogAuthoritative;
}
return true;
}
/** Get all registered provider IDs */
export function getRegisteredProviders(): string[] {
return Object.keys(REGISTRY);

View File

@@ -8,6 +8,9 @@ export const command_codeProvider: RegistryEntry = {
baseUrl: "https://api.commandcode.ai",
chatPath: "/alpha/generate",
modelsUrl: "https://api.commandcode.ai/provider/v1/models",
// The discovery response is a partial routing catalog; static registry
// entries omitted from it can still be accepted by the gateway.
liveCatalogAuthoritative: false,
authType: "apikey",
authHeader: "Authorization",
authPrefix: "Bearer ",

View File

@@ -139,6 +139,15 @@ export interface RegistryEntry {
clientVersion?: string;
timeoutMs?: number;
passthroughModels?: boolean;
/**
* Whether a non-empty synchronized live model list is exhaustive enough
* to reject static registry IDs that it omits.
*
* Defaults to true. Set this explicitly to false for providers whose
* discovery endpoint is known to return only a partial subset of the models
* that the provider can route.
*/
liveCatalogAuthoritative?: boolean;
/** Default context window for all models in this provider (can be overridden per-model) */
defaultContextLength?: number;
/** Maximum OpenAI-compatible function name length accepted by this provider. */

View File

@@ -31,7 +31,7 @@
import { wildcardMatch } from "../wildcardRouter.ts";
import { getProviderModels } from "../../config/providerModels.ts";
import { getSyncedAvailableModels } from "../../../src/lib/db/models.ts";
import { getActiveSyncedCatalog } from "../../../src/lib/db/models/activeSyncedCatalog.ts";
import type { ComboLike } from "./types.ts";
/** Sentinel pattern used for "all models of a provider". */
@@ -116,39 +116,18 @@ function parseWildcardEntry(entry: unknown): ProviderWildcardSpec | null {
}
/**
* Collect candidate model IDs for a provider from two sources:
* 1. Synced available models in the DB (runtime-dynamic; custom/OAuth providers)
* 2. Static provider registry (built-in providers bundled with the release)
*
* The union is deduped by model id.
* Collect candidate model IDs using the active synced catalog as the
* authoritative source when it is non-empty. Static registry models remain a
* fail-open fallback when no active usable catalog exists.
*/
async function collectProviderModelIds(providerId: string): Promise<string[]> {
const seen = new Set<string>();
const ids: string[] = [];
const liveCatalog = await getActiveSyncedCatalog(providerId);
// 1. Synced DB models (highest priority — reflects the live catalog)
try {
const synced = await getSyncedAvailableModels(providerId);
for (const m of synced) {
if (m.id && !seen.has(m.id)) {
seen.add(m.id);
ids.push(m.id);
}
}
} catch {
// Non-fatal — DB may be offline in tests or at early init.
if (liveCatalog.authoritative) {
return liveCatalog.models.map((model) => model.id);
}
// 2. Static registry models (fallback / built-in providers)
const registryModels = getProviderModels(providerId);
for (const m of registryModels) {
if (m.id && !seen.has(m.id)) {
seen.add(m.id);
ids.push(m.id);
}
}
return ids;
return getProviderModels(providerId).map((model) => model.id);
}
/**

View File

@@ -1,5 +1,6 @@
import { PROVIDER_ID_TO_ALIAS, PROVIDER_MODELS } from "../config/providerModels.ts";
import { resolveWildcardAlias } from "./wildcardRouter.ts";
import { getRegisteredProviderEffortBaseModelId } from "../utils/registeredEffortVariants.ts";
type ProviderModelAliasMap = Record<string, Record<string, string>>;
type ModelAliasValue = string | { provider?: string; model?: string };
@@ -341,6 +342,48 @@ async function getActiveSyncedProvidersForModel(modelId: string) {
}
}
async function reconcileInferredProvidersWithActiveCatalog(providerIds: string[], modelId: string) {
const uniqueProviders = Array.from(new Set(providerIds));
try {
const { reconcileProvidersWithActiveSyncedCatalog } =
await import("@/lib/db/models/activeSyncedCatalog");
const reconciliations = await Promise.all(
uniqueProviders.map(async (provider) => {
const effortBaseModelId = getRegisteredProviderEffortBaseModelId(provider, modelId);
const catalogModelId = effortBaseModelId ?? modelId;
const reconciliation = await reconcileProvidersWithActiveSyncedCatalog(
[provider],
catalogModelId
);
return {
provider,
allowed: reconciliation.providers.includes(provider),
excluded: reconciliation.excludedProviders.includes(provider),
};
})
);
return {
providers: reconciliations
.filter((result) => result.allowed)
.map((result) => result.provider),
excludedProviders: reconciliations
.filter((result) => result.excluded)
.map((result) => result.provider),
};
} catch {
return {
providers: uniqueProviders,
excludedProviders: [],
};
}
}
function isTruthyEnv(value: string | undefined) {
return typeof value === "string" && /^(1|true|yes|on)$/i.test(value.trim());
}
@@ -597,19 +640,22 @@ async function resolveModelByProviderInference(modelId: string, extendedContext:
};
}
}
// #FIX: synced catalogs (populated from `/v1/models` per connection) can
// claim ownership of models the provider does not actually serve (e.g. a
// `kiro` upstream briefly advertising `claude-opus-5` before it was
// vendored into the registry). Without this filter the bare-routing path
// would forward traffic to providers that 404 on the upstream call.
// Auto-discovery still wins when no static registry entry exists for the
// model id — only entries that conflict with the static catalog are dropped.
const staticCatalogProviders = MODEL_TO_PROVIDERS.get(modelId) || [];
const validatedSyncedProviders =
staticCatalogProviders.length > 0
? activeSyncedProviders.filter((p) => staticCatalogProviders.includes(p))
: activeSyncedProviders;
const providers = getInferredProvidersForModel(modelId, validatedSyncedProviders);
const candidateProviders = getInferredProvidersForModel(modelId, activeSyncedProviders);
const { providers, excludedProviders } = await reconcileInferredProvidersWithActiveCatalog(
candidateProviders,
modelId
);
if (providers.length === 0 && excludedProviders.length > 0) {
return {
provider: null,
model: modelId,
extendedContext,
errorType: "model_not_found",
errorMessage: `Model '${modelId}' is not available in the active live catalog for provider(s): ${excludedProviders.join(", ")}.`,
};
}
const nonOpenAIProviders = providers.filter((p) => p !== "openai");
// Bare model IDs from Codex CLI do not preserve OmniRoute's `cx/` prefix.
@@ -686,6 +732,25 @@ async function resolveModelByProviderInference(modelId: string, extendedContext:
activeCandidates = canonicalCandidates.filter((p) => activeProviders.has(p));
}
// An authoritative active live catalog excluded at least one static
// candidate, and none of the remaining static candidates has an active
// connection. Do not escape the live-catalog decision by selecting an
// unrelated inactive provider that happens to share the same static model id.
if (
activeProviders &&
activeProviders.size > 0 &&
activeCandidates.length === 0 &&
excludedProviders.length > 0
) {
return {
provider: null,
model: modelId,
extendedContext,
errorType: "model_not_found",
errorMessage: `Model '${modelId}' is not available in the active live catalog for provider(s): ${excludedProviders.join(", ")}.`,
};
}
// Auto-pick:
// 1. If active providers match, pick from active candidates (first active provider).
// 2. If no active providers filter applied, but canonical candidates deduplicate to 1 provider, pick it.

View File

@@ -0,0 +1,36 @@
import { getProviderModels } from "../config/providerModels.ts";
const REGISTERED_EFFORT_SUFFIXES = ["none", "low", "medium", "high", "max", "xhigh"] as const;
/**
* Return the registered base model for an explicit effort variant.
*
* Both the exact variant and its base must exist in the provider registry.
* Callers with an authoritative live catalog must additionally verify that
* the returned base model is present in that live catalog.
*/
export function getRegisteredProviderEffortBaseModelId(
providerId: string,
modelId: string
): string | null {
const providerModels = getProviderModels(providerId);
if (!providerModels.some((candidate) => candidate.id === modelId)) {
return null;
}
for (const effort of REGISTERED_EFFORT_SUFFIXES) {
const suffix = `-${effort}`;
if (!modelId.endsWith(suffix)) continue;
const baseModelId = modelId.slice(0, -suffix.length);
return providerModels.some((candidate) => candidate.id === baseModelId) ? baseModelId : null;
}
return null;
}
export function isRegisteredProviderEffortVariant(providerId: string, modelId: string): boolean {
return getRegisteredProviderEffortBaseModelId(providerId, modelId) !== null;
}

View File

@@ -37,7 +37,8 @@ import {
createBuiltinAutoCombo,
isPaidTierAutoId,
} from "@omniroute/open-sse/services/autoCombo/builtinCatalog";
import { getAllSyncedAvailableModels, type SyncedAvailableModel } from "@/lib/db/models";
import type { SyncedAvailableModel } from "@/lib/db/models";
import { getAllActiveSyncedModels } from "@/lib/db/models/activeSyncedCatalog";
import { getModelCatalogCacheVersion } from "@/lib/db/readCache";
import { getCompatibleFallbackModels } from "@/lib/providers/managedAvailableModels";
import { providerUsesCuratedModelsOnly } from "@/lib/providers/modelListingCapability";
@@ -676,7 +677,7 @@ async function buildUnifiedModelsResponseCore(
let syncedModelsByProvider: Record<string, SyncedAvailableModel[]> = {};
try {
syncedModelsByProvider = await getAllSyncedAvailableModels();
syncedModelsByProvider = await getAllActiveSyncedModels();
} catch (e) {
// DB unavailable — log and fall through; static models remain as defaults.
console.log("[catalog] Could not fetch synced available models:", e);

View File

@@ -0,0 +1,197 @@
import { providerUsesAuthoritativeLiveCatalog } from "@omniroute/open-sse/config/providerRegistry";
import { PROVIDER_ID_TO_ALIAS } from "@omniroute/open-sse/config/providerModels.ts";
import { getSyncedAvailableModelsByConnection, type SyncedAvailableModel } from "../models";
import { getRawProviderConnections } from "../providers";
export type ActiveSyncedCatalog = {
authoritative: boolean;
models: SyncedAvailableModel[];
};
export type ProviderCatalogReconciliation = {
providers: string[];
excludedProviders: string[];
};
type ProviderConnectionRef = {
id: string;
provider: string;
};
function resolveStoredProviderId(aliasOrId: string): string {
const normalized = aliasOrId.trim();
if (!normalized) return "";
if (Object.prototype.hasOwnProperty.call(PROVIDER_ID_TO_ALIAS, normalized)) {
return normalized;
}
for (const [providerId, alias] of Object.entries(PROVIDER_ID_TO_ALIAS)) {
if (alias === normalized) return providerId;
}
return normalized;
}
function readConnectionRef(connection: unknown): ProviderConnectionRef | null {
if (!connection || typeof connection !== "object") return null;
const record = connection as {
id?: unknown;
provider?: unknown;
};
if (
typeof record.id !== "string" ||
record.id.length === 0 ||
typeof record.provider !== "string" ||
record.provider.length === 0
) {
return null;
}
return {
id: record.id,
provider: record.provider,
};
}
function collectModelsForConnections(
modelsByConnection: Record<string, SyncedAvailableModel[]>,
connectionIds: Iterable<string>
): SyncedAvailableModel[] {
const models = new Map<string, SyncedAvailableModel>();
for (const connectionId of connectionIds) {
for (const model of modelsByConnection[connectionId] || []) {
if (!model?.id || models.has(model.id)) continue;
models.set(model.id, model);
}
}
return Array.from(models.values());
}
/**
* Return the unioned synced catalog belonging only to active connections.
*
* A provider is authoritative only when at least one active connection has a
* non-empty usable catalog. Missing, empty, malformed, or unavailable state
* fails open to the static registry.
*/
export async function getActiveSyncedCatalog(providerId: string): Promise<ActiveSyncedCatalog> {
const storedProviderId = resolveStoredProviderId(providerId);
if (!storedProviderId) {
return { authoritative: false, models: [] };
}
try {
const [connections, modelsByConnection] = await Promise.all([
getRawProviderConnections(
{ provider: storedProviderId, isActive: true },
undefined,
undefined,
["id", "provider"]
),
getSyncedAvailableModelsByConnection(storedProviderId),
]);
const activeConnectionIds = connections
.map(readConnectionRef)
.filter((connection): connection is ProviderConnectionRef => connection !== null)
.map((connection) => connection.id);
const models = collectModelsForConnections(modelsByConnection, activeConnectionIds);
return {
authoritative: models.length > 0 && providerUsesAuthoritativeLiveCatalog(providerId),
models,
};
} catch {
return { authoritative: false, models: [] };
}
}
/**
* Return non-empty synced catalogs grouped by provider, restricted to active
* connections. This is the authoritative live source for /v1/models.
*/
export async function getAllActiveSyncedModels(): Promise<Record<string, SyncedAvailableModel[]>> {
try {
const connections = await getRawProviderConnections({ isActive: true }, undefined, undefined, [
"id",
"provider",
]);
const connectionIdsByProvider = new Map<string, Set<string>>();
for (const rawConnection of connections) {
const connection = readConnectionRef(rawConnection);
if (!connection) continue;
if (!connectionIdsByProvider.has(connection.provider)) {
connectionIdsByProvider.set(connection.provider, new Set());
}
connectionIdsByProvider.get(connection.provider)!.add(connection.id);
}
const result: Record<string, SyncedAvailableModel[]> = {};
await Promise.all(
Array.from(connectionIdsByProvider.entries()).map(async ([providerId, connectionIds]) => {
const modelsByConnection = await getSyncedAvailableModelsByConnection(providerId);
const models = collectModelsForConnections(modelsByConnection, connectionIds);
if (models.length > 0) {
result[providerId] = models;
}
})
);
return result;
} catch {
return {};
}
}
/**
* Remove static provider candidates whose active live catalog exists but does
* not contain the requested model. Providers without a usable live catalog
* retain their static fallback behavior.
*/
export async function reconcileProvidersWithActiveSyncedCatalog(
providerIds: string[],
modelId: string
): Promise<ProviderCatalogReconciliation> {
const uniqueProviders = Array.from(
new Set(
providerIds.filter(
(provider): provider is string => typeof provider === "string" && provider.length > 0
)
)
);
const states = await Promise.all(
uniqueProviders.map(async (provider) => ({
provider,
catalog: await getActiveSyncedCatalog(provider),
}))
);
const providers: string[] = [];
const excludedProviders: string[] = [];
for (const { provider, catalog } of states) {
const modelIsLive = catalog.models.some((model) => model.id === modelId);
if (!catalog.authoritative || modelIsLive) {
providers.push(provider);
} else {
excludedProviders.push(provider);
}
}
return { providers, excludedProviders };
}

View File

@@ -8,7 +8,7 @@ import {
getCustomModels,
} from "@/lib/localDb";
import { getCachedSettings } from "@/lib/localDb";
import { getSyncedAvailableModels } from "@/lib/db/models";
import { getActiveSyncedCatalog } from "@/lib/db/models/activeSyncedCatalog";
import {
parseModel,
getModelInfoCore,
@@ -16,6 +16,7 @@ import {
stripContextWindowSuffix,
} from "@omniroute/open-sse/services/model.ts";
import { REGISTRY } from "@omniroute/open-sse/config/providerRegistry.ts";
import { getRegisteredProviderEffortBaseModelId } from "@omniroute/open-sse/utils/registeredEffortVariants.ts";
export { parseModel, stripContextWindowSuffix };
@@ -210,12 +211,18 @@ function buildRuntimeModelMeta(customMatch: any, syncedMatch: any): RuntimeModel
async function lookupModelMeta(
providerId: string,
modelId: string
): Promise<{ modelId: string; metadata: RuntimeModelMeta }> {
): Promise<{
modelId: string;
metadata: RuntimeModelMeta;
available: boolean;
}> {
try {
const [customModels, syncedModels] = await Promise.all([
const [customModels, liveCatalog] = await Promise.all([
getCustomModels(providerId),
getSyncedAvailableModels(providerId),
getActiveSyncedCatalog(providerId),
]);
const syncedModels = liveCatalog.models;
// #7694: no direct match on the raw modelId? try a synced-declared `-{effort}`
// suffix before falling back to the literal id, so `<prefix>/<model>-<tier>`
// resolves to the real base model + a resolved effort.
@@ -224,15 +231,25 @@ async function lookupModelMeta(
modelId,
syncedModels
);
// #7364: exact match first; retain the case-insensitive custom-model fallback
// while also consulting the API-synced catalog for Kimi runtime metadata.
// Custom models remain explicit operator overrides even when live discovery
// is authoritative for the provider.
const customMatch = findCustomModelMeta(customModels, resolvedModelId);
const syncedMatch = findSyncedModelMeta(syncedModels, resolvedModelId);
const effortBaseModelId = getRegisteredProviderEffortBaseModelId(providerId, modelId);
const liveBackedEffortVariant =
effortBaseModelId !== null && syncedModels.some((model) => model.id === effortBaseModelId);
const available =
!liveCatalog.authoritative || Boolean(customMatch || syncedMatch || liveBackedEffortVariant);
const metadata = buildRuntimeModelMeta(customMatch, syncedMatch);
if (effort) metadata.resolvedThinkingEffort = effort;
return { modelId: resolvedModelId, metadata };
return { modelId: resolvedModelId, metadata, available };
} catch {
return { modelId, metadata: {} };
return { modelId, metadata: {}, available: true };
}
}
@@ -261,8 +278,23 @@ export async function getModelInfo(modelStr) {
const attachRuntimeModelMeta = async (info: any) => {
if (!info?.provider || !info?.model) return info;
const { modelId, metadata } = await lookupModelMeta(String(info.provider), String(info.model));
const providerId = String(info.provider);
const requestedModelId = String(info.model);
const { modelId, metadata, available } = await lookupModelMeta(providerId, requestedModelId);
if (!available) {
return {
provider: null,
model: requestedModelId,
extendedContext: info.extendedContext,
errorType: "model_not_found",
errorMessage: `Model '${requestedModelId}' is not available in the active live catalog for provider '${providerId}'.`,
};
}
const resolvedInfo = modelId !== info.model ? { ...info, model: modelId } : info;
return Object.keys(metadata).length > 0 ? { ...resolvedInfo, ...metadata } : resolvedInfo;
};

View File

@@ -43,7 +43,21 @@ function makeCombo(models: unknown[], name = "test-combo") {
}
// Seed synced models for a provider into the DB.
async function seedSyncedModels(providerId: string, connectionId: string, modelIds: string[]) {
async function seedSyncedModels(
providerId: string,
connectionId: string,
modelIds: string[],
isActive = true
) {
const db = core.getDbInstance();
const now = new Date().toISOString();
db.prepare(
`INSERT OR REPLACE INTO provider_connections
(id, provider, is_active, created_at, updated_at)
VALUES (?, ?, ?, ?, ?)`
).run(connectionId, providerId, isActive ? 1 : 0, now, now);
await replaceSyncedAvailableModelsForConnection(
providerId,
connectionId,
@@ -346,3 +360,49 @@ test("expandProviderWildcardsInCombo: three providers mixed with explicit entrie
assert.equal((result.models[3] as any).model, `${p2}/m-c`);
assert.equal(result.models[4], "openai/gpt-4o");
});
test("#8926: active synced catalog replaces static wildcard entries", async () => {
const providerId = "github";
const liveModelId = "live-only-model-8926";
await seedSyncedModels(providerId, "github-live-8926", [liveModelId]);
const result = await expandProviderWildcardsInCombo(
makeCombo([`${providerId}/*`], "github-live-authority-8926")
);
assert.deepEqual(
result.models.map((entry) => (entry as { model: string }).model),
[`${providerId}/${liveModelId}`],
"an active non-empty synced catalog must replace, not union with, static models"
);
const aliasResult = await expandProviderWildcardsInCombo(
makeCombo(["gh/*"], "github-live-alias-8926")
);
assert.deepEqual(
aliasResult.models.map((entry) => (entry as { model: string }).model),
[`gh/${liveModelId}`],
"the public provider alias must use the canonical provider's active catalog"
);
});
test("#8926: inactive synced catalog does not override static wildcard fallback", async () => {
const providerId = "openai";
const inactiveModelId = "inactive-only-model-8926";
await seedSyncedModels(providerId, "openai-inactive-8926", [inactiveModelId], false);
const result = await expandProviderWildcardsInCombo(
makeCombo([`${providerId}/*`], "openai-static-fallback-8926")
);
const expanded = result.models.map((entry) => (entry as { model: string }).model);
assert.ok(expanded.length > 0, "static fallback should remain available");
assert.ok(
!expanded.includes(`${providerId}/${inactiveModelId}`),
"an inactive connection must not make its synced catalog authoritative"
);
});

View File

@@ -0,0 +1,204 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { providerUsesAuthoritativeLiveCatalog } from "../../open-sse/config/providerRegistry.ts";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-live-catalog-8926-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "live-catalog-8926-test-secret";
const core = await import("../../src/lib/db/core.ts");
const { addCustomModel, replaceSyncedAvailableModelsForConnection } =
await import("../../src/lib/db/models.ts");
const { getActiveSyncedCatalog, getAllActiveSyncedModels } =
await import("../../src/lib/db/models/activeSyncedCatalog.ts");
const { isRegisteredProviderEffortVariant } =
await import("../../open-sse/utils/registeredEffortVariants.ts");
const { getModelInfo } = await import("../../src/sse/services/model.ts");
const { getProviderModels } = await import("../../open-sse/config/providerModels.ts");
const PROVIDER = "github";
const CONNECTION_ID = "github-live-catalog-8926";
const LIVE_MODEL = "gpt-4.1";
const PHANTOM_MODEL = "oswe-vscode-prime";
function seedProviderCatalog(
providerId: string,
connectionId: string,
modelIds: string[],
isActive = true
) {
const db = core.getDbInstance();
const now = new Date().toISOString();
db.prepare(
`INSERT OR REPLACE INTO provider_connections
(id, provider, is_active, created_at, updated_at)
VALUES (?, ?, ?, ?, ?)`
).run(connectionId, providerId, isActive ? 1 : 0, now, now);
return replaceSyncedAvailableModelsForConnection(
providerId,
connectionId,
modelIds.map((id) => ({
id,
name: id,
source: "imported" as const,
}))
);
}
function seedActiveLiveCatalog() {
return seedProviderCatalog(PROVIDER, CONNECTION_ID, [LIVE_MODEL]);
}
test.beforeEach(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
assert.ok(
getProviderModels(PROVIDER).some((model: { id?: string }) => model.id === PHANTOM_MODEL),
`precondition: ${PHANTOM_MODEL} must exist in the static GitHub catalog`
);
await seedActiveLiveCatalog();
});
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("#8926: bare inference excludes a stale static model absent from the active live catalog", async () => {
const resolved = await getModelInfo(PHANTOM_MODEL);
assert.equal(resolved.provider, null);
assert.equal(resolved.errorType, "model_not_found");
assert.match(
resolved.errorMessage,
/active live catalog/i,
"the error should explain that live availability rejected the stale entry"
);
});
test("#8926: explicit provider/model rejects a stale static model before upstream dispatch", async () => {
const resolved = await getModelInfo(`${PROVIDER}/${PHANTOM_MODEL}`);
assert.equal(resolved.provider, null);
assert.equal(resolved.errorType, "model_not_found");
assert.match(
resolved.errorMessage,
/active live catalog/i,
"the explicit route should report live-catalog unavailability"
);
});
test("#8926: active alternative provider remains eligible", async () => {
await seedProviderCatalog("ghe-copilot", "ghe-copilot-active-8926", []);
const resolved = await getModelInfo(PHANTOM_MODEL);
assert.equal(resolved.provider, "ghe-copilot");
assert.equal(resolved.model, PHANTOM_MODEL);
});
test("#8926: explicit custom model overrides live-catalog exclusion", async () => {
await addCustomModel(PROVIDER, PHANTOM_MODEL, "Operator custom override");
const resolved = await getModelInfo(`${PROVIDER}/${PHANTOM_MODEL}`);
assert.equal(resolved.provider, PROVIDER);
assert.equal(resolved.model, PHANTOM_MODEL);
});
test("#8926: effort helper identifies only explicitly registered variants", () => {
assert.equal(isRegisteredProviderEffortVariant("cursor", "gpt-5.3-codex-high"), true);
assert.equal(
isRegisteredProviderEffortVariant("cursor", "gpt-5.3-codex-max"),
false,
"an invented suffix must not bypass live-catalog authority"
);
});
test("#8926: registered effort route survives while invented effort route is rejected", async () => {
await seedProviderCatalog("cursor", "cursor-live-8926", ["gpt-5.3-codex"]);
const registered = await getModelInfo("cursor/gpt-5.3-codex-high");
assert.equal(registered.provider, "cursor");
assert.equal(registered.model, "gpt-5.3-codex-high");
const invented = await getModelInfo("cursor/gpt-5.3-codex-max");
assert.equal(invented.provider, null);
assert.equal(invented.errorType, "model_not_found");
});
test("#8926: active-only catalog excludes inactive siblings and resolves aliases", async () => {
await seedProviderCatalog(PROVIDER, "github-inactive-sibling-8926", [PHANTOM_MODEL], false);
const allActive = await getAllActiveSyncedModels();
assert.deepEqual(
allActive[PROVIDER]?.map((model) => model.id),
[LIVE_MODEL]
);
const aliasCatalog = await getActiveSyncedCatalog("gh");
assert.equal(aliasCatalog.authoritative, true);
assert.deepEqual(
aliasCatalog.models.map((model) => model.id),
[LIVE_MODEL]
);
});
test("#8926: providers without an authoritative live catalog retain static fallback", async () => {
const resolved = await getModelInfo("openai/gpt-4o-mini");
assert.equal(resolved.provider, "openai");
assert.equal(resolved.model, "gpt-4o-mini");
});
test("#8926: registered effort variant is rejected when its live base is absent", async () => {
await seedProviderCatalog("cursor", "cursor-live-without-base-8926", ["cursor-live-only-8926"]);
const explicit = await getModelInfo("cursor/gpt-5.3-codex-high");
assert.equal(explicit.provider, null);
assert.equal(explicit.errorType, "model_not_found");
assert.match(explicit.errorMessage, /active live catalog/i);
const bare = await getModelInfo("gpt-5.3-codex-high");
assert.equal(bare.provider, null);
assert.equal(bare.errorType, "model_not_found");
assert.match(bare.errorMessage, /active live catalog/i);
});
test("#8926: live authority defaults to strict and honors explicit partial-discovery opt-outs", () => {
assert.equal(providerUsesAuthoritativeLiveCatalog("github"), true);
assert.equal(providerUsesAuthoritativeLiveCatalog("cursor"), true);
assert.equal(providerUsesAuthoritativeLiveCatalog("unknown-provider-8926"), true);
assert.equal(providerUsesAuthoritativeLiveCatalog("theoldllm"), true);
assert.equal(providerUsesAuthoritativeLiveCatalog("command-code"), false);
});
test("#8926: partial passthrough discovery remains non-authoritative", async () => {
await seedProviderCatalog("command-code", "command-code-partial-live-8926", ["gpt-5.6-luna"]);
const catalog = await getActiveSyncedCatalog("command-code");
assert.equal(catalog.authoritative, false);
assert.deepEqual(
catalog.models.map((model) => model.id),
["gpt-5.6-luna"]
);
});