Skip to content

refactor: modularize 2.2K-line models route.ts (Issue #3594) - #3652

Closed
oyi77 wants to merge 34 commits into
cheaper-inference:release/v3.8.24from
oyi77:refactor/modularize-provider-models-route
Closed

oyi77 wants to merge 34 commits into
cheaper-inference:release/v3.8.24from
oyi77:refactor/modularize-provider-models-route

Conversation

@oyi77

@oyi77 oyi77 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

This PR addresses another "Medium Priority" file from Issue #3594 by modularizing the massive `src/app/api/providers/[id]/models/route.ts` file (2,286 lines).

The file has been heavily refactored to support the upcoming Plugin System.

Changes:

  • Extracted 17 provider-specific model discovery handler blocks into individual files inside `handlers/`
  • Extracted shared generic helpers into `utils.ts`
  • Extracted shared constants and configuration to `config.ts`
  • Extracted Antigravity and specific normalizers into `antigravityHelpers.ts` and `customNormalizers.ts`
  • Reduced the main `GET` function from 1500+ lines to a clean facade that delegates to the appropriate domain handlers

Fixes #3594

@oyi77
oyi77 requested a review from diegosouzapw as a code owner June 11, 2026 13:24

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the large model discovery GET handler in route.ts by extracting provider-specific logic into modular handler files, custom normalizers, configurations, and types. However, the refactoring introduces several critical issues: the extracted handlers are called sequentially without provider guards (causing short-circuiting), the handler mappings are completely mixed up (e.g., handleDatarobotModels contains OpenAI logic), and there are multiple compilation and runtime errors due to missing imports and undefined variables (such as HttpProxyConfig, toLocalCatalogModels, url, and handleCloudflare_aiModels).

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

connection: any;
apiKey: string;
accessToken: string;
proxy: HttpProxyConfig | undefined;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

HttpProxyConfig is referenced here but it is never imported or defined in this file, which will cause a TypeScript compilation error.

proxyConfig: proxy,
...(init as Record<string, unknown>),
}),
fallbackModels: toLocalCatalogModels(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

toLocalCatalogModels is called here but it is neither imported nor defined in this file. It was a local helper function inside the GET handler in route.ts. This will throw a ReferenceError at runtime.

{ status: 400 }
);
}
url = url.replace("{accountId}", accountId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

url is referenced and assigned here, but it is not defined or declared anywhere in this file or function. This will throw a ReferenceError at runtime.

}
url = url.replace("{accountId}", accountId);
}
const cloudflare_aiRes = await handleCloudflare_aiModels(ctx); if (cloudflare_aiRes) return cloudflare_aiRes;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

handleCloudflare_aiModels is called here but it is never imported in this file. This will throw a ReferenceError at runtime.

Comment on lines +1031 to +1062
const rekaRes = await handleRekaModels(ctx);
if (rekaRes) return rekaRes;
const bedrockRes = await handleBedrockModels(ctx);
if (bedrockRes) return bedrockRes;
const datarobotRes = await handleDatarobotModels(ctx);
if (datarobotRes) return datarobotRes;
const azure_aiRes = await handleAzureAiModels(ctx);
if (azure_aiRes) return azure_aiRes;
const azure_openaiRes = await handleAzureOpenaiModels(ctx);
if (azure_openaiRes) return azure_openaiRes;
const watsonxRes = await handleWatsonxModels(ctx);
if (watsonxRes) return watsonxRes;
const ociRes = await handleOciModels(ctx);
if (ociRes) return ociRes;
const sapRes = await handleSapModels(ctx);
if (sapRes) return sapRes;
const claudeRes = await handleClaudeModels(ctx);
if (claudeRes) return claudeRes;
const cursorRes = await handleCursorModels(ctx);
if (cursorRes) return cursorRes;
const inner_aiRes = await handleInnerAiModels(ctx);
if (inner_aiRes) return inner_aiRes;
const glmRes = await handleGlmModels(ctx);
if (glmRes) return glmRes;
const gemini_cliRes = await handleGeminiCliModels(ctx);
if (gemini_cliRes) return gemini_cliRes;
const antigravityRes = await handleAntigravityModels(ctx);
if (antigravityRes) return antigravityRes;
const githubRes = await handleGithubModels(ctx);
if (githubRes) return githubRes;
const anthropicCompatibleRes = await handleAnthropicCompatibleModels(ctx);
if (anthropicCompatibleRes) return anthropicCompatibleRes;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Critical Bug: Missing Provider Guards and Mixed-up Handler Mappings

