mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-02 23:31:34 +00:00
* fix(agents): stop apply_patch from silently overwriting existing files An "*** Add File:" hunk wrote its target unconditionally. When the path already existed, apply_patch replaced the entire file, returned Success, and listed the path under "added", so neither the model nor the UI got any signal that existing content had been destroyed. The "*** Move to:" destination of an update hunk had the same gap and reported the clobbered path as merely modified. The add and move-to branches now check the destination through the patch file ops before writing and fail closed when it exists. Routing the check through fileOps keeps it correct on all three backends (workspace-scoped fs-safe root, raw fs, sandbox bridge). The check runs per hunk in patch order, so deleting a path earlier in the same patch and recreating it still works. * fix(agents): make apply_patch destination creation atomic The previous guard checked that an add or move-to destination was absent and then wrote it. A competing writer could create the path in that gap, after which the write still replaced it, so the no-clobber guarantee did not hold under contention. Destination creation now goes through a single exclusive create-if-absent operation on every patch backend: Root.create for the workspace-scoped default, an O_EXCL write for the raw filesystem, and a new pinned create operation in the sandbox mutation helper that opens the target with O_CREAT|O_EXCL and reports a reserved exit code when it already exists. PatchFileOps drops its separate existence check. Resolving the host ops behind an early return removes the repeated workspaceOnly branch inside each operation and the optional-call dance that let a missing root silently skip a write. * fix(agents): complete atomic apply-patch creation * fix(agents): preserve raced create replacements * fix(agents): handle fs-safe patch collisions * fix(agents): publish sandbox creates atomically * test(agents): cover exclusive create provenance rollback * fix(agents): use typed exclusive-create signal --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
66 lines
2.2 KiB
Markdown
66 lines
2.2 KiB
Markdown
---
|
|
summary: "Apply multi-file patches with the apply_patch tool"
|
|
read_when:
|
|
- You need structured file edits across multiple files
|
|
- You want to document or debug patch-based edits
|
|
title: "apply_patch tool"
|
|
---
|
|
|
|
Apply file changes using a structured patch format. This is ideal for multi-file
|
|
or multi-hunk edits where a single `edit` call would be brittle.
|
|
|
|
The tool accepts a single `input` string that wraps one or more file operations:
|
|
|
|
```text
|
|
*** Begin Patch
|
|
*** Add File: path/to/file.txt
|
|
+line 1
|
|
+line 2
|
|
*** Update File: src/app.ts
|
|
@@ optional change context
|
|
-old line
|
|
+new line
|
|
*** Delete File: obsolete.txt
|
|
*** End Patch
|
|
```
|
|
|
|
## Parameters
|
|
|
|
- `input` (required): Full patch contents including `*** Begin Patch` and `*** End Patch`.
|
|
|
|
## Notes
|
|
|
|
- Patch paths support relative paths (from the workspace directory) and absolute paths.
|
|
- `tools.exec.applyPatch.workspaceOnly` defaults to `true` (workspace-contained). Set it to `false` only if you intentionally want `apply_patch` to write/delete outside the workspace directory.
|
|
- `*** Add File:` and a non-self `*** Move to:` require the destination path to be absent. To intentionally replace a path, delete it earlier in the same patch before adding or moving the replacement.
|
|
- Use `*** Move to:` within an `*** Update File:` hunk to rename files.
|
|
- `*** End of File` marks an EOF-only insert when needed.
|
|
- Enabled by default for every model. Set `tools.exec.applyPatch.enabled: false`
|
|
to disable it, or restrict it to specific models with
|
|
`tools.exec.applyPatch.allowModels` (accepts raw ids like `gpt-5.4` or full
|
|
ids like `openai/gpt-5.4`).
|
|
- Config lives under `tools.exec.applyPatch.*`.
|
|
|
|
## Example
|
|
|
|
```json
|
|
{
|
|
"tool": "apply_patch",
|
|
"input": "*** Begin Patch\n*** Update File: src/index.ts\n@@\n-const foo = 1\n+const foo = 2\n*** End Patch"
|
|
}
|
|
```
|
|
|
|
## Related
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Diffs" href="/tools/diffs" icon="code-compare">
|
|
Read-only diff viewer for change presentation.
|
|
</Card>
|
|
<Card title="Exec tool" href="/tools/exec" icon="terminal">
|
|
Shell command execution from the agent.
|
|
</Card>
|
|
<Card title="Code execution" href="/tools/code-execution" icon="square-code">
|
|
Sandboxed remote Python analysis with xAI.
|
|
</Card>
|
|
</CardGroup>
|