Skip to content

Commit da3cfed

Browse files
committed
increase max_steps in config and enhance system prompt; implement parallel execution for SWE-bench instances with improved logging and patch saving
1 parent 86a842a commit da3cfed

2 files changed

Lines changed: 117 additions & 37 deletions

File tree

config.example.yaml

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,71 @@
11
agent:
2-
max_steps: 30
2+
max_steps: 80
33
log_dir: logs/
44
enable_memory: false
55
system_prompt: |
6-
You are a helpful assistant that can interact multiple times with a computer shell to solve programming tasks.
6+
You are a software engineer that interacts multiple times with a computer shell to solve programming tasks.
77
You operate in a REPL (Read-Eval-Print Loop) environment where you must issue exactly ONE shell tool call at a time.
88
IMPORTANT: To execute commands you MUST call the shell tool — do NOT just write bash code blocks in your response text, as those are not executed.
99
After each tool call, wait for the result before deciding the next step.
1010
Please briefly explain your reasoning before each tool call.
11+
12+
## Recommended Workflow Phases (follow in order)
13+
You have a limited number of steps. Spend them wisely across these phases:
14+
1. **Explore** (≤12 steps): Understand the codebase and locate the relevant code.
15+
2. **Reproduce** (≤5 steps): Build the project if needed and create a minimal reproduction app.
16+
3. **Fix** (≤8 steps): Edit the source code to resolve the issue.
17+
4. **Verify** (≤10 steps): Confirm the fix works using ask_web_agent and test edge cases.
18+
If you are still exploring after 15 steps, stop and move to reproduction immediately. Do NOT spend too many steps exploring!
19+
20+
## Important Boundaries
21+
- DO NOT MODIFY: Tests, configuration files
22+
- Only EXECUTE ONE command at a time, and wait for the result before issuing your next command.
23+
24+
## Shell Usage Rules (CRITICAL)
25+
- NEVER wrap commands in `bash -lc '...'` or `bash -c '...'`. You are already inside a bash session.
26+
- When using grep/find, always search within /testbed (use `.` or `/testbed`). NEVER search from `..` or `/` as it will time out.
27+
- Do NOT run blocking commands that take more than 60 seconds. Start servers/processes in the background (append `&`) and return immediately.
28+
29+
## Efficient Code Reading
30+
- Use `grep -n "pattern" -r src/ --include="*.js"` to find relevant lines first.
31+
- Then read only the relevant section with `sed -n 'START,ENDp' file`. Keep ranges to ~100 lines maximum — this is a hard limit, not a suggestion.
32+
- Do NOT use `cat` on source files. Do NOT use sed ranges larger than 100 lines. Outputs too long will be summarized and you will lose detail.
33+
- Never search for something you already found — track what you know.
34+
35+
## Editing Source Code
36+
- Do NOT use `applypatch`, `patch`, or any tool not available in a standard bash environment.
37+
- After each edit, verify the change took effect with `grep -n` or a small `sed -n` read.
38+
- If an edit fails twice in a row, switch to a different approach immediately.
39+
40+
### Edit files with sed:
41+
```bash
42+
# Replace all occurrences
43+
sed -i 's/old_string/new_string/g' filename
44+
45+
# Replace only first occurrence
46+
sed -i 's/old_string/new_string/' filename
47+
48+
# Replace first occurrence on line 1
49+
sed -i '1s/old_string/new_string/' filename
50+
51+
# Replace all occurrences in lines 1-10
52+
sed -i '1,10s/old_string/new_string/g' filename
53+
54+
## Using ask_web_agent
55+
- Call ask_web_agent at most 1-2 times per verification cycle.
56+
- Each call should ask a specific, different question. Do NOT repeat the same question with different wording.
57+
- If the result is ambiguous, act on your best interpretation rather than asking again.
58+
- Once ask_web_agent confirms the fix is correct, stop verifying and conclude.
59+
60+
## Tool Output
61+
- If a tool result starts with "[Output was ... chars — summarized below]", the raw output was too long and has been automatically summarized for you. Treat the summary as the actual result and continue accordingly.
62+
1163
LLM:
12-
provider: openai # "openai" | "anthropic"
64+
provider: openai
1365
model: gpt-5
14-
api_key: "" # or set via LLM_API_KEY env var
15-
base_url: "" # leave empty for default endpoint
16-
temperature: null # null = use provider default; e.g. 0.0 for deterministic output
66+
api_key: ""
67+
base_url: ""
68+
temperature: 0.5
1769
Memory:
1870
user_id: default
1971
base_url: http://localhost:1995/api/v1

run_swebench_multimodal.py

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import json
88
import logging
99
import random
10+
import threading
11+
from concurrent.futures import ThreadPoolExecutor, as_completed
1012
from pathlib import Path
1113

1214
from datasets import load_dataset
@@ -159,6 +161,32 @@ def _build_web_agent(cfg: WebAgentConfig, instance_id: str) -> WebAgent:
159161
)
160162

161163

164+
def _run_instance(cfg: Config, instance: dict, port: int, predictions_file, file_lock: threading.Lock) -> None:
165+
"""Run a single SWE-bench instance and write its prediction."""
166+
instance_id = instance["instance_id"]
167+
logger.info("=== %s starting (port %d) ===", instance_id, port)
168+
169+
web_agent = _build_web_agent(cfg.web_agent, instance_id)
170+
agent = _build_agent(cfg.agent, instance, port, web_agent)
171+
agent.run(_build_task_with_images(instance, port, cfg.agent.max_steps))
172+
173+
logger.info("=== %s finished, saving results ===", instance_id)
174+
shell = next((t for t in agent.tool_list if isinstance(t, ShellTool)), None)
175+
if shell is not None:
176+
patch = shell.get_patch() or ""
177+
record = json.dumps(
178+
{
179+
"instance_id": instance_id,
180+
"model_name_or_path": "Argus",
181+
"model_patch": patch,
182+
}
183+
)
184+
with file_lock:
185+
predictions_file.write(record + "\n")
186+
predictions_file.flush()
187+
logger.info("Patch written to predictions for %s", instance_id)
188+
189+
162190
def main() -> None:
163191
parser = argparse.ArgumentParser(description="Run Argus on SWE-bench Multimodal")
164192
parser.add_argument("--config", default="config.yaml", help="Path to config.yaml")
@@ -169,6 +197,12 @@ def main() -> None:
169197
metavar="ID",
170198
help="Run only the specified instance IDs (runs all if omitted)",
171199
)
200+
parser.add_argument(
201+
"--workers",
202+
type=int,
203+
default=1,
204+
help="Number of parallel workers (default: 1)",
205+
)
172206
args = parser.parse_args()
173207

174208
cfg = Config.from_yaml(Path(__file__).parent / args.config)
@@ -178,41 +212,35 @@ def main() -> None:
178212
keep = set(args.instance_ids)
179213
dataset = dataset.filter(lambda x: x["instance_id"] in keep)
180214

181-
logger.info("Running %d instances", len(dataset))
215+
logger.info("Running %d instances with %d worker(s)", len(dataset), args.workers)
182216

183217
predictions_path = Path("predictions.jsonl")
218+
file_lock = threading.Lock()
219+
220+
# Assign a unique port to each instance up front (thread-safe: done before threads start)
221+
used_ports: set[int] = set()
222+
instance_ports: list[int] = []
223+
for _ in dataset:
224+
port = random.randint(10000, 65535)
225+
while port in used_ports:
226+
port = random.randint(10000, 65535)
227+
used_ports.add(port)
228+
instance_ports.append(port)
184229

185-
used_port = []
186230
with predictions_path.open("a", encoding="utf-8") as predictions_file:
187-
for instance in dataset:
188-
instance_id = instance["instance_id"]
189-
logger.info("=== %s ===", instance_id)
190-
191-
# Find an available port for this instance's server to run on.
192-
port = random.randint(10000, 65535)
193-
while port in used_port:
194-
port = random.randint(10000, 65535)
195-
used_port.append(port)
196-
197-
web_agent = _build_web_agent(cfg.web_agent, instance_id)
198-
agent = _build_agent(cfg.agent, instance, port, web_agent)
199-
agent.run(_build_task_with_images(instance, port, cfg.agent.max_steps))
200-
201-
# Generate and save git patch after agent finishes
202-
logger.info("=== %s finished, saving results ===", instance_id)
203-
shell = next((t for t in agent.tool_list if isinstance(t, ShellTool)), None)
204-
if shell is not None:
205-
patch = shell.get_patch() or ""
206-
record = json.dumps(
207-
{
208-
"instance_id": instance_id,
209-
"model_name_or_path": "Argus",
210-
"model_patch": patch,
211-
}
212-
)
213-
predictions_file.write(record + "\n")
214-
predictions_file.flush()
215-
logger.info("Patch written to predictions for %s", instance_id)
231+
with ThreadPoolExecutor(max_workers=args.workers) as executor:
232+
futures = {
233+
executor.submit(_run_instance, cfg, instance, port, predictions_file, file_lock): instance[
234+
"instance_id"
235+
]
236+
for instance, port in zip(dataset, instance_ports)
237+
}
238+
for future in as_completed(futures):
239+
instance_id = futures[future]
240+
try:
241+
future.result()
242+
except Exception:
243+
logger.exception("Instance %s failed", instance_id)
216244

217245

218246
if __name__ == "__main__":

0 commit comments

Comments
 (0)