# How the file_patch Tool in GenericAgent Modifies Files Safely with Unique Content Matching

> Learn how GenericAgent's file_patch tool safely modifies files using unique content matching. Prevent accidental overwrites with exact text verification for secure updates.

- Repository: [LJQ/GenericAgent](https://github.com/lsdefine/GenericAgent)
- Tags: how-to-guide
- Published: 2026-04-16

---

**The `file_patch` tool in GenericAgent enforces safe file modifications by requiring an exact, unique text match before performing replacements, eliminating risks of accidental overwrites or ambiguous changes.**

The `file_patch` tool is a critical utility within the **GenericAgent** repository (`lsdefine/GenericAgent`) that enables autonomous agents to edit files programmatically without corrupting code or configuration. Unlike naive find-and-replace operations that might modify multiple unintended locations, this implementation guarantees **unique content matching** by validating that the target text appears exactly once before proceeding.

## How Unique Content Matching Protects Your Files

The safety model relies on a strict validation workflow implemented in [`ga.py`](https://github.com/lsdefine/GenericAgent/blob/main/ga.py) (lines 200-221). The function refuses to modify any file unless it can identify a single, unambiguous location for the replacement.

### Path Resolution and Validation

Before attempting any modification, the tool performs defensive checks:

1. **Canonical path resolution**: Converts relative paths to absolute using `path = str(Path(path).resolve())`, preventing directory traversal attacks
2. **Existence verification**: Returns an error with status `"文件不存在"` if the target file is missing, avoiding accidental file creation
3. **Empty pattern prevention**: Validates that `old_content` is not empty, preventing patterns that could match the entire file

### The Counting Mechanism

The core safety feature uses Python's `count()` method to analyze the target file's contents:

```python
count = full_text.count(old_content)

```

This simple operation enables three distinct safety gates:

- **Zero matches**: Returns `"未找到匹配的旧文本块"` (matching old text block not found), prompting the user to verify current content via `file_read` first
- **Multiple matches**: Returns `"找到 {count} 处匹配，无法确定唯一位置"` (found {count} matches, cannot determine unique location), preventing changes to scattered identical snippets
- **Unique match**: Only proceeds when `count == 1`, guaranteeing the replacement affects exactly the intended location

### Strict Match Validation

Once a unique match is confirmed, the tool performs the replacement using `full_text.replace(old_content, new_content)` and writes the result back atomically with UTF-8 encoding. This approach ensures **exact substring matching** rather than regex patterns, eliminating risks of special character interpretation errors.

## Implementation Details in ga.py

According to the GenericAgent source code, the `file_patch` function resides in [[`ga.py`](https://github.com/lsdefine/GenericAgent/blob/main/ga.py)](https://github.com/lsdefine/GenericAgent/blob/main/ga.py#L200-L221) and implements a nine-step safety workflow:

| Step | Code Action | Safety Purpose |
|------|-------------|----------------|
| Resolve path | `Path(path).resolve()` | Prevents directory traversal |
| Check existence | `os.path.exists(path)` | Fails early on missing files |
| Read content | `open(path, 'r', encoding='utf-8')` | Enables accurate substring analysis |
| Validate input | `if not old_content` check | Blocks empty replacement patterns |
| Count occurrences | `full_text.count(old_content)` | Determines match uniqueness |
| Handle zero matches | `if count == 0` | Prevents silent failures |
| Handle multiple matches | `if count > 1` | Eliminates ambiguous modifications |
| Perform replacement | `full_text.replace(...)` | Swaps only the intended block |
| Atomic write | `open(path, 'w', ...)` | Commits changes in single operation |

The dispatcher method `do_file_patch` (lines 370-384) handles argument extraction and invokes this utility, ensuring the agent receives structured feedback via JSON responses containing `"status"` and `"msg"` fields.

## Practical Usage Examples

Here are three scenarios demonstrating how the unique matching policy protects your files:

### Example 1: Successful Replacement

When the old content exists exactly once, the modification succeeds:

```python
from ga import file_patch

result = file_patch(
    path="config/settings.py",
    old_content="DEBUG = False",
    new_content="DEBUG = True"
)
print(result)

# → {'status': 'success', 'msg': '文件局部修改成功'}

```

### Example 2: Missing Content Protection

If the target text does not exist, the tool prevents modifications:

```python
result = file_patch(
    path="README.md",
    old_content="Non-existent marker",
    new_content="New content"
)
print(result)

# → {'status': 'error', 'msg': '未找到匹配的旧文本块，建议：先用 file_read 确认当前内容...'}

```

### Example 3: Ambiguous Match Prevention

When identical content appears multiple times, the tool refuses to guess:

```python

# Suppose script.sh contains "echo Hello" in two locations

result = file_patch(
    path="script.sh",
    old_content="echo Hello",
    new_content="echo Hi"
)
print(result)

# → {'status': 'error', 'msg': '找到 2 处匹配，无法确定唯一位置。请提供更长、更具体的旧文本块...'}

```

## Integration with the Agent Workflow

The `file_patch` tool integrates into the GenericAgent architecture through the `do_file_patch` dispatcher method (lines 370-380). When an agent needs to modify files safely, the workflow typically follows this pattern:

1. The agent calls `do_file_patch` with `path`, `old_content`, and `new_content` arguments
2. The dispatcher validates arguments and invokes `file_patch`
3. The function returns a JSON result with either `"success"` status or detailed error information
4. The agent surfaces this feedback to the user or higher-level logic, potentially using `file_read` (lines 231-259) to verify current content before retrying

This design ensures that **autonomous agents** cannot accidentally destroy files through ambiguous replacements, maintaining file integrity even during complex multi-step operations.

## Summary

- **Unique content matching** requires `old_content` to appear exactly once in the target file, preventing ambiguous modifications
- **Path canonicalization** via `Path.resolve()` eliminates directory traversal vulnerabilities before file access
- **Atomic validation** occurs before any writes, with specific error messages for zero matches, multiple matches, and missing files
- **UTF-8 encoding** ensures consistent text handling across different platforms and file types
- **JSON feedback** provides agents with structured status reporting for downstream decision-making

## Frequently Asked Questions

### What happens if the old_content appears multiple times in the file?

The `file_patch` tool returns an error status with the message `"找到 {count} 处匹配，无法确定唯一位置"` (found {count} matches, cannot determine unique location). This prevents the agent from accidentally modifying unintended sections of code or configuration that happen to contain identical text blocks.

### Can file_patch create new files if the path doesn't exist?

No. According to the implementation in [`ga.py`](https://github.com/lsdefine/GenericAgent/blob/main/ga.py) lines 200-221, the function explicitly checks `os.path.exists(path)` and returns `{"status":"error","msg":"文件不存在"}` if the file is missing. This early validation prevents accidental file creation and ensures the agent only modifies existing, verified files.

### How should I prepare the old_content argument to ensure successful matching?

Provide the longest unique snippet possible that identifies the specific location you want to modify. Since the tool performs exact substring matching using Python's `count()` method, including surrounding context (such as adjacent lines or unique whitespace) helps distinguish the target location from similar text elsewhere in the file. If unsure, use the `file_read` function first to verify the exact current content.

### Is file_patch vulnerable to regex injection or special character interpretation?

No. The implementation uses simple string operations (`count()` and `replace()`) rather than regular expressions. This means special characters like `.`, `*`, or `?` are treated as literal text, eliminating regex injection risks and ensuring predictable behavior when patching code containing special syntax.