CP Legendre commited on
Commit
52073ff
·
1 Parent(s): 4fd20a0

Finalize efficiency review updates

Browse files
Files changed (5) hide show
  1. README.md +54 -50
  2. app.py +56 -107
  3. src/charts.py +119 -55
  4. src/leaderboard.py +87 -35
  5. tests/test_token_efficiency.py +237 -85
README.md CHANGED
@@ -19,77 +19,45 @@ Compare coding-agent models and harnesses across benchmark performance, cost, la
19
 
20
  ## Leaderboard views
21
 
22
- ### Cost vs Performance
23
 
24
- The Cost vs Performance scatter plot compares benchmark score with mean cost per task. Use its controls to select the benchmark, grouping, color palette, image background, and optional point labels.
 
25
 
26
- Point labels are disabled by default to keep the chart uncluttered. When enabled, concise run labels are shown without replacing the full hover details.
27
 
28
- ### Token Efficiency
 
 
29
 
30
- The **Efficiency** tab shows that score alone is insufficient: agents with similar benchmark performance can use substantially different token budgets.
31
 
32
- The tab provides:
33
-
34
- - benchmark filtering, including **All benchmarks**
35
- - total, input, output, or solved-task-normalized token metrics
36
- - linear or logarithmic token axes
37
- - coloring by model, harness, or benchmark
38
- - optional point labels
39
- - an optional token-efficiency Pareto frontier
40
- - a sortable token-efficiency ranking table
41
-
42
- #### Metric definitions
43
-
44
- Scores are stored internally as fractions from 0 to 1 and displayed as percentages.
45
-
46
- - **Total Tokens Per Task**: mean total token usage for one task.
47
- - **Input Tokens Per Task**: mean input token usage for one task.
48
- - **Output Tokens Per Task**: mean output token usage for one task.
49
- - **Cache Tokens Per Task**: mean cached token usage for one task.
50
- - **Tokens Per Solved Task**: `Total Tokens Per Task / Score`, where Score is the fractional value from 0 to 1.
51
-
52
- For example, a run using 10,000 total tokens per task with a score of 0.5 has 20,000 Tokens Per Solved Task.
53
-
54
- #### Missing and invalid token data
55
-
56
- A token measurement is available only when its value is present and greater than zero. Missing, zero, and negative token values are excluded from token-efficiency plots rather than treated as perfect efficiency.
57
-
58
- Tokens Per Solved Task is also unavailable when the score is zero or negative, which avoids division by zero. The UI reports how many runs were omitted because the selected token metric was missing or non-positive.
59
 
60
  #### Pareto frontier
61
 
62
- A run is token Pareto-efficient when no other displayed run:
63
 
64
- - uses fewer or equal tokens, and
65
  - achieves an equal or higher score,
66
 
67
- with at least one of those comparisons being a strict improvement.
68
 
69
- The dashed frontier connects the efficient runs. Points below and to the right of the frontier are dominated: another run achieves at least as much score with no more token usage.
70
 
71
- The dotted horizontal lines at **70%** and **80%** are fixed capability guides for visual orientation. They do not affect Pareto membership and are not statistical thresholds.
72
-
73
- #### Color palettes and themes
74
 
75
- The Cost vs Performance and Efficiency charts share the same palette registry and support:
76
 
77
- - Default
78
- - Pastel
79
- - Bold
80
- - Safe
81
- - Grayscale
82
- - Viridis
83
- - Plasma
84
- - Cividis
85
 
86
- All palettes are available with light and dark chart backgrounds. The grayscale endpoints use near-white and near-black shades to retain practical contrast on both backgrounds.
87
 
88
  ## Adding a New Leaderboard Entry
89
 
90
  Create a pull request adding a new entry to the `results/` folder. See [`results/qwen3-6-35b-nvfp4-claude-code.json`](./results/qwen3-6-35b-nvfp4-claude-code.json) for an example result.
91
 
92
- Do not change the result JSON schema for token-efficiency analysis. The feature uses token and performance metrics already present in the existing result model.
93
 
94
  ## Development
95
 
@@ -115,3 +83,39 @@ Do not change the result JSON schema for token-efficiency analysis. The feature
115
  ```sh
116
  pytest
117
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  ## Leaderboard views
21
 
22
+ ### Efficiency
23
 
24
+ The **Efficiency** tab compares benchmark score with resource use for one selected benchmark at a time. Keeping the view benchmark-specific avoids misleading comparisons when model and harness combinations have incomplete benchmark coverage.
25
+ The generalized performance-vs-resource chart covers tokens, cost, and agent time in one benchmark-specific view.
26
 
27
+ The scatter plot supports three resource metrics on the x-axis:
28
 
29
+ - **Total tokens**: mean total token usage per task.
30
+ - **Cost per task**: the repository's reported `mean_cost_usd_per_task` value, in USD.
31
+ - **Agent time per task**: the repository's reported `mean_agent_time_seconds_per_task` value, in seconds.
32
 
33
+ Only positive, available values for the selected resource are plotted. Missing, zero, and negative values are treated as unavailable rather than as perfect efficiency. The UI reports how many runs for the selected benchmark were excluded for the chosen resource metric.
34
 
35
+ Scores are stored internally as fractions from 0 to 1 and displayed as percentages. Point labels are optional and coloring can be grouped by **Model** or **Harness**. Linear and logarithmic resource axes are available.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  #### Pareto frontier
38
 
39
+ For all three resource metrics, lower resource use and higher score are better. A displayed run is Pareto-efficient when no other valid run on the selected benchmark:
40
 
41
+ - uses an equal or lower amount of the selected resource, and
42
  - achieves an equal or higher score,
43
 
44
+ with at least one strict improvement. Tied nondominated points are preserved. The dashed line connects the Pareto-efficient observations.
45
 
46
+ #### Ranking table
47
 
48
+ The ranking table remains benchmark-specific and begins with **Model**, **Harness**, and **Benchmark**. Displayed scores are rounded to one decimal place without reducing the precision used for calculations.
 
 
49
 
50
+ **Tokens Per Solved Task** remains available in the table as a reference metric even though it is no longer an Efficiency scatter x-axis option. It is defined as `Total Tokens Per Task / Score`, where Score is the fractional value from 0 to 1. It is unavailable when total token data is missing/non-positive or when Score is zero or negative.
51
 
52
+ #### Color palettes and themes
 
 
 
 
 
 
 
53
 
54
+ The Efficiency chart uses the shared palette registry and supports Citrus, Okabe-Ito, High contrast, Rainbow, Grayscale, Viridis, Plasma, and Cividis palettes with light and dark chart backgrounds.
55
 
56
  ## Adding a New Leaderboard Entry
57
 
58
  Create a pull request adding a new entry to the `results/` folder. See [`results/qwen3-6-35b-nvfp4-claude-code.json`](./results/qwen3-6-35b-nvfp4-claude-code.json) for an example result.
59
 
60
+ Do not change the result JSON schema for Efficiency analysis. The feature uses resource and performance metrics already present in the existing result model.
61
 
62
  ## Development
63
 
 
83
  ```sh
84
  pytest
