From d213ef030416b2e1e276c9f429496eb2c3ce82ce Mon Sep 17 00:00:00 2001 From: b3nw Date: Sun, 30 Aug 2026 07:13:39 -0500 Subject: [PATCH] feat(dashboard): show cache percentage in request logs (#11970) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mostra a % de cache nos logs de requisição, com teste próprio (`request-logger-cache-percentage.test.ts`). Validado no worktree combinado do lote. Pequeno ajuste feito por cima: `formatCachePercentage` movida de `RequestLoggerV2.tsx` para `src/shared/utils/formatting.ts`. `RequestLoggerV2.tsx` importa `RequestLoggerDetail`, que desde o #11703 (mergeado nesta mesma sessão) importa CSS bruto de `react18-json-view` — algo que o Node native test runner não consegue carregar. O teste original importava a função direto do componente e quebrava por causa dessa cadeia de import, não por bug na PR. Movida a função (pura, sem dependências) para o utils compartilhado; ajustado o import do componente e do teste. Typecheck limpo, teste passando (6/6). --- .../features/dashboard-cache-percentage.md | 1 + src/shared/components/RequestLoggerV2.tsx | 4 ++- src/shared/utils/formatting.ts | 10 ++++++ .../request-logger-cache-percentage.test.ts | 33 +++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 changelog.d/features/dashboard-cache-percentage.md create mode 100644 tests/unit/request-logger-cache-percentage.test.ts diff --git a/changelog.d/features/dashboard-cache-percentage.md b/changelog.d/features/dashboard-cache-percentage.md new file mode 100644 index 0000000000..784cc34f8e --- /dev/null +++ b/changelog.d/features/dashboard-cache-percentage.md @@ -0,0 +1 @@ +- **feat(dashboard):** display clamped `[0, 100]%` cached input token ratio in request logs table ([#PR_NUMBER](https://github.com/diegosouzapw/OmniRoute/pull/PR_NUMBER)) diff --git a/src/shared/components/RequestLoggerV2.tsx b/src/shared/components/RequestLoggerV2.tsx index 699bf1f36d..f9cd90a63b 100644 --- a/src/shared/components/RequestLoggerV2.tsx +++ b/src/shared/components/RequestLoggerV2.tsx @@ -25,6 +25,7 @@ import { maskAccount, stableAccountSuffix, formatApiKeyLabel, + formatCachePercentage, } from "@/shared/utils/formatting"; import { getProviderDisplayLabel } from "@/shared/utils/providerDisplayLabel"; import useEmailPrivacyStore from "@/store/emailPrivacyStore"; @@ -1572,7 +1573,8 @@ const RequestLoggerV2 = forwardRef - {log.tokens.cacheRead.toLocaleString()} + {log.tokens.cacheRead.toLocaleString()} ( + {formatCachePercentage(log.tokens.in, log.tokens.cacheRead)}%) )} diff --git a/src/shared/utils/formatting.ts b/src/shared/utils/formatting.ts index bb6091c4f2..7213ff99b8 100644 --- a/src/shared/utils/formatting.ts +++ b/src/shared/utils/formatting.ts @@ -216,3 +216,13 @@ export function formatErrorForDisplay(err: unknown): string | null { return String(err); } } + +/** Percentage of `tokensIn` served from cache, clamped to [0, 100]. */ +export function formatCachePercentage( + tokensIn: number | null | undefined, + cacheRead: number | null | undefined +): number { + if (!tokensIn || tokensIn <= 0) return 0; + if (!cacheRead || cacheRead <= 0) return 0; + return Math.min(100, Math.round((cacheRead / tokensIn) * 100)); +} diff --git a/tests/unit/request-logger-cache-percentage.test.ts b/tests/unit/request-logger-cache-percentage.test.ts new file mode 100644 index 0000000000..61467db1a0 --- /dev/null +++ b/tests/unit/request-logger-cache-percentage.test.ts @@ -0,0 +1,33 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { formatCachePercentage } from "../../src/shared/utils/formatting"; + +test("formatCachePercentage", async (t) => { + await t.test("returns 0 when tokensIn is 0, null, or undefined", () => { + assert.strictEqual(formatCachePercentage(0, 100), 0); + assert.strictEqual(formatCachePercentage(null, 100), 0); + assert.strictEqual(formatCachePercentage(undefined, 100), 0); + }); + + await t.test("returns 0 when cacheRead is 0, null, or undefined", () => { + assert.strictEqual(formatCachePercentage(100, 0), 0); + assert.strictEqual(formatCachePercentage(100, null), 0); + assert.strictEqual(formatCachePercentage(100, undefined), 0); + }); + + await t.test("returns 0 for negative values", () => { + assert.strictEqual(formatCachePercentage(-100, 50), 0); + assert.strictEqual(formatCachePercentage(100, -50), 0); + }); + + await t.test("calculates standard percentages correctly", () => { + assert.strictEqual(formatCachePercentage(100, 50), 50); + assert.strictEqual(formatCachePercentage(1000, 250), 25); + assert.strictEqual(formatCachePercentage(3, 1), 33); + }); + + await t.test("clamps percentage at 100 when cacheRead > tokensIn", () => { + assert.strictEqual(formatCachePercentage(100, 150), 100); + assert.strictEqual(formatCachePercentage(50, 1000), 100); + }); +});