Generate and verify a patch for a crash. Returns (diff_bytes, verdict, agent_result). diff_bytes is None if the agent never emitted a readable . verdict is None if no diff was produced. Writes patch.diff + patch_result.json to out_dir on every iteration (last one wins).
(
crash: CrashArtifact,
target: TargetConfig,
model: str,
out_dir: Path,
report_text: str | None = None,
max_iterations: int = DEFAULT_MAX_ITERATIONS,
max_turns: int = PATCH_MAX_TURNS,
container_name: str = "patch_target",
run_reattack: bool = True,
run_style: bool = False,
agent_env: dict[str, str] | None = None,
transcript_path: str | None = None,
progress_prefix: str | None = None,
system_prompt: str | None = None,
)
| 28 | |
| 29 | |
| 30 | async def run_patch( |
| 31 | crash: CrashArtifact, |
| 32 | target: TargetConfig, |
| 33 | model: str, |
| 34 | out_dir: Path, |
| 35 | report_text: str | None = None, |
| 36 | max_iterations: int = DEFAULT_MAX_ITERATIONS, |
| 37 | max_turns: int = PATCH_MAX_TURNS, |
| 38 | container_name: str = "patch_target", |
| 39 | run_reattack: bool = True, |
| 40 | run_style: bool = False, |
| 41 | agent_env: dict[str, str] | None = None, |
| 42 | transcript_path: str | None = None, |
| 43 | progress_prefix: str | None = None, |
| 44 | system_prompt: str | None = None, |
| 45 | ) -> tuple[bytes | None, PatchVerdict | None, AgentResult]: |
| 46 | """Generate and verify a patch for a crash. |
| 47 | |
| 48 | Returns (diff_bytes, verdict, agent_result). diff_bytes is None if the |
| 49 | agent never emitted a readable <patch_path>. verdict is None if no diff |
| 50 | was produced. Writes patch.diff + patch_result.json to out_dir on every |
| 51 | iteration (last one wins). |
| 52 | """ |
| 53 | if not target.build_command: |
| 54 | raise ValueError(f"target {target.name!r} has no build_command") |
| 55 | if crash.poc_path not in crash.reproduction_command: |
| 56 | raise ValueError( |
| 57 | f"poc_path {crash.poc_path!r} not in reproduction_command " |
| 58 | f"{crash.reproduction_command!r}" |
| 59 | ) |
| 60 | |
| 61 | out_dir = Path(out_dir) |
| 62 | out_dir.mkdir(parents=True, exist_ok=True) |
| 63 | |
| 64 | diff: bytes | None = None |
| 65 | verdict: PatchVerdict | None = None |
| 66 | result = AgentResult() |
| 67 | retry_evidence: tuple[str, str] | None = None |
| 68 | iterations = 0 |
| 69 | timings: dict[str, float] = {} |
| 70 | |
| 71 | with sandbox.agent_container( |
| 72 | target.image_tag, container_name, agent_env, |
| 73 | memory=target.memory_limit, shm_size=target.shm_size, |
| 74 | ) as container: |
| 75 | await asyncio.to_thread( |
| 76 | docker_ops.write_file, container, "/tmp/poc.bin", crash.poc_bytes |
| 77 | ) |
| 78 | adapted_cmd = crash.reproduction_command.replace(crash.poc_path, "/tmp/poc.bin") |
| 79 | # Ensure source_root is a git repo with a baseline commit so the |
| 80 | # agent's `git diff` is deterministic. Gitignore the built binary so |
| 81 | # the diff is source-only (otherwise the rebuilt binary lands in the |
| 82 | # diff and grade's `git apply` rejects it). |
| 83 | binary_rel = os.path.relpath(target.binary_path, target.source_root) |
| 84 | ignore = f"printf '%s\\n' '{binary_rel}' '*.o' >> .gitignore && " |
| 85 | await asyncio.to_thread( |
| 86 | docker_ops.exec_sh, |
| 87 | container, |