mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(ui): merge colliding param sets instead of overwriting one
Two spellings of the same model in one tier resolve to a single registered
key, and resolveParamKeys built the resolved map with Object.fromEntries, so
the later spelling's litellm_params replaced the earlier one's wholesale.
One model holds one param set both here and in the submitted payload, so a
collision has to collapse; it does not have to lose anything. Merging keeps
params only one spelling set, and leaves a key both set resolving last-wins,
which is how hydrateTierModelParams already collapses two entries spelled
identically.
Closes the P2 Greptile held a point back for on #38453. The bundled-preset
invariant added in 7174fa7a4c still guards shipped data; this covers a preset
that has not been through that gate yet.
This commit is contained in:
parent
7174fa7a4c
commit
90c40fdfee
2 changed files with 36 additions and 2 deletions
|
|
@ -604,6 +604,28 @@ describe("autorouter_presets", () => {
|
|||
});
|
||||
});
|
||||
|
||||
// Two spellings of one model in a tier collapse to a single registered key, and one model can
|
||||
// only hold one param set downstream. Merging keeps whatever only one spelling set instead of
|
||||
// dropping that spelling's params wholesale.
|
||||
it("merges rather than drops params when two spellings resolve to the same registered model", () => {
|
||||
const config = {
|
||||
tiers: { SIMPLE: [], MEDIUM: [], COMPLEX: [], REASONING: ["claude-sonnet-4-5", "claude-sonnet-4.5"] },
|
||||
tier_model_configs: {
|
||||
REASONING: [
|
||||
{ model_name: "claude-sonnet-4-5", litellm_params: { reasoning_effort: "high", temperature: 0.2 } },
|
||||
{ model_name: "claude-sonnet-4.5", litellm_params: { reasoning_effort: "low" } },
|
||||
],
|
||||
},
|
||||
classifier_type: "heuristic" as const,
|
||||
};
|
||||
const prefill = buildPresetPrefill(config, groupsOnly(["claude-sonnet-4.5"]));
|
||||
// temperature survives from the spelling that would otherwise have been overwritten;
|
||||
// reasoning_effort, set by both, resolves last-wins.
|
||||
expect(prefill.complexityRouterConfig.tier_model_params).toEqual({
|
||||
REASONING: { "claude-sonnet-4.5": { reasoning_effort: "low", temperature: 0.2 } },
|
||||
});
|
||||
});
|
||||
|
||||
it("leaves tier_model_params undefined for a preset that carries no per-model params", () => {
|
||||
const config = {
|
||||
tiers: { SIMPLE: ["gpt-5-nano"], MEDIUM: [], COMPLEX: [], REASONING: [] },
|
||||
|
|
|
|||
|
|
@ -12,7 +12,11 @@ import {
|
|||
} from "@/components/add_model/ComplexityRouterConfig";
|
||||
import { KeywordTierRule } from "@/components/add_model/KeywordTierRules";
|
||||
import { hydrateKeywordTierRules } from "@/components/add_model/complexity_router_keywords";
|
||||
import { TierModelParamsByTier, hydrateTierModelParams } from "@/components/add_model/complexity_router_tiers";
|
||||
import {
|
||||
TierModelParams,
|
||||
TierModelParamsByTier,
|
||||
hydrateTierModelParams,
|
||||
} from "@/components/add_model/complexity_router_tiers";
|
||||
import { DEFAULT_ESCALATION_KEYWORDS } from "@/components/add_model/EscalationKeywords";
|
||||
import { DEFAULT_MATCH_THRESHOLD } from "@/components/add_model/SemanticKeywordMatching";
|
||||
import presetsRaw from "@/autorouter_presets.json";
|
||||
|
|
@ -248,12 +252,20 @@ export const buildPresetPrefill = (
|
|||
// Params key on the model name the preset spells while every tier entry is rewritten to the
|
||||
// caller's registered spelling, so the keys have to be rewritten the same way. Otherwise
|
||||
// serializeTierModelConfigs drops them for naming a model the tier no longer holds.
|
||||
//
|
||||
// Two spellings in one tier can resolve to the same registered model, and one model holds one
|
||||
// param set here and in the payload, so a collision has to collapse. Merge rather than replace:
|
||||
// params only one spelling set still survive, and a key both set resolves last-wins, matching
|
||||
// how hydrateTierModelParams already collapses two entries spelled identically.
|
||||
const resolveParamKeys = (params: TierModelParamsByTier | undefined): TierModelParamsByTier | undefined =>
|
||||
params &&
|
||||
Object.fromEntries(
|
||||
Object.entries(params).map(([tier, byModel]) => [
|
||||
tier,
|
||||
Object.fromEntries(Object.entries(byModel).map(([model, litellmParams]) => [resolve(model), litellmParams])),
|
||||
Object.entries(byModel).reduce<Record<string, TierModelParams>>((byResolved, [model, litellmParams]) => {
|
||||
const resolved = resolve(model);
|
||||
return { ...byResolved, [resolved]: { ...byResolved[resolved], ...litellmParams } };
|
||||
}, {}),
|
||||
]),
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue