rounakbende commited on
Commit
e57d344
·
1 Parent(s): 0c17ce6

Add CSV export script with data validation and auto-update workflow

Browse files

- src/results_to_csv.py: converts result JSONs to CSV, validates for missing fields
- results.csv: generated CSV with all 22 current results
- .github/workflows/update-csv.yml: auto-regenerates CSV when results/*.json changes on main
- Makefile: added `make csv` target

.github/workflows/update-csv.yml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Update results CSV
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "results/*.json"
8
+
9
+ jobs:
10
+ update-csv:
11
+ runs-on: ubuntu-latest
12
+ timeout-minutes: 5
13
+ permissions:
14
+ contents: write
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+
22
+ - name: Install dependencies
23
+ run: pip install pandas
24
+
25
+ - name: Generate CSV
26
+ run: python src/results_to_csv.py
27
+
28
+ - name: Commit if changed
29
+ run: |
30
+ git config user.name "github-actions[bot]"
31
+ git config user.email "github-actions[bot]@users.noreply.github.com"
32
+ git add results.csv
33
+ git diff --staged --quiet || git commit -m "Auto-update results.csv" && git push
Makefile CHANGED
@@ -11,3 +11,7 @@ quality:
11
  python -m black --check --line-length 119 .
12
  python -m isort --check-only .
13
  ruff check .
 
 
 
 
 
11
  python -m black --check --line-length 119 .
12
  python -m isort --check-only .
13
  ruff check .
14
+
15
+
16
+ csv:
17
+ python src/results_to_csv.py
results.csv ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ benchmark.name,benchmark.repo,benchmark.num_tasks,benchmark.url,harness.name,harness.skills,harness.is_oss,harness.url,model.name,model.repo,model.is_oss,model.num_params,model.precision,model.url,environment.name,environment.url,metrics.n_tasks,metrics.n_errors,metrics.score,metrics.n_input_tokens,metrics.n_cache_tokens,metrics.n_output_tokens,metrics.n_total_tokens,metrics.agent_time_seconds,metrics.total_time_seconds,metrics.cost_usd,metrics.mean_input_tokens_per_task,metrics.mean_cache_tokens_per_task,metrics.mean_output_tokens_per_task,metrics.mean_tokens_per_task,metrics.mean_cost_usd_per_task,metrics.mean_total_time_seconds_per_task,metrics.mean_agent_time_seconds_per_task
2
+ RH SWE-Bench,rounakbende10/rh-swe-bench,357,https://huggingface.co/datasets/rounakbende/rh-swe-bench,Claude Code,[],False,https://github.com/anthropics/claude-code,Opus 4.6,Opus 4.6,False,1000,bf16,https://www.anthropic.com/news/claude-opus-4-6,harbor,https://github.com/harbor-framework/harbor,357.0,0.0,0.633,438501505.0,419608736.0,2823496.0,860933737.0,126529.0,243310.0,434.54,1228295.0,1175374.0,7908.0,2411579.0,1.22,681.0,354.0
3
+ RH SWE-Bench,rounakbende10/rh-swe-bench,357,https://huggingface.co/datasets/rounakbende/rh-swe-bench,Claude Code,[],False,https://github.com/anthropics/claude-code,Sonnet 4.6,Sonnet 4.6,False,1000,bf16,https://www.anthropic.com/news/claude-sonnet-4-6,harbor,https://github.com/harbor-framework/harbor,357.0,0.0,0.557,500304168.0,479035103.0,4937782.0,984277053.0,150652.0,269008.0,349.77,1401412.0,1341835.0,13831.0,2757078.0,0.98,753.0,421.0
4
+ SWE-Bench Pro -- Ansible,ScaleAI/SWE-bench_Pro,96,https://huggingface.co/datasets/ScaleAI/SWE-bench_Pro,Claude Code,[],False,https://github.com/anthropics/claude-code,Opus 4.8,Opus 4.8,False,1000,bf16,https://www.anthropic.com/news/claude-opus-4-8,harbor,https://github.com/harbor-framework/harbor,96.0,0.0,0.698,192346997.0,186506482.0,2179945.0,381033424.0,32745.0,39030.0,185.66155285,2003614.0,1942775.0,22707.0,3969098.0,1.93,406.0,341.0
5
+ SWE-Bench Pro -- Ansible,ScaleAI/SWE-bench_Pro,96,https://huggingface.co/datasets/ScaleAI/SWE-bench_Pro,OpenCode,[],True,https://github.com/anomalyco/opencode,Opus 4.8,Opus 4.8,False,1000,bf16,https://www.anthropic.com/news/claude-opus-4-8,harbor,https://github.com/harbor-framework/harbor,96.0,0.0,0.781,187217712.0,187209844.0,1280944.0,375708500.0,30686.0,39352.0,151.4104807499999,1950184.0,1950102.0,13343.0,3913630.0,1.58,409.0,319.0
6
+ SWE-Bench Pro -- Ansible,ScaleAI/SWE-bench_Pro,96,https://huggingface.co/datasets/ScaleAI/SWE-bench_Pro,Claude Code,[],False,https://github.com/anthropics/claude-code,Sonnet 4.6,Sonnet 4.6,False,1000,bf16,https://www.anthropic.com/news/claude-sonnet-4-6,harbor,https://github.com/harbor-framework/harbor,96.0,1.0,0.5,190672390.0,184409111.0,1593112.0,376674613.0,40527.0,49734.0,184.42824125000004,1986170.0,1920928.0,16594.0,3923693.0,1.92,518.0,422.0
7
+ SWE-Bench Pro -- Ansible,ScaleAI/SWE-bench_Pro,96,https://huggingface.co/datasets/ScaleAI/SWE-bench_Pro,Codex,[],True,https://github.com/openai/codex,GPT 5.5 - high,GPT 5.5 - high,False,9700,bf16,https://openai.com/index/introducing-gpt-5-5,harbor,https://github.com/harbor-framework/harbor,96.0,0.0,0.604,198924339.0,189578624.0,1560836.0,390063799.0,32914.0,39468.0,188.34296700000002,2072128.0,1974777.0,16258.0,4063164.0,1.96,411.0,342.0
8
+ SWE-Bench Pro -- Ansible,ScaleAI/SWE-bench_Pro,96,https://huggingface.co/datasets/ScaleAI/SWE-bench_Pro,Claude Code,[],False,https://github.com/anthropics/claude-code,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,96.0,6.0,0.458,367897697.0,0.0,1694885.0,369592582.0,39024.0,46758.0,9.64,3832267.0,0.0,17655.0,3849922.0,0.1,487.0,406.0
9
+ SWE-Bench Pro -- Ansible,ScaleAI/SWE-bench_Pro,96,https://huggingface.co/datasets/ScaleAI/SWE-bench_Pro,OpenCode,[],True,https://github.com/anomalyco/opencode,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,96.0,4.0,0.375,207164679.0,0.0,1598703.0,208763382.0,49450.0,57287.0,12.21,2157965.0,0.0,16653.0,2174618.0,0.13,596.0,515.0
10
+ SWE-Bench Pro -- Ansible,ScaleAI/SWE-bench_Pro,96,https://huggingface.co/datasets/ScaleAI/SWE-bench_Pro,OpenClaw,[],True,https://github.com/openclaw/openclaw,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,96.0,5.0,0.406,0.0,0.0,0.0,0.0,38085.0,50779.0,9.4,0.0,0.0,0.0,0.0,0.1,528.0,396.0
11
+ SWE-Bench Pro -- Ansible,ScaleAI/SWE-bench_Pro,96,https://huggingface.co/datasets/ScaleAI/SWE-bench_Pro,Pi,[],True,https://github.com/earendil-works/pi/tree/main,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,96.0,1.0,0.479,742491363.0,0.0,2387609.0,744878972.0,54543.0,62422.0,13.47,7734285.0,0.0,24870.0,7759155.0,0.14,650.0,568.0
12
+ SWE-Bench Pro -- Ansible,ScaleAI/SWE-bench_Pro,96,https://huggingface.co/datasets/ScaleAI/SWE-bench_Pro,Qwen Code,[],True,https://github.com/QwenLM/qwen-code,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,96.0,9.0,0.438,159198517.0,0.0,972133.0,160170650.0,33610.0,38272.0,9.34,1658317.0,0.0,10126.0,1668444.0,0.1,398.0,350.0
13
+ SWE-Bench Verified,SWE-bench/SWE-bench_Verified,500,https://huggingface.co/datasets/SWE-bench/SWE-bench_Verified,Claude Code,[],False,https://github.com/anthropics/claude-code,Opus 4.8,Opus 4.8,False,1000,bf16,https://www.anthropic.com/news/claude-opus-4-8,harbor,https://github.com/harbor-framework/harbor,500.0,0.0,0.868,402225158.0,388781382.0,4588859.0,795595399.0,104467.0,159566.0,394.7823929,804450.0,777562.0,9177.0,1591190.0,0.79,319.0,208.0
14
+ SWE-Bench Verified,SWE-bench/SWE-bench_Verified,500,https://huggingface.co/datasets/SWE-bench/SWE-bench_Verified,OpenCode,[],True,https://github.com/anomalyco/opencode,Opus 4.8,Opus 4.8,False,1000,bf16,https://www.anthropic.com/news/claude-opus-4-8,harbor,https://github.com/harbor-framework/harbor,500.0,0.0,0.834,347751942.0,347725246.0,3640204.0,699117392.0,114633.0,171540.0,319.53304049999974,695503.0,695450.0,7280.0,1398234.0,0.64,343.0,229.0
15
+ SWE-Bench Verified,SWE-bench/SWE-bench_Verified,500,https://huggingface.co/datasets/SWE-bench/SWE-bench_Verified,Claude Code,[],False,https://github.com/anthropics/claude-code,Sonnet 4.6,Sonnet 4.6,False,1000,bf16,https://www.anthropic.com/news/claude-sonnet-4-6,harbor,https://github.com/harbor-framework/harbor,,,0.796,,,,,,,,,,,,,,
16
+ SWE-Bench Verified,SWE-bench/SWE-bench_Verified,500,https://huggingface.co/datasets/SWE-bench/SWE-bench_Verified,Codex,[],True,https://github.com/openai/codex,GPT 5.5 - high,GPT 5.5 - high,False,9700,bf16,https://openai.com/index/introducing-gpt-5-5,harbor,https://github.com/harbor-framework/harbor,500.0,0.0,0.798,415795756.0,386352384.0,3431224.0,805579364.0,92588.0,141637.0,443.32977200000016,831591.0,772704.0,6862.0,1611158.0,0.89,283.0,185.0
17
+ SWE-Bench Verified,SWE-bench/SWE-bench_Verified,500,https://huggingface.co/datasets/SWE-bench/SWE-bench_Verified,Claude Code,[],False,https://github.com/anthropics/claude-code,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,500.0,1.0,0.632,1106618897.0,0.0,5733245.0,1112352142.0,122808.0,171897.0,34.11,2213237.0,0.0,11466.0,2224704.0,0.07,343.0,245.0
18
+ SWE-Bench Verified,SWE-bench/SWE-bench_Verified,500,https://huggingface.co/datasets/SWE-bench/SWE-bench_Verified,OpenClaw,[],True,https://github.com/openclaw/openclaw,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,500.0,3.0,0.588,0.0,0.0,0.0,0.0,120399.0,200354.0,33.44,0.0,0.0,0.0,0.0,0.07,400.0,240.0
19
+ SWE-Bench Verified,SWE-bench/SWE-bench_Verified,500,https://huggingface.co/datasets/SWE-bench/SWE-bench_Verified,OpenCode,[],True,https://github.com/anomalyco/opencode,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,500.0,4.0,0.548,469806650.0,0.0,4937761.0,474744411.0,120473.0,185168.0,29.75,939613.0,0.0,9875.0,949488.0,0.06,370.0,240.0
20
+ SWE-Bench Verified,SWE-bench/SWE-bench_Verified,500,https://huggingface.co/datasets/SWE-bench/SWE-bench_Verified,Pi,[],True,https://github.com/earendil-works/pi/tree/main,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,500.0,6.0,0.65,791183735.0,0.0,6333798.0,797517533.0,154531.0,218988.0,38.16,1582367.0,0.0,12667.0,1595035.0,0.08,437.0,309.0
21
+ SWE-Bench Verified,SWE-bench/SWE-bench_Verified,500,https://huggingface.co/datasets/SWE-bench/SWE-bench_Verified,Qwen Code,[],True,https://github.com/QwenLM/qwen-code,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,500.0,3.0,0.638,609589099.0,0.0,3964252.0,613553351.0,132273.0,178984.0,36.74,1219178.0,0.0,7928.0,1227106.0,0.07,357.0,264.0
22
+ Terminal Bench 2.0,terminal-bench/terminal-bench-2,89,https://www.tbench.ai/benchmarks/terminal-bench-2,OpenCode,[],True,https://github.com/anomalyco/opencode,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,89.0,5.0,0.303,47607780.0,0.0,1657188.0,49264968.0,46467.0,58507.0,11.47,534918.0,0.0,18620.0,553538.0,0.13,657.0,522.0
23
+ Terminal Bench 2.0,terminal-bench/terminal-bench-2,89,https://www.tbench.ai/benchmarks/terminal-bench-2,Pi,[],True,https://github.com/earendil-works/pi/tree/main,Qwen3.6-35B-A3B-NVFP4,RedHatAI/Qwen3.6-35B-A3B-NVFP4,True,35,nvfp4,https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4,harbor,https://github.com/harbor-framework/harbor,89.0,5.0,0.36,82108716.0,0.0,2056390.0,84165106.0,44991.0,64760.0,11.11,922569.0,0.0,23105.0,945675.0,0.12,727.0,505.0
src/results_to_csv.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Convert result JSON files to CSV and validate data completeness.
3
+
4
+ Based on load_dicts_to_df from:
5
+ https://github.com/erikerlandson/paired-comparison-ranking/blob/main/nb/paired-comparison-ranking.ipynb
6
+ """
7
+
8
+ import ast
9
+ import json
10
+ import sys
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ import pandas as pd
15
+
16
+
17
+ REQUIRED_METRICS = [
18
+ "metrics.n_tasks",
19
+ "metrics.n_errors",
20
+ "metrics.score",
21
+ "metrics.cost_usd",
22
+ "metrics.n_input_tokens",
23
+ "metrics.n_output_tokens",
24
+ "metrics.agent_time_seconds",
25
+ "metrics.total_time_seconds",
26
+ ]
27
+
28
+
29
+ def load_dicts_to_df(
30
+ directory: str | Path,
31
+ pattern: str = "*.json",
32
+ ) -> pd.DataFrame:
33
+ directory = Path(directory)
34
+ if not directory.is_dir():
35
+ raise NotADirectoryError(directory)
36
+
37
+ rows: list[dict[str, Any]] = []
38
+ for path in sorted(directory.glob(pattern)):
39
+ if not path.is_file() or path.name.startswith("."):
40
+ continue
41
+ suffix = path.suffix.lower()
42
+ if suffix == ".json":
43
+ with path.open(encoding="utf-8") as f:
44
+ data = json.load(f)
45
+ else:
46
+ text = path.read_text(encoding="utf-8")
47
+ data = ast.literal_eval(text)
48
+
49
+ if not isinstance(data, dict):
50
+ raise TypeError(f"{path} does not contain a dict (got {type(data).__name__})")
51
+ rows.append(data)
52
+
53
+ return pd.json_normalize(rows)
54
+
55
+
56
+ def validate(df: pd.DataFrame) -> bool:
57
+ issues = []
58
+ for _, row in df.iterrows():
59
+ label = f"{row.get('benchmark.name', '?')} / {row.get('model.name', '?')} / {row.get('harness.name', '?')}"
60
+ missing = [col for col in REQUIRED_METRICS if col in df.columns and pd.isna(row.get(col))]
61
+ if missing:
62
+ fields = ", ".join(c.replace("metrics.", "") for c in missing)
63
+ issues.append(f" {label}: missing {fields}")
64
+
65
+ if issues:
66
+ print(f"Validation: {len(issues)} result(s) with missing data:")
67
+ for issue in issues:
68
+ print(issue)
69
+ return False
70
+
71
+ print("Validation: all results complete")
72
+ return True
73
+
74
+
75
+ def main():
76
+ results_dir = Path(__file__).parent.parent / "results"
77
+ output_path = Path(__file__).parent.parent / "results.csv"
78
+
79
+ if len(sys.argv) > 1:
80
+ results_dir = Path(sys.argv[1])
81
+ if len(sys.argv) > 2:
82
+ output_path = Path(sys.argv[2])
83
+
84
+ df = load_dicts_to_df(results_dir)
85
+
86
+ drop_cols = [c for c in df.columns if c.startswith("environment.config.")]
87
+ df = df.drop(columns=drop_cols)
88
+
89
+ validate(df)
90
+
91
+ df.to_csv(output_path, index=False)
92
+ print(f"Wrote {len(df)} rows to {output_path}")
93
+
94
+
95
+ if __name__ == "__main__":
96
+ main()