diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailContent.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailContent.tsx
new file mode 100644
index 00000000000..ef5de9febc3
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailContent.tsx
@@ -0,0 +1,442 @@
+import { useState } from "react";
+import { Typography, Descriptions, Card, Tag, Tabs, Alert, Collapse, Radio, Space } from "antd";
+import moment from "moment";
+import { LogEntry } from "../columns";
+import { formatNumberWithCommas } from "@/utils/dataUtils";
+import GuardrailViewer from "../GuardrailViewer/GuardrailViewer";
+import { CostBreakdownViewer } from "../CostBreakdownViewer";
+import { ConfigInfoMessage } from "../ConfigInfoMessage";
+import { VectorStoreViewer } from "../VectorStoreViewer";
+import { TruncatedValue } from "./TruncatedValue";
+import { TokenFlow } from "./TokenFlow";
+import { JsonViewer } from "./JsonViewer";
+import {
+ formatData,
+ checkHasMessages,
+ checkHasResponse,
+ normalizeGuardrailEntries,
+ calculateTotalMaskedEntities,
+ getGuardrailLabel,
+ checkHasVectorStoreData,
+} from "./utils";
+import {
+ DRAWER_CONTENT_PADDING,
+ API_BASE_MAX_WIDTH,
+ METADATA_MAX_HEIGHT,
+ TAB_REQUEST,
+ TAB_RESPONSE,
+ FONT_SIZE_SMALL,
+ FONT_FAMILY_MONO,
+ SPACING_XLARGE,
+ SPACING_MEDIUM,
+} from "./constants";
+import { ToolsSection } from "../ToolsSection";
+import { PrettyMessagesView } from "./PrettyMessagesView";
+
+const { Text } = Typography;
+
+export interface LogDetailContentProps {
+ logEntry: LogEntry;
+ onOpenSettings?: () => void;
+}
+
+/**
+ * The scrollable detail content for a single log entry.
+ * Renders request details, metrics, cost breakdown, request/response,
+ * guardrails, vector store data, and metadata.
+ *
+ * Designed to be placed inside LogDetailsDrawer's right panel so it can
+ * be reused for both single-log and session-mode views.
+ */
+export function LogDetailContent({ logEntry, onOpenSettings }: LogDetailContentProps) {
+ const metadata = logEntry.metadata || {};
+ const hasError = metadata.status === "failure";
+ const errorInfo = hasError ? metadata.error_information : null;
+
+ const hasMessages = checkHasMessages(logEntry.messages);
+ const hasResponse = checkHasResponse(logEntry.response);
+ const missingData = !hasMessages && !hasResponse && !hasError;
+
+ // Guardrail data
+ const guardrailInfo = metadata?.guardrail_information;
+ const guardrailEntries = normalizeGuardrailEntries(guardrailInfo);
+ const hasGuardrailData = guardrailEntries.length > 0;
+ const totalMaskedEntities = calculateTotalMaskedEntities(guardrailEntries);
+ const primaryGuardrailLabel = getGuardrailLabel(guardrailEntries);
+
+ // Vector store data
+ const hasVectorStoreData = checkHasVectorStoreData(metadata);
+
+ const getRawRequest = () => {
+ return formatData(logEntry.proxy_server_request || logEntry.messages);
+ };
+
+ const getFormattedResponse = () => {
+ if (hasError && errorInfo) {
+ return {
+ error: {
+ message: errorInfo.error_message || "An error occurred",
+ type: errorInfo.error_class || "error",
+ code: errorInfo.error_code || "unknown",
+ param: null,
+ },
+ };
+ }
+ return formatData(logEntry.response);
+ };
+
+ return (
+
+ {/* Error Alert */}
+ {hasError && errorInfo && (
+
}
+ className="mb-6"
+ />
+ )}
+
+ {/* Tags */}
+ {logEntry.request_tags && Object.keys(logEntry.request_tags).length > 0 && (
+
+ )}
+
+ {/* Request Details */}
+
+
+
+ {logEntry.model}
+ {logEntry.custom_llm_provider || "-"}
+ {logEntry.call_type}
+
+
+
+
+
+
+ {logEntry.requester_ip_address && (
+ {logEntry.requester_ip_address}
+ )}
+ {hasGuardrailData && (
+
+
+
+ )}
+
+
+
+
+ {/* Metrics */}
+
+
+ {/* Cost Breakdown */}
+
+
+ {/* Tools */}
+
+
+ {/* Configuration Info Message */}
+ {missingData && (
+
+
+
+ )}
+
+ {/* Request/Response JSON */}
+
+
+ {/* Guardrail Data */}
+ {hasGuardrailData &&
}
+
+ {/* Vector Store Data */}
+ {hasVectorStoreData &&
}
+
+ {/* Metadata */}
+ {logEntry.metadata && Object.keys(logEntry.metadata).length > 0 && (
+
+ )}
+
+ {/* Bottom spacing */}
+
+
+ );
+}
+
+// ============================================================================
+// Helper Components
+// ============================================================================
+
+function ErrorDescription({ errorInfo }: { errorInfo: any }) {
+ return (
+
+ {errorInfo.error_code && (
+
+ Error Code: {errorInfo.error_code}
+
+ )}
+ {errorInfo.error_message && (
+
+ Message: {errorInfo.error_message}
+
+ )}
+
+ );
+}
+
+function TagsSection({ tags }: { tags: Record }) {
+ return (
+
+
+ Tags
+
+
+ {Object.entries(tags).map(([key, value]) => (
+
+ {key}: {String(value)}
+
+ ))}
+
+
+ );
+}
+
+function GuardrailLabel({ label, maskedCount }: { label: string; maskedCount: number }) {
+ return (
+
+ {label}
+ {maskedCount > 0 && (
+
+ {maskedCount} masked
+
+ )}
+
+ );
+}
+
+function MetricsSection({ logEntry, metadata }: { logEntry: LogEntry; metadata: Record }) {
+ const hasCacheActivity =
+ logEntry.cache_hit ||
+ (metadata?.additional_usage_values?.cache_read_input_tokens &&
+ metadata.additional_usage_values.cache_read_input_tokens > 0);
+
+ return (
+
+
+
+
+
+
+ ${formatNumberWithCommas(logEntry.spend || 0, 8)}
+ {logEntry.duration?.toFixed(3)} s
+
+ {hasCacheActivity && (
+ <>
+
+ {logEntry.cache_hit || "None"}
+
+ {metadata?.additional_usage_values?.cache_read_input_tokens > 0 && (
+
+ {formatNumberWithCommas(metadata.additional_usage_values.cache_read_input_tokens)}
+
+ )}
+ {metadata?.additional_usage_values?.cache_creation_input_tokens > 0 && (
+
+ {formatNumberWithCommas(metadata.additional_usage_values.cache_creation_input_tokens)}
+
+ )}
+ >
+ )}
+
+ {metadata?.litellm_overhead_time_ms !== undefined && metadata.litellm_overhead_time_ms !== null && (
+
+ {metadata.litellm_overhead_time_ms.toFixed(2)} ms
+
+ )}
+
+
+ {moment(logEntry.startTime).format("YYYY-MM-DDTHH:mm:ss.SSS[Z]")}
+
+
+ {moment(logEntry.endTime).format("YYYY-MM-DDTHH:mm:ss.SSS[Z]")}
+
+
+
+
+ );
+}
+
+interface RequestResponseSectionProps {
+ hasResponse: boolean;
+ hasError: boolean;
+ getRawRequest: () => any;
+ getFormattedResponse: () => any;
+ logEntry: LogEntry;
+}
+
+function RequestResponseSection({
+ hasResponse,
+ hasError,
+ getRawRequest,
+ getFormattedResponse,
+ logEntry,
+}: RequestResponseSectionProps) {
+ const [activeTab, setActiveTab] = useState(TAB_REQUEST);
+ const [viewMode, setViewMode] = useState<'pretty' | 'json'>('pretty');
+
+ const getCopyText = () => {
+ const data = activeTab === TAB_REQUEST ? getRawRequest() : getFormattedResponse();
+ return JSON.stringify(data, null, 2);
+ };
+
+ const totalSpend = logEntry.spend || 0;
+ const promptTokens = logEntry.prompt_tokens || 0;
+ const completionTokens = logEntry.completion_tokens || 0;
+ const totalTokens = promptTokens + completionTokens;
+ const inputCost = totalTokens > 0 ? (totalSpend * promptTokens) / totalTokens : 0;
+ const outputCost = totalTokens > 0 ? (totalSpend * completionTokens) / totalTokens : 0;
+
+ return (
+
+ {
+ const target = e.target as HTMLElement;
+ if (target.closest('.ant-radio-group')) {
+ e.stopPropagation();
+ }
+ }}
+ >
+ Request & Response
+ setViewMode(e.target.value)}
+ >
+ Pretty
+ JSON
+
+
+ ),
+ children: (
+
+ {viewMode === 'pretty' ? (
+
+ ) : (
+
setActiveTab(key as typeof TAB_REQUEST | typeof TAB_RESPONSE)}
+ tabBarExtraContent={
+
+ }
+ items={[
+ {
+ key: TAB_REQUEST,
+ label: "Request",
+ children: (
+
+
+
+ ),
+ },
+ {
+ key: TAB_RESPONSE,
+ label: "Response",
+ children: (
+
+ {hasResponse || hasError ? (
+
+ ) : (
+
+ Response data not available
+
+ )}
+
+ ),
+ },
+ ]}
+ />
+ )}
+
+ ),
+ },
+ ]}
+ />
+
+ );
+}
+
+function MetadataSection({ metadata }: { metadata: Record }) {
+ return (
+
+
Metadata,
+ children: (
+
+
+
+
+
+ {JSON.stringify(metadata, null, 2)}
+
+
+ ),
+ },
+ ]}
+ />
+
+ );
+}