diff --git a/ui/litellm-dashboard/src/components/add_model/ClassificationMethodConfig.tsx b/ui/litellm-dashboard/src/components/add_model/ClassificationMethodConfig.tsx index 8a982556a51..4eaab3f3af9 100644 --- a/ui/litellm-dashboard/src/components/add_model/ClassificationMethodConfig.tsx +++ b/ui/litellm-dashboard/src/components/add_model/ClassificationMethodConfig.tsx @@ -10,6 +10,8 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Switch } from "@/components/ui/switch"; import React from "react"; import ClassifierPromptEditor from "./ClassifierPromptEditor"; +import ClassificationPromptEditor from "./ClassificationPromptEditor"; +import { Restricted, restrictedBy } from "./TierRestrictions"; import HeuristicScoringConfig from "./HeuristicScoringConfig"; import { useComplexityScorerDefaults } from "@/app/(dashboard)/hooks/autoRouter/useComplexityScorerDefaults"; import { @@ -32,9 +34,6 @@ import { DEFAULT_HEURISTIC_FIRST_MAX_TIER, HEURISTIC_FIRST_MAX_TIER_KEYS, effectiveClassifierType, - heuristicScoringRole, - restrictedBy, - Restricted, } from "./ComplexityRouterConfig"; const DEFAULT_SCORING_EXPLANATION = @@ -202,6 +201,10 @@ const ClassificationMethodConfig: React.FC = ({ onChange({ ...value, heuristic_first_max_tier: tier }); }; + const handleClassificationPromptChange = (classificationPrompt: string | undefined) => { + onChange({ ...value, classification_prompt: classificationPrompt }); + }; + const handleClassifierModelChange = (model: string) => { onChange({ ...value, @@ -414,7 +417,13 @@ const ClassificationMethodConfig: React.FC = ({
Classifier Prompt - + {value.custom_tier_set ? ( + + ) : ( = ({ tierLabels={value.tier_labels} classificationRubric={classificationRubric} /> - + )}
If the classifier fails diff --git a/ui/litellm-dashboard/src/components/add_model/ClassificationPromptEditor.tsx b/ui/litellm-dashboard/src/components/add_model/ClassificationPromptEditor.tsx new file mode 100644 index 00000000000..1840eaea13c --- /dev/null +++ b/ui/litellm-dashboard/src/components/add_model/ClassificationPromptEditor.tsx @@ -0,0 +1,101 @@ +import React, { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { Textarea } from "@/components/ui/textarea"; +import { TierRow, activeTierName } from "./tier_rows"; + +interface ClassificationPromptEditorProps { + classificationPrompt: string | undefined; + onChange: (classificationPrompt: string | undefined) => void; + tierRows: readonly TierRow[]; +} + +const PLACEHOLDER = `Classify the request into exactly one tier for a payments engineering team. + +Examples: +- "bump the copy on the checkout button" -> TRIAGE +- "why is our webhook signature check failing" -> SECURITY_REVIEW`; + +const appendedTierBullets = (tierRows: readonly TierRow[]): string => + tierRows.map((row) => `- ${activeTierName(row)}: ${row.definition}`).join("\n"); + +const ClassificationPromptEditor: React.FC = ({ + classificationPrompt, + onChange, + tierRows, +}) => { + const [isOpen, setIsOpen] = useState(false); + const [draft, setDraft] = useState(""); + const isOverridden = Boolean(classificationPrompt?.trim()); + + const openEditor = () => { + setDraft(classificationPrompt ?? ""); + setIsOpen(true); + }; + + const handleSave = () => { + onChange(draft.trim() || undefined); + setIsOpen(false); + }; + + return ( +
+
+ + {isOverridden && ( + + )} +
+

+ {isOverridden + ? "This router opens its classifier prompt with your own instructions." + : "Replace the opening instructions, and write calibration examples of your own. Your tier definitions and the injection guard are always appended below them."} +

+ + + + + Classifier prompt + + +

+ Your text is the opening of the classifier prompt, so it is where calibration examples of your own belong. + The router appends your tier definitions and its injection guard underneath, and neither can be edited or + removed from here. Edit the definitions themselves with Edit tiers above. +

+ +