import type { UsageProviderKind } from "@t3tools/contracts";import { CheckIcon, RefreshCwIcon, XIcon } from "lucide-react";import { useMemo, useState } from "react"; import type { DailyTotals, HourlyTotals } from "@t3tools/shared/usageMerge"; import { isElectron } from "../../env";import { cn } from "../../lib/utils";import { useUsage, type EnvironmentUsageStatus } from "../../state/usage";import { enumerateDays, enumerateHourStarts, formatCount, formatDateTimeShort, formatDayShort, formatHourShort, formatPercent, formatTokens, formatUsd, makeWindow,} from "@t3tools/shared/usageFormat";import { ScrollArea } from "../ui/scroll-area";import { Button } from "../ui/button";import { SidebarInset } from "../ui/sidebar";import { WorkspaceBreadcrumb, WorkspaceBreadcrumbItem } from "../WorkspaceBreadcrumb";import { COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS } from "../../workspaceTitlebar";import { UsageChartLegend, UsageProviderChart, type UsageChartMetric } from "./UsageProviderChart";import { PROVIDER_ORDER, PROVIDER_PRESENTATION } from "./usageProviders"; const WINDOW_OPTIONS = [ { days: 1, label: "Past 24h" }, { days: 7, label: "7 days" }, { days: 30, label: "30 days" }, { days: 90, label: "90 days" },] as const; export function UsagePage() { const [windowSelection, setWindowSelection] = useState(() => ({ days: 30, window: makeWindow(30), })); const [metric, setMetric] = useState<UsageChartMetric>("cost"); const [breakdown, setBreakdown] = useState<"model" | "time">("model"); const { days: windowDays, window } = windowSelection; const isPast24Hours = windowDays === 1; const { merged, environments, isPending, isPartial, refresh } = useUsage(window); // Hold the content until every environment is terminal. Rendering merged // totals while devices are still answering makes every number on the page // jump as each one lands. const settling = isPending || isPartial; const days = useMemo( () => enumerateDays(window.sinceDay, window.untilDay), [window.sinceDay, window.untilDay], ); const hours = useMemo( () => window.sinceTime === undefined || window.untilTime === undefined ? [] : enumerateHourStarts(window.sinceTime, window.untilTime), [window.sinceTime, window.untilTime], ); // Newest first: the window can run 90 periods, so the interesting end // belongs at the top of the table. const breakdownPeriods = useMemo<readonly (DailyTotals | HourlyTotals)[]>( () => (isPast24Hours ? merged.hourly : merged.daily).toReversed(), [isPast24Hours, merged.daily, merged.hourly], ); // Ranked by whatever the toggle is showing, so the bars always descend. const orderedProviders = useMemo( () => merged.providers.toSorted((a, b) => metric === "cost" ? b.costUsd - a.costUsd : b.totalTokens - a.totalTokens, ), [merged.providers, metric], ); const activePeriods = (isPast24Hours ? merged.hourly : merged.daily).filter( (period) => period.totalTokens > 0, ).length; const periodAverage = activePeriods === 0 ? 0 : merged.totalTokens / activePeriods; const observedInput = merged.uncachedInputTokens + merged.cachedInputTokens; const cachedShare = observedInput === 0 ? 0 : merged.cachedInputTokens / observedInput; const selectWindow = (days: number) => { setWindowSelection({ days, window: makeWindow(days, undefined, days === 1 ? "hour" : "day"), }); }; const refreshWindow = () => { const nextWindow = makeWindow(windowDays, undefined, isPast24Hours ? "hour" : "day"); if ( nextWindow.sinceDay === window.sinceDay && nextWindow.untilDay === window.untilDay && nextWindow.sinceTime === window.sinceTime && nextWindow.untilTime === window.untilTime ) { refresh(); } else { setWindowSelection({ days: windowDays, window: nextWindow }); } }; return ( <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground isolate"> <div className="flex min-h-0 min-w-0 flex-1 flex-col bg-background text-foreground"> {!isElectron && ( <header className={cn( "flex h-[var(--workspace-topbar-height)] min-h-[var(--workspace-topbar-height)] shrink-0 items-center px-3 transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none sm:px-5", COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS, )} > <WorkspaceBreadcrumb ariaLabel="Usage breadcrumb"> <WorkspaceBreadcrumbItem current>Usage</WorkspaceBreadcrumbItem> </WorkspaceBreadcrumb> </header> )} {isElectron && ( <div className={cn( "drag-region flex h-[52px] shrink-0 items-center px-5 transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none wco:h-[env(titlebar-area-height)] wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]", COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS, )} > <WorkspaceBreadcrumb ariaLabel="Usage breadcrumb"> <WorkspaceBreadcrumbItem current>Usage</WorkspaceBreadcrumbItem> </WorkspaceBreadcrumb> </div> )} <ScrollArea className="min-h-0 flex-1"> <div className="mx-auto flex w-full max-w-6xl flex-col gap-8 px-6 py-6"> <div className="flex flex-wrap items-center justify-between gap-4"> <p className="text-sm text-muted-foreground"> {isPast24Hours && window.sinceTime !== undefined && window.untilTime !== undefined ? `${formatDateTimeShort(window.sinceTime, window.timeZone)} to ${formatDateTimeShort(window.untilTime, window.timeZone)}` : `${formatDayShort(window.sinceDay)} to ${formatDayShort(window.untilDay)}`} </p> <div className="flex items-center gap-2"> <div className="flex rounded-md border border-border"> {WINDOW_OPTIONS.map((option) => ( <button key={option.days} type="button" aria-pressed={option.days === windowDays} onClick={() => selectWindow(option.days)} className={cn( "relative cursor-pointer px-3 py-1.5 text-xs outline-none first:rounded-s-[calc(var(--radius-md)-1px)] last:rounded-e-[calc(var(--radius-md)-1px)] focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", option.days === windowDays ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground", )} > {option.label} </button> ))} </div> <Button size="icon" variant="outline" onClick={refreshWindow} aria-label="Refresh usage" > <RefreshCwIcon className="size-3.5" /> </Button> </div> </div> {settling ? ( <> {environments.length > 1 ? <UsageDeviceStrip environments={environments} /> : null} <UsageSkeleton resolution={isPast24Hours ? "hour" : "day"} /> </> ) : ( <> <UsageCoverageNotice environments={environments} duplicateSources={merged.duplicateSources} staleEnvironments={merged.staleEnvironments} /> {/* Cost first: the financial answer, then the provider split. */} <section className="grid gap-6 lg:grid-cols-[minmax(0,20rem)_minmax(0,1fr)]"> {/* The summary follows the chart toggle, so the headline and the series are always reading the same units. */} <div className="flex flex-col gap-5"> <div className="flex flex-col gap-1"> <span className="text-xs tracking-wide text-muted-foreground uppercase"> {metric === "cost" ? "Raw token cost" : "Processed tokens"} </span> <span className="text-4xl font-semibold text-foreground tabular-nums"> {metric === "cost" ? `${formatUsd(merged.costUsd)}*` : formatTokens(merged.totalTokens)} </span> <span className="text-xs text-muted-foreground"> {metric === "cost" ? "* if billed at full API rate" : `Input, cache reads and output across ${formatCount(merged.sessions)} sessions.`} </span> </div> {orderedProviders.map((provider) => { const share = metric === "cost" ? provider.costShare : provider.tokenShare; return ( <div key={provider.provider} className="flex flex-col gap-1.5"> <div className="flex items-baseline justify-between"> <span className="flex items-center gap-2 text-sm text-foreground"> <ProviderMark provider={provider.provider} className="size-4" /> {PROVIDER_PRESENTATION[provider.provider].label} </span> <span className="text-sm text-foreground tabular-nums"> {metric === "cost" ? formatUsd(provider.costUsd) : formatTokens(provider.totalTokens)} </span> </div> <div className="h-1 w-full overflow-hidden rounded-full bg-muted"> <div className="h-full" style={{ width: `${(share * 100).toFixed(1)}%`, backgroundColor: PROVIDER_PRESENTATION[provider.provider].color, }} /> </div> <span className="text-xs text-muted-foreground"> {metric === "cost" ? `${formatPercent(share)} of cost · ${formatTokens(provider.totalTokens)} tokens` : `${formatPercent(share)} of tokens · ${formatUsd(provider.costUsd)}`} </span> </div> ); })} </div> <div className="flex flex-col gap-3"> <div className="flex flex-wrap items-center justify-between gap-3"> <h2 className="text-sm font-medium text-foreground"> {isPast24Hours ? "Hourly" : "Daily"}{" "} {metric === "tokens" ? "processed tokens" : "cost"} </h2> <div className="flex items-center gap-4"> <div className="flex overflow-hidden rounded-md border border-border"> {(["cost", "tokens"] as const).map((option) => ( <button key={option} type="button" onClick={() => setMetric(option)} className={cn( "cursor-pointer px-2.5 py-1 text-[10px] tracking-wide uppercase", option === metric ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground", )} > {option} </button> ))} </div> <UsageChartLegend /> </div> </div> <UsageProviderChart days={days} daily={merged.daily} hours={hours} hourly={merged.hourly} metric={metric} referenceTime={window.untilTime} resolution={isPast24Hours ? "hour" : "day"} timeZone={window.timeZone} /> </div> </section> <section className="grid grid-cols-2 gap-px border-y border-border bg-border md:grid-cols-5"> <Metric label="Processed tokens" value={formatTokens(merged.totalTokens)} detail={`${formatTokens(periodAverage)} per active ${isPast24Hours ? "hour" : "day"}`} /> <Metric label="Cached input" value={formatTokens(merged.cachedInputTokens)} detail={`${formatPercent(cachedShare)} of observed input`} /> <Metric label="Uncached input" value={formatTokens(merged.uncachedInputTokens)} detail={`${formatTokens(merged.cacheCreationTokens)} cache writes`} /> <Metric label="Output" value={formatTokens(merged.outputTokens)} detail={`includes ${formatTokens(merged.reasoningTokens)} reasoning`} /> <Metric label="Cache savings" value={formatUsd(merged.costQuality.cacheSavingsUsd)} detail={ merged.costUsd > 0 ? `${(merged.costQuality.cacheSavingsUsd / merged.costUsd).toFixed(1)}x the raw token cost` : "vs full input rates" } /> </section> <section className="flex flex-col gap-3"> <div className="flex items-center justify-between gap-3"> <h2 className="text-sm font-medium text-foreground">Breakdown</h2> <div className="flex overflow-hidden rounded-md border border-border"> {( [ { value: "model", label: "model" }, { value: "time", label: isPast24Hours ? "hour" : "day" }, ] as const ).map((option) => ( <button key={option.value} type="button" onClick={() => setBreakdown(option.value)} className={cn( "cursor-pointer px-2.5 py-1 text-[10px] tracking-wide uppercase", option.value === breakdown ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground", )} > {option.label} </button> ))} </div> </div> {breakdown === "model" ? ( <table className="w-full text-sm"> <thead> <tr className="border-b border-border text-left text-xs text-muted-foreground"> <th className="py-2 font-normal">Model</th> <th className="py-2 text-right font-normal">Cost</th> <th className="py-2 text-right font-normal">Share</th> <th className="py-2 text-right font-normal">Tokens</th> </tr> </thead> <tbody> {merged.models.length === 0 ? ( <tr> <td colSpan={4} className="py-6 text-center text-muted-foreground"> No activity in this window. </td> </tr> ) : ( merged.models.map((model) => ( <tr key={`${model.provider}:${model.model}`} className="border-b border-border/50" > <td className="py-2 text-foreground"> <span className="flex items-center gap-2"> <ProviderMark provider={model.provider} className="size-3.5" /> {model.model} </span> </td> <td className="py-2 text-right text-foreground tabular-nums"> {formatUsd(model.costUsd)} </td> <td className="py-2 text-right text-muted-foreground tabular-nums"> {formatPercent(model.costShare)} </td> <td className="py-2 text-right text-muted-foreground tabular-nums"> {formatTokens(model.totalTokens)} </td> </tr> )) )} </tbody> </table> ) : ( <table className="w-full text-sm"> <thead> <tr className="border-b border-border text-left text-xs text-muted-foreground"> <th className="py-2 font-normal">{isPast24Hours ? "Hour" : "Day"}</th> {PROVIDER_ORDER.map((provider) => ( <th key={provider} className="py-2 text-right font-normal"> {PROVIDER_PRESENTATION[provider].label} </th> ))} <th className="py-2 text-right font-normal">Total</th> <th className="py-2 text-right font-normal">Tokens</th> </tr> </thead> <tbody> {breakdownPeriods.length === 0 ? ( <tr> <td colSpan={5} className="py-6 text-center text-muted-foreground"> No activity in this window. </td> </tr> ) : ( breakdownPeriods.map((period) => ( <tr key={"hourStart" in period ? period.hourStart : period.day} className="border-b border-border/50" > <td className="py-2 text-foreground"> {"hourStart" in period ? formatHourShort(period.hourStart, window.timeZone) : formatDayShort(period.day)} </td> {PROVIDER_ORDER.map((provider) => ( <td key={provider} className="py-2 text-right text-muted-foreground tabular-nums" > {formatUsd(period.byProvider.get(provider)?.costUsd ?? 0)} </td> ))} <td className="py-2 text-right text-foreground tabular-nums"> {formatUsd(period.costUsd)} </td> <td className="py-2 text-right text-muted-foreground tabular-nums"> {formatTokens(period.totalTokens)} </td> </tr> )) )} </tbody> </table> )} </section> </> )} </div> </ScrollArea> </div> </SidebarInset> );} /** Brand mark for the harness a row belongs to. */function ProviderMark({ provider, className,}: { readonly provider: UsageProviderKind; readonly className: string;}) { const Mark = PROVIDER_PRESENTATION[provider].mark; return <Mark className={cn("shrink-0", className)} aria-hidden />;} function Metric({ label, value, detail,}: { readonly label: string; readonly value: string; readonly detail: string;}) { return ( <div className="flex flex-col gap-0.5 bg-background px-4 py-3"> <span className="text-xs text-muted-foreground">{label}</span> <span className="text-lg text-foreground tabular-nums">{value}</span> <span className="text-xs text-muted-foreground">{detail}</span> </div> );} /** * Says plainly when the totals are incomplete: an environment that failed, or * one whose transcripts another environment already reported. Environments * that are still answering never reach this notice; the page shows the * loading skeleton until every one is terminal. */function UsageCoverageNotice({ environments, duplicateSources, staleEnvironments,}: { readonly environments: readonly EnvironmentUsageStatus[]; readonly duplicateSources: readonly string[]; readonly staleEnvironments: readonly string[];}) { const failed = environments.filter((environment) => environment.error !== null); const stale = environments.filter((environment) => staleEnvironments.includes(environment.environmentId), ); if (failed.length === 0 && stale.length === 0 && duplicateSources.length === 0) { return null; } return ( <div className="flex flex-col gap-1 border border-border px-3 py-2 text-xs text-muted-foreground"> {failed.map((environment) => (Lines 1–500 of 641. Load more
import type { UsageProviderKind } from "@t3tools/contracts"; import { CheckIcon, RefreshCwIcon, XIcon } from "lucide-react"; import { useMemo, useState } from "react"; import type { DailyTotals, HourlyTotals } from "@t3tools/shared/usageMerge"; import { isElectron } from "../../env"; import { cn } from "../../lib/utils"; import { useUsage, type EnvironmentUsageStatus } from "../../state/usage"; import { enumerateDays, enumerateHourStarts, formatCount, formatDateTimeShort, formatDayShort, formatHourShort, formatPercent, formatTokens, formatUsd, makeWindow, } from "@t3tools/shared/usageFormat"; import { ScrollArea } from "../ui/scroll-area"; import { Button } from "../ui/button"; import { SidebarInset } from "../ui/sidebar"; import { WorkspaceBreadcrumb, WorkspaceBreadcrumbItem } from "../WorkspaceBreadcrumb"; import { COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS } from "../../workspaceTitlebar"; import { UsageChartLegend, UsageProviderChart, type UsageChartMetric } from "./UsageProviderChart"; import { PROVIDER_ORDER, PROVIDER_PRESENTATION } from "./usageProviders"; const WINDOW_OPTIONS = [ { days: 1, label: "Past 24h" }, { days: 7, label: "7 days" }, { days: 30, label: "30 days" }, { days: 90, label: "90 days" }, ] as const; export function UsagePage() { const [windowSelection, setWindowSelection] = useState(() => ({ days: 30, window: makeWindow(30), })); const [metric, setMetric] = useState<UsageChartMetric>("cost"); const [breakdown, setBreakdown] = useState<"model" | "time">("model"); const { days: windowDays, window } = windowSelection; const isPast24Hours = windowDays === 1; const { merged, environments, isPending, isPartial, refresh } = useUsage(window); // Hold the content until every environment is terminal. Rendering merged // totals while devices are still answering makes every number on the page // jump as each one lands. const settling = isPending || isPartial; const days = useMemo( () => enumerateDays(window.sinceDay, window.untilDay), [window.sinceDay, window.untilDay], ); const hours = useMemo( () => window.sinceTime === undefined || window.untilTime === undefined ? [] : enumerateHourStarts(window.sinceTime, window.untilTime), [window.sinceTime, window.untilTime], ); // Newest first: the window can run 90 periods, so the interesting end // belongs at the top of the table. const breakdownPeriods = useMemo<readonly (DailyTotals | HourlyTotals)[]>( () => (isPast24Hours ? merged.hourly : merged.daily).toReversed(), [isPast24Hours, merged.daily, merged.hourly], ); // Ranked by whatever the toggle is showing, so the bars always descend. const orderedProviders = useMemo( () => merged.providers.toSorted((a, b) => metric === "cost" ? b.costUsd - a.costUsd : b.totalTokens - a.totalTokens, ), [merged.providers, metric], ); const activePeriods = (isPast24Hours ? merged.hourly : merged.daily).filter( (period) => period.totalTokens > 0, ).length; const periodAverage = activePeriods === 0 ? 0 : merged.totalTokens / activePeriods; const observedInput = merged.uncachedInputTokens + merged.cachedInputTokens; const cachedShare = observedInput === 0 ? 0 : merged.cachedInputTokens / observedInput; const selectWindow = (days: number) => { setWindowSelection({ days, window: makeWindow(days, undefined, days === 1 ? "hour" : "day"), }); }; const refreshWindow = () => { const nextWindow = makeWindow(windowDays, undefined, isPast24Hours ? "hour" : "day"); if ( nextWindow.sinceDay === window.sinceDay && nextWindow.untilDay === window.untilDay && nextWindow.sinceTime === window.sinceTime && nextWindow.untilTime === window.untilTime ) { refresh(); } else { setWindowSelection({ days: windowDays, window: nextWindow }); } }; return ( <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground isolate"> <div className="flex min-h-0 min-w-0 flex-1 flex-col bg-background text-foreground"> {!isElectron && ( <header className={cn( "flex h-[var(--workspace-topbar-height)] min-h-[var(--workspace-topbar-height)] shrink-0 items-center px-3 transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none sm:px-5", COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS, )} > <WorkspaceBreadcrumb ariaLabel="Usage breadcrumb"> <WorkspaceBreadcrumbItem current>Usage</WorkspaceBreadcrumbItem> </WorkspaceBreadcrumb> </header> )} {isElectron && ( <div className={cn( "drag-region flex h-[52px] shrink-0 items-center px-5 transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none wco:h-[env(titlebar-area-height)] wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]", COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS, )} > <WorkspaceBreadcrumb ariaLabel="Usage breadcrumb"> <WorkspaceBreadcrumbItem current>Usage</WorkspaceBreadcrumbItem> </WorkspaceBreadcrumb> </div> )} <ScrollArea className="min-h-0 flex-1"> <div className="mx-auto flex w-full max-w-6xl flex-col gap-8 px-6 py-6"> <div className="flex flex-wrap items-center justify-between gap-4"> <p className="text-sm text-muted-foreground"> {isPast24Hours && window.sinceTime !== undefined && window.untilTime !== undefined ? `${formatDateTimeShort(window.sinceTime, window.timeZone)} to ${formatDateTimeShort(window.untilTime, window.timeZone)}` : `${formatDayShort(window.sinceDay)} to ${formatDayShort(window.untilDay)}`} </p> <div className="flex items-center gap-2"> <div className="flex rounded-md border border-border"> {WINDOW_OPTIONS.map((option) => ( <button key={option.days} type="button" aria-pressed={option.days === windowDays} onClick={() => selectWindow(option.days)} className={cn( "relative cursor-pointer px-3 py-1.5 text-xs outline-none first:rounded-s-[calc(var(--radius-md)-1px)] last:rounded-e-[calc(var(--radius-md)-1px)] focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", option.days === windowDays ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground", )} > {option.label} </button> ))} </div> <Button size="icon" variant="outline" onClick={refreshWindow} aria-label="Refresh usage" > <RefreshCwIcon className="size-3.5" /> </Button> </div> </div> {settling ? ( <> {environments.length > 1 ? <UsageDeviceStrip environments={environments} /> : null} <UsageSkeleton resolution={isPast24Hours ? "hour" : "day"} /> </> ) : ( <> <UsageCoverageNotice environments={environments} duplicateSources={merged.duplicateSources} staleEnvironments={merged.staleEnvironments} /> {/* Cost first: the financial answer, then the provider split. */} <section className="grid gap-6 lg:grid-cols-[minmax(0,20rem)_minmax(0,1fr)]"> {/* The summary follows the chart toggle, so the headline and the series are always reading the same units. */} <div className="flex flex-col gap-5"> <div className="flex flex-col gap-1"> <span className="text-xs tracking-wide text-muted-foreground uppercase"> {metric === "cost" ? "Raw token cost" : "Processed tokens"} </span> <span className="text-4xl font-semibold text-foreground tabular-nums"> {metric === "cost" ? `${formatUsd(merged.costUsd)}*` : formatTokens(merged.totalTokens)} </span> <span className="text-xs text-muted-foreground"> {metric === "cost" ? "* if billed at full API rate" : `Input, cache reads and output across ${formatCount(merged.sessions)} sessions.`} </span> </div> {orderedProviders.map((provider) => { const share = metric === "cost" ? provider.costShare : provider.tokenShare; return ( <div key={provider.provider} className="flex flex-col gap-1.5"> <div className="flex items-baseline justify-between"> <span className="flex items-center gap-2 text-sm text-foreground"> <ProviderMark provider={provider.provider} className="size-4" /> {PROVIDER_PRESENTATION[provider.provider].label} </span> <span className="text-sm text-foreground tabular-nums"> {metric === "cost" ? formatUsd(provider.costUsd) : formatTokens(provider.totalTokens)} </span> </div> <div className="h-1 w-full overflow-hidden rounded-full bg-muted"> <div className="h-full" style={{ width: `${(share * 100).toFixed(1)}%`, backgroundColor: PROVIDER_PRESENTATION[provider.provider].color, }} /> </div> <span className="text-xs text-muted-foreground"> {metric === "cost" ? `${formatPercent(share)} of cost · ${formatTokens(provider.totalTokens)} tokens` : `${formatPercent(share)} of tokens · ${formatUsd(provider.costUsd)}`} </span> </div> ); })} </div> <div className="flex flex-col gap-3"> <div className="flex flex-wrap items-center justify-between gap-3"> <h2 className="text-sm font-medium text-foreground"> {isPast24Hours ? "Hourly" : "Daily"}{" "} {metric === "tokens" ? "processed tokens" : "cost"} </h2> <div className="flex items-center gap-4"> <div className="flex overflow-hidden rounded-md border border-border"> {(["cost", "tokens"] as const).map((option) => ( <button key={option} type="button" onClick={() => setMetric(option)} className={cn( "cursor-pointer px-2.5 py-1 text-[10px] tracking-wide uppercase", option === metric ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground", )} > {option} </button> ))} </div> <UsageChartLegend /> </div> </div> <UsageProviderChart days={days} daily={merged.daily} hours={hours} hourly={merged.hourly} metric={metric} referenceTime={window.untilTime} resolution={isPast24Hours ? "hour" : "day"} timeZone={window.timeZone} /> </div> </section> <section className="grid grid-cols-2 gap-px border-y border-border bg-border md:grid-cols-5"> <Metric label="Processed tokens" value={formatTokens(merged.totalTokens)} detail={`${formatTokens(periodAverage)} per active ${isPast24Hours ? "hour" : "day"}`} /> <Metric label="Cached input" value={formatTokens(merged.cachedInputTokens)} detail={`${formatPercent(cachedShare)} of observed input`} /> <Metric label="Uncached input" value={formatTokens(merged.uncachedInputTokens)} detail={`${formatTokens(merged.cacheCreationTokens)} cache writes`} /> <Metric label="Output" value={formatTokens(merged.outputTokens)} detail={`includes ${formatTokens(merged.reasoningTokens)} reasoning`} /> <Metric label="Cache savings" value={formatUsd(merged.costQuality.cacheSavingsUsd)} detail={ merged.costUsd > 0 ? `${(merged.costQuality.cacheSavingsUsd / merged.costUsd).toFixed(1)}x the raw token cost` : "vs full input rates" } /> </section> <section className="flex flex-col gap-3"> <div className="flex items-center justify-between gap-3"> <h2 className="text-sm font-medium text-foreground">Breakdown</h2> <div className="flex overflow-hidden rounded-md border border-border"> {( [ { value: "model", label: "model" }, { value: "time", label: isPast24Hours ? "hour" : "day" }, ] as const ).map((option) => ( <button key={option.value} type="button" onClick={() => setBreakdown(option.value)} className={cn( "cursor-pointer px-2.5 py-1 text-[10px] tracking-wide uppercase", option.value === breakdown ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground", )} > {option.label} </button> ))} </div> </div> {breakdown === "model" ? ( <table className="w-full text-sm"> <thead> <tr className="border-b border-border text-left text-xs text-muted-foreground"> <th className="py-2 font-normal">Model</th> <th className="py-2 text-right font-normal">Cost</th> <th className="py-2 text-right font-normal">Share</th> <th className="py-2 text-right font-normal">Tokens</th> </tr> </thead> <tbody> {merged.models.length === 0 ? ( <tr> <td colSpan={4} className="py-6 text-center text-muted-foreground"> No activity in this window. </td> </tr> ) : ( merged.models.map((model) => ( <tr key={`${model.provider}:${model.model}`} className="border-b border-border/50" > <td className="py-2 text-foreground"> <span className="flex items-center gap-2"> <ProviderMark provider={model.provider} className="size-3.5" /> {model.model} </span> </td> <td className="py-2 text-right text-foreground tabular-nums"> {formatUsd(model.costUsd)} </td> <td className="py-2 text-right text-muted-foreground tabular-nums"> {formatPercent(model.costShare)} </td> <td className="py-2 text-right text-muted-foreground tabular-nums"> {formatTokens(model.totalTokens)} </td> </tr> )) )} </tbody> </table> ) : ( <table className="w-full text-sm"> <thead> <tr className="border-b border-border text-left text-xs text-muted-foreground"> <th className="py-2 font-normal">{isPast24Hours ? "Hour" : "Day"}</th> {PROVIDER_ORDER.map((provider) => ( <th key={provider} className="py-2 text-right font-normal"> {PROVIDER_PRESENTATION[provider].label} </th> ))} <th className="py-2 text-right font-normal">Total</th> <th className="py-2 text-right font-normal">Tokens</th> </tr> </thead> <tbody> {breakdownPeriods.length === 0 ? ( <tr> <td colSpan={5} className="py-6 text-center text-muted-foreground"> No activity in this window. </td> </tr> ) : ( breakdownPeriods.map((period) => ( <tr key={"hourStart" in period ? period.hourStart : period.day} className="border-b border-border/50" > <td className="py-2 text-foreground"> {"hourStart" in period ? formatHourShort(period.hourStart, window.timeZone) : formatDayShort(period.day)} </td> {PROVIDER_ORDER.map((provider) => ( <td key={provider} className="py-2 text-right text-muted-foreground tabular-nums" > {formatUsd(period.byProvider.get(provider)?.costUsd ?? 0)} </td> ))} <td className="py-2 text-right text-foreground tabular-nums"> {formatUsd(period.costUsd)} </td> <td className="py-2 text-right text-muted-foreground tabular-nums"> {formatTokens(period.totalTokens)} </td> </tr> )) )} </tbody> </table> )} </section> </> )} </div> </ScrollArea> </div> </SidebarInset> ); } /** Brand mark for the harness a row belongs to. */ function ProviderMark({ provider, className, }: { readonly provider: UsageProviderKind; readonly className: string; }) { const Mark = PROVIDER_PRESENTATION[provider].mark; return <Mark className={cn("shrink-0", className)} aria-hidden />; } function Metric({ label, value, detail, }: { readonly label: string; readonly value: string; readonly detail: string; }) { return ( <div className="flex flex-col gap-0.5 bg-background px-4 py-3"> <span className="text-xs text-muted-foreground">{label}</span> <span className="text-lg text-foreground tabular-nums">{value}</span> <span className="text-xs text-muted-foreground">{detail}</span> </div> ); } /** * Says plainly when the totals are incomplete: an environment that failed, or * one whose transcripts another environment already reported. Environments * that are still answering never reach this notice; the page shows the * loading skeleton until every one is terminal. */ function UsageCoverageNotice({ environments, duplicateSources, staleEnvironments, }: { readonly environments: readonly EnvironmentUsageStatus[]; readonly duplicateSources: readonly string[]; readonly staleEnvironments: readonly string[]; }) { const failed = environments.filter((environment) => environment.error !== null); const stale = environments.filter((environment) => staleEnvironments.includes(environment.environmentId), ); if (failed.length === 0 && stale.length === 0 && duplicateSources.length === 0) { return null; } return ( <div className="flex flex-col gap-1 border border-border px-3 py-2 text-xs text-muted-foreground"> {failed.map((environment) => (