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"; const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-provider-model-routes-")); process.env.DATA_DIR = TEST_DATA_DIR; const core = await import("../../src/lib/db/core.ts"); const providersDb = await import("../../src/lib/db/providers.ts"); const modelsDb = await import("../../src/lib/db/models.ts"); const providerModelsRoute = await import("../../src/app/api/providers/[id]/models/route.ts"); const antigravityVersion = await import("../../open-sse/services/antigravityVersion.ts"); const providerRegistry = await import("../../open-sse/config/providerRegistry.ts"); const originalFetch = globalThis.fetch; const originalAllowPrivateProviderUrls = process.env.OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS; async function resetStorage() { globalThis.fetch = originalFetch; if (originalAllowPrivateProviderUrls === undefined) { delete process.env.OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS; } else { process.env.OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS = originalAllowPrivateProviderUrls; } antigravityVersion.clearAntigravityVersionCache(); core.resetDbInstance(); fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); fs.mkdirSync(TEST_DATA_DIR, { recursive: true }); } async function seedConnection(provider, overrides = {}) { return providersDb.createProviderConnection({ provider, authType: overrides.authType || "apikey", name: overrides.name || `${provider}-${Math.random().toString(16).slice(2, 8)}`, apiKey: overrides.apiKey, accessToken: overrides.accessToken, projectId: overrides.projectId, isActive: overrides.isActive ?? true, testStatus: overrides.testStatus || "active", providerSpecificData: overrides.providerSpecificData || {}, }); } async function callRoute(connectionId, search = "") { return providerModelsRoute.GET( new Request(`http://localhost/api/providers/${connectionId}/models${search}`), { params: { id: connectionId } } ); } test.beforeEach(async () => { await resetStorage(); }); test.after(async () => { globalThis.fetch = originalFetch; core.resetDbInstance(); fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); test("provider models route returns a static local catalog for non-LLM search/agent providers (#5569/#5571/#5573/#5575)", async () => { const cases = [ { provider: "jules", expectId: "jules" }, { provider: "linkup-search", expectId: "standard" }, { provider: "ollama-search", expectId: "web_search" }, { provider: "searchapi-search", expectId: "google" }, ]; for (const { provider, expectId } of cases) { const connection = await seedConnection(provider, { apiKey: `${provider}-key` }); const response = await callRoute(connection.id); // RED before the fix: these had no static catalog → 400 "does not support models listing". assert.equal(response.status, 200, `${provider} should not 400 on model import`); const body = await response.json(); assert.equal(body.source, "local_catalog", `${provider} should serve a local catalog`); const ids = (body.models || []).map((m) => m.id); assert.ok( ids.includes(expectId), `${provider} should list "${expectId}"; got: ${ids.join(", ")}` ); } }); test("provider models route fetches the live AI/ML API catalog from the auth-free /models endpoint (#5570)", async () => { const connection = await seedConnection("aimlapi", { apiKey: "aiml-key" }); let calledUrl = ""; globalThis.fetch = async (url) => { calledUrl = String(url); return Response.json([ { id: "openai/gpt-5.5", type: "chat-completion", info: { name: "GPT-5.5" } }, { id: "zhipu/glm-5.2", type: "chat-completion", info: { name: "GLM 5.2" } }, { id: "flux/flux-pro", type: "image", info: { name: "FLUX Pro" } }, ]); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; // RED before the fix: aimlapi had no PROVIDER_MODELS_CONFIG entry → stale // 6-model local seed (source "local_catalog"), live endpoint never called. assert.equal(response.status, 200); assert.equal(body.source, "api"); assert.equal(calledUrl, "https://api.aimlapi.com/models"); const ids = body.models.map((m: any) => m.id); assert.ok(ids.includes("openai/gpt-5.5") && ids.includes("zhipu/glm-5.2")); assert.ok(!ids.includes("flux/flux-pro"), "non-chat model types are filtered out"); }); test("provider models route falls back to the local AI/ML API catalog when the live fetch fails (#5570)", async () => { const connection = await seedConnection("aimlapi", { apiKey: "aiml-key" }); globalThis.fetch = async () => new Response("upstream down", { status: 500 }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "local_catalog"); assert.ok(body.models.length > 0); }); test("cablyai is flagged deprecated (domain NXDOMAIN) and no longer 500s on model import (#5568)", async () => { const { APIKEY_PROVIDERS_GATEWAYS } = await import("../../src/shared/constants/providers/apikey/gateways.ts"); const cablyai = (APIKEY_PROVIDERS_GATEWAYS as Record).cablyai; assert.equal(cablyai?.deprecated, true, "cablyai must be marked deprecated (domain is NXDOMAIN)"); assert.ok( typeof cablyai?.deprecationReason === "string" && cablyai.deprecationReason.length > 0, "cablyai must carry a deprecationReason" ); // Removed from PROVIDER_MODELS_CONFIG → no live fetch to the dead domain → a // controlled 400 instead of an unhandled 500 crash. const connection = await seedConnection("cablyai", { apiKey: "dead-key" }); const response = await callRoute(connection.id); assert.notEqual(response.status, 500, "cablyai must not 500-crash on a dead domain"); }); test("provider models route returns 404 for unknown connections", async () => { const response = await callRoute("missing-connection"); assert.equal(response.status, 404); assert.deepEqual(await response.json(), { error: "Connection not found" }); }); test("provider models route rejects connections with an empty provider id", async () => { const connection = await seedConnection("openai", { apiKey: "sk-openai", }); const db = core.getDbInstance(); db.prepare("UPDATE provider_connections SET provider = '' WHERE id = ?").run(connection.id); const response = await callRoute(connection.id); assert.equal(response.status, 400); assert.deepEqual(await response.json(), { error: "Invalid connection provider" }); }); test("provider models route rejects OpenAI-compatible providers without a base URL", async () => { const connection = await seedConnection("openai-compatible-demo", { apiKey: "sk-openai-compatible", }); const response = await callRoute(connection.id); assert.equal(response.status, 400); assert.deepEqual(await response.json(), { error: "No base URL configured for OpenAI compatible provider", }); }); test("provider models route blocks private OpenAI-compatible base URLs", async () => { delete process.env.OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS; const connection = await seedConnection("openai-compatible-private", { apiKey: "sk-openai-compatible", providerSpecificData: { baseUrl: "http://127.0.0.1:11434/v1", }, }); let called = false; globalThis.fetch = async () => { called = true; return Response.json({ data: [] }); }; const response = await callRoute(connection.id); assert.equal(response.status, 400); assert.deepEqual(await response.json(), { error: "Blocked private or local provider URL", }); assert.equal(called, false); }); test("provider models route returns auth failures from OpenAI-compatible upstreams", async () => { const connection = await seedConnection("openai-compatible-auth", { apiKey: "sk-openai-compatible", providerSpecificData: { baseUrl: "https://proxy.example.com/v1/chat/completions", }, }); const seenUrls = []; globalThis.fetch = async (url) => { seenUrls.push(String(url)); return new Response("unauthorized", { status: 401 }); }; const response = await callRoute(connection.id); assert.equal(response.status, 401); assert.deepEqual(await response.json(), { error: "Auth failed: 401" }); assert.equal(seenUrls.length, 1); }); test("provider models route falls back after OpenAI-compatible endpoint probes all fail", async () => { const connection = await seedConnection("openai-compatible-fallback", { apiKey: "sk-openai-compatible", providerSpecificData: { baseUrl: "https://proxy.example.com/v1", }, }); const seenUrls = []; globalThis.fetch = async (url) => { seenUrls.push(String(url)); return new Response("bad gateway", { status: 502 }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "openai-compatible-fallback"); assert.ok(Array.isArray(body.models)); assert.ok(seenUrls.length >= 2); }); test("provider models route retries transient OpenAI-compatible probe failures before succeeding", async () => { const connection = await seedConnection("openai-compatible-retry", { apiKey: "sk-openai-compatible", providerSpecificData: { baseUrl: "https://proxy.example.com/v1", }, }); const seenUrls = []; globalThis.fetch = async (url) => { seenUrls.push(String(url)); if (seenUrls.length === 1) { throw new Error("temporary upstream failure"); } return Response.json({ data: [{ id: "demo-model", name: "Demo Model" }], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "api"); assert.deepEqual(seenUrls, [ "https://proxy.example.com/v1/models", "https://proxy.example.com/v1/models", ]); assert.deepEqual(body.models, [{ id: "demo-model", name: "Demo Model" }]); }); test("provider models route discovers SiliconFlow models from configured China base URL", async () => { const connection = await seedConnection("siliconflow", { apiKey: "sf-cn-key", providerSpecificData: { baseUrl: "https://api.siliconflow.cn/v1", }, }); const seenRequests: Array<{ url: string; method: string | undefined; authorization: string | null; }> = []; globalThis.fetch = async (url, init) => { const headers = new Headers(init?.headers as HeadersInit | undefined); seenRequests.push({ url: String(url), method: init?.method, authorization: headers.get("authorization"), }); return Response.json({ data: [{ id: "Qwen/Qwen3-Coder-480B-A35B-Instruct", name: "Qwen3 Coder" }], }); }; const response = await callRoute(connection.id, "?refresh=true"); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "siliconflow"); assert.equal(body.source, "api"); assert.deepEqual(seenRequests, [ { url: "https://api.siliconflow.cn/v1/models", method: "GET", authorization: "Bearer sf-cn-key", }, ]); assert.deepEqual(body.models, [ { id: "Qwen/Qwen3-Coder-480B-A35B-Instruct", name: "Qwen3 Coder", owned_by: "siliconflow", }, ]); }); test("provider models route handles local hostnames named 'v1' correctly", async () => { const connection = await seedConnection("openai-compatible-local-v1", { apiKey: "sk-local", providerSpecificData: { baseUrl: "http://v1/chat/completions", }, }); const seenUrls: string[] = []; globalThis.fetch = async (url) => { seenUrls.push(String(url)); return Response.json({ data: [{ id: "local-v1-model", name: "Local v1 Model" }], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "api"); assert.deepEqual(seenUrls, ["http://v1/v1/models"]); }); test("provider models route correctly strips standard /v1 paths", async () => { const connection = await seedConnection("openai-compatible-standard-v1", { apiKey: "sk-standard", providerSpecificData: { baseUrl: "https://api.openai.com/v1", }, }); const seenUrls: string[] = []; globalThis.fetch = async (url) => { seenUrls.push(String(url)); return Response.json({ data: [{ id: "standard-model", name: "Standard Model" }], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "api"); assert.deepEqual(seenUrls, ["https://api.openai.com/v1/models"]); }); test("provider models route strips /v1 when it precedes /chat/completions (#5899 no double /v1)", async () => { // Regression for #5899 (Api Airforce): a baseUrl of the form // "https://api.airforce/v1/chat/completions" must probe ".../v1/models" — NOT // ".../v1/v1/models". The old `else if` strip chain only removed // "/chat/completions", leaving a trailing "/v1" that the endpoint builder then // doubled, producing a 308 redirect that aborted discovery. const connection = await seedConnection("openai-compatible-airforce-v1", { apiKey: "sk-airforce", providerSpecificData: { baseUrl: "https://api.airforce/v1/chat/completions", }, }); const seenUrls: string[] = []; globalThis.fetch = async (url) => { seenUrls.push(String(url)); return Response.json({ data: [{ id: "airforce-model", name: "Airforce Model" }], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "api"); // First probed endpoint must have a single /v1 — no ".../v1/v1/models". assert.equal(seenUrls[0], "https://api.airforce/v1/models"); assert.ok( !seenUrls.some((u) => u.includes("/v1/v1/")), `no endpoint should contain a doubled /v1: ${JSON.stringify(seenUrls)}` ); }); test("provider models route continues probing past a REDIRECT_BLOCKED endpoint (#5899)", async () => { // Regression for #5899: a REDIRECT_BLOCKED error on one candidate endpoint must // not abort the whole probe loop — discovery should fall through to the next // endpoint instead of surfacing an empty catalog. const connection = await seedConnection("openai-compatible-redirect-v1", { apiKey: "sk-redirect", providerSpecificData: { baseUrl: "https://redirect.example", }, }); const seenUrls: string[] = []; globalThis.fetch = async (url) => { const u = String(url); seenUrls.push(u); // First candidate ".../v1/models" answers with a real 308 redirect → // safeOutboundFetch throws a SafeOutboundFetchError(REDIRECT_BLOCKED). The old // code re-threw on it (status 503) and aborted the loop; the fix `continue`s. if (u === "https://redirect.example/v1/models") { return new Response(null, { status: 308, headers: { location: "https://redirect.example/models" }, }); } return Response.json({ data: [{ id: "redirect-model", name: "Redirect Model" }], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); // Without the REDIRECT_BLOCKED `continue`, discovery aborted and fell back to a // non-api catalog. The fix lets it reach the next endpoint and return live models. assert.equal(body.source, "api"); assert.ok( seenUrls.length >= 2, `expected the loop to continue past REDIRECT_BLOCKED: ${JSON.stringify(seenUrls)}` ); }); test("provider models route returns static catalog entries for providers with hardcoded models", async () => { const connection = await seedConnection("bailian-coding-plan", { apiKey: "bailian-key", }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "bailian-coding-plan"); assert.equal(body.models.length, providerRegistry.REGISTRY["bailian-coding-plan"].models?.length); assert.deepEqual( body.models.map((model) => model.id), providerRegistry.REGISTRY["bailian-coding-plan"].models?.map((model) => model.id) ); }); test("provider models route returns AWS Polly speech engines from the audio registry", async () => { const connection = await seedConnection("aws-polly", { apiKey: "aws-secret-key", providerSpecificData: { accessKeyId: "AKIA_TEST", region: "us-east-1", }, }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "aws-polly"); assert.equal(body.source, "local_catalog"); assert.deepEqual( body.models.map((model) => model.id), ["standard", "neural", "long-form", "generative"] ); }); test("provider models route returns the local catalog for GitLab Duo fallback models", async () => { const connection = await seedConnection("gitlab", { apiKey: "glpat-test", }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "gitlab"); assert.equal(body.source, "local_catalog"); assert.deepEqual(body.models, [ { id: "gitlab-duo-code-suggestions", name: "GitLab Duo Code Suggestions" }, ]); }); test("provider models route discovers local OpenAI-style models without requiring an API key", async () => { process.env.OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS = "true"; const lmStudioConnection = await seedConnection("lm-studio", { providerSpecificData: { baseUrl: "http://localhost:1234/v1", }, }); const lemonadeConnection = await seedConnection("lemonade", { providerSpecificData: { baseUrl: "http://localhost:13305/api/v1", }, }); globalThis.fetch = async (url, init = {}) => { const target = String(url); assert.equal(init.headers.Authorization, undefined); if (target === "http://localhost:1234/v1/models") { return Response.json({ data: [{ id: "local-model", name: "Local Model" }], }); } if (target === "http://localhost:13305/api/v1/models") { return Response.json({ data: [{ id: "Llama-3.2-1B-Instruct-Hybrid", name: "Lemonade Llama" }], }); } throw new Error(`unexpected fetch: ${target}`); }; const lmStudioResponse = await callRoute(lmStudioConnection.id); const lmStudioBody = (await lmStudioResponse.json()) as any; const lemonadeResponse = await callRoute(lemonadeConnection.id); const lemonadeBody = (await lemonadeResponse.json()) as any; assert.equal(lmStudioResponse.status, 200); assert.equal(lmStudioBody.provider, "lm-studio"); assert.equal(lmStudioBody.source, "api"); assert.deepEqual(lmStudioBody.models, [{ id: "local-model", name: "Local Model" }]); assert.equal(lemonadeResponse.status, 200); assert.equal(lemonadeBody.provider, "lemonade"); assert.equal(lemonadeBody.source, "api"); assert.deepEqual(lemonadeBody.models, [ { id: "Llama-3.2-1B-Instruct-Hybrid", name: "Lemonade Llama" }, ]); }); test("provider models route returns the local catalog for built-in image providers", async () => { const connection = await seedConnection("topaz", { apiKey: "topaz-key", }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "topaz"); assert.ok(Array.isArray(body.models)); assert.deepEqual(body.models, [{ id: "topaz-enhance", name: "topaz-enhance" }]); }); test("provider models route prefers the remote OpenRouter /models API over static image models", async () => { const connection = await seedConnection("openrouter", { apiKey: "openrouter-key", }); const seenUrls = []; globalThis.fetch = async (url, init = {}) => { seenUrls.push(String(url)); assert.equal(init.method, "GET"); assert.equal(init.headers.Authorization, "Bearer openrouter-key"); return Response.json({ data: [{ id: "openai/gpt-4.1", name: "GPT-4.1 via OpenRouter" }], }); }; const response = await callRoute(connection.id, "?refresh=true"); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "api"); assert.deepEqual(seenUrls, ["https://openrouter.ai/api/v1/models"]); assert.deepEqual(body.models, [{ id: "openai/gpt-4.1", name: "GPT-4.1 via OpenRouter" }]); }); test("provider models route returns the local catalog for embedding and rerank providers", async () => { const voyage = await seedConnection("voyage-ai", { apiKey: "voyage-key", }); const jina = await seedConnection("jina-ai", { apiKey: "jina-key", }); const [voyageResponse, jinaResponse] = await Promise.all([ callRoute(voyage.id), callRoute(jina.id), ]); const voyageBody = (await voyageResponse.json()) as any; const jinaBody = (await jinaResponse.json()) as any; assert.equal(voyageResponse.status, 200); assert.equal(voyageBody.provider, "voyage-ai"); assert.equal(voyageBody.source, "local_catalog"); assert.ok(voyageBody.models.some((model) => model.id === "voyage-4-large")); assert.ok(voyageBody.models.some((model) => model.id === "voyage-code-3")); assert.ok(voyageBody.models.some((model) => model.id === "voyage-4-lite")); assert.equal(jinaResponse.status, 200); assert.equal(jinaBody.provider, "jina-ai"); assert.equal(jinaBody.source, "local_catalog"); assert.ok( jinaBody.models.some( (model) => model.id === "jina-embeddings-v5-text-small" && model.apiFormat === "embeddings" && model.supportedEndpoints?.includes("embeddings") ) ); assert.ok( jinaBody.models.some( (model) => model.id === "jina-reranker-v3" && model.apiFormat === "rerank" && model.supportedEndpoints?.includes("rerank") ) ); assert.ok(jinaBody.models.some((model) => model.id === "jina-reranker-m0")); }); test("provider models route flags intentional local-catalog-only providers so model-sync imports them (#5460/#5465)", async () => { // reka + voyage-ai never do a remote /models fetch — their local catalog is // the intended source, so the response must carry `intentional: true` for the // sync route to import instead of 502-ing ("local catalog fallback not synced"). const reka = await seedConnection("reka", { apiKey: "reka-key" }); const voyage = await seedConnection("voyage-ai", { apiKey: "voyage-key" }); const [rekaBody, voyageBody] = await Promise.all([ callRoute(reka.id).then((r) => r.json() as any), callRoute(voyage.id).then((r) => r.json() as any), ]); assert.equal(rekaBody.source, "local_catalog"); assert.equal(rekaBody.intentional, true, "reka local catalog must be flagged intentional"); assert.equal(voyageBody.source, "local_catalog"); assert.equal(voyageBody.intentional, true, "voyage-ai local catalog must be flagged intentional"); }); test("provider models route does NOT flag a degraded remote-fetch fallback as intentional (#5460/#5465)", async () => { // aimlapi normally discovers remotely; when the live fetch fails it falls back // to the local catalog — that IS degraded and must NOT be flagged intentional, // so model-sync still surfaces the failure (502) for it. const connection = await seedConnection("aimlapi", { apiKey: "aiml-key" }); globalThis.fetch = async () => new Response("upstream down", { status: 500 }); const body = (await (await callRoute(connection.id)).json()) as any; assert.equal(body.source, "local_catalog"); assert.notEqual(body.intentional, true, "degraded fallback must not be flagged intentional"); }); test("provider models route returns the local catalog for Runway video models", async () => { const connection = await seedConnection("runwayml", { apiKey: "runway-key", }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "runwayml"); assert.equal(body.source, "local_catalog"); assert.ok(body.models.some((model) => model.id === "gen4.5")); assert.ok(body.models.some((model) => model.id === "veo3.1")); assert.ok(body.models.some((model) => model.id === "gen3a_turbo")); }); test("provider models route returns the updated local catalog for GitHub Copilot", async () => { const connection = await seedConnection("github", { authType: "oauth", apiKey: null, accessToken: "github-access", providerSpecificData: { copilotToken: "copilot-token", }, }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "github"); assert.equal(body.source, "local_catalog"); assert.ok(body.models.some((model) => model.id === "gpt-5.4")); assert.ok(body.models.some((model) => model.id === "gpt-5.3-codex")); assert.ok(body.models.some((model) => model.id === "claude-opus-4.7")); assert.equal( body.models.some((model) => model.id === "gpt-5.1"), false ); }); test("provider models route returns codex gpt-5.4 effort variants in the local catalog", async () => { const connection = await seedConnection("codex", { authType: "oauth", apiKey: null, accessToken: "codex-access", }); const response = await callRoute(connection.id); const body = (await response.json()) as any; const modelIds = new Set((body.models || []).map((model: any) => model.id)); assert.equal(response.status, 200); assert.equal(body.provider, "codex"); assert.equal(body.source, "local_catalog"); assert.ok(modelIds.has("gpt-5.4")); assert.ok(modelIds.has("gpt-5.4-low")); assert.ok(modelIds.has("gpt-5.4-medium")); assert.ok(modelIds.has("gpt-5.4-high")); assert.ok(modelIds.has("gpt-5.4-xhigh")); }); test("provider models route returns the expanded local catalog for Kiro", async () => { const connection = await seedConnection("kiro", { authType: "oauth", apiKey: null, accessToken: "kiro-access", }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "kiro"); assert.equal(body.source, "local_catalog"); const kiroIds = new Set(body.models.map((model) => model.id)); // #6170: real upstream lineup assert.ok(kiroIds.has("claude-sonnet-5") && kiroIds.has("claude-sonnet-4.5") && kiroIds.has("claude-haiku-4.5")); assert.equal(kiroIds.has("claude-opus-4.7") || kiroIds.has("claude-sonnet-4.6"), false); // fabricated ids removed }); test("provider models route returns the local catalog for new built-in chat-openai-compat providers", async () => { const connection = await seedConnection("deepinfra", { apiKey: "deepinfra-key", }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "deepinfra"); assert.equal(body.source, "local_catalog"); assert.match(body.warning, /local catalog/i); assert.ok(Array.isArray(body.models)); assert.ok(body.models.length > 0); assert.ok(body.models.some((model) => model.id === "openai/gpt-oss-120b")); }); test("provider models route merges Upstage chat and embedding catalogs", async () => { const connection = await seedConnection("upstage", { apiKey: "upstage-key", }); const response = await callRoute(connection.id); const body = (await response.json()) as any; const modelIds = body.models.map((model) => model.id); assert.equal(response.status, 200); assert.equal(body.provider, "upstage"); assert.equal(body.source, "local_catalog"); assert.ok(modelIds.includes("solar-pro3")); assert.ok(modelIds.includes("solar-mini")); assert.ok(modelIds.includes("embedding-query")); assert.ok(modelIds.includes("embedding-passage")); assert.equal(modelIds.includes("document-parse"), false); }); test("provider models route caches discovered opencode-go models per connection", async () => { const connection = await seedConnection("opencode-go", { apiKey: "opencode-go-key", }); let fetchCalls = 0; globalThis.fetch = async (url, init = {}) => { fetchCalls += 1; assert.equal(String(url), "https://opencode.ai/zen/go/v1/models"); assert.equal(init.method, "GET"); assert.equal(init.headers.Authorization, "Bearer opencode-go-key"); return Response.json({ data: [{ id: "glm-5.1", name: "GLM 5.1" }], }); }; const firstResponse = await callRoute(connection.id); const firstBody = (await firstResponse.json()) as any; const cachedModels = await modelsDb.getSyncedAvailableModelsForConnection( "opencode-go", connection.id ); assert.equal(firstResponse.status, 200); assert.equal(firstBody.source, "api"); assert.deepEqual(firstBody.models, [{ id: "glm-5.1", name: "GLM 5.1", owned_by: "opencode-go" }]); assert.deepEqual(cachedModels, [{ id: "glm-5.1", name: "GLM 5.1", source: "imported" }]); globalThis.fetch = async () => { throw new Error("cached route should not hit upstream"); }; const cachedResponse = await callRoute(connection.id); const cachedBody = (await cachedResponse.json()) as any; assert.equal(cachedResponse.status, 200); assert.equal(cachedBody.source, "cache"); assert.deepEqual(cachedBody.models, [{ id: "glm-5.1", name: "GLM 5.1", source: "imported" }]); assert.equal(fetchCalls, 1); }); test("provider models route falls back to cached models when a refresh fails", async () => { const connection = await seedConnection("opencode-go", { apiKey: "opencode-go-key", }); await modelsDb.replaceSyncedAvailableModelsForConnection("opencode-go", connection.id, [ { id: "cached-go", name: "Cached Go", source: "imported" }, ]); let fetchCalls = 0; globalThis.fetch = async () => { fetchCalls += 1; return new Response("upstream unavailable", { status: 503 }); }; const response = await callRoute(connection.id, "?refresh=true"); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "cache"); assert.match(body.warning, /cached catalog/i); assert.deepEqual(body.models, [{ id: "cached-go", name: "Cached Go", source: "imported" }]); // T39 multi-endpoint discovery probes `${base}/v1/models` then `${base}/models` // before giving up; both 503 here, so it makes 2 attempts and then falls back to cache. assert.equal(fetchCalls, 2); }); test("provider models route clears cached discovery when a refresh returns no remote models", async () => { const connection = await seedConnection("opencode-go", { apiKey: "opencode-go-key", }); await modelsDb.replaceSyncedAvailableModelsForConnection("opencode-go", connection.id, [ { id: "cached-go", name: "Cached Go", source: "imported" }, ]); globalThis.fetch = async () => { return Response.json({ data: [] }); }; const response = await callRoute(connection.id, "?refresh=true"); const body = (await response.json()) as any; const cachedModels = await modelsDb.getSyncedAvailableModelsForConnection( "opencode-go", connection.id ); assert.equal(response.status, 200); assert.equal(body.source, "local_catalog"); assert.match(body.warning, /no remote models discovered/i); assert.ok(body.models.every((model) => model.id !== "cached-go")); assert.deepEqual(cachedModels, []); }); test("provider models route honors autoFetchModels=false and skips remote discovery", async () => { const connection = await seedConnection("opencode-go", { apiKey: "opencode-go-key", providerSpecificData: { autoFetchModels: false, }, }); let called = false; globalThis.fetch = async () => { called = true; return Response.json({ data: [{ id: "glm-5.1", name: "GLM 5.1" }], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "local_catalog"); assert.match(body.warning, /auto-fetch disabled/i); assert.equal(called, false); assert.ok(body.models.some((model) => model.id === "glm-5")); }); test("provider models route uses synced models as the authoritative local catalog (#3148)", async () => { // A connection that resolves to the local catalog (auto-fetch off, no remote // discovery). Once a sync has populated the synced-models table for this // provider, the route must surface the synced list — even on a connection // that never ran the sync itself — instead of the static catalog. const connection = await seedConnection("opencode-go", { apiKey: "opencode-go-key", providerSpecificData: { autoFetchModels: false, }, }); await modelsDb.replaceSyncedAvailableModelsForConnection("opencode-go", "synced-conn", [ { id: "synced-only-model", name: "Synced Only Model" }, ]); let called = false; globalThis.fetch = async () => { called = true; return Response.json({ data: [] }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "local_catalog"); assert.equal(called, false); // Synced models become the catalog… assert.ok( body.models.some((model) => model.id === "synced-only-model"), "synced model should be present in the local catalog" ); // …and the static catalog entries are no longer surfaced for this provider. assert.equal( body.models.some((model) => model.id === "glm-5"), false, "static catalog should be superseded by the synced list" ); }); test("provider models route retries Antigravity discovery endpoints before returning remote models", async () => { const connection = await seedConnection("antigravity", { authType: "oauth", accessToken: "ag-access", apiKey: null, }); const seenUrls: string[] = []; antigravityVersion.seedAntigravityVersionCache("1.22.2"); globalThis.fetch = async (url, init = {}) => { const urlString = String(url); // After PR #2219, the discovery flow calls loadCodeAssist first as a project // bootstrap; treat all bootstrap calls as non-fatal failures so the test // exercises the discovery retry path. if (urlString.includes("/v1internal:loadCodeAssist")) { return new Response("nope", { status: 503 }); } seenUrls.push(urlString); if (seenUrls.length === 1) { return new Response("unavailable", { status: 503 }); } assert.equal(init.method, "POST"); assert.equal(init.headers.Authorization, "Bearer ag-access"); assert.match(init.headers["User-Agent"], /^Antigravity\/1\.22\.2 /); assert.equal(init.headers["x-goog-api-client"], undefined); // Use a model id that is in the current user-callable Antigravity allowlist, otherwise // filterUserCallableAntigravityModels() drops it and discovery silently yields 0 models // → the route falls back to local_catalog instead of returning the remote (api) list. return Response.json({ models: [{ id: "gemini-2.5-flash", displayName: "Gemini 2.5 Flash" }], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; // After PR #2219, the route tries `:fetchAvailableModels` URLs before // `:models` URLs. The test mock returns 503 on the first call and success // on the second, so only the first two `:fetchAvailableModels` URLs are // hit — `:models` URLs are never reached. Assert on the actual discovery // sequence the route follows. const discoveryUrls = seenUrls.filter( (url) => url.includes("/v1internal:fetchAvailableModels") || url.includes("/v1internal:models") ); assert.equal(response.status, 200); assert.equal(body.source, "api"); assert.deepEqual(discoveryUrls, [ "https://daily-cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels", "https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels", ]); assert.deepEqual(body.models, [{ id: "gemini-2.5-flash", name: "Gemini 2.5 Flash" }]); }); test("provider models route falls back through all Antigravity discovery endpoints when needed", async () => { const connection = await seedConnection("antigravity", { authType: "oauth", accessToken: "ag-access", apiKey: null, }); const seenUrls = []; globalThis.fetch = async (url) => { seenUrls.push(String(url)); return new Response("down", { status: 502 }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; const discoveryUrls = seenUrls.filter((url) => url.includes("/v1internal:models")); assert.equal(response.status, 200); assert.equal(body.source, "local_catalog"); assert.match(body.warning, /local catalog/i); assert.deepEqual(discoveryUrls, [ "https://daily-cloudcode-pa.googleapis.com/v1internal:models", "https://cloudcode-pa.googleapis.com/v1internal:models", "https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:models", ]); assert.ok(body.models.some((model) => model.id === "gemini-3-pro-preview")); }); test("provider models route returns the local catalog for OAuth-backed Qwen connections", async () => { const connection = await seedConnection("qwen", { authType: "oauth", accessToken: "qwen-access", apiKey: null, }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "local_catalog"); assert.ok(Array.isArray(body.models)); }); test("provider models route filters hidden models from the static Claude catalog when requested", async () => { const connection = await seedConnection("claude", { authType: "oauth", accessToken: "claude-access", apiKey: null, }); modelsDb.mergeModelCompatOverride("claude", "claude-sonnet-4-6", { isHidden: true }); const response = await callRoute(connection.id, "?excludeHidden=true"); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "claude"); assert.ok(body.models.some((model) => model.id === "claude-opus-4-7")); assert.equal( body.models.some((model) => model.id === "claude-sonnet-4-6"), false ); assert.ok(body.models.some((model) => model.id === "claude-opus-4-6")); }); test("provider models route rejects Anthropic-compatible providers without a base URL", async () => { const connection = await seedConnection("anthropic-compatible-demo", { apiKey: "sk-anthropic-compatible", }); const response = await callRoute(connection.id); assert.equal(response.status, 400); assert.deepEqual(await response.json(), { error: "No base URL configured for Anthropic compatible provider", }); }); test("provider models route trims Anthropic-compatible message URLs and filters hidden upstream models", async () => { const connection = await seedConnection("anthropic-compatible-demo", { apiKey: "sk-anthropic-compatible", accessToken: "anthropic-access", providerSpecificData: { baseUrl: "https://proxy.example.com/v1/messages", }, }); modelsDb.mergeModelCompatOverride("anthropic-compatible-demo", "hidden-model", { isHidden: true, }); globalThis.fetch = async (url, init = {}) => { assert.equal(String(url), "https://proxy.example.com/v1/models"); assert.equal(init.method, "GET"); assert.equal(init.headers["Content-Type"], "application/json"); assert.equal(init.headers["x-api-key"], "sk-anthropic-compatible"); assert.equal(init.headers.Authorization, "Bearer anthropic-access"); assert.equal(init.headers["anthropic-version"], "2023-06-01"); return Response.json({ data: [ { id: "visible-model", name: "Visible Model" }, { id: "hidden-model", name: "Hidden Model" }, ], }); }; const response = await callRoute(connection.id, "?excludeHidden=true"); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.deepEqual(body.models, [{ id: "visible-model", name: "Visible Model" }]); }); test("provider models route forwards Anthropic-compatible upstream failures", async () => { const connection = await seedConnection("anthropic-compatible-demo", { apiKey: "sk-anthropic-compatible", providerSpecificData: { baseUrl: "https://proxy.example.com/v1/messages", }, }); globalThis.fetch = async () => new Response("upstream unavailable", { status: 502 }); const response = await callRoute(connection.id); assert.equal(response.status, 502); assert.deepEqual(await response.json(), { error: "Failed to fetch models: 502", }); }); test("provider models route paginates generic providers and filters hidden models when requested", async () => { const connection = await seedConnection("gemini", { apiKey: "gm-key", }); modelsDb.mergeModelCompatOverride("gemini", "gemini-hidden", { isHidden: true }); const seenUrls = []; globalThis.fetch = async (url) => { const currentUrl = String(url); seenUrls.push(currentUrl); if (!currentUrl.includes("pageToken=")) { assert.match(currentUrl, /key=gm-key/); return Response.json({ models: [ { name: "models/gemini-visible", displayName: "Gemini Visible", supportedGenerationMethods: ["generateContent"], }, { name: "models/gemini-hidden", displayName: "Gemini Hidden", supportedGenerationMethods: ["generateContent"], }, ], nextPageToken: "page-2", }); } assert.match(currentUrl, /pageToken=page-2/); assert.match(currentUrl, /key=gm-key/); return Response.json({ models: [ { name: "models/text-embedding-004", displayName: "Text Embedding 004", supportedGenerationMethods: ["embedContent"], }, ], }); }; const response = await callRoute(connection.id, "?excludeHidden=true"); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.deepEqual(body.models.map((model) => model.id).sort(), [ "gemini-visible", "text-embedding-004", ]); assert.equal(seenUrls.length, 2); }); test("provider models route stops pagination when the upstream repeats the next page token", async () => { const connection = await seedConnection("gemini", { apiKey: "gm-key", }); let calls = 0; globalThis.fetch = async () => { calls += 1; return Response.json({ models: [ { name: `models/gemini-page-${calls}`, displayName: `Gemini Page ${calls}`, supportedGenerationMethods: ["generateContent"], }, ], nextPageToken: "duplicate-token", }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.deepEqual( body.models.map((model) => model.id), ["gemini-page-1", "gemini-page-2"] ); assert.equal(calls, 2); }); test("provider models route forwards upstream status codes for generic provider model fetch failures", async () => { const connection = await seedConnection("groq", { apiKey: "groq-models-token", }); globalThis.fetch = async () => new Response("upstream unavailable", { status: 503 }); const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "local_catalog"); assert.match(body.warning, /local catalog/i); assert.ok(Array.isArray(body.models)); assert.ok(body.models.length > 0); }); test("provider models route returns 500 when fetching models throws unexpectedly", async () => { const connection = await seedConnection("groq", { apiKey: "groq-models-token", }); globalThis.fetch = async () => { throw new Error("socket closed"); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "local_catalog"); assert.match(body.warning, /local catalog/i); }); test("provider models route rejects generic providers without any configured token", async () => { const connection = await seedConnection("groq", { apiKey: null, accessToken: null, }); let called = false; globalThis.fetch = async () => { called = true; return Response.json({ data: [] }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.source, "local_catalog"); assert.match(body.warning, /local catalog/i); assert.equal(called, false); }); test("provider models route discovers active DataRobot gateway models from the catalog endpoint", async () => { const connection = await seedConnection("datarobot", { apiKey: "dr-key", providerSpecificData: { baseUrl: "https://app.datarobot.com", }, }); globalThis.fetch = async (url, init = {}) => { assert.equal(String(url), "https://app.datarobot.com/genai/llmgw/catalog/"); assert.equal(init.method, "GET"); assert.equal(init.headers.Authorization, "Bearer dr-key"); return Response.json({ data: [ { model: "azure/gpt-5-mini-2025-08-07", isActive: true }, { model: "azure/gpt-4o-mini", label: "Azure GPT-4o Mini", isActive: true }, { model: "anthropic/claude-sonnet-4-6", isActive: false }, ], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "datarobot"); assert.equal(body.source, "api"); assert.deepEqual(body.models, [ { id: "azure/gpt-5-mini-2025-08-07", name: "azure/gpt-5-mini-2025-08-07", owned_by: "datarobot", }, { id: "azure/gpt-4o-mini", name: "Azure GPT-4o Mini", owned_by: "datarobot", }, ]); }); test("provider models route discovers Clarifai OpenAI-compatible models with Key auth", async () => { const connection = await seedConnection("clarifai", { apiKey: "clarifai-pat", }); globalThis.fetch = async (url, init = {}) => { assert.equal(String(url), "https://api.clarifai.com/v2/ext/openai/v1/models"); assert.equal(init.method, "GET"); assert.equal(init.headers.Authorization, "Key clarifai-pat"); return Response.json({ data: [ { id: "openai/chat-completion/models/gpt-oss-120b", display_name: "GPT-OSS 120B", }, { id: "anthropic/completion/models/claude-sonnet-4" }, ], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "clarifai"); assert.equal(body.source, "api"); assert.deepEqual(body.models, [ { id: "openai/chat-completion/models/gpt-oss-120b", name: "GPT-OSS 120B", owned_by: "clarifai", }, { id: "anthropic/completion/models/claude-sonnet-4", name: "anthropic/completion/models/claude-sonnet-4", owned_by: "clarifai", }, ]); }); test("provider models route discovers Azure AI Foundry deployments through the v1 models endpoint", async () => { const connection = await seedConnection("azure-ai", { apiKey: "azure-ai-key", providerSpecificData: { baseUrl: "https://my-foundry.services.ai.azure.com", }, }); globalThis.fetch = async (url, init = {}) => { assert.equal(String(url), "https://my-foundry.services.ai.azure.com/openai/v1/models"); assert.equal(init.method, "GET"); assert.equal(init.headers["api-key"], "azure-ai-key"); return Response.json({ data: [{ id: "DeepSeek-V3.1", display_name: "DeepSeek V3.1" }, { name: "Claude-Opus-4.6" }], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "azure-ai"); assert.equal(body.source, "api"); assert.deepEqual(body.models, [ { id: "DeepSeek-V3.1", name: "DeepSeek V3.1", owned_by: "azure-ai" }, { id: "Claude-Opus-4.6", name: "Claude-Opus-4.6", owned_by: "azure-ai" }, ]); }); test("provider models route discovers Azure OpenAI deployments from the resource endpoint", async () => { const connection = await seedConnection("azure-openai", { apiKey: "azure-openai-key", providerSpecificData: { baseUrl: "https://my-resource.openai.azure.com/openai", apiVersion: "2024-12-01-preview", }, }); globalThis.fetch = async (url, init = {}) => { assert.equal( String(url), "https://my-resource.openai.azure.com/openai/deployments?api-version=2024-12-01-preview" ); assert.equal(init.method, "GET"); assert.equal(init.headers["api-key"], "azure-openai-key"); return Response.json({ data: [ { id: "gpt4o-prod", model: "gpt-4o", display_name: "GPT-4o Production" }, { id: "o3-mini-staging", model: "o3-mini" }, ], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "azure-openai"); assert.equal(body.source, "api"); assert.deepEqual(body.models, [ { id: "gpt4o-prod", name: "GPT-4o Production", owned_by: "azure-openai" }, { id: "o3-mini-staging", name: "o3-mini-staging", owned_by: "azure-openai" }, ]); }); test("provider models route discovers native Bedrock foundation models and inference profiles", async () => { const connection = await seedConnection("bedrock", { apiKey: "bedrock-key", providerSpecificData: { region: "eu-west-2", }, }); const seenUrls: string[] = []; globalThis.fetch = async (url, init = {}) => { const target = String(url); seenUrls.push(target); assert.equal(init.method, "GET"); assert.equal(init.headers.Authorization, "Bearer bedrock-key"); if ( target === "https://bedrock.eu-west-2.amazonaws.com/foundation-models?byOutputModality=TEXT" ) { return Response.json({ modelSummaries: [ { modelId: "anthropic.claude-sonnet-4-6", modelName: "Claude Sonnet 4.6", providerName: "Anthropic", inputModalities: ["TEXT", "IMAGE"], outputModalities: ["TEXT"], responseStreamingSupported: true, }, ], }); } if ( target === "https://bedrock.eu-west-2.amazonaws.com/inference-profiles?maxResults=100&typeEquals=SYSTEM_DEFINED" ) { return Response.json({ inferenceProfileSummaries: [ { inferenceProfileId: "eu.anthropic.claude-sonnet-4-6", inferenceProfileName: "EU Claude Sonnet 4.6", models: [ { modelArn: "arn:aws:bedrock:eu-west-2::foundation-model/anthropic.claude-sonnet-4-6", }, ], }, ], }); } throw new Error("unexpected fetch: " + target); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "bedrock"); assert.equal(body.source, "api"); assert.deepEqual(seenUrls, [ "https://bedrock.eu-west-2.amazonaws.com/foundation-models?byOutputModality=TEXT", "https://bedrock.eu-west-2.amazonaws.com/inference-profiles?maxResults=100&typeEquals=SYSTEM_DEFINED", ]); assert.deepEqual(body.models, [ { id: "anthropic.claude-sonnet-4-6", name: "Claude Sonnet 4.6", owned_by: "Anthropic", source: "foundation", supportsStreaming: true, supportsVision: true, inputTokenLimit: 1000000, outputTokenLimit: 64000, }, { id: "eu.anthropic.claude-sonnet-4-6", name: "EU Claude Sonnet 4.6", owned_by: "bedrock", source: "inference_profile", supportsStreaming: true, inputTokenLimit: 1000000, outputTokenLimit: 64000, }, ]); }); test("provider models route discovers watsonx gateway models from the v1 models endpoint", async () => { const connection = await seedConnection("watsonx", { apiKey: "watsonx-key", providerSpecificData: { baseUrl: "https://ca-tor.ml.cloud.ibm.com", }, }); globalThis.fetch = async (url, init = {}) => { assert.equal(String(url), "https://ca-tor.ml.cloud.ibm.com/ml/gateway/v1/models"); assert.equal(init.method, "GET"); assert.equal(init.headers.Authorization, "Bearer watsonx-key"); return Response.json({ data: [ { id: "ibm/granite-3-3-8b-instruct", display_name: "Granite 3.3 8B Instruct" }, { model: "openai/gpt-4o", provider: "openai" }, ], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "watsonx"); assert.equal(body.source, "api"); assert.deepEqual(body.models, [ { id: "ibm/granite-3-3-8b-instruct", name: "Granite 3.3 8B Instruct", owned_by: "watsonx", }, { id: "openai/gpt-4o", name: "openai/gpt-4o", owned_by: "openai", }, ]); }); test("provider models route discovers OCI OpenAI-compatible models and forwards the project header", async () => { const connection = await seedConnection("oci", { apiKey: "oci-key", projectId: "ocid1.generativeaiproject.oc1.us-chicago-1.demo", providerSpecificData: { baseUrl: "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com", }, }); globalThis.fetch = async (url, init = {}) => { assert.equal( String(url), "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/openai/v1/models" ); assert.equal(init.method, "GET"); assert.equal(init.headers.Authorization, "Bearer oci-key"); assert.equal(init.headers["OpenAI-Project"], "ocid1.generativeaiproject.oc1.us-chicago-1.demo"); return Response.json({ data: [ { id: "openai.gpt-oss-20b", display_name: "OpenAI GPT-OSS 20B" }, { id: "google.gemini-2.5-pro" }, ], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "oci"); assert.equal(body.source, "api"); assert.deepEqual(body.models, [ { id: "openai.gpt-oss-20b", name: "OpenAI GPT-OSS 20B", owned_by: "oci", }, { id: "google.gemini-2.5-pro", name: "google.gemini-2.5-pro", owned_by: "oci", }, ]); }); test("provider models route discovers Modal models from the configured OpenAI-compatible /v1 endpoint", async () => { const connection = await seedConnection("modal", { apiKey: "modal-key", providerSpecificData: { baseUrl: "https://alice--demo.modal.run/v1", }, }); globalThis.fetch = async (url, init = {}) => { assert.equal(String(url), "https://alice--demo.modal.run/v1/models"); assert.equal(init.method, "GET"); assert.equal(init.headers.Authorization, "Bearer modal-key"); return Response.json({ data: [ { id: "Qwen/Qwen3-4B-Thinking-2507-FP8", display_name: "Qwen3 4B Thinking FP8" }, { id: "google/gemma-4-26B-A4B-it" }, ], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "modal"); assert.equal(body.source, "api"); assert.deepEqual(body.models, [ { id: "Qwen/Qwen3-4B-Thinking-2507-FP8", name: "Qwen3 4B Thinking FP8", owned_by: "modal", }, { id: "google/gemma-4-26B-A4B-it", name: "google/gemma-4-26B-A4B-it", owned_by: "modal", }, ]); }); test("provider models route always returns the Reka preset catalog", async () => { const connection = await seedConnection("reka", { apiKey: "reka-key", providerSpecificData: { baseUrl: "https://api.reka.ai/v1", }, }); globalThis.fetch = async () => { throw new Error("Reka models endpoint should not be probed"); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "reka"); assert.equal(body.source, "local_catalog"); assert.deepEqual( body.models.map((model) => model.id), ["reka-flash-3", "reka-flash", "reka-edge-2603"] ); }); test("provider models route returns Reka local catalog without an API key", async () => { const connection = await seedConnection("reka", { providerSpecificData: { baseUrl: "https://api.reka.ai/v1", }, }); globalThis.fetch = async () => { throw new Error("Reka models endpoint should not be probed without a token"); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "reka"); assert.equal(body.source, "local_catalog"); assert.deepEqual( body.models.map((model) => model.id), ["reka-flash-3", "reka-flash", "reka-edge-2603"] ); }); test("provider models route discovers SAP models from AI_API_URL derived from deploymentUrl", async () => { const connection = await seedConnection("sap", { apiKey: "sap-key", providerSpecificData: { baseUrl: "https://sap.example.com/v2/lm/deployments/demo-deployment", resourceGroup: "shared", }, }); globalThis.fetch = async (url, init = {}) => { assert.equal(String(url), "https://sap.example.com/v2/lm/scenarios/foundation-models/models"); assert.equal(init.method, "GET"); assert.equal(init.headers.Authorization, "Bearer sap-key"); assert.equal(init.headers["AI-Resource-Group"], "shared"); return Response.json({ resources: [ { model: "gpt-4o", displayName: "GPT-4o", provider: "OpenAI" }, { model: "mistralai--mistral-medium-instruct", provider: "Mistral AI" }, ], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "sap"); assert.equal(body.source, "api"); assert.deepEqual(body.models, [ { id: "gpt-4o", name: "GPT-4o", owned_by: "OpenAI", }, { id: "mistralai--mistral-medium-instruct", name: "mistralai--mistral-medium-instruct", owned_by: "Mistral AI", }, ]); }); test("provider models route rejects unsupported providers without a models config", async () => { const connection = await seedConnection("unsupported-provider", { apiKey: "sk-unsupported", }); const response = await callRoute(connection.id); assert.equal(response.status, 400); assert.deepEqual(await response.json(), { error: "Provider unsupported-provider does not support models listing", }); }); test("provider models route uses provider-specific auth headers for Kimi Coding", async () => { const connection = await seedConnection("kimi-coding", { apiKey: "kimi-coding-key", }); globalThis.fetch = async (url, init = {}) => { assert.equal(String(url), "https://api.kimi.com/coding/v1/models"); assert.equal(init.method, "GET"); assert.equal(init.headers["x-api-key"], "kimi-coding-key"); assert.equal(init.headers.Authorization, undefined); return Response.json({ data: [{ id: "kimi-k2.5", name: "Kimi K2.5" }], }); }; const response = await callRoute(connection.id); const body = (await response.json()) as any; assert.equal(response.status, 200); assert.equal(body.provider, "kimi-coding"); assert.deepEqual(body.models, [{ id: "kimi-k2.5", name: "Kimi K2.5" }]); });