import { FastResponseHistory } from "../components/fast-responses/FastResponseHistory"; import { DecisionHistory } from "../components/decision-models/DecisionHistory"; import { SubscriptionCostCard, SubscriptionTokenUsage } from "../components/SubscriptionCostCard"; import { subscriptionsApi } from "../api/subscriptions"; import { useSearchParams } from "@/lib/router"; import { CostEstimateLabel } from "../components/CostEstimateLabel"; import { CostAmount } from "../components/CostAmount"; import { CostByUserTable } from "../components/CostByUserTable"; import { CostDataQualityNotice } from "../components/CostDataQualityNotice"; import { AgentIdentity } from "@/components/AgentIdentity"; import { useEffect, useMemo, useRef, useState, type ComponentType, type ReactNode } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { BudgetPolicySummary, CostByAgentModel, CostByBiller, CostByProviderModel, CostWindowSpendRow, FinanceEvent, QuotaWindow, ProviderQuotaResult, } from "@paperclipai/shared"; import { ArrowDownLeft, ArrowUpRight, ChevronDown, ChevronRight, Coins, DollarSign, ReceiptText } from "lucide-react"; import { budgetsApi } from "../api/budgets"; import { costsApi } from "../api/costs"; import { agentsApi } from "../api/agents"; import { BillerSpendCard } from "../components/BillerSpendCard"; import { BudgetIncidentCard } from "../components/BudgetIncidentCard"; import { BudgetPolicyCard } from "../components/BudgetPolicyCard"; import { EmptyState } from "../components/EmptyState"; import { FinanceBillerCard } from "../components/FinanceBillerCard"; import { FinanceKindCard } from "../components/FinanceKindCard"; import { FinanceTimelineCard } from "../components/FinanceTimelineCard"; import { Identity } from "../components/Identity"; import { PageSkeleton } from "../components/PageSkeleton"; import { PageTabBar } from "../components/PageTabBar"; import { ProviderQuotaCard } from "../components/ProviderQuotaCard"; import { StatusBadge } from "../components/StatusBadge"; import { useBreadcrumbs } from "../context/BreadcrumbContext"; import { useCompany } from "../context/CompanyContext"; import { useDateRange, PRESET_KEYS, PRESET_LABELS } from "../hooks/useDateRange"; import { retainQuotaWindows } from "../lib/quota-refresh"; import { queryKeys } from "../lib/queryKeys"; import { billingTypeDisplayName, cn, formatCents, formatTokens, providerDisplayName } from "../lib/utils"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; const NO_COMPANY = "__none__"; export type CostsMainTab = "overview" | "budgets" | "providers" | "billers" | "finance" | "decisions" | "fast-responses"; export interface CostsProps { /** Render inside Audit without a second page-level title or breadcrumb. */ embedded?: boolean; initialTab?: CostsMainTab; /** Pin the surface to one tab (used by Audit > Budgets). */ lockTab?: boolean; /** Budgets is a peer Audit section, so omit it from the Costs sub-navigation. */ hideBudgetsTab?: boolean; } function currentWeekRange(): { from: string; to: string } { const now = new Date(); const day = now.getDay(); const diffToMon = day === 0 ? -6 : 1 - day; const mon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + diffToMon, 0, 0, 0, 0); const sun = new Date(mon.getFullYear(), mon.getMonth(), mon.getDate() + 6, 23, 59, 59, 999); return { from: mon.toISOString(), to: sun.toISOString() }; } function ProviderTabLabel({ provider, rows }: { provider: string; rows: CostByProviderModel[] }) { const totalTokens = rows.reduce((sum, row) => sum + row.inputTokens + row.cachedInputTokens + row.outputTokens, 0); const totalCost = rows.reduce((sum, row) => sum + row.costCents, 0); return ( {providerDisplayName(provider)} {formatTokens(totalTokens)} {formatCents(totalCost)} ); } function BillerTabLabel({ biller, rows }: { biller: string; rows: CostByBiller[] }) { const totalTokens = rows.reduce((sum, row) => sum + row.inputTokens + row.cachedInputTokens + row.outputTokens, 0); const totalCost = rows.reduce((sum, row) => sum + row.costCents, 0); return ( {providerDisplayName(biller)} {formatTokens(totalTokens)} {formatCents(totalCost)} ); } function MetricTile({ label, value, subtitle, icon: Icon, }: { label: string; value: string; subtitle: ReactNode; icon: ComponentType<{ className?: string }>; }) { return (
{label}
{value}
{subtitle}
); } function FinanceSummaryCard({ debitCents, creditCents, netCents, estimatedDebitCents, eventCount, }: { debitCents: number; creditCents: number; netCents: number; estimatedDebitCents: number; eventCount: number; }) { return ( Finance ledger Account-level charges that do not map to a single inference request. ); } export function Costs({ embedded = false, initialTab = "overview", lockTab = false, hideBudgetsTab = false, }: CostsProps = {}) { const { selectedCompanyId } = useCompany(); const { setBreadcrumbs } = useBreadcrumbs(); const queryClient = useQueryClient(); const [searchParams, setSearchParams] = useSearchParams(); const scopedAgentId = searchParams.get("agentId"); const { data: scopedAgent, error: scopedAgentError } = useQuery({ queryKey: [...queryKeys.agents.detail(scopedAgentId ?? NO_COMPANY), selectedCompanyId], queryFn: () => agentsApi.get(scopedAgentId!, selectedCompanyId!), enabled: Boolean(selectedCompanyId && scopedAgentId), }); const museUsageUnavailable = scopedAgent?.adapterType === "paperclip_runner" && scopedAgent.adapterConfig.provider === "muse"; const [mainTab, setMainTab] = useState(initialTab); const [activeProvider, setActiveProvider] = useState("all"); const [activeBiller, setActiveBiller] = useState("all"); const showSummaryChrome = !(embedded && lockTab && initialTab === "budgets"); const { preset, setPreset, customFrom, setCustomFrom, customTo, setCustomTo, from, to, customReady, } = useDateRange(); useEffect(() => { if (!embedded) setBreadcrumbs([{ label: "Costs" }]); }, [embedded, setBreadcrumbs]); useEffect(() => { const tab = searchParams.get("tab"); setMainTab(!lockTab && tab && ["overview", "providers", "billers", "finance", "budgets", "decisions", "fast-responses"].includes(tab) ? tab as CostsMainTab : initialTab); }, [initialTab, lockTab, searchParams]); const [today, setToday] = useState(() => new Date().toDateString()); const todayTimerRef = useRef | null>(null); useEffect(() => { const schedule = () => { const now = new Date(); const ms = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1).getTime() - now.getTime(); todayTimerRef.current = setTimeout(() => { setToday(new Date().toDateString()); schedule(); }, ms); }; schedule(); return () => { if (todayTimerRef.current != null) clearTimeout(todayTimerRef.current); }; }, []); const weekRange = useMemo(() => currentWeekRange(), [today]); const companyId = selectedCompanyId ?? NO_COMPANY; // The clock advances the request bounds, not the identity of the report. // Keep successful data visible during polling; a different company or selected // period still gets its own cache entry and initial loading state. // Month/year-to-date become a different reporting period at their UTC // boundary. Rolling windows retain identity as their lower bound advances. const reportQueryFrom = ["custom", "mtd", "ytd"].includes(preset) ? from || undefined : undefined; const reportQueryTo = preset === "custom" ? to || undefined : preset; const subscriptionKey = ["cost-subscriptions", companyId, reportQueryFrom, reportQueryTo]; const { data: subscriptions, error: subscriptionError } = useQuery({ queryKey: subscriptionKey, queryFn: () => subscriptionsApi.report(companyId, from || undefined, to || undefined), enabled: !!selectedCompanyId && customReady && showSummaryChrome, refetchInterval: 30_000, }); const invalidateSubscriptions = () => { void queryClient.invalidateQueries({ queryKey: ["cost-subscriptions", companyId] }); }; const discoveryCompany = useRef(null); const discoverSubscriptions = useMutation({ mutationFn: (id: string) => subscriptionsApi.refresh(id), onSuccess: (_data, id) => { void queryClient.invalidateQueries({ queryKey: ["cost-subscriptions", id] }); } }); useEffect(() => { if (!selectedCompanyId || !showSummaryChrome || !subscriptions?.canRefresh || discoveryCompany.current === selectedCompanyId) return; discoveryCompany.current = selectedCompanyId; discoverSubscriptions.mutate(selectedCompanyId); }, [selectedCompanyId, showSummaryChrome, subscriptions?.canRefresh, discoverSubscriptions.mutate]); const { data: budgetData, isLoading: budgetLoading, error: budgetError } = useQuery({ queryKey: queryKeys.budgets.overview(companyId), queryFn: () => budgetsApi.overview(companyId), enabled: !!selectedCompanyId && customReady, refetchInterval: 30_000, staleTime: 5_000, }); const invalidateBudgetViews = () => { if (!selectedCompanyId) return; queryClient.invalidateQueries({ queryKey: queryKeys.budgets.overview(selectedCompanyId) }); queryClient.invalidateQueries({ queryKey: queryKeys.dashboard(selectedCompanyId) }); queryClient.invalidateQueries({ queryKey: queryKeys.agents.list(selectedCompanyId) }); queryClient.invalidateQueries({ queryKey: queryKeys.projects.all(selectedCompanyId) }); }; const policyMutation = useMutation({ mutationFn: ({ summary, changes }: { summary: BudgetPolicySummary; changes: Partial>; }) => budgetsApi.upsertPolicy(companyId, { scopeType: summary.scopeType, scopeId: summary.scopeId, metric: summary.metric, windowKind: summary.windowKind, ...changes, }), onSuccess: invalidateBudgetViews, }); const incidentMutation = useMutation({ mutationFn: (input: { incidentId: string; action: "keep_paused" | "raise_budget_and_resume"; amount?: number }) => budgetsApi.resolveIncident(companyId, input.incidentId, input), onSuccess: invalidateBudgetViews, }); const { data: spendData, isLoading: spendLoading, error: spendError } = useQuery({ queryKey: queryKeys.costs(companyId, reportQueryFrom, reportQueryTo), queryFn: async () => { const [summary, byAgent, byProject, byAgentModel] = await Promise.all([ costsApi.summary(companyId, from || undefined, to || undefined), costsApi.byAgent(companyId, from || undefined, to || undefined), costsApi.byProject(companyId, from || undefined, to || undefined), costsApi.byAgentModel(companyId, from || undefined, to || undefined), ]); return { summary, byAgent, byProject, byAgentModel }; }, enabled: !!selectedCompanyId && customReady && showSummaryChrome, refetchInterval: 30_000, }); const { data: userSpendData, error: userSpendError } = useQuery({ queryKey: [...queryKeys.costs(companyId, reportQueryFrom, reportQueryTo), "by-user"], queryFn: () => costsApi.byUser(companyId, from || undefined, to || undefined), enabled: !!selectedCompanyId && customReady && showSummaryChrome && mainTab === "overview", refetchInterval: 30_000, }); const { data: financeData, isLoading: financeLoading, error: financeError } = useQuery({ queryKey: [ queryKeys.financeSummary(companyId, reportQueryFrom, reportQueryTo), queryKeys.financeByBiller(companyId, reportQueryFrom, reportQueryTo), queryKeys.financeByKind(companyId, reportQueryFrom, reportQueryTo), queryKeys.financeEvents(companyId, reportQueryFrom, reportQueryTo, 18), ], queryFn: async () => { const [summary, byBiller, byKind, events] = await Promise.all([ costsApi.financeSummary(companyId, from || undefined, to || undefined), costsApi.financeByBiller(companyId, from || undefined, to || undefined), costsApi.financeByKind(companyId, from || undefined, to || undefined), costsApi.financeEvents(companyId, from || undefined, to || undefined, 18), ]); return { summary, byBiller, byKind, events }; }, enabled: !!selectedCompanyId && customReady && showSummaryChrome, refetchInterval: 30_000, }); const [expandedAgents, setExpandedAgents] = useState>(new Set()); useEffect(() => { setExpandedAgents(new Set()); }, [companyId, preset, customFrom, customTo]); function toggleAgent(agentId: string | null) { setExpandedAgents((prev) => { const next = new Set(prev); if (next.has(agentId)) next.delete(agentId); else next.add(agentId); return next; }); } const agentModelRows = useMemo(() => { const map = new Map(); for (const row of spendData?.byAgentModel ?? []) { const rows = map.get(row.agentId) ?? []; rows.push(row); map.set(row.agentId, rows); } for (const [agentId, rows] of map) { map.set(agentId, rows.slice().sort((a, b) => b.costCents - a.costCents)); } return map; }, [spendData?.byAgentModel]); const { data: providerData, error: providerError } = useQuery({ queryKey: queryKeys.usageByProvider(companyId, reportQueryFrom, reportQueryTo), queryFn: () => costsApi.byProvider(companyId, from || undefined, to || undefined), enabled: !!selectedCompanyId && customReady && (mainTab === "providers" || mainTab === "billers"), refetchInterval: 30_000, staleTime: 10_000, }); const { data: billerData, error: billerError } = useQuery({ queryKey: queryKeys.usageByBiller(companyId, reportQueryFrom, reportQueryTo), queryFn: () => costsApi.byBiller(companyId, from || undefined, to || undefined), enabled: !!selectedCompanyId && customReady && mainTab === "billers", refetchInterval: 30_000, staleTime: 10_000, }); const { data: weekData, error: weekError } = useQuery({ queryKey: queryKeys.usageByProvider(companyId, weekRange.from, weekRange.to), queryFn: () => costsApi.byProvider(companyId, weekRange.from, weekRange.to), enabled: !!selectedCompanyId && (mainTab === "providers" || mainTab === "billers"), refetchInterval: 30_000, staleTime: 10_000, }); const { data: weekBillerData, error: weekBillerError } = useQuery({ queryKey: queryKeys.usageByBiller(companyId, weekRange.from, weekRange.to), queryFn: () => costsApi.byBiller(companyId, weekRange.from, weekRange.to), enabled: !!selectedCompanyId && mainTab === "billers", refetchInterval: 30_000, staleTime: 10_000, }); const { data: windowData, error: windowError } = useQuery({ queryKey: queryKeys.usageWindowSpend(companyId), queryFn: () => costsApi.windowSpend(companyId), enabled: !!selectedCompanyId && mainTab === "providers", refetchInterval: 30_000, staleTime: 10_000, }); const { data: quotaData, isLoading: quotaLoading, error: quotaFetchError } = useQuery({ queryKey: queryKeys.usageQuotaWindows(companyId), queryFn: () => costsApi.quotaWindows(companyId), structuralSharing: (previous, incoming) => retainQuotaWindows( previous as ProviderQuotaResult[] | undefined, incoming as ProviderQuotaResult[], ), enabled: !!selectedCompanyId && mainTab === "providers", refetchInterval: 300_000, staleTime: 60_000, }); const byProvider = useMemo(() => { const map = new Map(); for (const row of providerData ?? []) { const rows = map.get(row.provider) ?? []; rows.push(row); map.set(row.provider, rows); } return map; }, [providerData]); const byBiller = useMemo(() => { const map = new Map(); for (const row of billerData ?? []) { const rows = map.get(row.biller) ?? []; rows.push(row); map.set(row.biller, rows); } return map; }, [billerData]); const weekSpendByProvider = useMemo(() => { const map = new Map(); for (const row of weekData ?? []) { map.set(row.provider, (map.get(row.provider) ?? 0) + row.costCents); } return map; }, [weekData]); const weekSpendByBiller = useMemo(() => { const map = new Map(); for (const row of weekBillerData ?? []) { map.set(row.biller, (map.get(row.biller) ?? 0) + row.costCents); } return map; }, [weekBillerData]); const windowSpendByProvider = useMemo(() => { const map = new Map(); for (const row of windowData ?? []) { const rows = map.get(row.provider) ?? []; rows.push(row); map.set(row.provider, rows); } return map; }, [windowData]); const quotaWindowsByProvider = useMemo(() => { const map = new Map(); for (const result of quotaData ?? []) { if (result.windows.length > 0) { map.set(result.provider, result.windows); } } return map; }, [quotaData]); const quotaErrorsByProvider = useMemo(() => { const map = new Map(); for (const result of quotaData ?? []) { if (!result.ok) map.set(result.provider, "unavailable"); } if (quotaFetchError) { map.set("anthropic", "unavailable"); map.set("openai", "unavailable"); } return map; }, [quotaData, quotaFetchError]); const quotaSourcesByProvider = useMemo(() => { const map = new Map(); for (const result of quotaData ?? []) { if (typeof result.source === "string" && result.source.length > 0) { map.set(result.provider, result.source); } } return map; }, [quotaData]); const deficitNotchByProvider = useMemo(() => { const map = new Map(); if (preset !== "mtd") return map; const budget = spendData?.summary.budgetCents ?? 0; if (budget <= 0) return map; const now = new Date(); const daysElapsed = now.getUTCDate(); const daysInMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 0)).getUTCDate(); for (const [providerKey, rows] of byProvider) { const providerCostCents = rows.reduce((sum, row) => sum + row.costCents, 0); const burnRate = providerCostCents / Math.max(daysElapsed, 1); map.set(providerKey, providerCostCents + burnRate * (daysInMonth - daysElapsed) > budget); } return map; }, [preset, spendData, byProvider]); const providers = useMemo(() => Array.from(byProvider.keys()), [byProvider]); const billers = useMemo(() => Array.from(byBiller.keys()), [byBiller]); const effectiveProvider = activeProvider === "all" || providers.includes(activeProvider) ? activeProvider : "all"; useEffect(() => { if (effectiveProvider !== activeProvider) setActiveProvider("all"); }, [effectiveProvider, activeProvider]); const effectiveBiller = activeBiller === "all" || billers.includes(activeBiller) ? activeBiller : "all"; useEffect(() => { if (effectiveBiller !== activeBiller) setActiveBiller("all"); }, [effectiveBiller, activeBiller]); const providerTabItems = useMemo(() => { const providerKeys = Array.from(byProvider.keys()); const allTokens = providerKeys.reduce( (sum, provider) => sum + (byProvider.get(provider)?.reduce((acc, row) => acc + row.inputTokens + row.cachedInputTokens + row.outputTokens, 0) ?? 0), 0, ); const allCents = providerKeys.reduce( (sum, provider) => sum + (byProvider.get(provider)?.reduce((acc, row) => acc + row.costCents, 0) ?? 0), 0, ); return [ { value: "all", label: ( All providers {providerKeys.length > 0 ? ( <> {formatTokens(allTokens)} {formatCents(allCents)} ) : null} ), }, ...providerKeys.map((provider) => ({ value: provider, label: , })), ]; }, [byProvider]); const billerTabItems = useMemo(() => { const billerKeys = Array.from(byBiller.keys()); const allTokens = billerKeys.reduce( (sum, biller) => sum + (byBiller.get(biller)?.reduce((acc, row) => acc + row.inputTokens + row.cachedInputTokens + row.outputTokens, 0) ?? 0), 0, ); const allCents = billerKeys.reduce( (sum, biller) => sum + (byBiller.get(biller)?.reduce((acc, row) => acc + row.costCents, 0) ?? 0), 0, ); return [ { value: "all", label: ( All billers {billerKeys.length > 0 ? ( <> {formatTokens(allTokens)} {formatCents(allCents)} ) : null} ), }, ...billerKeys.map((biller) => ({ value: biller, label: , })), ]; }, [byBiller]); const topFinanceEvents = (financeData?.events ?? []) as FinanceEvent[]; const budgetPolicies = budgetData?.policies ?? []; const activeBudgetIncidents = budgetData?.activeIncidents ?? []; const budgetPoliciesByScope = useMemo(() => ({ company: budgetPolicies.filter((policy) => policy.scopeType === "company"), agent: budgetPolicies.filter((policy) => policy.scopeType === "agent"), project: budgetPolicies.filter((policy) => policy.scopeType === "project"), }), [budgetPolicies]); if (!selectedCompanyId) { return ; } const showCustomPrompt = preset === "custom" && !customReady; const showOverviewLoading = spendLoading && customReady; const overviewError = !spendData && spendError; return (
{scopedAgentError && (

Could not load agent details. Totals below show recorded organization costs.

)} {museUsageUnavailable && (

{scopedAgent.name}'s Muse activity has no reported usage or cost. Totals below show recorded organization charges only. Paperclip cannot enforce a Muse spend ceiling.

)} {showSummaryChrome ? (
{embedded ? (

Costs

) : (

Costs

)}
{PRESET_KEYS.map((key) => ( ))}
{preset === "custom" ? (
setCustomFrom(event.target.value)} className="h-9 rounded-md border border-input bg-background px-3 text-sm text-foreground" /> to setCustomTo(event.target.value)} className="h-9 rounded-md border border-input bg-background px-3 text-sm text-foreground" />
) : null} {financeData?.summary.currencies?.some((row) => row.currency !== "USD") && (

Finance headline totals are USD only. Other currencies are listed separately; no exchange-rate conversion is applied.

)}
0 ? "—" : formatCents(Number(subscriptions.api.costCents)) : "—"} subtitle={subscriptions ?
: subscriptionError ? "API usage is unavailable" : "API usage is loading"} icon={DollarSign} /> 0 ? String(activeBudgetIncidents.length) : ( spendData?.summary.budgetCents && spendData.summary.budgetCents > 0 ? preset === "mtd" ? `${spendData.summary.utilizationPercent}%` : formatCents(spendData.summary.budgetCents) : "Open" )} subtitle={ activeBudgetIncidents.length > 0 ? `${budgetData?.pausedAgentCount ?? 0} agents paused · ${budgetData?.pausedProjectCount ?? 0} projects paused` : spendData?.summary.budgetCents && spendData.summary.budgetCents > 0 ? preset === "mtd" ? `${formatCents(spendData.summary.spendCents)} of ${formatCents(spendData.summary.budgetCents)} this month` : "Monthly limit" : "No monthly cap configured" } icon={Coins} /> {formatCents(financeData.summary.debitCents)} debits {formatCents(financeData.summary.creditCents)} credits ) : "Financial data unavailable"} icon={ReceiptText} />
{subscriptions && Number(subscriptions.subscription.costCents) > 0 &&

Subscription accounts also have {formatCents(Number(subscriptions.subscription.costCents))} in recorded usage charges for this period, separate from monthly fees.

} {subscriptions && subscriptions.unknown.eventCount > 0 &&

Other billing usage: {formatTokens(subscriptions.unknown.inputTokens + subscriptions.unknown.cachedInputTokens + subscriptions.unknown.outputTokens)} tokens{Number(subscriptions.unknown.costCents) > 0 ? ` · ${formatCents(Number(subscriptions.unknown.costCents))} in recorded charges` : ""}, included in the inference ledger.

} {subscriptionError && subscriptions &&

Showing the last loaded API and subscription usage. Updates will resume automatically.

} {discoverSubscriptions.error &&

Connected accounts could not be checked. Existing subscription estimates are still shown.

{subscriptions?.canRefresh && }
} {mainTab === "overview" && spendData && (spendData.summary.unpricedEventCount > 0 || spendData.summary.pendingRunCount > 0 || (spendData.summary.unknownBillingEventCount ?? 0) > 0) && ( )}
) : null} {budgetError && !budgetData ? (

Budget data could not be loaded. Please try again shortly.

) : null} {((spendData && spendError) || (financeData && financeError) || (budgetData && budgetError) || providerError || billerError || weekError || weekBillerError || windowError) ? (

Showing the last loaded data. Updates will resume automatically.

) : null} {incidentMutation.error &&

Could not update the budget. Check any pending runs or unpriced usage shown on this page, then try again.

} { setMainTab(value as typeof mainTab); setSearchParams(current => { const next = new URLSearchParams(current); next.set("tab", value); return next; }, { replace: true }); }}> {!lockTab ? (
Overview {!hideBudgetsTab ? Budgets : null} Providers Billers Finance Decisions Fast responses
) : null} {showCustomPrompt ?

Select a start and end date to load data.

: }
{showCustomPrompt ?

Select a start and end date to load data.

: }
{showCustomPrompt ? (

Select a start and end date to load data.

) : showOverviewLoading ? ( ) : overviewError ? (

Cost data could not be loaded. Please try again shortly.

) : ( <>
By agent {(spendData?.byAgent.length ?? 0) === 0 ? (

No cost events yet.

) : ( spendData?.byAgent.map((row) => { const modelRows = agentModelRows.get(row.agentId) ?? []; const isExpanded = expandedAgents.has(row.agentId); const hasBreakdown = modelRows.length > 0; return (
hasBreakdown && toggleAgent(row.agentId)} >
{hasBreakdown ? ( isExpanded ? : ) : ( )} {row.agentId ? : Paperclip services} {row.agentStatus === "terminated" ? : null}
in {formatTokens(row.inputTokens + row.cachedInputTokens)} ({formatTokens(row.cachedInputTokens)} cached) · out {formatTokens(row.outputTokens)}
{(row.apiRunCount > 0 || row.subscriptionRunCount > 0) ? (
{"runs: "} {row.apiRunCount > 0 ? `${row.apiRunCount} api` : "0 api"} {" · "} {row.subscriptionRunCount > 0 ? `${row.subscriptionRunCount} sub` : "0 sub"}
) : null}
{isExpanded && modelRows.length > 0 ? (
{modelRows.map((modelRow) => { const sharePct = row.costCents > 0 ? Math.round((modelRow.costCents / row.costCents) * 100) : 0; return (
{providerDisplayName(modelRow.provider)} / {modelRow.model}
{providerDisplayName(modelRow.biller)} · {billingTypeDisplayName(modelRow.billingType)}
({sharePct}%)} />
{formatTokens(modelRow.inputTokens + modelRow.cachedInputTokens + modelRow.outputTokens)} tok
); })}
) : null}
); }) )}
{userSpendError && (

{userSpendData ? "User costs could not be refreshed. Showing the last loaded data." : "User costs could not be loaded. Please try again shortly."}

)} {userSpendData && }
By project {(spendData?.byProject.length ?? 0) === 0 ? (

No project-attributed run costs yet.

) : ( spendData?.byProject.map((row, index) => (
{row.projectName ?? row.projectId ?? "Unattributed"}
)) )}
{activeBudgetIncidents.length > 0 ? (
{activeBudgetIncidents.slice(0, 2).map((incident) => ( incidentMutation.mutate({ incidentId: incident.id, action: "keep_paused" })} onRaiseAndResume={(amount) => incidentMutation.mutate({ incidentId: incident.id, action: "raise_budget_and_resume", amount, })} /> ))}
) : null} {financeData ? ( ) : (

{financeLoading ? "Loading financial events…" : "Financial events could not be loaded. Please try again shortly."}

)} )}
{policyMutation.error &&

Could not update the budget policy. Review your settings and try again.

} {budgetLoading ? ( ) : budgetError && !budgetData ? null : ( <> Budget control plane Hard-stop spend limits for agents and projects. Provider subscription quota stays separate and appears under Providers. {activeBudgetIncidents.length > 0 ? (

Active incidents

Raise the budget or keep a hard stop paused. Dismiss a warning when no action is needed.

{activeBudgetIncidents.map((incident) => ( incidentMutation.mutate({ incidentId: incident.id, action: "keep_paused" })} onRaiseAndResume={(amount) => incidentMutation.mutate({ incidentId: incident.id, action: "raise_budget_and_resume", amount, })} /> ))}
) : null}
{(["company", "agent", "project"] as const).map((scopeType) => { const rows = budgetPoliciesByScope[scopeType]; if (rows.length === 0) return null; return (

{scopeType === "company" ? "organization" : scopeType} budgets

{scopeType === "company" ? "Organization-wide monthly policy." : scopeType === "agent" ? "Recurring monthly spend policies for individual agents." : "Lifetime spend policies for execution-bound projects."}

{rows.map((summary) => ( policyMutation.mutate({ summary, changes: { reservationCents } })} onUnpricedUsagePolicyChange={(unpricedUsagePolicy) => policyMutation.mutate({ summary, changes: { unpricedUsagePolicy } })} isSaving={policyMutation.isPending} onSave={(amount) => policyMutation.mutate({ summary, changes: { amount } })} /> ))}
); })} {budgetPolicies.length === 0 ? ( No budget policies yet. Set agent and project budgets from their detail pages, or use the existing organization monthly budget control. ) : null}
)}
{showCustomPrompt ? (

Select a start and end date to load data.

) : ( <> {providers.length === 0 ? (

No cost events in this period.

) : (
{providers.map((provider) => ( account.provider === provider)} quotaRequestFailed={Boolean(quotaFetchError)} quotaWindows={quotaWindowsByProvider.get(provider) ?? []} quotaError={quotaErrorsByProvider.get(provider) ?? null} quotaSource={quotaSourcesByProvider.get(provider) ?? null} quotaLoading={quotaLoading} /> ))}
)}
{providers.map((provider) => ( account.provider === provider)} quotaRequestFailed={Boolean(quotaFetchError)} quotaWindows={quotaWindowsByProvider.get(provider) ?? []} quotaError={quotaErrorsByProvider.get(provider) ?? null} quotaSource={quotaSourcesByProvider.get(provider) ?? null} quotaLoading={quotaLoading} /> ))}
)}
{showCustomPrompt ? (

Select a start and end date to load data.

) : ( <> {billers.length === 0 ? (

No billable events in this period.

) : (
{billers.map((biller) => { const row = (byBiller.get(biller) ?? [])[0]; if (!row) return null; const providerRows = (providerData ?? []).filter((entry) => entry.biller === biller); return ( ); })}
)}
{billers.map((biller) => { const row = (byBiller.get(biller) ?? [])[0]; if (!row) return null; const providerRows = (providerData ?? []).filter((entry) => entry.biller === biller); return ( ); })}
)}
{financeData?.summary.providerReportedCentsExact !== undefined &&

Provider API cost reports: {formatCents(financeData.summary.providerReportedCents ?? 0)}. Report totals overlap invoices and run estimates and are shown separately from recorded charges.

} {showCustomPrompt ? (

Select a start and end date to load data.

) : financeLoading ? ( ) : financeError && !financeData ? (

Financial events could not be loaded. Please try again shortly.

) : ( <>
By biller Account-level financial events grouped by who charged or credited them. {(financeData?.byBiller.length ?? 0) === 0 ? (

No finance events yet.

) : ( financeData?.byBiller.map((row) => ) )}
)}
); }