mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
fix(ui): don't show enable-prompt-storage hint when storage is already on
This commit is contained in:
parent
9d745486d0
commit
ac65bc658b
6 changed files with 107 additions and 18 deletions
|
|
@ -13,13 +13,22 @@ describe("ConfigInfoMessage", () => {
|
|||
expect(container.innerHTML).toBe("");
|
||||
});
|
||||
|
||||
it("should display the YAML config snippet", () => {
|
||||
render(<ConfigInfoMessage show={true} />);
|
||||
it("should display the YAML config snippet when prompt storage is disabled", () => {
|
||||
render(<ConfigInfoMessage show={true} promptStorageEnabled={false} />);
|
||||
expect(screen.getByText(/store_prompts_in_spend_logs: true/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should reference Admin Settings \u2192 Logging Settings", () => {
|
||||
render(<ConfigInfoMessage show={true} />);
|
||||
it("should reference Admin Settings \u2192 Logging Settings when prompt storage is disabled", () => {
|
||||
render(<ConfigInfoMessage show={true} promptStorageEnabled={false} />);
|
||||
expect(screen.getByText(/Admin Settings → Logging Settings/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should not show the enable-storage config hint when prompt storage is already enabled", () => {
|
||||
render(<ConfigInfoMessage show={true} promptStorageEnabled={true} />);
|
||||
|
||||
expect(screen.getByText("Request/Response Data Not Available")).toBeInTheDocument();
|
||||
expect(screen.getByText(/Prompt storage is enabled/)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/store_prompts_in_spend_logs: true/)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/Admin Settings → Logging Settings/)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ import React from "react";
|
|||
|
||||
interface ConfigInfoMessageProps {
|
||||
show: boolean;
|
||||
promptStorageEnabled?: boolean;
|
||||
}
|
||||
|
||||
export const ConfigInfoMessage: React.FC<ConfigInfoMessageProps> = ({ show }) => {
|
||||
export const ConfigInfoMessage: React.FC<ConfigInfoMessageProps> = ({ show, promptStorageEnabled = false }) => {
|
||||
if (!show) return null;
|
||||
|
||||
return (
|
||||
|
|
@ -28,19 +29,31 @@ export const ConfigInfoMessage: React.FC<ConfigInfoMessageProps> = ({ show }) =>
|
|||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-blue-800">Request/Response Data Not Available</h4>
|
||||
<p className="text-sm text-blue-700 mt-1">
|
||||
To view request and response details, enable prompt storage in your LiteLLM configuration by adding the
|
||||
following to your <code className="bg-blue-100 px-1 py-0.5 rounded-sm">proxy_config.yaml</code> file, or
|
||||
toggle the setting in <strong>Admin Settings → Logging Settings</strong>.
|
||||
</p>
|
||||
<pre className="mt-2 bg-white p-3 rounded-sm border border-blue-200 text-xs font-mono overflow-auto">
|
||||
{`general_settings:
|
||||
{promptStorageEnabled ? (
|
||||
<p className="text-sm text-blue-700 mt-1">
|
||||
Prompt storage is enabled, but no request or response payload was recorded for this request. This usually
|
||||
means the payload was never captured rather than that storage is misconfigured, for example when a request
|
||||
failed before the payload was stored (such as a streaming request whose upstream call errored), or when the
|
||||
payload was written through a different logging integration. Check the request status and any error details
|
||||
above to see what happened.
|
||||
</p>
|
||||
) : (
|
||||
<>
|
||||
<p className="text-sm text-blue-700 mt-1">
|
||||
To view request and response details, enable prompt storage in your LiteLLM configuration by adding the
|
||||
following to your <code className="bg-blue-100 px-1 py-0.5 rounded-sm">proxy_config.yaml</code> file, or
|
||||
toggle the setting in <strong>Admin Settings → Logging Settings</strong>.
|
||||
</p>
|
||||
<pre className="mt-2 bg-white p-3 rounded-sm border border-blue-200 text-xs font-mono overflow-auto">
|
||||
{`general_settings:
|
||||
store_model_in_db: true
|
||||
store_prompts_in_spend_logs: true`}
|
||||
</pre>
|
||||
<p className="text-xs text-blue-700 mt-2">
|
||||
Note: This will only affect new requests after the configuration change.
|
||||
</p>
|
||||
</pre>
|
||||
<p className="text-xs text-blue-700 mt-2">
|
||||
Note: This will only affect new requests after the configuration change.
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -156,6 +156,40 @@ describe("LogDetailContent", () => {
|
|||
expect(screen.getByText("Request/Response Data Not Available")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should show the enable-storage config hint when payload is missing and prompt storage is disabled", () => {
|
||||
render(
|
||||
<LogDetailContent
|
||||
logEntry={createLogEntry({
|
||||
messages: [],
|
||||
response: {},
|
||||
metadata: {},
|
||||
})}
|
||||
promptStorageEnabled={false}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("Request/Response Data Not Available")).toBeInTheDocument();
|
||||
expect(screen.getByText(/store_prompts_in_spend_logs: true/)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/Prompt storage is enabled/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should show a per-request explanation (not the config hint) when payload is missing but prompt storage is enabled", () => {
|
||||
render(
|
||||
<LogDetailContent
|
||||
logEntry={createLogEntry({
|
||||
messages: [],
|
||||
response: {},
|
||||
metadata: {},
|
||||
})}
|
||||
promptStorageEnabled={true}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("Request/Response Data Not Available")).toBeInTheDocument();
|
||||
expect(screen.getByText(/Prompt storage is enabled/)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/store_prompts_in_spend_logs: true/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should not display ConfigInfoMessage when isLoadingDetails is true even without data", () => {
|
||||
render(
|
||||
<LogDetailContent
|
||||
|
|
|
|||
|
|
@ -41,6 +41,12 @@ export interface LogDetailContentProps {
|
|||
/** When true, log details (messages/response) are still being lazy-loaded. */
|
||||
isLoadingDetails?: boolean;
|
||||
accessToken?: string | null;
|
||||
/**
|
||||
* Whether store_prompts_in_spend_logs is enabled proxy-wide. Controls which
|
||||
* "data not available" hint is shown: the config instructions when storage is
|
||||
* off, or a per-request explanation when storage is on but this row has no payload.
|
||||
*/
|
||||
promptStorageEnabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -51,7 +57,12 @@ export interface LogDetailContentProps {
|
|||
* 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, isLoadingDetails = false, accessToken }: LogDetailContentProps) {
|
||||
export function LogDetailContent({
|
||||
logEntry,
|
||||
isLoadingDetails = false,
|
||||
accessToken,
|
||||
promptStorageEnabled = false,
|
||||
}: LogDetailContentProps) {
|
||||
const metadata = logEntry.metadata || {};
|
||||
const hasError = metadata.status === "failure";
|
||||
const errorInfo = hasError ? metadata.error_information : null;
|
||||
|
|
@ -157,7 +168,7 @@ export function LogDetailContent({ logEntry, isLoadingDetails = false, accessTok
|
|||
{/* Configuration Info Message */}
|
||||
{missingData && (
|
||||
<div className="mb-6">
|
||||
<ConfigInfoMessage show={missingData} />
|
||||
<ConfigInfoMessage show={missingData} promptStorageEnabled={promptStorageEnabled} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,14 @@ vi.mock("@/app/(dashboard)/hooks/logDetails/useLogDetails", () => ({
|
|||
useLogDetails: () => ({ data: null, isLoading: false }),
|
||||
}));
|
||||
|
||||
vi.mock("@/app/(dashboard)/hooks/proxyConfig/useProxyConfig", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("@/app/(dashboard)/hooks/proxyConfig/useProxyConfig")>();
|
||||
return {
|
||||
...actual,
|
||||
getProxyConfigCall: vi.fn().mockResolvedValue([]),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./LogDetailContent", () => ({
|
||||
LogDetailContent: () => null,
|
||||
GuardrailJumpLink: () => null,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { getSpendString } from "@/utils/dataUtils";
|
|||
import { normalizeGuardrailEntries, sortSessionLogs, SessionLogSortMode } from "./utils";
|
||||
import { DRAWER_WIDTH } from "./constants";
|
||||
import { useLogDetails } from "@/app/(dashboard)/hooks/logDetails/useLogDetails";
|
||||
import { ConfigType, getProxyConfigCall, proxyConfigKeys } from "@/app/(dashboard)/hooks/proxyConfig/useProxyConfig";
|
||||
|
||||
export interface LogDetailsDrawerProps {
|
||||
open: boolean;
|
||||
|
|
@ -121,6 +122,18 @@ export function LogDetailsDrawer({
|
|||
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
|
||||
const [copiedLeftPanelId, setCopiedLeftPanelId] = useState(false);
|
||||
|
||||
// Proxy-wide store_prompts_in_spend_logs. Shares the query key (and therefore
|
||||
// the cache) with useProxyConfig so the Logging Settings page and this drawer
|
||||
// stay consistent. Used to tell apart "storage disabled" (show config hint)
|
||||
// from "storage on but this request has no payload" in the missing-data notice.
|
||||
const { data: generalSettings } = useQuery({
|
||||
queryKey: proxyConfigKeys.list({ filters: { configType: ConfigType.GENERAL_SETTINGS } }),
|
||||
queryFn: () => getProxyConfigCall(accessToken!, ConfigType.GENERAL_SETTINGS),
|
||||
enabled: Boolean(open && accessToken),
|
||||
});
|
||||
const promptStorageEnabled =
|
||||
generalSettings?.find((field) => field.field_name === "store_prompts_in_spend_logs")?.field_value === true;
|
||||
|
||||
const { data: sessionData } = useQuery({
|
||||
queryKey: ["sessionLogs", sessionId],
|
||||
queryFn: async () => {
|
||||
|
|
@ -463,6 +476,7 @@ export function LogDetailsDrawer({
|
|||
logEntry={enrichedLog}
|
||||
isLoadingDetails={isLoadingDetails}
|
||||
accessToken={accessToken ?? null}
|
||||
promptStorageEnabled={promptStorageEnabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue