diff --git a/ui/litellm-dashboard/src/components/add_model/AutoRouterClassifierTabs.tsx b/ui/litellm-dashboard/src/components/add_model/AutoRouterClassifierTabs.tsx index 509329bb948..0b32995f707 100644 --- a/ui/litellm-dashboard/src/components/add_model/AutoRouterClassifierTabs.tsx +++ b/ui/litellm-dashboard/src/components/add_model/AutoRouterClassifierTabs.tsx @@ -233,6 +233,7 @@ const AutoRouterClassifierTabs: React.FC = ({ { value: "laya", label: "Laya" }, { value: "bespoke", label: "Bespoke Nimble" }, { value: "databricks", label: "Databricks" }, + { value: "nadir", label: "Nadir" }, ]} value={normalizeJevClassifierConfig(value.jev_classifier_config).provider} onValueChange={changeProvider} @@ -245,6 +246,7 @@ const AutoRouterClassifierTabs: React.FC = ({ Laya Bespoke Nimble Databricks + Nadir diff --git a/ui/litellm-dashboard/src/components/add_model/ClassifierTypeRadios.tsx b/ui/litellm-dashboard/src/components/add_model/ClassifierTypeRadios.tsx index 6ed46e2a27d..ce98b25f36f 100644 --- a/ui/litellm-dashboard/src/components/add_model/ClassifierTypeRadios.tsx +++ b/ui/litellm-dashboard/src/components/add_model/ClassifierTypeRadios.tsx @@ -55,7 +55,9 @@ const ClassifierTypeRadios: React.FC = ({ value, clas OSS Classifier{" "} - uses Jev, Laya, Bespoke, or Databricks to decide the tier + + uses Jev, Laya, Bespoke, Databricks, or Nadir to decide the tier + diff --git a/ui/litellm-dashboard/src/components/add_model/JevClassifierConfig.integration.test.tsx b/ui/litellm-dashboard/src/components/add_model/JevClassifierConfig.integration.test.tsx index f829a2f2e41..32f56128987 100644 --- a/ui/litellm-dashboard/src/components/add_model/JevClassifierConfig.integration.test.tsx +++ b/ui/litellm-dashboard/src/components/add_model/JevClassifierConfig.integration.test.tsx @@ -164,6 +164,28 @@ describe("JEV classifier editor", () => { }, ); + it("hides the model and instructions for Nadir and saves it without instructions", async () => { + renderWithProviders(
); + fireEvent.click(screen.getByRole("radio", { name: /^Decisions Model$/ })); + fireEvent.change(screen.getByLabelText("Classifier Instructions"), { target: { value: "Pick carefully" } }); + await chooseSelectOption(userEvent, screen.getByRole("combobox", { name: "Decision model" }), "Nadir"); + expect(screen.queryByLabelText("Classifier Model")).not.toBeInTheDocument(); + expect(screen.queryByLabelText("Classifier Instructions")).not.toBeInTheDocument(); + expect(screen.getByText(/Set NADIR_API_KEY on the gateway/)).toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Save and reload" })); + expect(screen.getByRole("combobox", { name: "Decision model" })).toHaveTextContent("Nadir"); + fireEvent.click(screen.getByRole("button", { name: "Probe current config" })); + expect(testAutoRouterRouting).toHaveBeenLastCalledWith( + "token", + expect.objectContaining({ + complexity_router_config: expect.objectContaining({ + classifier_type: "oss_classifier", + opensource_classifier_config: { provider: "nadir", model: "bucket", timeout_ms: 3000 }, + }), + }), + ); + }); + it("allows licensed instructions and can restore built-in instructions", () => { const authorized = useAuthorized(); vi.mocked(useAuthorized).mockReturnValue({ ...authorized, premiumUser: true }); diff --git a/ui/litellm-dashboard/src/components/add_model/JevClassifierConfig.tsx b/ui/litellm-dashboard/src/components/add_model/JevClassifierConfig.tsx index 4b3cfa21f9d..f09384ca2b8 100644 --- a/ui/litellm-dashboard/src/components/add_model/JevClassifierConfig.tsx +++ b/ui/litellm-dashboard/src/components/add_model/JevClassifierConfig.tsx @@ -7,7 +7,11 @@ import { Textarea } from "@/components/ui/textarea"; import ClassifierCircuitBreakerConfig from "./ClassifierCircuitBreakerConfig"; import type { ComplexityRouterConfigValue } from "./ComplexityRouterConfig"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { defaultJevClassifierConfig, fixedClassifierModels } from "./jev_classifier_config"; +import { + acceptsClassifierInstructions, + defaultJevClassifierConfig, + fixedClassifierModels, +} from "./jev_classifier_config"; const providerDescriptions = { jev: "Uses TypeSafe System One Choice evaluation with your configured tiers", @@ -16,6 +20,8 @@ const providerDescriptions = { "Uses Bespoke Nimble with your configured tiers. Set BESPOKE_API_BASE on the gateway to connect your Nimble server.", databricks: "Uses the Databricks ai_decide AI Function, or a decision serving endpoint you name, with your configured tiers. Set DATABRICKS_API_BASE to https:///serving-endpoints and DATABRICKS_API_KEY on the gateway.", + nadir: + "Uses Nadir's tier decision with your configured tiers. Set NADIR_API_KEY on the gateway; without it, calls use Nadir's anonymous, rate-limited tier. Set NADIR_API_BASE for a self-hosted Nadir.", }; export default function JevClassifierConfig({ @@ -38,34 +44,36 @@ export default function JevClassifierConfig({ {section !== "advanced" && !config.deployment_name && ( <>

{providerDescriptions[config.provider ?? "jev"]}

-
- - {models ? ( - - ) : ( - update({ model: event.target.value })} - /> - )} -
+ {config.provider !== "nadir" && ( +
+ + {models ? ( + + ) : ( + update({ model: event.target.value })} + /> + )} +
+ )} )} {section !== "model" && ( @@ -90,27 +98,29 @@ export default function JevClassifierConfig({ }) } /> -
- - -