udiffx
Parse and apply an AI-optimized “file changes” envelope that carries multiple file operations in a single block, using unified diff patches for updates.
This crate is designed for LLM output that needs to be machine-parsable and efficient for large files with small edits.
Concept, FILE_CHANGES
A response contains one root container:
<FILE_CHANGES> ... </FILE_CHANGES>
Inside it, you can mix multiple directives:
<FILE_NEW file_path="..."> ... </FILE_NEW><FILE_PATCH file_path="..."> ... </FILE_PATCH>(unified diff content)<FILE_RENAME from_path="..." to_path="..." /><FILE_DELETE file_path="..." />
Notes:
- Tags are XML-like but not intended to be strictly XML-compliant.
- The parser is tag-based. It extracts only the above tags, and content does not need XML escaping.
- Self-closing tags like
<FILE_DELETE ... />are supported.
API overview
The crate exposes two main operations:
- Extract: parse the first
<FILE_CHANGES>block from a string. - Apply: execute the extracted directives against a base directory.
Key public types:
FileChanges, an iterable list of directives.FileDirective, one directive (new, patch, rename, delete, fail).ApplyChangesStatus, per-directive success and error reporting.Error/Result<T>, the crate error type and alias.
Gathering file context
Use load_files_context to gather files matching globs and format them for an LLM context.
use ;
Output format:
... content ...
... content ...
Extracting changes from text
Use extract_file_changes to parse a model response or any input string.
use ;
extract_content parameter:
extract_content = falseparses tags and returnsextruded = None.extract_content = truealso returns the input with the extracted<FILE_CHANGES>block removed asSome(String).
Applying changes to disk
Use apply_file_changes to execute directives relative to a base directory.
- All file paths are treated as relative to
base_dir. - The crate performs basic path safety checks to ensure operations stay within
base_dir. - Patch application uses
diffy(unified diff parsing and application).
use SPath;
use ;
Directive behavior
FILE_NEW: creates or overwrites a file. Parent directories are created.FILE_PATCH: reads the target file, applies a unified diff, and writes the result back.- When a patch contains multiple hunks, each hunk is applied independently. If some hunks fail, the successfully applied hunks are still written. The directive is considered successful if at least one hunk applies. Per-hunk failure details are available in
DirectiveStatus.error_hunks.
- When a patch contains multiple hunks, each hunk is applied independently. If some hunks fail, the successfully applied hunks are still written. The directive is considered successful if at least one hunk applies. Per-hunk failure details are available in
FILE_RENAME: renames or movesfrom_pathtoto_path.FILE_DELETE: removes a file or directory recursively.
If extraction fails for a directive (unknown tag, missing attribute, etc.), the directive is represented as:
FileDirective::Fail { kind, file_path, error_msg }
When applying, Fail directives always yield an error for that directive and are reported via ApplyChangesInfo.
Format tips for LLM output
- Always emit exactly one
<FILE_CHANGES>block when you intend to apply changes. - Prefer
FILE_PATCHfor small edits to large files. - Use self-closing tags for rename and delete when convenient:
<FILE_RENAME from_path="a" to_path="b" /><FILE_DELETE file_path="path" />
System prompt (optional)
The crate includes the recommended system instructions for LLMs to ensure they output the correct format. This is available via the prompt feature.
[]
= { = "0.1", = ["prompt"] }
use prompt;
let instructions = prompt;
// Pass this to your LLM system message.
License
MIT OR Apache-2.0