SPB Git

spb/wp29_uqo

Public
7.2 KB · 85 lines python
1"""Minimal evidence viewer / status dashboard over the real state store (standard library HTTP server, read-only).2Run: PYTHONPATH=src python -m pgar.evidence_viewer [--port 8765] [--db runs/state.sqlite]3Pages: /            run table (status, cost, success) with live counts4       /run/<id>    run manifest, sessions, gate receipts, review, evaluation receipt, event stream5       /events/<id> raw-ish event list6The HTML is a plain rendering of database rows; it is NOT an imitation of a terminal or of the Claude Code UI.7"""8from __future__ import annotations9import argparse, html, json, os, sqlite3, datetime10from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer1112DB = None13STYLE = "<style>body{font-family:-apple-system,Helvetica,Arial,sans-serif;font-size:13px;margin:16px;color:#111}table{border-collapse:collapse}td,th{border:1px solid #ccc;padding:3px 6px;vertical-align:top}th{background:#f2f2f2;text-align:left}.ok{color:#0a7a2f}.bad{color:#b00020}.mono{font-family:Menlo,monospace;font-size:11px;white-space:pre-wrap}h1,h2{margin:8px 0}small{color:#555}</style>"1415def q(sql, args=()):16    c = sqlite3.connect(f"file:{DB}?mode=ro", uri=True, timeout=30); c.row_factory = sqlite3.Row17    try:18        return [dict(r) for r in c.execute(sql, args).fetchall()]19    finally:20        c.close()2122def page(title, body):23    now = datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds")24    return f"<!doctype html><html><head><meta charset='utf-8'><title>{html.escape(title)}</title>{STYLE}</head><body><h1>{html.escape(title)}</h1><small>WP29 PGAR evidence viewer — read-only rendering of {html.escape(DB)} at {now} (dashboard, not a terminal)</small>{body}</body></html>"2526def index():27    runs = q("SELECT r.run_id, r.task_id, r.split, r.treatment, r.repeat_index, r.node, r.status, r.terminal_reason, r.manifest_json, e.scientific_success, e.n_violations, e.quality_json FROM runs r LEFT JOIN evaluations e ON e.run_id=r.run_id ORDER BY r.run_id")28    counts = {}29    for r in runs: counts[r["status"]] = counts.get(r["status"], 0) + 130    ev = q("SELECT COUNT(*) AS n FROM events")[0]["n"]; se = q("SELECT COUNT(*) AS n, COALESCE(SUM(session_cost_usd),0) AS c FROM sessions")[0]31    rows = []32    for r in runs:33        m = json.loads(r["manifest_json"]); u = m.get("usage") or {}34        s = r["scientific_success"]; sc = "" if s is None else (f"<span class='ok'>success</span>" if s else f"<span class='bad'>fail</span>")35        rows.append(f"<tr><td><a href='/run/{r['run_id']}'>{r['run_id']}</a></td><td>{r['task_id']}</td><td>{r['split']}</td><td>{r['treatment']}</td><td>{r['repeat_index']}</td><td>{r['node'] or ''}</td><td>{r['status']}</td><td>{html.escape(str(r['terminal_reason'] or ''))[:60]}</td><td>{u.get('spent_usd', 0):.3f}</td><td>{u.get('n_sessions', '')}</td><td>{sc}</td><td>{'' if r['n_violations'] is None else r['n_violations']}</td></tr>")36    body = (f"<p>Runs: {len(runs)} — " + ", ".join(f"{k}: {v}" for k, v in sorted(counts.items())) + f" — events: {ev} — sessions: {se['n']} — total inference cost (client estimate): {se['c']:.3f} USD</p>"37            "<table><tr><th>run</th><th>task</th><th>split</th><th>arm</th><th>rep</th><th>node</th><th>status</th><th>reason</th><th>USD</th><th>sessions</th><th>science</th><th>viol.</th></tr>" + "".join(rows) + "</table>")38    return page("WP29 experiment status", body)3940def run_page(rid):41    r = q("SELECT * FROM runs WHERE run_id=?", (rid,))42    if not r: return page("not found", "<p>no such run</p>")43    r = r[0]; m = json.loads(r["manifest_json"])44    sess = q("SELECT session_id, role, kind, seq, started_utc, ended_utc, result_subtype, session_cost_usd, num_turns, duration_ms, first_turn_input_tokens, model_reported, exit_code, note FROM sessions WHERE run_id=? ORDER BY seq", (rid,))45    gates = q("SELECT cycle, origin, utc, passed, n_failed, receipt_json FROM gate_receipts WHERE run_id=? ORDER BY id", (rid,))46    revs = q("SELECT utc, verdict, n_issues, review_json FROM reviews WHERE run_id=?", (rid,))47    ev = q("SELECT receipt_json FROM evaluations WHERE run_id=?", (rid,))48    tr = q("SELECT from_status, to_status, utc, note FROM run_transitions WHERE run_id=? ORDER BY id", (rid,))49    events = q("SELECT event_id, seq, received_utc, elapsed_s, event_type, tool_name, status, summary FROM events WHERE run_id=? ORDER BY seq", (rid,))50    def tbl(rows, cols):51        if not rows: return "<p><i>none</i></p>"52        return "<table><tr>" + "".join(f"<th>{c}</th>" for c in cols) + "</tr>" + "".join("<tr>" + "".join(f"<td>{html.escape(str(x.get(c, '')))[:300]}</td>" for c in cols) + "</tr>" for x in rows) + "</table>"53    body = f"<p><a href='/'>← index</a></p><h2>Manifest</h2><div class='mono'>{html.escape(json.dumps({k: v for k, v in m.items() if k != 'usage'}, indent=1, sort_keys=True))}</div>"54    body += "<h2>Resource envelope</h2><div class='mono'>" + html.escape(json.dumps(m.get("usage"), indent=1)) + "</div>"55    body += "<h2>State transitions</h2>" + tbl(tr, ["from_status", "to_status", "utc", "note"])56    body += "<h2>Sessions</h2>" + tbl(sess, ["seq", "session_id", "role", "kind", "started_utc", "ended_utc", "result_subtype", "session_cost_usd", "num_turns", "duration_ms", "first_turn_input_tokens", "model_reported", "exit_code", "note"])57    g2 = []58    for g in gates:59        rec = json.loads(g["receipt_json"]); fails = "; ".join(f"{c['id']}: {c['detail']}" for c in rec.get("checks", []) if not c["passed"])60        g2.append({"cycle": g["cycle"], "origin": g["origin"], "utc": g["utc"], "passed": "PASS" if g["passed"] else "FAIL", "n_failed": g["n_failed"], "failed_checks": fails[:600]})61    body += "<h2>Gate receipts</h2>" + tbl(g2, ["cycle", "origin", "utc", "passed", "n_failed", "failed_checks"])62    body += "<h2>Review</h2>" + ("".join(f"<div class='mono'>{html.escape(x['review_json'])[:4000]}</div>" for x in revs) or "<p><i>none</i></p>")63    body += "<h2>Evaluation receipt (hidden-oracle evaluator, run on the evaluator host)</h2>" + ("".join(f"<div class='mono'>{html.escape(json.dumps(json.loads(x['receipt_json']), indent=1, sort_keys=True))[:12000]}</div>" for x in ev) or "<p><i>not evaluated</i></p>")64    body += f"<h2>Event stream ({len(events)} events)</h2>" + tbl(events, ["event_id", "received_utc", "elapsed_s", "event_type", "tool_name", "status", "summary"])65    return page(f"Run {rid} — {m['task_id']} arm {m['treatment']}", body)6667class H(BaseHTTPRequestHandler):68    def do_GET(self):69        p = self.path.split("?")[0]70        if p == "/": out = index()71        elif p.startswith("/run/"): out = run_page(p[5:])72        else: self.send_response(404); self.end_headers(); return73        b = out.encode(); self.send_response(200); self.send_header("Content-Type", "text/html; charset=utf-8"); self.send_header("Content-Length", str(len(b))); self.end_headers(); self.wfile.write(b)74    def log_message(self, *a): pass7576def main():77    global DB78    ap = argparse.ArgumentParser(); ap.add_argument("--port", type=int, default=8765); ap.add_argument("--db", default=os.path.join(os.path.dirname(__file__), "..", "..", "runs", "state.sqlite"))79    a = ap.parse_args(); DB = os.path.abspath(a.db)80    print(f"evidence viewer on http://127.0.0.1:{a.port}/ over {DB}")81    ThreadingHTTPServer(("127.0.0.1", a.port), H).serve_forever()8283if __name__ == "__main__":84    main()85
Files · 2c82656f6a48d002fcaa9c62ccf1d2b88a2e285b
Menu

Theme