There are two major issues with how the handlers are invoked here:

  1. Missing Provider Guards: The handlers are called sequentially without checking if the current provider matches the handler's target provider (e.g., if (provider === "reka")). Since handleRekaModels is called first and immediately returns buildLocalCatalogResponse() (which returns a response for any provider that has local models), almost all requests will short-circuit and return the local catalog, completely bypassing remote API discovery.
  2. Mixed-up Handler Mappings: The handlers and files have been completely mixed up (shifted down) during extraction:
    • handleDatarobotModels contains OpenAI-compatible logic.
    • handleAzureAiModels contains DataRobot logic.
    • handleAzureOpenaiModels contains Azure AI logic.
    • handleWatsonxModels contains Azure OpenAI logic.
    • handleOciModels contains Watsonx logic.
    • handleSapModels contains OCI logic.
    • handleClaudeModels contains SAP logic.
    • handleCursorModels contains Claude logic.
    • handleInnerAiModels contains Cursor logic.
    • handleGlmModels contains Inner.ai logic.
    • handleGeminiCliModels contains GLM logic.
    • handleAntigravityModels contains Gemini CLI logic.
    • handleGithubModels contains Antigravity logic.
    • handleAnthropicCompatibleModels contains GitHub Copilot logic.
    • The original isAnthropicCompatibleProvider logic is completely missing.

You must restore the proper mapping and wrap each handler call with a check for the corresponding provider.

@kilo-code-bot

kilo-code-bot Bot commented Jun 11, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: 19 Active Issues | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 19
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
src/app/api/providers/[id]/models/types.ts 46 Type signature mismatch — buildDiscoveryErrorFallbackResponse typed with message: string but all call sites pass warnings?: { cacheWarning?, localWarning? } object
src/app/api/providers/[id]/models/handlers/cloudflare_ai.ts 29 Security bypass — Uses raw fetch() instead of safeOutboundFetch(), bypassing URL guard and proxy configuration
src/app/api/providers/[id]/models/antigravityHelpers.ts 161 Security bypass — Passes raw global fetch into ensureAntigravityProjectAssigned, bypassing safe outbound fetch guard/proxy handling
src/app/api/providers/[id]/models/handlers/anthropicCompatible.ts 86 Wrong implementation — Handler for Anthropic-compatible providers uses GLM/OpenAI-style discovery logic instead of Anthropic API calls
src/app/api/providers/[id]/models/handlers/claude.ts 87 Wrong implementation — Handler returns static models instead of calling https://api.anthropic.com/v1/models
src/app/api/providers/[id]/models/handlers/datarobot.ts 124 Undefined function — Calls toLocalCatalogModels() which is neither imported nor defined in this module
src/app/api/providers/[id]/models/handlers/qwen.ts 87 Missing OAuth check — Unconditionally returns local catalog; should call Dashscope API for non-OAuth Qwen connections
src/app/api/providers/[id]/models/route.ts 701 Extracted handlers are not wired — GET remains an inline implementation and never calls the extracted handler modules, making them dead code
src/app/api/providers/[id]/models/route.ts 84 Duplicate definitions — JsonRecord and helper functions remain duplicated locally despite types.ts/utils.ts extraction
src/app/api/providers/[id]/models/route.ts 1278 Type mismatch — Calls buildDiscoveryErrorFallbackResponse(error, {...}) but type signature expects (error, message: string)

