diff --git a/AgentCompany-New/src/renderer/src/pages/SettingsPage.tsx b/AgentCompany-New/src/renderer/src/pages/SettingsPage.tsx index 8081ab10..3a1f4b4d 100644 --- a/AgentCompany-New/src/renderer/src/pages/SettingsPage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/SettingsPage.tsx @@ -133,7 +133,7 @@ export function SettingsPage({ snapshot, actions }: PageProps) { roleGrants={roleGrants} /> )} - {tab === "billing" && } + {tab === "billing" && } {tab === "models" && } {tab === "providers" && ( sum + agent.budgetCents, 0); - const monthRequests = providerRequests.filter((request) => withinDays(request.createdAt, 30)); + const totalBudget = agents.reduce((sum, a) => sum + a.budgetCents, 0); + const totalCap = hiringPolicies.reduce((sum, p) => sum + p.monthlyBudgetLimitCents, 0); + const monthRequests = providerRequests.filter((r) => withinDays(r.createdAt, 30)); + const totalInputChars = monthRequests.reduce((s, r) => s + r.inputCharCount, 0); + const totalOutputChars = monthRequests.reduce((s, r) => s + r.outputCharCount, 0); + const failedRequests = monthRequests.filter((r) => r.state === "failed"); + const agentSpend = useMemo(() => buildAgentSpend(agents, providers, monthRequests), [agents, providers, monthRequests]); + return ( Billing - Allocations, provider activity, and budget windows. - - Monthly allocation - {money(totalBudget)} - across {agents.length} {agents.length === 1 ? "agent" : "agents"} + Allocations, spend, and cost breakdown. + + + + 0 ? money(totalCap) : "—"} /> + + 0 ? "red" : undefined} /> - Activity (30 days) + + + Token usage (30d) + + Input chars{totalInputChars.toLocaleString()} + Output chars{totalOutputChars.toLocaleString()} + Total{(totalInputChars + totalOutputChars).toLocaleString()} + + + + Budget utilization + + 0 ? Math.min(100, Math.round((totalBudget / totalCap) * 100)) : 0}%`, height: "100%", background: "var(--accent)" }} /> + + + {totalCap > 0 ? `${Math.round((totalBudget / totalCap) * 100)}% of cap` : "No budget cap set"} + + + + + Cost by agent + + + AgentBudgetRequestsInputOutput + + {agentSpend.map((row, i) => ( + + + + {row.agent.name} + + {money(row.agent.budgetCents)} + {row.requestCount} + {row.inputChars.toLocaleString()} + {row.outputChars.toLocaleString()} + + ))} + + + Provider activity (30d) - + ProviderRequestsErrorsAgents {providers.map((provider, index) => { - const requests = monthRequests.filter((request) => request.providerId === provider.id); - const errors = requests.filter((request) => request.state === "failed").length; - const boundAgents = agents.filter((agent) => agent.modelProviderId === provider.id).length; - const last = index === providers.length - 1; + const requests = monthRequests.filter((r) => r.providerId === provider.id); + const errors = requests.filter((r) => r.state === "failed").length; + const boundAgents = agents.filter((a) => a.modelProviderId === provider.id).length; return ( - + {provider.label} - {provider.model && ( - {provider.model} - )} + {provider.model && {provider.model}} {requests.length} {errors > 0 ? {errors} : 0} @@ -59,6 +99,37 @@ export function BillingPanel({ ); } +function StatTile({ label, value, tone }: { label: string; value: string; tone?: "red" }) { + return ( + + {label} + {value} + + ); +} + +interface AgentSpendRow { + agent: AgentRecord; + requestCount: number; + inputChars: number; + outputChars: number; +} + +function buildAgentSpend(agents: AgentRecord[], providers: ProviderRecord[], requests: ProviderRequestRecord[]): AgentSpendRow[] { + return agents.map((agent) => { + const agentRequests = requests.filter((r) => { + if (!agent.modelProviderId) return false; + return r.providerId === agent.modelProviderId; + }); + return { + agent, + requestCount: agentRequests.length, + inputChars: agentRequests.reduce((s, r) => s + r.inputCharCount, 0), + outputChars: agentRequests.reduce((s, r) => s + r.outputCharCount, 0), + }; + }).sort((a, b) => b.requestCount - a.requestCount); +} + function withinDays(iso: string, days: number): boolean { return Date.now() - new Date(iso).getTime() < days * 24 * 60 * 60 * 1000; }
Allocations, provider activity, and budget windows.
Allocations, spend, and cost breakdown.