From c3c466a5c123558006c1a7cf151b86be6c06109c Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Tue, 22 Sep 2026 17:40:03 -0700 Subject: [PATCH] fix(ui): adapt the jev dashboard pieces to stable/1.102.x (cherry picked from commit 4bfac88281ae38c74dd34f7edbcceef469756a64) --- .../add_model/ClassificationMethodConfig.tsx | 324 ++++++++++++------ .../JevClassifierConfig.integration.test.tsx | 6 +- .../add_model/add_auto_router_tab.tsx | 26 +- .../classifier_type_transition.test.ts | 33 -- .../add_model/classifier_type_transition.ts | 8 +- .../components/add_model/classifier_types.ts | 12 +- .../edit_auto_router_modal.tsx | 215 ++++++++---- 7 files changed, 387 insertions(+), 237 deletions(-) diff --git a/ui/litellm-dashboard/src/components/add_model/ClassificationMethodConfig.tsx b/ui/litellm-dashboard/src/components/add_model/ClassificationMethodConfig.tsx index 6bfad366184..3b3343154a3 100644 --- a/ui/litellm-dashboard/src/components/add_model/ClassificationMethodConfig.tsx +++ b/ui/litellm-dashboard/src/components/add_model/ClassificationMethodConfig.tsx @@ -1,3 +1,5 @@ +import { transitionClassifierType } from "./classifier_type_transition"; +import JevClassifierConfig from "./JevClassifierConfig"; import { Info } from "lucide-react"; import { SimpleTooltip } from "@/components/ui/tooltip"; import { MultiSelect } from "@/components/shared/MultiSelect"; @@ -10,40 +12,51 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Switch } from "@/components/ui/switch"; import React from "react"; import ClassifierPromptEditor from "./ClassifierPromptEditor"; -import CustomTierPromptEditor from "./CustomTierPromptEditor"; +import OpeningPromptEditor, { type OpeningPromptSelection } from "./OpeningPromptEditor"; import { RestrictedSection, restrictedBy } from "./TierRestrictions"; import HeuristicScoringConfig from "./HeuristicScoringConfig"; +import ClassifierReasoningEffortSelect from "./ClassifierReasoningEffortSelect"; import ClassifierCircuitBreakerConfig from "./ClassifierCircuitBreakerConfig"; +import ClassifierVisionConfig from "./ClassifierVisionConfig"; +import type { ReasoningEffort } from "./complexity_router_tiers"; import { useComplexityScorerDefaults } from "@/app/(dashboard)/hooks/autoRouter/useComplexityScorerDefaults"; import { + ClassificationFrequency, ClassifierFallback, + ClassifierLLMConfig, ClassifierType, ComplexityRouterConfigValue, + classificationFrequency, + withClassificationFrequency, DEFAULT_CLASSIFIER_CONTEXT_BUDGET_CHARS, MIN_QUOTED_CONTEXT_TURN_CHARS, DEFAULT_CLASSIFIER_CONTEXT_WINDOW_SIZE, DEFAULT_CLASSIFIER_FALLBACK, DEFAULT_CLASSIFIER_TIMEOUT_MS, DEFAULT_CLASSIFICATION_RUBRIC, - NEW_CLASSIFIER_CLASSIFICATION_RUBRIC, - CLASSIFICATION_RUBRIC_DESCRIPTIONS, - CLASSIFICATION_RUBRIC_KEYS, ClassificationRubric, effectiveTierLabel, heuristicScoringRole, usesLlmClassifier, - DEFAULT_HEURISTIC_FIRST_MAX_TIER, + usesClassifierContext, + DEFAULT_HYBRID_BOUNDARY_MARGIN, HEURISTIC_FIRST_MAX_TIER_KEYS, effectiveClassifierType, } from "./ComplexityRouterConfig"; const DEFAULT_SCORING_EXPLANATION = - "The router scores each request across 7 dimensions: token count, code presence, reasoning markers, technical " + - "terms, simple indicators, multi-step patterns, and question complexity. The weighted score determines the tier:"; + "The router scores each request across 7 built-in dimensions: token count, code presence, reasoning markers, technical " + + "terms, simple indicators, multi-step patterns, and question complexity, plus any custom dimensions you add. " + + "The weighted score determines the tier:"; + +const HEURISTIC_V2_EXPLANATION = + "The router estimates success probability for all four tiers with the bundled calibrated model, then selects " + + "the first tier that meets its trained threshold. It runs locally with no classifier API call."; const CLASSIFIER_TIMEOUT_ID = "classifier-timeout-ms"; const CLASSIFIER_CONTEXT_WINDOW_SIZE_ID = "classifier-context-window-size"; const CLASSIFIER_CONTEXT_BUDGET_CHARS_ID = "classifier-context-budget-chars"; +const HYBRID_BOUNDARY_MARGIN_ID = "hybrid-boundary-margin"; const CUSTOM_PROMPT_WITH_HEURISTIC_FALLBACK = "This router classifies with your own prompt, so the tier comes from whatever rubric it states. The four tier " + @@ -60,6 +73,7 @@ const CUSTOM_PROMPT_WITH_DEFAULT_MODEL_FALLBACK = * at all, so the panel must not keep implying a score is involved on either router. */ const scoringExplanation = (value: ComplexityRouterConfigValue): string => { + if (value.classifier_type === "heuristic_v2") return HEURISTIC_V2_EXPLANATION; const usesCustomPrompt = usesLlmClassifier(value.classifier_type) && Boolean(value.classifier_llm_config?.system_prompt?.trim()); if (!usesCustomPrompt) return DEFAULT_SCORING_EXPLANATION; @@ -112,7 +126,7 @@ const HowClassificationWorks: React.FC<{ value: ComplexityRouterConfigValue }> = How Classification Works {scoringExplanation(value)} {scorerRuns && ranges && ( -