Previously Reported Issues (Resolved in this commit):

  • src/app/api/providers/[id]/models/handlers/cursor.ts — Now correctly calls fetchCursorAgentModels()
  • src/app/api/providers/[id]/models/handlers/glm.ts — Now correctly implements GLM discovery
  • src/app/api/providers/[id]/models/handlers/oci.ts — Fixed to use OCI_DEFAULT_BASE_URL and buildOciModelsUrl()
  • src/app/api/providers/[id]/models/handlers/sap.ts — Fixed to use SAP_DEFAULT_BASE_URL and buildSapModelsUrl()
  • src/app/api/providers/[id]/models/handlers/watsonx.ts — Now correctly uses Watsonx configuration
  • src/app/api/providers/[id]/models/handlers/antigravity.ts — Now correctly uses antigravity discovery
Files Reviewed (19 files)
  • src/app/api/providers/[id]/models/types.ts
  • src/app/api/providers/[id]/models/handlers/anthropicCompatible.ts
  • src/app/api/providers/[id]/models/handlers/antigravity.ts
  • src/app/api/providers/[id]/models/handlers/azure_ai.ts
  • src/app/api/providers/[id]/models/handlers/claude.ts
  • src/app/api/providers/[id]/models/handlers/cloudflare_ai.ts
  • src/app/api/providers/[id]/models/handlers/cursor.ts
  • src/app/api/providers/[id]/models/handlers/datarobot.ts
  • src/app/api/providers/[id]/models/handlers/gemini_cli.ts
  • src/app/api/providers/[id]/models/handlers/github.ts
  • src/app/api/providers/[id]/models/handlers/glm.ts
  • src/app/api/providers/[id]/models/handlers/inner_ai.ts
  • src/app/api/providers/[id]/models/handlers/oci.ts
  • src/app/api/providers/[id]/models/handlers/qwen.ts
  • src/app/api/providers/[id]/models/handlers/sap.ts
  • src/app/api/providers/[id]/models/handlers/watsonx.ts
  • src/app/api/providers/[id]/models/route.ts
  • src/app/api/providers/[id]/models/antigravityHelpers.ts
  • src/app/api/providers/[id]/models/customNormalizers.ts
  • src/app/api/providers/[id]/models/utils.ts

Reply with @kilocode-bot fix it to have Kilo Code address these issues.


Reviewed by laguna-m.1-20260312:free · 2,716,381 tokens

