Files
diegosouzapw--omniroute/tests/unit/provider-models-route.test.ts
2026-07-13 13:39:12 +08:00

1752 lines
59 KiB
TypeScript

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<string, any>).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" }]);
});