build-small-hackathon/the-apprentice
1
1"""Curate a session trace into a publishable sample.2 3Reads the most-recent oracles-trace-*.jsonl from the traces/ dir and4writes a copy into traces/sample/ under a friendlier filename. The5sample is then committed alongside the repo as the Sharing-is-Caring6badge deliverable.7 8Usage:9 cd oracles_app10 ../.venv/bin/python scripts/curate_trace.py \\11 --label fantasy-en-playthrough12"""13 14from __future__ import annotations15 16import argparse17import json18import shutil19import sys20from pathlib import Path21 22_HERE = Path(__file__).resolve().parent23_APP_ROOT = _HERE.parent24_TRACES_DIR = _APP_ROOT / "traces"25_SAMPLE_DIR = _TRACES_DIR / "sample"26 27 28def _newest_session_trace() -> Path:29 candidates = sorted(30 _TRACES_DIR.glob("oracles-trace-*.jsonl"),31 key=lambda p: p.stat().st_mtime,32 reverse=True,33 )34 if not candidates:35 sys.exit(36 f"ERROR: no session traces found in {_TRACES_DIR}. "37 "Run the app first and complete at least one trial."38 )39 return candidates[0]40 41 42def _summarize(path: Path) -> dict:43 """Quick stats so the user can sanity-check before committing."""44 stats: dict = {45 "n_records": 0,46 "modes": {},47 "models_requested": {},48 "models_returned": {},49 "total_completion_tokens": 0,50 "total_prompt_tokens": 0,51 }52 with path.open() as f:53 for line in f:54 line = line.strip()55 if not line:56 continue57 rec = json.loads(line)58 stats["n_records"] += 159 stats["modes"][rec.get("mode", "?")] = stats["modes"].get(rec.get("mode", "?"), 0) + 160 mr = rec.get("model_requested") or rec.get("model", "?")61 stats["models_requested"][mr] = stats["models_requested"].get(mr, 0) + 162 mreturn = rec.get("model_returned", "?")63 stats["models_returned"][mreturn] = stats["models_returned"].get(mreturn, 0) + 164 usage = rec.get("usage") or {}65 stats["total_prompt_tokens"] += int(usage.get("prompt_tokens", 0) or 0)66 stats["total_completion_tokens"] += int(usage.get("completion_tokens", 0) or 0)67 return stats68 69 70def main() -> int:71 ap = argparse.ArgumentParser(description=__doc__)72 ap.add_argument(73 "--label", default=None,74 help="Label to embed in the output filename "75 "(default: derived from the source filename).",76 )77 ap.add_argument(78 "--source", default=None,79 help="Specific source trace path. Default = newest in traces/.",80 )81 ap.add_argument(82 "--summary-only", action="store_true",83 help="Print stats and exit without copying.",84 )85 args = ap.parse_args()86 87 src = Path(args.source) if args.source else _newest_session_trace()88 if not src.exists():89 sys.exit(f"ERROR: source not found: {src}")90 if not src.is_file():91 sys.exit(f"ERROR: source is not a file: {src}")92 93 stats = _summarize(src)94 print(f"Source: {src}")95 print(f"Records: {stats['n_records']}")96 print(f"Modes: {stats['modes']}")97 print(f"Models requested: {stats['models_requested']}")98 print(f"Models returned: {stats['models_returned']}")99 print(f"Prompt tokens used: {stats['total_prompt_tokens']}")100 print(f"Output tokens used: {stats['total_completion_tokens']}")101 102 if args.summary_only:103 return 0104 105 _SAMPLE_DIR.mkdir(parents=True, exist_ok=True)106 label = args.label or src.stem.replace("oracles-trace-", "session-")107 dst = _SAMPLE_DIR / f"{label}.jsonl"108 if dst.exists():109 print(f"\nWARN: {dst} already exists — overwriting.", file=sys.stderr)110 shutil.copy2(src, dst)111 print(f"\nCopied to: {dst}")112 print(f"\nNext steps:")113 print(f" git add {dst.relative_to(_APP_ROOT.parent)}")114 print(f" git commit -m 'Add sample LLM trace from playthrough'")115 print(f" git push")116 return 0117 118 119if __name__ == "__main__":120 sys.exit(main())121 