diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.test.tsx
deleted file mode 100644
index 46aa23fcfc0..00000000000
--- a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.test.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { fireEvent, render } from "@testing-library/react";
-import { describe, expect, it, vi } from "vitest";
-
-vi.mock("./UsageTab", () => ({ __esModule: true, default: () =>
}));
-vi.mock("./PromptCompressionTab", () => ({ __esModule: true, default: () => }));
-vi.mock("./AutorouterTab", () => ({ __esModule: true, default: () => }));
-vi.mock("./PromptCachingTab", () => ({ __esModule: true, default: () => }));
-
-import CostOptimizationView from "./CostOptimizationView";
-
-const renderView = () => render();
-
-describe("CostOptimizationView", () => {
- it("renders all four cost-optimization tabs", () => {
- const { getByText } = renderView();
-
- expect(getByText("Usage")).toBeInTheDocument();
- expect(getByText("Prompt Compression")).toBeInTheDocument();
- expect(getByText("Autorouter")).toBeInTheDocument();
- expect(getByText("Prompt Caching")).toBeInTheDocument();
- });
-
- it("defaults to the Usage tab and switches the active tab on click", () => {
- const { getByRole } = renderView();
-
- expect(getByRole("tab", { name: "Usage" })).toHaveAttribute("aria-selected", "true");
- expect(getByRole("tab", { name: "Prompt Compression" })).toHaveAttribute("aria-selected", "false");
-
- fireEvent.click(getByRole("tab", { name: "Prompt Compression" }));
-
- expect(getByRole("tab", { name: "Usage" })).toHaveAttribute("aria-selected", "false");
- expect(getByRole("tab", { name: "Prompt Compression" })).toHaveAttribute("aria-selected", "true");
- });
-});
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.tsx
deleted file mode 100644
index 3bab6afee57..00000000000
--- a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-"use client";
-
-import React from "react";
-import { PiggyBank } from "lucide-react";
-import { Alert, Tabs } from "antd";
-
-import UsageTab from "./UsageTab";
-import PromptCompressionTab from "./PromptCompressionTab";
-import AutorouterTab from "./AutorouterTab";
-import PromptCachingTab from "./PromptCachingTab";
-import { useDailyActivityRange } from "./useDailyActivityRange";
-
-interface CostOptimizationViewProps {
- accessToken: string | null;
- userId: string | null;
- userRole: string;
-}
-
-const CostOptimizationView: React.FC = ({ accessToken, userId, userRole }) => {
- const activity = useDailyActivityRange(accessToken, userId, userRole);
-
- const items = [
- {
- key: "usage",
- label: "Usage",
- children: ,
- },
- {
- key: "compression",
- label: "Prompt Compression",
- children: ,
- },
- {
- key: "autorouter",
- label: "Autorouter",
- children: ,
- },
- {
- key: "caching",
- label: "Prompt Caching",
- children: ,
- },
- ];
-
- return (
-
-
-
-
- Track and configure the mechanisms that save you money: prompt compression, prompt caching, and auto routing
-
-
-
-
- Have feedback? Join the discussion{" "}
-
- here
-
-
- }
- />
-
-
-
- );
-};
-
-export default CostOptimizationView;
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/autorouter/page.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/autorouter/page.tsx
new file mode 100644
index 00000000000..6cf9700fdcb
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/autorouter/page.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+import AutorouterTab from "@/app/(dashboard)/cost-optimization/_components/AutorouterTab";
+import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
+
+export default function AutorouterPage() {
+ const { accessToken, userId, userRole } = useAuthorized();
+ return ;
+}
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/caching/page.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/caching/page.tsx
new file mode 100644
index 00000000000..de3f628829b
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/caching/page.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+import PromptCachingTab from "@/app/(dashboard)/cost-optimization/_components/PromptCachingTab";
+import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
+
+export default function PromptCachingPage() {
+ const { accessToken } = useAuthorized();
+ return ;
+}
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/compression/page.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/compression/page.tsx
new file mode 100644
index 00000000000..6bfbff16d84
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/compression/page.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+import PromptCompressionTab from "@/app/(dashboard)/cost-optimization/_components/PromptCompressionTab";
+import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
+
+export default function PromptCompressionPage() {
+ const { accessToken } = useAuthorized();
+ return ;
+}
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/layout.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/layout.test.tsx
new file mode 100644
index 00000000000..39e36935c88
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/layout.test.tsx
@@ -0,0 +1,82 @@
+/* @vitest-environment jsdom */
+import { act, render } from "@testing-library/react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import CostOptimizationLayout from "./layout";
+
+const { mockPush, navState } = vi.hoisted(() => ({
+ mockPush: vi.fn(),
+ navState: { pathname: "/cost-optimization" },
+}));
+vi.mock("next/navigation", () => ({
+ usePathname: () => navState.pathname,
+ useRouter: () => ({ push: mockPush }),
+}));
+
+vi.mock("@/components/networking", () => ({ serverRootPath: "" }));
+
+const renderLayout = () =>
+ render(
+
+ CHILD
+ ,
+ );
+
+describe("CostOptimizationLayout", () => {
+ beforeEach(() => {
+ navState.pathname = "/cost-optimization";
+ mockPush.mockClear();
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (global as any).ResizeObserver = class {
+ observe() {}
+ unobserve() {}
+ disconnect() {}
+ };
+ });
+
+ it("renders the tab bar and the active tab's page content", () => {
+ const { getByRole, getByTestId } = renderLayout();
+ expect(getByRole("tab", { name: "Usage" })).toBeInTheDocument();
+ expect(getByRole("tab", { name: "Prompt Compression" })).toBeInTheDocument();
+ expect(getByRole("tab", { name: "Autorouter" })).toBeInTheDocument();
+ expect(getByRole("tab", { name: "Prompt Caching" })).toBeInTheDocument();
+ expect(getByTestId("tab-content")).toHaveTextContent("CHILD");
+ });
+
+ it("marks the base route's Usage tab active", () => {
+ const { getByRole } = renderLayout();
+ expect(getByRole("tab", { name: "Usage" })).toHaveAttribute("aria-selected", "true");
+ expect(getByRole("tab", { name: "Prompt Compression" })).toHaveAttribute("aria-selected", "false");
+ });
+
+ it("navigates to a tab's path when its tab is clicked", async () => {
+ const { getByRole } = renderLayout();
+ await act(async () => {
+ getByRole("tab", { name: "Prompt Compression" }).click();
+ });
+ expect(mockPush).toHaveBeenCalledWith(expect.stringMatching(/\/cost-optimization\/compression\/$/));
+ });
+
+ it("routes the base tab back to the cost-optimization root (no slug)", async () => {
+ navState.pathname = "/cost-optimization/autorouter";
+ const { getByRole } = renderLayout();
+ await act(async () => {
+ getByRole("tab", { name: "Usage" }).click();
+ });
+ expect(mockPush).toHaveBeenCalledWith(expect.stringMatching(/\/cost-optimization\/$/));
+ });
+
+ it("redirects to the base cost-optimization path when the tab slug is unknown", async () => {
+ const replaceMock = vi.fn();
+ const originalLocation = window.location;
+ Object.defineProperty(window, "location", {
+ configurable: true,
+ value: { replace: replaceMock, assign: vi.fn(), href: "http://localhost/", pathname: "/", search: "" },
+ });
+ navState.pathname = "/cost-optimization/bogus";
+ await act(async () => {
+ renderLayout();
+ });
+ expect(replaceMock).toHaveBeenCalledWith(expect.stringMatching(/\/cost-optimization\/$/));
+ Object.defineProperty(window, "location", { configurable: true, value: originalLocation });
+ });
+});
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/layout.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/layout.tsx
new file mode 100644
index 00000000000..02eadc96e96
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/layout.tsx
@@ -0,0 +1,82 @@
+"use client";
+
+import type { ReactNode } from "react";
+import { useEffect } from "react";
+import { usePathname, useRouter } from "next/navigation";
+import { PiggyBank, Info } from "lucide-react";
+import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import {
+ costOptimizationTabHref,
+ slugFromPathname,
+ type CostOptimizationTabSlug,
+} from "@/app/(dashboard)/cost-optimization/tabRoutes";
+
+const BASE_TAB_KEY = "usage";
+
+const ORDERED_KEYS: Array<"" | CostOptimizationTabSlug> = ["", "compression", "autorouter", "caching"];
+
+const TAB_LABELS: Record<"" | CostOptimizationTabSlug, string> = {
+ "": "Usage",
+ compression: "Prompt Compression",
+ autorouter: "Autorouter",
+ caching: "Prompt Caching",
+};
+
+export default function CostOptimizationLayout({ children }: { children: ReactNode }) {
+ const pathname = usePathname();
+ const router = useRouter();
+
+ const activeSlug = slugFromPathname(pathname);
+ const isKnownSlug = ORDERED_KEYS.some((slug) => slug === activeSlug);
+ const activeKey = isKnownSlug ? activeSlug || BASE_TAB_KEY : BASE_TAB_KEY;
+
+ useEffect(() => {
+ if (activeSlug !== "" && !isKnownSlug) {
+ window.location.replace(costOptimizationTabHref(""));
+ }
+ }, [activeSlug, isKnownSlug]);
+
+ return (
+
+
+
+
+ Track and configure the mechanisms that save you money: prompt compression, prompt caching, and auto routing
+
+
+
+
+
+
+ This is an experimental dashboard. Have feedback? Join the discussion{" "}
+
+ here
+
+
+
+
+
router.push(costOptimizationTabHref(key === BASE_TAB_KEY ? "" : key))}
+ >
+
+ {ORDERED_KEYS.map((slug) => (
+
+ {TAB_LABELS[slug]}
+
+ ))}
+
+
+
+
{children}
+
+ );
+}
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/page.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/page.tsx
index e82cc633ae2..e90af9ac37d 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/page.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/page.tsx
@@ -1,9 +1,9 @@
"use client";
-import CostOptimizationView from "./_components/CostOptimizationView";
+import UsageTab from "./_components/UsageTab";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
export default function CostOptimizationPage() {
const { accessToken, userId, userRole } = useAuthorized();
- return ;
+ return ;
}
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/tabRoutes.test.ts b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/tabRoutes.test.ts
new file mode 100644
index 00000000000..49b9825a677
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/tabRoutes.test.ts
@@ -0,0 +1,38 @@
+/* @vitest-environment jsdom */
+import { describe, expect, it, vi } from "vitest";
+
+vi.mock("@/components/networking", () => ({ serverRootPath: "" }));
+
+import { COST_OPTIMIZATION_TAB_SLUGS, costOptimizationTabHref, slugFromPathname } from "./tabRoutes";
+
+describe("slugFromPathname", () => {
+ it("returns empty string for the base path with or without a trailing slash", () => {
+ expect(slugFromPathname("/cost-optimization")).toBe("");
+ expect(slugFromPathname("/cost-optimization/")).toBe("");
+ });
+
+ it("extracts the tab slug from dev and proxy-mounted (/ui) paths", () => {
+ expect(slugFromPathname("/cost-optimization/autorouter")).toBe("autorouter");
+ expect(slugFromPathname("/ui/cost-optimization/compression/")).toBe("compression");
+ });
+
+ it("returns the raw segment for an unknown tab so the layout can redirect to base", () => {
+ expect(slugFromPathname("/ui/cost-optimization/bogus")).toBe("bogus");
+ });
+
+ it("returns empty string when the cost-optimization base segment is not in the path", () => {
+ expect(slugFromPathname("/teams")).toBe("");
+ });
+});
+
+describe("costOptimizationTabHref", () => {
+ it("builds the trailing-slash base href for the empty slug", () => {
+ expect(costOptimizationTabHref("")).toBe("/ui/cost-optimization/");
+ });
+
+ it("builds a trailing-slash href for every tab slug (required by static export)", () => {
+ for (const slug of COST_OPTIMIZATION_TAB_SLUGS) {
+ expect(costOptimizationTabHref(slug)).toBe(`/ui/cost-optimization/${slug}/`);
+ }
+ });
+});
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/tabRoutes.ts b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/tabRoutes.ts
new file mode 100644
index 00000000000..df4429139a7
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/tabRoutes.ts
@@ -0,0 +1,21 @@
+import { migratedHref } from "@/utils/migratedPages";
+
+export const COST_OPTIMIZATION_BASE_SEGMENT = "cost-optimization";
+
+export const COST_OPTIMIZATION_TAB_SLUGS = ["compression", "autorouter", "caching"] as const;
+
+export type CostOptimizationTabSlug = (typeof COST_OPTIMIZATION_TAB_SLUGS)[number];
+
+export function costOptimizationTabHref(slug: string): string {
+ const base = migratedHref(COST_OPTIMIZATION_BASE_SEGMENT);
+ return slug ? `${base}/${slug}/` : `${base}/`;
+}
+
+export function slugFromPathname(pathname: string): string {
+ const parts = pathname.split("/").filter(Boolean);
+ const idx = parts.indexOf(COST_OPTIMIZATION_BASE_SEGMENT);
+ if (idx === -1) {
+ return "";
+ }
+ return parts[idx + 1] ?? "";
+}