Charts and tiles
The parts of the usage page, each drawn from a summary the app already has. Fold a summary first with deriveUsage(summary, metric).
tsx
import { deriveUsage, labelEveryFor } from '@adecore/agents-react/usage/summary';tsx
import { useState } from 'react';
import { Segmented } from '@adecore/ui';
import { formatTokens } from '@adecore/ui/format';
import { windowFor, type UsageMetric } from '@adecore/agents-react/state/usage';
import { useMoney } from '@adecore/agents-react/usage/money';
import { deriveUsage, labelEveryFor } from '@adecore/agents-react/usage/summary';
import { UsageBreakdown } from '@adecore/agents-react/usage/UsageBreakdown';
import { UsageChart } from '@adecore/agents-react/usage/UsageChart';
import { UsageSummary } from '@adecore/agents-react/usage/UsageSummary';
import { UsageTiles } from '@adecore/agents-react/usage/UsageTiles';
import { usageSummary } from '../shared/agents-data.ts';
import { AgentDemo } from '../shared/agents.tsx';
const summary = usageSummary(windowFor('30d'));
function Parts() {
const [metric, setMetric] = useState<UsageMetric>('cost');
const money = useMoney();
const derived = deriveUsage(summary, metric);
return (
<div className="flex w-full flex-col gap-6">
<Segmented<UsageMetric>
value={metric}
label="Metric"
options={[
{ id: 'cost', label: 'Cost' },
{ id: 'tokens', label: 'Tokens' }
]}
onValueChange={setMetric}
/>
<div className="grid gap-6 lg:grid-cols-[18rem_1fr]">
<UsageSummary metric={metric} costUsd={derived.costUsd} totals={derived.totals} sessions={summary.sessions} providers={derived.providers} />
<UsageChart
slots={derived.slots}
providers={derived.active}
format={metric === 'cost' ? money : formatTokens}
labelEvery={labelEveryFor(derived.slots.length)}
/>
</div>
<UsageTiles totals={derived.totals} cacheSavingsUsd={derived.cacheSavingsUsd} />
<UsageBreakdown summary={summary} metric={metric} providers={derived.active} />
</div>
);
}
export default function UsagePartsDemo() {
return (
<AgentDemo>
<Parts />
</AgentDemo>
);
}tsx
const derived = deriveUsage(summary, metric);
const money = useMoney();
<UsageSummary metric={metric} costUsd={derived.costUsd} totals={derived.totals} sessions={summary.sessions} providers={derived.providers} />
<UsageChart slots={derived.slots} providers={derived.active} format={metric === 'cost' ? money : formatTokens} labelEvery={labelEveryFor(derived.slots.length)} />
<UsageTiles totals={derived.totals} cacheSavingsUsd={derived.cacheSavingsUsd} />
<UsageBreakdown summary={summary} metric={metric} providers={derived.active} />UsageSummaryis the total of the period with its calls and sessions, and a legend row per CLI.UsageChartstacks a bar per slot by CLI, every slot of the period, an empty one included.formatwrites the values;labelEverysays which slots get a label.UsageTilesare the tokens processed, uncached and cached input, cache writes, output, and what the cache saved.UsageBreakdowncuts the period three ways behind tabs: by model, by folder and by day.
deriveUsage answers the slots of the chart, the totals per CLI (providers), the CLIs that did anything (active), and the period's totals, cost and cache savings. deriveDays(summary) is the table by day, newest first. enumerateSlots and niceScale are the axis.
Money and numbers
Every price is in dollars. useMoney() answers the formatter of the chosen currency at the rate the summary carries; moneyFormat(currency, rate) is the same outside React. formatCount, formatTokens, formatClock, formatDate, slotLabel, slotAxisLabel and shortPath write the rest. PROVIDER_LABELS and PROVIDER_COLORS name and color each CLI.