fix: refine token usage reporting (#807)

This commit is contained in:
Haile
2026-05-30 11:09:27 +03:00
committed by GitHub
parent 86948097aa
commit 38bf21ddf5
15 changed files with 549 additions and 272 deletions

View File

@@ -6,7 +6,6 @@ import {
CircleHelp,
Clipboard,
Coins,
Command as CommandIcon,
Cpu,
Gauge,
Package,
@@ -17,7 +16,6 @@ import {
Timer,
RefreshCw,
X,
Zap,
} from 'lucide-react';
import { Badge, Button, Dialog, DialogContent, DialogTitle, Input } from '../../../../shared/view/ui';
@@ -84,7 +82,7 @@ const PROVIDER_LABELS: Record<string, string> = {
const FALLBACK_COMMANDS: CommandEntry[] = [
{ name: '/models', description: 'Browse available models for the active provider.' },
{ name: '/cost', description: 'Review context usage and estimated token spend.' },
{ name: '/cost', description: 'Review token usage for the active session.' },
{ name: '/status', description: 'Inspect runtime, version, provider, and environment status.' },
{ name: '/memory', description: 'Open the project CLAUDE.md memory file.' },
{ name: '/config', description: 'Open settings and configuration.' },
@@ -99,13 +97,6 @@ const getProviderLabel = (provider: string | undefined, fallback = 'Unknown') =>
return PROVIDER_LABELS[provider] || provider;
};
const clampPercentage = (value: number) => {
if (!Number.isFinite(value)) {
return 0;
}
return Math.max(0, Math.min(100, value));
};
const formatNumber = (value: number) => {
if (!Number.isFinite(value)) {
return '0';
@@ -113,11 +104,6 @@ const formatNumber = (value: number) => {
return value.toLocaleString();
};
const formatCurrency = (value: number | string | undefined) => {
const numeric = Number(value ?? 0);
return `$${Number.isFinite(numeric) ? numeric.toFixed(4) : '0.0000'}`;
};
function MetricCard({
label,
value,
@@ -507,62 +493,71 @@ function ModelsContent({
function CostContent({ data }: { data: CostCommandData }) {
const used = Number(data.tokenUsage?.used ?? 0);
const total = Number(data.tokenUsage?.total ?? 0);
const percentage = clampPercentage(Number(data.tokenUsage?.percentage ?? 0));
const model = data.model || 'Unknown';
const provider = getProviderLabel(data.provider, data.provider || 'Unknown');
const inputTokens = Number(data.tokenBreakdown?.input ?? 0);
const outputTokens = Number(data.tokenBreakdown?.output ?? 0);
const cacheTokens = Number(data.tokenBreakdown?.cache ?? 0);
const totalCost = Number(data.cost?.total ?? 0);
const hasBreakdown =
typeof data.tokenBreakdown?.input === 'number' ||
typeof data.tokenBreakdown?.output === 'number';
const usageRows = [
{ label: 'Total tokens used', value: formatNumber(used), icon: Activity },
...(hasBreakdown
? [
{
label: 'Input tokens',
value: formatNumber(Number(data.tokenBreakdown?.input ?? 0)),
icon: TerminalSquare,
},
{
label: 'Output tokens',
value: formatNumber(Number(data.tokenBreakdown?.output ?? 0)),
icon: Coins,
},
]
: [
{
label: 'Breakdown',
value: 'Unavailable',
icon: TerminalSquare,
},
]),
...(total > 0
? [{ label: 'Context window', value: formatNumber(total), icon: Gauge }]
: []),
];
return (
<div className="grid gap-4 lg:grid-cols-[18rem_1fr]">
<div className="rounded-3xl border border-primary/25 bg-primary/10 p-5 text-center">
<div
className="mx-auto grid h-40 w-40 place-items-center rounded-full p-2 shadow-inner"
style={{
background: `conic-gradient(hsl(var(--primary)) ${percentage * 3.6}deg, hsl(var(--muted)) 0deg)`,
}}
>
<div className="grid h-full w-full place-items-center rounded-full border border-border/70 bg-popover">
<div>
<p className="font-mono text-3xl font-semibold text-foreground">{percentage.toFixed(1)}%</p>
<p className="mt-1 text-xs uppercase tracking-[0.18em] text-muted-foreground">context</p>
<div className="space-y-4">
<div className="overflow-hidden rounded-2xl border border-border/70 bg-background/75">
{usageRows.map((row) => {
const Icon = row.icon;
return (
<div
key={row.label}
className="flex items-center justify-between gap-4 border-b border-border/60 px-4 py-3 last:border-b-0"
>
<div className="flex min-w-0 items-center gap-3">
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-xl border border-primary/20 bg-primary/10 text-primary">
<Icon className="h-4 w-4" />
</span>
<span className="truncate text-sm font-medium text-foreground">{row.label}</span>
</div>
<span className="shrink-0 font-mono text-sm font-semibold text-foreground">{row.value}</span>
</div>
</div>
</div>
<p className="mt-4 text-sm text-muted-foreground">
{formatNumber(used)} of {formatNumber(total)} tokens used
</p>
);
})}
</div>
<div className="space-y-3">
<div className="grid gap-3 sm:grid-cols-3">
<MetricCard label="Input" value={formatCurrency(data.cost?.input)} icon={Zap} />
<MetricCard label="Output" value={formatCurrency(data.cost?.output)} icon={Activity} />
<MetricCard label="Total" value={formatCurrency(totalCost)} icon={Coins} tone="primary" />
</div>
<div className="grid gap-3 sm:grid-cols-3">
<MetricCard label="Input tokens" value={formatNumber(inputTokens)} icon={CommandIcon} />
<MetricCard label="Output tokens" value={formatNumber(outputTokens)} icon={TerminalSquare} />
<MetricCard label="Cache tokens" value={formatNumber(cacheTokens)} icon={Package} />
</div>
<div className="rounded-2xl border border-border/70 bg-muted/20 p-4">
<div className="grid gap-3 sm:grid-cols-2">
<div>
<p className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">Provider</p>
<p className="mt-1 text-sm font-semibold text-foreground">{provider}</p>
</div>
<div>
<p className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">Model</p>
<p className="mt-1 break-all font-mono text-sm text-foreground">{model}</p>
</div>
<div className="rounded-2xl border border-border/70 bg-muted/20 p-4">
<div className="grid gap-3 sm:grid-cols-2">
<div>
<p className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">Provider</p>
<p className="mt-1 text-sm font-semibold text-foreground">{provider}</p>
</div>
<div>
<p className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">Model</p>
<p className="mt-1 break-all font-mono text-sm text-foreground">{model}</p>
</div>
<p className="mt-3 text-xs leading-5 text-muted-foreground">
Cost is an estimate based on the available token counters and default provider rates.
</p>
</div>
</div>
</div>
@@ -636,8 +631,8 @@ export default function CommandResultModal({
},
cost: {
eyebrow: 'Session telemetry',
title: 'Usage & Cost',
subtitle: 'Token budget, context pressure, and estimated spend for this session.',
title: 'Token Usage',
subtitle: 'Input, output, and total token counts for this session.',
icon: Coins,
},
status: {