From 2a5a9fd7202dfafc25ed2173b7faaba0ffdf000e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 28 May 2026 15:13:22 -0400 Subject: [PATCH] fix: parse usage query numbers strictly --- ui/src/ui/usage-helpers.node.test.ts | 15 +++++++++++++++ ui/src/ui/usage-helpers.ts | 10 +++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/ui/src/ui/usage-helpers.node.test.ts b/ui/src/ui/usage-helpers.node.test.ts index 86166707e7d..d8bf1748812 100644 --- a/ui/src/ui/usage-helpers.node.test.ts +++ b/ui/src/ui/usage-helpers.node.test.ts @@ -33,6 +33,21 @@ describe("usage-helpers", () => { expect(filterSessionsByQuery([a, b], "maxTokens:10").sessions).toEqual([b]); }); + it("rejects non-decimal numeric filter values", () => { + const session = { key: "a", usage: { totalTokens: 10_000, totalCost: 0 } }; + + expect(filterSessionsByQuery([session], "minTokens:1k").sessions).toEqual([session]); + expect(filterSessionsByQuery([session], "minTokens:1e3").warnings).toEqual([ + "Invalid number for minTokens", + ]); + expect(filterSessionsByQuery([session], "minTokens:0x1000").warnings).toEqual([ + "Invalid number for minTokens", + ]); + expect(filterSessionsByQuery([session], "minTokens:9007199254740993").warnings).toEqual([ + "Invalid number for minTokens", + ]); + }); + it("warns on unknown keys and invalid numbers", () => { const session = { key: "a", usage: { totalTokens: 10, totalCost: 0 } }; const res = filterSessionsByQuery([session], "wat:1 minTokens:wat"); diff --git a/ui/src/ui/usage-helpers.ts b/ui/src/ui/usage-helpers.ts index 400898ed9e4..f0821e99029 100644 --- a/ui/src/ui/usage-helpers.ts +++ b/ui/src/ui/usage-helpers.ts @@ -77,11 +77,15 @@ const parseQueryNumber = (value: string): number | null => { multiplier = 1_000_000; raw = raw.slice(0, -1); } - const parsed = Number(raw); - if (!Number.isFinite(parsed)) { + if (!/^\d+(?:\.\d+)?$/.test(raw)) { return null; } - return parsed * multiplier; + const parsed = Number(raw); + const normalized = parsed * multiplier; + if (!Number.isFinite(normalized) || !Number.isSafeInteger(Math.round(normalized))) { + return null; + } + return normalized; }; export const extractQueryTerms = (query: string): UsageQueryTerm[] => {