Paper Summary – SWE-smith
1.Introduction
However, the most effective agents still rely on proprietary LMs, as building open source LMs for SE remains bottlenecked by the lack of large-scale, high-quality training data. This article creates, ==SWE-smith==, a novel pipeline for generating software engineering training data at scale.
SWE-bench:
- Find real bug
- Build up environment
- Verification
SWE-smith:
- Build up environment
- Create bug
- Verification
Contribution:
- 4 kinds bug generation strategies
- LM Generation
- Procedural Modification
- Combine Bugs
- Invert PRs
2. Main Work(Generate bug.diff)
2.1 Choose & Install Repository
SWE-smith requires ==Python== projects with ==unit tests==.
Filter Repository:
- Target repositories for the 5, 000 most downloaded packages listed in the ==Python Package Index== (PyPI) as of November 18, 2024
- Sort the PyPI packages by GitHub stars
- Remove any PyPI package with less than 1, 000 stars, as well as all 12 SWE-bench test repositories from consideration.
Creaete corresponding image:
- Get the newest ==commit== and ==SWE-agent== to automatically attempt to install and run tests in 100 steps.
- Manually Check:
- Are the installation steps reasonable (without damaging the system environment) ?
- Are the test commands correct (have they actually run a complete test instead of a dummy run) ?
- Check if more than 80% of existing tests pass
- Create a ==Docker Image== for the repository
2.2 Creating Task Instance Candidates
4 methods to create task instances:
- LM Generations
- Procedural Modification
- Combine Bugs
- Invert PRs (Most effective)
2.3 Execution-based Validation of Candidates
1 | git checkout origin-code |
2.4 Generating problem statements
End to End Demonstration
1 | 完整的端到端示例 |
3. Data Process & Tuning Model
3.1 Verification bug.diff is Effective
Run pre-gold test before applying patch, test log:
1
2
3
4
5
6
7
8
9
10
11
12test_get_loc_naive_dti_aware_str_deprecated PASSED
test_indexing_with_datetime_tz PASSED
test_indexing_fast_xs PASSED
test_consistency_with_tz_aware_scalar PASSED
test_indexing_with_datetimeindex_tz[setitem] PASSED
test_indexing_with_datetimeindex_tz[loc] PASSED
test_nanosecond_getitem_setitem_with_tz PASSED
test_getitem_str_slice_millisecond_resolution[DataFrame] PASSED
test_getitem_str_slice_millisecond_resolution[Series] PASSED
test_getitem_pyarrow_index[DataFrame] PASSED ← Notice ⚠️
test_getitem_pyarrow_index[Series] PASSED ← Notice ⚠️
Apply bug.diff file, then run test again
1
2
3
4
5
6
7
8
9
10
11test_get_loc_naive_dti_aware_str_deprecated PASSED
test_indexing_with_datetime_tz PASSED
test_indexing_fast_xs PASSED
test_consistency_with_tz_aware_scalar PASSED
test_indexing_with_datetimeindex_tz[setitem] PASSED
test_indexing_with_datetimeindex_tz[loc] PASSED
test_nanosecond_getitem_setitem_with_tz PASSED
test_getitem_str_slice_millisecond_resolution[DataFrame] PASSED
test_getitem_str_slice_millisecond_resolution[Series] PASSED
test_getitem_pyarrow_index[DataFrame] FAILED ← ❗
test_getitem_pyarrow_index[Series] FAILED ← ❗Create report.json
1
2
3
4
5
6
7
8
9
10
11
12
13{
"FAIL_TO_PASS": [
"pandas/tests/indexing/test_datetime.py::TestDatetimeIndex::test_getitem_pyarrow_index[DataFrame]",
"pandas/tests/indexing/test_datetime.py::TestDatetimeIndex::test_getitem_pyarrow_index[Series]"
],
"PASS_TO_PASS": [
"pandas/tests/indexing/test_datetime.py::TestDatetimeIndex::test_get_loc_naive_dti_aware_str_deprecated",
"pandas/tests/indexing/test_datetime.py::TestDatetimeIndex::test_indexing_with_datetime_tz",
"... total 9 ..."
],
"FAIL_TO_FAIL": [],
"PASS_TO_FAIL": []
}Failed Meaning Details FAIL_TO_PASS Pre-gold PASS → Post-gold FAIL 2 testcases disrupted by bug ✅ PASS_TO_PASS Pre-gold PASS → Post-gold PASS 9 testcases are not be affected ✅ FAIL_TO_FAIL Pre-gold PASS → Post-gold FAIL - PASS_TO_FAIL Pre-gold PASS → Post-gold FAIL - Judge Code (valid.py:144):
1
2
3
4if len(report[FAIL_TO_PASS]) == 0:
return {"status": "0_f2p"}
else:
return {"status": "1+_f2p"} # ✅ Valid Bug
3.2 Assemble SWE-bench Format Test Dataset
Read report and verify result (harness/gather.py :316-339)
1
2
3
4
5
6
7
8
9
10
11
12
13# read report.json
with open(path_results) as f:
results = json.load(f)
# 3 conditions needed
n_f2p = len(results[PASS_TO_FAIL])
n_p2p = len(results[PASS_TO_PASS])
# 1. not timeout
# 2. at least one testcase is disrupted
# 3. at least one testcase is passed
if KEY_TIMED_OUT in results or n_f2p == 0 or n_p2p == 0:
return SKIP # ← abortAssemble ==task_instance== (harness/gather.py :341-353) :
1
2
3
4
5
6
7
8task_instance = {
"instance_id": subfolder, # e.g. "pandas-dev__pandas.95280573.pr_53652"
"patch": patch_content, # bug diff contents
"FAIL_TO_PASS": results[PASS_TO_FAIL], # from report.json, note the task_instance[f2p] is from result[p2f] beacuse of the rule of SWE-bench is f2p.
"PASS_TO_PASS": results[PASS_TO_PASS], # from report.json
"image_name": rp.image_name, # Docker Image name
"repo": rp.mirror_name, # GitHub repo name
}Create new Git branch (harness/gather.py :466-569) :
Create new branch for each valid instance on Github, then:
1
2
3
4
5
6
7git clone repo
git checkout main
git apply bug.diff # apply bug.diff
git commit -m "Bug Patch" # commit bug code
remove the testcases that will fail
git commit -m "Remove F2P Tests" # commit
Delete the testcase that will fail:
1
2
3
4
5
6
7f2p_test_files, _ = rp.get_test_files(task_instance)
if f2p_test_files:
for test_file in f2p_test_files:
os.remove(test_file_path) # delete the test that will fail
git add . && git commit -m "Remove F2P Tests"
Why delete this file ?
This way SWE-agent can find the tests need to be repaired by git diff.
git diff main -> deleted file -> bug position
```sh Agent git checkout → testcase not exist Agent git log: commit 1: “Bug Patch” commit 2: “Remove Tests” Agent inference: Deleted files in commit 2 is used to verify bug Agent git checkout main – test_xxx.py -> Restore testcase …
1
2
3
4
5
6
7
8
- ==I don't think it make sense.==
4. Assemble all instances (harness/gather.py :269-273) :
```python
task_instances_path = LOG_DIR_TASKS / f"{run_id}.json"
json.dump(task_instances, f, indent=4)
3.3 Generate problem_statement by LLM (issue_gen/generate.py)
Input for LLM:
Demonstration :
Randomly select 2 genuine GitHub issues from the SWE-bench Verified as style references.
Patch (<patch> label) :
Content of bug.diff
test_output (<test_output> label) :
Testcases that failed in post-gold. (Introducing by bug.diff)
test_source_code (<test_source_code> label) :
Analyze the failed testcases’ source code by Python AST. Gather the full test source code.
LLM constrains (ig_v2.yaml) :
1 | instance: |- |
Generate problem_statement (generate.py :376-387) :
1 | if self.portkey_model: |
Extract statement (generate.py :398-401):
1 | problem_statements = [ |
Now the instances:
1 | { |
3.4 Collect traj by Expert Model ( Rejection Sampling Fine-Tuning) (_gen_trajs.sh)
SWE-smith aims to train a student model (Qwen 2.5 Coder 32B)
- If use student to solve the issues, the success rate is too low (~11%), and we cannot collect enough “successful trajectories”.
- Running with ==Claude 3.7 Sonnet== (success rate ~36%) can collect a large number of high-quality “correct answer demonstrations”.
1 | sweagent run-batch \ |
1 | { |
1 | trajectories/<run_id>/ |
3.5 Filter Success Patches (swesmith/harness/eval.py)
1 | python -m swesmith.harness.eval \ |
1 | def run_evaluation(pred, instance, run_id, ...): |
1 | logs/run_evaluation/<run_id>/ |
Summary Report:
1 | { |
3.6 Trans .traj into OpenAI messages
Filter success trajectories (collect_trajs.py : 57-58) :
1
2
3
4report = json.loads(report_path.read_text())
is_resolved = report.get("resolved", False)
...
traj["resolved"] = is_resolvedFormat Conversion (utils.py : 81-111) :
Package
thoughtandactionas content:1
2
3
4
5
6
7
8
9
10
11def transform_traj_xml(traj):
for message in get_messages(traj):
if message["role"] == "assistant":
content = message["thought"]
content += "\n\n" + tool_call_to_action(message["tool_calls"])
elif message["role"] == "system":
content = SYSTEM_PROMPT
else: # tool / user
content = message["content"][0]["text"]
new_traj.append({"role": role, "content": content})
return {"messages": new_traj}e.g.
Unconverted .traj:
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{
"trajectory": [
{
"step": 1,
"thought": "I'll help you implement the necessary changes to fix the issue. Let me first explore the repository structure.",
"action": "find /testbed -type f -name '*.py' | grep -v __pycache__ | grep -v test_ | head
-20",
"observation": "/testbed/pandas/core/indexes/base.py\n/testbed/pandas/core/indexes/datetime
s.py\n/testbed/pandas/core/indexes/datetimelike.py\n..."
},
{
"step": 2,
"thought": "The PR description mentions the error occurs in base.py around line 6039. Let
me look at that specific code.",
"action": "cat -n /testbed/pandas/core/indexes/base.py | sed -n '6070,6090p'",
"observation": "6070 if keyarr.dtype.kind in \"mM\":\n6071 if isinstance(key,
list) or (\n6072 isinstance(key, type(self))\n6073 and key.freq is
None\n6074 ):\n6075 keyarr = keyarr._with_freq(None)"
},
{
"step": 3,
"thought": "I see the issue. The code accesses `key.freq` but PyArrow-backed Index objects
don't have a `freq` attribute. Let me create a reproduction script first.",
"action": "cat > /testbed/reproduce.py << 'EOF'\nimport numpy as np\nimport pandas as
pd\n\nt = pd.date_range('2023-01-01', '2023-01-04', freq='1h')\nx = np.random.randn(len(t))\ndf =
pd.DataFrame(x, index=t, columns=['values'])\ndf.to_parquet('frame.parquet')\ndf2 =
pd.read_parquet('frame.parquet',
dtype_backend='pyarrow')\nprint(df2.loc[df2.index[:-5]].head())\nEOF",
"observation": "File created successfully."
},
{
"step": 4,
"thought": "Now let me run the reproduction script to confirm the error.",
"action": "cd /testbed && python reproduce.py",
"observation": "AttributeError: 'Index' object has no attribute 'freq'"
},
{
"step": 5,
"thought": "Confirmed. Now I'll fix the issue. I need to add a hasattr check before
accessing `key.freq`. Let me edit the file.",
"action": "sed -i 's/and key.freq is None/and (not hasattr(key, \"freq\") or key.freq is
None)/' /testbed/pandas/core/indexes/base.py",
"observation": "Command executed successfully."
},
{
"step": 6,
"thought": "I also need to handle the `_with_freq` call which doesn't exist on
PyArrow-backed Index objects.",
"action": "sed -i '/keyarr = keyarr._with_freq(None)/i\\ if hasattr(keyarr,
\"_with_freq\"):' /testbed/pandas/core/indexes/base.py",
"observation": "Command executed successfully."
},
{
"step": 7,
"thought": "Let me rerun the reproduction script to verify the fix.",
"action": "cd /testbed && python reproduce.py",
"observation": " values\n2023-01-01 00:00:00 -0.708777\n2023-01-01
01:00:00 0.869770\n2023-01-01 02:00:00 1.113152\n2023-01-01 03:00:00 -0.041397\n2023-01-01
04:00:00 -0.402612"
},
{
"step": 8,
"thought": "The fix works. Let me submit the changes.",
"action": "submit",
"observation": "Task completed."
}
],
"info": {
"model": "claude-3-7-sonnet-20250219",
"temperature": 0.0
}
}transform_traj_xml():
1
2
3
4
5
6
7
8step 1 → assistant: thought + action → assemble together
step 2 → assistant: thought + action → assemble together
step 3 → assistant: thought + action → assemble together
step 4 → user: observation → use as content
step 5 → assistant: thought + action → assemble together
step 6 → assistant: thought + action → assemble together
step 7 → user: observation → use as content
step 8 → assistant: thought + submit → assemble togetherUnconverted .jsonl:
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{
"messages": [
{
"role": "system",
"content": "You are a helpful assistant that can interact with a computer to solve
tasks.\n\nYou have access to the following functions:\n\n---- BEGIN FUNCTION #1: bash
----\nDescription: Execute a bash command in the terminal.\n..."
},
{
"role": "user",
"content": "I've uploaded a python code repository in the directory /testbed. Consider the
following PR description:\n\n### Bug Description\n\nWhen using PyArrow-backed timestamp indexes
with .loc indexing..."
},
{
"role": "assistant",
"content": "I'll help you implement the necessary changes to fix the issue. Let me first
explore the repository structure.\n\n<function=bash>\n<parameter=command>find /testbed -type f
-name '*.py' | grep -v __pycache__ | grep -v test_ | head -20</parameter>\n</function>"
},
{
"role": "user",
"content": "OBSERVATION:\n/testbed/pandas/core/indexes/base.py\n/testbed/pandas/core/indexe
s/datetimes.py\n/testbed/pandas/core/indexes/datetimelike.py\n..."
},
{
"role": "assistant",
"content": "The PR description mentions the error occurs in base.py around line 6039. Let
me look at that specific code.\n\n<function=bash>\n<parameter=command>cat -n
/testbed/pandas/core/indexes/base.py | sed -n '6070,6090p'</parameter>\n</function>"
},
{
"role": "user",
"content": "OBSERVATION:\n6070 if keyarr.dtype.kind in \"mM\":\n6071 if
isinstance(key, list) or (\n6072 isinstance(key, type(self))\n6073 and
key.freq is None\n6074 ):\n6075 keyarr = keyarr._with_freq(None)"
},
{
"role": "assistant",
"content": "I see the issue. The code accesses `key.freq` but PyArrow-backed Index objects
don't have a `freq` attribute. Let me create a reproduction script
first.\n\n<function=bash>\n<parameter=command>cat > /testbed/reproduce.py << 'EOF'\nimport numpy
as np\nimport pandas as pd\n\nt = pd.date_range('2023-01-01', '2023-01-04', freq='1h')\nx =
np.random.randn(len(t))\ndf = pd.DataFrame(x, index=t,
columns=['values'])\ndf.to_parquet('frame.parquet')\ndf2 = pd.read_parquet('frame.parquet',
dtype_backend='pyarrow')\nprint(df2.loc[df2.index[:-5]].head())\nEOF</parameter>\n</function>"
},
{
"role": "user",
"content": "OBSERVATION:\nFile created successfully."
},
{
"role": "assistant",
"content": "Now let me run the reproduction script to confirm the
error.\n\n<function=bash>\n<parameter=command>cd /testbed && python
reproduce.py</parameter>\n</function>"
},
{
"role": "user",
"content": "OBSERVATION:\nAttributeError: 'Index' object has no attribute 'freq'"
},
{
"role": "assistant",
"content": "Confirmed. Now I'll fix the issue. I need to add a hasattr check before
accessing `key.freq`.\n\n<function=bash>\n<parameter=command>sed -i 's/and key.freq is None/and
(not hasattr(key, \"freq\") or key.freq is None)/'
/testbed/pandas/core/indexes/base.py</parameter>\n</function>"
},
{
"role": "user",
"content": "OBSERVATION:\nCommand executed successfully."
},
{
"role": "assistant",
"content": "I also need to handle the `_with_freq` call which doesn't exist on
PyArrow-backed Index objects.\n\n<function=bash>\n<parameter=command>sed -i '/keyarr =
keyarr._with_freq(None)/i\\ if hasattr(keyarr, \"_with_freq\"):'
/testbed/pandas/core/indexes/base.py</parameter>\n</function>"
},
{
"role": "user",
"content": "OBSERVATION:\nCommand executed successfully."
},
{
"role": "assistant",
"content": "Let me rerun the reproduction script to verify the
fix.\n\n<function=bash>\n<parameter=command>cd /testbed && python
reproduce.py</parameter>\n</function>"
},
{
"role": "user",
"content": "OBSERVATION:\n values\n2023-01-01 00:00:00
-0.708777\n2023-01-01 01:00:00 0.869770\n2023-01-01 02:00:00 1.113152\n2023-01-01 03:00:00
-0.041397\n2023-01-01 04:00:00 -0.402612"
},
{
"role": "assistant",
"content": "The fix works. Let me submit the changes.\n\n<function=submit>\n</function>"
}
],
"resolved": true,
"instance_id": "pandas-dev__pandas.95280573.pr_53652"
}
3.7 Full Tuning
train/run/ft_torchtune.py
configs/train/full_ft_qwen_32b.yml
1 | modal run swesmith/train/run/ft_torchtune.py \ |
1 |
|
Train config (full_ft_qwen_32b.yml) :
1 | model: |
| message # | role | content | Calculate Loss? |
|---|---|---|---|
| system user |
“You are a helpful assistant…” “I’ve uploaded a python code repository…” |
||
| 1 | assistant | “I’ll help you…<function=bash>…” | ✅ |
| 2 | user | “OBSERVATION:/testbed/pandas/…” | |
| 3 | assistant | “The PR description mentions…<function=bash>” | ✅ |
| 4 | user | “OBSERVATION: if keyarr…” | |
| 5 | assistant | “I see the issue…Let me create a script… | ✅ |
| 6 | user | “OBSERVATION:created successfully.” | |
| 7 | assistant | “Now let me run the script… | ✅ |
| 8 | user | “OBSERVATION:: ’Inde… | |
| 9 | assistant | “Confirmed. Now I’ll fix… | ✅ |
| 10 | user | “OBSERVATION:executed | |
| 11 | assistant | “Let me rerun…< | ✅ |
| 12 | user | “OBSERVATION:values…” | |
| 13 | assistant | “The fix works. Let me submit.<function=submit>” | ✅ |
e.g.
1 | assistant: "I see the issue. Let me create a script. |
1 | Model Input: "...OBSERVATION:\nFile created.\n I see the issue. Let me create" |
…