From 3fbcdbc3dc68f6c246b764834974a999d7f0f4e8 Mon Sep 17 00:00:00 2001 From: zerone0x Date: Fri, 8 May 2026 04:39:53 +0800 Subject: [PATCH] fix(quota): stop showing misleading OpenRouter percentages (#1127) * fix(quota): stop showing misleading OpenRouter percentages Fixes #1085 * fix(quota): clean up OpenRouter credit labels --------- Co-authored-by: Bohdan Triapitsyn --- packages/ui/src/components/layout/Header.tsx | 14 +++++++++----- packages/ui/src/components/layout/VSCodeLayout.tsx | 5 +++-- .../ui/src/components/sections/usage/UsageCard.tsx | 4 ++-- packages/ui/src/lib/quota/index.ts | 1 + packages/ui/src/lib/quota/utils.ts | 7 +++++++ packages/vscode/src/quotaProviders.ts | 10 +++++----- .../web/server/lib/quota/providers/openrouter.js | 10 +++++----- 7 files changed, 32 insertions(+), 19 deletions(-) diff --git a/packages/ui/src/components/layout/Header.tsx b/packages/ui/src/components/layout/Header.tsx index 73d3a444..c15badc2 100644 --- a/packages/ui/src/components/layout/Header.tsx +++ b/packages/ui/src/components/layout/Header.tsx @@ -39,7 +39,7 @@ import { cn, hasModifier } from '@/lib/utils'; import { McpDropdownContent } from '@/components/mcp/McpDropdown'; import { McpIcon } from '@/components/icons/McpIcon'; import { ProviderLogo } from '@/components/ui/ProviderLogo'; -import { formatPercent, formatWindowLabel, QUOTA_PROVIDERS, calculatePace, calculateExpectedUsagePercent } from '@/lib/quota'; +import { formatQuotaValueLabel, formatWindowLabel, QUOTA_PROVIDERS, calculatePace, calculateExpectedUsagePercent } from '@/lib/quota'; import { UsageProgressBar } from '@/components/sections/usage/UsageProgressBar'; import { PaceIndicator } from '@/components/sections/usage/PaceIndicator'; import { updateDesktopSettings } from '@/lib/persistence'; @@ -446,6 +446,7 @@ const DesktopServicesMenu = React.memo(function DesktopServicesMenu({ ? 100 - calculateExpectedUsagePercent(paceInfo.elapsedRatio) : calculateExpectedUsagePercent(paceInfo.elapsedRatio)) : null; + const metricLabel = formatQuotaValueLabel(window.valueLabel, displayPercent); return (
@@ -458,7 +459,7 @@ const DesktopServicesMenu = React.memo(function DesktopServicesMenu({ ) : null}
- {formatPercent(displayPercent) === '-' ? '' : formatPercent(displayPercent)} + {metricLabel === '-' ? '' : metricLabel}
{getDisplayModelName(modelName)} - {formatPercent(displayPercent) === '-' ? '' : formatPercent(displayPercent)} + {metricLabel === '-' ? '' : metricLabel}
= ({ ? 100 - calculateExpectedUsagePercent(paceInfo.elapsedRatio) : calculateExpectedUsagePercent(paceInfo.elapsedRatio)) : null; + const metricLabel = formatQuotaValueLabel(window.valueLabel, displayPercent); return (
@@ -2206,7 +2209,7 @@ export const Header: React.FC = ({ ) : null}
- {formatPercent(displayPercent) === '-' ? '' : formatPercent(displayPercent)} + {metricLabel === '-' ? '' : metricLabel}
= ({ ? 100 - calculateExpectedUsagePercent(paceInfo.elapsedRatio) : calculateExpectedUsagePercent(paceInfo.elapsedRatio)) : null; + const metricLabel = formatQuotaValueLabel(window.valueLabel, displayPercent); return (
{getDisplayModelName(modelName)} - {formatPercent(displayPercent) === '-' ? '' : formatPercent(displayPercent)} + {metricLabel === '-' ? '' : metricLabel}
= ({ title, showBack, onBack, on ? 100 - calculateExpectedUsagePercent(paceInfo.elapsedRatio) : calculateExpectedUsagePercent(paceInfo.elapsedRatio)) : null; + const metricLabel = formatQuotaValueLabel(window.valueLabel, displayPercent); return ( = ({ title, showBack, onBack, on {formatWindowLabel(label)} - {formatPercent(displayPercent) === '-' ? '' : formatPercent(displayPercent)} + {metricLabel === '-' ? '' : metricLabel} = ({ const displayMode = useQuotaStore((state) => state.displayMode); const displayPercent = displayMode === 'remaining' ? window.remainingPercent : window.usedPercent; const barLabel = displayMode === 'remaining' ? 'remaining' : 'used'; - const percentLabel = window.valueLabel ?? formatPercent(displayPercent); + const percentLabel = formatQuotaValueLabel(window.valueLabel, displayPercent); const resetLabel = window.resetAfterFormatted ?? window.resetAtFormatted ?? ''; const windowLabel = formatWindowLabel(title); diff --git a/packages/ui/src/lib/quota/index.ts b/packages/ui/src/lib/quota/index.ts index 611121f1..82b37dd9 100644 --- a/packages/ui/src/lib/quota/index.ts +++ b/packages/ui/src/lib/quota/index.ts @@ -3,6 +3,7 @@ export type { QuotaProviderMeta } from './providers'; export { clampPercent, formatPercent, + formatQuotaValueLabel, resolveUsageTone, formatWindowLabel, calculatePace, diff --git a/packages/ui/src/lib/quota/utils.ts b/packages/ui/src/lib/quota/utils.ts index 484ad127..ad7dafd9 100644 --- a/packages/ui/src/lib/quota/utils.ts +++ b/packages/ui/src/lib/quota/utils.ts @@ -12,6 +12,13 @@ export const formatPercent = (value: number | null): string => { return `${Math.round(value)}%`; }; +export const formatQuotaValueLabel = ( + valueLabel: string | null | undefined, + percent: number | null, +): string => { + return valueLabel ?? formatPercent(percent); +}; + export const resolveUsageTone = (percent: number | null): 'safe' | 'warn' | 'critical' => { if (percent === null) { return 'safe'; diff --git a/packages/vscode/src/quotaProviders.ts b/packages/vscode/src/quotaProviders.ts index 86f144bd..81e730fd 100644 --- a/packages/vscode/src/quotaProviders.ts +++ b/packages/vscode/src/quotaProviders.ts @@ -1420,10 +1420,10 @@ export const fetchOpenRouterQuota = async (): Promise => { const remaining = totalCredits !== null && totalUsage !== null ? Math.max(0, totalCredits - totalUsage) : null; - const usedPercent = totalCredits && totalUsage !== null - ? Math.max(0, Math.min(100, (totalUsage / totalCredits) * 100)) - : null; - const valueLabel = remaining !== null ? `$${formatMoney(remaining)} remaining` : null; + let valueLabel: string | null = null; + if (remaining !== null && totalUsage !== null) { + valueLabel = `$${formatMoney(remaining)} left · $${formatMoney(totalUsage)} spent`; + } return buildResult({ providerId: 'openrouter', @@ -1433,7 +1433,7 @@ export const fetchOpenRouterQuota = async (): Promise => { usage: { windows: { credits: toUsageWindow({ - usedPercent, + usedPercent: null, windowSeconds: null, resetAt: null, valueLabel, diff --git a/packages/web/server/lib/quota/providers/openrouter.js b/packages/web/server/lib/quota/providers/openrouter.js index dc30655a..cd43770d 100644 --- a/packages/web/server/lib/quota/providers/openrouter.js +++ b/packages/web/server/lib/quota/providers/openrouter.js @@ -59,14 +59,14 @@ export const fetchQuota = async () => { const remaining = totalCredits !== null && totalUsage !== null ? Math.max(0, totalCredits - totalUsage) : null; - const usedPercent = totalCredits && totalUsage !== null - ? Math.max(0, Math.min(100, (totalUsage / totalCredits) * 100)) - : null; - const valueLabel = remaining !== null ? `$${formatMoney(remaining)} remaining` : null; + let valueLabel = null; + if (remaining !== null && totalUsage !== null) { + valueLabel = `$${formatMoney(remaining)} left · $${formatMoney(totalUsage)} spent`; + } const windows = { credits: toUsageWindow({ - usedPercent, + usedPercent: null, windowSeconds: null, resetAt: null, valueLabel