import { type EnvironmentId, type ProviderConsumeResetCreditOutcome, ProviderInstanceId, ServerProvider, ServerProviderResetCredits, ServerProviderUsageWindow, UsageLimitSourceAccount, UsageLimitSourceSnapshot, UsageProviderKind, } from "@t3tools/contracts"; import { useAtomValue } from "@effect/atom-react"; import { collectLimitSources, collectLimitsGroups, elapsedShare, formatDuration, formatResetsIn, limitsNotice, type LimitPace, paceOf, providerLimitsLabel, } from "@t3tools/shared/usageLimits"; import { GaugeIcon, TrendingDownIcon, TrendingUpIcon } from "lucide-react"; import { Fragment, useState } from "react"; import { usePrimarySettings } from "../../hooks/useSettings"; import { environmentPresentations } from "../../state/presentation"; import { serverEnvironment } from "../../state/server"; import { useAtomCommand } from "../../state/use-atom-command"; import { formatUpcomingTimestamp } from "../../timestampFormat"; import { ProviderInstanceIcon } from "../chat/ProviderInstanceIcon"; import { getDriverOption } from "../settings/providerDriverMeta"; import { RedactedSensitiveText } from "../settings/RedactedSensitiveText"; import { AlertDialog, AlertDialogClose, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPopup, AlertDialogTitle, } from "../ui/alert-dialog"; import { Button } from "../ui/button"; import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; import { PROVIDER_PRESENTATION } from "./usageProviders"; const PACE: Record = { ahead: { label: "Ahead of pace: spending faster than the window elapses", icon: TrendingUpIcon }, on: { label: "On pace with the window", icon: GaugeIcon }, under: { label: "Under pace: headroom left for the rest of the window", icon: TrendingDownIcon }, }; /** The series colour the cost chart uses for this driver, so the two views read as one. */ function barColor(driver: ServerProvider["driver"]): string { const kind: UsageProviderKind | undefined = driver === "codex" ? "codex" : driver === "claudeAgent" ? "claude" : undefined; return kind ? PROVIDER_PRESENTATION[kind].color : "var(--foreground)"; } /** Pace as a glyph with the words on hover. */ function PaceIcon({ pace }: { readonly pace: LimitPace }) { const Icon = PACE[pace].icon; return ( } > {PACE[pace].label} ); } /** * One window as a full-width bar from the moment it opened to its reset. * The fill is the share of quota spent; the hairline is how far into the * window the clock is, which is also where even spending would have put the * fill. Hover for the exact figures and reset time. */ function WindowBar({ color, window, now, }: { readonly color: string; readonly window: ServerProviderUsageWindow; readonly now: number; }) { const timestampFormat = usePrimarySettings((settings) => settings.timestampFormat); const used = Math.max(0, Math.min(100, window.usedPercent)); const elapsed = elapsedShare(window, now); const resetsIn = formatResetsIn(window, now); const resetsAt = window.resetsAt ? formatUpcomingTimestamp(window.resetsAt, timestampFormat, now) : null; const summary = `${window.label}: ${Math.round(used)}% used${ elapsed === null ? "" : `, ${Math.round(elapsed * 100)}% of the window elapsed` }${resetsIn ? `, ${resetsIn}` : ""}`; return ( } >
{used > 0 ? (
) : null} {elapsed !== null ? ( ) : null}
{Math.round(used)}% used {elapsed !== null ? ` · ${Math.round(elapsed * 100)}% of the window elapsed` : ""} {elapsed !== null ? ( The line is where even spending would be. ) : null} {resetsAt ? ( Resets {resetsAt} {resetsIn ? ` · ${resetsIn}` : ""} ) : null}
); } /** One account's windows as rows: label and percent, bar, pace and countdown. */ function LimitWindows({ driver, windows, now, }: { readonly driver: ServerProvider["driver"]; readonly windows: ReadonlyArray; readonly now: number; }) { const color = barColor(driver); return (
{windows.map((window, index) => { // Windows that reset together show the countdown once. const previous = windows[index - 1]; const sharesReset = previous?.resetsAt !== undefined && previous.resetsAt === window.resetsAt; const pace = paceOf(window, now); const resetsIn = formatResetsIn(window, now); return ( {window.label} {Math.round(window.usedPercent)}% {pace ? : null} {sharesReset ? "" : (resetsIn ?? "")} ); })}
); } /** * Heading shared by local providers and source accounts: icon, driver, instance, plan, * and the signed-in email blurred until clicked, as provider settings do. */ function AccountHeading({ driver, label, instanceLabel, plan, email, accentColor, }: { readonly driver: ServerProvider["driver"]; readonly label: string; readonly instanceLabel: string; readonly plan: string | undefined; readonly email: string | undefined; readonly accentColor?: string | undefined; }) { return (

{label} {instanceLabel !== label ? ( · {instanceLabel} ) : null} {plan ? · {plan} : null} {email ? ( ) : null}

); } function ProviderLimits({ provider, environmentId, now, }: { readonly provider: ServerProvider; readonly environmentId: EnvironmentId; readonly now: number; }) { const limits = provider.usageLimits; if (!limits) return null; const notice = limitsNotice(limits); return (
getDriverOption(driver)?.label)} plan={provider.auth.label} email={provider.auth.email} accentColor={provider.accentColor} /> {notice ? ( {notice} ) : ( )} {limits.resetCredits ? ( ) : null}
); } const OUTCOME_TEXT: Record = { reset: "Reset applied. Your windows have cleared.", nothingToReset: "Nothing to reset right now.", noCredit: "No reset credit left.", alreadyRedeemed: "That credit was already redeemed.", }; /** * Banked reset credits with a confirmed redeem action. Redeeming spends a * credit the provider granted the user, so it never fires on a bare click. */ function ResetCredits({ environmentId, instanceId, credits, now, }: { readonly environmentId: EnvironmentId; readonly instanceId: ProviderInstanceId; readonly credits: ServerProviderResetCredits; readonly now: number; }) { const consume = useAtomCommand(serverEnvironment.consumeResetCredit, { reportFailure: false }); const [confirming, setConfirming] = useState(false); const [busy, setBusy] = useState(false); const [status, setStatus] = useState(null); if (credits.availableCount === 0 && status === null) return null; const expiresIn = credits.nextExpiresAt ? formatDuration(Date.parse(credits.nextExpiresAt) - now) : null; const summary = credits.availableCount === 0 ? "No reset credits banked" : `${credits.availableCount} ${credits.availableCount === 1 ? "reset credit" : "reset credits"} banked${ expiresIn ? ` · next expires in ${expiresIn}` : "" }`; const redeem = async () => { setConfirming(false); setBusy(true); setStatus(null); const result = await consume({ environmentId, input: { instanceId } }); setBusy(false); if (result._tag === "Success") { setStatus(OUTCOME_TEXT[result.value.outcome]); return; } setStatus( "error" in result.cause && result.cause.error instanceof Error ? result.cause.error.message : "Could not use the reset credit.", ); }; return (
{summary} {credits.availableCount > 0 ? ( ) : null} {status ? {status} : null} Use a reset credit? This redeems one credit on your account and clears the current rate-limit windows. It cannot be undone. }>Cancel
); } /** One account pooled by a usage-limit source, drawn like a provider row. */ function SourceAccountLimits({ account, sourceKind, now, }: { readonly account: UsageLimitSourceAccount; readonly sourceKind: string; readonly now: number; }) { const notice = limitsNotice(account.usageLimits); return (
{notice ? ( {notice} ) : ( )}
); } const SOURCE_KIND_LABEL: Record = { cliproxy: "CLI Proxy", }; type LimitsSource = ReturnType[number]; /** Read-only accounts pooled by a configured usage source. */ function SourceLimits({ source, now }: { readonly source: LimitsSource; readonly now: number }) { const kind = SOURCE_KIND_LABEL[source.kind]; return (
{source.error ? ( {source.error} ) : source.accounts.length === 0 ? ( {source.hiddenAccountCount > 0 ? "All accounts are shown by connected providers." : "No accounts reported."} ) : ( source.accounts.map((account) => ( )) )}
); } /** * Subscription quota windows from every connected environment's providers. * Countdowns anchor to render time rather than ticking: a live clock would * repaint the page every minute for no decision-changing gain. */ export function UsageLimitsSection() { const presentations = useAtomValue(environmentPresentations.presentationsAtom); const groups = collectLimitsGroups(presentations); const sources = collectLimitSources(presentations); // Anchored once per mount on purpose: countdowns must not tick (see below). const [now] = useState(() => Date.now()); return (
{groups.length === 0 && sources.length === 0 ? (

No provider on a connected environment reports subscription limits.

) : null} {sources.map((source) => ( ))} {groups.map((group) => (
{group.environmentLabel ? (

{group.environmentLabel}

) : null} {group.providers.map((provider) => ( ))}
))}
); }