72 / 122 · Observability
Cost meter
What the run spent, split by model, against the session total.
$2.76this run$18.40 session
Opus 548.2k in · 12.4k out$1.66
Sonnet 592.8k in · 21.1k out$0.86
Haiku 4.5140.0k in · 8.9k out$0.24
Installation
npx shadcn@latest add "@assistant-ui/elements-cost-meter"
Usage
import { CostMeter } from "@/components/elements/cost-meter";
<CostMeter runCost="$2.76" sessionCost="$18.40" lines={lines} />Props
CostMeter
runCost*stringPre-formatted cost of this run.
sessionCost*stringPre-formatted cumulative cost.
lines*CostLine[]Per-model breakdown, ordered largest first so the bar reads left to right.
classNamestringExtra classes merged onto the root.
CostLine
model*stringModel this line accounts for.
inputTokens*numberInput tokens consumed. The element divides by 1000 for display.
outputTokens*numberOutput tokens produced.
share*numberFraction of the run's cost, 0 to 1. Drives the stacked bar.
cost*stringPre-formatted. The element never does currency math.
Source
cost-meter.tsx"use client";
import { cn } from "@/lib/utils";
import { mono, paper } from "./surfaces";
export interface CostLine {
model: string;
inputTokens: number;
outputTokens: number;
cost: string;
share: number;
}
export function CostMeter({
runCost,
sessionCost,
lines,
className,
}: {
runCost: string;
sessionCost: string;
lines: readonly CostLine[];
className?: string;
}) {
return (
<div
className={cn(
paper,
"flex w-full max-w-sm flex-col gap-3 rounded-2xl p-4",
className,
)}
>
<div className="flex items-baseline gap-2">
<span className="text-2xl font-medium tracking-tight tabular-nums">
{runCost}
</span>
<span className={cn(mono, "text-foreground/30")}>this run</span>
<span className={cn(mono, "text-foreground/35 ms-auto tabular-nums")}>
{sessionCost} session
</span>
</div>
<div className="bg-foreground/[0.06] flex h-1.5 w-full overflow-hidden rounded-full">
{lines.map((line, i) => (
<span
key={line.model}
className={cn(
"h-full transition-[width] duration-500 motion-reduce:transition-none",
i === 0
? "bg-blue-500 dark:bg-blue-400"
: i === 1
? "bg-blue-500/55 dark:bg-blue-400/55"
: "bg-foreground/25",
)}
style={{ width: `${line.share * 100}%` }}
/>
))}
</div>
<div className="flex flex-col gap-1.5">
{lines.map((line) => (
<div key={line.model} className="flex items-baseline gap-2">
<span className="text-foreground/75 min-w-0 flex-1 truncate text-[13px]">
{line.model}
</span>
<span
className={cn(mono, "text-foreground/25 shrink-0 tabular-nums")}
>
{(line.inputTokens / 1000).toFixed(1)}k in ·{" "}
{(line.outputTokens / 1000).toFixed(1)}k out
</span>
<span
className={cn(mono, "text-foreground/55 shrink-0 tabular-nums")}
>
{line.cost}
</span>
</div>
))}
</div>
</div>
);
}