import { sendToAgentChat } from "@agent-native/core/client/agent-chat"; import { useActionQuery } from "@agent-native/core/client/hooks"; import { useT } from "@agent-native/core/client/i18n"; import { IconActivity, IconAlertTriangle, IconArrowUpRight, IconApps, IconChartBar, IconCoin, IconMessages, IconUsersGroup, } from "@tabler/icons-react"; import { useMemo, useState, type ReactNode } from "react"; import { Link, useSearchParams } from "react-router"; import { Area, AreaChart, CartesianGrid, Line, LineChart, XAxis, YAxis, } from "recharts"; import { DispatchShell } from "../../components/dispatch-shell"; import { Alert, AlertDescription, AlertTitle } from "../../components/ui/alert"; import { Badge } from "../../components/ui/badge"; import { Button } from "../../components/ui/button"; import { ChartContainer, ChartTooltip, ChartTooltipContent, } from "../../components/ui/chart"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "../../components/ui/select"; import { Skeleton } from "../../components/ui/skeleton"; import { Tabs, TabsContent, TabsList, TabsTrigger, } from "../../components/ui/tabs"; import { UsageAlertsPanel } from "../../components/usage-alerts-panel"; import { cn } from "../../lib/utils"; export function meta() { return [{ title: "Metrics — Dispatch" }]; } interface UsageMetricBucket { key: string; label: string; costCents: number; calls: number; chatCalls: number; inputTokens: number; outputTokens: number; activeUsers: number; lastActiveAt: number | null; } interface UserUsageMetric extends UsageMetricBucket { ownerEmail: string; chatThreads: number; chatMessages: number; lastChatAt: number | null; topApp: string | null; role: string | null; } interface AppAdoptionActionMetric { key: string; label: string; calls: number; activeUsers: number; lastActiveAt: number | null; } interface UsageUserOption { email: string; role: string | null; } interface AppAccessMetric { id: string; name: string; path: string; status?: "ready" | "pending"; statusLabel?: string; isDispatch: boolean; accessLabel: string; accessUsers: number; ownerEmail: string | null; isOwnedByViewer: boolean; canViewUsage: boolean; usersWithUsage: number; dailyActiveUsers: number; weeklyActiveUsers: number; usageCalls: number; chatCalls: number; costCents: number; lastActiveAt: number | null; actionMetrics: AppAdoptionActionMetric[]; } interface DailyUsageMetric { date: string; costCents: number; calls: number; chatCalls: number; activeUsers: number; dailyActiveUsers: number; weeklyActiveUsers: number | null; } interface RecentUsageMetric { id: number; createdAt: number; ownerEmail: string; app: string; label: string; model: string; inputTokens: number; outputTokens: number; costCents: number; prompt: string | null; promptSource: "thread" | "thread-preview" | "not-captured" | "unavailable"; threadId: string | null; runId: string | null; taskId: string | null; sourcePlatform: string | null; sourceId: string | null; } interface UsageBillingMode { unit: "usd" | "builder-credits"; label: string; shortLabel: string; source: "estimated-provider-cost" | "builder-agent-credits"; hardCostMarginMultiplier?: number; creditsPerUsd?: number; } interface DispatchUsageMetrics { billing?: UsageBillingMode; viewScope?: "me" | "workspace" | "app"; selectedUserEmail?: string | null; selectedAppId?: string | null; availableUsers?: UsageUserOption[]; sinceDays: number; access: { viewerEmail: string; orgId: string | null; role: string | null; scope: "organization" | "solo"; totalUsers: number; }; totals: { costCents: number; calls: number; chatCalls: number; inputTokens: number; outputTokens: number; cacheReadTokens: number; cacheWriteTokens: number; activeUsers: number; chatThreads: number; chatMessages: number; workspaceApps: number; }; byApp: UsageMetricBucket[]; byUser: UserUsageMetric[]; byLabel: UsageMetricBucket[]; byModel: UsageMetricBucket[]; daily: DailyUsageMetric[]; dailyAvailable: boolean; appAccess: AppAccessMetric[]; recent: RecentUsageMetric[]; } const RANGES = [7, 30, 90] as const; type MetricsView = "overview" | "adoption" | "details"; function selectedMetricsView(value: string | null): MetricsView { if (value === "adoption" || value === "details") return value; return "overview"; } const USD_BILLING: UsageBillingMode = { unit: "usd", label: "Estimated spend", shortLabel: "Cost", source: "estimated-provider-cost", }; function displayAmountFromCostCents( cents: number, billing: UsageBillingMode, ): number { if (billing.unit !== "builder-credits") return cents; const margin = billing.hardCostMarginMultiplier ?? 1.25; const creditsPerUsd = billing.creditsPerUsd ?? 20; const credits = (cents / 100) * margin * creditsPerUsd; return credits <= 0 ? 0 : Math.ceil(credits * 1000) / 1000; } function formatCredits(credits: number): string { if (!Number.isFinite(credits) || credits === 0) return "0 credits"; const maximumFractionDigits = credits < 1 ? 3 : credits < 10 ? 2 : 1; const value = credits.toLocaleString(undefined, { maximumFractionDigits, }); return `${value} ${credits === 1 ? "credit" : "credits"}`; } function formatSpend(cents: number, billing: UsageBillingMode): string { if (billing.unit === "builder-credits") { return formatCredits(displayAmountFromCostCents(cents, billing)); } if (!Number.isFinite(cents) || cents === 0) return "$0.00"; if (Math.abs(cents) < 1) return `${cents.toFixed(3)}¢`; if (Math.abs(cents) < 100) return `${cents.toFixed(2)}¢`; return (cents / 100).toLocaleString(undefined, { style: "currency", currency: "USD", maximumFractionDigits: 2, }); } function formatNumber(value: number | null | undefined): string { if (value == null || !Number.isFinite(value)) return "—"; return new Intl.NumberFormat(undefined, { notation: value >= 10_000 ? "compact" : "standard", maximumFractionDigits: value >= 10_000 ? 1 : 0, }).format(value); } function formatTokens(value: number): string { return new Intl.NumberFormat(undefined, { notation: "compact", maximumFractionDigits: 1, }).format(value); } function timeAgo(timestamp: number | null): string { if (!timestamp) return "No activity"; const diff = Date.now() - timestamp; if (diff < 60_000) return "just now"; if (diff < 3_600_000) return `${Math.floor(diff / 60_000)}m ago`; if (diff < 86_400_000) return `${Math.floor(diff / 3_600_000)}h ago`; return `${Math.floor(diff / 86_400_000)}d ago`; } function formatTrendDate(value: string): string { const date = new Date(`${value}T12:00:00`); return date.toLocaleDateString(undefined, { month: "short", day: "numeric", }); } function completeUsageTrendRows(rows: DailyUsageMetric[]): DailyUsageMetric[] { if (rows.length < 2) return rows; const byDate = new Map(rows.map((row) => [row.date, row])); const start = new Date(`${rows[0].date}T12:00:00`); const end = new Date(`${rows[rows.length - 1].date}T12:00:00`); const completed: DailyUsageMetric[] = []; for ( const cursor = start; cursor <= end; cursor.setDate(cursor.getDate() + 1) ) { const date = cursor.toISOString().slice(0, 10); completed.push( byDate.get(date) ?? { date, costCents: 0, calls: 0, chatCalls: 0, activeUsers: 0, dailyActiveUsers: 0, weeklyActiveUsers: 0, }, ); } return completed; } function UserActivityTrend({ rows }: { rows: DailyUsageMetric[] }) { const chartData = rows.map((row) => ({ ...row, dau: row.dailyActiveUsers, wau: row.weeklyActiveUsers, })); return ( } action={
DAU WAU
} > {chartData.length === 0 ? (
No active users in this window yet.
) : ( formatNumber(Number(value))} /> formatTrendDate(String(value))} formatter={(value, name) => [ `${formatNumber(Number(value))} users`, name === "dau" ? "DAU" : "WAU", ]} /> } /> )}
); } function displayApp(value: string | null | undefined): string { const trimmed = value?.trim(); if (!trimmed || trimmed === "unattributed") return "Unattributed"; return trimmed; } function maxSpend( rows: Array<{ costCents: number }>, billing: UsageBillingMode, ): number { return rows.reduce( (max, row) => Math.max(max, displayAmountFromCostCents(row.costCents, billing)), 0, ); } function barWidth(value: number, max: number): string { if (max <= 0 || value <= 0) return "0%"; return `${Math.max(4, Math.round((value / max) * 100))}%`; } function RangeSelector({ value, onChange, }: { value: number; onChange: (value: number) => void; }) { return (
{RANGES.map((range) => ( ))}
); } function MetricCard({ label, value, detail, icon, }: { label: string; value: string; detail: string; icon: ReactNode; }) { return (
{label} {icon}
{value}
{detail}
); } function Panel({ title, icon, children, action, }: { title: string; icon: ReactNode; children: ReactNode; action?: ReactNode; }) { return (
{icon}

{title}

{action}
{children}
); } function LoadingMetrics() { return (
{Array.from({ length: 5 }).map((_, index) => (
))}
); } function ScopeSelector({ value, onChange, }: { value: "me" | "workspace"; onChange: (value: "me" | "workspace") => void; }) { return (
{( [ ["me", "My usage"], ["workspace", "Workspace"], ] as const ).map(([scope, label]) => ( ))}
); } function UserSelector({ value, users, onChange, }: { value: string | null; users: UsageUserOption[]; onChange: (value: string | null) => void; }) { return ( ); } function UsageTrend({ rows, billing, }: { rows: DailyUsageMetric[]; billing: UsageBillingMode; }) { const chartData = completeUsageTrendRows(rows).map((row) => ({ ...row, spend: displayAmountFromCostCents(row.costCents, billing), })); return ( } action={
{billing.shortLabel} Calls
} > {chartData.length === 0 ? (
No usage in this window yet.
) : ( billing.unit === "builder-credits" ? formatCredits(Number(value)) : formatSpend(Number(value), billing) } /> formatTrendDate(String(value))} formatter={(value, name) => [ name === "spend" ? billing.unit === "builder-credits" ? formatCredits(Number(value)) : formatSpend(Number(value), billing) : `${formatNumber(Number(value))} calls`, name === "spend" ? billing.shortLabel : "Calls", ]} /> } /> )}
); } function ReviewUsageButton({ metrics, billing, }: { metrics: DispatchUsageMetrics; billing: UsageBillingMode; }) { function reviewUsage() { const topApps = metrics.byApp .slice(0, 5) .map( (row) => `${displayApp(row.key)}: ${formatSpend(row.costCents, billing)} / ${row.calls} calls`, ) .join("; "); const topLabels = metrics.byLabel .slice(0, 5) .map( (row) => `${row.label}: ${formatSpend(row.costCents, billing)} / ${row.calls} calls`, ) .join("; "); const recentPrompts = metrics.recent .slice(0, 8) .map((row) => { const prompt = row.prompt ? row.prompt.slice(0, 180) : "prompt not captured"; return `${timeAgo(row.createdAt)} | ${displayApp(row.app)} | ${row.label} | ${prompt}`; }) .join("\n"); sendToAgentChat({ message: "Review this LLM usage and explain where the spend is going. Identify repeated, background, or unexpectedly expensive work, cite the strongest evidence, and suggest concrete fixes. Call out missing attribution instead of guessing.", context: [ `Dispatch usage scope: ${metrics.viewScope === "workspace" ? "workspace" : "my account"}.`, `Lookback: ${metrics.sinceDays} days. Viewer: ${metrics.access.viewerEmail}.`, `Total: ${formatSpend(metrics.totals.costCents, billing)}, ${metrics.totals.calls} calls, ${metrics.totals.chatCalls} chat calls, ${formatTokens(metrics.totals.inputTokens + metrics.totals.outputTokens)} input/output tokens.`, `Top apps: ${topApps || "none"}.`, `Top work types: ${topLabels || "none"}.`, `Recent prompt evidence (bounded to the latest 8 rows):\n${recentPrompts || "none"}`, ].join("\n"), submit: true, openSidebar: true, chatTarget: "local", }); } return ( ); } function AppSpendRows({ rows, billing, }: { rows: UsageMetricBucket[]; billing: UsageBillingMode; }) { const max = maxSpend(rows, billing); if (rows.length === 0) { return (
No LLM usage recorded for this window.
); } return (
{rows.map((row) => (
{displayApp(row.key)}
{formatNumber(row.chatCalls)} chats ·{" "} {formatNumber(row.activeUsers)} users
{formatSpend(row.costCents, billing)}
{formatNumber(row.calls)} calls
))}
); } function AppAdoptionPanel({ rows, selectedAppId, scope, backScope, }: { rows: AppAccessMetric[]; selectedAppId: string | null; scope: "me" | "workspace" | "app"; backScope: "me" | "workspace"; }) { const t = useT(); const visibleRows = rows .filter((row) => !row.isDispatch) .sort( (a, b) => b.usageCalls - a.usageCalls || b.usersWithUsage - a.usersWithUsage || (b.lastActiveAt ?? 0) - (a.lastActiveAt ?? 0) || a.name.localeCompare(b.name), ); const [showAll, setShowAll] = useState(false); const selectedRow = selectedAppId ? visibleRows.find((row) => row.id === selectedAppId) : null; const isDetail = !!selectedRow; const actionMetrics = selectedRow?.actionMetrics ?? []; const rowsToRender = showAll ? visibleRows : visibleRows.slice(0, 9); const detailStats = [ [t("dispatch.pages.dailyActiveUsers"), selectedRow?.dailyActiveUsers], [t("dispatch.pages.weeklyActiveUsers"), selectedRow?.weeklyActiveUsers], [t("dispatch.pages.trackedActions"), selectedRow?.usageCalls], ] satisfies Array<[string, number | null | undefined]>; const title = isDetail ? t("dispatch.pages.appAdoptionFor", { name: selectedRow.name }) : scope === "workspace" ? t("dispatch.pages.appAdoption") : t("dispatch.pages.yourAppActivity"); const backHref = backScope === "workspace" ? "/admin/metrics?scope=workspace&view=adoption" : "/admin/metrics?view=adoption"; if (visibleRows.length === 0) { return ( }>
{t("dispatch.pages.noWorkspaceApps")}
); } return ( } action={ isDetail ? ( {t("allApps")} ) : ( {t("dispatch.pages.appAdoptionDefinition")} ) } > {isDetail ? (
{selectedRow.name}
{selectedRow.path}
{selectedRow.ownerEmail ? selectedRow.isOwnedByViewer ? t("dispatch.pages.appMetadataOwner") : selectedRow.ownerEmail : t("dispatch.pages.ownerUnavailable")}
{detailStats.map(([label, value]) => (
{label}
{formatNumber(value)}
))}
{t("dispatch.pages.trackedActionBreakdown")}
{actionMetrics.length === 0 ? (
{t("dispatch.pages.noTrackedActions")}
) : (
{actionMetrics.slice(0, 10).map((action) => (
{action.label} {formatNumber(action.calls)}{" "} {t("dispatch.pages.trackedActions")} ·{" "} {formatNumber(action.activeUsers)}{" "} {t("dispatch.pages.activeUsers")}
))}
)}
) : ( <>
{rowsToRender.map((row) => (
{row.name}
{row.path}
{row.isOwnedByViewer ? ( {t("dispatch.pages.appMetadataOwner")} ) : null}
{t("dispatch.pages.dailyActiveUsers")}
{formatNumber(row.dailyActiveUsers)}
{t("dispatch.pages.weeklyActiveUsers")}
{formatNumber(row.weeklyActiveUsers)}
{formatNumber(row.usageCalls)}{" "} {t("dispatch.pages.trackedActions")}
{row.canViewUsage ? ( {t("dispatch.pages.viewAppMetrics")} ) : null}
))}
{visibleRows.length > 9 ? (
) : null} )}
); } function AppAccessTable({ rows, billing, }: { rows: AppAccessMetric[]; billing: UsageBillingMode; }) { const visibleRows = rows.filter((row) => !row.isDispatch); if (visibleRows.length === 0) { return (
No workspace apps discovered yet.
); } return (
{visibleRows.map((row) => ( ))}
App Access Users Chats {billing.shortLabel} Last activity
{row.name}
{row.path}
{row.status === "pending" ? row.statusLabel || "Builder branch" : row.accessLabel} {formatNumber(row.usersWithUsage)} /{" "} {formatNumber(row.accessUsers)} {formatNumber(row.chatCalls)} {formatSpend(row.costCents, billing)} {timeAgo(row.lastActiveAt)}
); } function UserTable({ rows, billing, }: { rows: UserUsageMetric[]; billing: UsageBillingMode; }) { if (rows.length === 0) { return (
No users have triggered LLM usage in this window.
); } return (
{rows.slice(0, 12).map((row) => ( ))}
User Role Top app Chats Threads Tokens {billing.shortLabel}
{row.ownerEmail}
{timeAgo(row.lastActiveAt ?? row.lastChatAt)}
{row.role ?? "user"} {displayApp(row.topApp)} {formatNumber(row.chatCalls)} {formatNumber(row.chatThreads)} {formatTokens(row.inputTokens + row.outputTokens)} {formatSpend(row.costCents, billing)}
); } function CompactBreakdown({ rows, empty, billing, }: { rows: UsageMetricBucket[]; empty: string; billing: UsageBillingMode; }) { const max = maxSpend(rows, billing); if (rows.length === 0) { return
{empty}
; } return (
{rows.slice(0, 6).map((row) => (
{row.label} {formatSpend(row.costCents, billing)}
))}
); } export default function MetricsRoute() { const t = useT(); const [sinceDays, setSinceDays] = useState(30); const [searchParams, setSearchParams] = useSearchParams(); const view = selectedMetricsView(searchParams.get("view")); const appId = searchParams.get("app") || null; const backScope: "me" | "workspace" = searchParams.get("scope") === "workspace" ? "workspace" : "me"; const scope: "me" | "workspace" | "app" = appId ? "app" : searchParams.get("scope") === "workspace" ? "workspace" : "me"; const userEmail = scope === "workspace" ? searchParams.get("user") || null : null; function setScope(nextScope: "me" | "workspace") { const next = new URLSearchParams(searchParams); next.delete("app"); if (nextScope === "me") next.delete("scope"); else next.set("scope", nextScope); if (nextScope === "me") next.delete("user"); setSearchParams(next, { replace: true }); } function setUserEmail(nextUserEmail: string | null) { const next = new URLSearchParams(searchParams); if (nextUserEmail) next.set("user", nextUserEmail); else next.delete("user"); setSearchParams(next, { replace: true }); } function setView(nextView: MetricsView) { const next = new URLSearchParams(searchParams); if (nextView === "overview") next.delete("view"); else next.set("view", nextView); setSearchParams(next, { replace: true }); } const { data, isLoading, error } = useActionQuery( "list-dispatch-usage-metrics", { sinceDays, scope, userEmail: userEmail ?? undefined, appId: appId ?? undefined, }, ); const metrics = data as DispatchUsageMetrics | undefined; const selectedAppName = metrics?.selectedAppId ? metrics.appAccess.find((row) => row.id === metrics.selectedAppId)?.name : null; const billing = metrics?.billing ?? USD_BILLING; const totalTokens = useMemo(() => { if (!metrics) return 0; return ( metrics.totals.inputTokens + metrics.totals.outputTokens + metrics.totals.cacheReadTokens + metrics.totals.cacheWriteTokens ); }, [metrics]); return (
{scope === "app" ? t("dispatch.pages.appAdoption") : metrics?.selectedUserEmail ? `${metrics.selectedUserEmail}'s usage` : scope === "workspace" ? "Workspace usage" : "Your usage"}
{scope === "app" ? selectedAppName || t("dispatch.pages.workspaceAppFallback") : metrics?.selectedUserEmail ? "Filtered to this workspace member" : scope === "workspace" ? `${metrics?.access.totalUsers ?? 0} users with access` : metrics?.access.viewerEmail || "Signed-in account"}
{appId ? ( {t("allApps")} ) : ( )} {scope === "workspace" && metrics ? ( ) : null}
{error ? ( {t("dispatch.pages.metricsUnavailable")} {error instanceof Error ? error.message : t("dispatch.pages.unableToLoadUsage")} ) : null} {isLoading && !metrics ? : null} {metrics ? ( { if ( value === "overview" || value === "adoption" || value === "details" ) { setView(value); } }} className="flex min-w-0 flex-col gap-5" > {t("dispatch.nav.overview")} {t("dispatch.pages.appAdoption")} {t("details")} {metrics.dailyAvailable === false ? ( {t("dispatch.pages.metricsUnavailable")} {t("dispatch.pages.unableToLoadUsage")} ) : null}
Review this usage with the agent
{scope !== "app" ? ( row.key && row.key !== "unattributed") .map((row) => ({ id: row.key, label: displayApp(row.key), }))} /> ) : null}
} /> } /> } /> } /> } />
} > }> {scope !== "app" ? ( }> ) : null}
}> }>
) : null}
); }