import { Fuel, ShieldAlert, Check } from "lucide-react" import { useGovernor } from "@/lib/queries" import type { GovernorRun } from "@/lib/api" // ── Token-Wächter („Tankuhr mit Handbremse") ──────────────────────────────── // Zeigt in Klartext, wie voll die laufende Coding-Sitzung ist. Zwei Marken: // Soft = ab hier bittet der Governor um einen Savepoint (Sitzung sauber beenden) // Hart = ab hier antwortet er selbst und lässt das Modell gar nicht mehr ran // Die Zeile „Schätzung vs. Wahrheit" ist der Ehrlichkeits-Nachweis: bis 25.07. lag der // Governor bei werkzeugdichten Agenten um Faktor 3 daneben, weil er Werkzeug-Schemata // nicht mitzählte. Jetzt lernt er aus den echten prompt_tokens jeder Antwort. const fmtNum = (n: number | null | undefined) => n == null ? "–" : n.toLocaleString("de-DE") function ago(ts: number): string { const s = Math.max(0, Date.now() / 1000 - ts) if (s < 60) return `vor ${Math.round(s)} s` if (s < 3600) return `vor ${Math.round(s / 60)} min` return `vor ${Math.round(s / 3600)} h` } const ACTION_META: Record = { passthrough: { label: "frei", tone: "text-emerald-400" }, defer: { label: "wartet", tone: "text-amber-400" }, soft: { label: "Savepoint", tone: "text-amber-400" }, hard: { label: "STOPP", tone: "text-rose-400" }, } /** Abweichung Schätzung↔Wahrheit in Prozent — der Ehrlichkeits-Messwert. */ function drift(run: GovernorRun | undefined): number | null { if (!run?.est || !run?.exact) return null return ((run.est - run.exact) / run.exact) * 100 } export function GovernorCard() { const { data } = useGovernor() if (!data?.reachable) { return (

Token-Wächter

Nicht erreichbar. Die Coding-Sitzungen laufen dann ohne Sitzungs-Bremse.
{data?.error ?? "keine Antwort von :8100"}
) } const soft = data.soft ?? 0 const hard = data.hard ?? null const runs = data.recent ?? [] // Nur echte Bau-Läufe füllen die Tankuhr; Lucys Gespräche sind ausgenommen. const lastBuild = runs.find((r) => !(data.exempt_models ?? []).includes(r.model)) const füllung = lastBuild?.exact ?? lastBuild?.est ?? 0 const skala = Math.max(hard ?? soft * 1.2, soft * 1.2, füllung) const pct = Math.min(100, (füllung / skala) * 100) const abw = drift(runs.find((r) => r.est != null && r.exact != null)) const c = data.counters const tone = hard && füllung >= hard ? "bg-rose-500" : füllung >= soft ? "bg-amber-500" : "bg-emerald-500" return (

Token-Wächter

live
{fmtNum(füllung)} Tokens in der letzten Bau-Anfrage
Savepoint ab {fmtNum(soft)}
{hard != null && (
Stopp ab {fmtNum(hard)}
)}
{/* Tankuhr */}
{hard != null && (
)}
{/* Zählerstand */}
{[ { k: "Anfragen", v: fmtNum(c?.chat) }, { k: "Savepoints", v: fmtNum(c?.soft) }, { k: "Stopps", v: fmtNum(c?.hard) }, { k: "Tokens ges.", v: fmtNum(c?.tokens_prompt) }, ].map((x) => (
{x.v}
{x.k}
))}
{/* Ehrlichkeits-Nachweis */} {abw != null && (
{Math.abs(abw) < 15 ? : } Schätzung lag{" "} {abw > 0 ? "+" : ""}{abw.toFixed(1)} % {" "} neben der Wahrheit — er kalibriert sich aus jeder Antwort selbst nach.
)} {/* Letzte Läufe */} {runs.length > 0 && (
{runs.slice(0, 5).map((r, i) => { const m = ACTION_META[r.action] ?? { label: r.action, tone: "text-muted-foreground" } return (
{ago(r.t)} {r.model || "?"} {fmtNum(r.exact ?? r.est)} {r.exact != null && r.est != null && ( (geschätzt {fmtNum(r.est)}) )} {m.label}
) })}
)}
Alle Coding-Agenten laufen durch den Wächter (:8100). Lucys Alltagsmodelle sind ausgenommen — ein Gespräch ist keine Bau-Sitzung und wird nie unterbrochen.
) }