@diegosouzapw
diegosouzapw changed the base branch from main to release/v3.8.23 June 12, 2026 01:18
zhiru and others added 24 commits June 12, 2026 02:40
…API (cheaper-inference#3712)

Integrated into release/v3.8.23. Vertex dynamic model discovery — surfaces image models (imagen-*, gemini-*-image), embeddings and audio from the live Generative Language catalog, with cached→static fallback and the shared parseGeminiModelsList helper. Validated: parser test 5/5, typecheck:core clean.
Integrated into release/v3.8.23. Makes the cheaper-inference#3588 reasoning token buffer safe and configurable: only inflates max_tokens when the model has a known, non-default output cap and the buffered value fits inside it; otherwise preserves/clamps the client limit. Adds the reasoningTokenBufferEnabled kill switch (default ON). Validated: combo-routing-engine 81/81, combo-config 25/25, combo-quality-validator-reasoning 12/12, phase1f 10/10, typecheck:core clean.
…4062→3408 LOC (-654) (cheaper-inference#3717)

Phase 1g-1j of cheaper-inference#3501: client 4062→3408 LOC. Pure extraction (ProviderPlaygroundPanel, useCommandCodeAuth, useExternalLinkFlow+ExternalLinkModal, useAuthFileHandlers) + loadConnProxies ReferenceError fix + phase1f test path fix.

Co-authored-by: oyi77 <14921983+oyi77@users.noreply.github.com>
…3408→2553 LOC (-855) (cheaper-inference#3721)

Phase 1k-1m of cheaper-inference#3501: client 3408→2553 LOC. Pure extraction (useModelImportHandlers+ImportProgressModal, useModelVisibilityHandlers, ProviderModelsSection).

Co-authored-by: oyi77 <14921983+oyi77@users.noreply.github.com>
….8.20 release branch

The fix itself reached main pre-tag via cherry-pick cheaper-inference#3591, but its changelog
bullet (commit e33fdd4) only ever existed on release/v3.8.20 after the
squash-merge. Restored under [3.8.20] per the 2026-06-12 release-branch
leftover audit (_tasks/release-audit/release-leftovers-audit-2026-06-12.md).
…2553→1376 LOC (-1177) (cheaper-inference#3725)

Phase 1n-1s of cheaper-inference#3501: client 2553→1376 LOC. Pure extraction (ConnectionsListPanel, ConnectionsHeaderToolbar, ZedImportCard, BatchTestResultsModal, AdaptaTutorialModal, useApiKeySave + helpers).

Co-authored-by: oyi77 <14921983+oyi77@users.noreply.github.com>
…cation, and success-decay recovery (cheaper-inference#3629)

Integrated into release/v3.8.23
…6→781 LOC (≤800 TARGET REACHED ✅) (cheaper-inference#3727)

Phase 1t of cheaper-inference#3501: client 1376→781 LOC (≤800 reached). Original god-component 12,882→781 (−94%).

Co-authored-by: oyi77 <14921983+oyi77@users.noreply.github.com>
… every chatHelpers import

cheaper-inference#3692 added a lazy 'await import(proxyEgress)' for egress-IP visibility inside
safeLogEvents, which is a sync function — an ES syntax error. It went unnoticed
because typecheck:core does not cover src/sse and no test in the merge gates
loaded chatHelpers via tsx; any consumer that did (chat-context-relay and
chat-route-coverage suites, integration harnesses) failed at module load with
'await can only be used inside an async function'.

safeLogEvents is fire-and-forget logging with an outer try/catch, so making it
async (and 'void'-ing the single chat.ts call site) preserves behavior exactly.

Validation: tests/unit/chat-context-relay.test.ts + chat-route-coverage.test.ts
went from failing-at-load to green (+14 tests destravados).
diegosouzapw and others added 8 commits June 12, 2026 11:51
… + combo/proxy audit fixes (cheaper-inference#3699)

Integrated into release/v3.8.23
…ce#3594)

- extracted all generic helpers to utils, config, types, antigravityHelpers, customNormalizers
- extracted 17 provider-specific model discovery handlers to handlers/ directory
- reduced route.ts from 2,286 lines to ~200 lines
…er instead of using undefined toLocalCatalogModels
@oyi77
oyi77 force-pushed the refactor/modularize-provider-models-route branch from 99c547f to 31e867a Compare June 12, 2026 19:12
const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/models/search`;

try {
const res = await fetch(url, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Cloudflare model discovery bypasses safe outbound fetch

This handler still uses raw fetch() for an outbound provider URL, which bypasses the repository's outbound URL guard and proxy configuration. Use safeOutboundFetch() with the models discovery preset, guard: getProviderOutboundGuard(), and proxyConfig: proxy to match the surrounding handlers.

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

await resolveAntigravityVersion();
await ensureAntigravityProjectAssigned(
accessToken,
fetch,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Antigravity bootstrap bypasses safe outbound fetch

ensureAntigravityProjectAssigned receives global fetch, so the bootstrap loadCodeAssist request can bypass safeOutboundFetch URL guard and proxy handling. Pass a guarded fetch wrapper or change the helper call site to use safeOutboundFetch with the models discovery preset, guard, and proxy config.

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

maybeReturnCachedDiscovery: () => NextResponse | null;
maybeReturnAutoFetchDisabled: () => NextResponse | null;
buildDiscoveryFallbackResponse: (args: { cacheWarning?: string; localWarning?: string; error?: any }) => NextResponse | null;
buildDiscoveryErrorFallbackResponse: (error: any, message: string) => NextResponse | null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Context callback type does not match implementation

ModelsRequestContext.buildDiscoveryErrorFallbackResponse is typed as (error: any, message: string), but route.ts implements (error: unknown, warnings?: { cacheWarning?: string; localWarning?: string }). This hides mismatches and allows handlers to pass the wrong second argument without type feedback.

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

}

console.warn(`[models] All endpoints failed for ${provider}, using local catalog`);
models = toLocalCatalogModels();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Undefined local helper reference

toLocalCatalogModels is referenced here but is neither imported nor defined in this handler. It used to be a local helper inside route.ts, so invoking this handler would throw a ReferenceError.

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

return buildResponse({
provider,
connectionId,
models: toLocalCatalogModels(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Undefined local helper reference

toLocalCatalogModels is referenced here but is neither imported nor defined in this handler. It used to be a local helper inside route.ts, so invoking this handler would throw a ReferenceError.

Reply with @kilocode-bot fix it to have Kilo Code address this issue.


let response: Response;
try {
response = await safeOutboundFetch(buildSapModelsUrl(baseUrl), {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Missing import for buildSapModelsUrl

This handler calls buildSapModelsUrl() but the import only brings in getProviderBaseUrl and buildOptionalBearerHeaders. Add the missing import or this handler will fail when invoked.

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@diegosouzapw
diegosouzapw changed the base branch from release/v3.8.23 to release/v3.8.24 June 13, 2026 02:52
localWarning?: string;
error?: unknown;
}) => NextResponse | null;
buildDiscoveryErrorFallbackResponse: (error: unknown, message: string) => NextResponse | null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Type signature mismatch — buildDiscoveryErrorFallbackResponse is typed with message: string as second parameter, but all call sites (route.ts:lines 1278, 1500, 1629, etc.) and the actual implementation call it with warnings?: { cacheWarning?: string; localWarning?: string }. This will cause TypeScript errors and potential runtime failures.

return buildResponse({
provider,
connectionId,
models: toLocalCatalogModels(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Undefined function reference — toLocalCatalogModels() is called on this line but is neither imported nor defined in this handler. This function is defined locally within route.ts and is not available in the handler scope. This will cause a ReferenceError at runtime.


export async function handleClaudeModels(ctx: ModelsRequestContext): Promise<any> {
const { provider, connectionId, connection, apiKey, accessToken, proxy, id, maybeReturnCachedDiscovery, maybeReturnAutoFetchDisabled, buildDiscoveryFallbackResponse, buildDiscoveryErrorFallbackResponse, buildApiDiscoveryResponse, buildResponse, buildLocalCatalogResponse } = ctx;
return buildResponse({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Handler returns static models instead of discovering from the actual Anthropic API. The handleClaudeModels function should call https://api.anthropic.com/v1/models with the API key to fetch the live model catalog, not return hardcoded static models. This defeats the purpose of model discovery for Claude providers.

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Thanks @oyi77 for the modularization work on models route.ts (Issue #3594). I can't merge this as it currently stands — and the reason is structural, not about the quality of the split:

  1. It's a stacked/cumulative chain. This branch carries ~49–55 commits all starting from chore(release): open v3.8.23 development cycle, and the per-PR additions grow monotonically (refactor: modularize providerRegistry.ts (Issue #3594) #3617 ≈ +22k → refactor: modularize 3.1K-line providers.ts constants (Issue #3594) #3646 ≈ +52k). Each refactor branch is built on top of the previous one, so merging any single PR drags in all the earlier refactors too. That makes each PR impossible to review in isolation and guarantees conflicts between them.

  2. The base is stale (v3.8.23 era). Since these were cut, release/v3.8.24 has merged dozens of PRs — including changes to the very files several of these PRs modularize (e.g. providerRegistry.ts grew via fix(providers): correct Ollama Cloud kimi-k2.7-code capabilities (#3761) #3768, validation.ts via fix(providers): repair qwen-web validation + stop mislabeling benign redirects as SSRF (#3288, #3758) #3767, plus combo/stream/usage edits). GitHub now reports this PR as CONFLICTING, and the conflicts are substantial.

What would let this land: re-cut it as a single, independent PR branched from the current release/v3.8.24 tip, modularizing only models route.ts (not stacked on the other refactors), small enough to review on its own. One file per PR, rebased on current release. I'll gladly review and merge them in that form — the god-file modularization goal is worth it; it's the 14-deep stack on a 2-week-old base that can't go in. Leaving this open so nothing is lost.

@oyi77

oyi77 commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

Closed in favor of clean re-cut — see #3790 (chatgpt-web), #3788 (stream), #3789 (models route), #3791 (auth), #3792 (schemas). Only modularization commits were cherry-picked onto current release/v3.8.24 — no stacked dependencies, no unrelated changes.

@oyi77 oyi77 closed this Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Codebase Modularization (Preparing for WordPress-style Plugin System)