fix(autoRouting): recognize auto/\<family\> combos in classifyAutoModel (#8866)

* fix(autoRouting): recognize auto/\<family\> combos in classifyAutoModel

classifyAutoModel() checks VALID_AUTO_VARIANTS and parseAutoSuffix but
never isValidModelFamily, so auto/glm, auto/minimax, auto/llama etc. are
rejected as "Unknown built-in auto combo" before chatHelpers.ts or
builtinCatalog.ts can handle them.

Fix: import isValidModelFamily and ModelFamily, add family to spec type,
check family suffixes before returning unrecognized. Mirrors the pattern
already in builtinCatalog.ts createBuiltinAutoCombo.

Closes: auto/\<family\> combos listed in /api/combos/auto but unusable
at /v1/chat/completions.

* test(autoRouting): cover auto/<family> classification + changelog fragment

The PR changed production code with no test — nothing in tests/ referenced
classifyAutoModel. Since it is module-private, the new suite exercises it through
the public resolveAutoRoutingState().

Verified it guards something real: against the release tip without this fix the
family case fails ("auto/glm should be a recognized built-in auto model"), and
passes with it. Also pins that a category suffix does not pick up spec.family and
that an unknown suffix stays unrecognized.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: rafaeldrincon <rafaeldrincon@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
rafaeldrincon
2026-07-28 13:18:38 -04:00
committed by GitHub
parent 832d713358
commit bf77648071
3 changed files with 69 additions and 7 deletions

View File

@@ -0,0 +1 @@
- **Auto routing**: `auto/<family>` combos (`auto/glm`, `auto/gemini`, `auto/llama`, …) are recognized as built-in auto models again — the family suffix failed the category/tier parser and fell through as an unknown model instead of routing to that family

View File

@@ -10,13 +10,17 @@ import {
type AutoCategory,
type AutoTier,
} from "@omniroute/open-sse/services/autoCombo/suffixComposition.ts";
import {
isValidModelFamily,
type ModelFamily,
} from "@omniroute/open-sse/services/autoCombo/modelFamily.ts";
import { getCachedSettings } from "@/lib/localDb";
import * as log from "../utils/logger";
export type AutoRoutingState = {
model: string;
variant?: AutoVariant;
spec?: { category?: AutoCategory; tier?: AutoTier };
spec?: { category?: AutoCategory; tier?: AutoTier; family?: ModelFamily };
isAutoRouting: boolean;
recognizedBuiltInAuto: boolean;
response: Response | null;
@@ -37,12 +41,19 @@ function classifyAutoModel(
return { recognizedBuiltInAuto: true };
}
const parsedSuffix = parseAutoSuffix(suffix);
return parsedSuffix.valid
? {
recognizedBuiltInAuto: true,
spec: { category: parsedSuffix.category, tier: parsedSuffix.tier },
}
: { recognizedBuiltInAuto };
if (parsedSuffix.valid) {
return {
recognizedBuiltInAuto: true,
spec: { category: parsedSuffix.category, tier: parsedSuffix.tier },
};
}
if (isValidModelFamily(suffix)) {
return {
recognizedBuiltInAuto: true,
spec: { family: suffix as ModelFamily },
};
}
return { recognizedBuiltInAuto };
}
async function applyAutoPrefix(

View File

@@ -0,0 +1,50 @@
/**
* #8866 — `auto/<family>` must be recognized as a built-in auto model.
*
* classifyAutoModel() is module-private, so this exercises it through the public
* resolveAutoRoutingState(). Before the fix, a family suffix failed parseAutoSuffix()
* and fell through to `recognizedBuiltInAuto: false` with no spec, so `auto/glm` was
* treated as an unknown model instead of a family-scoped auto combo.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { MODEL_FAMILIES } from "@omniroute/open-sse/services/autoCombo/modelFamily.ts";
import { resolveAutoRoutingState } from "../../src/sse/handlers/autoRouting.ts";
test("#8866: every model family is recognized as auto/<family>", async () => {
assert.ok(MODEL_FAMILIES.length > 0, "expected a non-empty family list");
for (const family of MODEL_FAMILIES) {
const state = await resolveAutoRoutingState(`auto/${family}`);
assert.equal(
state.recognizedBuiltInAuto,
true,
`auto/${family} should be a recognized built-in auto model`
);
assert.equal(state.spec?.family, family, `auto/${family} should carry spec.family`);
assert.equal(state.isAutoRouting, true);
}
});
test("#8866: a family suffix does not hijack the category/tier spec", async () => {
// A valid category/tier suffix keeps its own shape — the family branch is only a
// fallback for suffixes parseAutoSuffix rejects.
const state = await resolveAutoRoutingState("auto/coding");
assert.equal(state.recognizedBuiltInAuto, true);
assert.equal(state.spec?.family, undefined, "auto/coding is a category, not a family");
});
test("#8866: an unknown suffix stays unrecognized", async () => {
const state = await resolveAutoRoutingState("auto/not-a-real-family-xyz");
assert.equal(
state.recognizedBuiltInAuto,
false,
"an unknown suffix must not be treated as a built-in auto model"
);
assert.equal(state.spec?.family, undefined);
});
test("#8866: a plain model is untouched by the family branch", async () => {
const state = await resolveAutoRoutingState("gpt-5.6-sol");
assert.equal(state.isAutoRouting, false);
assert.equal(state.spec?.family, undefined);
});