fix(combo): advance to next model on 400 'model not supported' (#5249)

A 400 classified as MODEL_CAPACITY (e.g. 'requested model is not supported') hit the #2101 anti-loop stop-branch and halted the combo instead of advancing. Drop the MODEL_CAPACITY trigger from that stop condition so model-specific 400s fall through to the next combo target; genuinely body-specific 400s (malformed/invalid/bad-request substrings) still stop. Validated: combo-strategies suite 16/16 (incl. the new regression test) green on current release tip, typecheck clean. Stale pre-merge CI was from an older base.

Co-authored-by: Chewji9875 <Chewji9875@users.noreply.github.com>
This commit is contained in:
Chewji
2026-06-29 11:33:15 +07:00
committed by GitHub
parent 21c1f540b3
commit 12de25b6f6
2 changed files with 37 additions and 3 deletions

View File

@@ -17,7 +17,6 @@ import {
recordProviderFailure,
selectLockoutCooldownMs,
} from "./accountFallback.ts";
import { RateLimitReason } from "../config/constants.ts";
import { errorResponse, unavailableResponse } from "../utils/error.ts";
import {
recordComboIntent,
@@ -2345,8 +2344,7 @@ export async function handleComboChat({
fallbackResult.shouldFallback &&
!isContextOverflow400(errorText) &&
!isParamValidation400(errorText) &&
(fallbackResult.reason === RateLimitReason.MODEL_CAPACITY ||
errorText.toLowerCase().includes("context") ||
(errorText.toLowerCase().includes("context") ||
errorText.toLowerCase().includes("prompt") ||
errorText.toLowerCase().includes("token") ||
errorText.toLowerCase().includes("malformed") ||

View File

@@ -708,3 +708,39 @@ test("reset-aware strategy scores provider-specific weekly windows when availabl
assert.equal(await selectedConnectionFor(combo), soon);
});
test("priority combo advances to next model when first returns 400 'model not supported'", async () => {
const name = `model-not-supported-${randomUUID()}`;
const combo = await combosDb.createCombo({
name,
strategy: "priority",
models: ["openai/gpt-4", "openai/gpt-3.5-turbo"],
});
const calls: string[] = [];
const response = await handleComboChat({
body: reqBodyTextArray,
combo,
allCombos: [combo],
isModelAvailable: undefined,
relayOptions: undefined,
signal: undefined,
settings: {},
log: makeLog(),
handleSingleModel: async (_body: unknown, modelStr: string) => {
calls.push(modelStr);
if (modelStr === "openai/gpt-4") {
return Response.json(
{ error: { message: "requested model is not supported" } },
{ status: 400 }
);
}
return okResponse(modelStr);
},
});
assert.equal(response.status, 200, "combo should advance to second model and return 200");
assert.equal(calls.length, 2, "combo should have tried both models");
assert.equal(calls[0], "openai/gpt-4", "first model should be tried first");
assert.equal(calls[1], "openai/gpt-3.5-turbo", "second model should be tried after 400");
});