diff --git a/ui/litellm-dashboard/src/app/page.tsx b/ui/litellm-dashboard/src/app/page.tsx
index 8b882e9cd23..fb749d7afb0 100644
--- a/ui/litellm-dashboard/src/app/page.tsx
+++ b/ui/litellm-dashboard/src/app/page.tsx
@@ -549,7 +549,7 @@ function CreateKeyPageContent() {
) : page == "vector-stores" ? (
) : page == "guardrails-monitor" ? (
-
+
) : page == "new_usage" ? (
void;
+ guardrailName?: string;
+ accessToken: string | null;
+ onRunEvaluation?: (settings: { prompt: string; schema: string; model: string }) => void;
+}
+
+export function EvaluationSettingsModal({
+ open,
+ onClose,
+ guardrailName,
+ accessToken,
+ onRunEvaluation,
+}: EvaluationSettingsModalProps) {
+ const [prompt, setPrompt] = useState(DEFAULT_PROMPT);
+ const [schema, setSchema] = useState(DEFAULT_SCHEMA);
+ const [model, setModel] = useState(null);
+ const [modelOptions, setModelOptions] = useState([]);
+ const [loadingModels, setLoadingModels] = useState(false);
+
+ useEffect(() => {
+ if (!open || !accessToken) {
+ setModelOptions([]);
+ return;
+ }
+ let cancelled = false;
+ setLoadingModels(true);
+ fetchAvailableModels(accessToken)
+ .then((list) => {
+ if (!cancelled) setModelOptions(list);
+ })
+ .catch(() => {
+ if (!cancelled) setModelOptions([]);
+ })
+ .finally(() => {
+ if (!cancelled) setLoadingModels(false);
+ });
+ return () => {
+ cancelled = true;
+ };
+ }, [open, accessToken]);
+
+ const handleResetPrompt = () => setPrompt(DEFAULT_PROMPT);
+ const handleRun = () => {
+ if (model) {
+ onRunEvaluation?.({ prompt, schema, model });
+ onClose();
+ }
+ };
+
+ const modelSelectOptions = modelOptions.map((m) => ({
+ value: m.model_group,
+ label: m.model_group,
+ }));
+
+ return (
+ }
+ destroyOnClose
+ >
+
+ {guardrailName
+ ? `Configure AI evaluation for ${guardrailName}`
+ : "Configure AI evaluation for re-running on logs"}
+
+
+
+
+
+
+
+
+
setPrompt(e.target.value)}
+ rows={6}
+ className="font-mono text-sm"
+ />
+
+ System prompt sent to the evaluation model. Output is structured via response_format.
+
+
+
+
+
+
response_format: json_schema
+
setSchema(e.target.value)}
+ rows={6}
+ className="font-mono text-sm"
+ />
+
+
+
+
+
+
+
+
+
+
+ } onClick={handleRun} disabled={!model}>
+ Run Evaluation
+
+
+
+ );
+}
diff --git a/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailDetail.tsx b/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailDetail.tsx
index d664e99033b..5c16979d3e0 100644
--- a/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailDetail.tsx
+++ b/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailDetail.tsx
@@ -3,19 +3,23 @@ import {
BellOutlined,
CheckOutlined,
CloseOutlined,
+ PlayCircleOutlined,
SafetyOutlined,
+ SettingOutlined,
WarningOutlined,
} from "@ant-design/icons";
import { Card, Col, Grid, Title } from "@tremor/react";
import { Button, Input, Tabs } from "antd";
import React, { useState } from "react";
import { getGuardrailDetailOrDefault } from "./mockData";
+import { EvaluationSettingsModal } from "./EvaluationSettingsModal";
import { LogViewer } from "./LogViewer";
import { MetricCard } from "./MetricCard";
interface GuardrailDetailProps {
guardrailId: string;
onBack: () => void;
+ accessToken?: string | null;
}
const statusColors: Record<
@@ -27,10 +31,15 @@ const statusColors: Record<
critical: { bg: "bg-red-50", text: "text-red-700", dot: "bg-red-500" },
};
-export function GuardrailDetail({ guardrailId, onBack }: GuardrailDetailProps) {
+export function GuardrailDetail({
+ guardrailId,
+ onBack,
+ accessToken = null,
+}: GuardrailDetailProps) {
const [activeTab, setActiveTab] = useState("overview");
const [showNotifyPanel, setShowNotifyPanel] = useState(false);
const [notifySaved, setNotifySaved] = useState(false);
+ const [evaluationModalOpen, setEvaluationModalOpen] = useState(false);
const [notifyConfig, setNotifyConfig] = useState({
failRateThreshold: "",
apiErrorThreshold: "",
@@ -77,6 +86,15 @@ export function GuardrailDetail({ guardrailId, onBack }: GuardrailDetailProps) {
{data.provider}
+ }>
+ Re-run AI
+
+ }
+ onClick={() => setEvaluationModalOpen(true)}
+ title="Evaluation settings"
+ />
)}
+
+ setEvaluationModalOpen(false)}
+ guardrailName={data.name}
+ accessToken={accessToken}
+ />
);
}
diff --git a/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailsMonitorView.tsx b/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailsMonitorView.tsx
index a4d0f892ec6..7cc2074e468 100644
--- a/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailsMonitorView.tsx
+++ b/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailsMonitorView.tsx
@@ -6,7 +6,11 @@ type View =
| { type: "overview" }
| { type: "detail"; guardrailId: string };
-export default function GuardrailsMonitorView() {
+interface GuardrailsMonitorViewProps {
+ accessToken?: string | null;
+}
+
+export default function GuardrailsMonitorView({ accessToken = null }: GuardrailsMonitorViewProps) {
const [view, setView] = useState({ type: "overview" });
const handleSelectGuardrail = (id: string) => {
@@ -20,9 +24,13 @@ export default function GuardrailsMonitorView() {
return (
{view.type === "overview" ? (
-
+
) : (
-
+
)}
);
diff --git a/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailsOverview.tsx b/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailsOverview.tsx
index e18bc987fb2..41933977693 100644
--- a/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailsOverview.tsx
+++ b/ui/litellm-dashboard/src/components/GuardrailsMonitor/GuardrailsOverview.tsx
@@ -5,6 +5,7 @@ import {
PlayCircleOutlined,
RiseOutlined,
SafetyOutlined,
+ SettingOutlined,
WarningOutlined,
} from "@ant-design/icons";
import { Card, Col, Grid, Title } from "@tremor/react";
@@ -16,10 +17,12 @@ import {
policiesTable,
type PerformanceRow,
} from "./mockData";
+import { EvaluationSettingsModal } from "./EvaluationSettingsModal";
import { MetricCard } from "./MetricCard";
import { ScoreChart } from "./ScoreChart";
interface GuardrailsOverviewProps {
+ accessToken?: string | null;
onSelectGuardrail: (id: string) => void;
}
@@ -59,11 +62,15 @@ function computeMetrics(data: PerformanceRow[]) {
type RerunState = "idle" | "running" | "done";
-export function GuardrailsOverview({ onSelectGuardrail }: GuardrailsOverviewProps) {
+export function GuardrailsOverview({
+ accessToken = null,
+ onSelectGuardrail,
+}: GuardrailsOverviewProps) {
const [viewMode, setViewMode] = useState("guardrails");
const [sortBy, setSortBy] = useState("failRate");
const [sortDir, setSortDir] = useState<"asc" | "desc">("desc");
const [rerunState, setRerunState] = useState("idle");
+ const [evaluationModalOpen, setEvaluationModalOpen] = useState(false);
useEffect(() => {
if (rerunState !== "done") return;
@@ -357,26 +364,34 @@ export function GuardrailsOverview({ onSelectGuardrail }: GuardrailsOverviewProp
: "Click a policy to view details, logs, and configuration"}
-
- ) : rerunState === "done" ? (
-
- ) : (
-
- )
- }
- disabled={rerunState === "running"}
- onClick={handleRerun}
- >
- {rerunState === "idle"
- ? "Re-run AI on last 100 logs"
- : rerunState === "running"
- ? "Re-running on 100 logs…"
- : "Re-run complete"}
-
+
+ }
+ onClick={() => setEvaluationModalOpen(true)}
+ title="Evaluation settings"
+ />
+
+ ) : rerunState === "done" ? (
+
+ ) : (
+
+ )
+ }
+ disabled={rerunState === "running"}
+ onClick={handleRerun}
+ >
+ {rerunState === "idle"
+ ? "Re-run AI on last 100 logs"
+ : rerunState === "running"
+ ? "Re-running on 100 logs…"
+ : "Re-run complete"}
+
+
+
+ setEvaluationModalOpen(false)}
+ accessToken={accessToken}
+ />
);
}