Spaces:
Running on Zero
Running on Zero
| import React from "react"; | |
| import { Zap, Box, ArrowRight, CornerDownRight, AlertTriangle, Terminal } from "lucide-react"; | |
| import { C, FD, FM, fmt, toolIcon } from "../theme.js"; | |
| import { Bar, PanelTitle, GeneratedTag, BinaryRow } from "./Primitives.jsx"; | |
| import { turnProse } from "../useAnalysis.js"; | |
| // RIGHT panel. Mirrors the Elastic "powershell.exe detail" idea: full execution | |
| // detail of the selected node. Three states below. | |
| export function SessionDetail({ session }) { | |
| const { tokens } = session; | |
| const ctx = session.context; | |
| return ( | |
| <div style={{ overflowY: "auto", padding: 16 }}> | |
| <PanelTitle icon={Zap} text="SESSION TOKENS (CUMULATIVE)" /> | |
| <Bar label="cache re-reads" v={tokens.cacheRead} max={tokens.cacheRead} c={C.orange} note="summed across every round-trip — the cost driver, not window size" /> | |
| <Bar label="cache write" v={tokens.cacheCreate} max={tokens.cacheRead} c={C.amber} /> | |
| <Bar label="generated" v={tokens.out} max={tokens.cacheRead} c={C.cyan} /> | |
| <Bar label="fresh input" v={tokens.in} max={tokens.cacheRead} c={C.blue} /> | |
| <div style={{ fontSize: 11.5, color: C.text2, marginTop: 10, lineHeight: 1.55 }}> | |
| Cache re-reads are <b style={{ color: C.orange }}>~{Math.round(tokens.cacheRead / Math.max(1, tokens.out))}×</b> generated — cumulative, so they vastly exceed the window. Spend tracks tool-call iterations, not answer length. | |
| </div> | |
| {ctx && ( | |
| <div style={{ fontSize: 11.5, color: C.text2, marginTop: 10, lineHeight: 1.55, background: C.black, border: `1px solid ${C.border}`, borderRadius: 7, padding: "8px 10px" }}> | |
| Peak context window: <b style={{ color: (ctx.peakPct || 0) >= 0.8 ? C.amber : C.cyan }}>{fmt(ctx.peak)} / {fmt(ctx.limit)}</b> ({Math.round((ctx.peakPct || 0) * 100)}%) — the fuel gauge, bounded by the window. {ctx.compactions?.length ? `${ctx.compactions.length} compaction(s).` : "No compactions."} | |
| </div> | |
| )} | |
| <PanelTitle icon={ArrowRight} text="WHO DROVE THE WORK" mt /> | |
| <CausalitySplit direct={session.direct} indirect={session.indirect} /> | |
| <div style={{ fontSize: 11, color: C.muted, marginTop: 8, lineHeight: 1.5 }}> | |
| {Math.round((100 * session.indirect) / Math.max(1, session.direct + session.indirect))}% of tool calls were triggered by the agent's own prior output (proven value-flow). | |
| </div> | |
| </div> | |
| ); | |
| } | |
| export function TurnDetail({ turn, narrated, binaries }) { | |
| const { tokens } = turn; | |
| const prose = turnProse(narrated, turn.i); | |
| // binaries (real tools behind Bash/npx) that fired in THIS turn — filtered from | |
| // the session-level list by the turns each appeared in. | |
| const turnBins = (binaries || []).filter((b) => (b.turns || []).includes(turn.i)); | |
| const a = turn.indirect > turn.direct * 1.5; | |
| const deterministic = [ | |
| `This query set off ${turn.reqs} model round-trip${turn.reqs !== 1 ? "s" : ""} and ${turn.tools.length} tool call${turn.tools.length !== 1 ? "s" : ""}.`, | |
| turn.tools.length | |
| ? a | |
| ? `${turn.indirect} (${Math.round((100 * turn.indirect) / turn.tools.length)}%) were driven by earlier tool output, not your message.` | |
| : `${turn.direct} came from your instruction; ${turn.indirect} followed from earlier output.` | |
| : "", | |
| `Cost is dominated by cache re-reads — ${fmt(tokens.cacheRead)} cached tokens reloaded (cumulative across round-trips), vs ${fmt(tokens.out)} generated.`, | |
| turn.ctxPeak ? `The live context window peaked at ${fmt(turn.ctxPeak)} during this turn (point-in-time, not cumulative).` : "", | |
| ].filter(Boolean).join(" "); | |
| return ( | |
| <div style={{ overflowY: "auto", padding: 16 }}> | |
| <PanelTitle icon={Zap} text="WHY THESE TOKENS" /> | |
| {prose ? ( | |
| <div style={{ marginTop: 10 }}> | |
| <div style={{ marginBottom: 6 }}><GeneratedTag cites={`turn ${turn.i}`} /></div> | |
| <div style={{ fontSize: 13, color: C.text2, lineHeight: 1.6 }}>{prose}</div> | |
| </div> | |
| ) : ( | |
| <div style={{ fontSize: 13, color: C.text2, lineHeight: 1.6, marginTop: 10 }}>{deterministic}</div> | |
| )} | |
| <PanelTitle icon={Box} text="TOKEN BREAKDOWN (CUMULATIVE)" mt /> | |
| <Bar label="cache re-reads" v={tokens.cacheRead} max={tokens.cacheRead} c={C.orange} note="volume = long tool loops · summed across round-trips" /> | |
| <Bar label="cache write" v={tokens.cacheCreate} max={tokens.cacheRead} c={C.amber} /> | |
| <Bar label="generated" v={tokens.out} max={tokens.cacheRead} c={C.cyan} /> | |
| <Bar label="fresh input" v={tokens.in} max={tokens.cacheRead} c={C.blue} /> | |
| <PanelTitle icon={ArrowRight} text="CAUSALITY SPLIT" mt /> | |
| <CausalitySplit direct={turn.direct} indirect={turn.indirect} /> | |
| <div style={{ fontSize: 11, color: C.muted, marginTop: 8, lineHeight: 1.5 }}> | |
| Indirect = the tool's input appeared verbatim in an earlier result (proven). Tap a tool to see its trigger. | |
| </div> | |
| {turnBins.length > 0 && ( | |
| <> | |
| <PanelTitle icon={Terminal} text="BINARIES RUN HERE" mt /> | |
| <div style={{ fontSize: 10.5, color: C.muted, marginTop: 4, lineHeight: 1.5 }}> | |
| The real tools behind this turn's Bash calls — extracted from the command, not just "npx". | |
| </div> | |
| <div style={{ marginTop: 6 }}> | |
| {turnBins.map((b) => <BinaryRow key={b.binary} b={b} />)} | |
| </div> | |
| </> | |
| )} | |
| </div> | |
| ); | |
| } | |
| export function ToolDetail({ tool, onBack }) { | |
| const Icon = toolIcon(tool.name); | |
| const ind = tool.provenance === "indirect"; | |
| const provenFlow = ind && tool.flowValue; | |
| const inputStr = | |
| tool.input && typeof tool.input === "object" | |
| ? JSON.stringify(tool.input, null, 2) | |
| : String(tool.input ?? tool.summary ?? ""); | |
| return ( | |
| <div style={{ overflowY: "auto", padding: 16 }}> | |
| <PanelTitle icon={Icon} text="TOOL DETAIL" /> | |
| <div style={{ fontFamily: FD, fontSize: 15, fontWeight: 600, marginTop: 8, display: "flex", alignItems: "center", gap: 8 }}> | |
| {tool.mcp ? `${tool.mcp.server}:${tool.mcp.tool}` : tool.name} | |
| {tool.errored && ( | |
| <span style={{ fontFamily: FM, fontSize: 9, color: C.red, border: `1px solid ${C.red}`, borderRadius: 4, padding: "1px 6px", display: "inline-flex", alignItems: "center", gap: 4 }}> | |
| <AlertTriangle size={10} /> ERRORED | |
| </span> | |
| )} | |
| </div> | |
| {tool.mcp && ( | |
| <div style={{ fontFamily: FM, fontSize: 9.5, color: C.cyan, marginTop: 6 }}>MCP · {tool.mcp.server}</div> | |
| )} | |
| {/* full input */} | |
| <div style={{ fontFamily: FM, fontSize: 9.5, color: C.muted, marginTop: 12, marginBottom: 4 }}>FULL INPUT</div> | |
| <pre style={{ fontFamily: FM, fontSize: 11, color: C.text2, margin: 0, background: C.black, padding: 10, borderRadius: 7, border: `1px solid ${C.borderSoft}`, whiteSpace: "pre-wrap", wordBreak: "break-word", maxHeight: 220, overflow: "auto", lineHeight: 1.5 }}> | |
| {inputStr} | |
| </pre> | |
| {/* provenance verdict — proven vs hypothesis separated */} | |
| <div style={{ marginTop: 14 }}> | |
| {provenFlow ? ( | |
| <div style={{ background: C.orangeMut, border: `1px solid ${C.orangeBd}`, borderRadius: 8, padding: 12 }}> | |
| <div style={{ color: C.orange, fontWeight: 600, fontSize: 13, display: "flex", alignItems: "center", gap: 7 }}> | |
| <CornerDownRight size={15} /> Indirect — proven value-flow | |
| </div> | |
| <div style={{ fontSize: 12.5, color: C.text2, marginTop: 8, lineHeight: 1.55 }}> | |
| Fired because a value from an earlier <b style={{ color: C.orange }}>{tool.sourceTool}</b> result reappeared <b>verbatim</b> in this input. This is asserted, not inferred. | |
| </div> | |
| <div style={{ marginTop: 10 }}> | |
| <div style={{ fontFamily: FM, fontSize: 9.5, color: C.muted, marginBottom: 4 }}>VALUE THAT FLOWED</div> | |
| <div style={{ fontFamily: FM, fontSize: 11, color: C.orange, background: C.black, padding: "6px 9px", borderRadius: 5, border: `1px solid ${C.orangeBd}`, wordBreak: "break-all" }}> | |
| {tool.flowValue} | |
| </div> | |
| </div> | |
| </div> | |
| ) : ind ? ( | |
| <div style={{ background: C.card, border: `1px dashed ${C.border}`, borderRadius: 8, padding: 12 }}> | |
| <div style={{ color: C.amber, fontWeight: 600, fontSize: 13 }}>Indirect — proximity (hypothesis)</div> | |
| <div style={{ fontSize: 12.5, color: C.text2, marginTop: 8, lineHeight: 1.55 }}> | |
| Likely driven by an earlier <b>{tool.sourceTool || "tool"}</b> result, but no verbatim value was pinned. A hypothesis for you to judge — not asserted. | |
| </div> | |
| </div> | |
| ) : ( | |
| <div style={{ background: C.card, border: `1px solid ${C.border}`, borderRadius: 8, padding: 12 }}> | |
| <div style={{ color: C.text, fontWeight: 600, fontSize: 13 }}>Direct — from your instruction</div> | |
| <div style={{ fontSize: 12.5, color: C.text2, marginTop: 8, lineHeight: 1.55 }}> | |
| No earlier tool result fed this input. It traces to your query. | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| <div onClick={onBack} style={{ marginTop: 14, fontFamily: FM, fontSize: 11, color: C.muted, cursor: "pointer" }}>← back</div> | |
| </div> | |
| ); | |
| } | |
| function CausalitySplit({ direct, indirect }) { | |
| const tot = Math.max(1, direct + indirect); | |
| return ( | |
| <div style={{ display: "flex", height: 26, borderRadius: 7, overflow: "hidden", border: `1px solid ${C.borderSoft}`, marginTop: 8 }}> | |
| <div style={{ width: `${(100 * direct) / tot}%`, background: C.border, display: "flex", alignItems: "center", justifyContent: "center" }}> | |
| {direct > 0 && <span style={{ fontFamily: FM, fontSize: 10, color: C.text }}>{direct} direct</span>} | |
| </div> | |
| <div style={{ width: `${(100 * indirect) / tot}%`, background: `linear-gradient(90deg,${C.orange},${C.orangeHi})`, display: "flex", alignItems: "center", justifyContent: "center" }}> | |
| {indirect > 0 && <span style={{ fontFamily: FM, fontSize: 10, color: "#fff" }}>{indirect} indirect</span>} | |
| </div> | |
| </div> | |
| ); | |
| } | |