import { Button, Popover, PopoverPopup, PopoverPortal, PopoverPositioner, PopoverTrigger, } from "@ace/ui"; import type { Usage as Totals } from "@ace/channel/protocol"; const compact = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 }); const exact = new Intl.NumberFormat("en-US"); const dollars = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", minimumFractionDigits: 2, maximumFractionDigits: 4, }); function cost(value: number): string { return value > 0 && value < 0.0001 ? "<$0.0001" : dollars.format(value); } /** A ring for how full the context window is, like other coding agents show. */ function Ring({ fraction }: { fraction: number }) { const radius = 6; const length = 2 * Math.PI * radius; return ( 0.9 ? "stroke-destructive" : fraction > 0.7 ? "stroke-amber-500" : "stroke-muted-foreground"} /> ); } export function Usage({ value, context }: { value: Totals; context?: { used: number; window: number }; }) { const fraction = context ? context.used / context.window : 0; const percent = Math.round(fraction * 100); const rows = [ ["Input", value.input], ["Output", value.output], ["Cache read", value.cacheRead], ["Cache write", value.cacheWrite], ] as const; return ( } >

Context

{context ? `${percent}% ยท ${compact.format(context.used)} of ${ compact.format(context.window) } tokens` : "No responses yet"}

Billed in this chat

{rows.map(([label, count]) => (
{label}
{exact.format(count)}
))}
Estimated cost (USD)
{cost(value.cost)}

Token counts are what each provider reported. Every request re-sends the conversation, mostly as cache reads, so billed tokens grow faster than the context. Cost uses list prices.

); }