mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-20 00:11:50 +00:00
* feat(spend): track prompt compression saved tokens in daily spend aggregates Native compression interception now records tokens_before/after/saved into the request litellm_metadata so savings land in the SpendLog metadata JSON under a typed compression_savings key. A single normalizer (extract_compression_saved_tokens) sums that key with Headroom guardrail tokens_saved; the two writers are disjoint and run at different stages, so summing never double-counts. The spend-log redactor now preserves purely numeric compression stats inside guardrail_response so Headroom savings survive the store_prompts_in_spend_logs=false default. compression_saved_tokens is threaded through BaseDailySpendTransaction, queue aggregation, the daily upsert blocks, a new BigInt column on all six daily spend tables, and the daily activity read path (SpendMetrics, DailySpendMetadata, raw-SQL rollups) * fix(spend): normalize legacy guardrail shapes and float token stats in compression savings reader * feat(spend): aggregate compression and prompt caching dollar savings in daily rollups Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(spend): update daily spend aggregation fixtures for savings columns Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * feat(ui): add Cost Optimization dashboard page New left-nav Cost Optimization page under Observability that surfaces money saved by prompt compression and prompt caching. It reads the daily activity rollup (userDailyActivityCall / get_daily_activity) and never scans SpendLogs, so it stays fast at 1M+ rows. Renders a Total saved card, per-driver Compression and Prompt caching cards, a savings-over-time area chart, and a savings-by-driver donut, all aggregated in memory from the per-day metrics.compression_savings_spend and metrics.prompt_caching_savings_spend fields. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Krrish Dholakia <krrishdholakia@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
83 lines
3.1 KiB
TypeScript
83 lines
3.1 KiB
TypeScript
import { serverRootPath } from "@/components/networking";
|
|
|
|
/**
|
|
* Single source of truth for pages cut over from the legacy `?page=` switch in
|
|
* app/page.tsx to path-based routes under app/(dashboard)/.
|
|
*
|
|
* Key = legacy page id emitted by the sidebar. Value = route segment under (dashboard)/.
|
|
* Add an entry to route the sidebar and deep links to the new path and redirect the
|
|
* legacy `?page=` URL; remove it to roll back.
|
|
*/
|
|
export const MIGRATED_PAGES: Record<string, string> = {
|
|
"api-keys": "api-keys",
|
|
models: "models-and-endpoints",
|
|
api_ref: "api-reference",
|
|
// Legacy alias: older bookmarks used the hyphenated ?page=api-reference form.
|
|
"api-reference": "api-reference",
|
|
"llm-playground": "playground",
|
|
projects: "projects",
|
|
chat: "chat",
|
|
"access-groups": "access-groups",
|
|
budgets: "budgets",
|
|
workflows: "workflows",
|
|
"guardrails-monitor": "guardrails-monitor",
|
|
"mcp-servers": "mcp-servers",
|
|
"search-tools": "search-tools",
|
|
"tag-management": "tag-management",
|
|
"vector-stores": "vector-stores",
|
|
memory: "memory",
|
|
policies: "policies",
|
|
guardrails: "guardrails",
|
|
prompts: "prompts",
|
|
"tool-policies": "tool-policies",
|
|
skills: "skills",
|
|
// Legacy alias: the old switch matched ?page=claude-code-plugins for the same panel.
|
|
"claude-code-plugins": "skills",
|
|
caching: "caching",
|
|
"cost-tracking": "cost-tracking",
|
|
"transform-request": "transform-request",
|
|
"ui-theme": "ui-theme",
|
|
logs: "logs",
|
|
"admin-panel": "admin-panel",
|
|
"logging-and-alerts": "logging-and-alerts",
|
|
"model-hub-table": "model-hub-table",
|
|
// The modern usage dashboard; the legacy ?page=usage report routes to /old-usage.
|
|
new_usage: "usage",
|
|
usage: "old-usage",
|
|
"cost-optimization": "cost-optimization",
|
|
agents: "agents",
|
|
"router-settings": "router-settings",
|
|
users: "users",
|
|
teams: "teams",
|
|
organizations: "organizations",
|
|
};
|
|
|
|
function uiBase(): string {
|
|
// next dev serves the app at the root; only the proxy mounts the static export under /ui
|
|
// (and optionally under server_root_path). Inlined at build time, so production is unaffected.
|
|
if (process.env.NODE_ENV === "development") {
|
|
return "";
|
|
}
|
|
const root = serverRootPath && serverRootPath !== "/" ? `/${serverRootPath.replace(/^\/+|\/+$/g, "")}` : "";
|
|
return `${root}/ui`;
|
|
}
|
|
|
|
/** Absolute (same-origin) href for a migrated route segment, e.g. "api-reference" -> "/ui/api-reference". */
|
|
export function migratedHref(routeSegment: string): string {
|
|
return `${uiBase()}/${routeSegment.replace(/^\/+/, "")}`;
|
|
}
|
|
|
|
/** Href for a not-yet-migrated page, served by the legacy `?page=` switch at the UI root. */
|
|
export function legacyPageHref(pageKey: string): string {
|
|
return `${uiBase()}/?page=${pageKey}`;
|
|
}
|
|
|
|
/** Reverse-maps a path-routed location back to its legacy page id, e.g. "/ui/api-reference" -> "api_ref". */
|
|
export function legacyKeyForPathname(pathname: string): string | null {
|
|
const base = uiBase();
|
|
const rel = (pathname.startsWith(base) ? pathname.slice(base.length) : pathname).replace(/^\/+|\/+$/g, "");
|
|
for (const [key, segment] of Object.entries(MIGRATED_PAGES)) {
|
|
if (rel === segment) return key;
|
|
}
|
|
return null;
|
|
}
|