fix(routing): recognize CLIProxyAPI unknown-provider 400 as fallback-worthy (#12800) (#13284)

Merged as part of the 39-PR owner batch of 2026-09-11, validated as a unit.

Boarded into one consolidated worktree cut from `release/v3.8.51` with the other 38 — zero conflicts between them.

- ESLint over every changed file: no errors (the only finding was one suppression entry the batch emptied, pruned on #13243)
- `typecheck:core` clean; `check:dashboard-typecheck` OK (206 pre-existing, within baseline); `check:changelog-integrity` OK
- complexity 2821 / baseline 3218 and cognitive-complexity 1272 / baseline 1437 — both under baseline
- 256 assertions green: 246 under node:test and 10 under vitest, which is where `tests/unit/**/*.test.tsx` actually runs
- `check-file-size`: `chatCore.ts` rebaselined 6144 → 6146 for #13278 and #13276, annotated and landed on #13243

⚠️ base-red inherited: #12732 — the provider count (356 in the docs vs the 358 the modules define) and `open-sse/utils/stream.ts` at 3115 > frozen 3098 both reproduce on the pure tip with zero contribution from this batch.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-09-11 22:05:47 -03:00
committed by GitHub
parent 7a938fe39f
commit 660137b3ce
3 changed files with 29 additions and 2 deletions

View File

@@ -0,0 +1 @@
- fix(routing): recognize CLIProxyAPI's 'unknown provider for model' 400 as fallback-worthy (#12800)

View File

@@ -376,7 +376,7 @@ export const MODEL_ACCESS_DENIED_PATTERNS = [
/\bunsupported\s+model\b/i,
/\baccess.*denied.*model\b/i,
/\bmodel.*access.*denied\b/i,
/\bplease select a different model\b/i,
/\bplease select a different model\b/i, /\bunknown\s+provider\s+for\s+model\b/i,
// "...access to the requested model" / "model ... access" — bounded lookahead
// (no nested quantifiers) so it stays ReDoS-safe while requiring BOTH an
// access/permission word and "model" so a pure auth error never matches.
@@ -416,7 +416,7 @@ const PROVIDER_MODEL_UNSUPPORTED_PATTERNS = [
/\bmodel\b[\s\S]{0,80}?\b(?:does\s+not\s+support|doesn't\s+support|unsupported)\b/i,
/\b(?:does\s+not\s+support|doesn't\s+support|unsupported)\b[\s\S]{0,80}?\bmodel\b/i,
/\bunsupported\s+model\b/i,
/\bplease select a different model\b/i,
/\bplease select a different model\b/i, /\bunknown\s+provider\s+for\s+model\b/i,
];
/**

View File

@@ -0,0 +1,26 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import {
MODEL_ACCESS_DENIED_PATTERNS,
isProviderModelUnsupported400,
} from "../../open-sse/services/accountFallback.ts";
const CLIPROXYAPI_ERROR_TEXT = "unknown provider for model Qwen/Qwen3.6-27B-TEE";
describe("#12800 — CLIProxyAPI 'unknown provider for model X' classification", () => {
it("MODEL_ACCESS_DENIED_PATTERNS should recognize it as a model-access-denied 400", () => {
const matches = MODEL_ACCESS_DENIED_PATTERNS.some((p) => p.test(CLIPROXYAPI_ERROR_TEXT));
assert.equal(matches, true);
});
it("isProviderModelUnsupported400() should recognize it as provider-wide unsupported", () => {
const result = isProviderModelUnsupported400(400, CLIPROXYAPI_ERROR_TEXT);
assert.equal(result, true);
});
it("should not match a genuine auth/credential error", () => {
const authText = "invalid api key for model Qwen/Qwen3.6-27B-TEE";
assert.equal(isProviderModelUnsupported400(400, authText), false);
});
});