mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
Python scripts for running SWE-bench Lite evals against Fabro agent in Daytona sandboxes: instance orchestration, Dockerfile generation, and result evaluation via the official swebench harness. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
137 lines
4 KiB
Python
137 lines
4 KiB
Python
#!/usr/bin/env python3
|
|
"""Evaluate SWE-bench predictions using the official harness.
|
|
|
|
Thin wrapper around swebench.harness.run_evaluation that reads a predictions
|
|
JSONL file, runs the evaluation, and prints a summary.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
from collections import Counter
|
|
from pathlib import Path
|
|
|
|
from swebench.harness.run_evaluation import main as run_evaluation
|
|
|
|
|
|
def print_summary(results_dir: Path):
|
|
"""Print evaluation summary from swebench output."""
|
|
results_file = results_dir / "results.json"
|
|
if not results_file.exists():
|
|
print(f"No results file found at {results_file}")
|
|
return
|
|
|
|
with open(results_file) as f:
|
|
results = json.load(f)
|
|
|
|
total = len(results)
|
|
resolved = sum(1 for r in results.values() if r.get("resolved", False))
|
|
|
|
print(f"\n{'=' * 60}")
|
|
print(f"SWE-bench Evaluation Results")
|
|
print(f"{'=' * 60}")
|
|
print(f"Total instances: {total}")
|
|
print(f"Resolved: {resolved} ({100 * resolved / total:.1f}%)")
|
|
print(f"{'=' * 60}")
|
|
|
|
# Per-repo breakdown
|
|
repo_counts: Counter[str] = Counter()
|
|
repo_resolved: Counter[str] = Counter()
|
|
for instance_id, result in results.items():
|
|
repo = instance_id.rsplit("-", 1)[0].rsplit("__", 1)[0]
|
|
# instance_id format: <owner>__<repo>-<number>
|
|
# Extract repo: split on "__" to get owner/repo parts
|
|
parts = instance_id.split("__")
|
|
if len(parts) >= 2:
|
|
repo = f"{parts[0]}/{parts[1].rsplit('-', 1)[0]}"
|
|
else:
|
|
repo = instance_id.rsplit("-", 1)[0]
|
|
repo_counts[repo] += 1
|
|
if result.get("resolved", False):
|
|
repo_resolved[repo] += 1
|
|
|
|
print(f"\nPer-repo breakdown:")
|
|
print(f"{'Repo':<40} {'Resolved':>10} {'Total':>8} {'Rate':>8}")
|
|
print(f"{'-' * 40} {'-' * 10} {'-' * 8} {'-' * 8}")
|
|
for repo in sorted(repo_counts):
|
|
res = repo_resolved[repo]
|
|
tot = repo_counts[repo]
|
|
rate = 100 * res / tot if tot > 0 else 0
|
|
print(f"{repo:<40} {res:>10} {tot:>8} {rate:>7.1f}%")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Evaluate SWE-bench predictions"
|
|
)
|
|
parser.add_argument(
|
|
"--predictions",
|
|
type=Path,
|
|
required=True,
|
|
help="Path to predictions JSONL file",
|
|
)
|
|
parser.add_argument(
|
|
"--max-workers",
|
|
type=int,
|
|
default=4,
|
|
help="Number of parallel evaluation workers",
|
|
)
|
|
parser.add_argument(
|
|
"--instance-ids",
|
|
nargs="+",
|
|
help="Evaluate only these instance IDs",
|
|
)
|
|
parser.add_argument(
|
|
"--run-id",
|
|
default="swebench-eval",
|
|
help="Run ID for swebench evaluation output",
|
|
)
|
|
parser.add_argument(
|
|
"--dataset",
|
|
default="princeton-nlp/SWE-bench_Lite",
|
|
help="HuggingFace dataset name",
|
|
)
|
|
parser.add_argument(
|
|
"--split",
|
|
default="test",
|
|
help="Dataset split",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
if not args.predictions.exists():
|
|
print(f"Error: predictions file not found: {args.predictions}")
|
|
raise SystemExit(1)
|
|
|
|
print(f"Running swebench evaluation...")
|
|
print(f" Predictions: {args.predictions}")
|
|
print(f" Max workers: {args.max_workers}")
|
|
|
|
report_dir = str(args.predictions.parent)
|
|
|
|
run_evaluation(
|
|
dataset_name=args.dataset,
|
|
split=args.split,
|
|
instance_ids=args.instance_ids or [],
|
|
predictions_path=str(args.predictions),
|
|
max_workers=args.max_workers,
|
|
force_rebuild=False,
|
|
cache_level="env",
|
|
clean=False,
|
|
open_file_limit=4096,
|
|
run_id=args.run_id,
|
|
timeout=1800,
|
|
namespace=None,
|
|
rewrite_reports=False,
|
|
modal=False,
|
|
report_dir=report_dir,
|
|
)
|
|
|
|
# Try to find and print results
|
|
results_dir = Path(report_dir) / args.run_id
|
|
if results_dir.exists():
|
|
print_summary(results_dir)
|
|
else:
|
|
print(f"\nEvaluation complete. Check {report_dir}/ directory for results.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|