"use client"; import { useMemo } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { Badge } from "@/components/ui/badge"; import { HelpTip } from "@/components/ui/help-tip"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { useAllMemberScorecards, useCeoScorecard, useOrgScorecard, } from "@/hooks/use-observability"; import { useAgents } from "@/hooks/use-agents"; import { AgentRole, type Agent, type MemberScorecard } from "@/types"; function pctOrNa(rate: number | null): string { return rate === null ? "n/a" : (rate * 100).toFixed(0) + "%"; } function numOrNa(value: number | null, digits = 1): string { return value === null ? "n/a" : value.toFixed(digits); } function hoursOrDash(seconds: number): string { return (seconds / 3600).toFixed(1) + "h"; } /** One member's row. Data comes from the batched useAllMemberScorecards * fetch (one request for the whole table) rather than each row self-fetching * — ~20 agents used to mean ~20 parallel `/metrics/member/{id}` requests * (each 3 DB queries) on every table poll. */ function MemberRow({ agent, data, }: { agent: Agent; data: MemberScorecard | undefined; }) { if (!data) { return ( {agent.name || agent.slug} ); } return ( {agent.name || agent.slug} {data.includes_live_inflight && ( live )} {data.tasks_completed} {pctOrNa(data.first_pass_yield)} {data.active_runtime_hours.toFixed(1)}h {numOrNa(data.turns_per_task)} {pctOrNa(data.qa_pass_rate)} {data.escalations} {data.blocked_others} {pctOrNa(data.utilization)} ); } function OrgSummary() { const { data, isLoading, isError } = useOrgScorecard(); if (isError) return (
Failed to load organization metrics.
); if (isLoading || !data) return ; const cells: [string, string, string?][] = [ ["Members", String(data.member_count)], ["Completed", String(data.tasks_completed)], [ "First-pass yield", pctOrNa(data.first_pass_yield), "Share of completed tasks that shipped without a QA/PR-gate/PM/CEO bounce", ], [ "Throughput/hr", numOrNa(data.effort_throughput_per_hour, 2), "Tasks completed per hour of active (non-idle) agent runtime", ], [ "Active effort", data.active_runtime_hours.toFixed(1) + "h", "Total hours agents spent actively working — idle time excluded", ], ["Cost", "$" + data.cost_usd.toFixed(2)], ]; return (
{cells.map(([k, v, tip]) => (
{v}
{k}
))}
); } function CeoCard() { const { data, isLoading, isError } = useCeoScorecard(); if (isError) return (
Failed to load CEO metrics.
); if (isLoading || !data) return ; const cells: [string, string, string?][] = [ ["Approvals", String(data.approval_count)], [ "Approval p50", hoursOrDash(data.approval_p50_seconds), "Median time from a task reaching your queue to your approval", ], [ "Approval p90", hoursOrDash(data.approval_p90_seconds), "90th percentile — the slowest 10% of approvals took at least this long", ], ["Unblocks", String(data.unblock_count)], [ "Unblock p50", hoursOrDash(data.unblock_p50_seconds), "Median time from a task blocking to you unblocking it", ], [ "God-mode actions", String(data.godmode_actions), "Direct admin overrides you made outside the normal approval flow", ], ]; return (
{cells.map(([k, v, tip]) => (
{v}
{k}
))}
); } export function ScorecardsTabContent() { const { data: agents } = useAgents(); const members = (agents ?? []).filter( (a) => a.role !== AgentRole.CEO && a.role !== AgentRole.SYSTEM, ); const { data: scorecards, isError: scorecardsError } = useAllMemberScorecards(); const scorecardById = useMemo( () => new Map((scorecards ?? []).map((s) => [s.id, s])), [scorecards], ); return (
Organization CEO (you) Members {scorecardsError && (

Failed to load member scorecards.

)} Member Done FPY Effort Turns/task QA pass Escal. Blocked others Util. {members.map((a) => ( ))}
); }