CP Legendre commited on
Commit ·
4fd20a0
1
Parent(s): 04b11c9
Add token efficiency analysis and visualizations
Browse files- README.md +91 -14
- app.py +155 -18
- src/charts.py +221 -17
- src/leaderboard.py +180 -39
- tests/test_token_efficiency.py +241 -0
README.md
CHANGED
|
@@ -15,26 +15,103 @@ tags:
|
|
| 15 |
|
| 16 |
# Coding Agent Leaderboard
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
## Adding a New Leaderboard Entry
|
| 19 |
|
| 20 |
-
Create a
|
| 21 |
-
|
|
|
|
| 22 |
|
| 23 |
## Development
|
| 24 |
|
| 25 |
-
1. Install dependencies
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
-
|
| 28 |
-
pip install -r requirements.txt
|
| 29 |
|
| 30 |
-
|
|
|
|
|
|
|
| 31 |
|
| 32 |
-
|
| 33 |
-
uv pip install -r requirements.txt
|
| 34 |
-
```
|
| 35 |
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
python app.py
|
| 40 |
-
```
|
|
|
|
| 15 |
|
| 16 |
# Coding Agent Leaderboard
|
| 17 |
|
| 18 |
+
Compare coding-agent models and harnesses across benchmark performance, cost, latency, and token usage.
|
| 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 |
|
| 96 |
+
1. Install dependencies:
|
| 97 |
+
|
| 98 |
+
```sh
|
| 99 |
+
pip install -r requirements.txt
|
| 100 |
+
|
| 101 |
+
# or
|
| 102 |
+
|
| 103 |
+
uv venv
|
| 104 |
+
uv pip install -r requirements.txt
|
| 105 |
+
```
|
| 106 |
|
| 107 |
+
2. Run the app:
|
|
|
|
| 108 |
|
| 109 |
+
```sh
|
| 110 |
+
python app.py
|
| 111 |
+
```
|
| 112 |
|
| 113 |
+
3. Run tests:
|
|
|
|
|
|
|
| 114 |
|
| 115 |
+
```sh
|
| 116 |
+
pytest
|
| 117 |
+
```
|
|
|
|
|
|
app.py
CHANGED
|
@@ -51,19 +51,39 @@ from src.charts import (
|
|
| 51 |
clean_markdown_link,
|
| 52 |
create_leaderboard_benchmark_plot,
|
| 53 |
create_score_vs_cost_plot,
|
|
|
|
| 54 |
)
|
| 55 |
from src.display.text_blocks import (
|
| 56 |
HOW_TO_USE_TEXT,
|
| 57 |
INTRODUCTION_TEXT,
|
| 58 |
LLM_BENCHMARKS_TEXT,
|
| 59 |
)
|
| 60 |
-
from src.leaderboard import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
REPO_ID = "taagarwa/coding-agent-leaderboard"
|
| 63 |
TOKEN = os.environ.get("HF_TOKEN")
|
| 64 |
API = HfApi(token=TOKEN)
|
| 65 |
COLOR_BY_CHOICES = ["Model", "Harness"]
|
| 66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
DEFAULT_COLOR_PALETTE = "Citrus"
|
| 68 |
PLOT_BACKGROUND_CHOICES = ["Dark", "White"]
|
| 69 |
DEFAULT_PLOT_BACKGROUND = "Dark"
|
|
@@ -91,6 +111,7 @@ BENCHMARK_NAMES = get_benchmark_names()
|
|
| 91 |
DEFAULT_BENCHMARK = BENCHMARK_NAMES[0] if BENCHMARK_NAMES else None
|
| 92 |
BENCHMARK_RUN_DF = get_benchmark_run_df()
|
| 93 |
SCORE_VS_COST_DF = get_score_vs_cost_df()
|
|
|
|
| 94 |
|
| 95 |
|
| 96 |
def render_leaderboard_benchmark_plot(
|
|
@@ -111,6 +132,7 @@ def render_leaderboard_benchmark_plot(
|
|
| 111 |
def render_score_vs_cost_plot(
|
| 112 |
benchmark_name,
|
| 113 |
color_by,
|
|
|
|
| 114 |
color_palette=DEFAULT_COLOR_PALETTE,
|
| 115 |
plot_background=DEFAULT_PLOT_BACKGROUND,
|
| 116 |
):
|
|
@@ -118,11 +140,46 @@ def render_score_vs_cost_plot(
|
|
| 118 |
SCORE_VS_COST_DF,
|
| 119 |
benchmark_name=benchmark_name,
|
| 120 |
color_by=color_by,
|
|
|
|
| 121 |
palette_name=color_palette,
|
| 122 |
background_name=plot_background,
|
| 123 |
)
|
| 124 |
|
| 125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
def build_header_html(df):
|
| 127 |
n_results = len(df)
|
| 128 |
n_models = df["Model"].nunique()
|
|
@@ -270,37 +327,117 @@ with demo:
|
|
| 270 |
label="Image background",
|
| 271 |
elem_classes="color-control",
|
| 272 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 273 |
score_vs_cost_plot = gr.Plot(
|
| 274 |
value=render_score_vs_cost_plot(
|
| 275 |
DEFAULT_BENCHMARK,
|
| 276 |
"Model",
|
|
|
|
| 277 |
DEFAULT_COLOR_PALETTE,
|
| 278 |
DEFAULT_PLOT_BACKGROUND,
|
| 279 |
),
|
| 280 |
show_label=False,
|
| 281 |
elem_classes="responsive-plot",
|
| 282 |
)
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
)
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
)
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
|
|
|
| 297 |
)
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
|
|
|
| 302 |
)
|
| 303 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 304 |
with gr.Tab("🏃 Benchmark Runs"):
|
| 305 |
benchmark_runs = init_benchmark_runs(BENCHMARK_RUN_DF)
|
| 306 |
|
|
|
|
| 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,
|
| 58 |
INTRODUCTION_TEXT,
|
| 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 |
|
| 72 |
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",
|
| 80 |
+
"High contrast",
|
| 81 |
+
"Rainbow",
|
| 82 |
+
"Grayscale",
|
| 83 |
+
"Viridis",
|
| 84 |
+
"Plasma",
|
| 85 |
+
"Cividis",
|
| 86 |
+
]
|
| 87 |
DEFAULT_COLOR_PALETTE = "Citrus"
|
| 88 |
PLOT_BACKGROUND_CHOICES = ["Dark", "White"]
|
| 89 |
DEFAULT_PLOT_BACKGROUND = "Dark"
|
|
|
|
| 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 |
|
| 117 |
def render_leaderboard_benchmark_plot(
|
|
|
|
| 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 |
):
|
|
|
|
| 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,
|
| 153 |
+
x_scale,
|
| 154 |
+
show_pareto_frontier,
|
| 155 |
+
show_labels,
|
| 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(
|
| 165 |
+
benchmark_name=benchmark_name,
|
| 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,
|
| 176 |
+
show_labels=show_labels,
|
| 177 |
+
palette_name=color_palette,
|
| 178 |
+
background_name=plot_background,
|
| 179 |
+
)
|
| 180 |
+
return figure, table_df, note
|
| 181 |
+
|
| 182 |
+
|
| 183 |
def build_header_html(df):
|
| 184 |
n_results = len(df)
|
| 185 |
n_models = df["Model"].nunique()
|
|
|
|
| 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,
|
| 383 |
+
value="Model",
|
| 384 |
+
label="Color by",
|
| 385 |
+
)
|
| 386 |
+
efficiency_scale = gr.Radio(choices=["Log", "Linear"], value="Log", label="X-axis scale")
|
| 387 |
+
with gr.Row():
|
| 388 |
+
efficiency_pareto = gr.Checkbox(value=True, label="Show Pareto frontier")
|
| 389 |
+
efficiency_labels = gr.Checkbox(value=False, label="Show point labels")
|
| 390 |
+
efficiency_palette = gr.Dropdown(
|
| 391 |
+
choices=COLOR_PALETTE_CHOICES,
|
| 392 |
+
value=DEFAULT_COLOR_PALETTE,
|
| 393 |
+
label="Color palette",
|
| 394 |
+
)
|
| 395 |
+
efficiency_background = gr.Dropdown(
|
| 396 |
+
choices=PLOT_BACKGROUND_CHOICES,
|
| 397 |
+
value=DEFAULT_PLOT_BACKGROUND,
|
| 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,
|
| 407 |
+
False,
|
| 408 |
+
DEFAULT_COLOR_PALETTE,
|
| 409 |
+
DEFAULT_PLOT_BACKGROUND,
|
| 410 |
)
|
| 411 |
+
efficiency_note = gr.Markdown(initial_efficiency[2])
|
| 412 |
+
efficiency_plot = gr.Plot(
|
| 413 |
+
value=initial_efficiency[0],
|
| 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,
|
| 421 |
+
show_label=False,
|
| 422 |
)
|
| 423 |
|
| 424 |
+
efficiency_controls = [
|
| 425 |
+
efficiency_benchmark,
|
| 426 |
+
efficiency_metric,
|
| 427 |
+
efficiency_color_by,
|
| 428 |
+
efficiency_scale,
|
| 429 |
+
efficiency_pareto,
|
| 430 |
+
efficiency_labels,
|
| 431 |
+
efficiency_palette,
|
| 432 |
+
efficiency_background,
|
| 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 |
|
src/charts.py
CHANGED
|
@@ -5,11 +5,21 @@ import re
|
|
| 5 |
from typing import Literal
|
| 6 |
|
| 7 |
import pandas as pd
|
|
|
|
| 8 |
import plotly.graph_objects as go
|
| 9 |
from plotly.graph_objs._figure import Figure
|
| 10 |
|
| 11 |
ColorBy = Literal["Model", "Harness"]
|
| 12 |
-
PaletteName = Literal[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
PlotBackground = Literal["Dark", "White"]
|
| 14 |
DEFAULT_PALETTE: PaletteName = "Citrus"
|
| 15 |
DEFAULT_BACKGROUND: PlotBackground = "Dark"
|
|
@@ -92,6 +102,32 @@ PLOT_BACKGROUNDS: dict[PlotBackground, dict[str, str]] = {
|
|
| 92 |
}
|
| 93 |
|
| 94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
def clean_markdown_link(value: object) -> str:
|
| 96 |
"""Return human-readable text from Markdown links used in leaderboard tables."""
|
| 97 |
text = str(value).replace("<sup>*</sup>", "")
|
|
@@ -101,25 +137,40 @@ def clean_markdown_link(value: object) -> str:
|
|
| 101 |
return text
|
| 102 |
|
| 103 |
|
| 104 |
-
|
| 105 |
"Citrus": MODEL_FALLBACK_PALETTE,
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
"High contrast": ["#FFD166", "#06D6A0", "#118AB2", "#EF476F", "#A78BFA", "#F97316", "#22D3EE", "#E5E7EB"],
|
| 110 |
-
# Categorical rainbow-style palette. This is not a continuous colorscale; it is
|
| 111 |
-
# sampled as discrete colors so each category gets a distinct color.
|
| 112 |
"Rainbow": ["#E6194B", "#F58231", "#FFE119", "#3CB44B", "#42D4F4", "#4363D8", "#911EB4", "#F032E6", "#469990", "#9A6324"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
}
|
| 114 |
|
|
|
|
|
|
|
| 115 |
HARNESS_PALETTES: dict[PaletteName, list[str]] = {
|
|
|
|
| 116 |
"Citrus": HARNESS_FALLBACK_PALETTE,
|
| 117 |
-
# Use the same broad Okabe-Ito family but with a different starting point so the
|
| 118 |
-
# harness mode does not visually mirror the model mode.
|
| 119 |
-
"Okabe-Ito": ["#0072B2", "#D55E00", "#CC79A7", "#009E73", "#56B4E9", "#E69F00", "#F0E442", "#999999"],
|
| 120 |
-
"High contrast": ["#38BDF8", "#34D399", "#A78BFA", "#F472B6", "#FACC15", "#FB923C", "#22D3EE", "#E5E7EB"],
|
| 121 |
-
"Rainbow": ["#4363D8", "#E6194B", "#3CB44B", "#F58231", "#911EB4", "#42D4F4", "#F032E6", "#FFE119", "#469990", "#9A6324"],
|
| 122 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
|
| 125 |
def normalize_palette_name(palette_name: str | None) -> PaletteName:
|
|
@@ -160,7 +211,7 @@ def get_color(name: str, color_by: ColorBy, palette_name: str | None = DEFAULT_P
|
|
| 160 |
def palette_colors_for(color_by: ColorBy, palette_name: str | None = DEFAULT_PALETTE) -> list[str]:
|
| 161 |
palette_key = normalize_palette_name(palette_name)
|
| 162 |
palettes = MODEL_PALETTES if color_by == "Model" else HARNESS_PALETTES
|
| 163 |
-
return palettes[palette_key]
|
| 164 |
|
| 165 |
|
| 166 |
def color_map_for(
|
|
@@ -261,7 +312,9 @@ def prepare_benchmark_run_plot_df(dataframe: pd.DataFrame) -> pd.DataFrame:
|
|
| 261 |
plot_df["Model Label"] = plot_df["Model"].map(clean_markdown_link)
|
| 262 |
plot_df["Harness Label"] = plot_df["Harness"].map(clean_markdown_link)
|
| 263 |
plot_df["Benchmark Label"] = plot_df["Benchmark"].map(clean_markdown_link)
|
| 264 |
-
plot_df["Run Label"] =
|
|
|
|
|
|
|
| 265 |
plot_df["Score"] = pd.to_numeric(plot_df["Score"], errors="coerce")
|
| 266 |
return plot_df
|
| 267 |
|
|
@@ -324,10 +377,24 @@ def create_leaderboard_benchmark_plot(
|
|
| 324 |
return fig
|
| 325 |
|
| 326 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 327 |
def create_score_vs_cost_plot(
|
| 328 |
dataframe: pd.DataFrame,
|
| 329 |
benchmark_name: str | None,
|
| 330 |
color_by: ColorBy = "Model",
|
|
|
|
| 331 |
palette_name: str | None = DEFAULT_PALETTE,
|
| 332 |
background_name: str | None = DEFAULT_BACKGROUND,
|
| 333 |
) -> Figure:
|
|
@@ -351,14 +418,13 @@ def create_score_vs_cost_plot(
|
|
| 351 |
fig = go.Figure()
|
| 352 |
|
| 353 |
for group, group_df in plot_df.groupby(color_by, sort=True):
|
|
|
|
| 354 |
fig.add_trace(
|
| 355 |
go.Scatter(
|
| 356 |
x=group_df["Cost Per Task (USD)"],
|
| 357 |
y=group_df["Score"],
|
| 358 |
-
mode="markers+text",
|
| 359 |
name=str(group),
|
| 360 |
-
|
| 361 |
-
textposition="top center",
|
| 362 |
marker={
|
| 363 |
"size": 15,
|
| 364 |
"color": colors[str(group)],
|
|
@@ -383,3 +449,141 @@ def create_score_vs_cost_plot(
|
|
| 383 |
legend_title_text=color_by,
|
| 384 |
)
|
| 385 |
return apply_plot_theme(fig, background_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
from typing import Literal
|
| 6 |
|
| 7 |
import pandas as pd
|
| 8 |
+
import plotly.colors as pc
|
| 9 |
import plotly.graph_objects as go
|
| 10 |
from plotly.graph_objs._figure import Figure
|
| 11 |
|
| 12 |
ColorBy = Literal["Model", "Harness"]
|
| 13 |
+
PaletteName = Literal[
|
| 14 |
+
"Citrus",
|
| 15 |
+
"Okabe-Ito",
|
| 16 |
+
"High contrast",
|
| 17 |
+
"Rainbow",
|
| 18 |
+
"Grayscale",
|
| 19 |
+
"Viridis",
|
| 20 |
+
"Plasma",
|
| 21 |
+
"Cividis",
|
| 22 |
+
]
|
| 23 |
PlotBackground = Literal["Dark", "White"]
|
| 24 |
DEFAULT_PALETTE: PaletteName = "Citrus"
|
| 25 |
DEFAULT_BACKGROUND: PlotBackground = "Dark"
|
|
|
|
| 102 |
}
|
| 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>", "")
|
|
|
|
| 137 |
return text
|
| 138 |
|
| 139 |
|
| 140 |
+
COLOR_PALETTES: dict[PaletteName, list[str]] = {
|
| 141 |
"Citrus": MODEL_FALLBACK_PALETTE,
|
| 142 |
+
"Okabe-Ito": [
|
| 143 |
+
"#E69F00",
|
| 144 |
+
"#56B4E9",
|
| 145 |
+
"#009E73",
|
| 146 |
+
"#F0E442",
|
| 147 |
+
"#0072B2",
|
| 148 |
+
"#D55E00",
|
| 149 |
+
"#CC79A7",
|
| 150 |
+
"#999999",
|
| 151 |
+
],
|
| 152 |
"High contrast": ["#FFD166", "#06D6A0", "#118AB2", "#EF476F", "#A78BFA", "#F97316", "#22D3EE", "#E5E7EB"],
|
|
|
|
|
|
|
| 153 |
"Rainbow": ["#E6194B", "#F58231", "#FFE119", "#3CB44B", "#42D4F4", "#4363D8", "#911EB4", "#F032E6", "#469990", "#9A6324"],
|
| 154 |
+
# Near-white and near-black endpoints remain visible against both supported backgrounds.
|
| 155 |
+
"Grayscale": ["#E2E8F0", "#CBD5E1", "#94A3B8", "#64748B", "#475569", "#334155", "#1E293B", "#111827"],
|
| 156 |
+
"Viridis": list(pc.sequential.Viridis),
|
| 157 |
+
"Plasma": list(pc.sequential.Plasma),
|
| 158 |
+
"Cividis": list(pc.sequential.Cividis),
|
| 159 |
}
|
| 160 |
|
| 161 |
+
# Harness categories use the same central registry, with the default palette retaining
|
| 162 |
+
# its established cyan/blue/violet identity.
|
| 163 |
HARNESS_PALETTES: dict[PaletteName, list[str]] = {
|
| 164 |
+
**COLOR_PALETTES,
|
| 165 |
"Citrus": HARNESS_FALLBACK_PALETTE,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
}
|
| 167 |
+
MODEL_PALETTES = COLOR_PALETTES
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def get_color_palette(name: str | None) -> list[str]:
|
| 171 |
+
"""Return a copy of the requested palette, falling back to Citrus."""
|
| 172 |
+
palette_name = normalize_palette_name(name)
|
| 173 |
+
return list(COLOR_PALETTES[palette_name])
|
| 174 |
|
| 175 |
|
| 176 |
def normalize_palette_name(palette_name: str | None) -> PaletteName:
|
|
|
|
| 211 |
def palette_colors_for(color_by: ColorBy, palette_name: str | None = DEFAULT_PALETTE) -> list[str]:
|
| 212 |
palette_key = normalize_palette_name(palette_name)
|
| 213 |
palettes = MODEL_PALETTES if color_by == "Model" else HARNESS_PALETTES
|
| 214 |
+
return list(palettes[palette_key])
|
| 215 |
|
| 216 |
|
| 217 |
def color_map_for(
|
|
|
|
| 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 |
|
|
|
|
| 377 |
return fig
|
| 378 |
|
| 379 |
|
| 380 |
+
def scatter_label_kwargs(
|
| 381 |
+
dataframe: pd.DataFrame,
|
| 382 |
+
show_labels: bool,
|
| 383 |
+
preferred_columns: tuple[str, ...] = ("Run Label", "Label"),
|
| 384 |
+
) -> dict[str, object]:
|
| 385 |
+
"""Return consistent Plotly scatter label arguments without affecting hover data."""
|
| 386 |
+
if not show_labels:
|
| 387 |
+
return {"mode": "markers", "text": None, "textposition": "top center"}
|
| 388 |
+
label_column = next((column for column in preferred_columns if column in dataframe.columns), None)
|
| 389 |
+
labels = dataframe[label_column] if label_column else None
|
| 390 |
+
return {"mode": "markers+text", "text": labels, "textposition": "top center"}
|
| 391 |
+
|
| 392 |
+
|
| 393 |
def create_score_vs_cost_plot(
|
| 394 |
dataframe: pd.DataFrame,
|
| 395 |
benchmark_name: str | None,
|
| 396 |
color_by: ColorBy = "Model",
|
| 397 |
+
show_labels: bool = False,
|
| 398 |
palette_name: str | None = DEFAULT_PALETTE,
|
| 399 |
background_name: str | None = DEFAULT_BACKGROUND,
|
| 400 |
) -> Figure:
|
|
|
|
| 418 |
fig = go.Figure()
|
| 419 |
|
| 420 |
for group, group_df in plot_df.groupby(color_by, sort=True):
|
| 421 |
+
label_kwargs = scatter_label_kwargs(group_df, show_labels)
|
| 422 |
fig.add_trace(
|
| 423 |
go.Scatter(
|
| 424 |
x=group_df["Cost Per Task (USD)"],
|
| 425 |
y=group_df["Score"],
|
|
|
|
| 426 |
name=str(group),
|
| 427 |
+
**label_kwargs,
|
|
|
|
| 428 |
marker={
|
| 429 |
"size": 15,
|
| 430 |
"color": colors[str(group)],
|
|
|
|
| 449 |
legend_title_text=color_by,
|
| 450 |
)
|
| 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 = [
|
| 487 |
+
"Model",
|
| 488 |
+
"Harness",
|
| 489 |
+
"Benchmark",
|
| 490 |
+
"Score (%)",
|
| 491 |
+
"Input Tokens Per Task",
|
| 492 |
+
"Output Tokens Per Task",
|
| 493 |
+
"Cache Tokens Per Task",
|
| 494 |
+
"Total Tokens Per Task",
|
| 495 |
+
"Cost Per Task",
|
| 496 |
+
"Total Time Per Task",
|
| 497 |
+
"Agent Time Per Task",
|
| 498 |
+
]
|
| 499 |
+
for column in hover_columns:
|
| 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,
|
| 511 |
+
marker={
|
| 512 |
+
"size": 13,
|
| 513 |
+
"color": colors[str(group)],
|
| 514 |
+
"line": {"width": 1, "color": theme["marker_line_color"]},
|
| 515 |
+
},
|
| 516 |
+
customdata=group_df[hover_columns],
|
| 517 |
+
hovertemplate=(
|
| 518 |
+
"<b>%{customdata[0]}</b><br>"
|
| 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",
|
| 543 |
+
line={"width": 3, "dash": "dash", "color": theme["text_primary"]},
|
| 544 |
+
marker={
|
| 545 |
+
"size": 10,
|
| 546 |
+
"symbol": "diamond-open",
|
| 547 |
+
"color": theme["text_primary"],
|
| 548 |
+
"line": {"width": 2, "color": theme["text_primary"]},
|
| 549 |
+
},
|
| 550 |
+
customdata=frontier_df[["Run Label"]],
|
| 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,
|
| 586 |
+
show_labels=show_labels,
|
| 587 |
+
palette_name=palette_name,
|
| 588 |
+
background_name=background_name,
|
| 589 |
+
)
|
src/leaderboard.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
-
from pathlib import Path
|
| 2 |
import json
|
|
|
|
| 3 |
|
| 4 |
import pandas as pd
|
| 5 |
|
|
@@ -12,6 +12,47 @@ BENCHMARK_SORT_ORDER = {
|
|
| 12 |
"SWE-Bench Pro -- Ansible": 1,
|
| 13 |
}
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
def benchmark_sort_key(name: str) -> tuple[int, str]:
|
| 17 |
return (BENCHMARK_SORT_ORDER.get(name, 99), name)
|
|
@@ -40,6 +81,136 @@ def get_benchmark_names(results: list[Result] | None = None) -> list[str]:
|
|
| 40 |
return sorted({r.benchmark.name for r in results}, key=benchmark_sort_key)
|
| 41 |
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
def get_benchmark_run_df():
|
| 44 |
results = get_results()
|
| 45 |
|
|
@@ -81,43 +252,13 @@ def get_benchmark_run_df():
|
|
| 81 |
|
| 82 |
|
| 83 |
def get_score_vs_cost_df():
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
for result in results:
|
| 88 |
-
mean_cost = result.metrics.mean_cost_usd_per_task
|
| 89 |
-
if mean_cost is None:
|
| 90 |
-
continue
|
| 91 |
-
|
| 92 |
-
model_label = result.model.repo or result.model.name
|
| 93 |
-
harness_label = result.harness.name
|
| 94 |
-
|
| 95 |
-
rows.append(
|
| 96 |
-
{
|
| 97 |
-
"Label": f"{model_label} / {harness_label}",
|
| 98 |
-
"Model": model_label,
|
| 99 |
-
"Harness": harness_label,
|
| 100 |
-
"Benchmark": result.benchmark.name,
|
| 101 |
-
"Category": "FOSS" if result.model.is_oss and result.harness.is_oss else "Proprietary",
|
| 102 |
-
"Score": round(result.metrics.score * 100, 1),
|
| 103 |
-
"Cost Per Task (USD)": round(mean_cost, 2),
|
| 104 |
-
}
|
| 105 |
-
)
|
| 106 |
-
|
| 107 |
-
columns = [
|
| 108 |
-
"Label",
|
| 109 |
-
"Model",
|
| 110 |
-
"Harness",
|
| 111 |
-
"Benchmark",
|
| 112 |
-
"Category",
|
| 113 |
-
"Score",
|
| 114 |
-
"Cost Per Task (USD)",
|
| 115 |
-
]
|
| 116 |
-
score_vs_cost_df = pd.DataFrame(rows, columns=columns)
|
| 117 |
if score_vs_cost_df.empty:
|
| 118 |
-
return
|
| 119 |
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
)
|
|
|
|
|
|
|
| 1 |
import json
|
| 2 |
+
from pathlib import Path
|
| 3 |
|
| 4 |
import pandas as pd
|
| 5 |
|
|
|
|
| 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",
|
| 25 |
+
"Harness",
|
| 26 |
+
"Run Label",
|
| 27 |
+
"Category",
|
| 28 |
+
"Score",
|
| 29 |
+
"Score (%)",
|
| 30 |
+
"Tasks",
|
| 31 |
+
"Errors",
|
| 32 |
+
"Input Tokens Per Task",
|
| 33 |
+
"Cache Tokens Per Task",
|
| 34 |
+
"Output Tokens Per Task",
|
| 35 |
+
"Total Tokens Per Task",
|
| 36 |
+
"Tokens Per Solved Task",
|
| 37 |
+
"Cost Per Task",
|
| 38 |
+
"Total Time Per Task",
|
| 39 |
+
"Agent Time Per Task",
|
| 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",
|
| 51 |
+
"Tokens Per Solved Task",
|
| 52 |
+
"Tasks",
|
| 53 |
+
"Errors",
|
| 54 |
+
]
|
| 55 |
+
|
| 56 |
|
| 57 |
def benchmark_sort_key(name: str) -> tuple[int, str]:
|
| 58 |
return (BENCHMARK_SORT_ORDER.get(name, 99), name)
|
|
|
|
| 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:
|
| 87 |
+
results = get_results()
|
| 88 |
+
|
| 89 |
+
rows = []
|
| 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
|
| 98 |
+
else None
|
| 99 |
+
)
|
| 100 |
+
rows.append(
|
| 101 |
+
{
|
| 102 |
+
"Benchmark": result.benchmark.name,
|
| 103 |
+
"Model": model_label,
|
| 104 |
+
"Harness": result.harness.name,
|
| 105 |
+
"Run Label": f"{model_label} / {result.harness.name}",
|
| 106 |
+
"Category": "FOSS" if result.model.is_oss and result.harness.is_oss else "Proprietary",
|
| 107 |
+
"Score": metrics.score,
|
| 108 |
+
"Score (%)": metrics.score * 100,
|
| 109 |
+
"Tasks": metrics.n_tasks,
|
| 110 |
+
"Errors": metrics.n_errors,
|
| 111 |
+
"Input Tokens Per Task": metrics.mean_input_tokens_per_task,
|
| 112 |
+
"Cache Tokens Per Task": metrics.mean_cache_tokens_per_task,
|
| 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 |
+
)
|
| 122 |
+
|
| 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 |
+
|
| 184 |
+
candidates = dataframe.copy()
|
| 185 |
+
candidates[token_metric] = pd.to_numeric(candidates[token_metric], errors="coerce")
|
| 186 |
+
candidates[score_column] = pd.to_numeric(candidates[score_column], errors="coerce")
|
| 187 |
+
candidates = candidates.dropna(subset=[token_metric, score_column])
|
| 188 |
+
candidates = candidates[candidates[token_metric] > 0]
|
| 189 |
+
if candidates.empty:
|
| 190 |
+
return candidates
|
| 191 |
+
|
| 192 |
+
tie_breakers = [column for column in ("Benchmark", "Model", "Harness", "Run Label") if column in candidates]
|
| 193 |
+
candidates = candidates.sort_values(
|
| 194 |
+
[token_metric, score_column, *tie_breakers],
|
| 195 |
+
ascending=[True, False, *([True] * len(tie_breakers))],
|
| 196 |
+
kind="mergesort",
|
| 197 |
+
)
|
| 198 |
+
|
| 199 |
+
frontier_indices: list[object] = []
|
| 200 |
+
best_score_at_lower_tokens = float("-inf")
|
| 201 |
+
for _, token_group in candidates.groupby(token_metric, sort=True):
|
| 202 |
+
group_best_score = float(token_group[score_column].max())
|
| 203 |
+
if group_best_score > best_score_at_lower_tokens:
|
| 204 |
+
frontier_indices.extend(token_group[token_group[score_column] == group_best_score].index.tolist())
|
| 205 |
+
best_score_at_lower_tokens = group_best_score
|
| 206 |
+
|
| 207 |
+
return candidates.loc[frontier_indices].sort_values(
|
| 208 |
+
[token_metric, score_column, *tie_breakers],
|
| 209 |
+
ascending=[True, False, *([True] * len(tie_breakers))],
|
| 210 |
+
kind="mergesort",
|
| 211 |
+
)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
def get_benchmark_run_df():
|
| 215 |
results = get_results()
|
| 216 |
|
|
|
|
| 252 |
|
| 253 |
|
| 254 |
def get_score_vs_cost_df():
|
| 255 |
+
analysis_df = get_analysis_df()
|
| 256 |
+
score_vs_cost_df = analysis_df.dropna(subset=["Cost Per Task"]).copy()
|
| 257 |
+
columns = ["Label", "Model", "Harness", "Benchmark", "Category", "Score", "Cost Per Task (USD)"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
if score_vs_cost_df.empty:
|
| 259 |
+
return pd.DataFrame(columns=columns)
|
| 260 |
|
| 261 |
+
score_vs_cost_df["Label"] = score_vs_cost_df["Run Label"]
|
| 262 |
+
score_vs_cost_df["Score"] = score_vs_cost_df["Score (%)"].round(1)
|
| 263 |
+
score_vs_cost_df["Cost Per Task (USD)"] = score_vs_cost_df["Cost Per Task"].round(2)
|
| 264 |
+
return score_vs_cost_df[columns].sort_values(["Benchmark", "Score"], ascending=[True, False])
|
tests/test_token_efficiency.py
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
|
| 14 |
+
|
| 15 |
+
def make_result(
|
| 16 |
+
*,
|
| 17 |
+
benchmark: str = "Benchmark A",
|
| 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,
|
| 32 |
+
is_oss=True,
|
| 33 |
+
num_params=1,
|
| 34 |
+
precision="fp16",
|
| 35 |
+
url="https://example.com/model",
|
| 36 |
+
),
|
| 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():
|
| 76 |
+
dataframe = get_analysis_df([make_result(score=0, total_tokens=100)])
|
| 77 |
+
|
| 78 |
+
assert pd.isna(dataframe.loc[0, "Tokens Per Solved Task"])
|
| 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)
|
| 163 |
+
assert len(empty.layout.annotations) == 1
|
| 164 |
+
assert len(invalid.layout.annotations) == 1
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def test_palette_lookup_new_palettes_fallback_and_copy():
|
| 168 |
+
from src.charts import COLOR_PALETTES, get_color_palette
|
| 169 |
+
|
| 170 |
+
for palette_name in ("Grayscale", "Viridis", "Plasma", "Cividis"):
|
| 171 |
+
assert get_color_palette(palette_name) == COLOR_PALETTES[palette_name]
|
| 172 |
+
assert get_color_palette(palette_name) is not COLOR_PALETTES[palette_name]
|
| 173 |
+
|
| 174 |
+
fallback = get_color_palette("unknown")
|
| 175 |
+
assert fallback == COLOR_PALETTES["Citrus"]
|
| 176 |
+
fallback.append("#000000")
|
| 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"],
|
| 186 |
+
"Model": ["model-a"],
|
| 187 |
+
"Harness": ["harness-a"],
|
| 188 |
+
"Score": [50.0],
|
| 189 |
+
"Cost Per Task (USD)": [0.25],
|
| 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}
|