From d5481ca0370141442539231f6e2240a58a080516 Mon Sep 17 00:00:00 2001 From: moe-berri Date: Thu, 3 Sep 2026 20:01:44 -0700 Subject: [PATCH] fix(ui): respect reported reasoning efforts --- .../add_model/add_auto_router_tab.tsx | 4 +- .../components/add_model/auto_setup.test.ts | 55 +++++++++++++++++-- .../src/components/add_model/auto_setup.ts | 21 ++----- 3 files changed, 57 insertions(+), 23 deletions(-) diff --git a/ui/litellm-dashboard/src/components/add_model/add_auto_router_tab.tsx b/ui/litellm-dashboard/src/components/add_model/add_auto_router_tab.tsx index 917c775760e..a548c2c6533 100644 --- a/ui/litellm-dashboard/src/components/add_model/add_auto_router_tab.tsx +++ b/ui/litellm-dashboard/src/components/add_model/add_auto_router_tab.tsx @@ -273,8 +273,8 @@ const AddAutoRouterTab: React.FC = ({ [presets, availability], ); const automaticRouterConfig = React.useMemo( - () => buildAutomaticRouterConfig(modelInfo, deployments ?? [], preferredTierModels, availability), - [modelInfo, deployments, preferredTierModels, availability], + () => buildAutomaticRouterConfig(modelInfo, deployments ?? [], preferredTierModels), + [modelInfo, deployments, preferredTierModels], ); // A preset's models can only be trusted against a successfully loaded list. Selection and the diff --git a/ui/litellm-dashboard/src/components/add_model/auto_setup.test.ts b/ui/litellm-dashboard/src/components/add_model/auto_setup.test.ts index b158b7f3b6e..c5784db4501 100644 --- a/ui/litellm-dashboard/src/components/add_model/auto_setup.test.ts +++ b/ui/litellm-dashboard/src/components/add_model/auto_setup.test.ts @@ -4,6 +4,12 @@ import { buildModelAvailability } from "@/lib/autorouter_presets"; import { buildAutomaticRouterConfig, buildPreferredTierModels, type PreferredTierModels } from "./auto_setup"; const models = (...names: string[]) => names.map((model_group) => ({ model_group, mode: "chat" })); +const reasoningModel = (model_group: string, supported_reasoning_efforts: string[]) => ({ + model_group, + mode: "chat", + supports_reasoning: true, + supported_reasoning_efforts, +}); const deployment = (model_name: string, model = model_name): AutoRouterDeployment => ({ model_name, litellm_params: { model }, @@ -66,42 +72,79 @@ describe("buildAutomaticRouterConfig", () => { provider: "OpenAI", available: ["gpt-5.6-luna", "gpt-5.6-terra", "gpt-6-astra"], expected: ["gpt-5.6-luna", "gpt-5.6-terra", "gpt-6-astra", "gpt-6-astra"], + supportedEfforts: ["low", "medium", "high", "xhigh", "max"], effort: "max", }, { provider: "Anthropic", available: ["claude-haiku-4-5", "claude-sonnet-5", "claude-opus-5"], expected: ["claude-haiku-4-5", "claude-sonnet-5", "claude-opus-5", "claude-opus-5"], + supportedEfforts: ["low", "medium", "high", "max"], effort: "max", }, { provider: "Google", available: ["gemini-3.5-flash-lite", "gemini-3.8-flash", "gemini-3.1-pro-preview"], expected: ["gemini-3.5-flash-lite", "gemini-3.8-flash", "gemini-3.1-pro-preview", "gemini-3.1-pro-preview"], + supportedEfforts: ["low", "medium", "high"], effort: "high", }, { provider: "DeepSeek", available: ["deepseek-v4-flash", "deepseek-v4-pro"], expected: ["deepseek-v4-flash", "deepseek-v4-flash", "deepseek-v4-pro", "deepseek-v4-pro"], + supportedEfforts: ["none", "high"], effort: "high", }, { provider: "xAI", available: ["grok-4.6"], expected: ["grok-4.6", "grok-4.6", "grok-4.6", "grok-4.6"], + supportedEfforts: ["low", "medium", "high", "xhigh"], effort: "xhigh", }, - ])("uses the current $provider ladder and maximum reasoning effort", ({ available, expected, effort }) => { + ])( + "uses the current $provider ladder and strongest advertised reasoning effort", + ({ available, expected, supportedEfforts, effort }) => { + const availability = buildModelAvailability(available, []); + const preferred = buildPreferredTierModels([], availability); + const modelInfo = models(...available).map((model) => + model.model_group === expected[3] ? reasoningModel(model.model_group, supportedEfforts) : model, + ); + + const config = buildAutomaticRouterConfig(modelInfo, [], preferred); + + expect(tierModels(config)).toEqual(expected); + expect(config?.tier_model_params).toEqual({ + REASONING: { [expected[3]]: { reasoning_effort: effort } }, + }); + }, + ); + + it("never exceeds the selected model group's advertised reasoning efforts", () => { + const available = ["gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.6-sol"]; + const availability = buildModelAvailability(available, []); + const preferred = buildPreferredTierModels([], availability); + const modelInfo = [ + ...models("gpt-5.6-luna", "gpt-5.6-terra"), + reasoningModel("gpt-5.6-sol", ["none", "low", "medium", "high", "xhigh"]), + ]; + + const config = buildAutomaticRouterConfig(modelInfo, [], preferred); + + expect(config?.tier_model_params).toEqual({ + REASONING: { "gpt-5.6-sol": { reasoning_effort: "xhigh" } }, + }); + }); + + it("leaves reasoning effort unset when the proxy does not report supported values", () => { + const available = ["grok-4.6"]; const availability = buildModelAvailability(available, []); const preferred = buildPreferredTierModels([], availability); - const config = buildAutomaticRouterConfig(models(...available), [], preferred, availability); + const config = buildAutomaticRouterConfig(models(...available), [], preferred); - expect(tierModels(config)).toEqual(expected); - expect(config?.tier_model_params).toEqual({ - REASONING: { [expected[3]]: { reasoning_effort: effort } }, - }); + expect(config?.tier_model_params).toBeUndefined(); }); it("reuses the closest available tier when a tier has no match", () => { diff --git a/ui/litellm-dashboard/src/components/add_model/auto_setup.ts b/ui/litellm-dashboard/src/components/add_model/auto_setup.ts index 0e8ef7c9824..cd7d587e2c2 100644 --- a/ui/litellm-dashboard/src/components/add_model/auto_setup.ts +++ b/ui/litellm-dashboard/src/components/add_model/auto_setup.ts @@ -7,6 +7,8 @@ const TIER_NAMES = ["SIMPLE", "MEDIUM", "COMPLEX", "REASONING"] as const; type TierName = (typeof TIER_NAMES)[number]; export type PreferredTierModels = Record; +const REASONING_EFFORT_STRENGTH = ["max", "xhigh", "high", "medium", "low", "minimal", "none"] as const; + const CURRENT_TIER_MODELS: PreferredTierModels = { SIMPLE: ["gpt-5.6-luna", "claude-haiku-4-5", "gemini-3.5-flash-lite", "deepseek-v4-flash"], MEDIUM: ["gpt-5.6-terra", "claude-sonnet-5", "gemini-3.8-flash", "deepseek-v4-flash"], @@ -14,15 +16,6 @@ const CURRENT_TIER_MODELS: PreferredTierModels = { REASONING: ["gpt-6-astra", "gpt-5.6-sol", "claude-opus-5", "gemini-3.1-pro-preview", "deepseek-v4-pro", "grok-4.6"], }; -const MAX_REASONING_EFFORT: Record = { - "gpt-6-astra": "max", - "gpt-5.6-sol": "max", - "claude-opus-5": "max", - "gemini-3.1-pro-preview": "high", - "deepseek-v4-pro": "high", - "grok-4.6": "xhigh", -}; - export const buildPreferredTierModels = ( presets: AutoRouterPreset[], availability: ModelAvailability, @@ -63,7 +56,6 @@ export const buildAutomaticRouterConfig = ( models: ModelGroup[], deployments: AutoRouterDeployment[], preferredByTier: PreferredTierModels, - availability?: ModelAvailability, ): ComplexityRouterConfigValue | null => { const autoRouterNames: ReadonlySet = new Set( deployments @@ -83,11 +75,10 @@ export const buildAutomaticRouterConfig = ( const selected = selectPreferredTierModels(preferredByTier, usableNames); if (selected === null) return null; - const reasoningEffort = - availability && - Object.entries(MAX_REASONING_EFFORT).find( - ([model]) => resolveAvailableModel(model, availability) === selected[3], - )?.[1]; + const supportedReasoningEfforts = models.find( + (model) => model.model_group === selected[3], + )?.supported_reasoning_efforts; + const reasoningEffort = REASONING_EFFORT_STRENGTH.find((effort) => supportedReasoningEfforts?.includes(effort)); return { tiers: {