File size: 5,545 Bytes
8bddb37 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | # /// script
# requires-python = ">=3.10"
# dependencies = [
# "datasets",
# "huggingface_hub",
# ]
# ///
#!/usr/bin/env python3
"""
Agent Solve Rate Experiment for SWE-Bench Pro
Uses DeepSeek-V4-Flash (free HF inference) to attempt solving SWE-Bench Pro tasks.
Measures format-compliant patch generation rate (NOT actual correctness).
"""
import json
import time
import re
import sys
from pathlib import Path
# Configuration
NUM_TASKS = 20 # Test on 20 tasks for statistical significance
MODEL = "deepseek-ai/DeepSeek-V4-Flash"
MAX_TOKENS = 2048
RATE_LIMIT_DELAY = 2.0 # seconds between calls to avoid rate limits
OUTPUT_FILE = "/tmp/agent_solve_results.json"
def load_dataset():
"""Load SWE-Bench Pro dataset from HuggingFace."""
from datasets import load_dataset
ds = load_dataset("ScaleAI/SWE-bench_Pro", split="test")
return ds
def create_prompt(instance):
"""Create a prompt for the model to generate a patch."""
repo = instance.get("repo", "unknown")
instance_id = instance.get("instance_id", "unknown")
problem_statement = instance.get("problem_statement", "")
base_commit = instance.get("base_commit", "")
prompt = f"""You are an expert software engineer. Given the following issue in the repository {repo}, generate a patch to fix the issue.
Issue: {problem_statement}
Please provide a unified diff patch that fixes this issue. The patch should:
1. Be in unified diff format (--- a/file.py, +++ b/file.py)
2. Only modify the necessary files
3. Be minimal and focused on the fix
Output ONLY the patch in unified diff format, no explanation:"""
return prompt
def call_model(prompt, max_retries=3):
"""Call DeepSeek-V4-Flash with retry logic."""
from huggingface_hub import InferenceClient
client = InferenceClient()
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": prompt}],
max_tokens=MAX_TOKENS,
temperature=0.0
)
return response.choices[0].message.content
except Exception as e:
if "rate" in str(e).lower() and attempt < max_retries - 1:
wait = RATE_LIMIT_DELAY * (attempt + 1)
print(f"Rate limited, waiting {wait}s...")
time.sleep(wait)
else:
print(f"Error calling model: {e}")
return None
return None
def is_valid_patch(response):
"""Check if the response looks like a valid unified diff patch."""
if not response:
return False, "No response"
# Check for unified diff markers
has_diff_header = bool(re.search(r'^diff --git', response, re.MULTILINE) or
re.search(r'^---', response, re.MULTILINE) or
re.search(r'^\+\+\+', response, re.MULTILINE))
has_hunk_header = bool(re.search(r'^@@', response, re.MULTILINE))
has_additions = bool(re.search(r'^\+[^+]', response, re.MULTILINE))
has_deletions = bool(re.search(r'^-[^-]', response, re.MULTILINE))
if has_diff_header and has_hunk_header and (has_additions or has_deletions):
return True, "Valid unified diff"
elif has_hunk_header:
return True, "Has hunk headers"
elif has_additions or has_deletions:
return True, "Has changes"
else:
return False, "No diff markers found"
def main():
print(f"Loading SWE-Bench Pro dataset...")
ds = load_dataset()
print(f"Total instances: {len(ds)}")
# Sample tasks
import random
random.seed(42)
indices = random.sample(range(len(ds)), min(NUM_TASKS, len(ds)))
tasks = [ds[i] for i in indices]
results = []
success_count = 0
error_count = 0
for i, instance in enumerate(tasks):
instance_id = instance.get("instance_id", f"task_{i}")
print(f"\n[{i+1}/{len(tasks)}] Processing {instance_id}...")
prompt = create_prompt(instance)
response = call_model(prompt)
is_valid, reason = is_valid_patch(response)
result = {
"instance_id": instance_id,
"repo": instance.get("repo", ""),
"response_length": len(response) if response else 0,
"is_valid_patch": is_valid,
"validation_reason": reason,
"response_preview": response[:500] if response else ""
}
results.append(result)
if is_valid:
success_count += 1
print(f" ✓ Valid patch ({reason})")
else:
error_count += 1
print(f" ✗ {reason}")
# Rate limiting
time.sleep(RATE_LIMIT_DELAY)
# Summary
summary = {
"model": MODEL,
"total_tasks": len(tasks),
"valid_patches": success_count,
"invalid_patches": error_count,
"format_compliance_rate": success_count / len(tasks) if tasks else 0,
"results": results
}
# Save results
with open(OUTPUT_FILE, "w") as f:
json.dump(summary, f, indent=2)
print(f"\n{'='*60}")
print(f"RESULTS SUMMARY")
print(f"{'='*60}")
print(f"Model: {MODEL}")
print(f"Tasks tested: {len(tasks)}")
print(f"Valid patches: {success_count}/{len(tasks)} ({success_count/len(tasks)*100:.1f}%)")
print(f"Results saved to: {OUTPUT_FILE}")
return summary
if __name__ == "__main__":
main()
|