Spaces:
Running on Zero
Running on Zero
| import React from "react"; | |
| import { | |
| CheckCircle2, AlertTriangle, ShieldAlert, Bot, ScrollText, Flame, Coins, | |
| Wrench, RefreshCw, Info, Clock, Cpu, GitBranch, Layers, MessageSquare, | |
| Network, Map, Code2, Sparkles, ArrowRight, Link2, ChevronRight, Lightbulb, ShieldCheck, | |
| Rocket, Database, Boxes, Server, Gauge, Scissors, | |
| } from "lucide-react"; | |
| import { C, FD, FB, FM, fmt, fmtWhen } from "../theme.js"; | |
| import { BinaryLogo, GeneratedTag } from "./Primitives.jsx"; | |
| // SESSION REPORT — the executive cover page for a session (the simplified default | |
| // view). It unifies every deterministic signal Her produces — cost, outcome, the | |
| // real binaries run, the high-impact actions + risk, timestamps, and the cited | |
| // recommendations — and is the jumping-off point to the Journey Graph (Mode A) and | |
| // the turn-by-turn detail (Mode B). Numbers are the engine; the only GENERATED | |
| // prose is the "What happened" overview (labelled). Suggest, never assert. | |
| const COST_W = { in: 1.0, cacheCreate: 1.25, cacheRead: 0.1, out: 5.0 }; | |
| const RISK = { | |
| High: { c: C.red, note: "high-impact actions detected" }, | |
| Medium: { c: C.amber, note: "review the flagged actions" }, | |
| Low: { c: C.cyan, note: "minor actions only" }, | |
| None: { c: C.muted, note: "nothing high-impact" }, | |
| }; | |
| const TAG = { | |
| LIVE: { c: C.red, icon: Rocket }, | |
| PRODUCTION: { c: C.red, icon: Rocket }, // legacy alias | |
| SECURITY: { c: C.orange, icon: ShieldAlert }, | |
| DATA: { c: "#f472b6", icon: Database }, | |
| NETWORK: { c: C.cyan, icon: Network }, | |
| CONFIG: { c: C.amber, icon: Code2 }, | |
| DEV: { c: C.blue, icon: Server }, | |
| }; | |
| function durationStr(a, b) { | |
| if (!a || !b) return "—"; | |
| const ms = new Date(b).getTime() - new Date(a).getTime(); | |
| if (isNaN(ms) || ms < 0) return "—"; | |
| const s = Math.round(ms / 1000); | |
| const h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), ss = s % 60; | |
| return h ? `${h}h ${m}m` : m ? `${m}m ${ss}s` : `${ss}s`; | |
| } | |
| // A friendly type tag for a binary in "Tools Discovered". | |
| function binKind(b) { | |
| const blob = `${b.product || ""} ${b.blurb || ""} ${b.security || ""}`.toLowerCase(); | |
| if (/\b(database|postgres|sql|mongo|redis|sqlite|db client)\b/.test(blob)) return "DB CLI"; | |
| if (b.via && b.via !== "direct") return "pkg"; | |
| if (/\bcli\b/.test(blob) || b.identified) return "CLI"; | |
| return "binary"; | |
| } | |
| export default function SessionReport({ | |
| session, turns, binaries, entities, impact, recommendations, advice, | |
| overview, narrated, onOpenTurn, onOpenJourney, onOpenRaw, onAskHer, chatOpen, | |
| }) { | |
| const S = session; | |
| const tk = S.tokens || {}; | |
| // point-in-time window occupancy ("fuel gauge") — distinct from the cumulative tk.* | |
| const ctx = S.context || { peak: 0, limit: 1e6, peakPct: 0, trajectory: [], compactions: [], overLimit: [] }; | |
| const reqs = turns.reduce((s, t) => s + (t.reqs || 0), 0); | |
| const im = impact || { riskLevel: "None", actions: [], outcome: null }; | |
| const outcome = im.outcome || { label: "—", detail: "" }; | |
| const risk = RISK[im.riskLevel] || RISK.None; | |
| const agentPct = Math.round(100 * (S.indirectRatio || 0)); | |
| // cost breakdown (by COST contribution — this is "why this COST so much") | |
| const parts = [ | |
| { label: "Cache re-reads", raw: tk.cacheRead || 0, cost: (tk.cacheRead || 0) * COST_W.cacheRead, c: C.orange }, | |
| { label: "Generated (agent output)", raw: tk.out || 0, cost: (tk.out || 0) * COST_W.out, c: C.cyan }, | |
| { label: "Cache write", raw: tk.cacheCreate || 0, cost: (tk.cacheCreate || 0) * COST_W.cacheCreate, c: C.amber }, | |
| { label: "Fresh input", raw: tk.in || 0, cost: (tk.in || 0) * COST_W.in, c: C.blue }, | |
| ]; | |
| const totalCost = parts.reduce((s, p) => s + p.cost, 0) || 1; | |
| const driver = parts.reduce((a, b) => (b.cost > a.cost ? b : a), parts[0]); | |
| // most important turns — by cost | |
| const ranked = [...turns] | |
| .filter((t) => (t.tokens?.cost ?? 0) > 0) | |
| .sort((a, b) => (b.tokens.cost ?? 0) - (a.tokens.cost ?? 0)) | |
| .slice(0, 4); | |
| // tools discovered = binaries (real CLIs/pkgs) + skills/plugins + sub-agents + MCP | |
| const bins = (binaries || []).map((b) => ({ ...b, glyph: "binary", kind: binKind(b) })); | |
| const skills = (entities?.skills || []).map((s) => ({ name: s.name, turns: s.turns, glyph: "skill", kind: "skill" })); | |
| const agents = (entities?.subAgents || []).map((a) => ({ name: a.name, turns: a.turns, glyph: "agent", kind: a.via === "workflow" ? "workflow" : "agent" })); | |
| const mcp = (entities?.mcpServers || []).map((m) => ({ name: m.name, turns: m.turns, glyph: "mcp", kind: "MCP" })); | |
| const tools = [...bins, ...skills, ...agents, ...mcp]; | |
| const recs = (advice?.recommendations?.length ? advice.recommendations : recommendations) || []; | |
| function copySummary() { | |
| const lines = [ | |
| `Her · session report — ${S.sessionId ? S.sessionId.slice(0, 8) : ""}`, | |
| `${S.cwd || ""}`, | |
| `Outcome: ${outcome.label} (${outcome.detail})`, | |
| `Token cost: ${fmt(S.cost || 0)} cost-weighted tokens (not $) · cache re-reads ${fmt(tk.cacheRead || 0)} cumulative across ${reqs} round-trips · agent-driven ${agentPct}%`, | |
| `Peak context: ${fmt(ctx.peak || 0)} / ${fmt(ctx.limit || 0)} (${Math.round((ctx.peakPct || 0) * 100)}% of the window)${ctx.compactions?.length ? ` · ${ctx.compactions.length} compaction(s)` : ""}`, | |
| `Risk: ${im.riskLevel} (${im.riskReason || ""})`, | |
| `Tools: ${tools.map((t) => t.product || t.name).join(", ")}`, | |
| im.actions?.length ? `Actions: ${im.actions.map((a) => `${a.title} [${a.tag}]`).join("; ")}` : "", | |
| `Started ${fmtWhen(S.startedAt)} · ${durationStr(S.startedAt, S.endedAt)} · ${S.model || ""}`, | |
| ].filter(Boolean); | |
| try { navigator.clipboard.writeText(lines.join("\n")); } catch { /* ignore */ } | |
| } | |
| return ( | |
| <div style={{ flex: 1, minWidth: 0, overflowY: "auto", padding: "22px 26px 40px" }}> | |
| {/* title + actions */} | |
| <div style={{ display: "flex", alignItems: "flex-start", gap: 16, flexWrap: "wrap" }}> | |
| <div style={{ flex: 1, minWidth: 280 }}> | |
| <div style={{ fontFamily: FD, fontWeight: 700, fontSize: 26, letterSpacing: 0.2 }}>Session Report</div> | |
| <div style={{ fontSize: 13, color: C.text2, marginTop: 4, lineHeight: 1.5, maxWidth: 640 }}> | |
| Executive summary for this coding-agent session — what happened, why it cost, and what to review. | |
| </div> | |
| </div> | |
| <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}> | |
| <ReportBtn icon={Map} text="Open Journey Graph" onClick={onOpenJourney} /> | |
| <ReportBtn icon={Code2} text="Open Raw Trace" onClick={onOpenRaw} /> | |
| <ReportBtn icon={Sparkles} text="Ask Her" onClick={onAskHer} primary active={chatOpen} /> | |
| </div> | |
| </div> | |
| {/* stat band */} | |
| <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(190px,1fr))", gap: 12, marginTop: 18 }}> | |
| <StatCard label="OUTCOME" icon={outcome.label === "Succeeded" ? CheckCircle2 : AlertTriangle} | |
| iconColor={outcome.label === "Succeeded" ? C.cyan : C.amber} | |
| value={outcome.label} valueColor={outcome.label === "Succeeded" ? C.cyan : C.amber} | |
| sub={outcome.detail} big /> | |
| <StatCard label="TOKEN COST" value={fmt(S.cost || 0)} valueColor={C.orange} grad sub="cost-weighted tokens · not $ (cacheRead ×0.1 · out ×5)" /> | |
| <PeakContextCard ctx={ctx} /> | |
| <StatCard label="CACHE RE-READS" value={fmt(tk.cacheRead || 0)} | |
| sub={`cumulative across ${reqs} round-trips · ~${Math.round(S.cacheReadOverOut || 0)}× generated · not window size`} /> | |
| <StatCard label="RISK LEVEL" icon={ShieldAlert} iconColor={risk.c} value={im.riskLevel} valueColor={risk.c} | |
| sub={im.riskReason || risk.note} /> | |
| <StatCard label="AGENT-DRIVEN" icon={Bot} iconColor={C.orange} value={`${agentPct}%`} | |
| sub={`${S.indirect || 0} of ${S.tools || 0} tool calls`} /> | |
| </div> | |
| {/* main grid */} | |
| <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(260px,1fr))", gap: 12, marginTop: 12 }}> | |
| {/* WHAT HAPPENED */} | |
| <Card icon={ScrollText} title="WHAT HAPPENED"> | |
| {overview?.text ? ( | |
| <> | |
| <div style={{ marginBottom: 8 }}><GeneratedTag cites={overview.label} /></div> | |
| <ul style={{ margin: 0, paddingLeft: 0, listStyle: "none", display: "flex", flexDirection: "column", gap: 8 }}> | |
| {sentences(overview.text).map((s, i) => ( | |
| <li key={i} style={{ display: "flex", gap: 8, fontSize: 12.5, color: C.text2, lineHeight: 1.5 }}> | |
| <CheckCircle2 size={13} color={C.cyan} style={{ flexShrink: 0, marginTop: 2 }} /> <span>{s}</span> | |
| </li> | |
| ))} | |
| </ul> | |
| </> | |
| ) : ( | |
| <div style={{ fontSize: 12.5, color: C.muted, lineHeight: 1.5 }}> | |
| {S.turns} queries · {S.tools} tool calls · {S.humanTurns} human / {S.systemTurns} system turns. (Plain-English summary appears when the local model is running.) | |
| </div> | |
| )} | |
| </Card> | |
| {/* ACTIONS WORTH REVIEWING */} | |
| <Card icon={AlertTriangle} title="ACTIONS WORTH REVIEWING" accent={C.amber}> | |
| {im.actions?.length ? im.actions.map((a, i) => { | |
| const tg = TAG[a.tag] || { c: C.muted, icon: Info }; | |
| const Ic = tg.icon; | |
| return ( | |
| <div key={i} className="row lift" onClick={() => a.turns?.length && onOpenTurn(a.turns[0])} | |
| style={{ display: "flex", gap: 10, alignItems: "center", cursor: a.turns?.length ? "pointer" : "default", background: C.card, border: `1px solid ${C.borderSoft}`, borderRadius: 8, padding: "9px 11px", marginTop: i ? 7 : 0 }}> | |
| <div style={{ width: 26, height: 26, borderRadius: 7, background: C.elevated, border: `1px solid ${tg.c}`, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}> | |
| <Ic size={13} color={tg.c} /> | |
| </div> | |
| <div style={{ minWidth: 0, flex: 1 }}> | |
| <div style={{ fontSize: 12.5, fontWeight: 600, color: C.text }}>{a.title}</div> | |
| <div style={{ fontSize: 11, color: C.muted, lineHeight: 1.4, marginTop: 1 }}>{a.detail}</div> | |
| </div> | |
| <span style={{ fontFamily: FM, fontSize: 8.5, letterSpacing: 0.5, color: tg.c, border: `1px solid ${tg.c}`, borderRadius: 4, padding: "1px 6px", flexShrink: 0 }}>{a.tag}</span> | |
| </div> | |
| ); | |
| }) : ( | |
| <div className="row" style={{ display: "flex", gap: 9, alignItems: "center", fontSize: 12.5, color: C.text2, lineHeight: 1.5 }}> | |
| <ShieldCheck size={16} color={C.cyan} style={{ flexShrink: 0 }} /> | |
| <span>No high-impact actions detected — no deploys, config/secret changes, tunnels, or privilege changes.</span> | |
| </div> | |
| )} | |
| </Card> | |
| {/* TOOLS DISCOVERED */} | |
| <Card icon={Wrench} title="TOOLS DISCOVERED"> | |
| {tools.length ? ( | |
| <> | |
| <div style={{ display: "flex", flexWrap: "wrap", gap: 7 }}> | |
| {tools.map((t) => { | |
| const clickable = t.turns && t.turns.length; | |
| return ( | |
| <span key={t.glyph + ":" + t.name} | |
| onClick={() => clickable && onOpenTurn(t.turns[0])} | |
| className={clickable ? "lift" : ""} | |
| title={`${t.product || t.name}${t.blurb ? " — " + t.blurb : ""}${t.security ? " ⚠ " + t.security : ""}${t.turns?.length ? " · turn(s) " + t.turns.join(", ") : ""}`} | |
| style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: FM, fontSize: 10.5, color: C.text2, border: `1px solid ${C.borderSoft}`, borderRadius: 7, padding: "4px 8px 4px 6px", cursor: clickable ? "pointer" : "default" }}> | |
| {toolGlyph(t)} | |
| <span style={{ color: C.text }}>{t.product || t.name}</span> | |
| <span style={{ color: C.muted, fontSize: 9 }}>({t.kind})</span> | |
| {t.security && <ShieldAlert size={10} color={C.amber} />} | |
| </span> | |
| ); | |
| })} | |
| </div> | |
| <div onClick={onOpenJourney} className="lift" style={{ cursor: "pointer", fontFamily: FM, fontSize: 10.5, color: C.orange, marginTop: 12, display: "inline-flex", alignItems: "center", gap: 5 }}> | |
| See all {S.tools} tool calls <ArrowRight size={12} /> | |
| </div> | |
| </> | |
| ) : <Empty text="No external binaries or MCP servers detected." />} | |
| </Card> | |
| </div> | |
| {/* COST & CONTEXT — one widget, two halves of the same token story: cumulative | |
| spend (left, no ceiling) vs the point-in-time window gauge (right, ≤1M). Side | |
| by side so the two quantities can't be mistaken for each other. */} | |
| <CostContextCard S={S} parts={parts} totalCost={totalCost} driver={driver} | |
| ctx={ctx} reqs={reqs} onOpenTurn={onOpenTurn} /> | |
| {/* bottom grid */} | |
| <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(300px,1fr))", gap: 12, marginTop: 12 }}> | |
| {/* MOST IMPORTANT TURNS */} | |
| <Card icon={Flame} title="MOST IMPORTANT TURNS"> | |
| <div style={{ display: "flex", flexDirection: "column", gap: 7 }}> | |
| {ranked.map((t) => { | |
| const errs = (t.tools || []).filter((tc) => tc.errored).length; | |
| const title = t.guide?.head || (t.heavy ? "Heaviest turn" : firstClause(t.prompt)); | |
| const detail = t.guide?.body ? clip(t.guide.body, 90) : `${(t.tools || []).length} tools${errs ? `, ${errs} errored` : ""}`; | |
| const pct = Math.round((100 * (t.tokens.cost ?? 0)) / Math.max(1, S.cost || 1)); | |
| return ( | |
| <div key={t.i} className="row lift" onClick={() => onOpenTurn(t.i)} | |
| style={{ display: "flex", gap: 10, alignItems: "flex-start", cursor: "pointer", background: C.card, border: `1px solid ${C.borderSoft}`, borderRadius: 8, padding: "9px 11px" }}> | |
| <span style={{ fontFamily: FM, fontSize: 10, color: C.muted, background: C.black, borderRadius: 5, padding: "2px 6px", flexShrink: 0 }}>#{String(t.i).padStart(2, "0")}</span> | |
| <div style={{ minWidth: 0, flex: 1 }}> | |
| <div style={{ fontSize: 12.5, fontWeight: 600, color: C.text, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{title}</div> | |
| <div style={{ fontSize: 11, color: C.muted, lineHeight: 1.4, marginTop: 2 }}>{detail}</div> | |
| </div> | |
| <div style={{ textAlign: "right", flexShrink: 0 }}> | |
| <div style={{ fontFamily: FM, fontSize: 12, color: t.heavy ? C.orange : C.text2, fontWeight: 600 }}>{fmt(t.tokens.cost ?? 0)}</div> | |
| <div style={{ fontFamily: FM, fontSize: 9, color: C.muted }}>{pct}% of cost</div> | |
| </div> | |
| <ChevronRight size={14} color={C.muted} style={{ flexShrink: 0, marginTop: 2 }} /> | |
| </div> | |
| ); | |
| })} | |
| {ranked.length === 0 && <Empty text="No costed turns." />} | |
| </div> | |
| </Card> | |
| {/* RECOMMENDED NEXT RUN */} | |
| <Card icon={RefreshCw} title="RECOMMENDED NEXT RUN"> | |
| {recs.length ? recs.slice(0, 4).map((r, i) => ( | |
| <div key={i} className="row lift" onClick={() => r.turns?.length && onOpenTurn(r.turns[0])} | |
| style={{ display: "flex", gap: 10, alignItems: "flex-start", cursor: r.turns?.length ? "pointer" : "default", background: C.card, border: `1px solid ${C.borderSoft}`, borderRadius: 8, padding: "9px 11px", marginTop: i ? 7 : 0 }}> | |
| <Lightbulb size={14} color={C.amber} style={{ flexShrink: 0, marginTop: 2 }} /> | |
| <div style={{ minWidth: 0, flex: 1 }}> | |
| <div style={{ fontSize: 12.5, fontWeight: 600, color: C.text, display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}> | |
| {r.headline} | |
| <AttrBadge attribution={r.attribution} scoped={!!r.scoped} /> | |
| </div> | |
| <div style={{ fontSize: 11.5, color: C.muted, lineHeight: 1.45, marginTop: 2 }}>{clip(r.scoped || r.advice || "", 120)}</div> | |
| </div> | |
| <ChevronRight size={14} color={C.muted} style={{ flexShrink: 0, marginTop: 2 }} /> | |
| </div> | |
| )) : ( | |
| <div className="row" style={{ display: "flex", gap: 9, alignItems: "center", fontSize: 12.5, color: C.text2, lineHeight: 1.5 }}> | |
| <CheckCircle2 size={16} color={C.cyan} style={{ flexShrink: 0 }} /> | |
| <span>Nothing stands out to change — expensive but clean. No loops, avoidable re-reads, or CLI flailing.</span> | |
| </div> | |
| )} | |
| </Card> | |
| {/* SESSION AT A GLANCE */} | |
| <Card icon={Info} title="SESSION AT A GLANCE"> | |
| <Glance icon={Clock} label="Started" value={fmtWhen(S.startedAt) || "—"} /> | |
| <Glance icon={Clock} label="Duration" value={durationStr(S.startedAt, S.endedAt)} /> | |
| <Glance icon={Cpu} label="Model" value={modelLabel(S.model)} /> | |
| <Glance icon={Layers} label="Mode" value={`${S.humanTurns || 0} human + ${S.systemTurns || 0} system`} /> | |
| <Glance icon={GitBranch} label="Branch" value={S.gitBranch || "—"} /> | |
| <Glance icon={MessageSquare} label="Queries" value={String(S.turns ?? "—")} /> | |
| <Glance icon={Wrench} label="Tools called" value={String(S.tools ?? "—")} /> | |
| <div onClick={copySummary} className="lift" style={{ cursor: "pointer", marginTop: 12, display: "flex", alignItems: "center", justifyContent: "center", gap: 7, background: C.black, border: `1px solid ${C.borderSoft}`, borderRadius: 8, padding: "8px 10px", fontFamily: FM, fontSize: 11, color: C.text2 }}> | |
| <Link2 size={13} color={C.orange} /> Copy summary | |
| </div> | |
| </Card> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| // ---------- small presentational atoms (Tactical Grey) ---------------------- | |
| function ReportBtn({ icon: Icon, text, onClick, primary, active }) { | |
| // `active` (panel open) gives a pressed look so it reads as a toggle — click again to close. | |
| const bg = primary ? (active ? C.orangeHi : C.orange) : (active ? C.orangeMut : "transparent"); | |
| const fg = primary ? "#fff" : (active ? C.orange : C.text2); | |
| return ( | |
| <div onClick={onClick} className="row lift" title={active ? "click to close the panel" : undefined} | |
| style={{ display: "flex", alignItems: "center", gap: 7, cursor: "pointer", fontFamily: FM, fontSize: 11.5, color: fg, background: bg, border: `1px solid ${primary || active ? (active && !primary ? C.orangeBd : C.orange) : C.border}`, borderRadius: 8, padding: "8px 13px", boxShadow: active ? "inset 0 1px 4px rgba(0,0,0,.35)" : "none" }}> | |
| <Icon size={14} color={primary ? "#fff" : C.orange} /> {text} | |
| </div> | |
| ); | |
| } | |
| function StatCard({ label, icon: Icon, iconColor, value, valueColor, sub, grad, big }) { | |
| return ( | |
| <div style={{ background: `linear-gradient(135deg,${C.card},${C.panel})`, border: `1px solid ${C.borderSoft}`, borderRadius: 10, padding: "13px 15px" }}> | |
| <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> | |
| <span style={{ fontFamily: FM, fontSize: 9, letterSpacing: 0.6, color: C.muted }}>{label}</span> | |
| {Icon && <Icon size={14} color={iconColor || C.muted} />} | |
| </div> | |
| <div className={grad ? "hb" : ""} style={{ fontFamily: FD, fontWeight: 700, fontSize: big ? 22 : 26, color: grad ? undefined : (valueColor || C.text), marginTop: 6, lineHeight: 1.1, display: "flex", alignItems: "center", gap: 8 }}> | |
| {big && Icon && <Icon size={20} color={iconColor} />}{value} | |
| </div> | |
| {sub && <div style={{ fontSize: 10.5, color: C.muted, marginTop: 5, lineHeight: 1.4 }}>{sub}</div>} | |
| </div> | |
| ); | |
| } | |
| // PEAK CONTEXT — the "fuel gauge" headline: the fullest the live window ever got, | |
| // over the model's limit. Point-in-time, bounded by the window (≤1M) — the opposite | |
| // kind of number from the cumulative cost/cache stats beside it. | |
| function PeakContextCard({ ctx }) { | |
| const pct = Math.round((ctx.peakPct || 0) * 100); | |
| const over = (ctx.overLimit || []).length > 0; | |
| const near = pct >= 80; | |
| const c = over ? C.red : near ? C.amber : C.cyan; | |
| return ( | |
| <div style={{ background: `linear-gradient(135deg,${C.card},${C.panel})`, border: `1px solid ${C.borderSoft}`, borderRadius: 10, padding: "13px 15px" }}> | |
| <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> | |
| <span style={{ fontFamily: FM, fontSize: 9, letterSpacing: 0.6, color: C.muted }}>PEAK CONTEXT</span> | |
| <Gauge size={14} color={c} /> | |
| </div> | |
| <div style={{ fontFamily: FD, fontWeight: 700, fontSize: 22, color: c, marginTop: 6, lineHeight: 1.1 }}> | |
| {fmt(ctx.peak || 0)}<span style={{ fontSize: 13, color: C.muted, fontWeight: 500 }}> / {fmt(ctx.limit || 0)}</span> | |
| </div> | |
| <div style={{ height: 6, background: C.black, borderRadius: 3, marginTop: 7, overflow: "hidden" }}> | |
| <div style={{ width: `${Math.min(100, Math.max(2, pct))}%`, height: "100%", background: `linear-gradient(90deg,${c},${c}aa)` }} /> | |
| </div> | |
| <div style={{ fontSize: 10.5, color: C.muted, marginTop: 5, lineHeight: 1.4 }}> | |
| {over ? "⚠ a request exceeded the window — data suspect" : `${pct}% of the window · point-in-time, not cumulative`} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| // COST & CONTEXT — the unified token story in one card. LEFT: cumulative cost | |
| // breakdown (no ceiling). RIGHT: the point-in-time window gauge + trajectory (≤1M). | |
| // The side-by-side contrast IS the point — cumulative ≠ window occupancy. | |
| function CostContextCard({ S, parts, totalCost, driver, ctx, reqs, onOpenTurn }) { | |
| return ( | |
| <div style={{ marginTop: 12 }}> | |
| <Card icon={Coins} title="COST & CONTEXT — THE TOKEN STORY"> | |
| <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(290px,1fr))", gap: 22 }}> | |
| {/* LEFT — cumulative spend */} | |
| <div> | |
| <SubHead text="WHY IT COST · cumulative tokens" /> | |
| {/* Whole phrase is the hover target — the native `title` lives on this | |
| <span> (a `title` on an inline <svg> icon does NOT show a tooltip in | |
| Chrome). Dotted underline signals it's hoverable. */} | |
| <div style={{ fontSize: 12.5, color: C.text2, margin: "8px 0 10px" }}> | |
| Total: <b style={{ color: C.orange }}>{fmt(S.cost || 0)}</b>{" "} | |
| <span | |
| title={ | |
| `HOW IT'S COMPUTED\n` + | |
| `cost-weighted tokens = fresh-input ×1 + cache-write ×1.25 + cache-read ×0.1 + generated ×5\n` + | |
| `(Anthropic's uniform price ratios), summed across all ${reqs} round-trips.\n` + | |
| `A relative spend proxy in input-token-equivalents — multiply by your input $/token for dollars.\n\n` + | |
| `WHY IT'S NOT THE CONTEXT WINDOW\n` + | |
| `This is CUMULATIVE and has no ceiling, so it routinely dwarfs the window. ` + | |
| `The context window here is ${fmt(ctx.limit || 0)} (point-in-time, bounded — see the gauge on the right). ` + | |
| `${fmt(S.cost || 0)} cost-weighted tokens is the running sum over every round-trip, NOT how full the ${fmt(ctx.limit || 0)} window got — different quantities.` | |
| } | |
| style={{ color: C.muted, cursor: "help", borderBottom: `1px dotted ${C.muted}` }}> | |
| cost-weighted tokens (not $) <Info size={11} color={C.muted} style={{ verticalAlign: "-1px" }} /> | |
| </span> | |
| </div> | |
| {parts.map((p) => { | |
| const pct = Math.round((100 * p.cost) / totalCost); | |
| return ( | |
| <div key={p.label} style={{ marginTop: 8 }}> | |
| <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11.5 }}> | |
| <span style={{ color: C.text2 }}>{p.label}</span> | |
| <span style={{ fontFamily: FM, color: C.muted }}>{fmt(p.raw)} <span style={{ color: p.c }}>({pct}%)</span></span> | |
| </div> | |
| <div style={{ height: 6, background: C.black, borderRadius: 3, marginTop: 4, overflow: "hidden" }}> | |
| <div style={{ width: `${Math.max(1, pct)}%`, height: "100%", background: `linear-gradient(90deg,${p.c},${p.c}aa)` }} /> | |
| </div> | |
| </div> | |
| ); | |
| })} | |
| <div style={{ display: "flex", gap: 7, marginTop: 12, fontSize: 11.5, color: C.text2, lineHeight: 1.5, background: C.black, border: `1px solid ${C.borderSoft}`, borderRadius: 7, padding: "9px 10px" }}> | |
| <Lightbulb size={13} color={C.amber} style={{ flexShrink: 0, marginTop: 1 }} /> | |
| <span><b style={{ color: driver.c }}>{driver.label}</b> dominates cost ({Math.round((100 * driver.cost) / totalCost)}%){driver.label === "Cache re-reads" ? ` — the conversation re-read from cache on every round-trip, summed across all ${reqs}. Cumulative spend, not window size.` : "."}</span> | |
| </div> | |
| </div> | |
| {/* RIGHT — point-in-time window */} | |
| <div style={{ borderLeft: `1px solid ${C.borderSoft}`, paddingLeft: 22 }}> | |
| <SubHead text="CONTEXT WINDOW · point-in-time fill" /> | |
| <div style={{ marginTop: 8 }}> | |
| <ContextTrajectory ctx={ctx} reqs={reqs} onOpenTurn={onOpenTurn} /> | |
| </div> | |
| </div> | |
| </div> | |
| </Card> | |
| </div> | |
| ); | |
| } | |
| function SubHead({ text }) { | |
| return <div style={{ fontFamily: FM, fontSize: 9.5, letterSpacing: 0.6, color: C.muted, textTransform: "uppercase" }}>{text}</div>; | |
| } | |
| // CONTEXT WINDOW trajectory — an area chart of how full the live window got per turn | |
| // (the gauge over time), with compaction markers (sharp drops) and the 1M ceiling. | |
| function ContextTrajectory({ ctx, reqs, onOpenTurn }) { | |
| const traj = ctx.trajectory || []; | |
| const limit = ctx.limit || 1e6; | |
| const compactTurns = new Set((ctx.compactions || []).map((c) => c.atTurn)); | |
| const W = 300, H = 84, n = traj.length; | |
| if (!n) return <Empty text="No per-request token usage in this session." />; | |
| const x = (i) => (n === 1 ? W / 2 : (i / (n - 1)) * W); | |
| const y = (v) => H - Math.min(1, v / limit) * H; | |
| const pts = traj.map((e, i) => `${x(i).toFixed(1)},${y(e.end).toFixed(1)}`); | |
| const area = `M0,${H} L${pts.join(" L")} L${W},${H} Z`; | |
| const line = `M${pts.join(" L")}`; | |
| const over = (ctx.overLimit || []).length > 0; | |
| const peakPct = Math.round((ctx.peakPct || 0) * 100); | |
| return ( | |
| <div> | |
| <div style={{ fontSize: 11.5, color: C.text2, marginBottom: 8, lineHeight: 1.5 }}> | |
| Peak fill <b style={{ color: peakPct >= 80 ? C.amber : C.cyan }}>{fmt(ctx.peak || 0)}</b> of {fmt(limit)} (<b>{peakPct}%</b>). The live window — bounded by {fmt(limit)} — across {reqs} round-trips. Not the cumulative totals. | |
| </div> | |
| <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{ width: "100%", height: 84, display: "block" }}> | |
| {/* 1M ceiling */} | |
| <line x1="0" y1="1" x2={W} y2="1" stroke={C.red} strokeWidth="1" strokeDasharray="3 3" opacity="0.5" /> | |
| {/* 80% line */} | |
| <line x1="0" y1={H * 0.2} x2={W} y2={H * 0.2} stroke={C.amber} strokeWidth="0.75" strokeDasharray="2 4" opacity="0.4" /> | |
| <path d={area} fill={`${C.cyan}22`} /> | |
| <path d={line} fill="none" stroke={over ? C.red : C.cyan} strokeWidth="1.5" /> | |
| {/* compaction markers */} | |
| {traj.map((e, i) => compactTurns.has(e.i) ? ( | |
| <line key={e.i} x1={x(i)} y1="0" x2={x(i)} y2={H} stroke={C.orange} strokeWidth="1.25" strokeDasharray="2 2" /> | |
| ) : null)} | |
| </svg> | |
| <div style={{ display: "flex", justifyContent: "space-between", fontFamily: FM, fontSize: 9, color: C.muted, marginTop: 3 }}> | |
| <span>turn 00</span> | |
| <span>{fmt(limit)} ceiling</span> | |
| <span>turn {String(traj[n - 1].i).padStart(2, "0")}</span> | |
| </div> | |
| <div style={{ display: "flex", gap: 7, marginTop: 10, fontSize: 11.5, color: C.text2, lineHeight: 1.5, background: C.black, border: `1px solid ${C.borderSoft}`, borderRadius: 7, padding: "9px 10px" }}> | |
| <Scissors size={13} color={C.orange} style={{ flexShrink: 0, marginTop: 1 }} /> | |
| {ctx.compactions?.length ? ( | |
| <span><b style={{ color: C.orange }}>{ctx.compactions.length} compaction{ctx.compactions.length === 1 ? "" : "s"}</b> detected — the window was trimmed where it dips.{" "} | |
| {ctx.compactions.map((c) => ( | |
| <span key={c.atTurn} onClick={() => onOpenTurn(c.atTurn)} className="lift" style={{ cursor: "pointer", color: C.orange, fontFamily: FM }}> | |
| #{String(c.atTurn).padStart(2, "0")} ({fmt(c.before)}→{fmt(c.after)}){" "} | |
| </span> | |
| ))} | |
| </span> | |
| ) : ( | |
| <span>No compactions — the window climbed to {peakPct}% and never had to be trimmed.</span> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| function Card({ icon: Icon, title, accent, children }) { | |
| return ( | |
| <div style={{ background: C.panel, border: `1px solid ${C.borderSoft}`, borderRadius: 10, padding: "14px 15px" }}> | |
| <div style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: 11 }}> | |
| <Icon size={14} color={accent || C.cyan} /> | |
| <span style={{ fontFamily: FM, fontSize: 10.5, letterSpacing: 0.7, color: accent || C.cyan, fontWeight: 600 }}>{title}</span> | |
| </div> | |
| {children} | |
| </div> | |
| ); | |
| } | |
| function Glance({ icon: Icon, label, value }) { | |
| return ( | |
| <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "5px 0", borderBottom: `1px solid ${C.borderSoft}` }}> | |
| <Icon size={13} color={C.muted} /> | |
| <span style={{ fontSize: 12, color: C.muted, flex: 1 }}>{label}</span> | |
| <span style={{ fontFamily: FM, fontSize: 11.5, color: C.text2, textAlign: "right", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: 200 }}>{value}</span> | |
| </div> | |
| ); | |
| } | |
| function AttrBadge({ attribution, scoped }) { | |
| const generally = attribution && attribution !== "Anthropic"; | |
| return ( | |
| <span title={generally ? "A widely-recommended practice (not Anthropic-specific)" : "From Anthropic's Claude Code best practices"} | |
| style={{ fontFamily: FM, fontSize: 8, letterSpacing: 0.3, color: generally ? C.amber : C.cyan, border: `1px solid ${generally ? C.amber : C.cyan}`, borderRadius: 4, padding: "1px 5px" }}> | |
| {generally ? "GENERALLY RECOMMENDED" : "ANTHROPIC"} | |
| </span> | |
| ); | |
| } | |
| function Empty({ text }) { | |
| return <div style={{ fontSize: 12, color: C.muted, padding: "4px 0" }}>{text}</div>; | |
| } | |
| // ---------- helpers --------------------------------------------------------- | |
| function sentences(text) { | |
| return String(text || "") | |
| .split(/(?<=[.!?])\s+/) | |
| .map((s) => s.trim()) | |
| .filter((s) => s.length > 2) | |
| .slice(0, 6); | |
| } | |
| function firstClause(p) { | |
| const s = String(p || "").replace(/\s+/g, " ").trim(); | |
| return s.length > 48 ? s.slice(0, 48) + "…" : s || "(turn)"; | |
| } | |
| function clip(s, n) { | |
| s = String(s || ""); | |
| return s.length > n ? s.slice(0, n).trimEnd() + "…" : s; | |
| } | |
| function modelLabel(m) { | |
| if (!m) return "—"; | |
| return String(m).replace(/^claude-/, "Claude ").replace(/-(\d{8})$/, "").replace(/-/g, " "); | |
| } | |
| // Leading glyph for a Tools-Discovered chip: binaries get their logo (monogram | |
| // fallback); skills/plugins, sub-agents, and MCP servers get a typed icon. | |
| function toolGlyph(t) { | |
| if (t.glyph === "binary") return <BinaryLogo b={t} size={14} />; | |
| if (t.glyph === "mcp") return <Network size={13} color={C.cyan} />; | |
| if (t.glyph === "skill") return <Boxes size={13} color={C.amber} />; | |
| return <Bot size={13} color={C.blue} />; // agent / workflow | |
| } | |