PeterKruger Cursor commited on
Commit
7e19265
·
1 Parent(s): 7f8a86c

Add the Router Benchmark tab and the October 2026 board.

Browse files

Router runs stay out of the model dropdown.

Co-authored-by: Cursor <cursoragent@cursor.com>

app.py CHANGED
@@ -1,6 +1,7 @@
1
  import gradio as gr
2
  import pandas as pd
3
  import plotly.express as px
 
4
  import os
5
  import json
6
  from typing import Dict, List, Optional
@@ -47,6 +48,10 @@ def discover_available_runs() -> List[Dict]:
47
  try:
48
  with open(metadata_path, 'r') as f:
49
  metadata = json.load(f)
 
 
 
 
50
  metadata["path"] = run_path
51
  runs.append(metadata)
52
  except Exception as e:
@@ -463,7 +468,171 @@ def update_leaderboard_data(selected_run_id: str) -> tuple:
463
  )
464
 
465
  # --- Build Gradio App ---
466
- with gr.Blocks(theme=gr.themes.Soft()) as app:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
467
  gr.Markdown("# AutoBench LLM Leaderboard")
468
  gr.Markdown(
469
  "Interactive leaderboard for AutoBench, where LLMs rank LLMs' responses. "
@@ -604,12 +773,57 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
604
  label="Domain Performance"
605
  )
606
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
  # --- Tab 5: About ---
608
  with gr.Tab("About AutoBench"):
