#!/usr/bin/env python3 """progress.py [--table] — summarise a pi round from events.jsonl + metrics.json (step table, tokens, tool mix).""" import json, sys, os, datetime d = sys.argv[1]; table = "--table" in sys.argv ev = [] for l in open(os.path.join(d, "events.jsonl"), errors="ignore"): try: ev.append(json.loads(l)) except Exception: pass rows = []; pend = {}; in_tok = out_tok = 0; turns = 0; final = ""; usage = {} for e in ev: t = e.get("type") if t == "message_end" and e["message"]["role"] == "assistant": m = e["message"]; u = m.get("usage", {}); in_tok += u.get("input", 0); out_tok += u.get("output", 0); turns += 1 txt = "".join(c.get("text", "") for c in m["content"] if c["type"] == "text") if txt.strip(): final = txt for c in m["content"]: if c["type"] == "toolCall": usage[c["id"]] = (turns, u.get("input", 0), u.get("output", 0), m.get("timestamp", 0)) if t == "tool_execution_start": pend[e.get("toolCallId")] = (e.get("toolName"), e.get("args") or {}) if t == "tool_execution_end": name, a = pend.pop(e.get("toolCallId"), ("?", {})); tu = usage.get(e.get("toolCallId"), (turns, 0, 0, 0)) r = e.get("result", {}); c = r.get("content") or [{}]; txt = c[0].get("text", "") if c else "" arg = a.get("path") or a.get("command") or ("quick" if name == "verify" else "") rows.append({"turn": tu[0], "in": tu[1], "out": tu[2], "t": tu[3], "tool": name, "arg": str(arg)[:50], "err": bool(r.get("isError")), "res": txt[:90].replace("\n", " | ")}) m = {} try: m = json.load(open(os.path.join(d, "metrics.json"))) except Exception: pass el = m.get("elapsed_s", 0) print(f"turns={turns} steps={len(rows)} in_tok={in_tok} out_tok={out_tok} elapsed={el//60}m{el%60:02d}s reads={m.get('reads')} writes={m.get('writes')} edits={m.get('edits')} appends={m.get('appends')} cargo={m.get('cargo_runs')} verify={m.get('verify_runs')} scope_refusals={m.get('scope_refusals')} oversized={m.get('oversized_writes')} blocked={m.get('blocked_calls')} req_chars_max={m.get('request_chars_max')} marker={m.get('marker')}") if table: for i, r in enumerate(rows, 1): dt = datetime.datetime.fromtimestamp(r["t"] / 1000, datetime.timezone.utc).strftime("%H:%M:%S") print(f"{i:3d} t{r['turn']:<3d}{dt} in={r['in']:6d} out={r['out']:5d} {r['tool']:12s} {r['arg']:50s} {'ERR ' if r['err'] else ''}{r['res']}") if final: print("--- last assistant text ---\n" + final[:1500])