mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-29 06:33:28 +00:00
fix(ui): match simple auto router models to advanced setup (#48851)
This commit is contained in:
parent
471918c30b
commit
fd9a37d233
4 changed files with 77 additions and 31 deletions
|
|
@ -37,6 +37,7 @@ import {
|
|||
} from "./tier_rows";
|
||||
import React from "react";
|
||||
import { ModelGroup } from "@/components/llm_calls/fetch_models";
|
||||
import { routingModelGroups } from "./auto_setup";
|
||||
import ClassificationMethodConfig, { InactiveHeuristicV2Threshold } from "./ClassificationMethodConfig";
|
||||
import ComplexityRouterAdvancedSections from "./ComplexityRouterAdvancedSections";
|
||||
import { type TierSetAction, applyTierSetAction, setFallbackTier } from "./tier_set_actions";
|
||||
|
|
@ -657,13 +658,10 @@ const ComplexityRouterConfig: React.FC<ComplexityRouterConfigProps> = ({
|
|||
);
|
||||
const classifierEffortOptionsByModel = classifierEffortOptionsForModels(modelInfo);
|
||||
|
||||
// Embedding models can't serve a chat-completion role, so they're excluded here.
|
||||
const modelOptions = modelInfo
|
||||
.filter((model) => model.mode !== "embedding")
|
||||
.map((model) => ({
|
||||
value: model.model_group,
|
||||
label: model.model_group,
|
||||
}));
|
||||
const modelOptions = routingModelGroups(modelInfo).map((model) => ({
|
||||
value: model.model_group,
|
||||
label: model.model_group,
|
||||
}));
|
||||
|
||||
const handleTierModelParamChange = (tier: string, model: string, change: TierModelParamChange) =>
|
||||
onChange({
|
||||
|
|
|
|||
|
|
@ -319,6 +319,27 @@ describe("AddAutoRouterTab", () => {
|
|||
},
|
||||
);
|
||||
|
||||
it("carries Responses model choices from simple setup into Advanced tiers", async () => {
|
||||
const models = ["gpt-6-luna", "gpt-6-astra"];
|
||||
mockFetchAvailableModels.mockResolvedValue(models.map((model_group) => ({ model_group, mode: "responses" })));
|
||||
mockFetchAllModelDeployments.mockResolvedValue(
|
||||
models.map((model_name) => ({
|
||||
model_name,
|
||||
litellm_params: { model: `chatgpt/${model_name}` },
|
||||
model_info: { mode: "responses" },
|
||||
})),
|
||||
);
|
||||
renderWithProviders(<Harness />);
|
||||
await waitFor(() =>
|
||||
expect(screen.getByRole("combobox", { name: "Everyday model" })).toHaveTextContent("gpt-6-luna"),
|
||||
);
|
||||
expect(screen.getByRole("combobox", { name: "Hard tasks model" })).toHaveTextContent("gpt-6-astra");
|
||||
expect(screen.queryByText(/Two deployed models are needed/)).not.toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole("button", { name: "Advanced configuration", exact: true }));
|
||||
expectTierModel("Simple", "gpt-6-luna");
|
||||
expectTierModel("Reasoning", "gpt-6-astra");
|
||||
});
|
||||
|
||||
it("keeps manual solver choices on goal changes and carries them into Advanced", async () => {
|
||||
mockFetchAvailableModels.mockResolvedValue(
|
||||
["claude-haiku-5-5", "custom-fast", "claude-opus-5-5"].map((model_group) => ({
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
solverPairConfig,
|
||||
nextRouterName,
|
||||
simpleSetupError,
|
||||
routingModelGroups,
|
||||
} from "./auto_setup";
|
||||
|
||||
const deployment = (name: string, model: string, extra: Partial<AutoRouterDeployment> = {}): AutoRouterDeployment => ({
|
||||
|
|
@ -76,7 +77,7 @@ describe("deployedRouterModels", () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it("uses only caller-visible chat models and excludes blocked and recursive targets", () => {
|
||||
it("matches Advanced choices while keeping blocked and recursive targets out of suggestions", () => {
|
||||
const rows = [
|
||||
deployment("hidden", "anthropic/claude-opus-6"),
|
||||
deployment("blocked", "anthropic/claude-opus-5", { model_info: { blocked: true } }),
|
||||
|
|
@ -94,9 +95,40 @@ describe("deployedRouterModels", () => {
|
|||
],
|
||||
rows,
|
||||
).map((model) => model.name),
|
||||
).toEqual(["ready"]);
|
||||
).toEqual(["blocked", "ready", "recursive"]);
|
||||
expect(
|
||||
recommendSolverPair(
|
||||
deployedRouterModels(
|
||||
rows
|
||||
.filter((row) => row.model_name !== "hidden" && row.model_name !== "embedding")
|
||||
.map((row) => ({ model_group: row.model_name! })),
|
||||
rows,
|
||||
),
|
||||
"balanced",
|
||||
"auto",
|
||||
),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it.each(["chat", "responses", "completion", "unknown", undefined])(
|
||||
"offers the same routing choices as Advanced for mode %s",
|
||||
(mode) => {
|
||||
const groups = [
|
||||
{ model_group: "everyday", mode },
|
||||
{ model_group: "hard", mode },
|
||||
{ model_group: "embedding", mode: "embedding" },
|
||||
];
|
||||
const rows = [
|
||||
deployment("everyday", "chatgpt/gpt-6-luna", { model_info: { mode } }),
|
||||
deployment("hard", "chatgpt/gpt-6-astra", { model_info: { mode } }),
|
||||
];
|
||||
const models = deployedRouterModels(groups, rows);
|
||||
expect(models.map((model) => model.name)).toEqual(routingModelGroups(groups).map((group) => group.model_group));
|
||||
expect(models.map((model) => model.name)).toEqual(["everyday", "hard"]);
|
||||
expect(names(recommendSolverPair(models, "balanced", "openai"))).toEqual(["everyday", "hard"]);
|
||||
},
|
||||
);
|
||||
|
||||
it("does not claim a mixed-version or unknown model group is a known version", () => {
|
||||
const rows = [
|
||||
deployment("mixed", "anthropic/claude-opus-5"),
|
||||
|
|
@ -112,7 +144,7 @@ describe("deployedRouterModels", () => {
|
|||
],
|
||||
rows,
|
||||
);
|
||||
expect(models.map((model) => model.name)).toEqual(["claude-sonnet-5", "mixed"]);
|
||||
expect(models.map((model) => model.name)).toEqual(["claude-sonnet-5", "mixed", "wildcard"]);
|
||||
expect(models.every((model) => model.family === undefined)).toBe(true);
|
||||
expect(recommendSolverPair(models, "balanced", "auto")).toBeNull();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -146,24 +146,21 @@ const compareVersion = (left: readonly number[], right: readonly number[]): numb
|
|||
const compareRelease = (left: ModelIdentity, right: ModelIdentity): number =>
|
||||
compareVersion(left.version, right.version) || left.snapshot - right.snapshot;
|
||||
|
||||
export const routingModelGroups = (groups: readonly ModelGroup[]): ModelGroup[] =>
|
||||
groups.filter((group) => group.mode !== "embedding");
|
||||
|
||||
export const deployedRouterModels = (
|
||||
groups: readonly ModelGroup[],
|
||||
deployments: readonly AutoRouterDeployment[],
|
||||
): SolverModel[] =>
|
||||
groups
|
||||
.flatMap((group) => {
|
||||
if (group.mode && group.mode !== "chat") return [];
|
||||
routingModelGroups(groups)
|
||||
.map((group) => {
|
||||
const rows = deployments.filter((row) => row.model_name === group.model_group);
|
||||
if (
|
||||
rows.some(isAutoRouterDeployment) ||
|
||||
group.model_group.includes("*") ||
|
||||
group.model_group.startsWith("auto_router/")
|
||||
)
|
||||
return [];
|
||||
const active = rows.filter((row) => !row.model_info?.blocked);
|
||||
if (rows.length > 0 && active.length === 0) return [];
|
||||
if (active.some((row) => row.model_info?.mode && row.model_info.mode !== "chat")) return [];
|
||||
if (active.some((row) => row.litellm_params?.model?.includes("*"))) return [];
|
||||
const isRouter = rows.some(isAutoRouterDeployment) || group.model_group.startsWith("auto_router/");
|
||||
const hasWildcard =
|
||||
group.model_group.includes("*") || active.some((row) => row.litellm_params?.model?.includes("*"));
|
||||
const manualOnly = isRouter || hasWildcard || (rows.length > 0 && active.length === 0);
|
||||
const identities = active.length > 0 ? active.map(identityOf) : [parseModel(group.model_group)];
|
||||
const first = identities[0];
|
||||
const homogeneous =
|
||||
|
|
@ -173,19 +170,17 @@ export const deployedRouterModels = (
|
|||
const sameLine = identity.family === first.family && identity.line === first.line;
|
||||
return sameLine && compareRelease(identity, first) === 0;
|
||||
});
|
||||
const identity = homogeneous ? first : undefined;
|
||||
const identity = homogeneous && !manualOnly ? first : undefined;
|
||||
const providers =
|
||||
active.length > 0
|
||||
? active.map((row) => providerOf(row, group, identity?.family))
|
||||
: [providerOf({}, group, identity?.family)];
|
||||
return [
|
||||
{
|
||||
...identity,
|
||||
name: group.model_group,
|
||||
model: identity?.model ?? group.model_group,
|
||||
provider: [...new Set(providers)].toSorted().join(", "),
|
||||
},
|
||||
];
|
||||
return {
|
||||
...identity,
|
||||
name: group.model_group,
|
||||
model: identity?.model ?? group.model_group,
|
||||
provider: [...new Set(providers)].toSorted().join(", "),
|
||||
};
|
||||
})
|
||||
.toSorted((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue