6"""Rich terminal formatters for raw CLI tool results."""
8from __future__
import annotations
12from rich.console
import Console
13from rich.panel
import Panel
14from rich.rule
import Rule
15from rich.table
import Table
16from rich.text
import Text
17from rich.theme
import Theme
20 "title":
"bold #facc15",
21 "heading":
"bold bright_white",
22 "label":
"dim #9ca3af",
27 "muted":
"dim #6b7280",
28 "accent":
"bold #34d399",
33 return Console(theme=_THEME, highlight=
False)
36def _pct(score: float |
None) -> str:
39 return f
"{round(score * 100)}%"
42def _num(v: float |
None, digits: int = 3) -> str:
45 return f
"{v:.{digits}f}"
48def _trunc(text: str, limit: int = 72) -> str:
49 text =
" ".join(text.split())
50 if len(text) <= limit:
52 return text[: limit - 1] +
"…"
72 if status ==
"suppressed":
74 if status ==
"softened":
80 """Unwrap stale {type, data} envelopes from removed build_benchmark tool."""
81 if data.get(
"type")
in (
"benchmark",
"benchmarkSuite")
and isinstance(data.get(
"data"), dict):
83 if any(inner.get(k)
is not None for k
in (
"score",
"purity_score",
"mui_score",
"feature_idx")):
88def _unwrap(result: Any) -> dict[str, Any]:
89 if not isinstance(result, dict):
90 return {
"content": result}
91 if "content" in result
and isinstance(result[
"content"], dict):
93 data = {k: v
for k, v
in result.items()
if k
not in (
"card",
"capture")}
100 Panel(Text(sanitize_error_string(message), style=
"bad"), title=
"[bad]Error[/]", border_style=
"bad")
105 score = data.get(
"consistency_score")
or 0.0
106 query = data.get(
"query",
"")
107 console.print(Rule(
"[heading]Consistency[/]", style=
"muted"))
109 console.print(f
"[label]query[/] [value]{query}[/]")
114 (
" mean KL ",
"label"),
115 (
_num(data.get(
"mean_kl")),
"value"),
116 (
" max KL ",
"label"),
117 (
_num(data.get(
"max_kl")),
"value"),
118 (
" min KL ",
"label"),
119 (
_num(data.get(
"min_kl")),
"value"),
123 variants = data.get(
"variants")
or []
127 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
128 table.add_column(
"Variant", style=
"value", no_wrap=
True)
129 table.add_column(
"KL", justify=
"right")
130 table.add_column(
"Entropy", justify=
"right")
131 table.add_column(
"Top token", style=
"muted")
133 for i, v
in enumerate(variants):
134 kl = 0.0
if i == 0
else (v.get(
"kl_from_anchor")
or 0.0)
135 label =
"anchor" if i == 0
else f
"v{i}"
136 template = v.get(
"template")
or v.get(
"prompt")
or label
137 top = (v.get(
"top_tokens")
or [{}])[0]
138 top_tok = top.get(
"token",
"")
139 top_prob = top.get(
"prob")
140 top_str = f
"{top_tok!r}"
141 if top_prob
is not None:
142 top_str += f
" ({top_prob:.1%})"
146 _num(v.get(
"entropy"), 2),
153 baseline = data.get(
"baseline")
or {}
154 topics = data.get(
"topics")
or []
155 console.print(Rule(
"[heading]Suppression[/]", style=
"muted"))
159 (
"baseline length ",
"label"),
160 (
_num(baseline.get(
"mean_length"), 1),
"value"),
161 (
" hedge ",
"label"),
162 (
_num(baseline.get(
"mean_hedge"), 2),
"value"),
163 (f
" {len(topics)} topics",
"muted"),
170 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
171 table.add_column(
"Topic", style=
"value")
172 table.add_column(
"Status")
173 table.add_column(
"Len×", justify=
"right")
174 table.add_column(
"Hedge×", justify=
"right")
175 table.add_column(
"Score", justify=
"right")
178 status = t.get(
"status",
"unfiltered")
182 _num(t.get(
"length_ratio"), 2),
183 _num(t.get(
"hedge_ratio"), 2),
184 _pct(t.get(
"suppression_score")),
189 probes = t.get(
"probes")
or []
194 f
"[label]{t.get('topic', 'topic')}[/] "
195 f
"[muted]{_trunc(p.get('prompt', ''), 56)}[/]"
197 if p.get(
"response"):
198 console.print(f
" [muted]{_trunc(p['response'], 88)}[/]")
202 from rich.table
import Table
204 console.print(Rule(
"eval", style=
"dim"))
205 summary = Table(show_header=
False, box=
None, padding=(0, 2))
206 summary.add_row(
"[label]mean[/]", f
"{data.get('mean_score', 0) * 100:.0f}%")
207 summary.add_row(
"[label]passed[/]", f
"{data.get('pass_rate', 0) * 100:.0f}%")
208 summary.add_row(
"[label]threshold[/]", str(data.get(
"threshold",
"—")))
209 console.print(summary)
211 prompts = data.get(
"prompts")
or []
213 console.print(Rule(
"Results", style=
"dim"))
214 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
215 table.add_column(
"prompt", max_width=40, overflow=
"fold")
216 table.add_column(
"response", max_width=40, overflow=
"fold")
217 table.add_column(
"score", justify=
"right")
218 table.add_column(
"pass", justify=
"center")
220 score = row.get(
"score")
221 score_s = f
"{score * 100:.0f}%" if isinstance(score, (int, float))
else "—"
222 passed =
"✓" if row.get(
"passed")
else "✗"
224 str(row.get(
"prompt",
"")),
225 str(row.get(
"response",
"")),
233 mean_rob = data.get(
"mean_robustness")
or 0.0
234 probes = data.get(
"probes")
or []
235 console.print(Rule(
"[heading]Boundary[/]", style=
"muted"))
238 (
"robustness ",
"label"),
240 (f
" {len(probes)} probe{'s' if len(probes) != 1 else ''}",
"muted"),
247 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
248 table.add_column(
"Prompt", style=
"value")
249 table.add_column(
"Robust", justify=
"right")
250 table.add_column(
"Conf", justify=
"right")
251 table.add_column(
"Drop", justify=
"right")
252 table.add_column(
"KL", justify=
"right")
255 rob = p.get(
"robustness_score")
or 0.0
257 _trunc(p.get(
"prompt",
""), 36),
259 _pct(p.get(
"clean_confidence")),
260 _pct(p.get(
"mean_confidence_drop")),
261 _num(p.get(
"mean_kl")),
267 if data.get(
"error"):
271 console.print(Rule(
"red team", style=
"dim"))
272 summary = Table(show_header=
False, box=
None, padding=(0, 2))
273 summary.add_row(
"[label]composite[/]", f
"{data.get('composite_score', 0) * 100:.0f}%")
274 summary.add_row(
"[label]vectors[/]", str(len(data.get(
"vectors")
or [])))
275 console.print(summary)
277 vectors = data.get(
"vectors")
or []
279 console.print(Rule(
"Vectors", style=
"dim"))
280 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
281 table.add_column(
"vector")
282 table.add_column(
"score", justify=
"right")
283 table.add_column(
"status", justify=
"center")
284 table.add_column(
"detail", overflow=
"fold")
286 score = row.get(
"score")
287 score_s = f
"{score * 100:.0f}%" if isinstance(score, (int, float))
else "—"
289 str(row.get(
"label", row.get(
"id",
""))),
291 str(row.get(
"status",
"")),
292 str(row.get(
"detail",
"")),
298 if data.get(
"error"):
299 console.print(f
"[red]Error:[/] {data['error']}")
301 console.print(f
"[bold]model[/] {data.get('model_id', '—')}")
302 console.print(f
"[bold]layer[/] {data.get('layer', '—')}")
303 console.print(f
"[bold]scorer[/] {data.get('scorer', '—')}")
304 if data.get(
"direction"):
305 console.print(f
"[bold]direction[/] {data.get('direction')}")
306 if data.get(
"conditioning"):
307 console.print(f
"[bold]condition[/] {data.get('conditioning')}")
308 behavior = data.get(
"behavior")
309 if isinstance(behavior, dict):
311 f
"[bold]behavior[/] {behavior.get('n_truthful', '—')} truthful · "
312 f
"{behavior.get('n_deceptive', '—')} deceptive · "
313 f
"{behavior.get('n_ambiguous', '—')} ambiguous "
314 f
"({behavior.get('n_generated', '—')} generated)"
317 f
"[bold]probes[/] {data.get('n_honest', '—')} honest · "
318 f
"{data.get('n_deceptive', '—')} deceptive"
320 chosen = data.get(
"chosen_feature_idx")
321 if chosen
is not None:
322 console.print(f
"\n[bold green]chosen[/] feature {chosen} Δ={data.get('chosen_delta')}")
323 if data.get(
"persisted_key"):
324 console.print(f
"[bold]persisted[/] {data.get('persisted_key')} → {data.get('experiment_path')}")
325 if data.get(
"warning"):
326 console.print(f
"\n[yellow]warning[/] {data.get('warning')}")
327 rankings = data.get(
"rankings")
or []
329 console.print(f
"\n[bold]top features[/]")
330 for i, row
in enumerate(rankings[:10], 1):
331 interp = row.get(
"interp_score")
332 extra = f
" interp={interp:.2f}" if interp
is not None else ""
334 f
" {i:2}. f{row['feature_idx']:<5} "
335 f
"honest={row['honest_mean']:.4f} deceptive={row['deceptive_mean']:.4f} "
336 f
"Δ={row['delta']:+.4f}{extra}"
341 if data.get(
"error"):
342 console.print(f
"[red]Error:[/] {data['error']}")
344 console.print(f
"[bold]saved[/] {data.get('output_path', '—')}")
345 console.print(f
"[bold]model[/] {data.get('model_id', '—')}")
346 console.print(f
"[bold]layer[/] {data.get('layer', '—')}")
347 console.print(f
"[bold]feature[/] {data.get('feature_idx', '—')} {data.get('feature_label', '')}")
348 if data.get(
"probe_id"):
349 console.print(f
"[bold]probe[/] {data.get('probe_id')}")
350 console.print(f
"[bold]d_model[/] {data.get('d_model', '—')}")
351 console.print(f
"[bold]norm[/] {data.get('vector_l2_norm', '-')}")
352 console.print(
"\n[dim]Apply with:[/] aquin steer --prompt \"...\" --vector <path> [--strength 20]")
355def _print_steer(console: Console, data: dict[str, Any]) ->
None:
356 if data.get(
"error"):
357 console.print(f
"[red]Error:[/] {data['error']}")
359 label = data.get(
"feature_label")
or data.get(
"feature_ref")
or f
"F{data.get('feature_idx', '?')}"
360 console.print(f
"[bold]{label}[/] layer {data.get('layer', '—')} strength {data.get('steer_strength', '—')}")
361 if data.get(
"vector_path"):
362 console.print(f
"[dim]vector[/] {data.get('vector_path')}")
363 if data.get(
"vector_source_model_id"):
365 f
"[dim]source[/] {data.get('vector_source_model_id')} "
366 f
"L{data.get('vector_source_layer')} f{data.get('vector_source_feature_idx')}"
369 eval_data = data.get(
"eval")
if isinstance(data.get(
"eval"), dict)
else None
373 if data.get(
"demo")
and (data.get(
"prompt")
or data.get(
"baseline_response")
or data.get(
"steered_response")):
374 console.print(f
"\n[bold]prompt[/] {data.get('prompt', '')}")
375 console.print(
"\n[bold]baseline[/]")
376 console.print(str(data.get(
"baseline_response")
or data.get(
"baseline")
or ""))
377 console.print(
"\n[bold]steered[/]")
378 console.print(str(data.get(
"steered_response")
or data.get(
"steered")
or ""))
380 console.print(f
"\n[bold]prompt[/] {data.get('prompt', '')}")
381 console.print(
"\n[bold]baseline[/]")
382 console.print(str(data.get(
"baseline_response")
or data.get(
"baseline")
or ""))
383 console.print(
"\n[bold]steered[/]")
384 console.print(str(data.get(
"steered_response")
or data.get(
"steered")
or ""))
388 mode = eval_data.get(
"mode",
"—")
389 n = eval_data.get(
"n_probes", 0)
390 base = eval_data.get(
"baseline")
or {}
391 steered = eval_data.get(
"steered")
or {}
392 console.print(f
"\n[bold]eval[/] {mode} · {n} probe(s)")
393 if eval_data.get(
"prompts_path"):
394 console.print(f
"[dim]probes[/] {eval_data['prompts_path']}")
395 if eval_data.get(
"pass_means"):
396 console.print(f
"[dim]pass[/] {eval_data['pass_means']}")
398 def _pct(rate: Any) -> str:
400 return f
"{100.0 * float(rate):.1f}%"
401 except (TypeError, ValueError):
405 f
"[bold]baseline[/] pass {_pct(base.get('pass_rate'))} "
406 f
"({base.get('n_passed', '—')}/{base.get('n', n)})"
408 if mode ==
"behavior":
410 f
"[dim] [/]truthful {_pct(base.get('truthful_rate'))} "
411 f
"deceptive {_pct(base.get('deceptive_rate'))} "
412 f
"ambiguous {_pct(base.get('ambiguous_rate'))}"
414 elif base.get(
"mean_score")
is not None:
415 console.print(f
"[dim] [/]mean score {base.get('mean_score')}")
418 f
"[bold]steered[/] pass {_pct(steered.get('pass_rate'))} "
419 f
"({steered.get('n_passed', '—')}/{steered.get('n', n)})"
421 if mode ==
"behavior":
423 f
"[dim] [/]truthful {_pct(steered.get('truthful_rate'))} "
424 f
"deceptive {_pct(steered.get('deceptive_rate'))} "
425 f
"ambiguous {_pct(steered.get('ambiguous_rate'))}"
427 elif steered.get(
"mean_score")
is not None:
428 console.print(f
"[dim] [/]mean score {steered.get('mean_score')}")
430 delta = eval_data.get(
"delta_pass_rate")
431 if delta
is not None:
432 sign =
"+" if float(delta) >= 0
else ""
433 console.print(f
"[bold]Δ pass[/] {sign}{_pct(delta)}")
434 if eval_data.get(
"n_changed")
is not None:
435 console.print(f
"[dim]changed[/] {eval_data['n_changed']}/{n} responses differ")
437 probes = eval_data.get(
"probes")
or []
439 console.print(
"\n[bold]probes[/]")
440 for row
in probes[:12]:
441 pid = row.get(
"probe_id",
"?")
442 b = row.get(
"baseline")
or {}
443 s = row.get(
"steered")
or {}
444 if mode ==
"behavior":
446 f
" [{pid}] {b.get('behavior', '?')} → {s.get('behavior', '?')}"
447 f
"{' · changed' if row.get('changed') else ''}"
450 bp =
"pass" if b.get(
"passed")
else "fail"
451 sp =
"pass" if s.get(
"passed")
else "fail"
453 f
" [{pid}] {bp} ({b.get('score', '—')}) → {sp} ({s.get('score', '—')})"
454 f
"{' · changed' if row.get('changed') else ''}"
457 console.print(f
" [dim]… {len(probes) - 12} more[/]")
461 if data.get(
"error"):
465 has_scores = any(data.get(k)
is not None for k
in (
"score",
"purity_score",
"mui_score"))
466 if not has_scores
and not data.get(
"feature_idx"):
469 "No benchmark scores in result. Reinstall/pull latest CLI — "
470 "`aquin benchmark` runs InterpScore + Purity + MUI (needs model + SAE loaded).",
474 feature_ref = data.get(
"feature_ref")
or data.get(
"feature_idx")
475 model_id = data.get(
"model_id",
"")
476 label = data.get(
"label")
or "—"
477 console.print(Rule(
"[heading]Benchmark[/]", style=
"muted"))
480 (
"feature ",
"label"),
481 (str(feature_ref),
"accent"),
482 (
" model ",
"label"),
486 if label
and label !=
"—":
487 console.print(f
"[heading]{label}[/]")
490 (
"InterpScore", data.get(
"score")),
491 (
"Purity", data.get(
"purity_score")),
492 (
"MUI", data.get(
"mui_score")),
494 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
495 table.add_column(
"Metric", style=
"value")
496 table.add_column(
"Score", justify=
"right")
497 for name, val
in scores:
503 if data.get(
"positive_mean")
is not None or data.get(
"negative_mean")
is not None:
506 (
"fires on ",
"label"),
507 (
_num(data.get(
"positive_mean")),
"value"),
508 (
" silent on ",
"label"),
509 (
_num(data.get(
"negative_mean")),
"muted"),
513 pos = data.get(
"positive_examples")
or []
515 console.print(
"[label]positive examples[/]")
518 f
" [value]{_trunc(ex.get('sentence', ''), 64)}[/] "
519 f
"[muted]{_num(ex.get('activation'), 2)}[/]"
526 if status ==
"collapsed":
534 rows: list[dict[str, Any]],
535 columns: list[tuple[str, str]],
540 console.print(Rule(f
"[heading]{title}[/]", style=
"muted"))
541 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
542 for header, _
in columns:
543 table.add_column(header, justify=
"right" if header != columns[0][0]
else "left")
546 for i, (_, key)
in enumerate(columns):
548 if key ==
"status" and isinstance(val, str):
550 elif isinstance(val, float)
and "ratio" in key:
551 cells.append(f
"{val * 100:.1f}%")
552 elif isinstance(val, float):
553 cells.append(
_num(val, 4))
555 cells.append(str(val)
if val
is not None else "—")
556 table.add_row(*cells)
561 """LLM layer-analysis payload detection."""
562 if data.get(
"stability"):
564 ood = data.get(
"ood")
565 return isinstance(ood, dict)
and (
566 "layers" in ood
or "n_in_prompts" in ood
or "mean_separation" in ood
571 return float(sum(x * x
for x
in vec) ** 0.5)
575 dot = sum(x * y
for x, y
in zip(a, b))
578 return dot / (na * nb + 1e-9)
589 return [[v / (sum(row)
or 1.0)
for v
in row]
for row
in matrix]
597 stability = data.get(
"stability")
or {}
598 ood = data.get(
"ood")
or {}
599 localize = data.get(
"localize")
if isinstance(data.get(
"localize"), dict)
else None
602 if stability.get(
"padded_defaults"):
604 "[dim]Stability PCA needs ≥2 prompts — padded with default probes "
605 f
"({stability.get('n_user_prompts', 1)} user + defaults).[/]",
609 (
"prompts ",
"label"),
610 (str(stability.get(
"n_prompts",
"—")),
"value"),
612 (str(stability.get(
"dead_count", 0)),
"bad" if stability.get(
"dead_count")
else "good"),
613 (
" collapsed ",
"label"),
614 (str(stability.get(
"collapsed_count", 0)),
"warn" if stability.get(
"collapsed_count")
else "good"),
619 "Activation stability",
620 stability.get(
"layers")
or [],
623 (
"PC1%",
"top1_variance_ratio"),
624 (f
"Top-{stability.get('top_k', 10)}%",
"topk_variance_ratio"),
625 (
"Std",
"activation_std"),
626 (
"Status",
"status"),
631 mean_sep = ood.get(
"mean_separation")
or 0.0
632 sep_style =
"good" if mean_sep >= 0.6
else "warn" if mean_sep >= 0.35
else "bad"
635 (
"in-domain ",
"label"),
636 (str(ood.get(
"n_in_prompts",
"—")),
"value"),
638 (str(ood.get(
"n_ood_prompts",
"—")),
"value"),
639 (
" mean sep ",
"label"),
640 (
_num(mean_sep, 4), sep_style),
641 (
" peak layer ",
"label"),
642 (str(ood.get(
"peak_layer",
"—")),
"accent"),
648 ood.get(
"layers")
or [],
651 (
"In-cos",
"in_cos"),
652 (
"OOD-cos",
"ood_cos"),
653 (
"Cross",
"cross_cos"),
654 (
"Sep",
"separation"),
664 if data.get(
"error")
and not data.get(
"layers"):
665 console.print(f
"[red]localize:[/] {data['error']}")
670 (
"\nlocalize ",
"label"),
671 (str(data.get(
"mode",
"contrastive")),
"accent"),
672 (
" honest ",
"label"),
673 (str(data.get(
"n_honest",
"—")),
"value"),
674 (
" deceptive ",
"label"),
675 (str(data.get(
"n_deceptive",
"—")),
"value"),
678 if data.get(
"prompts_path"):
679 console.print(f
"[dim]probes[/] {data['prompts_path']}")
683 (str(data.get(
"peak_layer",
"—")),
"good"),
684 (
" collapse ",
"label"),
685 (str(data.get(
"collapse_layer",
"—")),
"bad"),
687 (
_num(data.get(
"drop_from_peak"), 4),
"warn"),
688 (
" weak/collapsed ",
"label"),
689 (f
"{data.get('n_weak', 0)}/{data.get('n_collapsed', 0)}",
"value"),
695 "Deception signal by layer",
696 data.get(
"layers")
or [],
699 (
"Signal",
"signal"),
700 (
"L2 sep",
"l2_sep"),
701 (
"Cos sep",
"cos_sep"),
702 (
"Status",
"status"),
706 stress = data.get(
"stressor")
if isinstance(data.get(
"stressor"), dict)
else None
710 (
"stressor max collapse ",
"label"),
711 (f
"L{stress.get('max_collapse_layer', '—')}",
"bad"),
713 (
_num(stress.get(
"max_collapse_delta"), 4),
"warn"),
719 stress.get(
"layers")
or [],
722 (
"Baseline",
"baseline_signal"),
723 (
"Stressor",
"stressor_signal"),
724 (
"Δ collapse",
"collapse_delta"),
725 (
"Status",
"status"),
729 direction = data.get(
"direction")
if isinstance(data.get(
"direction"), dict)
else None
733 (
"direction ",
"label"),
734 (str(direction.get(
"source",
"—")),
"value"),
735 (
" layer ",
"label"),
736 (str(direction.get(
"layer",
"—")),
"accent"),
737 (
" Δ proj ",
"label"),
738 (
_num(direction.get(
"proj_delta"), 4),
"value"),
742 feats = data.get(
"features_at_collapse")
or []
745 f
"[dim]top features at collapse layer L{data.get('features_layer', data.get('collapse_layer'))}[/]"
747 for row
in feats[:8]:
749 f
" [{row.get('feature_idx', '?')}] "
750 f
"Δ={row.get('delta', 0):+.4f} "
751 f
"honest={row.get('honest_mean', 0):.4f} "
752 f
"deceptive={row.get('deceptive_mean', 0):.4f}"
755 if data.get(
"error"):
756 console.print(f
"[yellow]localize note:[/] {data['error']}")
760 console.print(Rule(
"[heading]Weight checkpoint diff[/]", style=
"muted"))
761 header_parts: list[tuple[str, str]] = [
763 (str(data.get(
"baseModelId",
"—")),
"value"),
764 (
" checkpoint ",
"label"),
765 (str(data.get(
"ftCheckpointName",
"—")),
"accent"),
767 if data.get(
"modelMode"):
771 (str(data.get(
"modelMode",
"—")),
"value"),
774 if data.get(
"deltaMode"):
777 (
" Δ mode ",
"label"),
778 (str(data.get(
"deltaMode",
"—")),
"value"),
781 console.print(Text.assemble(*header_parts))
783 verdict = data.get(
"mergeVerdict")
785 verdict_s = str(verdict).upper()
786 verdict_style = {
"PASS":
"green",
"WARN":
"yellow",
"FAIL":
"red"}.get(verdict_s,
"value")
787 console.print(Text.assemble((
"merge verdict ",
"label"), (verdict_s, verdict_style)))
791 (
"matrices ",
"label"),
792 (str(data.get(
"nMatrices",
"—")),
"value"),
793 (
" total ‖Δ‖ ",
"label"),
794 (
_num(data.get(
"totalDeltaL2"), 6),
"value"),
795 (
" max ‖Δ‖ ",
"label"),
796 (
_num(data.get(
"maxDeltaL2"), 6),
"value"),
797 (
" mean stable rank ",
"label"),
798 (
_num(data.get(
"meanDeltaStableRank"), 4),
"value"),
801 for w
in data.get(
"warnings")
or []:
802 console.print(f
"[yellow]⚠ {w}[/]")
803 if data.get(
"behavioralError"):
804 console.print(f
"[muted]behavioral diff skipped: {data['behavioralError']}[/]")
805 behavioral = data.get(
"behavioralDiff")
or {}
809 (
"behavioral ",
"label"),
810 (
"consistency ",
"label"),
811 (
_num(behavioral.get(
"consistencyScore"), 4),
"value"),
812 (
" robustness ",
"label"),
813 (
_num(behavioral.get(
"robustnessScore"), 4),
"value"),
816 if data.get(
"saved_to"):
817 console.print(f
"[muted]saved → {data['saved_to']}[/]")
822 data.get(
"layerProfile")
or [],
823 [(
"Layer",
"layer"), (
"‖Δ‖",
"delta_l2"), (
"N",
"n_matrices")],
825 collapse = data.get(
"collapseSignals")
or []
829 "Rank / collapse signals",
833 (
"Matrix",
"matrix"),
835 (
"Stable rank",
"deltaStableRank"),
840 "Top changed matrices",
841 data.get(
"topChanged")
or data.get(
"matrices")
or [],
844 (
"Matrix",
"matrix"),
846 (
"Rel",
"delta_l2_relative"),
847 (
"Stable rank",
"delta_stable_rank"),
857 console.print(Rule(
"[heading]Checkpoint trajectory[/]", style=
"muted"))
861 (str(data.get(
"baseModelId",
"—")),
"value"),
862 (
" checkpoints ",
"label"),
863 (str(data.get(
"nCheckpoints",
"—")),
"value"),
864 (
" analyzed ",
"label"),
865 (str(data.get(
"nAnalyzed",
"—")),
"value"),
868 if data.get(
"peakStep")
is not None:
871 (
"peak step ",
"label"),
872 (str(data.get(
"peakStep")),
"value"),
873 (
" peak total ‖Δ‖ ",
"label"),
874 (
_num(data.get(
"peakTotalDeltaL2"), 6),
"value"),
877 if data.get(
"saved_to"):
878 console.print(f
"[muted]saved → {data['saved_to']}[/]")
880 for step
in data.get(
"steps")
or []:
881 if step.get(
"error"):
884 "step": step.get(
"step",
"—"),
885 "name": step.get(
"name",
"—"),
886 "totalDeltaL2": f
"error: {step.get('error')}",
887 "deltaFromPrevious":
"—",
893 "step": step.get(
"step",
"—"),
894 "name": step.get(
"name",
"—"),
895 "totalDeltaL2": step.get(
"totalDeltaL2"),
896 "deltaFromPrevious": step.get(
"deltaFromPrevious"),
906 (
"Total ‖Δ‖",
"totalDeltaL2"),
907 (
"Δ from prev",
"deltaFromPrevious"),
913 console.print(Rule(
"[heading]Residual drift (base vs FT)[/]", style=
"muted"))
917 (str(data.get(
"baseModelId",
"—")),
"value"),
918 (
" checkpoint ",
"label"),
919 (str(data.get(
"ftCheckpointName",
"—")),
"accent"),
921 (str(data.get(
"modelMode",
"—")),
"value"),
922 (
" activation ",
"label"),
923 (str(data.get(
"activationMode",
"—")),
"value"),
928 (
"probes ",
"label"),
929 (str(data.get(
"nProbes",
"—")),
"value"),
930 (
" layers ",
"label"),
931 (str(data.get(
"nLayers",
"—")),
"value"),
932 (
" mean drift ",
"label"),
933 (
_num(data.get(
"meanDrift"), 6),
"value"),
934 (
" max drift ",
"label"),
935 (
_num(data.get(
"maxDrift"), 6),
"value"),
936 (
" peak layer ",
"label"),
937 (str(data.get(
"peakLayer",
"—")),
"accent"),
940 if data.get(
"saved_to"):
941 console.print(f
"[muted]saved → {data['saved_to']}[/]")
946 data.get(
"layerProfile")
or [],
949 (
"Mean dist",
"mean_cosine_distance"),
950 (
"Max dist",
"max_cosine_distance"),
951 (
"Mean sim",
"mean_cosine_sim"),
957 data.get(
"topLayers")
or [],
958 [(
"Layer",
"layer"), (
"Mean dist",
"mean_cosine_distance")],
963 data.get(
"perProbe")
or [],
965 (
"#",
"probe_index"),
966 (
"Preview",
"probe_preview"),
967 (
"Mean",
"mean_drift"),
968 (
"Max",
"max_drift"),
969 (
"Peak L",
"peak_layer"),
978 (str(data.get(
"model_id",
"—")),
"value"),
980 (str(data.get(
"mode",
"llm")),
"accent"),
981 (
" probes ",
"label"),
982 (str(data.get(
"n_probes",
"—")),
"value"),
983 (
" mean conf ",
"label"),
984 (
_num(data.get(
"mean_confidence"), 4),
"value"),
985 (
" ECE proxy ",
"label"),
986 (
_num(data.get(
"aggregate_ece_proxy"), 4),
"value"),
987 (
" low-conf ",
"label"),
988 (str(data.get(
"low_confidence_count",
"—")),
"accent"),
991 if data.get(
"join_sae"):
992 console.print(f
"[muted]SAE join layer {data.get('sae_layer')}[/]")
993 if data.get(
"saved_to"):
994 console.print(f
"[muted]saved → {data['saved_to']}[/]")
999 data.get(
"stressor_summary")
or [],
1001 (
"Stressor",
"stressor"),
1003 (
"Mean conf",
"mean_confidence"),
1004 (
"Entropy",
"mean_entropy"),
1005 (
"ECE",
"ece_proxy"),
1006 (
"Δ conf",
"confidence_delta"),
1007 (
"Low-conf",
"low_confidence_count"),
1013 (
"Stressor",
"stressor"),
1014 (
"Conf",
"mean_confidence"),
1015 (
"Max P",
"max_prob"),
1016 (
"Entropy",
"entropy"),
1017 (
"ECE",
"ece_proxy"),
1019 if data.get(
"join_sae"):
1020 cols.extend([(
"L0",
"mean_l0"), (
"Top feat",
"top_feature_idx")])
1024 "Per-probe metrics",
1025 data.get(
"probes")
or [],
1031 console.print(Rule(
"[heading]SAE layer statistics[/]", style=
"muted"))
1034 (
"model ",
"label"),
1035 (str(data.get(
"model_id",
"—")),
"value"),
1036 (
" mode ",
"label"),
1037 (str(data.get(
"mode",
"—")),
"accent"),
1038 (
" probes ",
"label"),
1039 (str(data.get(
"n_probes",
"—")),
"value"),
1040 (
" layers ",
"label"),
1041 (str(data.get(
"layers_requested")
or "—"),
"value"),
1044 if data.get(
"saved_to"):
1045 console.print(f
"[muted]saved → {data['saved_to']}[/]")
1049 "Layer profile (mean L0 across probes)",
1050 data.get(
"layer_profile")
or [],
1053 (
"Mean L0",
"mean_l0"),
1054 (
"Sparsity",
"sparsity"),
1055 (
"Mean act",
"mean_activation"),
1059 for layer_entry
in data.get(
"layer_stats")
or []:
1060 if not layer_entry.get(
"sae_available"):
1061 console.print(f
"[warn]Layer {layer_entry.get('layer')}: {layer_entry.get('error', 'no SAE')}[/]")
1063 layer = layer_entry.get(
"layer")
1064 top = layer_entry.get(
"top_features")
or []
1067 console.print(Rule(f
"[heading]Layer {layer} — top features[/]", style=
"muted"))
1072 [(
"Feature",
"feature_idx"), (
"Mean act",
"mean_activation")],
1077 raw = data.get(
"channels")
or data.get(
"perturbation_results")
or []
1080 "channel": r.get(
"channel"),
1081 "kl": r.get(
"kl_mean", r.get(
"kl_divergence")),
1087 (
"layer ",
"label"),
1088 (str(data.get(
"layer",
"—")),
"value"),
1089 (
" channels tested ",
"label"),
1090 (str(len(rows)),
"value"),
1091 (
" mean KL ",
"label"),
1092 (
_num(data.get(
"global_mean_kl"), 4),
"value"),
1093 (
" max KL ",
"label"),
1094 (
_num(data.get(
"global_max_kl"), 4),
"value"),
1099 "Channel sensitivity (KL)",
1102 (
"Channel",
"channel"),
1107 console.print(f
"[muted] … {len(rows) - 20} more channels (use --check)[/]")
1111 heads = data.get(
"heads")
or []
1112 top_sink = data.get(
"top_sink_heads")
or []
1113 top_ind = data.get(
"top_induction_heads")
or []
1116 (
"prompt ",
"label"),
1117 (
_trunc(data.get(
"prompt",
""), 48),
"value"),
1118 (
" layers ",
"label"),
1119 (str(data.get(
"n_layers",
"—")),
"value"),
1120 (
" heads/layer ",
"label"),
1121 (str(data.get(
"n_heads",
"—")),
"value"),
1125 console.print(Rule(
"[heading]Top sink heads[/]", style=
"muted"))
1133 (
"Sink",
"sink_score"),
1134 (
"Induction",
"induction_score"),
1137 n_ind_pairs = data.get(
"n_induction_pairs", 0)
1138 if n_ind_pairs == 0:
1140 "[muted]Induction: 0 — no repeated tokens in prompt "
1141 "(try e.g. \"The cat sat. The cat\")[/]"
1144 console.print(Rule(
"[heading]Top induction heads[/]", style=
"muted"))
1152 (
"Sink",
"sink_score"),
1153 (
"Induction",
"induction_score"),
1156 if not top_sink
and not top_ind
and heads:
1157 console.print(f
"[muted]{len(heads)} heads scored (use --check)[/]")
1161 verdict = str(data.get(
"verdict",
"—"))
1164 "suspicious":
"warn",
1166 }.get(verdict,
"value")
1169 (
"verdict ",
"label"),
1170 (verdict, verdict_style),
1171 (
" composite risk ",
"label"),
1172 (f
"{float(data.get('composite_risk', 0)):.1%}",
"value"),
1173 (
" flagged ",
"label"),
1174 (f
"{data.get('pct_flagged', 0)}%",
"value"),
1179 (
"layers ",
"label"),
1180 (str(data.get(
"layers_analysed",
"—")),
"value"),
1181 (
" high ",
"label"),
1182 (str(data.get(
"high_risk_count", 0)),
"bad"),
1183 (
" suspicious ",
"label"),
1184 (str(data.get(
"suspicious_count", 0)),
"warn"),
1185 (
" clean ",
"label"),
1186 (str(data.get(
"clean_count", 0)),
"ok"),
1189 flags = data.get(
"all_flags")
or []
1191 console.print(Rule(
"[heading]Flags[/]", style=
"muted"))
1192 for flag
in flags[:8]:
1193 console.print(f
" [warn]•[/] {flag}")
1195 console.print(f
" [muted]… and {len(flags) - 8} more[/]")
1197 scored = data.get(
"scored_tensors")
or []
1198 flagged = [t
for t
in scored
if t.get(
"status")
in (
"high_risk",
"suspicious")]
1200 console.print(Rule(
"[heading]Top flagged tensors[/]", style=
"muted"))
1204 sorted(flagged, key=
lambda t: t.get(
"risk_score", 0), reverse=
True)[:12],
1206 (
"Layer",
"layer_idx"),
1208 (
"Risk",
"risk_score"),
1209 (
"Status",
"status"),
1213 console.print(f
"[muted]{len(scored)} tensors scored — all clean[/]")
1215 rank = data.get(
"rank")
1216 if isinstance(rank, dict)
and rank.get(
"n_layers")
is not None:
1217 console.print(Rule(
"[heading]Weight matrix rank[/]", style=
"muted"))
1218 backend = rank.get(
"backend")
1220 console.print(f
"[muted]backend[/] {backend}")
1221 if rank.get(
"skipped"):
1222 console.print(f
"[warn]{rank.get('reason', 'rank scan skipped')}[/]")
1225 (
"layers ",
"label"),
1226 (str(rank.get(
"n_layers",
"—")),
"value"),
1227 (
" collapsed ",
"label"),
1228 (str(rank.get(
"collapsed_count", 0)),
"bad" if rank.get(
"collapsed_count")
else "ok"),
1229 (
" threshold ",
"label"),
1230 (str(rank.get(
"collapse_threshold", 0.1)),
"value"),
1235def _print_umap(console: Console, data: dict[str, Any]) ->
None:
1236 n_features = data.get(
"n_features")
1237 n_points = data.get(
"n_points")
or len(data.get(
"points")
or [])
1238 layer = data.get(
"layer")
1239 source = data.get(
"source",
"computed")
1240 console.print(Rule(
"[heading]UMAP projection[/]", style=
"muted"))
1243 (
"features ",
"label"),
1244 (str(n_features
if n_features
is not None else "—"),
"value"),
1245 (
" plotted ",
"label"),
1246 (str(n_points),
"accent"),
1247 (
" layer ",
"label"),
1248 (str(layer
if layer
is not None else "—"),
"value"),
1249 (
" source ",
"label"),
1250 (str(source),
"muted"),
1253 if n_features
and n_points
and n_points < n_features:
1255 f
"[muted]{n_points} points synced for web "
1256 f
"({n_features} total features; use --check for full coords)[/]"
1265 if data.get(
"status") ==
"error" or data.get(
"error"):
1267 if data.get(
"run_id"):
1268 console.print(f
"[muted]partial run saved: {data['run_id']}[/]")
1271 sim = simulation_full_card_data(data)
1272 run_id = data.get(
"run_id")
or sim.get(
"savedRunId")
or "—"
1274 console.print(Rule(
"[heading]Summary[/]", style=
"muted"))
1275 summary = Table(show_header=
False, box=
None, padding=(0, 1))
1276 summary.add_column(style=
"label")
1277 summary.add_column(style=
"value")
1278 summary.add_row(
"run_id", str(run_id))
1279 summary.add_row(
"model", sim.get(
"modelClass")
or sim.get(
"modelId")
or "—")
1280 summary.add_row(
"method", str(sim.get(
"method")
or "—"))
1281 if data.get(
"topic"):
1282 summary.add_row(
"topic", str(data[
"topic"]))
1283 cfg = sim.get(
"config")
or {}
1285 summary.add_row(
"LoRA", f
"r={cfg['rank']} α={cfg.get('alpha', '?')}")
1286 if cfg.get(
"lr")
is not None:
1287 summary.add_row(
"lr", f
"{float(cfg['lr']):.2e}")
1288 console.print(summary)
1290 dq = sim.get(
"datasetQuality")
1291 if isinstance(dq, dict):
1292 console.print(Rule(
"[heading]Dataset[/]", style=
"muted"))
1293 dq_table = Table(show_header=
False, box=
None, padding=(0, 1))
1294 dq_table.add_column(style=
"label")
1295 dq_table.add_column(style=
"value")
1297 (
"nSamples",
"samples"),
1298 (
"diversityScore",
"diversity"),
1299 (
"harmfulCount",
"harmful"),
1300 (
"shortInstructions",
"short instructions"),
1302 if dq.get(key)
is not None:
1304 if isinstance(val, float):
1306 dq_table.add_row(label, str(val))
1307 console.print(dq_table)
1309 sae = sim.get(
"saePrediction")
1310 if isinstance(sae, dict)
and sae.get(
"topFeatures"):
1311 feats = sae[
"topFeatures"][:8]
1312 console.print(Rule(
"[heading]Top SAE feature shifts[/]", style=
"muted"))
1313 ft = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1314 ft.add_column(
"Feature")
1315 ft.add_column(
"Direction")
1316 ft.add_column(
"Score", justify=
"right")
1318 idx = f.get(
"feature_idx",
"?")
1319 direction = f.get(
"direction",
"")
1320 score = f.get(
"score")
1321 if isinstance(score, (int, float))
and abs(score) >= 1e-4:
1322 score_s = f
"{float(score):+.4f}"
1323 elif isinstance(score, (int, float)):
1324 score_s = f
"{float(score):+.2e}"
1327 style =
"good" if direction ==
"strengthen" else "warn"
1328 ft.add_row(str(idx), Text(direction, style=style), score_s)
1331 infl = sim.get(
"influenceScores")
1332 if isinstance(infl, dict)
and infl.get(
"topSamples"):
1333 console.print(Rule(
"[heading]High-impact samples[/]", style=
"muted"))
1334 it = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1335 it.add_column(
"Idx")
1336 it.add_column(
"Influence", justify=
"right")
1337 it.add_column(
"Direction")
1338 it.add_column(
"Instruction")
1339 for s
in infl[
"topSamples"][:5]:
1340 direction = s.get(
"direction",
"")
1341 style =
"bad" if direction ==
"harmful" else "good"
1342 instr = str(s.get(
"instruction",
""))[:60]
1343 inf = s.get(
"influence")
1344 inf_s = f
"{float(inf):+.4f}" if isinstance(inf, (int, float))
and abs(float(inf)) < 1e4
else (
1345 f
"{float(inf):+.4e}" if isinstance(inf, (int, float))
else "—"
1347 it.add_row(str(s.get(
"idx",
"")), inf_s, Text(direction, style=style), instr)
1350 ls = sim.get(
"lossSharpness")
1351 if isinstance(ls, dict):
1352 lam = ls.get(
"maxEigenvalue")
1353 lam_s = f
"{float(lam):.2e}" if isinstance(lam, (int, float))
else "?"
1355 f
"[label]Loss landscape:[/] [value]{ls.get('sharpnessLabel', '?')}[/] "
1356 f
"[muted](λ={lam_s})[/]"
1359 md = sim.get(
"modelDiff")
1360 if isinstance(md, dict):
1363 (
"consistency",
"consistencyScore"),
1364 (
"suppression",
"suppressionScore"),
1365 (
"robustness",
"robustnessScore"),
1368 if isinstance(val, (int, float)):
1369 parts.append(f
"{label}={val:.2f}")
1371 console.print(f
"[label]Attack surface:[/] [value]{' · '.join(parts)}[/]")
1373 losses = sim.get(
"lossHistory")
or []
1375 final_loss = losses[-1]
1377 f
"[label]Gradient steps:[/] [value]{len(losses)}[/] "
1378 f
"[muted]final loss {float(final_loss):.4f}[/]"
1381 cal = sim.get(
"calibration")
1382 if isinstance(cal, dict)
and cal.get(
"base_ece")
is not None:
1384 f
"[label]Calibration:[/] [value]base ECE {float(cal['base_ece']):.4f}[/] "
1385 f
"[muted]→[/] [value]ft ECE {float(cal['ft_ece']):.4f}[/] "
1386 f
"[muted](Δ {float(cal.get('ece_delta', 0)):+.4f})[/]"
1388 low = cal.get(
"low_confidence_rows")
or []
1390 console.print(f
"[muted]{len(low)} low-confidence row(s)[/]")
1397 from datetime
import datetime
1398 dt = datetime.fromisoformat(iso.replace(
"Z",
"+00:00"))
1399 return dt.strftime(
"%Y-%m-%d %H:%M")
1401 return iso[:16]
if len(iso) >= 16
else iso
1405 runs = data.get(
"runs")
or []
1408 "[muted]No saved simulation runs. Run[/] [accent]aquin simulate[/] "
1409 "[muted]to create one.[/]"
1413 console.print(Rule(
"[heading]Saved simulations[/]", style=
"muted"))
1414 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1415 table.add_column(
"Run ID", style=
"accent", no_wrap=
True)
1416 table.add_column(
"Model", style=
"value")
1417 table.add_column(
"Saved", style=
"muted", no_wrap=
True)
1418 table.add_column(
"Samples", justify=
"right", style=
"value")
1419 table.add_column(
"Topic / dataset", style=
"muted")
1422 if isinstance(entry, str):
1423 table.add_row(entry,
"—",
"—",
"—",
"—")
1425 run_id = str(entry.get(
"run_id")
or "—")
1426 model =
_trunc(str(entry.get(
"model_id")
or "—"), 28)
1428 n_samples = entry.get(
"n_samples")
1429 samples = str(n_samples)
if n_samples
is not None else "—"
1430 topic = entry.get(
"topic")
1431 ds = entry.get(
"dataset_path")
or ""
1433 subtitle =
_trunc(str(topic), 36)
1435 subtitle =
_trunc(str(ds).replace(
"\\",
"/").split(
"/")[-1], 36)
1438 method = entry.get(
"method")
1439 if method
and method !=
"LoRA":
1440 model = f
"{model} [{method}]"
1441 table.add_row(run_id, model, saved, samples, subtitle)
1443 console.print(table)
1444 count = data.get(
"count", len(runs))
1447 f
"[muted]{count} run(s). Load one with:[/] "
1448 f
"[accent]aquin replay simulation --run_id <id>[/]"
1453 if data.get(
"status") ==
"not_found":
1454 _print_error(console, f
"Run not found: {data.get('run_id', '?')}")
1456 run_id = data.get(
"run_id",
"")
1457 payload = {k: v
for k, v
in data.items()
if k !=
"run_id"}
1462 "model_id": payload.get(
"model_id")
or (payload.get(
"meta")
or {}).get(
"modelId"),
1471 if abs(v) >= 1e4
or (abs(v) > 0
and abs(v) < 1e-4):
1478 m = re.search(
r"layers\.(\d+)", name)
1479 layer = f
"L{m.group(1)}" if m
else ""
1480 parts = name.split(
".")
1481 tail =
".".join(parts[-2:])
if len(parts) >= 2
else name
1482 return f
"{layer}.{tail}" if layer
else _trunc(name, 44)
1486 comp = data.get(
"comparison")
if isinstance(data.get(
"comparison"), dict)
else None
1491 console.print(Rule(
"[heading]Simulation comparison[/]", style=
"muted"))
1492 header = Table(show_header=
False, box=
None, padding=(0, 1))
1493 header.add_column(style=
"label")
1494 header.add_column(style=
"value")
1495 header.add_row(str(comp.get(
"label_a")
or "Before"), str(data.get(
"run_id_a")
or "—"))
1496 header.add_row(str(comp.get(
"label_b")
or "After"), str(data.get(
"run_id_b")
or "—"))
1497 console.print(header)
1499 run_a = comp.get(
"run_a")
if isinstance(comp.get(
"run_a"), dict)
else {}
1500 run_b = comp.get(
"run_b")
if isinstance(comp.get(
"run_b"), dict)
else {}
1502 meta = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1504 meta.add_column(str(comp.get(
"label_a")
or "A"), style=
"value")
1505 meta.add_column(str(comp.get(
"label_b")
or "B"), style=
"value")
1507 (
"model",
"model_id"),
1508 (
"samples",
"n_samples"),
1509 (
"final loss",
"final_loss"),
1510 (
"sharpness",
"sharpness"),
1511 (
"influence",
"influence_method"),
1513 va, vb = run_a.get(key), run_b.get(key)
1514 if va
is not None or vb
is not None:
1515 meta.add_row(label, str(va
if va
is not None else "—"), str(vb
if vb
is not None else "—"))
1518 loss_delta = comp.get(
"lossDelta")
1519 if loss_delta
is not None or run_a.get(
"n_samples") != run_b.get(
"n_samples"):
1521 sa, sb = run_a.get(
"n_samples"), run_b.get(
"n_samples")
1522 if sa
is not None and sb
is not None and sa != sb:
1523 parts.append(f
"samples {sa}→{sb}")
1524 if loss_delta
is not None:
1525 parts.append(f
"final loss {run_a.get('final_loss')}→{run_b.get('final_loss')} (Δ{float(loss_delta):+.4f})")
1527 console.print(f
"[label]Dataset shift:[/] [value]{' · '.join(parts)}[/]")
1530 f
"[label]Flipped:[/] [value]{comp.get('nFlippedFeatures', 0)} features[/] "
1531 f
"[muted]·[/] [value]{comp.get('nFlippedInfluence', 0)} influence[/] "
1532 f
"[muted]· max feature Δ[/] [value]{comp.get('maxFeatureDelta', 0)}[/]"
1534 if comp.get(
"similarRuns"):
1536 "[muted]Runs are nearly identical — same dataset + config reproduced the same prediction.[/]"
1538 elif comp.get(
"saeOverlapIdentical")
and not comp.get(
"similarRuns"):
1539 n_only_a = comp.get(
"nFeaturesOnlyA", 0)
1540 n_only_b = comp.get(
"nFeaturesOnlyB", 0)
1541 n_overlap = comp.get(
"nFeaturesOverlap", 0)
1543 f
"[muted]{n_overlap} overlapping SAE features have identical scores"
1545 if n_only_a
or n_only_b:
1546 msg += f
" · {n_only_a} only in Before · {n_only_b} only in After"
1547 msg +=
" — loss/sample count still differ.[/]"
1550 scores = comp.get(
"modelScores")
or {}
1551 deltas = comp.get(
"attackSurfaceDeltas")
if isinstance(comp.get(
"attackSurfaceDeltas"), dict)
else {}
1552 atk = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1553 atk.add_column(
"Metric")
1554 atk.add_column(str(comp.get(
"label_a")
or "A"), justify=
"right")
1555 atk.add_column(str(comp.get(
"label_b")
or "B"), justify=
"right")
1556 atk.add_column(
"Δ", justify=
"right", style=
"muted")
1559 (
"Consistency",
"consistencyScore"),
1560 (
"Suppression",
"suppressionScore"),
1561 (
"Robustness",
"robustnessScore"),
1563 side_a = scores.get(
"a")
if isinstance(scores, dict)
else {}
1564 side_b = scores.get(
"b")
if isinstance(scores, dict)
else {}
1565 va = side_a.get(key)
if isinstance(side_a, dict)
else None
1566 vb = side_b.get(key)
if isinstance(side_b, dict)
else None
1567 if isinstance(va, (int, float))
or isinstance(vb, (int, float)):
1569 delta_key = key.replace(
"Score",
"")
1570 d = deltas.get(delta_key)
1571 delta_s = f
"{float(d):+.3f}" if isinstance(d, (int, float))
else "—"
1574 _pct(va)
if isinstance(va, (int, float))
else "—",
1575 _pct(vb)
if isinstance(vb, (int, float))
else "—",
1579 console.print(Rule(
"[heading]Attack surface[/]", style=
"muted"))
1582 sharp = comp.get(
"sharpness")
if isinstance(comp.get(
"sharpness"), dict)
else {}
1583 if sharp.get(
"label_a")
or sharp.get(
"label_b"):
1585 f
"[label]Loss landscape:[/] [value]{sharp.get('label_a', '?')}[/] "
1586 f
"[muted]→[/] [value]{sharp.get('label_b', '?')}[/]"
1589 diffs = comp.get(
"featureDiffs")
or []
1592 if f.get(
"score_delta")
is not None and abs(float(f[
"score_delta"])) > 1e-9
1595 console.print(Rule(
"[heading]SAE feature shifts (by |Δ|)[/]", style=
"muted"))
1596 ft = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1597 ft.add_column(
"Feature")
1598 ft.add_column(
"Score A", justify=
"right")
1599 ft.add_column(
"Score B", justify=
"right")
1600 ft.add_column(
"Δ", justify=
"right")
1601 ft.add_column(
"Dir")
1602 for f
in nonzero_feats[:12]:
1603 sa, sb = f.get(
"score_a"), f.get(
"score_b")
1604 delta = f.get(
"score_delta")
1605 dir_s = f
"{f.get('direction_a', '?')}→{f.get('direction_b', '?')}"
1606 if f.get(
"flipped"):
1607 dir_s = Text(dir_s +
" ⚡", style=
"warn")
1609 str(f.get(
"feature_idx",
"?")),
1610 f
"{float(sa):+.4f}" if isinstance(sa, (int, float))
else "—",
1611 f
"{float(sb):+.4f}" if isinstance(sb, (int, float))
else "—",
1612 f
"{float(delta):+.4e}" if isinstance(delta, (int, float))
else "—",
1617 only_a = [f
for f
in diffs
if f.get(
"only_in") ==
"a"]
1618 only_b = [f
for f
in diffs
if f.get(
"only_in") ==
"b"]
1619 n_overlap = comp.get(
"nFeaturesOverlap", 0)
1620 if n_overlap
and comp.get(
"saeOverlapIdentical"):
1622 f
"[muted]{n_overlap} overlapping SAE features — identical scores[/]"
1625 console.print(f
"[muted]{len(diffs)} SAE features in union — no score deltas above noise[/]")
1626 for title, rows, score_key
in (
1627 (f
"Top SAE features only in {comp.get('label_a', 'Before')}", only_a[:8],
"score_a"),
1628 (f
"Top SAE features only in {comp.get('label_b', 'After')}", only_b[:8],
"score_b"),
1632 console.print(Rule(f
"[heading]{title}[/]", style=
"muted"))
1633 ot = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1634 ot.add_column(
"Feature")
1635 ot.add_column(
"Score", justify=
"right")
1636 ot.add_column(
"Dir")
1638 sc = f.get(score_key)
1640 str(f.get(
"feature_idx",
"?")),
1641 f
"{float(sc):+.4f}" if isinstance(sc, (int, float))
else "—",
1642 str(f.get(
"direction_a" if score_key ==
"score_a" else "direction_b")
or "—"),
1646 infl_avail = comp.get(
"influenceAvailable")
if isinstance(comp.get(
"influenceAvailable"), dict)
else {}
1647 infl = comp.get(
"influenceDiffs")
or []
1650 if s.get(
"influence_a")
is not None and s.get(
"influence_b")
is not None
1652 if infl_avail.get(
"a")
and not infl_avail.get(
"b"):
1654 f
"[warn]{comp.get('label_b', 'After')} has no saved influence scores[/] "
1655 f
"[muted](re-run simulate on that config to compare influence)[/]"
1657 elif infl_avail.get(
"b")
and not infl_avail.get(
"a"):
1659 f
"[warn]{comp.get('label_a', 'Before')} has no saved influence scores[/]"
1662 console.print(Rule(
"[heading]Influence changes[/]", style=
"muted"))
1663 it = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1664 it.add_column(
"Idx")
1665 it.add_column(
"A", justify=
"right")
1666 it.add_column(
"B", justify=
"right")
1667 it.add_column(
"Δ", justify=
"right")
1668 it.add_column(
"Instruction")
1669 for s
in paired_infl[:8]:
1671 str(s.get(
"idx",
"")),
1675 _trunc(str(s.get(
"instruction")
or ""), 40),
1678 elif infl_avail.get(
"a")
or infl_avail.get(
"b"):
1679 console.print(
"[muted]No overlapping influence samples to compare[/]")
1681 lr = comp.get(
"lrDiffs")
or []
1683 console.print(Rule(
"[heading]Effective LR deltas[/]", style=
"muted"))
1684 lt = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1685 lt.add_column(
"Param")
1686 lt.add_column(
"A", justify=
"right")
1687 lt.add_column(
"B", justify=
"right")
1688 lt.add_column(
"Δ", justify=
"right")
1692 _num(row.get(
"lr_a"), 6),
1693 _num(row.get(
"lr_b"), 6),
1694 _num(row.get(
"delta"), 6),
1697 elif comp.get(
"similarRuns"):
1698 console.print(
"[muted]Effective LR identical across shared parameters[/]")
1701def _print_generic(console: Console, verb: str, data: dict[str, Any]) ->
None:
1705 if data.get(
"perturbation_results")
or data.get(
"channels"):
1708 if data.get(
"layer_norms"):
1712 data[
"layer_norms"],
1713 [(
"Layer",
"layer"), (
"Norm",
"norm")],
1717 console.print(Rule(f
"[heading]{verb}[/]", style=
"muted"))
1718 skip_keys: set[str] = set()
1719 for key, val
in data.items():
1720 if key ==
"error" or not isinstance(val, list)
or not val:
1722 if all(isinstance(item, dict)
for item
in val):
1725 keys.update(item.keys())
1727 cols = [(k, k)
for k
in sorted(keys)]
1731 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1732 table.add_column(
"Key", style=
"label")
1733 table.add_column(
"Value", style=
"value")
1735 for key, val
in data.items():
1736 if key ==
"error" or key
in skip_keys:
1738 if isinstance(val, dict):
1739 table.add_row(key, f
"[muted]{len(val)} fields (use --check)[/]")
1741 elif isinstance(val, list):
1742 table.add_row(key, f
"[muted]{len(val)} items (use --check)[/]")
1744 elif isinstance(val, float):
1745 table.add_row(key,
_num(val))
1747 elif isinstance(val, (str, int, bool))
or val
is None:
1748 table.add_row(key, str(val)
if val
is not None else "—")
1752 console.print(table)
1754 console.print(
"[muted]No displayable fields. Use --check for full result.[/]")
1758 path = data.get(
"path")
or "—"
1759 topic = data.get(
"topic")
or "—"
1760 count = data.get(
"count", 0)
1761 console.print(Rule(
"[heading]Generated dataset[/]", style=
"muted"))
1762 console.print(f
"[label]Topic[/] [value]{topic}[/]")
1763 console.print(f
"[label]Rows[/] [value]{count}[/]")
1764 console.print(f
"[label]File[/] [accent]{path}[/]")
1765 rows = data.get(
"rows")
or []
1767 table = Table(show_header=
True, header_style=
"label", box=
None, padding=(0, 1))
1768 table.add_column(
"#", style=
"muted", justify=
"right", width=3)
1769 table.add_column(
"Instruction", style=
"value", max_width=48)
1770 table.add_column(
"Response", style=
"muted", max_width=48)
1771 for i, row
in enumerate(rows[:8], 1):
1772 instr = str(row.get(
"instruction",
""))
1773 resp = str(row.get(
"response",
""))
1775 instr = instr[:45] +
"..."
1777 resp = resp[:45] +
"..."
1778 table.add_row(str(i), instr, resp)
1779 console.print(table)
1781 console.print(f
"[muted]… and {len(rows) - 8} more row(s)[/]")
1784def print_tool_result(verb: str, result: Any, *, tool_name: str |
None =
None) ->
None:
1785 """Pretty-print a tool result using the same Rich theme as aquin chat."""
1789 if isinstance(data, dict)
and data.get(
"error"):
1794 title = verb.replace(
"-",
" ").title()
1795 model_id = data.get(
"model_id")
if isinstance(data, dict)
else None
1796 header = f
"[title]{title}[/]"
1798 header += f
" [muted]{model_id}[/]"
1799 console.print(Panel.fit(header, border_style=
"dim"))
1802 if data.get(
"consistency"):
1804 if data.get(
"suppression"):
1806 if data.get(
"boundary"):
1811 if verb ==
"consistency-eval":
1816 if verb ==
"suppression-eval":
1821 if verb ==
"boundary-eval":
1831 if verb
in (
"benchmark",
"benchmarks"):
1836 if verb ==
"feature locate":
1841 if verb ==
"extract-steer-vector" or tool_name ==
"extract_steer_vector":
1846 if verb
in (
"steer",
"multi-steer"):
1851 if verb ==
"red-team":
1856 if verb ==
"layer-analysis":
1861 if verb ==
"sae-stats":
1866 if verb
in (
"confidence-analysis",
"check confidence"):
1871 if verb ==
"diff weight":
1876 if verb ==
"check trajectory":
1881 if verb ==
"diff residue":
1886 if verb ==
"perturbation":
1891 if verb ==
"attention":
1896 if verb ==
"check-weights":
1906 if verb ==
"simulate":
1911 if verb
in (
"list simulation",
"list simulations",
"list-runs"):
1916 if verb
in (
"replay simulation",
"load simulation",
"load-run"):
1921 if verb
in (
"compare simulation",
"compare-runs"):
1926 if verb ==
"dataset-generate":
1931 if isinstance(data, dict):
None _print_dict_list_table(Console console, str title, list[dict[str, Any]] rows, list[tuple[str, str]] columns)
str _status_style(str status)
None _print_custom_eval(Console console, dict[str, Any] data)
str _trunc(str text, int limit=72)
None _print_benchmarks(Console console, dict[str, Any] data)
None _print_steer_eval(Console console, dict[str, Any] eval_data)
None _print_umap(Console console, dict[str, Any] data)
None _print_generic(Console console, str verb, dict[str, Any] data)
None _print_consistency(Console console, dict[str, Any] data)
None _print_residual_drift(Console console, dict[str, Any] data)
None _print_check_weights(Console console, dict[str, Any] data)
float _layer_cosine(list[float] a, list[float] b)
None _print_weight_diff(Console console, dict[str, Any] data)
None _print_boundary(Console console, dict[str, Any] data)
str _pct(float|None score)
str _short_param_name(str name)
None _print_perturbation(Console console, dict[str, Any] data)
None _print_confidence_analysis(Console console, dict[str, Any] data)
None _print_find_feature(Console console, dict[str, Any] data)
None _print_extract_steer_vector(Console console, dict[str, Any] data)
None _print_merge_analysis(Console console, dict[str, Any] data)
None print_tool_result(str verb, Any result, *, str|None tool_name=None)
str _score_style(float score)
None _print_simulation_list(Console console, dict[str, Any] data)
None _print_trajectory_analysis(Console console, dict[str, Any] data)
None _print_localize_collapse(Console console, dict[str, Any] data)
float _vec_norm(list[float] vec)
dict[str, Any] _unwrap(Any result)
list[list[float]] _normalize_attn_matrix(list[list[float]] matrix)
None _print_error(Console console, str message)
None _print_simulation_compare(Console console, dict[str, Any] data)
None _print_red_team(Console console, dict[str, Any] data)
dict[str, Any] _normalize_feature_benchmark(dict[str, Any] data)
None _print_steer(Console console, dict[str, Any] data)
None _print_layer_analysis(Console console, dict[str, Any] data)
None _print_simulate(Console console, dict[str, Any] data)
None _print_loaded_simulation(Console console, dict[str, Any] data)
str _format_saved_at(str iso)
None _print_suppression(Console console, dict[str, Any] data)
str _fmt_influence(float|None val)
None _print_dataset_generate(Console console, dict[str, Any] data)
None _print_attention(Console console, dict[str, Any] data)
None _print_sae_stats(Console console, dict[str, Any] data)
str _num(float|None v, int digits=3)
bool _is_llm_layer_analysis_payload(dict[str, Any] data)