Repository navigation
revert(feat): improve auto routing #1969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,12 +9,7 @@ import { | |
| } from "@/chat-helpers.e2e.js"; | ||
|
|
||
| import { db, tables, eq } from "@llmgateway/db"; | ||
| import { | ||
| hasProviderEnvironmentToken, | ||
| models, | ||
| providers, | ||
| getProviderEnvVar, | ||
| } from "@llmgateway/models"; | ||
| import { models, providers, getProviderEnvVar } from "@llmgateway/models"; | ||
|
|
||
| import { app } from "./app.js"; | ||
| import { | ||
|
|
@@ -108,15 +103,6 @@ describe("e2e individual tests", () => { | |
| } | ||
| } | ||
|
|
||
| function hasConfiguredProviderForModel(modelId: string) { | ||
| const model = models.find((modelDef) => modelDef.id === modelId); | ||
| return ( | ||
| model?.providers.some((provider) => | ||
| hasProviderEnvironmentToken(provider.providerId), | ||
| ) ?? false | ||
| ); | ||
| } | ||
|
|
||
| test( | ||
| "JSON output mode error for unsupported model", | ||
| getTestOptions({ completions: false }), | ||
|
|
@@ -317,16 +303,19 @@ describe("e2e individual tests", () => { | |
| "completions with llmgateway/auto in credits mode", | ||
| getTestOptions({ completions: false }), | ||
| async () => { | ||
| if (!hasConfiguredProviderForModel("claude-sonnet-4-6")) { | ||
| console.log( | ||
| "Skipping llmgateway/auto in credits mode test - no Claude Sonnet 4.6 provider is configured", | ||
| ); | ||
| return; | ||
| // require all provider keys to be set | ||
| for (const provider of providers) { | ||
| const envVarName = getProviderEnvVar(provider.id); | ||
| const envVarValue = envVarName ? process.env[envVarName] : undefined; | ||
| if (!envVarValue) { | ||
| console.log( | ||
| `Skipping llmgateway/auto in credits mode test - no API key provided for ${provider.id}`, | ||
| ); | ||
| return; | ||
| } | ||
|
Comment on lines
+306
to
+315
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This gate will skip the auto-routing credits test in most environments. Requiring keys for every provider ( 🔧 Proposed fix- // require all provider keys to be set
- for (const provider of providers) {
- const envVarName = getProviderEnvVar(provider.id);
- const envVarValue = envVarName ? process.env[envVarName] : undefined;
- if (!envVarValue) {
- console.log(
- `Skipping llmgateway/auto in credits mode test - no API key provided for ${provider.id}`,
- );
- return;
- }
- }
+ // require at least one provider key eligible for auto-routing
+ const autoModelIds = new Set(["gpt-oss-120b", "gpt-5-nano", "gpt-4.1-nano"]);
+ const autoProviderIds = new Set(
+ models
+ .filter((m) => autoModelIds.has(m.id))
+ .flatMap((m) => m.providers.map((p) => p.providerId)),
+ );
+ const hasAnyAutoProviderKey = Array.from(autoProviderIds).some((providerId) => {
+ const envVarName = getProviderEnvVar(providerId);
+ return Boolean(envVarName && process.env[envVarName]);
+ });
+ if (!hasAnyAutoProviderKey) {
+ console.log(
+ "Skipping llmgateway/auto in credits mode test - no eligible auto-routing provider key configured",
+ );
+ return;
+ }🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| const { userId, orgId, projectId } = await createTestData( | ||
| `credits-auto-${Date.now()}`, | ||
| ); | ||
| const { userId, orgId, projectId } = await createTestData("credits-auto"); | ||
|
||
|
|
||
| await db | ||
| .update(tables.organization) | ||
|
|
@@ -338,10 +327,9 @@ describe("e2e individual tests", () => { | |
| .set({ mode: "credits" }) | ||
| .where(eq(tables.project.id, projectId)); | ||
|
|
||
| const creditsSuffix = generateTestRequestId(); | ||
| const creditsToken = `credits-token-auto-${creditsSuffix}`; | ||
| const creditsToken = "credits-token-auto"; | ||
| await db.insert(tables.apiKey).values({ | ||
| id: `token-credits-auto-${creditsSuffix}`, | ||
| id: "token-credits-auto", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This insert reuses Useful? React with 👍 / 👎. |
||
| token: creditsToken, | ||
| projectId: projectId, | ||
| description: "Test API Key for Credits", | ||
|
|
@@ -374,27 +362,17 @@ describe("e2e individual tests", () => { | |
| expect(json).toHaveProperty("choices.[0].message.content"); | ||
|
|
||
| const log = await waitForLogByRequestId(requestId); | ||
| expect(log.requestedModel).toBe("llmgateway/auto"); | ||
| expect(log.requestedModel).toBe("auto"); | ||
| expect(log.usedProvider).toBeTruthy(); | ||
| expect(log.usedModel).toBeTruthy(); | ||
| expect(log.usedModel).toContain("claude-sonnet-4-6"); | ||
| }, | ||
| ); | ||
|
|
||
| test( | ||
| "completions with bare 'auto' model and credits", | ||
| getTestOptions({ completions: false }), | ||
| async () => { | ||
| if (!hasConfiguredProviderForModel("claude-sonnet-4-6")) { | ||
| console.log( | ||
| "Skipping bare auto credits test - no Claude Sonnet 4.6 provider is configured", | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| const { orgId, projectId, token } = await createTestData( | ||
| `bare-auto-${Date.now()}`, | ||
| ); | ||
| const { orgId, projectId, token } = await createTestData("bare-auto"); | ||
|
|
||
| await db | ||
| .update(tables.organization) | ||
|
|
@@ -434,7 +412,6 @@ describe("e2e individual tests", () => { | |
| expect(log.requestedModel).toBe("auto"); | ||
| expect(log.usedProvider).toBeTruthy(); | ||
| expect(log.usedModel).toBeTruthy(); | ||
| expect(log.usedModel).toContain("claude-sonnet-4-6"); | ||
| }, | ||
| ); | ||
|
|
||
|
|
@@ -665,9 +642,11 @@ describe("e2e individual tests", () => { | |
| "Auto-routing sets reasoning_effort appropriately", | ||
| getTestOptions({ completions: false }), | ||
| async () => { | ||
| if (!hasConfiguredProviderForModel("claude-sonnet-4-6")) { | ||
| const envVarName = getProviderEnvVar("openai"); | ||
| const envVarValue = envVarName ? process.env[envVarName] : undefined; | ||
| if (!envVarValue) { | ||
| console.log( | ||
| "Skipping auto-routing reasoning_effort test - no Claude Sonnet 4.6 provider is configured", | ||
| "Skipping auto-routing reasoning_effort test - no OpenAI API key provided", | ||
| ); | ||
| return; | ||
| } | ||
|
|
@@ -719,11 +698,14 @@ describe("e2e individual tests", () => { | |
| // Verify a reasoning model was selected | ||
| const usedModel = log.usedModelMapping; | ||
| expect(usedModel).toBeDefined(); | ||
| expect(usedModel).toContain("claude-sonnet-4-6"); | ||
|
|
||
| // Claude auto-routing should always default to low reasoning effort. | ||
| // Verify reasoningEffort is set and has the correct value based on model | ||
| expect(log.reasoningEffort).toBeDefined(); | ||
| expect(log.reasoningEffort).toEqual("low"); | ||
| if (usedModel?.startsWith("gpt-5")) { | ||
| expect(log.reasoningEffort).toEqual("minimal"); | ||
| } else { | ||
| expect(log.reasoningEffort).toEqual("low"); | ||
| } | ||
|
|
||
| // Verify the response has valid usage information (if available) | ||
| // Some auto-routed models may not return usage in non-streaming mode | ||
|
|
@@ -742,63 +724,6 @@ describe("e2e individual tests", () => { | |
| }, | ||
| ); | ||
|
|
||
| test( | ||
| "Auto-routing with no_reasoning chooses Claude Haiku 4.5", | ||
| getTestOptions({ completions: false }), | ||
| async () => { | ||
| if (!hasConfiguredProviderForModel("claude-haiku-4-5")) { | ||
| console.log( | ||
| "Skipping auto-routing no_reasoning test - no Claude Haiku 4.5 provider is configured", | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| const { orgId, projectId, token } = await createTestData( | ||
| `auto-no-reasoning-${Date.now()}`, | ||
| ); | ||
|
|
||
| await db | ||
| .update(tables.organization) | ||
| .set({ credits: "1000" }) | ||
| .where(eq(tables.organization.id, orgId)); | ||
|
|
||
| await db | ||
| .update(tables.project) | ||
| .set({ mode: "credits" }) | ||
| .where(eq(tables.project.id, projectId)); | ||
|
|
||
| const requestId = generateTestRequestId(); | ||
| const res = await app.request("/v1/chat/completions", { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| "x-request-id": requestId, | ||
| "x-no-fallback": "true", | ||
| Authorization: `Bearer ${token}`, | ||
| }, | ||
| body: JSON.stringify({ | ||
| model: "auto", | ||
| no_reasoning: true, | ||
| messages: [ | ||
| { | ||
| role: "user", | ||
| content: "Summarize this request without extended reasoning.", | ||
| }, | ||
| ], | ||
| }), | ||
| }); | ||
|
|
||
| expect(res.status).toBe(200); | ||
| const json = await res.json(); | ||
| validateResponse(json); | ||
|
|
||
| const log = await validateLogByRequestId(requestId); | ||
| expect(log.requestedModel).toBe("auto"); | ||
| expect(log.usedModelMapping).toContain("claude-haiku-4-5"); | ||
| expect(log.reasoningEffort).toBeNull(); | ||
| }, | ||
| ); | ||
|
|
||
| test( | ||
| "Success when requesting multi-provider model without prefix", | ||
| getTestOptions({ completions: false }), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The credits auto-routing test now requires all provider env vars to be set in order to run. This makes the test extremely likely to be skipped in most environments and reduces coverage of the auto-routing path. Consider only requiring the providers that can actually be selected by the auto-routing candidates under test (e.g., the providers backing
allowedAutoModels), or at minimum the provider you expect the test to route to.