85
  ```
86
+
87
+ ## Manual validation
88
+
89
+ After automated checks pass, launch the app from a clean process with `python app.py` and verify the Efficiency view in a real browser. Unit tests and figure-level smoke tests do not replace this browser validation.
90
+
91
+ ### Efficiency behavior
92
+
93
+ - Confirm there is no **All benchmarks** option and that a valid benchmark is selected by default.
94
+ - Confirm **Color By** offers only **Model** and **Harness**.
95
+ - Confirm the resource selector offers **Total tokens**, **Cost per task**, and **Agent time per task**.
96
+ - Switch through all three resource metrics and verify axis labels and hover formatting.
97
+ - Verify the Pareto frontier for all three metrics.
98
+ - Verify linear and logarithmic scales where valid.
99
+ - Verify point labels off and on.
100
+ - Confirm the ranking table starts with **Model**, **Harness**, **Benchmark**, shows scores to one decimal place, and retains **Tokens Per Solved Task**.
101
+ - Confirm the existing Leaderboard and Benchmark Runs tabs still work without new terminal tracebacks.
102
+
103
+ ### Responsive layout verification
104
+
105
+ - Restart the app from a clean launch.
106
+ - Open **Efficiency** as the first non-default tab and confirm the plot is not squished.
107
+ - Switch away from Efficiency and back several times.
108
+ - Resize the browser narrower and wider.
109
+ - Confirm the plot resizes correctly without requiring a control change.
110
+ - Verify there is no legend overlap or clipping.
111
+ - Verify the ranking table below does not force the plot into a narrow column.
112
+ - Repeat the checks with point labels off and on, Pareto off and on, each resource metric, and light and dark plot backgrounds.
113
+ - Also switch **Leaderboard → Efficiency** and **Benchmark Runs → Efficiency** to confirm hidden-tab initialization does not collapse the chart.
114
+
115
+ ### PR completion report
116
+
117
+ The final PR report should state the files changed, metric definitions, tests and results, data-quality limitations, and whether the app was manually verified. For the responsive-layout fix, it must additionally record:
118
+
119
+ - the root cause of the initial squished-chart issue;
120
+ - the exact responsive-layout fix used; and
121
+ - whether the behavior was manually verified from a fresh app launch.
app.py CHANGED
@@ -50,8 +50,7 @@ from huggingface_hub import HfApi
50
  from src.charts import (
51
  clean_markdown_link,
52
  create_leaderboard_benchmark_plot,
53
- create_score_vs_cost_plot,
54
- create_score_vs_tokens_plot,
55
  )
56
  from src.display.text_blocks import (
57
  HOW_TO_USE_TEXT,
@@ -59,13 +58,11 @@ from src.display.text_blocks import (
59
  LLM_BENCHMARKS_TEXT,
60
  )
61
  from src.leaderboard import (
62
- ALL_BENCHMARKS,
63
- TOKEN_METRICS,
64
  get_analysis_df,
65
  get_benchmark_names,
66
  get_benchmark_run_df,
67
- get_score_vs_cost_df,
68
- get_token_efficiency_df,
69
  get_token_efficiency_table_df,
70
  )
71
 
@@ -73,7 +70,7 @@ REPO_ID = "taagarwa/coding-agent-leaderboard"
73
  TOKEN = os.environ.get("HF_TOKEN")
74
  API = HfApi(token=TOKEN)
75
  COLOR_BY_CHOICES = ["Model", "Harness"]
76
- EFFICIENCY_COLOR_BY_CHOICES = ["Model", "Harness", "Benchmark"]
77
  COLOR_PALETTE_CHOICES = [
78
  "Citrus",
79
  "Okabe-Ito",
@@ -87,7 +84,24 @@ COLOR_PALETTE_CHOICES = [
87
  DEFAULT_COLOR_PALETTE = "Citrus"
88
  PLOT_BACKGROUND_CHOICES = ["Dark", "White"]
89
  DEFAULT_PLOT_BACKGROUND = "Dark"
90
- FORCE_DARK_MODE_HEAD = """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  <script>
92
  (() => {
93
  const url = new URL(window.location.href);
@@ -97,10 +111,9 @@ FORCE_DARK_MODE_HEAD = """
97
  }
98
  })();
99
  </script>
100
- <style>
101
- .responsive-plot { overflow-x: auto; }
102
- </style>
103
  """
 
 
104
 
105
 
106
  def restart_space():
@@ -110,7 +123,6 @@ def restart_space():
110
  BENCHMARK_NAMES = get_benchmark_names()
111
  DEFAULT_BENCHMARK = BENCHMARK_NAMES[0] if BENCHMARK_NAMES else None
112
  BENCHMARK_RUN_DF = get_benchmark_run_df()
113
- SCORE_VS_COST_DF = get_score_vs_cost_df()
114
  ANALYSIS_DF = get_analysis_df()
115
 
116
 
@@ -129,24 +141,8 @@ def render_leaderboard_benchmark_plot(
129
  )
130
 
131
 
132
- def render_score_vs_cost_plot(
133
- benchmark_name,
134
- color_by,
135
- show_labels=False,
136
- color_palette=DEFAULT_COLOR_PALETTE,
137
- plot_background=DEFAULT_PLOT_BACKGROUND,
138
- ):
139
- return create_score_vs_cost_plot(
140
- SCORE_VS_COST_DF,
141
- benchmark_name=benchmark_name,
142
- color_by=color_by,
143
- show_labels=show_labels,
144
- palette_name=color_palette,
145
- background_name=plot_background,
146
- )
147
-
148
 
149
- def render_token_efficiency(
150
  benchmark_name,
151
  token_metric,
152
  color_by,
@@ -156,9 +152,9 @@ def render_token_efficiency(
156
  color_palette=DEFAULT_COLOR_PALETTE,
157
  plot_background=DEFAULT_PLOT_BACKGROUND,
158
  ):
159
- plot_df = get_token_efficiency_df(
160
  benchmark_name=benchmark_name,
161
- token_metric=token_metric,
162
  analysis_df=ANALYSIS_DF,
163
  )
164
  table_df = get_token_efficiency_table_df(
@@ -166,10 +162,10 @@ def render_token_efficiency(
166
  analysis_df=ANALYSIS_DF,
167
  )
168
  exclusion_count = plot_df.attrs.get("exclusion_count", 0)
169
- note = f"{exclusion_count} runs excluded because {token_metric.lower()} was missing or non-positive."
170
- figure = create_score_vs_tokens_plot(
171
  plot_df,
172
- token_metric=token_metric,
173
  color_by=color_by,
174
  x_scale=x_scale,
175
  show_pareto_frontier=show_pareto_frontier,
@@ -302,81 +298,25 @@ with demo:
302
  outputs=plot,
303
  )
304
 
305
- with gr.Tab("💰 Cost vs Performance"):
306
- cost_benchmark = gr.Dropdown(
307
- choices=BENCHMARK_NAMES,
308
- value=DEFAULT_BENCHMARK,
309
- label="Benchmark",
310
- )
311
- with gr.Row():
312
- cost_color_by = gr.Radio(
313
- choices=COLOR_BY_CHOICES,
314
- value="Model",
315
- label="Color by",
316
- elem_classes="color-control",
317
- )
318
- cost_palette = gr.Dropdown(
319
- choices=COLOR_PALETTE_CHOICES,
320
- value=DEFAULT_COLOR_PALETTE,
321
- label="Color palette",
322
- elem_classes="color-control",
323
- )
324
- cost_background = gr.Dropdown(
325
- choices=PLOT_BACKGROUND_CHOICES,
326
- value=DEFAULT_PLOT_BACKGROUND,
327
- label="Image background",
328
- elem_classes="color-control",
329
- )
330
- cost_labels = gr.Checkbox(
331
- value=False,
332
- label="Show point labels",
333
- elem_classes="color-control",
334
- )
335
- score_vs_cost_plot = gr.Plot(
336
- value=render_score_vs_cost_plot(
337
- DEFAULT_BENCHMARK,
338
- "Model",
339
- False,
340
- DEFAULT_COLOR_PALETTE,
341
- DEFAULT_PLOT_BACKGROUND,
342
- ),
343
- show_label=False,
344
- elem_classes="responsive-plot",
345
- )
346
- cost_controls = [
347
- cost_benchmark,
348
- cost_color_by,
349
- cost_labels,
350
- cost_palette,
351
- cost_background,
352
- ]
353
- for control in cost_controls:
354
- control.change(
355
- fn=render_score_vs_cost_plot,
356
- inputs=cost_controls,
357
- outputs=score_vs_cost_plot,
358
- )
359
-
360
- with gr.Tab("⚡ Efficiency"):
361
  gr.Markdown(
362
- "### Token Efficiency\n"
363
- "Score alone does not show how much token budget an agent uses to achieve it. "
364
- "Tokens Per Solved Task divides mean tokens per task by the fractional score. "
365
- "The dashed Pareto frontier connects runs for which no other run uses fewer or equal tokens "
366
- "while achieving an equal or higher score; points below and to the right are dominated. "
367
- "The dotted 70% and 80% horizontal lines are fixed capability guides only—they do not affect "
368
- "Pareto membership and are not statistical thresholds."
369
  )
370
  with gr.Row():
371
  efficiency_benchmark = gr.Dropdown(
372
- choices=[ALL_BENCHMARKS, *BENCHMARK_NAMES],
373
- value=ALL_BENCHMARKS,
374
  label="Benchmark",
375
  )
376
  efficiency_metric = gr.Dropdown(
377
- choices=list(TOKEN_METRICS),
378
- value="Tokens Per Solved Task",
379
- label="Token metric",
380
  )
381
  efficiency_color_by = gr.Radio(
382
  choices=EFFICIENCY_COLOR_BY_CHOICES,
@@ -398,9 +338,9 @@ with demo:
398
  label="Image background",
399
  )
400
 
401
- initial_efficiency = render_token_efficiency(
402
- ALL_BENCHMARKS,
403
- "Tokens Per Solved Task",
404
  "Model",
405
  "Log",
406
  True,
@@ -414,7 +354,7 @@ with demo:
414
  show_label=False,
415
  elem_classes="responsive-plot",
416
  )
417
- gr.Markdown("#### Token-efficiency ranking")
418
  efficiency_table = gr.Dataframe(
419
  value=initial_efficiency[1],
420
  interactive=False,
@@ -433,11 +373,20 @@ with demo:
433
  ]
434
  for control in efficiency_controls:
435
  control.change(
436
- fn=render_token_efficiency,
437
  inputs=efficiency_controls,
438
  outputs=[efficiency_plot, efficiency_table, efficiency_note],
439
  )
440
 
 
 
 
 
 
 
 
 
 
441
  with gr.Tab("🏃 Benchmark Runs"):
442
  benchmark_runs = init_benchmark_runs(BENCHMARK_RUN_DF)
443
 
 
50
  from src.charts import (
51
  clean_markdown_link,
52
  create_leaderboard_benchmark_plot,
53
+ create_performance_vs_resource_plot,
 
54
  )
55
  from src.display.text_blocks import (
56
  HOW_TO_USE_TEXT,
 
58
  LLM_BENCHMARKS_TEXT,
59
  )
60
  from src.leaderboard import (
61
+ EFFICIENCY_RESOURCE_METRICS,
 
62
  get_analysis_df,
63
  get_benchmark_names,
64
  get_benchmark_run_df,
65
+ get_efficiency_df,
 
66
  get_token_efficiency_table_df,
67
  )
68
 
 
70
  TOKEN = os.environ.get("HF_TOKEN")
71
  API = HfApi(token=TOKEN)
72
  COLOR_BY_CHOICES = ["Model", "Harness"]
73
+ EFFICIENCY_COLOR_BY_CHOICES = ["Model", "Harness"]
74
  COLOR_PALETTE_CHOICES = [
75
  "Citrus",
76
  "Okabe-Ito",
 
84
  DEFAULT_COLOR_PALETTE = "Citrus"
85
  PLOT_BACKGROUND_CHOICES = ["Dark", "White"]
86
  DEFAULT_PLOT_BACKGROUND = "Dark"
87
+ RESPONSIVE_PLOT_MIN_HEIGHT_PX = 420
88
+ RESPONSIVE_PLOT_CSS = f"""
89
+ <style>
90
+ .responsive-plot {{
91
+ overflow-x: auto;
92
+ width: 100%;
93
+ min-height: {RESPONSIVE_PLOT_MIN_HEIGHT_PX}px;
94
+ }}
95
+ .responsive-plot .plot-container,
96
+ .responsive-plot .js-plotly-plot,
97
+ .responsive-plot .plotly-graph-div {{
98
+ width: 100% !important;
99
+ min-height: {RESPONSIVE_PLOT_MIN_HEIGHT_PX}px;
100
+ }}
101
+ </style>
102
+ """
103
+ FORCE_DARK_MODE_HEAD = (
104
+ """
105
  <script>
106
  (() => {
107
  const url = new URL(window.location.href);
 
111
  }
112
  })();
113
  </script>
 
 
 
114
  """
115
+ + RESPONSIVE_PLOT_CSS
116
+ )
117
 
118
 
119
  def restart_space():
 
123
  BENCHMARK_NAMES = get_benchmark_names()
124
  DEFAULT_BENCHMARK = BENCHMARK_NAMES[0] if BENCHMARK_NAMES else None
125
  BENCHMARK_RUN_DF = get_benchmark_run_df()
 
126
  ANALYSIS_DF = get_analysis_df()
127
 
128
 
 
141
  )
142
 
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
145
+ def render_efficiency(
146
  benchmark_name,
147
  token_metric,
148
  color_by,
 
152
  color_palette=DEFAULT_COLOR_PALETTE,
153
  plot_background=DEFAULT_PLOT_BACKGROUND,
154
  ):
155
+ plot_df = get_efficiency_df(
156
  benchmark_name=benchmark_name,
157
+ resource_metric=token_metric,
158
  analysis_df=ANALYSIS_DF,
159
  )
160
  table_df = get_token_efficiency_table_df(
 
162
  analysis_df=ANALYSIS_DF,
163
  )
164
  exclusion_count = plot_df.attrs.get("exclusion_count", 0)
165
+ note = f"{exclusion_count} runs excluded for this benchmark because {token_metric.lower()} was missing or non-positive."
166
+ figure = create_performance_vs_resource_plot(
167
  plot_df,
168
+ resource_metric=token_metric,
169
  color_by=color_by,
170
  x_scale=x_scale,
171
  show_pareto_frontier=show_pareto_frontier,
 
298
  outputs=plot,
299
  )
300
 
301
+ with gr.Tab(" Efficiency") as efficiency_tab:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  gr.Markdown(
303
+ "### Efficiency\n"
304
+ "Compare score with resource use within one benchmark. The x-axis can show total tokens, "
305
+ "cost per task, or agent execution time per task. The dashed Pareto frontier connects runs "
306
+ "for which no other displayed run uses an equal or lower amount of the selected resource "
307
+ "while achieving an equal or higher score. Tokens Per Solved Task remains in the ranking "
308
+ "table as a reference metric."
 
309
  )
310
  with gr.Row():
311
  efficiency_benchmark = gr.Dropdown(
312
+ choices=BENCHMARK_NAMES,
313
+ value=BENCHMARK_NAMES[0] if BENCHMARK_NAMES else None,
314
  label="Benchmark",
315
  )
316
  efficiency_metric = gr.Dropdown(
317
+ choices=list(EFFICIENCY_RESOURCE_METRICS),
318
+ value="Total tokens",
319
+ label="Resource metric",
320
  )
321
  efficiency_color_by = gr.Radio(
322
  choices=EFFICIENCY_COLOR_BY_CHOICES,
 
338
  label="Image background",
339
  )
340
 
341
+ initial_efficiency = render_efficiency(
342
+ BENCHMARK_NAMES[0] if BENCHMARK_NAMES else None,
343
+ "Total tokens",
344
  "Model",
345
  "Log",
346
  True,
 
354
  show_label=False,
355
  elem_classes="responsive-plot",
356
  )
357
+ gr.Markdown("#### Efficiency ranking")
358
  efficiency_table = gr.Dataframe(
359
  value=initial_efficiency[1],
360
  interactive=False,
 
373
  ]
374
  for control in efficiency_controls:
375
  control.change(
376
+ fn=render_efficiency,
377
  inputs=efficiency_controls,
378
  outputs=[efficiency_plot, efficiency_table, efficiency_note],
379
  )
380
 
381
+ # Gradio initially lays out hidden tabs without reliable dimensions. Re-render
382
+ # once Efficiency becomes visible so Plotly can autosize against the real
383
+ # container instead of keeping the hidden-tab geometry.
384
+ efficiency_tab.select(
385
+ fn=render_efficiency,
386
+ inputs=efficiency_controls,
387
+ outputs=[efficiency_plot, efficiency_table, efficiency_note],
388
+ )
389
+
390
  with gr.Tab("🏃 Benchmark Runs"):
391
  benchmark_runs = init_benchmark_runs(BENCHMARK_RUN_DF)
392
 
src/charts.py CHANGED
@@ -103,31 +103,6 @@ PLOT_BACKGROUNDS: dict[PlotBackground, dict[str, str]] = {
103
 
104
 
105
 
106
- CAPABILITY_TIER_BOUNDARIES = (70.0, 80.0)
107
-
108
-
109
- def add_capability_tier_guides(fig: Figure, background_name: str | None = DEFAULT_BACKGROUND) -> None:
110
- """Add fixed score-band guides without affecting Pareto calculations."""
111
- theme = get_plot_background(background_name)
112
- for boundary in CAPABILITY_TIER_BOUNDARIES:
113
- fig.add_hline(
114
- y=boundary,
115
- line={"width": 1.5, "dash": "dot", "color": theme["zero_line_color"]},
116
- layer="below",
117
- )
118
- fig.add_annotation(
119
- x=1.0,
120
- xref="paper",
121
- xanchor="right",
122
- y=boundary,
123
- yref="y",
124
- yshift=8,
125
- text=f"{boundary:.0f}% guide",
126
- showarrow=False,
127
- font={"size": 11, "color": theme["text_muted"]},
128
- )
129
-
130
-
131
  def clean_markdown_link(value: object) -> str:
132
  """Return human-readable text from Markdown links used in leaderboard tables."""
133
  text = str(value).replace("<sup>*</sup>", "")
@@ -312,9 +287,7 @@ def prepare_benchmark_run_plot_df(dataframe: pd.DataFrame) -> pd.DataFrame:
312
  plot_df["Model Label"] = plot_df["Model"].map(clean_markdown_link)
313
  plot_df["Harness Label"] = plot_df["Harness"].map(clean_markdown_link)
314
  plot_df["Benchmark Label"] = plot_df["Benchmark"].map(clean_markdown_link)
315
- plot_df["Run Label"] = (
316
- plot_df["Model Label"] + " / " + plot_df["Harness Label"]
317
- )
318
  plot_df["Score"] = pd.to_numeric(plot_df["Score"], errors="coerce")
319
  return plot_df
320
 
@@ -323,6 +296,7 @@ def create_leaderboard_benchmark_plot(
323
  dataframe: pd.DataFrame,
324
  benchmark_name: str,
325
  color_by: ColorBy = "Model",
 
326
  palette_name: str | None = DEFAULT_PALETTE,
327
  background_name: str | None = DEFAULT_BACKGROUND,
328
  ) -> Figure:
@@ -451,36 +425,82 @@ def create_score_vs_cost_plot(
451
  return apply_plot_theme(fig, background_name)
452
 
453
 
454
- def create_score_vs_tokens_plot(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
  dataframe: pd.DataFrame,
456
- token_metric: str = "Tokens Per Solved Task",
457
- color_by: Literal["Model", "Harness", "Benchmark"] = "Model",
458
  x_scale: Literal["Linear", "Log"] = "Log",
459
  show_pareto_frontier: bool = True,
460
  show_labels: bool = False,
461
  palette_name: str | None = DEFAULT_PALETTE,
462
  background_name: str | None = DEFAULT_BACKGROUND,
463
  ) -> Figure:
464
- """Plot score against a positive token metric, optionally with its Pareto frontier."""
465
- from src.leaderboard import get_token_pareto_frontier_df
 
 
 
 
 
 
 
 
 
 
466
 
467
  if dataframe is None or dataframe.empty:
468
- return empty_figure("No valid token data available.", background_name)
469
- if token_metric not in dataframe.columns:
470
- return empty_figure(f"Token metric not available: {token_metric}.", background_name)
471
- if color_by not in dataframe.columns:
472
  return empty_figure(f"Color dimension not available: {color_by}.", background_name)
473
 
474
  plot_df = dataframe.copy()
475
- plot_df[token_metric] = pd.to_numeric(plot_df[token_metric], errors="coerce")
 
 
 
476
  plot_df["Score (%)"] = pd.to_numeric(plot_df["Score (%)"], errors="coerce")
477
- plot_df = plot_df.dropna(subset=[token_metric, "Score (%)"])
478
- plot_df = plot_df[plot_df[token_metric] > 0]
479
  if plot_df.empty:
480
- return empty_figure("No valid token data available.", background_name)
481
 
482
- palette_color_by: ColorBy = color_by if color_by in ("Model", "Harness") else "Model"
483
- colors = color_map_for(plot_df[color_by], palette_color_by, palette_name)
484
  theme = get_plot_background(background_name)
485
  fig = go.Figure()
486
  hover_columns = [
@@ -500,11 +520,17 @@ def create_score_vs_tokens_plot(
500
  if column not in plot_df:
501
  plot_df[column] = None
502
 
 
 
 
 
 
 
503
  for group, group_df in plot_df.groupby(color_by, sort=True):
504
  label_kwargs = scatter_label_kwargs(group_df, show_labels)
505
  fig.add_trace(
506
  go.Scatter(
507
- x=group_df[token_metric],
508
  y=group_df["Score (%)"],
509
  name=str(group),
510
  **label_kwargs,
@@ -519,24 +545,30 @@ def create_score_vs_tokens_plot(
519
  "Harness: %{customdata[1]}<br>"
520
  "Benchmark: %{customdata[2]}<br>"
521
  "Score: %{customdata[3]:.1f}%<br>"
 
522
  "Input tokens/task: %{customdata[4]:,.0f}<br>"
523
  "Output tokens/task: %{customdata[5]:,.0f}<br>"
524
  "Cache tokens/task: %{customdata[6]:,.0f}<br>"
525
  "Total tokens/task: %{customdata[7]:,.0f}<br>"
526
  "Cost/task: $%{customdata[8]:.4f}<br>"
527
- "Total time/task: %{customdata[9]:,.0f}s<br>"
528
- "Agent time/task: %{customdata[10]:,.0f}s"
529
  "<extra></extra>"
530
  ),
531
  )
532
  )
533
 
534
  if show_pareto_frontier:
535
- frontier_df = get_token_pareto_frontier_df(plot_df, token_metric)
536
  if not frontier_df.empty:
 
 
 
 
 
537
  fig.add_trace(
538
  go.Scatter(
539
- x=frontier_df[token_metric],
540
  y=frontier_df["Score (%)"],
541
  mode="lines+markers",
542
  name="Pareto frontier",
@@ -551,35 +583,67 @@ def create_score_vs_tokens_plot(
551
  hovertemplate=(
552
  "<b>Pareto frontier</b><br>"
553
  "%{customdata[0]}<br>"
554
- f"{token_metric}: %{{x:,.0f}}<br>"
555
  "Score: %{y:.1f}%<extra></extra>"
556
  ),
557
  )
558
  )
559
 
560
- add_capability_tier_guides(fig, background_name)
 
 
 
 
 
 
 
 
561
 
562
  fig.update_layout(
563
  title=None,
564
- xaxis={"title": token_metric, "type": "log" if x_scale == "Log" else "linear"},
565
  yaxis={"title": "Score (%)", "range": [0, 105]},
566
  legend_title_text=color_by,
567
  )
568
  return apply_plot_theme(fig, background_name)
569
 
570
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
571
  def create_token_pareto_frontier_plot(
572
  dataframe: pd.DataFrame,
573
- token_metric: str = "Tokens Per Solved Task",
574
- color_by: Literal["Model", "Harness", "Benchmark"] = "Model",
575
  x_scale: Literal["Linear", "Log"] = "Log",
576
  show_labels: bool = False,
577
  palette_name: str | None = DEFAULT_PALETTE,
578
  background_name: str | None = DEFAULT_BACKGROUND,
579
  ) -> Figure:
580
- return create_score_vs_tokens_plot(
 
581
  dataframe=dataframe,
582
- token_metric=token_metric,
583
  color_by=color_by,
584
  x_scale=x_scale,
585
  show_pareto_frontier=True,
 
103
 
104
 
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  def clean_markdown_link(value: object) -> str:
107
  """Return human-readable text from Markdown links used in leaderboard tables."""
108
  text = str(value).replace("<sup>*</sup>", "")
 
287
  plot_df["Model Label"] = plot_df["Model"].map(clean_markdown_link)
288
  plot_df["Harness Label"] = plot_df["Harness"].map(clean_markdown_link)
289
  plot_df["Benchmark Label"] = plot_df["Benchmark"].map(clean_markdown_link)
290
+ plot_df["Run Label"] = plot_df["Model Label"] + "<br>" + plot_df["Harness Label"]
 
 
291
  plot_df["Score"] = pd.to_numeric(plot_df["Score"], errors="coerce")
292
  return plot_df
293
 
 
296
  dataframe: pd.DataFrame,
297
  benchmark_name: str,
298
  color_by: ColorBy = "Model",
299
+ show_labels: bool = False,
300
  palette_name: str | None = DEFAULT_PALETTE,
301
  background_name: str | None = DEFAULT_BACKGROUND,
302
  ) -> Figure:
 
425
  return apply_plot_theme(fig, background_name)
426
 
427
 
428
+ RESOURCE_AXIS_CONFIG = {
429
+ "Total tokens": {
430
+ "column": "Total Tokens Per Task",
431
+ "axis_title": "Total tokens per task",
432
+ "hover_label": "Total tokens/task",
433
+ "hover_format": ",.0f",
434
+ },
435
+ "Cost per task": {
436
+ "column": "Cost Per Task",
437
+ "axis_title": "Cost per task (USD)",
438
+ "hover_label": "Cost/task",
439
+ "hover_format": ".4f",
440
+ "tickprefix": "$",
441
+ },
442
+ "Agent time per task": {
443
+ "column": "Agent Time Per Task",
444
+ "axis_title": "Agent time per task (seconds)",
445
+ "hover_label": "Agent time/task",
446
+ "hover_format": ",.1f",
447
+ "ticksuffix": "s",
448
+ },
449
+ }
450
+
451
+
452
+ def _resource_axis_config(resource_metric: str) -> dict[str, str]:
453
+ """Return display metadata for a supported Efficiency resource metric."""
454
+ if resource_metric in RESOURCE_AXIS_CONFIG:
455
+ return RESOURCE_AXIS_CONFIG[resource_metric]
456
+ for config in RESOURCE_AXIS_CONFIG.values():
457
+ if resource_metric == config["column"]:
458
+ return config
459
+ raise ValueError(f"Unsupported efficiency resource metric: {resource_metric}")
460
+
461
+
462
+ def create_performance_vs_resource_plot(
463
  dataframe: pd.DataFrame,
464
+ resource_metric: str = "Total tokens",
465
+ color_by: ColorBy = "Model",
466
  x_scale: Literal["Linear", "Log"] = "Log",
467
  show_pareto_frontier: bool = True,
468
  show_labels: bool = False,
469
  palette_name: str | None = DEFAULT_PALETTE,
470
  background_name: str | None = DEFAULT_BACKGROUND,
471
  ) -> Figure:
472
+ """Plot benchmark score against one positive resource metric.
473
+
474
+ Lower resource use and higher score define the optional Pareto frontier.
475
+ The caller is expected to provide rows for one benchmark only.
476
+ """
477
+ from src.leaderboard import get_resource_pareto_frontier_df
478
+
479
+ try:
480
+ resource_config = _resource_axis_config(resource_metric)
481
+ except ValueError:
482
+ return empty_figure(f"Resource metric not available: {resource_metric}.", background_name)
483
+ resource_column = resource_config["column"]
484
 
485
  if dataframe is None or dataframe.empty:
486
+ return empty_figure("No valid resource data available for this benchmark.", background_name)
487
+ if resource_column not in dataframe.columns:
488
+ return empty_figure(f"Resource metric not available: {resource_column}.", background_name)
489
+ if color_by not in ("Model", "Harness") or color_by not in dataframe.columns:
490
  return empty_figure(f"Color dimension not available: {color_by}.", background_name)
491
 
492
  plot_df = dataframe.copy()
493
+ if "Benchmark" in plot_df.columns and plot_df["Benchmark"].dropna().nunique() > 1:
494
+ return empty_figure("Select one benchmark for the Efficiency view.", background_name)
495
+
496
+ plot_df[resource_column] = pd.to_numeric(plot_df[resource_column], errors="coerce")
497
  plot_df["Score (%)"] = pd.to_numeric(plot_df["Score (%)"], errors="coerce")
498
+ plot_df = plot_df.dropna(subset=[resource_column, "Score (%)"])
499
+ plot_df = plot_df[plot_df[resource_column] > 0]
500
  if plot_df.empty:
501
+ return empty_figure("No valid resource data available for this benchmark.", background_name)
502
 
503
+ colors = color_map_for(plot_df[color_by], color_by, palette_name)
 
504
  theme = get_plot_background(background_name)
505
  fig = go.Figure()
506
  hover_columns = [
 
520
  if column not in plot_df:
521
  plot_df[column] = None
522
 
523
+ resource_hover = f"{resource_config['hover_label']}: %{{x:{resource_config['hover_format']}}}"
524
+ if resource_metric == "Cost per task" or resource_column == "Cost Per Task":
525
+ resource_hover = f"{resource_config['hover_label']}: $%{{x:{resource_config['hover_format']}}}"
526
+ elif resource_metric == "Agent time per task" or resource_column == "Agent Time Per Task":
527
+ resource_hover += "s"
528
+
529
  for group, group_df in plot_df.groupby(color_by, sort=True):
530
  label_kwargs = scatter_label_kwargs(group_df, show_labels)
531
  fig.add_trace(
532
  go.Scatter(
533
+ x=group_df[resource_column],
534
  y=group_df["Score (%)"],
535
  name=str(group),
536
  **label_kwargs,
 
545
  "Harness: %{customdata[1]}<br>"
546
  "Benchmark: %{customdata[2]}<br>"
547
  "Score: %{customdata[3]:.1f}%<br>"
548
+ f"{resource_hover}<br>"
549
  "Input tokens/task: %{customdata[4]:,.0f}<br>"
550
  "Output tokens/task: %{customdata[5]:,.0f}<br>"
551
  "Cache tokens/task: %{customdata[6]:,.0f}<br>"
552
  "Total tokens/task: %{customdata[7]:,.0f}<br>"
553
  "Cost/task: $%{customdata[8]:.4f}<br>"
554
+ "Total time/task: %{customdata[9]:,.1f}s<br>"
555
+ "Agent time/task: %{customdata[10]:,.1f}s"
556
  "<extra></extra>"
557
  ),
558
  )
559
  )
560
 
561
  if show_pareto_frontier:
562
+ frontier_df = get_resource_pareto_frontier_df(plot_df, resource_column)
563
  if not frontier_df.empty:
564
+ frontier_hover = f"{resource_config['hover_label']}: %{{x:{resource_config['hover_format']}}}"
565
+ if resource_column == "Cost Per Task":
566
+ frontier_hover = f"{resource_config['hover_label']}: $%{{x:{resource_config['hover_format']}}}"
567
+ elif resource_column == "Agent Time Per Task":
568
+ frontier_hover += "s"
569
  fig.add_trace(
570
  go.Scatter(
571
+ x=frontier_df[resource_column],
572
  y=frontier_df["Score (%)"],
573
  mode="lines+markers",
574
  name="Pareto frontier",
 
583
  hovertemplate=(
584
  "<b>Pareto frontier</b><br>"
585
  "%{customdata[0]}<br>"
586
+ f"{frontier_hover}<br>"
587
  "Score: %{y:.1f}%<extra></extra>"
588
  ),
589
  )
590
  )
591
 
592
+
593
+ xaxis = {
594
+ "title": resource_config["axis_title"],
595
+ "type": "log" if x_scale == "Log" else "linear",
596
+ }
597
+ if "tickprefix" in resource_config:
598
+ xaxis["tickprefix"] = resource_config["tickprefix"]
599
+ if "ticksuffix" in resource_config:
600
+ xaxis["ticksuffix"] = resource_config["ticksuffix"]
601
 
602
  fig.update_layout(
603
  title=None,
604
+ xaxis=xaxis,
605
  yaxis={"title": "Score (%)", "range": [0, 105]},
606
  legend_title_text=color_by,
607
  )
608
  return apply_plot_theme(fig, background_name)
609
 
610
 
611
+ def create_score_vs_tokens_plot(
612
+ dataframe: pd.DataFrame,
613
+ token_metric: str = "Total tokens",
614
+ color_by: ColorBy = "Model",
615
+ x_scale: Literal["Linear", "Log"] = "Log",
616
+ show_pareto_frontier: bool = True,
617
+ show_labels: bool = False,
618
+ palette_name: str | None = DEFAULT_PALETTE,
619
+ background_name: str | None = DEFAULT_BACKGROUND,
620
+ ) -> Figure:
621
+ """Backward-compatible wrapper around the performance-vs-resource chart."""
622
+ return create_performance_vs_resource_plot(
623
+ dataframe=dataframe,
624
+ resource_metric=token_metric,
625
+ color_by=color_by,
626
+ x_scale=x_scale,
627
+ show_pareto_frontier=show_pareto_frontier,
628
+ show_labels=show_labels,
629
+ palette_name=palette_name,
630
+ background_name=background_name,
631
+ )
632
+
633
+
634
  def create_token_pareto_frontier_plot(
635
  dataframe: pd.DataFrame,
636
+ token_metric: str = "Total tokens",
637
+ color_by: ColorBy = "Model",
638
  x_scale: Literal["Linear", "Log"] = "Log",
639
  show_labels: bool = False,
640
  palette_name: str | None = DEFAULT_PALETTE,
641
  background_name: str | None = DEFAULT_BACKGROUND,
642
  ) -> Figure:
643
+ """Backward-compatible convenience wrapper with the Pareto frontier enabled."""
644
+ return create_performance_vs_resource_plot(
645
  dataframe=dataframe,
646
+ resource_metric=token_metric,
647
  color_by=color_by,
648
  x_scale=x_scale,
649
  show_pareto_frontier=True,
src/leaderboard.py CHANGED
@@ -12,13 +12,11 @@ BENCHMARK_SORT_ORDER = {
12
  "SWE-Bench Pro -- Ansible": 1,
13
  }
14
 
15
- ALL_BENCHMARKS = "All benchmarks"
16
- TOKEN_METRICS = (
17
- "Total Tokens Per Task",
18
- "Input Tokens Per Task",
19
- "Output Tokens Per Task",
20
- "Tokens Per Solved Task",
21
- )
22
  ANALYSIS_COLUMNS = [
23
  "Benchmark",
24
  "Model",
@@ -40,11 +38,13 @@ ANALYSIS_COLUMNS = [
40
  "Token Data Available",
41
  ]
42
  TOKEN_EFFICIENCY_TABLE_COLUMNS = [
43
- "Benchmark",
44
  "Model",
45
  "Harness",
 
46
  "Score (%)",
47
  "Total Tokens Per Task",
 
 
48
  "Input Tokens Per Task",
49
  "Output Tokens Per Task",
50
  "Cache Tokens Per Task",
@@ -81,6 +81,28 @@ def get_benchmark_names(results: list[Result] | None = None) -> list[str]:
81
  return sorted({r.benchmark.name for r in results}, key=benchmark_sort_key)
82
 
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  def get_analysis_df(results: list[Result] | None = None) -> pd.DataFrame:
85
  """Return one normalized analysis row per benchmark result."""
86
  if results is None:
@@ -90,8 +112,10 @@ def get_analysis_df(results: list[Result] | None = None) -> pd.DataFrame:
90
  for result in results:
91
  metrics = result.metrics
92
  model_label = result.model.repo or result.model.name
93
- total_tokens = metrics.mean_tokens_per_task
94
- token_data_available = total_tokens is not None and total_tokens > 0
 
 
95
  tokens_per_solved_task = (
96
  total_tokens / metrics.score
97
  if token_data_available and metrics.score > 0
@@ -113,9 +137,9 @@ def get_analysis_df(results: list[Result] | None = None) -> pd.DataFrame:
113
  "Output Tokens Per Task": metrics.mean_output_tokens_per_task,
114
  "Total Tokens Per Task": total_tokens,
115
  "Tokens Per Solved Task": tokens_per_solved_task,
116
- "Cost Per Task": metrics.mean_cost_usd_per_task,
117
  "Total Time Per Task": metrics.mean_total_time_seconds_per_task,
118
- "Agent Time Per Task": metrics.mean_agent_time_seconds_per_task,
119
  "Token Data Available": token_data_available,
120
  }
121
  )
@@ -123,61 +147,80 @@ def get_analysis_df(results: list[Result] | None = None) -> pd.DataFrame:
123
  return pd.DataFrame(rows, columns=ANALYSIS_COLUMNS)
124
 
125
 
126
- def get_token_efficiency_df(
127
- benchmark_name: str | None = ALL_BENCHMARKS,
128
- token_metric: str = "Tokens Per Solved Task",
129
  analysis_df: pd.DataFrame | None = None,
130
  ) -> pd.DataFrame:
131
- """Filter normalized analysis data for a selected positive token metric.
132
 
133
- The number of rows excluded because the selected metric is missing or
134
- non-positive is available as ``dataframe.attrs["exclusion_count"]``.
135
  """
136
- if token_metric not in TOKEN_METRICS:
137
- raise ValueError(f"Unsupported token metric: {token_metric}")
138
-
139
  dataframe = get_analysis_df() if analysis_df is None else analysis_df.copy()
140
- if benchmark_name and benchmark_name != ALL_BENCHMARKS:
141
- dataframe = dataframe[dataframe["Benchmark"] == benchmark_name].copy()
142
 
143
  if dataframe.empty:
144
  dataframe.attrs["exclusion_count"] = 0
145
  return dataframe
146
 
147
- metric_values = pd.to_numeric(dataframe[token_metric], errors="coerce")
148
  valid_mask = metric_values.notna() & (metric_values > 0)
149
  exclusion_count = int((~valid_mask).sum())
150
  dataframe = dataframe.loc[valid_mask].copy()
151
- dataframe[token_metric] = metric_values.loc[valid_mask]
152
  dataframe = dataframe.sort_values(
153
- ["Tokens Per Solved Task", "Score (%)", "Benchmark", "Model", "Harness"],
154
- ascending=[True, False, True, True, True],
155
  na_position="last",
156
  )
157
  dataframe.attrs["exclusion_count"] = exclusion_count
158
  return dataframe
159
 
160
 
 
 
 
 
 
 
 
 
 
161
  def get_token_efficiency_table_df(
162
- benchmark_name: str | None = ALL_BENCHMARKS,
163
  analysis_df: pd.DataFrame | None = None,
164
  ) -> pd.DataFrame:
165
- dataframe = get_token_efficiency_df(
166
- benchmark_name=benchmark_name,
167
- token_metric="Tokens Per Solved Task",
168
- analysis_df=analysis_df,
 
 
 
 
 
 
 
169
  )
170
  table_df = dataframe.reindex(columns=TOKEN_EFFICIENCY_TABLE_COLUMNS).copy()
171
- table_df.attrs.update(dataframe.attrs)
 
 
 
 
 
 
172
  return table_df
173
 
174
 
175
- def get_token_pareto_frontier_df(
176
  dataframe: pd.DataFrame,
177
  token_metric: str,
178
  score_column: str = "Score (%)",
179
  ) -> pd.DataFrame:
180
- """Return deterministic non-dominated points for lower tokens/higher score."""
181
  if token_metric not in dataframe.columns or score_column not in dataframe.columns:
182
  return dataframe.iloc[0:0].copy()
183
 
@@ -211,6 +254,15 @@ def get_token_pareto_frontier_df(
211
  )
212
 
213
 
 
 
 
 
 
 
 
 
 
214
  def get_benchmark_run_df():
215
  results = get_results()
216
 
 
12
  "SWE-Bench Pro -- Ansible": 1,
13
  }
14
 
15
+ EFFICIENCY_RESOURCE_METRICS = {
16
+ "Total tokens": "Total Tokens Per Task",
17
+ "Cost per task": "Cost Per Task",
18
+ "Agent time per task": "Agent Time Per Task",
19
+ }
 
 
20
  ANALYSIS_COLUMNS = [
21
  "Benchmark",
22
  "Model",
 
38
  "Token Data Available",
39
  ]
40
  TOKEN_EFFICIENCY_TABLE_COLUMNS = [
 
41
  "Model",
42
  "Harness",
43
+ "Benchmark",
44
  "Score (%)",
45
  "Total Tokens Per Task",
46
+ "Cost Per Task",
47
+ "Agent Time Per Task",
48
  "Input Tokens Per Task",
49
  "Output Tokens Per Task",
50
  "Cache Tokens Per Task",
 
81
  return sorted({r.benchmark.name for r in results}, key=benchmark_sort_key)
82
 
83
 
84
+ def _positive_number_or_none(value: object) -> float | None:
85
+ """Return a positive numeric value, otherwise ``None``."""
86
+ if value is None:
87
+ return None
88
+ try:
89
+ numeric = float(value)
90
+ except (TypeError, ValueError):
91
+ return None
92
+ if pd.isna(numeric) or numeric <= 0:
93
+ return None
94
+ return numeric
95
+
96
+
97
+ def get_efficiency_resource_column(metric_name: str) -> str:
98
+ """Resolve an Efficiency UI metric name to its canonical analysis column."""
99
+ if metric_name in EFFICIENCY_RESOURCE_METRICS:
100
+ return EFFICIENCY_RESOURCE_METRICS[metric_name]
101
+ if metric_name in EFFICIENCY_RESOURCE_METRICS.values():
102
+ return metric_name
103
+ raise ValueError(f"Unsupported efficiency resource metric: {metric_name}")
104
+
105
+
106
  def get_analysis_df(results: list[Result] | None = None) -> pd.DataFrame:
107
  """Return one normalized analysis row per benchmark result."""
108
  if results is None:
 
112
  for result in results:
113
  metrics = result.metrics
114
  model_label = result.model.repo or result.model.name
115
+ total_tokens = _positive_number_or_none(metrics.mean_tokens_per_task)
116
+ cost_per_task = _positive_number_or_none(metrics.mean_cost_usd_per_task)
117
+ agent_time_per_task = _positive_number_or_none(metrics.mean_agent_time_seconds_per_task)
118
+ token_data_available = total_tokens is not None
119
  tokens_per_solved_task = (
120
  total_tokens / metrics.score
121
  if token_data_available and metrics.score > 0
 
137
  "Output Tokens Per Task": metrics.mean_output_tokens_per_task,
138
  "Total Tokens Per Task": total_tokens,
139
  "Tokens Per Solved Task": tokens_per_solved_task,
140
+ "Cost Per Task": cost_per_task,
141
  "Total Time Per Task": metrics.mean_total_time_seconds_per_task,
142
+ "Agent Time Per Task": agent_time_per_task,
143
  "Token Data Available": token_data_available,
144
  }
145
  )
 
147
  return pd.DataFrame(rows, columns=ANALYSIS_COLUMNS)
148
 
149
 
150
+ def get_efficiency_df(
151
+ benchmark_name: str,
152
+ resource_metric: str = "Total tokens",
153
  analysis_df: pd.DataFrame | None = None,
154
  ) -> pd.DataFrame:
155
+ """Return valid resource rows for one benchmark-specific Efficiency plot.
156
 
157
+ The number of rows excluded because the selected resource is missing or
158
+ non-positive is exposed via ``dataframe.attrs["exclusion_count"]``.
159
  """
160
+ metric_column = get_efficiency_resource_column(resource_metric)
 
 
161
  dataframe = get_analysis_df() if analysis_df is None else analysis_df.copy()
162
+ dataframe = dataframe[dataframe["Benchmark"] == benchmark_name].copy()
 
163
 
164
  if dataframe.empty:
165
  dataframe.attrs["exclusion_count"] = 0
166
  return dataframe
167
 
168
+ metric_values = pd.to_numeric(dataframe[metric_column], errors="coerce")
169
  valid_mask = metric_values.notna() & (metric_values > 0)
170
  exclusion_count = int((~valid_mask).sum())
171
  dataframe = dataframe.loc[valid_mask].copy()
172
+ dataframe[metric_column] = metric_values.loc[valid_mask]
173
  dataframe = dataframe.sort_values(
174
+ [metric_column, "Score (%)", "Model", "Harness"],
175
+ ascending=[True, False, True, True],
176
  na_position="last",
177
  )
178
  dataframe.attrs["exclusion_count"] = exclusion_count
179
  return dataframe
180
 
181
 
182
+ def get_token_efficiency_df(
183
+ benchmark_name: str,
184
+ token_metric: str = "Total tokens",
185
+ analysis_df: pd.DataFrame | None = None,
186
+ ) -> pd.DataFrame:
187
+ """Backward-compatible wrapper for :func:`get_efficiency_df`."""
188
+ return get_efficiency_df(benchmark_name, token_metric, analysis_df)
189
+
190
+
191
  def get_token_efficiency_table_df(
192
+ benchmark_name: str,
193
  analysis_df: pd.DataFrame | None = None,
194
  ) -> pd.DataFrame:
195
+ """Return the benchmark-specific Efficiency ranking table for display."""
196
+ dataframe = get_analysis_df() if analysis_df is None else analysis_df.copy()
197
+ dataframe = dataframe[dataframe["Benchmark"] == benchmark_name].copy()
198
+ if dataframe.empty:
199
+ return pd.DataFrame(columns=TOKEN_EFFICIENCY_TABLE_COLUMNS)
200
+
201
+ dataframe["Score (%)"] = pd.to_numeric(dataframe["Score (%)"], errors="coerce")
202
+ dataframe = dataframe.sort_values(
203
+ ["Tokens Per Solved Task", "Score (%)", "Model", "Harness"],
204
+ ascending=[True, False, True, True],
205
+ na_position="last",
206
  )
207
  table_df = dataframe.reindex(columns=TOKEN_EFFICIENCY_TABLE_COLUMNS).copy()
208
+ table_df["Score (%)"] = table_df["Score (%)"].round(1)
209
+ if "Cost Per Task" in table_df:
210
+ table_df["Cost Per Task"] = pd.to_numeric(table_df["Cost Per Task"], errors="coerce").round(4)
211
+ if "Agent Time Per Task" in table_df:
212
+ table_df["Agent Time Per Task"] = pd.to_numeric(
213
+ table_df["Agent Time Per Task"], errors="coerce"
214
+ ).round(1)
215
  return table_df
216
 
217
 
218
+ def get_resource_pareto_frontier_df(
219
  dataframe: pd.DataFrame,
220
  token_metric: str,
221
  score_column: str = "Score (%)",
222
  ) -> pd.DataFrame:
223
+ """Return deterministic non-dominated points for lower resource use/higher score."""
224
  if token_metric not in dataframe.columns or score_column not in dataframe.columns:
225
  return dataframe.iloc[0:0].copy()
226
 
 
254
  )
255
 
256
 
257
+ def get_token_pareto_frontier_df(
258
+ dataframe: pd.DataFrame,
259
+ token_metric: str,
260
+ score_column: str = "Score (%)",
261
+ ) -> pd.DataFrame:
262
+ """Backward-compatible wrapper for the generic resource Pareto helper."""
263
+ return get_resource_pareto_frontier_df(dataframe, token_metric, score_column)
264
+
265
+
266
  def get_benchmark_run_df():
267
  results = get_results()
268
 
tests/test_token_efficiency.py CHANGED
@@ -1,13 +1,21 @@
 
1
  import pandas as pd
2
  import plotly.graph_objects as go
3
 
4
- from src.charts import create_score_vs_tokens_plot, create_token_pareto_frontier_plot
 
 
 
 
5
  from src.leaderboard import (
6
- ALL_BENCHMARKS,
7
  ANALYSIS_COLUMNS,
 
 
8
  get_analysis_df,
9
- get_token_efficiency_df,
10
- get_token_pareto_frontier_df,
 
 
11
  )
12
  from src.models import Benchmark, Environment, Harness, Metrics, Model, Result
13
 
@@ -18,14 +26,29 @@ def make_result(
18
  model: str = "model-a",
19
  harness: str = "harness-a",
20
  score: float = 0.5,
 
21
  total_tokens: int | None = 100,
22
  input_tokens: int | None = 60,
23
  cache_tokens: int | None = 10,
24
  output_tokens: int | None = 30,
 
 
 
 
25
  ) -> Result:
26
  return Result(
27
- benchmark=Benchmark(name=benchmark, repo="repo", num_tasks=10, url="https://example.com/benchmark"),
28
- harness=Harness(name=harness, skills=[], is_oss=True, url="https://example.com/harness"),
 
 
 
 
 
 
 
 
 
 
29
  model=Model(
30
  name=model,
31
  repo=None,
@@ -37,39 +60,58 @@ def make_result(
37
  environment=Environment(name="env", url="https://example.com/env"),
38
  metrics=Metrics(
39
  score=score,
40
- n_tasks=10,
41
  n_errors=1,
42
  mean_input_tokens_per_task=input_tokens,
43
  mean_cache_tokens_per_task=cache_tokens,
44
  mean_output_tokens_per_task=output_tokens,
45
  mean_tokens_per_task=total_tokens,
46
- mean_cost_usd_per_task=0.25,
47
  mean_total_time_seconds_per_task=12,
48
- mean_agent_time_seconds_per_task=10,
 
 
49
  ),
50
  )
51
 
52
 
53
- def test_get_analysis_df_columns_and_derived_values():
54
- dataframe = get_analysis_df([make_result(score=0.25, total_tokens=200)])
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  assert set(ANALYSIS_COLUMNS).issubset(dataframe.columns)
57
  assert dataframe.loc[0, "Score (%)"] == 25
58
  assert dataframe.loc[0, "Tokens Per Solved Task"] == 800
 
 
59
  assert bool(dataframe.loc[0, "Token Data Available"]) is True
60
 
61
 
62
- def test_missing_zero_and_negative_tokens_are_unavailable():
63
  dataframe = get_analysis_df(
64
  [
65
- make_result(model="missing", total_tokens=None),
66
- make_result(model="zero", total_tokens=0),
67
- make_result(model="negative", total_tokens=-10),
68
  ]
69
  )
70
 
71
  assert dataframe["Token Data Available"].tolist() == [False, False, False]
72
  assert dataframe["Tokens Per Solved Task"].isna().all()
 
 
73
 
74
 
75
  def test_zero_score_does_not_divide_by_zero():
@@ -79,84 +121,205 @@ def test_zero_score_does_not_divide_by_zero():
79
  assert bool(dataframe.loc[0, "Token Data Available"]) is True
80
 
81
 
82
- def test_token_efficiency_filtering_and_exclusion_count():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  analysis_df = get_analysis_df(
84
  [
85
- make_result(model="valid", total_tokens=100),
86
- make_result(model="zero", total_tokens=0),
87
- make_result(model="missing", total_tokens=None),
 
88
  ]
89
  )
90
 
91
- filtered = get_token_efficiency_df(
92
- token_metric="Total Tokens Per Task",
 
93
  analysis_df=analysis_df,
94
  )
95
 
96
  assert filtered["Model"].tolist() == ["valid"]
 
97
  assert filtered.attrs["exclusion_count"] == 2
 
 
 
98
 
99
 
100
- def test_all_benchmarks_and_single_benchmark_filtering():
101
  analysis_df = get_analysis_df(
102
  [
103
- make_result(benchmark="Benchmark A", model="a"),
104
- make_result(benchmark="Benchmark B", model="b"),
105
  ]
106
  )
107
 
108
- all_rows = get_token_efficiency_df(ALL_BENCHMARKS, analysis_df=analysis_df)
109
- one_benchmark = get_token_efficiency_df("Benchmark B", analysis_df=analysis_df)
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
- assert set(all_rows["Benchmark"]) == {"Benchmark A", "Benchmark B"}
112
- assert one_benchmark["Benchmark"].tolist() == ["Benchmark B"]
 
 
 
113
 
114
 
115
- def test_pareto_frontier_identification():
116
  dataframe = pd.DataFrame(
117
  {
118
  "Run Label": ["a", "b", "c", "d"],
 
119
  "Total Tokens Per Task": [100, 200, 300, 400],
 
 
120
  "Score (%)": [50, 60, 55, 80],
121
  }
122
  )
123
 
124
- frontier = get_token_pareto_frontier_df(dataframe, "Total Tokens Per Task")
 
 
125
 
126
- assert frontier["Run Label"].tolist() == ["a", "b", "d"]
127
 
128
-
129
- def test_pareto_ties_are_deterministic_and_not_falsely_dominated():
130
  dataframe = pd.DataFrame(
131
  {
132
  "Run Label": ["z", "a", "dominated", "higher"],
133
  "Model": ["z", "a", "d", "h"],
134
- "Total Tokens Per Task": [100, 100, 100, 200],
135
  "Score (%)": [50, 50, 40, 60],
136
  }
137
  )
138
 
139
- frontier = get_token_pareto_frontier_df(dataframe, "Total Tokens Per Task")
140
 
141
  assert frontier["Run Label"].tolist() == ["a", "z", "higher"]
142
  assert "dominated" not in frontier["Run Label"].tolist()
143
 
144
 
145
- def test_chart_functions_return_figures_for_valid_data():
146
- dataframe = get_analysis_df([make_result(), make_result(model="model-b", score=0.7, total_tokens=200)])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
- scatter = create_score_vs_tokens_plot(dataframe, token_metric="Total Tokens Per Task")
149
- pareto = create_token_pareto_frontier_plot(dataframe, token_metric="Total Tokens Per Task")
150
 
151
- assert isinstance(scatter, go.Figure)
152
- assert isinstance(pareto, go.Figure)
153
- assert scatter.layout.xaxis.type == "log"
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
- def test_empty_and_fully_invalid_chart_data_are_graceful():
157
- empty = create_score_vs_tokens_plot(pd.DataFrame(), token_metric="Total Tokens Per Task")
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  invalid_df = get_analysis_df([make_result(total_tokens=0)])
159
- invalid = create_score_vs_tokens_plot(invalid_df, token_metric="Total Tokens Per Task")
160
 
161
  assert isinstance(empty, go.Figure)
162
  assert isinstance(invalid, go.Figure)
@@ -177,9 +340,7 @@ def test_palette_lookup_new_palettes_fallback_and_copy():
177
  assert "#000000" not in COLOR_PALETTES["Citrus"]
178
 
179
 
180
- def test_cost_and_token_scatter_labels_toggle_consistently():
181
- from src.charts import create_score_vs_cost_plot
182
-
183
  cost_df = pd.DataFrame(
184
  {
185
  "Benchmark": ["Benchmark A"],
@@ -190,52 +351,43 @@ def test_cost_and_token_scatter_labels_toggle_consistently():
190
  "Label": ["model-a<br>harness-a"],
191
  }
192
  )
193
- token_df = get_analysis_df([make_result()])
194
 
195
  cost_without = create_score_vs_cost_plot(cost_df, "Benchmark A", show_labels=False)
196
  cost_with = create_score_vs_cost_plot(cost_df, "Benchmark A", show_labels=True)
197
- token_without = create_score_vs_tokens_plot(token_df, show_labels=False, show_pareto_frontier=False)
198
- token_with = create_score_vs_tokens_plot(token_df, show_labels=True, show_pareto_frontier=False)
 
 
 
 
 
 
 
 
199
 
200
  assert cost_without.data[0].mode == "markers"
201
  assert cost_with.data[0].mode == "markers+text"
202
- assert list(cost_with.data[0].text) == ["model-a<br>harness-a"]
203
- assert token_without.data[0].mode == "markers"
204
- assert token_with.data[0].mode == "markers+text"
205
- assert list(token_with.data[0].text) == ["model-a / harness-a"]
206
  assert cost_without.data[0].hovertemplate == cost_with.data[0].hovertemplate
207
- assert token_without.data[0].hovertemplate == token_with.data[0].hovertemplate
208
-
209
-
210
- def test_label_toggle_handles_empty_data():
211
- from src.charts import create_score_vs_cost_plot
212
 
213
- cost = create_score_vs_cost_plot(pd.DataFrame(), "Benchmark A", show_labels=True)
214
- tokens = create_score_vs_tokens_plot(pd.DataFrame(), show_labels=True)
 
 
 
 
215
 
216
- assert isinstance(cost, go.Figure)
217
- assert isinstance(tokens, go.Figure)
218
- assert len(cost.layout.annotations) == 1
219
- assert len(tokens.layout.annotations) == 1
220
 
221
 
222
- def test_score_vs_tokens_plot_adds_capability_guide_lines():
223
- dataframe = pd.DataFrame(
224
- {
225
- "Benchmark": ["bench"],
226
- "Model": ["model"],
227
- "Harness": ["harness"],
228
- "Run Label": ["model / harness"],
229
- "Score (%)": [75.0],
230
- "Tokens Per Solved Task": [1000.0],
231
- }
232
- )
233
-
234
- figure = create_score_vs_tokens_plot(dataframe, show_pareto_frontier=False)
235
 
236
- horizontal_lines = [
237
- shape
238
- for shape in figure.layout.shapes
239
- if shape.type == "line" and shape.y0 == shape.y1
240
- ]
241
- assert {shape.y0 for shape in horizontal_lines} == {70.0, 80.0}
 
1
+ from pathlib import Path
2
  import pandas as pd
3
  import plotly.graph_objects as go
4
 
5
+ from src.charts import (
6
+ create_performance_vs_resource_plot,
7
+ create_score_vs_cost_plot,
8
+ create_score_vs_tokens_plot,
9
+ )
10
  from src.leaderboard import (
 
11
  ANALYSIS_COLUMNS,
12
+ EFFICIENCY_RESOURCE_METRICS,
13
+ TOKEN_EFFICIENCY_TABLE_COLUMNS,
14
  get_analysis_df,
15
+ get_efficiency_resource_column,
16
+ get_efficiency_df,
17
+ get_token_efficiency_table_df,
18
+ get_resource_pareto_frontier_df,
19
  )
20
  from src.models import Benchmark, Environment, Harness, Metrics, Model, Result
21
 
 
26
  model: str = "model-a",
27
  harness: str = "harness-a",
28
  score: float = 0.5,
29
+ n_tasks: int | None = 10,
30
  total_tokens: int | None = 100,
31
  input_tokens: int | None = 60,
32
  cache_tokens: int | None = 10,
33
  output_tokens: int | None = 30,
34
+ cost_per_task: float | None = 0.25,
35
+ agent_time_per_task: int | None = 10,
36
+ cost_usd: float | None = None,
37
+ agent_time_seconds: int | None = None,
38
  ) -> Result:
39
  return Result(
40
+ benchmark=Benchmark(
41
+ name=benchmark,
42
+ repo="repo",
43
+ num_tasks=10,
44
+ url="https://example.com/benchmark",
45
+ ),
46
+ harness=Harness(
47
+ name=harness,
48
+ skills=[],
49
+ is_oss=True,
50
+ url="https://example.com/harness",
51
+ ),
52
  model=Model(
53
  name=model,
54
  repo=None,
 
60
  environment=Environment(name="env", url="https://example.com/env"),
61
  metrics=Metrics(
62
  score=score,
63
+ n_tasks=n_tasks,
64
  n_errors=1,
65
  mean_input_tokens_per_task=input_tokens,
66
  mean_cache_tokens_per_task=cache_tokens,
67
  mean_output_tokens_per_task=output_tokens,
68
  mean_tokens_per_task=total_tokens,
69
+ mean_cost_usd_per_task=cost_per_task,
70
  mean_total_time_seconds_per_task=12,
71
+ mean_agent_time_seconds_per_task=agent_time_per_task,
72
+ cost_usd=cost_usd,
73
+ agent_time_seconds=agent_time_seconds,
74
  ),
75
  )
76
 
77
 
78
+ def test_cost_vs_performance_tab_removed_without_efficiency_cost_regression():
79
+ app_source = Path("app.py").read_text()
80
+
81
+ assert 'gr.Tab("💰 Cost vs Performance")' not in app_source
82
+ assert "cost_benchmark" not in app_source
83
+ assert "cost_controls" not in app_source
84
+ assert "render_score_vs_cost_plot" not in app_source
85
+ assert 'with gr.Tab("⚡ Efficiency")' in app_source
86
+ assert app_source.index('with gr.Tab("🏆 Leaderboard")') < app_source.index('with gr.Tab("⚡ Efficiency")')
87
+ assert app_source.index('with gr.Tab("⚡ Efficiency")') < app_source.index('with gr.Tab("🏃 Benchmark Runs")')
88
+
89
+ def test_analysis_df_columns_and_derived_metrics():
90
+ dataframe = get_analysis_df(
91
+ [make_result(score=0.25, total_tokens=200, cost_per_task=0.125, agent_time_per_task=7)]
92
+ )
93
 
94
  assert set(ANALYSIS_COLUMNS).issubset(dataframe.columns)
95
  assert dataframe.loc[0, "Score (%)"] == 25
96
  assert dataframe.loc[0, "Tokens Per Solved Task"] == 800
97
+ assert dataframe.loc[0, "Cost Per Task"] == 0.125
98
+ assert dataframe.loc[0, "Agent Time Per Task"] == 7
99
  assert bool(dataframe.loc[0, "Token Data Available"]) is True
100
 
101
 
102
+ def test_missing_zero_negative_resource_values_are_unavailable():
103
  dataframe = get_analysis_df(
104
  [
105
+ make_result(model="missing", total_tokens=None, cost_per_task=None, agent_time_per_task=None),
106
+ make_result(model="zero", total_tokens=0, cost_per_task=0, agent_time_per_task=0),
107
+ make_result(model="negative", total_tokens=-10, cost_per_task=-1, agent_time_per_task=-3),
108
  ]
109
  )
110
 
111
  assert dataframe["Token Data Available"].tolist() == [False, False, False]
112
  assert dataframe["Tokens Per Solved Task"].isna().all()
113
+ assert dataframe["Cost Per Task"].isna().all()
114
+ assert dataframe["Agent Time Per Task"].isna().all()
115
 
116
 
117
  def test_zero_score_does_not_divide_by_zero():
 
121
  assert bool(dataframe.loc[0, "Token Data Available"]) is True
122
 
123
 
124
+ def test_invalid_task_denominator_does_not_trigger_total_metric_fallback():
125
+ dataframe = get_analysis_df(
126
+ [
127
+ make_result(
128
+ n_tasks=0,
129
+ cost_per_task=None,
130
+ agent_time_per_task=None,
131
+ cost_usd=1.5,
132
+ agent_time_seconds=30,
133
+ )
134
+ ]
135
+ )
136
+
137
+ assert pd.isna(dataframe.loc[0, "Cost Per Task"])
138
+ assert pd.isna(dataframe.loc[0, "Agent Time Per Task"])
139
+
140
+
141
+ def test_efficiency_resource_metric_choices_are_exact():
142
+ assert list(EFFICIENCY_RESOURCE_METRICS) == [
143
+ "Total tokens",
144
+ "Cost per task",
145
+ "Agent time per task",
146
+ ]
147
+ assert "Tokens Per Solved Task" not in EFFICIENCY_RESOURCE_METRICS
148
+ assert get_efficiency_resource_column("Total tokens") == "Total Tokens Per Task"
149
+ assert get_efficiency_resource_column("Cost per task") == "Cost Per Task"
150
+ assert get_efficiency_resource_column("Agent time per task") == "Agent Time Per Task"
151
+
152
+
153
+ def test_efficiency_filtering_is_benchmark_specific_and_counts_exclusions():
154
  analysis_df = get_analysis_df(
155
  [
156
+ make_result(benchmark="Benchmark A", model="valid", total_tokens=100),
157
+ make_result(benchmark="Benchmark A", model="zero", total_tokens=0),
158
+ make_result(benchmark="Benchmark A", model="missing", total_tokens=None),
159
+ make_result(benchmark="Benchmark B", model="other", total_tokens=100),
160
  ]
161
  )
162
 
163
+ filtered = get_efficiency_df(
164
+ benchmark_name="Benchmark A",
165
+ resource_metric="Total tokens",
166
  analysis_df=analysis_df,
167
  )
168
 
169
  assert filtered["Model"].tolist() == ["valid"]
170
+ assert filtered["Benchmark"].unique().tolist() == ["Benchmark A"]
171
  assert filtered.attrs["exclusion_count"] == 2
172
+ assert get_efficiency_df(
173
+ "All benchmarks", "Total tokens", analysis_df
174
+ ).empty
175
 
176
 
177
+ def test_cost_and_agent_time_filtering_use_positive_values_only():
178
  analysis_df = get_analysis_df(
179
  [
180
+ make_result(model="valid", cost_per_task=0.2, agent_time_per_task=9),
181
+ make_result(model="invalid", cost_per_task=0, agent_time_per_task=-1),
182
  ]
183
  )
184
 
185
+ cost = get_efficiency_df("Benchmark A", "Cost per task", analysis_df)
186
+ agent_time = get_efficiency_df("Benchmark A", "Agent time per task", analysis_df)
187
+
188
+ assert cost["Model"].tolist() == ["valid"]
189
+ assert agent_time["Model"].tolist() == ["valid"]
190
+ assert cost.attrs["exclusion_count"] == 1
191
+ assert agent_time.attrs["exclusion_count"] == 1
192
+
193
+
194
+ def test_efficiency_table_keeps_tokens_per_solved_task_and_expected_order():
195
+ analysis_df = get_analysis_df(
196
+ [make_result(score=0.333333333333, total_tokens=120, cost_per_task=0.123456)]
197
+ )
198
+
199
+ table = get_token_efficiency_table_df("Benchmark A", analysis_df)
200
 
201
+ assert list(table.columns) == TOKEN_EFFICIENCY_TABLE_COLUMNS
202
+ assert list(table.columns[:3]) == ["Model", "Harness", "Benchmark"]
203
+ assert "Tokens Per Solved Task" in table.columns
204
+ assert table.loc[0, "Score (%)"] == 33.3
205
+ assert table.loc[0, "Cost Per Task"] == 0.1235
206
 
207
 
208
+ def test_pareto_frontier_for_all_resource_metrics():
209
  dataframe = pd.DataFrame(
210
  {
211
  "Run Label": ["a", "b", "c", "d"],
212
+ "Model": ["a", "b", "c", "d"],
213
  "Total Tokens Per Task": [100, 200, 300, 400],
214
+ "Cost Per Task": [0.1, 0.2, 0.3, 0.4],
215
+ "Agent Time Per Task": [10, 20, 30, 40],
216
  "Score (%)": [50, 60, 55, 80],
217
  }
218
  )
219
 
220
+ for metric in ("Total Tokens Per Task", "Cost Per Task", "Agent Time Per Task"):
221
+ frontier = get_resource_pareto_frontier_df(dataframe, metric)
222
+ assert frontier["Run Label"].tolist() == ["a", "b", "d"]
223
 
 
224
 
225
+ def test_pareto_equal_x_equal_score_ties_are_preserved():
 
226
  dataframe = pd.DataFrame(
227
  {
228
  "Run Label": ["z", "a", "dominated", "higher"],
229
  "Model": ["z", "a", "d", "h"],
230
+ "Cost Per Task": [0.1, 0.1, 0.1, 0.2],
231
  "Score (%)": [50, 50, 40, 60],
232
  }
233
  )
234
 
235
+ frontier = get_resource_pareto_frontier_df(dataframe, "Cost Per Task")
236
 
237
  assert frontier["Run Label"].tolist() == ["a", "z", "higher"]
238
  assert "dominated" not in frontier["Run Label"].tolist()
239
 
240
 
241
+ def test_pareto_excludes_missing_zero_and_negative_resources():
242
+ dataframe = pd.DataFrame(
243
+ {
244
+ "Run Label": ["valid", "missing", "zero", "negative"],
245
+ "Agent Time Per Task": [10, None, 0, -1],
246
+ "Score (%)": [50, 100, 100, 100],
247
+ }
248
+ )
249
+
250
+ frontier = get_resource_pareto_frontier_df(dataframe, "Agent Time Per Task")
251
+
252
+ assert frontier["Run Label"].tolist() == ["valid"]
253
+
254
+
255
+ def test_performance_resource_charts_construct_with_metric_specific_axes():
256
+ dataframe = get_analysis_df(
257
+ [
258
+ make_result(),
259
+ make_result(model="model-b", score=0.7, total_tokens=200, cost_per_task=0.4, agent_time_per_task=20),
260
+ ]
261
+ )
262
+
263
+ expected_titles = {
264
+ "Total tokens": "Total tokens per task",
265
+ "Cost per task": "Cost per task (USD)",
266
+ "Agent time per task": "Agent time per task (seconds)",
267
+ }
268
+ for metric, title in expected_titles.items():
269
+ figure = create_performance_vs_resource_plot(dataframe, resource_metric=metric)
270
+ assert isinstance(figure, go.Figure)
271
+ assert figure.layout.xaxis.type == "log"
272
+ assert figure.layout.xaxis.title.text == title
273
+ assert any(trace.name == "Pareto frontier" for trace in figure.data)
274
+
275
+ compatibility = create_score_vs_tokens_plot(dataframe, token_metric="Total tokens")
276
+ assert isinstance(compatibility, go.Figure)
277
 
 
 
278
 
 
 
 
279
 
280
+ def test_performance_resource_chart_rejects_multiple_benchmarks():
281
+ dataframe = get_analysis_df(
282
+ [
283
+ make_result(benchmark="Benchmark A"),
284
+ make_result(benchmark="Benchmark B", model="model-b"),
285
+ ]
286
+ )
287
+ figure = create_performance_vs_resource_plot(dataframe, resource_metric="Total tokens")
288
+
289
+ assert len(figure.layout.annotations) == 1
290
+ assert "Select one benchmark" in figure.layout.annotations[0].text
291
+
292
+ def test_linear_scale_and_point_labels_still_work():
293
+ dataframe = get_analysis_df([make_result()])
294
+ figure = create_performance_vs_resource_plot(
295
+ dataframe,
296
+ resource_metric="Cost per task",
297
+ x_scale="Linear",
298
+ show_labels=True,
299
+ show_pareto_frontier=False,
300
+ )
301
+
302
+ assert figure.layout.xaxis.type == "linear"
303
+ assert figure.data[0].mode == "markers+text"
304
+ assert list(figure.data[0].text) == ["model-a / harness-a"]
305
 
306
+
307
+ def test_color_by_benchmark_is_not_supported_in_efficiency_chart():
308
+ dataframe = get_analysis_df([make_result()])
309
+ figure = create_performance_vs_resource_plot(
310
+ dataframe,
311
+ resource_metric="Total tokens",
312
+ color_by="Benchmark", # type: ignore[arg-type]
313
+ )
314
+
315
+ assert len(figure.layout.annotations) == 1
316
+ assert "Color dimension not available" in figure.layout.annotations[0].text
317
+
318
+
319
+ def test_empty_and_fully_invalid_resource_chart_data_are_graceful():
320
+ empty = create_performance_vs_resource_plot(pd.DataFrame(), resource_metric="Total tokens")
321
  invalid_df = get_analysis_df([make_result(total_tokens=0)])
322
+ invalid = create_performance_vs_resource_plot(invalid_df, resource_metric="Total tokens")
323
 
324
  assert isinstance(empty, go.Figure)
325
  assert isinstance(invalid, go.Figure)
 
340
  assert "#000000" not in COLOR_PALETTES["Citrus"]
341
 
342
 
343
+ def test_cost_and_efficiency_scatter_labels_toggle_consistently():
 
 
344
  cost_df = pd.DataFrame(
345
  {
346
  "Benchmark": ["Benchmark A"],
 
351
  "Label": ["model-a<br>harness-a"],
352
  }
353
  )
354
+ efficiency_df = get_analysis_df([make_result()])
355
 
356
  cost_without = create_score_vs_cost_plot(cost_df, "Benchmark A", show_labels=False)
357
  cost_with = create_score_vs_cost_plot(cost_df, "Benchmark A", show_labels=True)
358
+ efficiency_without = create_performance_vs_resource_plot(
359
+ efficiency_df,
360
+ show_labels=False,
361
+ show_pareto_frontier=False,
362
+ )
363
+ efficiency_with = create_performance_vs_resource_plot(
364
+ efficiency_df,
365
+ show_labels=True,
366
+ show_pareto_frontier=False,
367
+ )
368
 
369
  assert cost_without.data[0].mode == "markers"
370
  assert cost_with.data[0].mode == "markers+text"
371
+ assert efficiency_without.data[0].mode == "markers"
372
+ assert efficiency_with.data[0].mode == "markers+text"
 
 
373
  assert cost_without.data[0].hovertemplate == cost_with.data[0].hovertemplate
374
+ assert efficiency_without.data[0].hovertemplate == efficiency_with.data[0].hovertemplate
 
 
 
 
375
 
376
+ def test_efficiency_figure_uses_responsive_autosizing_without_fixed_width():
377
+ dataframe = get_analysis_df([make_result()])
378
+ figure = create_performance_vs_resource_plot(
379
+ dataframe,
380
+ resource_metric="Total tokens",
381
+ )
382
 
383
+ assert figure.layout.autosize is True
384
+ assert figure.layout.width is None
385
+ assert figure.layout.height is None
 
386
 
387
 
388
+ def test_shared_plot_container_has_minimum_height_and_efficiency_tab_refresh():
389
+ app_source = (Path(__file__).parents[1] / "app.py").read_text()
 
 
 
 
 
 
 
 
 
 
 
390
 
391
+ assert "RESPONSIVE_PLOT_MIN_HEIGHT_PX = 420" in app_source
392
+ assert "min-height: {RESPONSIVE_PLOT_MIN_HEIGHT_PX}px" in app_source
393
+ assert "efficiency_tab.select(" in app_source