Skip to content

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} />
  • UsageSummary is the total of the period with its calls and sessions, and a legend row per CLI.
  • UsageChart stacks a bar per slot by CLI, every slot of the period, an empty one included. format writes the values; labelEvery says which slots get a label.
  • UsageTiles are the tokens processed, uncached and cached input, cache writes, output, and what the cache saved.
  • UsageBreakdown cuts 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.

Licenses and third-party notices are listed in each package.