From 360a97b654d036964ea39e62eff7a1edabde0a01 Mon Sep 17 00:00:00 2001 From: Automation Date: Mon, 11 May 2026 09:27:55 +0200 Subject: [PATCH 1/2] refactor(catalog): remove .ts import extensions, as any casts, and normalize alias resolution Addresses code review feedback from PR #2136: - Remove .ts extensions from @omniroute/open-sse imports for better module resolution - Replace all as any casts with proper types: ComboModelStep for combo step iteration, Record bracket access for custom model fields, ManagedAvailableModel.contextLength type for fallback models, and Error instanceof check for catch blocks - Normalize provider alias resolution in combo context_length calculation via resolveCanonicalProviderId for consistent getTokenLimit lookups Co-Authored-By: Claude Opus 4.7 --- src/app/api/v1/models/catalog.ts | 40 ++++++++++----------- src/lib/providers/managedAvailableModels.ts | 1 + 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/app/api/v1/models/catalog.ts b/src/app/api/v1/models/catalog.ts index 49e9d7c944..878595d71e 100644 --- a/src/app/api/v1/models/catalog.ts +++ b/src/app/api/v1/models/catalog.ts @@ -8,14 +8,14 @@ import { getProviderNodes, getModelIsHidden, } from "@/lib/localDb"; -import { getAllEmbeddingModels } from "@omniroute/open-sse/config/embeddingRegistry.ts"; -import { getAllImageModels } from "@omniroute/open-sse/config/imageRegistry.ts"; -import { getAllRerankModels } from "@omniroute/open-sse/config/rerankRegistry.ts"; -import { getAllAudioModels } from "@omniroute/open-sse/config/audioRegistry.ts"; -import { getAllModerationModels } from "@omniroute/open-sse/config/moderationRegistry.ts"; -import { getAllVideoModels } from "@omniroute/open-sse/config/videoRegistry.ts"; -import { getAllMusicModels } from "@omniroute/open-sse/config/musicRegistry.ts"; -import { REGISTRY } from "@omniroute/open-sse/config/providerRegistry.ts"; +import { getAllEmbeddingModels } from "@omniroute/open-sse/config/embeddingRegistry"; +import { getAllImageModels } from "@omniroute/open-sse/config/imageRegistry"; +import { getAllRerankModels } from "@omniroute/open-sse/config/rerankRegistry"; +import { getAllAudioModels } from "@omniroute/open-sse/config/audioRegistry"; +import { getAllModerationModels } from "@omniroute/open-sse/config/moderationRegistry"; +import { getAllVideoModels } from "@omniroute/open-sse/config/videoRegistry"; +import { getAllMusicModels } from "@omniroute/open-sse/config/musicRegistry"; +import { REGISTRY } from "@omniroute/open-sse/config/providerRegistry"; import { getAllSyncedAvailableModels } from "@/lib/db/models"; import { getCompatibleFallbackModels } from "@/lib/providers/managedAvailableModels"; import { hasEligibleConnectionForModel } from "@/domain/connectionModelRules"; @@ -25,8 +25,9 @@ import { getCatalogDiagnosticsHeaders, } from "@/lib/modelMetadataRegistry"; import { isAuthRequired, isDashboardSessionAuthenticated } from "@/shared/utils/apiAuth"; -import { parseModel } from "@omniroute/open-sse/services/model.ts"; -import { getTokenLimit } from "@omniroute/open-sse/services/contextManager.ts"; +import { parseModel } from "@omniroute/open-sse/services/model"; +import { getTokenLimit } from "@omniroute/open-sse/services/contextManager"; +import type { ComboModelStep } from "@/lib/combos/steps"; const FALLBACK_ALIAS_TO_PROVIDER = { ag: "antigravity", @@ -321,10 +322,11 @@ export async function getUnifiedModelsResponse( // they fall back to a conservative ~4000 token limit, causing truncation. const comboContextLength = Array.isArray(combo.models) ? combo.models - .filter((step) => step && step.kind === "model" && step.model) + .filter((step): step is ComboModelStep => step?.kind === "model" && Boolean(step.model)) .map((step) => { const parsed = parseModel(step.model); - const provider = parsed.provider || (step as any).providerId || "unknown"; + const rawProvider = parsed.provider || step.providerId || "unknown"; + const provider = resolveCanonicalProviderId(rawProvider); const model = parsed.model || step.model; return getTokenLimit(provider, model); }) @@ -732,8 +734,8 @@ export async function getUnifiedModelsResponse( ...(endpoints.length > 1 || !endpoints.includes("chat") ? { supported_endpoints: endpoints } : {}), - ...(typeof (model as any).inputTokenLimit === "number" - ? { context_length: (model as any).inputTokenLimit } + ...(typeof model["inputTokenLimit"] === "number" + ? { context_length: model["inputTokenLimit"] as number } : {}), ...(visionFields || {}), }); @@ -757,8 +759,8 @@ export async function getUnifiedModelsResponse( parent: aliasId, custom: true, ...(modelType ? { type: modelType } : {}), - ...(typeof (model as any).inputTokenLimit === "number" - ? { context_length: (model as any).inputTokenLimit } + ...(typeof model["inputTokenLimit"] === "number" + ? { context_length: model["inputTokenLimit"] as number } : {}), ...(providerVisionFields || {}), }); @@ -793,9 +795,7 @@ export async function getUnifiedModelsResponse( const visionFields = getVisionCapabilityFields(aliasId) || getVisionCapabilityFields(modelId); const contextLength = - typeof (model as any).contextLength === "number" - ? (model as any).contextLength - : undefined; + typeof model.contextLength === "number" ? model.contextLength : undefined; models.push({ id: aliasId, @@ -873,7 +873,7 @@ export async function getUnifiedModelsResponse( return Response.json( { error: { - message: (error as any).message, + message: error instanceof Error ? error.message : String(error), type: "server_error", code: INTERNAL_PROXY_ERROR, }, diff --git a/src/lib/providers/managedAvailableModels.ts b/src/lib/providers/managedAvailableModels.ts index 9905bfd25a..d450edfdf3 100644 --- a/src/lib/providers/managedAvailableModels.ts +++ b/src/lib/providers/managedAvailableModels.ts @@ -4,6 +4,7 @@ import { isClaudeCodeCompatibleProvider } from "@/shared/constants/providers"; type ManagedAvailableModel = { id?: string; name?: string; + contextLength?: number; }; export function getCompatibleFallbackModels( From 66d5808d4a654f66a1d5409e8e453c87d0d10baa Mon Sep 17 00:00:00 2001 From: Automation Date: Mon, 11 May 2026 09:43:19 +0200 Subject: [PATCH 2/2] refactor(catalog): replace bracket-access with CustomModelEntry interface Addresses code review feedback from PR #2152: use a proper CustomModelEntry interface instead of Record bracket-access for custom model fields like inputTokenLimit. Co-Authored-By: Claude Opus 4.7 --- src/app/api/v1/models/catalog.ts | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/app/api/v1/models/catalog.ts b/src/app/api/v1/models/catalog.ts index 878595d71e..a590673add 100644 --- a/src/app/api/v1/models/catalog.ts +++ b/src/app/api/v1/models/catalog.ts @@ -29,6 +29,16 @@ import { parseModel } from "@omniroute/open-sse/services/model"; import { getTokenLimit } from "@omniroute/open-sse/services/contextManager"; import type { ComboModelStep } from "@/lib/combos/steps"; +interface CustomModelEntry { + id?: string; + name?: string; + source?: string; + apiFormat?: string; + supportedEndpoints?: string[]; + inputTokenLimit?: number; + isHidden?: boolean; +} + const FALLBACK_ALIAS_TO_PROVIDER = { ag: "antigravity", cc: "claude", @@ -659,9 +669,9 @@ export async function getUnifiedModelsResponse( // Skip Gemini — handled by syncedAvailableModels above if (providerId === "gemini") continue; if (providerId === "reka") continue; - const providerCustomModels = Array.isArray(rawProviderCustomModels) + const providerCustomModels: CustomModelEntry[] = Array.isArray(rawProviderCustomModels) ? rawProviderCustomModels.filter( - (model): model is Record => + (model): model is CustomModelEntry => !!model && typeof model === "object" && !Array.isArray(model) ) : []; @@ -734,8 +744,8 @@ export async function getUnifiedModelsResponse( ...(endpoints.length > 1 || !endpoints.includes("chat") ? { supported_endpoints: endpoints } : {}), - ...(typeof model["inputTokenLimit"] === "number" - ? { context_length: model["inputTokenLimit"] as number } + ...(typeof model.inputTokenLimit === "number" + ? { context_length: model.inputTokenLimit } : {}), ...(visionFields || {}), }); @@ -759,8 +769,8 @@ export async function getUnifiedModelsResponse( parent: aliasId, custom: true, ...(modelType ? { type: modelType } : {}), - ...(typeof model["inputTokenLimit"] === "number" - ? { context_length: model["inputTokenLimit"] as number } + ...(typeof model.inputTokenLimit === "number" + ? { context_length: model.inputTokenLimit } : {}), ...(providerVisionFields || {}), });