"""Generate testresult.html: every unique activity prompt -> expected intent, model output, executor command (Windows + Pi), device, model status, executor status (real execution for safe read-only actions on this machine, dry-run otherwise). python eval/make_report.py (uses model/ numpy runtime for the curated rows)""" import json, os, sys, html, time, collections, platform as _pf HERE = os.path.dirname(os.path.abspath(__file__)); ROOT = os.path.dirname(HERE) sys.path.insert(0, os.path.join(ROOT, "model")); sys.path.insert(0, os.path.join(ROOT, "executor")) from runtime import CommandModel # noqa from catalog import ACTIONS # noqa import executor as EX # noqa run_dir = sys.argv[1] if len(sys.argv) > 1 else None _sp = os.path.join(run_dir, "eval", "summary.json") if run_dir else os.path.join(HERE, "model_eval_summary.json") summary = json.load(open(_sp)) if os.path.exists(_sp) else {} curated = [json.loads(l) for l in open(os.path.join(HERE, "curated_prompts.jsonl"), encoding="utf-8")] model = CommandModel(os.path.join(ROOT, "model")) esc = lambda s: html.escape(str(s if s is not None else "")) EXEC_HERE = {"sh", "py"} # kinds that can really run on this Linux box rows = []; t_all = time.time(); exec_counts = collections.Counter(); model_ok = 0 for r in curated: out = model.predict(r["text"]); cmd = {k: v for k, v in out.items() if k != "_meta"}; canon = out["_meta"]["canonical"] ok = canon == r["target"]; model_ok += ok plans = {pl: EX.plan(cmd, pl, r["text"]) for pl in ("pi", "win")} ppi = plans["pi"]; st, outp = "", "" if not ppi.supported: st, outp = "n/a on Pi/Linux", ppi.note elif ppi.kind not in EXEC_HERE: st, outp = "dry-run", f"{ppi.kind} step (needs desktop/keyboard); command rendered only" elif ppi.risk != "safe": st, outp = f"dry-run ({ppi.risk}, gated)", "rendered only; UI asks for confirmation before running" elif not ok: st, outp = "skipped (model mismatch)", "not executed because the parse differed from the expected intent" else: res = EX.run(ppi, cmd, dry_run=False); outp = res["output"][:300] st = "executed: tool not on this machine" if ("command not found" in outp or ("No such file" in outp and "/sys/" in outp)) else f"executed: {res['status']}" exec_counts[st.split(":")[0].split(" (")[0]] += 1 rows.append({"text": r["text"], "action": r["action"], "device": r["device"], "risk": r["risk"], "expected": r["target"], "pred": canon, "json": cmd, "ok": ok, "conf": out["_meta"]["confidence"], "cmd_win": plans["win"].command if plans["win"].supported else "— " + plans["win"].note, "cmd_pi": ppi.command if ppi.supported else "— " + ppi.note, "kind_pi": ppi.kind, "exec_status": st, "exec_out": outp}) acc = model_ok / len(rows) def cell_json(j): return "
".join(f"{esc(k)}={esc('••••' if k == 'password' else v)}" for k, v in j.items() if k != "action") summ_rows = "".join(f"{esc(n)}{s['n']}=0.99 else 'y' if s['exact']>=0.95 else 'r'}'>{s['exact']*100:.2f}%{s['action']*100:.2f}%{esc(', '.join(f'{a}→{b} ({n})' for (a,b),n in s['top_confusions'][:5]))}" for n, s in summary.items()) by_risk = collections.Counter(r["risk"] for r in rows); by_dev = collections.Counter(r["device"] for r in rows) table = "".join(f"""{i+1}{esc(r['text'])}{esc(r['action'])}
{esc(ACTIONS[r['action']]['desc'])}
{esc(r['pred'])}
{cell_json(r['json'])}
conf {r['conf']*100:.1f}%
{'PASS' if r['ok'] else 'FAIL'}{'' if r['ok'] else '
expected: '+esc(r['expected'])+'
'} {esc(r['risk'])}
{esc(r['device'])}
Windows
{esc(r['cmd_win'][:400])}
Raspberry Pi [{esc(r['kind_pi'])}]
{esc(r['cmd_pi'][:400])}
{esc(r['exec_status'])}
{esc(r['exec_out'][:300])}
""" for i, r in enumerate(rows)) doc = f"""Union Command Agent — test results

Union Command Agent — test results

generated {time.strftime('%Y-%m-%d %H:%M')} on {esc(_pf.node())} ({esc(_pf.system())}) · model: char-level transformer seq2seq, {sum(v.size for v in model.W.values())/1e6:.2f}M params, grammar-constrained decoding · {len(ACTIONS)} actions
{acc*100:.2f}%unique-activity prompts exact match ({model_ok}/{len(rows)}) — one held-out-template prompt per action
{''.join(f"
=0.99 else 'y' if s['exact']>=0.95 else 'r'}'>{s['exact']*100:.2f}%{esc(n)} exact (n={s['n']})
" for n, s in summary.items() if n in ('val','test_strict','curated_strict','B_golden_final'))}
{len(rows)}activities: safe {by_risk['safe']} · caution {by_risk['caution']} · critical {by_risk['critical']}
{by_dev['both']}/{by_dev['pi']}/{by_dev['windows']}both / Pi-only / Windows-only

Model accuracy per set

exact = full canonical target (action + every slot value) matches. action = action label only. val shares templates with training. test / curated are held-out templates; since v6 the dataset also contains machine paraphrases of templates, so a held-out paraphrase can have a sibling paraphrase in train — test_strict / curated_strict keep only base-template rows (no sibling anywhere in train) and are the honest generalisation numbers. A_* / B_* are the two source projects' own evaluation sets relabelled to the union schema (their label conventions differ from the union in places, so they under-count).

{summ_rows}
setnexactactiontop confusions

Executor status on this machine

Safe, read-only actions whose Pi/Linux command is runnable here were actually executed and their output captured. Caution/critical actions are rendered but gated (the UI asks for confirmation; critical ones require typing the action name). Key/desktop steps need a display. {esc(', '.join(f'{k}: {v}' for k, v in exec_counts.most_common()))}.

Every unique activity ({len(rows)})

{table}
#promptintent (expected)model outputmodelrisk / deviceexecutor commandexecutor status
""" open(os.path.join(HERE, "testresult.html"), "w", encoding="utf-8").write(doc) print(f"curated exact {acc*100:.2f}% ({model_ok}/{len(rows)}); executor: {dict(exec_counts)}; report in {time.time()-t_all:.0f}s -> eval/testresult.html")