+
+
+ );
+}
diff --git a/ui/litellm-dashboard/src/components/molecules/DecisionModelsBanner.integration.test.tsx b/ui/litellm-dashboard/src/components/molecules/DecisionModelsBanner.integration.test.tsx
new file mode 100644
index 00000000000..b7d81a09f4e
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/molecules/DecisionModelsBanner.integration.test.tsx
@@ -0,0 +1,71 @@
+import { fireEvent, render, screen } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import DecisionModelsBanner from "./DecisionModelsBanner";
+
+const STORAGE_KEY = "hideDecisionModelsBanner";
+
+describe("DecisionModelsBanner", () => {
+ beforeEach(() => {
+ localStorage.removeItem(STORAGE_KEY);
+ localStorage.removeItem("hideCostOptimizationFeedbackBanner");
+ });
+
+ it("links directly to the System One playground", () => {
+ render();
+ const link = screen.getByRole("link", { name: "Try decision models" });
+ expect(link).toHaveAttribute("href", "/ui/playground?tab=system-one");
+ });
+
+ it("links to the docs on how to call decision models", () => {
+ render();
+ expect(screen.getByRole("link", { name: "How to call them" })).toHaveAttribute(
+ "href",
+ "https://docs.litellm.ai/docs/decisions",
+ );
+ });
+
+ it("offers Add a decision model only when the page can add models, and calls back on click", () => {
+ const onAddModel = vi.fn();
+ const { rerender } = render();
+ expect(screen.queryByRole("button", { name: "Add a decision model" })).not.toBeInTheDocument();
+
+ rerender();
+ fireEvent.click(screen.getByRole("button", { name: "Add a decision model" }));
+
+ expect(onAddModel).toHaveBeenCalledTimes(1);
+ });
+
+ it("points only users who can add models at Add Model", () => {
+ const { rerender } = render();
+ expect(screen.getByRole("paragraph")).not.toHaveTextContent("Add Model");
+ expect(screen.getByRole("paragraph")).toHaveTextContent("Call them at /v1/decisions or /v1/systemone");
+
+ rerender();
+
+ expect(screen.getByRole("paragraph")).toHaveTextContent(
+ "Search decision in Add Model to find them. Call them at /v1/decisions",
+ );
+ });
+
+ it("shows the announcement even if the old feedback banner was dismissed", () => {
+ localStorage.setItem("hideCostOptimizationFeedbackBanner", "true");
+ render();
+ expect(screen.getByText("Decision models are now supported")).toBeInTheDocument();
+ });
+
+ it("hides itself and persists the dismissal when the dismiss button is clicked", () => {
+ render();
+ expect(screen.getByText("Decision models are now supported")).toBeInTheDocument();
+
+ fireEvent.click(screen.getByLabelText("Dismiss banner"));
+
+ expect(screen.queryByText("Decision models are now supported")).not.toBeInTheDocument();
+ expect(localStorage.getItem(STORAGE_KEY)).toBe("true");
+ });
+
+ it("stays dismissed on remount once persisted", () => {
+ localStorage.setItem(STORAGE_KEY, "true");
+ render();
+ expect(screen.queryByText("Decision models are now supported")).not.toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/molecules/DecisionModelsBanner.tsx b/ui/litellm-dashboard/src/components/molecules/DecisionModelsBanner.tsx
new file mode 100644
index 00000000000..5dbf5191198
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/molecules/DecisionModelsBanner.tsx
@@ -0,0 +1,78 @@
+import React, { useState } from "react";
+import { ArrowRight, Sparkles, X } from "lucide-react";
+
+import { DECISIONS_DOCS_URL, SYSTEM_ONE_PLAYGROUND_ROUTE } from "@/lib/decisionModels";
+import { uiHref } from "@/utils/uiHref";
+
+import { Button } from "@/components/ui/button";
+
+const STORAGE_KEY = "hideDecisionModelsBanner";
+
+interface DecisionModelsBannerProps {
+ onAddModel?: () => void;
+}
+
+const DecisionModelsBanner: React.FC = ({ onAddModel }) => {
+ const [dismissed, setDismissed] = useState(() => {
+ if (typeof window !== "undefined") {
+ return localStorage.getItem(STORAGE_KEY) === "true";
+ }
+ return false;
+ });
+
+ if (dismissed) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
Decision models are now supported
+
+ {onAddModel && (
+ <>
+ Search decision in Add Model to find them.{" "}
+ >
+ )}
+ Call them at /v1/decisions or /v1/systemone, or try them in the System One
+ playground.{" "}
+
+ How to call them
+
+