609
  gr.Markdown("""
610
  ## About AutoBench
611
 
612
- AutoBench is an LLM benchmark where Large Language Models (LLMs) evaluate and rank the responses generated by other LLMs. The questions themselves are also generated by LLMs across a diverse set of domains and ranked for quality.
 
 
613
 
614
  ### Methodology
615
  1. **Question Generation:** High-quality questions across various domains (Coding, History, Science, etc.) are generated by selected LLMs.
@@ -625,9 +839,10 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
625
  * **Chatbot Arena / Artificial Analysis Intelligence Index / MMLU:** Scores from other well-known benchmarks for comparison (where available).
626
 
627
  ### Data
628
- This leaderboard reflects a run completed on April 23, 2025. Models included recently released models such as o4-mini, Gpt-4.1-mini, Gemini 2.5 Pro Preview, Claude 3.7 Sonnet:thikning, etc..
629
 
630
  ### Links
 
631
  * [AutoBench Run 2 Results](https://huggingface.co/blog/PeterKruger/autobench-2nd-run)
632
  * [AutoBench Blog Post](https://huggingface.co/blog/PeterKruger/autobench)
633
  * [Autobench Repositories](https://huggingface.co/AutoBench)
@@ -662,12 +877,16 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
662
  # Note: Initial data is already loaded via value parameters above
663
 
664
  # --- Launch the App ---
665
- print("Launching Gradio app...")
666
- app.launch(
667
- favicon_path="static/manifest.json" if os.path.exists("static/manifest.json") else None,
668
- server_name="0.0.0.0",
669
- server_port=7860,
670
- ssr_mode=False,
671
- show_error=True
672
- )
673
- print("Gradio app launched.")
 
 
 
 
 
1
  import gradio as gr
2
  import pandas as pd
3
  import plotly.express as px
4
+ import inspect
5
  import os
6
  import json
7
  from typing import Dict, List, Optional
 
48
  try:
49
  with open(metadata_path, 'r') as f:
50
  metadata = json.load(f)
51
+ # Router runs have their own tab. Leaving them in this list
52
+ # would make the model dropdown try to load summary CSVs.
53
+ if metadata.get("run_type") == "router":
54
+ continue
55
  metadata["path"] = run_path
56
  runs.append(metadata)
57
  except Exception as e:
 
468
  )
469
 
470
  # --- Build Gradio App ---
471
+ def discover_router_runs() -> List[Dict]:
472
+ """Router runs are excluded from the model dropdown."""
473
+ routers = []
474
+ if not os.path.exists(RUNS_DIR):
475
+ return routers
476
+ for run_dir in os.listdir(RUNS_DIR):
477
+ run_path = os.path.join(RUNS_DIR, run_dir)
478
+ metadata_path = os.path.join(run_path, "metadata.json")
479
+ if not os.path.isdir(run_path) or not os.path.exists(metadata_path):
480
+ continue
481
+ try:
482
+ with open(metadata_path, "r", encoding="utf-8") as handle:
483
+ metadata = json.load(handle)
484
+ except Exception as exc:
485
+ print(f"Error loading router metadata for {run_dir}: {exc}")
486
+ continue
487
+ if metadata.get("run_type") != "router":
488
+ continue
489
+ metadata["path"] = run_path
490
+ routers.append(metadata)
491
+ routers.sort(key=lambda item: item.get("date", ""), reverse=True)
492
+ return routers
493
+
494
+
495
+ def router_quality_cost_figure(board: pd.DataFrame):
496
+ headline = board[board["is_baseline"] == 0].copy()
497
+ headline["group"] = headline["collapsed"].map(
498
+ {1: "Collapsed (at least 90% one model)", 0: "Spread"}
499
+ )
500
+ figure = px.scatter(
501
+ headline,
502
+ x="cost",
503
+ y="accuracy",
504
+ color="group",
505
+ hover_name="label",
506
+ hover_data={
507
+ "vendor": True,
508
+ "n": True,
509
+ "cost": ":.4f",
510
+ "accuracy": ":.1f",
511
+ "group": False,
512
+ },
513
+ log_x=True,
514
+ color_discrete_map={
515
+ "Spread": "#155dfc",
516
+ "Collapsed (at least 90% one model)": "#d97706",
517
+ },
518
+ labels={"cost": "USD per question", "accuracy": "Accuracy (%)", "group": ""},
519
+ )
520
+ for name, color in (
521
+ ("Always-Sol", "#111827"),
522
+ ("Always-Luna", "#059669"),
523
+ ("Random", "#6b7280"),
524
+ ):
525
+ match = board[board["label"] == name]
526
+ if match.empty:
527
+ continue
528
+ accuracy = float(match.iloc[0]["accuracy"])
529
+ figure.add_hline(
530
+ y=accuracy,
531
+ line_dash="dash",
532
+ line_color=color,
533
+ annotation_text=f"{name} {accuracy:.1f}%",
534
+ annotation_position="top left",
535
+ )
536
+ figure.update_layout(
537
+ yaxis_title="Accuracy (%)",
538
+ xaxis_title="USD per question (log scale)",
539
+ legend_title_text="",
540
+ margin=dict(l=20, r=20, t=30, b=20),
541
+ )
542
+ return figure
543
+
544
+
545
+ def router_collapse_figure(board: pd.DataFrame):
546
+ headline = board[board["is_baseline"] == 0].dropna(subset=["top_share"]).copy()
547
+ headline = headline.sort_values("top_share", ascending=True)
548
+ headline["share_pct"] = headline["top_share"] * 100
549
+ figure = px.bar(
550
+ headline,
551
+ x="share_pct",
552
+ y="label",
553
+ orientation="h",
554
+ labels={"share_pct": "Top-model share (%)", "label": ""},
555
+ )
556
+ figure.add_vline(x=90, line_dash="dash", line_color="#d97706")
557
+ figure.update_layout(margin=dict(l=20, r=20, t=30, b=20), showlegend=False)
558
+ return figure
559
+
560
+
561
+ def router_same_pick_figure(same: pd.DataFrame, axis: List[str]):
562
+ pivot = same.pivot(index="pass_a", columns="pass_b", values="rate")
563
+ pivot = pivot.reindex(index=axis, columns=axis)
564
+ figure = px.imshow(
565
+ pivot,
566
+ zmin=0,
567
+ zmax=1,
568
+ color_continuous_scale="Blues",
569
+ labels=dict(color="Same-pick rate", x="", y=""),
570
+ aspect="auto",
571
+ )
572
+ figure.update_layout(margin=dict(l=20, r=20, t=30, b=20))
573
+ return figure
574
+
575
+
576
+ def router_board_display(board: pd.DataFrame) -> pd.DataFrame:
577
+ view = board.sort_values(["cost", "display_order"]).copy()
578
+ displayed = pd.DataFrame(
579
+ {
580
+ "Pass": view["label"],
581
+ "Vendor": view["vendor"],
582
+ "Setting": view["setting"],
583
+ "n": view["n"],
584
+ "Accuracy (%)": view["accuracy"].map(lambda value: f"{value:.1f}"),
585
+ "95% CI": [
586
+ f"{low:.1f}–{high:.1f}"
587
+ for low, high in zip(view["ci_low"], view["ci_high"])
588
+ ],
589
+ "USD / question": view["cost"].map(lambda value: f"{value:.4f}"),
590
+ "Cost CI": [
591
+ f"{low:.4f}–{high:.4f}"
592
+ for low, high in zip(view["cost_ci_low"], view["cost_ci_high"])
593
+ ],
594
+ "Top-model share": view["top_share"].map(
595
+ lambda value: "" if pd.isna(value) else f"{value * 100:.1f}%"
596
+ ),
597
+ "Collapsed": view["collapsed"].map({1: "Yes", 0: ""}),
598
+ "Baseline": view["is_baseline"].map({1: "Yes", 0: ""}),
599
+ }
600
+ )
601
+ return displayed
602
+
603
+
604
+ def router_intro_markdown(metadata: Dict) -> str:
605
+ facts = metadata.get("facts", {})
606
+ threshold = float(facts.get("collapse_threshold", 0.9)) * 100
607
+ median = facts.get("median_same_pick", 0)
608
+ return f"""
609
+ ## AutoBench Router Benchmark
610
+
611
+ {metadata.get("description", "")}
612
+
613
+ We graded **{facts.get("commercial_routers")} commercial routers** ({facts.get("headline_passes")} passes) on a frozen matrix of {facts.get("questions")} questions and {facts.get("matrix_models")} models ({facts.get("matrix_date")}).
614
+
615
+ **Accuracy** is the share of questions where the chosen model is statistically as good as the best available answer.
616
+
617
+ ### Findings
618
+ - The cheap-and-strong region is empty.
619
+ - {facts.get("collapsed_passes")} of {facts.get("headline_passes")} passes collapsed, sending at least {threshold:.0f}% of questions to one model.
620
+ - Median cross-vendor same-pick is {median:g} across {facts.get("cross_vendor_pairs")} pairs.
621
+
622
+ The board is sorted by cost. Each row shows how many questions that pass actually answered (`n`). Read the report: [{metadata.get("report_url", "")}]({metadata.get("report_url", "")}).
623
+ """
624
+
625
+
626
+ def open_blocks():
627
+ """Gradio 5 takes theme on Blocks. Gradio 6 takes it on launch."""
628
+ parameters = inspect.signature(gr.Blocks.__init__).parameters
629
+ theme_on_blocks = "theme" in parameters and parameters["theme"].kind is not inspect.Parameter.VAR_KEYWORD
630
+ if theme_on_blocks:
631
+ return gr.Blocks(theme=gr.themes.Soft())
632
+ return gr.Blocks()
633
+
634
+
635
+ with open_blocks() as app:
636
  gr.Markdown("# AutoBench LLM Leaderboard")
637
  gr.Markdown(
638
  "Interactive leaderboard for AutoBench, where LLMs rank LLMs' responses. "
 
773
  label="Domain Performance"
774
  )
775
 
776
+ # --- Router Benchmark (not part of the model-run dropdown) ---
777
+ with gr.Tab("Router Benchmark"):
778
+ router_runs = discover_router_runs()
779
+ if not router_runs:
780
+ gr.Markdown("No router benchmark run is in this checkout.")
781
+ else:
782
+ router_meta = router_runs[0]
783
+ router_board = pd.read_csv(os.path.join(router_meta["path"], "router_board.csv"))
784
+ router_same = pd.read_csv(os.path.join(router_meta["path"], "same_pick.csv"))
785
+ gr.Markdown(router_intro_markdown(router_meta))
786
+ gr.Markdown("### Board")
787
+ gr.DataFrame(value=router_board_display(router_board), interactive=False)
788
+ gr.Markdown(
789
+ "### Quality versus cost\n\n"
790
+ "Dashed lines are Always-Sol, Always-Luna, and Random. "
791
+ "Amber points collapsed onto one model."
792
+ )
793
+ gr.Plot(value=router_quality_cost_figure(router_board))
794
+ gr.Markdown("### Top-model share\n\nPasses at or above 90% are collapsed.")
795
+ gr.Plot(value=router_collapse_figure(router_board))
796
+ gr.Markdown(
797
+ "### Same-pick\n\n"
798
+ "Share of questions on which two passes named the same model. "
799
+ "This grid is the 12-pass comparison from the report. "
800
+ "The median of 0 is across the full set of cross-vendor pairs, not this grid alone."
801
+ )
802
+ gr.Plot(
803
+ value=router_same_pick_figure(
804
+ router_same, router_meta.get("same_pick_axis", [])
805
+ )
806
+ )
807
+ gr.Markdown(
808
+ f"""
809
+ ### Methodology
810
+ - The answer matrix is frozen: {router_meta.get("questions")} questions, {router_meta.get("matrix_models")} models, dated {router_meta.get("matrix_date")}.
811
+ - Scoring rules were locked before any router was called. Each router choice is scored by lookup on that matrix. Routers are not re-judged.
812
+ - **Accuracy** is the share of questions where the chosen model is statistically as good as the best available answer.
813
+ - A pass is collapsed when its top model receives at least 90% of questions.
814
+ - Same-pick is the share of questions on which two passes named the same model. The published median is the median across cross-vendor pairs.
815
+ - [Read the report]({router_meta.get("report_url", "")})
816
+ """
817
+ )
818
+
819
  # --- Tab 5: About ---
820
  with gr.Tab("About AutoBench"):
821
  gr.Markdown("""
822
  ## About AutoBench
823
 
824
+ AutoBench is the evaluation engine for the agentic era. A committee of language models writes questions, answers them, and scores the answers, so quality, cost, and speed are measured together. The same evidence grades models and, on the Router Benchmark tab, grades routers.
825
+
826
+ We don't build base models. We measure them. Neutrality is the product.
827
 
828
  ### Methodology
829
  1. **Question Generation:** High-quality questions across various domains (Coding, History, Science, etc.) are generated by selected LLMs.
 
839
  * **Chatbot Arena / Artificial Analysis Intelligence Index / MMLU:** Scores from other well-known benchmarks for comparison (where available).
840
 
841
  ### Data
842
+ The model tabs show the latest public model run. The Router Benchmark is a separate tab and does not replace that run. Routers are scored by lookup on a frozen answer matrix: the rules were locked before any router was called.
843
 
844
  ### Links
845
+ * [Router Benchmark report](https://autobench.org/reports/router-benchmark-2026.pdf)
846
  * [AutoBench Run 2 Results](https://huggingface.co/blog/PeterKruger/autobench-2nd-run)
847
  * [AutoBench Blog Post](https://huggingface.co/blog/PeterKruger/autobench)
848
  * [Autobench Repositories](https://huggingface.co/AutoBench)
 
877
  # Note: Initial data is already loaded via value parameters above
878
 
879
  # --- Launch the App ---
880
+ if __name__ == "__main__":
881
+ print("Launching Gradio app...")
882
+ launch_kwargs = {
883
+ "favicon_path": "static/manifest.json" if os.path.exists("static/manifest.json") else None,
884
+ "server_name": "0.0.0.0",
885
+ "server_port": 7860,
886
+ "ssr_mode": False,
887
+ "show_error": True,
888
+ }
889
+ if "theme" in inspect.signature(gr.Blocks.launch).parameters:
890
+ launch_kwargs["theme"] = gr.themes.Soft()
891
+ app.launch(**launch_kwargs)
892
+ print("Gradio app launched.")
export_router_run.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Export the Router Benchmark board from the paper's generated stats.
3
+
4
+ Reads stats.json, collapse.dat, and isolation.dat. Does not retype results.
5
+ Writes runs/router1_2026-10-26/ for the Hugging Face Space and the website importer.
6
+
7
+ Usage (from AutoBench-Leaderboard-live):
8
+ python export_router_run.py
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import csv
15
+ import json
16
+ import re
17
+ from pathlib import Path
18
+
19
+
20
+ # Frozen answer matrix this board is scored on. Identity of the published
21
+ # model run, not a result copied out of the paper tables.
22
+ MATRIX_DATE = "2026-08-29"
23
+ MATRIX_MODELS = 20
24
+ COLLAPSE_THRESHOLD = 0.90
25
+
26
+ # key, public label, vendor, setting, is_baseline, collapse.dat label
27
+ PASSES = [
28
+ ("oracle", "Oracle", "Baseline", "oracle", 1, None),
29
+ ("cheapest_adequate", "Cheapest-adequate", "Baseline", "cheapest adequate", 1, None),
30
+ ("best_static_single", "Always-Sol", "Baseline", "always Sol", 1, None),
31
+ ("always_luna", "Always-Luna", "Baseline", "always Luna", 1, None),
32
+ ("random", "Random", "Baseline", "random", 1, "Random"),
33
+ ("always_cheapest", "Always-cheapest", "Baseline", "always cheapest", 1, None),
34
+ ("orca_constrained_cheapest", "Orca cheapest", "OrcaRouter", "cheapest", 0, "Orca cheap"),
35
+ ("orca_constrained_balanced", "Orca balanced", "OrcaRouter", "balanced", 0, "Orca bal"),
36
+ ("orca_constrained_quality", "Orca quality", "OrcaRouter", "quality", 0, "Orca qual"),
37
+ ("azure_cost", "Azure cost", "Azure Model Router", "cost", 0, "Azure cost"),
38
+ ("azure_balanced", "Azure balanced", "Azure Model Router", "balanced", 0, "Azure bal"),
39
+ ("azure_quality", "Azure quality", "Azure Model Router", "quality", 0, "Azure qual"),
40
+ ("nadirclaw", "NadirClaw", "NadirClaw", "as shipped", 0, "NadirClaw"),
41
+ ("brick", "Brick", "Brick", "as shipped", 0, "Brick"),
42
+ ("cascade", "Cascade", "Cascade", "as shipped", 0, "Cascade"),
43
+ ("nd_subset_k0", "ND k0", "Not Diamond", "k0", 0, "ND k0"),
44
+ ("nd_subset_k4", "ND k4", "Not Diamond", "k4", 0, "ND k4"),
45
+ ("nd_subset_k5", "ND k5", "Not Diamond", "k5", 0, "ND k5"),
46
+ ("nd_native_k5", "ND native", "Not Diamond", "native", 0, "ND native"),
47
+ ("or_auto", "Auto low", "OpenRouter", "low", 0, "Auto low"),
48
+ ("or_auto_medium", "Auto medium", "OpenRouter", "medium", 0, "Auto med"),
49
+ ("or_auto_high", "Auto high", "OpenRouter", "high", 0, "Auto high"),
50
+ ("or_auto_max", "Auto max", "OpenRouter", "max", 0, "Auto max"),
51
+ ]
52
+
53
+ BOARD_FIELDS = [
54
+ "pass_key",
55
+ "label",
56
+ "vendor",
57
+ "setting",
58
+ "n",
59
+ "accuracy",
60
+ "ci_low",
61
+ "ci_high",
62
+ "cost",
63
+ "cost_ci_low",
64
+ "cost_ci_high",
65
+ "top_share",
66
+ "collapsed",
67
+ "is_baseline",
68
+ "display_order",
69
+ ]
70
+
71
+
72
+ def parse_collapse(path: Path) -> dict[str, float]:
73
+ shares: dict[str, float] = {}
74
+ for line in path.read_text(encoding="utf-8").splitlines():
75
+ line = line.strip()
76
+ if not line or line.startswith("idx"):
77
+ continue
78
+ match = re.match(r"^\d+\s+([0-9.]+)\s+\{(.+)\}$", line)
79
+ if not match:
80
+ raise SystemExit(f"Unparsed collapse row: {line}")
81
+ shares[match.group(2)] = float(match.group(1))
82
+ return shares
83
+
84
+
85
+ def parse_axis(path: Path) -> list[str]:
86
+ text = path.read_text(encoding="utf-8")
87
+ match = re.search(r"xticklabels=\{([^}]+)\}", text)
88
+ if not match:
89
+ raise SystemExit(f"No xticklabels in {path}")
90
+ return [label.strip() for label in match.group(1).split(",")]
91
+
92
+
93
+ def parse_isolation(path: Path, axis: list[str]) -> list[dict]:
94
+ rows = []
95
+ for line in path.read_text(encoding="utf-8").splitlines():
96
+ line = line.strip()
97
+ if not line or line.startswith("x "):
98
+ continue
99
+ x_s, y_s, rate_s = line.split()
100
+ x, y = int(x_s), int(y_s)
101
+ rows.append(
102
+ {
103
+ "axis_a": x,
104
+ "axis_b": y,
105
+ "pass_a": axis[x],
106
+ "pass_b": axis[y],
107
+ "rate": float(rate_s),
108
+ }
109
+ )
110
+ return rows
111
+
112
+
113
+ def main() -> None:
114
+ parser = argparse.ArgumentParser()
115
+ parser.add_argument(
116
+ "--stats",
117
+ type=Path,
118
+ default=Path(
119
+ r"C:\DEV\AutoBench\autobench\docs\projects\router-benchmark-paper\generated\stats.json"
120
+ ),
121
+ )
122
+ parser.add_argument(
123
+ "--out",
124
+ type=Path,
125
+ default=Path(__file__).resolve().parent / "runs" / "router1_2026-10-26",
126
+ )
127
+ args = parser.parse_args()
128
+
129
+ generated = args.stats.parent
130
+ stats = json.loads(args.stats.read_text(encoding="utf-8"))
131
+ marginal = stats["marginal"]
132
+ shares = parse_collapse(generated / "data" / "collapse.dat")
133
+ axis = parse_axis(generated / "data" / "isolation_axis.tex")
134
+ same_pick = parse_isolation(generated / "data" / "isolation.dat", axis)
135
+ isolation = stats["isolation_summary"]
136
+
137
+ board = []
138
+ for order, (key, label, vendor, setting, is_baseline, collapse_label) in enumerate(PASSES):
139
+ if key not in marginal:
140
+ raise SystemExit(f"Missing marginal key: {key}")
141
+ row = marginal[key]
142
+ top_share = ""
143
+ collapsed = 0
144
+ if collapse_label is not None:
145
+ if collapse_label not in shares:
146
+ raise SystemExit(f"Missing collapse label: {collapse_label}")
147
+ top_share = shares[collapse_label]
148
+ collapsed = 1 if top_share >= COLLAPSE_THRESHOLD else 0
149
+ board.append(
150
+ {
151
+ "pass_key": key,
152
+ "label": label,
153
+ "vendor": vendor,
154
+ "setting": setting,
155
+ "n": int(row["n"]),
156
+ "accuracy": row["dh_pct"],
157
+ "ci_low": row["dh_ci"][0],
158
+ "ci_high": row["dh_ci"][1],
159
+ "cost": row["cost"],
160
+ "cost_ci_low": row["cost_ci"][0],
161
+ "cost_ci_high": row["cost_ci"][1],
162
+ "top_share": top_share,
163
+ "collapsed": collapsed,
164
+ "is_baseline": is_baseline,
165
+ "display_order": order,
166
+ }
167
+ )
168
+
169
+ headline = [row for row in board if row["is_baseline"] == 0]
170
+ collapsed_n = sum(row["collapsed"] for row in headline)
171
+ vendors = sorted({row["vendor"] for row in headline})
172
+ questions = int(marginal["oracle"]["n"])
173
+
174
+ metadata = {
175
+ "run_id": "router1_2026-10-26",
176
+ "run_type": "router",
177
+ "title": "AutoBench Router Benchmark 1 - October 2026",
178
+ "date": "2026-10-26",
179
+ "run_version": "2026-10-26",
180
+ "is_latest": False,
181
+ "description": (
182
+ "Commercial routers and baselines graded on a frozen answer matrix. "
183
+ "Accuracy is the share of questions where the chosen model is statistically "
184
+ "as good as the best available answer."
185
+ ),
186
+ "report_url": "https://autobench.org/reports/router-benchmark-2026.pdf",
187
+ "blog_url": "https://autobench.org/reports/router-benchmark-2026.pdf",
188
+ "matrix_date": MATRIX_DATE,
189
+ "matrix_models": MATRIX_MODELS,
190
+ "questions": questions,
191
+ "same_pick_axis": axis,
192
+ "facts": {
193
+ "headline_passes": len(headline),
194
+ "collapsed_passes": collapsed_n,
195
+ "collapse_threshold": COLLAPSE_THRESHOLD,
196
+ "commercial_routers": len(vendors),
197
+ "cross_vendor_pairs": isolation["n_cross_vendor"],
198
+ "median_same_pick": isolation["median_same_pick"],
199
+ "questions": questions,
200
+ "matrix_models": MATRIX_MODELS,
201
+ "matrix_date": MATRIX_DATE,
202
+ },
203
+ }
204
+
205
+ args.out.mkdir(parents=True, exist_ok=True)
206
+ (args.out / "metadata.json").write_text(
207
+ json.dumps(metadata, indent=2) + "\n", encoding="utf-8"
208
+ )
209
+ with (args.out / "router_board.csv").open("w", encoding="utf-8", newline="") as handle:
210
+ writer = csv.DictWriter(handle, fieldnames=BOARD_FIELDS)
211
+ writer.writeheader()
212
+ writer.writerows(board)
213
+ with (args.out / "same_pick.csv").open("w", encoding="utf-8", newline="") as handle:
214
+ writer = csv.DictWriter(
215
+ handle, fieldnames=["axis_a", "axis_b", "pass_a", "pass_b", "rate"]
216
+ )
217
+ writer.writeheader()
218
+ writer.writerows(same_pick)
219
+
220
+ print(f"Wrote {args.out}")
221
+ print(
222
+ f"headline={len(headline)} collapsed={collapsed_n} "
223
+ f"vendors={len(vendors)} ({', '.join(vendors)}) "
224
+ f"pairs={isolation['n_cross_vendor']} median={isolation['median_same_pick']} "
225
+ f"questions={questions} same_pick_cells={len(same_pick)}"
226
+ )
227
+
228
+
229
+ if __name__ == "__main__":
230
+ main()
runs/router1_2026-10-26/metadata.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "run_id": "router1_2026-10-26",
3
+ "run_type": "router",
4
+ "title": "AutoBench Router Benchmark 1 - October 2026",
5
+ "date": "2026-10-26",
6
+ "run_version": "2026-10-26",
7
+ "is_latest": false,
8
+ "description": "Commercial routers and baselines graded on a frozen answer matrix. Accuracy is the share of questions where the chosen model is statistically as good as the best available answer.",
9
+ "report_url": "https://autobench.org/reports/router-benchmark-2026.pdf",
10
+ "blog_url": "https://autobench.org/reports/router-benchmark-2026.pdf",
11
+ "matrix_date": "2026-08-29",
12
+ "matrix_models": 20,
13
+ "questions": 252,
14
+ "same_pick_axis": [
15
+ "Orca cheap",
16
+ "Orca bal",
17
+ "Orca qual",
18
+ "Azure cost",
19
+ "Azure bal",
20
+ "Azure qual",
21
+ "NadirClaw",
22
+ "Brick",
23
+ "Cascade",
24
+ "ND k5",
25
+ "Auto high",
26
+ "Auto low"
27
+ ],
28
+ "facts": {
29
+ "headline_passes": 17,
30
+ "collapsed_passes": 5,
31
+ "collapse_threshold": 0.9,
32
+ "commercial_routers": 7,
33
+ "cross_vendor_pairs": 59,
34
+ "median_same_pick": 0.0,
35
+ "questions": 252,
36
+ "matrix_models": 20,
37
+ "matrix_date": "2026-08-29"
38
+ }
39
+ }
runs/router1_2026-10-26/router_board.csv ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pass_key,label,vendor,setting,n,accuracy,ci_low,ci_high,cost,cost_ci_low,cost_ci_high,top_share,collapsed,is_baseline,display_order
2
+ oracle,Oracle,Baseline,oracle,252,100.0,100.0,100.0,0.03406342571592063,0.023090085942222026,0.04675808716741607,,0,1,0
3
+ cheapest_adequate,Cheapest-adequate,Baseline,cheapest adequate,252,100.0,100.0,100.0,0.0017775440658730159,0.0012147553282936506,0.0024296202333019836,,0,1,1
4
+ best_static_single,Always-Sol,Baseline,always Sol,248,87.5,83.5,91.5,0.07865474395161291,0.06454585211693548,0.09954083326612903,,0,1,2
5
+ always_luna,Always-Luna,Baseline,always Luna,251,85.3,80.9,89.6,0.004334039103585658,0.0037202327948207175,0.005072818161354581,,0,1,3
6
+ random,Random,Baseline,random,252,64.7,58.7,70.6,0.011535058849650793,0.007392945504305159,0.017047359445582142,0.0714,0,1,4
7
+ always_cheapest,Always-cheapest,Baseline,always cheapest,252,44.4,38.5,50.4,0.00016450185134920633,0.00014635133277579365,0.0001831236469801587,,0,1,5
8
+ orca_constrained_cheapest,Orca cheapest,OrcaRouter,cheapest,252,39.3,33.3,45.2,0.00022013774206349209,0.00019737690396825396,0.00024262488363095238,0.9921,1,0,6
9
+ orca_constrained_balanced,Orca balanced,OrcaRouter,balanced,252,39.3,33.3,45.2,0.0002193627023809524,0.00019667757688492064,0.0002418150847222222,0.996,1,0,7
10
+ orca_constrained_quality,Orca quality,OrcaRouter,quality,245,65.7,59.2,71.0,0.0005173967175510203,0.00042429937727755105,0.0006060875131632653,1.0,1,0,8
11
+ azure_cost,Azure cost,Azure Model Router,cost,74,45.9,33.8,56.8,0.00912647891891892,0.00708104558918919,0.01094242530135135,0.5913,0,0,9
12
+ azure_balanced,Azure balanced,Azure Model Router,balanced,179,82.7,78.8,89.4,0.020369913128491617,0.013021539309357542,0.03823974199790503,0.4802,0,0,10
13
+ azure_quality,Azure quality,Azure Model Router,quality,238,85.3,80.3,89.1,0.064655818697479,0.054270396591386556,0.08091888025735294,0.4087,0,0,11
14
+ nadirclaw,NadirClaw,NadirClaw,as shipped,249,70.3,64.3,75.9,0.05136010172289157,0.04020215791164659,0.0689510219376506,0.5873,0,0,12
15
+ brick,Brick,Brick,as shipped,241,63.9,57.7,69.7,0.00310902156506224,0.002298716507154565,0.005002192490113071,0.8016,0,0,13
16
+ cascade,Cascade,Cascade,as shipped,235,60.9,53.2,66.0,0.01035301790706383,0.007934312614846808,0.012938480779023402,0.5826,0,0,14
17
+ nd_subset_k0,ND k0,Not Diamond,k0,248,87.5,83.5,91.5,0.07865474395161291,0.06454585211693548,0.09954083326612903,1.0,1,0,15
18
+ nd_subset_k4,ND k4,Not Diamond,k4,249,80.3,75.5,85.2,0.05996616918433735,0.04669444507111647,0.07957475177908833,0.7698,0,0,16
19
+ nd_subset_k5,ND k5,Not Diamond,k5,251,46.6,40.2,52.6,0.000941773053625498,0.0006677803593406375,0.0012532932769940238,0.8294,0,0,17
20
+ nd_native_k5,ND native,Not Diamond,native,250,72.0,66.0,77.2,0.059749960000000005,0.0475751486,0.07856580617999999,0.6389,0,0,18
21
+ or_auto,Auto low,OpenRouter,low,245,65.7,59.2,71.0,0.0005501390004897959,0.0004446207167918367,0.0006506275904183674,0.9841,1,0,19
22
+ or_auto_medium,Auto medium,OpenRouter,medium,246,73.6,67.1,78.0,0.013130098215934962,0.008043599401597561,0.019080980965126015,0.7817,0,0,20
23
+ or_auto_high,Auto high,OpenRouter,high,244,79.1,73.4,83.6,0.023005027726557378,0.018076698892231558,0.02858057378719467,0.5794,0,0,21
24
+ or_auto_max,Auto max,OpenRouter,max,240,78.3,72.9,83.3,0.028915902712999996,0.020327376228814583,0.043068421132057284,0.7817,0,0,22
runs/router1_2026-10-26/same_pick.csv ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ axis_a,axis_b,pass_a,pass_b,rate
2
+ 0,0,Orca cheap,Orca cheap,1.0
3
+ 0,1,Orca cheap,Orca bal,0.9881
4
+ 0,2,Orca cheap,Orca qual,0.0079
5
+ 0,3,Orca cheap,Azure cost,0.1389
6
+ 0,4,Orca cheap,Azure bal,0.0079
7
+ 0,5,Orca cheap,Azure qual,0.0
8
+ 0,6,Orca cheap,NadirClaw,0.0238
9
+ 0,7,Orca cheap,Brick,0.004
10
+ 0,8,Orca cheap,Cascade,0.0083
11
+ 0,9,Orca cheap,ND k5,0.0
12
+ 0,10,Orca cheap,Auto high,0.004
13
+ 0,11,Orca cheap,Auto low,0.0119
14
+ 1,0,Orca bal,Orca cheap,0.9881
15
+ 1,1,Orca bal,Orca bal,1.0
16
+ 1,2,Orca bal,Orca qual,0.004
17
+ 1,3,Orca bal,Azure cost,0.1389
18
+ 1,4,Orca bal,Azure bal,0.0079
19
+ 1,5,Orca bal,Azure qual,0.0
20
+ 1,6,Orca bal,NadirClaw,0.0238
21
+ 1,7,Orca bal,Brick,0.004
22
+ 1,8,Orca bal,Cascade,0.0
23
+ 1,9,Orca bal,ND k5,0.0
24
+ 1,10,Orca bal,Auto high,0.004
25
+ 1,11,Orca bal,Auto low,0.0079
26
+ 2,0,Orca qual,Orca cheap,0.0079
27
+ 2,1,Orca qual,Orca bal,0.004
28
+ 2,2,Orca qual,Orca qual,1.0
29
+ 2,3,Orca qual,Azure cost,0.0
30
+ 2,4,Orca qual,Azure bal,0.0
31
+ 2,5,Orca qual,Azure qual,0.0
32
+ 2,6,Orca qual,NadirClaw,0.0
33
+ 2,7,Orca qual,Brick,0.8016
34
+ 2,8,Orca qual,Cascade,0.5826
35
+ 2,9,Orca qual,ND k5,0.0
36
+ 2,10,Orca qual,Auto high,0.0
37
+ 2,11,Orca qual,Auto low,0.9841
38
+ 3,0,Azure cost,Orca cheap,0.1389
39
+ 3,1,Azure cost,Orca bal,0.1389
40
+ 3,2,Azure cost,Orca qual,0.0
41
+ 3,3,Azure cost,Azure cost,1.0
42
+ 3,4,Azure cost,Azure bal,0.1905
43
+ 3,5,Azure cost,Azure qual,0.0317
44
+ 3,6,Azure cost,NadirClaw,0.0
45
+ 3,7,Azure cost,Brick,0.0
46
+ 3,8,Azure cost,Cascade,0.0
47
+ 3,9,Azure cost,ND k5,0.0
48
+ 3,10,Azure cost,Auto high,0.0
49
+ 3,11,Azure cost,Auto low,0.0
50
+ 4,0,Azure bal,Orca cheap,0.0079
51
+ 4,1,Azure bal,Orca bal,0.0079
52
+ 4,2,Azure bal,Orca qual,0.0
53
+ 4,3,Azure bal,Azure cost,0.1905
54
+ 4,4,Azure bal,Azure bal,1.0
55
+ 4,5,Azure bal,Azure qual,0.1111
56
+ 4,6,Azure bal,NadirClaw,0.0079
57
+ 4,7,Azure bal,Brick,0.0
58
+ 4,8,Azure bal,Cascade,0.0
59
+ 4,9,Azure bal,ND k5,0.0
60
+ 4,10,Azure bal,Auto high,0.0
61
+ 4,11,Azure bal,Auto low,0.0119
62
+ 5,0,Azure qual,Orca cheap,0.0
63
+ 5,1,Azure qual,Orca bal,0.0
64
+ 5,2,Azure qual,Orca qual,0.0
65
+ 5,3,Azure qual,Azure cost,0.0317
66
+ 5,4,Azure qual,Azure bal,0.1111
67
+ 5,5,Azure qual,Azure qual,1.0
68
+ 5,6,Azure qual,NadirClaw,0.123
69
+ 5,7,Azure qual,Brick,0.0
70
+ 5,8,Azure qual,Cascade,0.0
71
+ 5,9,Azure qual,ND k5,0.0
72
+ 5,10,Azure qual,Auto high,0.0079
73
+ 5,11,Azure qual,Auto low,0.0
74
+ 6,0,NadirClaw,Orca cheap,0.0238
75
+ 6,1,NadirClaw,Orca bal,0.0238
76
+ 6,2,NadirClaw,Orca qual,0.0
77
+ 6,3,NadirClaw,Azure cost,0.0
78
+ 6,4,NadirClaw,Azure bal,0.0079
79
+ 6,5,NadirClaw,Azure qual,0.123
80
+ 6,6,NadirClaw,NadirClaw,1.0
81
+ 6,7,NadirClaw,Brick,0.0
82
+ 6,8,NadirClaw,Cascade,0.0
83
+ 6,9,NadirClaw,ND k5,0.3413
84
+ 6,10,NadirClaw,Auto high,0.004
85
+ 6,11,NadirClaw,Auto low,0.0
86
+ 7,0,Brick,Orca cheap,0.004
87
+ 7,1,Brick,Orca bal,0.004
88
+ 7,2,Brick,Orca qual,0.8016
89
+ 7,3,Brick,Azure cost,0.0
90
+ 7,4,Brick,Azure bal,0.0
91
+ 7,5,Brick,Azure qual,0.0
92
+ 7,6,Brick,NadirClaw,0.0
93
+ 7,7,Brick,Brick,1.0
94
+ 7,8,Brick,Cascade,0.4752
95
+ 7,9,Brick,ND k5,0.0
96
+ 7,10,Brick,Auto high,0.0
97
+ 7,11,Brick,Auto low,0.7897
98
+ 8,0,Cascade,Orca cheap,0.0083
99
+ 8,1,Cascade,Orca bal,0.0
100
+ 8,2,Cascade,Orca qual,0.5826
101
+ 8,3,Cascade,Azure cost,0.0
102
+ 8,4,Cascade,Azure bal,0.0
103
+ 8,5,Cascade,Azure qual,0.0
104
+ 8,6,Cascade,NadirClaw,0.0
105
+ 8,7,Cascade,Brick,0.4752
106
+ 8,8,Cascade,Cascade,1.0
107
+ 8,9,Cascade,ND k5,0.0
108
+ 8,10,Cascade,Auto high,0.0
109
+ 8,11,Cascade,Auto low,0.5702
110
+ 9,0,ND k5,Orca cheap,0.0
111
+ 9,1,ND k5,Orca bal,0.0
112
+ 9,2,ND k5,Orca qual,0.0
113
+ 9,3,ND k5,Azure cost,0.0
114
+ 9,4,ND k5,Azure bal,0.0
115
+ 9,5,ND k5,Azure qual,0.0
116
+ 9,6,ND k5,NadirClaw,0.3413
117
+ 9,7,ND k5,Brick,0.0
118
+ 9,8,ND k5,Cascade,0.0
119
+ 9,9,ND k5,ND k5,1.0
120
+ 9,10,ND k5,Auto high,0.0
121
+ 9,11,ND k5,Auto low,0.0
122
+ 10,0,Auto high,Orca cheap,0.004
123
+ 10,1,Auto high,Orca bal,0.004
124
+ 10,2,Auto high,Orca qual,0.0
125
+ 10,3,Auto high,Azure cost,0.0
126
+ 10,4,Auto high,Azure bal,0.0
127
+ 10,5,Auto high,Azure qual,0.0079
128
+ 10,6,Auto high,NadirClaw,0.004
129
+ 10,7,Auto high,Brick,0.0
130
+ 10,8,Auto high,Cascade,0.0
131
+ 10,9,Auto high,ND k5,0.0
132
+ 10,10,Auto high,Auto high,1.0
133
+ 10,11,Auto high,Auto low,0.0
134
+ 11,0,Auto low,Orca cheap,0.0119
135
+ 11,1,Auto low,Orca bal,0.0079
136
+ 11,2,Auto low,Orca qual,0.9841
137
+ 11,3,Auto low,Azure cost,0.0
138
+ 11,4,Auto low,Azure bal,0.0119
139
+ 11,5,Auto low,Azure qual,0.0
140
+ 11,6,Auto low,NadirClaw,0.0
141
+ 11,7,Auto low,Brick,0.7897
142
+ 11,8,Auto low,Cascade,0.5702
143
+ 11,9,Auto low,ND k5,0.0
144
+ 11,10,Auto low,Auto high,0.0
145
+ 11,11,Auto low,Auto low,1.0