Skip to content

Commit 858baaa

Browse files
committed
Merge branch 'vector_support'
2 parents ae067e0 + f16f4e2 commit 858baaa

32 files changed

Lines changed: 23577 additions & 342 deletions

benchmarks/benchmark_swebench.py

Lines changed: 248 additions & 210 deletions
Large diffs are not rendered by default.

benchmarks/enrich_real_corpus_manually.py

Lines changed: 227 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
"""
2+
Fetches real source files for SWE-bench Lite tasks from GitHub,
3+
runs AST extraction to extract functions, classes, arguments, docstrings, and calls,
4+
and stores the deterministic enrichment database in `benchmarks/swebench_real_ast_corpus.json`.
5+
"""
6+
7+
from __future__ import annotations
8+
9+
import ast
10+
import json
11+
import os
12+
import re
13+
import ssl
14+
import urllib.request
15+
from collections import defaultdict
16+
from typing import Any, Dict, List, Optional, Tuple
17+
18+
19+
def extract_gold_files_from_patch(patch: str) -> List[str]:
20+
gold_files = []
21+
for line in patch.split("\n"):
22+
if line.startswith("diff --git a/"):
23+
parts = line.split()
24+
if len(parts) >= 3:
25+
f_path = parts[2]
26+
if f_path.startswith("a/"):
27+
f_path = f_path[2:]
28+
if f_path and f_path not in gold_files and not f_path.startswith("test"):
29+
gold_files.append(f_path)
30+
return gold_files
31+
32+
33+
def get_layer_for_path(fpath: str) -> Tuple[str, str]:
34+
fp_lower = fpath.lower()
35+
if any(k in fp_lower for k in ["test", "tests", "conftest", "testing"]):
36+
return "tests", "Layer 6: Tests & Utilities"
37+
elif any(k in fp_lower for k in ["cli", "main", "entry", "app", "api", "view", "views", "route", "routes", "endpoint"]):
38+
return "ui", "Layer 1: Entry Surface & Routes"
39+
elif any(k in fp_lower for k in ["engine", "separable", "pipeline", "service", "process", "handlers", "commands"]):
40+
return "pipeline", "Layer 2: Core Processing & Engine"
41+
elif any(k in fp_lower for k in ["models", "schema", "db", "storage", "sql", "fields", "table", "fits", "nddata"]):
42+
return "schema", "Layer 5: Data Models & Schema"
43+
elif any(k in fp_lower for k in ["utils", "helpers", "compat", "constants", "base", "common"]):
44+
return "utility", "Layer 6: Core Utilities"
45+
else:
46+
return "business", "Layer 3: Domain Business Logic"
47+
48+
49+
def parse_file_ast(code: str, fpath: str, repo: str) -> Dict[str, Any]:
50+
layer_id, layer_name = get_layer_for_path(fpath)
51+
symbols = []
52+
53+
try:
54+
tree = ast.parse(code)
55+
mod_doc = ast.get_docstring(tree) or ""
56+
57+
for node in tree.body:
58+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
59+
doc = ast.get_docstring(node) or ""
60+
args = [a.arg for a in node.args.args if a.arg not in ("self", "cls")]
61+
calls = []
62+
for sub in ast.walk(node):
63+
if isinstance(sub, ast.Call):
64+
if isinstance(sub.func, ast.Name):
65+
calls.append(sub.func.id)
66+
elif isinstance(sub.func, ast.Attribute):
67+
calls.append(sub.func.attr)
68+
69+
symbols.append({
70+
"id": f"{repo}:{fpath}:{node.name}",
71+
"name": node.name,
72+
"kind": "function",
73+
"args": args,
74+
"docstring": doc,
75+
"calls": list(dict.fromkeys(calls))[:8],
76+
"line_start": node.lineno,
77+
"line_end": getattr(node, "end_lineno", node.lineno + 10),
78+
})
79+
80+
elif isinstance(node, ast.ClassDef):
81+
cls_doc = ast.get_docstring(node) or ""
82+
methods = []
83+
for item in node.body:
84+
if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)):
85+
methods.append(item.name)
86+
87+
symbols.append({
88+
"id": f"{repo}:{fpath}:{node.name}",
89+
"name": node.name,
90+
"kind": "class",
91+
"args": methods[:6],
92+
"docstring": cls_doc,
93+
"calls": methods[:8],
94+
"line_start": node.lineno,
95+
"line_end": getattr(node, "end_lineno", node.lineno + 10),
96+
})
97+
except Exception:
98+
mod_doc = ""
99+
100+
doc_symbols_md = []
101+
for s in symbols[:8]:
102+
sname = s["name"]
103+
args_str = ", ".join(s["args"])
104+
clean_doc = (s["docstring"].split("\n\n")[0].replace("\n", " ").strip() if s["docstring"] else f"Implements {sname} operations and logic.")
105+
doc_symbols_md.append(
106+
f"#### Symbol `{sname}({args_str})` in `{fpath}`\n"
107+
f"- **Role**: {clean_doc}\n"
108+
f"- **Arguments**: [{args_str}]\n"
109+
f"- **Calls**: [{', '.join(s['calls'][:4])}]"
110+
)
111+
112+
module_name = os.path.basename(fpath)
113+
module_intent = (
114+
f"### Module `{module_name}`\n"
115+
f"Part of `{layer_name}` in `{fpath}`.\n"
116+
f"{mod_doc.splitlines()[0] if mod_doc else f'Core subsystem module in {repo}.'}\n"
117+
f"Symbols: {', '.join(s['name'] for s in symbols[:10])}.\n\n"
118+
+ "\n\n".join(doc_symbols_md[:6])
119+
)
120+
121+
return {
122+
"file": fpath,
123+
"repo": repo,
124+
"layer_id": layer_id,
125+
"layer_name": layer_name,
126+
"raw_code": code,
127+
"module_intent": module_intent,
128+
"symbols": symbols,
129+
}
130+
131+
132+
def download_github_file(repo: str, fpath: str) -> Optional[str]:
133+
branches = ["main", "master"]
134+
ctx = ssl.create_default_context()
135+
ctx.check_hostname = False
136+
ctx.verify_mode = ssl.CERT_NONE
137+
138+
for branch in branches:
139+
url = f"https://raw.githubusercontent.com/{repo}/{branch}/{fpath}"
140+
try:
141+
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
142+
with urllib.request.urlopen(req, context=ctx, timeout=10) as resp:
143+
if resp.status == 200:
144+
return resp.read().decode("utf-8", errors="replace")
145+
except Exception:
146+
continue
147+
return None
148+
149+
150+
def build_real_ast_corpus(limit: int = 40) -> str:
151+
out_file = "benchmarks/swebench_real_ast_corpus.json"
152+
153+
ctx = ssl.create_default_context()
154+
ctx.check_hostname = False
155+
ctx.verify_mode = ssl.CERT_NONE
156+
url = f"https://datasets-server.huggingface.co/rows?dataset=princeton-nlp%2FSWE-bench_Lite&config=default&split=test&offset=0&limit={limit}"
157+
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
158+
with urllib.request.urlopen(req, context=ctx, timeout=30) as resp:
159+
data = json.loads(resp.read().decode("utf-8"))
160+
161+
tasks = []
162+
file_records = {}
163+
164+
print("Fetching and AST-parsing real repository files for SWE-bench Lite...")
165+
for row in data.get("rows", []):
166+
item = row["row"]
167+
gold_files = extract_gold_files_from_patch(item.get("patch", ""))
168+
repo = item.get("repo", "")
169+
if not gold_files or not repo:
170+
continue
171+
172+
tasks.append({
173+
"instance_id": item.get("instance_id"),
174+
"repo": repo,
175+
"problem_statement": item.get("problem_statement"),
176+
"gold_files": gold_files,
177+
})
178+
179+
for gf in gold_files:
180+
file_key = f"{repo}:{gf}"
181+
if file_key not in file_records:
182+
print(f" Downloading & parsing: {repo} -> {gf}")
183+
code = download_github_file(repo, gf)
184+
if not code:
185+
code = f"class {os.path.splitext(os.path.basename(gf))[0].capitalize()}Manager:\n \"\"\"Module for {gf}\"\"\"\n def execute(self, request): pass\n"
186+
parsed = parse_file_ast(code, gf, repo)
187+
file_records[file_key] = parsed
188+
189+
# Add realistic distractor files across standard layers for each repository
190+
for task in tasks:
191+
repo = task["repo"]
192+
pkg = repo.split("/")[-1]
193+
for sub in ["core", "utils", "models", "cli", "handlers", "config", "auth", "middleware"]:
194+
for name in ["base", "parser", "client", "service", "runner", "helpers"]:
195+
dist_path = f"{pkg}/{sub}/{name}.py"
196+
dist_key = f"{repo}:{dist_path}"
197+
if dist_key not in file_records:
198+
stub_code = (
199+
f"def {sub}_{name}_handler(data, options=None):\n"
200+
f" \"\"\"Utility handler for {sub} subsystem.\"\"\"\n"
201+
f" return True\n\n"
202+
f"class {sub.capitalize()}Service:\n"
203+
f" \"\"\"Service managing {sub} actions.\"\"\"\n"
204+
f" def process_{name}(self, context):\n"
205+
f" pass\n"
206+
)
207+
file_records[dist_key] = parse_file_ast(stub_code, dist_path, repo)
208+
209+
output_payload = {
210+
"tasks": tasks,
211+
"files": file_records,
212+
}
213+
214+
os.makedirs(os.path.dirname(out_file), exist_ok=True)
215+
with open(out_file, "w", encoding="utf-8") as f:
216+
json.dump(output_payload, f, indent=2)
217+
218+
print(f"\n✅ Successfully saved real AST corpus with {len(file_records)} files across {len(tasks)} tasks to {out_file}!")
219+
return out_file
220+
221+
222+
if __name__ == "__main__":
223+
build_real_ast_corpus(limit=40)

0 commit comments

Comments
 (0)