Supyagent
ToolsBuilt-in Tools

Patch Tool

Reference for the patch default tool: apply_patch with V4A context-anchored diffs for multi-file atomic changes.

Patch Tool

Script: powers/patch.py Dependencies: pydantic

Apply context-anchored diffs across multiple files in a single atomic operation. Inspired by the V4A diff format, the patch tool uses context lines to locate changes rather than fragile line numbers or exact string matching.


apply_patch

Apply a multi-file patch using context-anchored diffs. All operations are validated before any changes are written (atomic), so either the entire patch succeeds or nothing changes.

Input

FieldTypeDefaultDescription
patchstrrequiredMulti-file patch in V4A-style format (see format below)
dry_runboolfalseValidate the patch without applying changes
working_dirstr"."Base directory for resolving relative file paths

Output

FieldTypeDescription
okbooltrue if all operations succeeded
resultslistArray of per-file result objects
files_modifiedintNumber of files updated
files_addedintNumber of new files created
files_deletedintNumber of files removed
errorstrError message on failure

Each result object:

FieldTypeDescription
filestrFile path
operationstr"add", "update", or "delete"
okboolWhether this operation succeeded
errorstrError message if failed

Patch Format

The patch format supports three operations:

Add File

Create a new file with the given content. Each content line starts with +:

*** Add File: path/to/new_file.py
+#!/usr/bin/env python3
+"""New module."""
+
+def hello():
+    print("hello")

Update File

Modify an existing file using context-anchored hunks. The @@ line identifies where in the file to apply changes. Lines prefixed with - are removed, lines prefixed with + are added:

*** Update File: path/to/existing.py
@@ def main():
-    pass
+    print("hello")
+    return 0

Multiple hunks can be applied to the same file:

*** Update File: src/config.py
@@ DEBUG = False
-DEBUG = False
+DEBUG = True
@@ DEFAULT_PORT = 8080
-DEFAULT_PORT = 8080
+DEFAULT_PORT = 3000

Delete File

Remove an existing file:

*** Delete File: path/to/unwanted.py

Multi-File Example

A single patch can contain multiple file operations:

{
  "patch": "*** Add File: src/utils/helpers.py\n+\"\"\"Helper utilities.\"\"\"\n+\n+def clamp(value, min_val, max_val):\n+    return max(min_val, min(value, max_val))\n\n*** Update File: src/main.py\n@@ import os\n-import os\n+import os\n+from utils.helpers import clamp\n\n*** Delete File: src/old_helpers.py",
  "dry_run": false
}

Examples

// Add a new file
{"patch": "*** Add File: hello.py\n+print('hello')\n"}

// Update an existing file
{"patch": "*** Update File: main.py\n@@ def main():\n-    pass\n+    print('hello')\n"}

// Delete a file
{"patch": "*** Delete File: old_module.py"}

// Dry run (validate without applying)
{
  "patch": "*** Update File: config.py\n@@ PORT = 8080\n-PORT = 8080\n+PORT = 3000\n",
  "dry_run": true
}

How Context Matching Works

The @@ line specifies a context anchor -- a line that exists in the file. The patch tool:

  1. Searches the file for a line matching the context (exact match, or stripped whitespace match)
  2. Verifies that the - (remove) lines appear immediately after the context line
  3. Replaces the remove lines with the + (add) lines

If the context line is not found, or the remove lines don't match what's in the file, the entire patch fails (atomic behavior).

Atomicity

The patch tool operates in two phases:

  1. Validation phase: All operations are parsed and validated. For updates, the context anchors are located and remove lines are verified. No files are modified.
  2. Application phase: Only if all operations pass validation, changes are written to disk.

If any single operation fails validation, nothing is changed. This prevents partial updates that could leave the codebase in an inconsistent state.

Tips

  • Use dry_run: true to validate a patch before applying it
  • Context lines should be unique enough to identify the correct location in the file
  • The - lines in an Update hunk must exactly match the file content (whitespace-tolerant)
  • The patch tool is ideal for making coordinated changes across multiple files
  • Combine with read_file to inspect files before generating patches
  • When a hunk fails, the error message includes the context line that was not found, making it easy to diagnose