mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(ui): count only LiteLLM-injected caching in the total savings figures
The caching tile's headline switched to the gateway-attributed share, but the Total saved tile and the by-driver donut kept summing total caching, so the three visible headlines no longer added up to the total beside them and the donut sliced a number no tile printed. Point the total, the per-day series and the donut at the injected share; caching the gateway did not cause stays visible as the caching tile's secondary Total figure
This commit is contained in:
parent
baf140a35d
commit
23afd7f4a8
4 changed files with 28 additions and 18 deletions
|
|
@ -137,28 +137,34 @@ describe("UsageTab", () => {
|
|||
});
|
||||
|
||||
it("sums compression and caching dollars across days into the summary cards", () => {
|
||||
// Total caching and the LiteLLM-injected share deliberately differ so these
|
||||
// assertions pin which one each figure uses: the caching headline and the
|
||||
// Total-saved tile take the injected share, the secondary keeps the total.
|
||||
const { getByText } = renderWith([
|
||||
day("2026-07-12", {
|
||||
compression_savings_spend: 0.04,
|
||||
prompt_caching_savings_spend: 0.006,
|
||||
gateway_injected_caching_savings_spend: 0.004,
|
||||
compression_saved_tokens: 40000,
|
||||
}),
|
||||
day("2026-07-13", {
|
||||
compression_savings_spend: 0.1,
|
||||
prompt_caching_savings_spend: 0.01,
|
||||
gateway_injected_caching_savings_spend: 0.006,
|
||||
compression_saved_tokens: 100000,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(getByText("$0.1560")).toBeInTheDocument();
|
||||
expect(getByText("$0.1500")).toBeInTheDocument();
|
||||
expect(getByText("$0.1400")).toBeInTheDocument();
|
||||
expect(getByText("$0.0100")).toBeInTheDocument();
|
||||
expect(getByText("$0.0160")).toBeInTheDocument();
|
||||
expect(getByText("140,000 tokens compressed")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const twoDays = () => [
|
||||
day("2026-07-12", { compression_savings_spend: 0.04, prompt_caching_savings_spend: 0.006 }),
|
||||
day("2026-07-13", { compression_savings_spend: 0.1, prompt_caching_savings_spend: 0.01 }),
|
||||
day("2026-07-12", { compression_savings_spend: 0.04, gateway_injected_caching_savings_spend: 0.006 }),
|
||||
day("2026-07-13", { compression_savings_spend: 0.1, gateway_injected_caching_savings_spend: 0.01 }),
|
||||
];
|
||||
|
||||
it("opens on a running total anchored at $0 at the start of the range", () => {
|
||||
|
|
@ -179,7 +185,7 @@ describe("UsageTab", () => {
|
|||
// synthetic start anchor gives the line a zero origin to climb from.
|
||||
const oneDay = new Date(2026, 6, 24);
|
||||
const { getByTestId } = renderWith(
|
||||
[day("2026-07-24", { compression_savings_spend: 0.2, prompt_caching_savings_spend: 0.05 })],
|
||||
[day("2026-07-24", { compression_savings_spend: 0.2, gateway_injected_caching_savings_spend: 0.05 })],
|
||||
{ from: oneDay, to: oneDay },
|
||||
);
|
||||
|
||||
|
|
@ -194,8 +200,8 @@ describe("UsageTab", () => {
|
|||
// still read left to right in time, and the running total must climb toward
|
||||
// the newest day, not fall away from it.
|
||||
const newestFirst = [
|
||||
day("2026-07-13", { prompt_caching_savings_spend: 0.1 }),
|
||||
day("2026-07-12", { prompt_caching_savings_spend: 0.04 }),
|
||||
day("2026-07-13", { gateway_injected_caching_savings_spend: 0.1 }),
|
||||
day("2026-07-12", { gateway_injected_caching_savings_spend: 0.04 }),
|
||||
];
|
||||
const { getByTestId, getByRole } = renderWith(newestFirst);
|
||||
|
||||
|
|
@ -260,7 +266,7 @@ describe("UsageTab", () => {
|
|||
const { getByRole, getByTestId } = renderWith([
|
||||
day("2026-07-12", {
|
||||
compression_savings_spend: 0.1,
|
||||
prompt_caching_savings_spend: 0.02,
|
||||
gateway_injected_caching_savings_spend: 0.02,
|
||||
autorouter_savings_spend: -0.05,
|
||||
}),
|
||||
]);
|
||||
|
|
@ -312,7 +318,7 @@ describe("UsageTab", () => {
|
|||
const { getByText, getByTestId } = renderWith([
|
||||
day("2026-07-12", {
|
||||
compression_savings_spend: 0.1,
|
||||
prompt_caching_savings_spend: 0.02,
|
||||
gateway_injected_caching_savings_spend: 0.02,
|
||||
autorouter_savings_spend: -0.05,
|
||||
}),
|
||||
]);
|
||||
|
|
@ -329,12 +335,12 @@ describe("UsageTab", () => {
|
|||
const { getByText, getByTestId } = renderWith([
|
||||
day("2026-07-12", {
|
||||
compression_savings_spend: 0.04,
|
||||
prompt_caching_savings_spend: 0.006,
|
||||
gateway_injected_caching_savings_spend: 0.006,
|
||||
autorouter_savings_spend: 0.02,
|
||||
}),
|
||||
day("2026-07-13", {
|
||||
compression_savings_spend: 0.1,
|
||||
prompt_caching_savings_spend: 0.01,
|
||||
gateway_injected_caching_savings_spend: 0.01,
|
||||
autorouter_savings_spend: 0.05,
|
||||
}),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import { getToolSpend, ToolSpendResponse } from "@/components/networking";
|
|||
import {
|
||||
autorouterOf,
|
||||
buildDailyToolSeries,
|
||||
cachingOf,
|
||||
compressionOf,
|
||||
formatRangeLabel,
|
||||
gatewayAttributedCachingOf,
|
||||
localIsoDay,
|
||||
MAX_POINTS_WITH_DOTS,
|
||||
SAVINGS_COLORS,
|
||||
|
|
@ -88,7 +88,7 @@ const UsageTab: React.FC<UsageTabProps> = ({ accessToken, activity }) => {
|
|||
.map((d) => ({
|
||||
date: shortDate(d.date),
|
||||
Compression: compressionOf(d.metrics),
|
||||
"Prompt caching": cachingOf(d.metrics),
|
||||
"Prompt caching": gatewayAttributedCachingOf(d.metrics),
|
||||
"Auto-router": autorouterOf(d.metrics),
|
||||
})),
|
||||
[results],
|
||||
|
|
@ -119,9 +119,11 @@ const UsageTab: React.FC<UsageTabProps> = ({ accessToken, activity }) => {
|
|||
SAVINGS_DRIVERS.map(({ name, color }) => ({
|
||||
driver: name,
|
||||
color,
|
||||
usd: { Compression: totals.compression, "Prompt caching": totals.caching, "Auto-router": totals.autorouter }[
|
||||
name
|
||||
],
|
||||
usd: {
|
||||
Compression: totals.compression,
|
||||
"Prompt caching": totals.gatewayAttributedCaching,
|
||||
"Auto-router": totals.autorouter,
|
||||
}[name],
|
||||
})).filter((d) => d.usd > 0),
|
||||
[totals],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ export const useSavingsTotals = (results: DailyData[]) =>
|
|||
const compression = sumOf(compressionOf);
|
||||
const caching = sumOf(cachingOf);
|
||||
const autorouter = sumOf(autorouterOf);
|
||||
const gatewayAttributedCaching = sumOf(gatewayAttributedCachingOf);
|
||||
return {
|
||||
compression,
|
||||
caching,
|
||||
autorouter,
|
||||
gatewayAttributedCaching: sumOf(gatewayAttributedCachingOf),
|
||||
gatewayAttributedCaching,
|
||||
savedTokens: sumOf(savedTokensOf),
|
||||
total: compression + caching + autorouter,
|
||||
total: compression + gatewayAttributedCaching + autorouter,
|
||||
};
|
||||
}, [results]);
|
||||
|
||||
|
|
@ -41,6 +42,7 @@ const SavingsTiles = ({ results, isLoading }: { results: DailyData[]; isLoading:
|
|||
label="Total saved"
|
||||
value={usd(totals.total)}
|
||||
hint={isLoading ? "Loading..." : "Compression + prompt caching + auto-router"}
|
||||
info="The sum of the three tiles beside it. Its caching term is the LiteLLM-injected share, so this total is what the gateway itself delivered; caching that clients or providers brought on their own appears only in the caching tile's Total figure."
|
||||
/>
|
||||
<SummaryCard
|
||||
label="Compression savings"
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ describe("KeySavingsTab", () => {
|
|||
|
||||
renderTab();
|
||||
|
||||
expect(screen.getByTestId("summary-card-total-saved")).toHaveTextContent("$6.00");
|
||||
expect(screen.getByTestId("summary-card-total-saved")).toHaveTextContent("$5.40");
|
||||
expect(screen.getByTestId("summary-card-compression-savings")).toHaveTextContent("$2.00");
|
||||
expect(screen.getByTestId("summary-card-compression-savings")).toHaveTextContent("1,000 tokens compressed");
|
||||
// the card leads with what LiteLLM's own injection earned and carries the total beneath it,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue