diff options
| author | Vineet Kumar <git@vineetk.net> | 2026-05-25 23:46:24 -0400 |
|---|---|---|
| committer | Vineet Kumar <git@vineetk.net> | 2026-05-25 23:46:24 -0400 |
| commit | 62336cfba249c9bdd781d0789cc041f02f2aef0b (patch) | |
| tree | 5fa29458bce4d770f3cf255b2f9e87f181fc7eb9 | |
| parent | b4464b16c87f3b4a39584aa5faf66f2f9fee8be2 (diff) | |
final tool, edit_file, added
this took way too long.
| -rw-r--r-- | llm-tools.el | 144 |
1 files changed, 143 insertions, 1 deletions
diff --git a/llm-tools.el b/llm-tools.el index 56aeddd..efb8865 100644 --- a/llm-tools.el +++ b/llm-tools.el | |||
| @@ -91,7 +91,149 @@ final file.")) | |||
| 91 | :confirm t | 91 | :confirm t |
| 92 | :include t) | 92 | :include t) |
| 93 | 93 | ||
| 94 | ;; TODO edit_file (hashline + patch apply) | 94 | ;; edit_file (hl-edit) |
| 95 | (gptel-make-tool | ||
| 96 | :name "edit_file" | ||
| 97 | :function #'llm-tools--hl-edit | ||
| 98 | :description "\ | ||
| 99 | Edit an existing file surgically using the hashline patch | ||
| 100 | format. Call `read_file` first to obtain current content and valid | ||
| 101 | line anchors. Use `write_file` instead for creating new files or | ||
| 102 | completely replacing content. Returns a success message if the patch | ||
| 103 | applied, or an error string describing what went wrong (structural | ||
| 104 | issues or stale anchors)." | ||
| 105 | :args '((:name "patch" | ||
| 106 | :type string | ||
| 107 | :description "\ | ||
| 108 | A hashline patch string containing one or more file sections. Each | ||
| 109 | section begins with `@@ PATH` on its own line, followed by operations | ||
| 110 | that reference lines by their anchor (line number + 2-character hash, | ||
| 111 | e.g. `5ff`). Copy anchors verbatim from `read_file` output; never | ||
| 112 | fabricate or modify them. | ||
| 113 | |||
| 114 | CRITICAL: This is NOT a unified diff. Do NOT use `---`, `+++`, `@@ -1,3 | ||
| 115 | +1,4 @@`, `-old`, `+new`, or any unified diff syntax. The header is | ||
| 116 | `@@ PATH`; operations use `<`, `+`, `-`, `=`. This format is purely | ||
| 117 | textual -- the tool has NO awareness of language, indentation, | ||
| 118 | brackets, fences, or table widths. You must emit valid syntax in | ||
| 119 | replacements and insertions. | ||
| 120 | |||
| 121 | Operations: | ||
| 122 | + ANCHOR Insert lines AFTER the anchored line (or `EOF` to append) | ||
| 123 | < ANCHOR Insert lines BEFORE the anchored line (or `BOF` to prepend) | ||
| 124 | - A..B Delete the inclusive line range A through B | ||
| 125 | = A..B Replace the inclusive range A through B with payload lines | ||
| 126 | |||
| 127 | Payload lines follow the operation line and must start with `~` | ||
| 128 | immediately followed by content -- no space after `~`. Every character | ||
| 129 | after `~` is verbatim file content. Op lines carry no content: | ||
| 130 | |||
| 131 | WRONG: + 5pg some code | ||
| 132 | RIGHT: | ||
| 133 | + 5pg | ||
| 134 | ~some code | ||
| 135 | |||
| 136 | One operation can have many payload lines. To insert N consecutive | ||
| 137 | lines, write ONE op followed by N `~` lines: | ||
| 138 | |||
| 139 | WRONG (one op per line, with fabricated anchors): | ||
| 140 | + 5pg | ||
| 141 | ~first new line | ||
| 142 | + 6xx <- FABRICATED | ||
| 143 | ~second new line | ||
| 144 | |||
| 145 | RIGHT (one op, many payload lines): | ||
| 146 | + 5pg | ||
| 147 | ~first new line | ||
| 148 | ~second new line | ||
| 149 | |||
| 150 | Rules: | ||
| 151 | - Payload is ONLY what is NEW relative to your range. Do not repeat | ||
| 152 | existing lines or duplicate nearby content. | ||
| 153 | - Anchors reference the file as last read via `read_file`. Do not shift | ||
| 154 | line numbers for prior operations in the same patch. | ||
| 155 | - Prefer narrow operations (`+`, `-`) over wide replacements (`=`). | ||
| 156 | Two narrow ops beat one wide `=`. | ||
| 157 | - When editing a multiline construct, widen to the whole construct | ||
| 158 | rather than bisecting it. | ||
| 159 | - `= A..B` deletes the range; payload is what is written. Before using | ||
| 160 | `=`, mentally delete A..B. If that splits an unclosed brace or | ||
| 161 | orphans a closer, you are bisecting a construct -- widen the range. | ||
| 162 | - Every payload line must start with `~`. Raw content without `~` is | ||
| 163 | invalid. | ||
| 164 | - Comments (lines starting with `#`) and blank lines are ignored. | ||
| 165 | |||
| 166 | Examples: | ||
| 167 | |||
| 168 | Replace a single line: | ||
| 169 | @@ greeting.el | ||
| 170 | = 2in..2in | ||
| 171 | ~(defconst greeting-title \"Mrs\") | ||
| 172 | |||
| 173 | Replace a multiline block (widen to self-contained boundary): | ||
| 174 | @@ greeting.el | ||
| 175 | = 4ei..7be | ||
| 176 | ~ (concat | ||
| 177 | ~ greeting-title | ||
| 178 | ~ (or (string-trim name) \"guest\")) | ||
| 179 | ~ ) | ||
| 180 | |||
| 181 | Insert after: | ||
| 182 | @@ greeting.el | ||
| 183 | + 4ei | ||
| 184 | ~ greeting-title | ||
| 185 | |||
| 186 | Insert before: | ||
| 187 | @@ greeting.el | ||
| 188 | < 5ff | ||
| 189 | ~ greeting-title | ||
| 190 | |||
| 191 | Append to end of file: | ||
| 192 | @@ greeting.el | ||
| 193 | + EOF | ||
| 194 | ~(provide 'greeting) | ||
| 195 | |||
| 196 | Prepend to beginning of file: | ||
| 197 | @@ greeting.el | ||
| 198 | < BOF | ||
| 199 | ~;; greeting.el -- utilities | ||
| 200 | |||
| 201 | Delete a single line: | ||
| 202 | @@ greeting.el | ||
| 203 | - 5ff..5ff | ||
| 204 | |||
| 205 | Blank a line (replace with empty): | ||
| 206 | @@ greeting.el | ||
| 207 | = 5ff..5ff | ||
| 208 | |||
| 209 | Multiple operations in one section: | ||
| 210 | @@ greeting.el | ||
| 211 | + 1vx | ||
| 212 | ~(defconst DEBUG nil) | ||
| 213 | - 5ff..5ff | ||
| 214 | |||
| 215 | Multiple files in one patch: | ||
| 216 | @@ a.el | ||
| 217 | + 1vx | ||
| 218 | ~(require 'b) | ||
| 219 | @@ b.el | ||
| 220 | = 2in..2in | ||
| 221 | ~(defconst VALUE 42) | ||
| 222 | |||
| 223 | Insert multiple lines with one op: | ||
| 224 | @@ greeting.el | ||
| 225 | + 1vx | ||
| 226 | ~(defconst GREETING \"Hello\") | ||
| 227 | ~(defconst FAREWELL \"Goodbye\") | ||
| 228 | |||
| 229 | Replace one line with multiple lines: | ||
| 230 | @@ greeting.el | ||
| 231 | = 1vx..1vx | ||
| 232 | ~(defconst TITLE \"Dr\") | ||
| 233 | ~(defconst SUBTITLE \"Assistant\")")) | ||
| 234 | :async nil | ||
| 235 | :confirm t | ||
| 236 | :include t) | ||
| 95 | 237 | ||
| 96 | ;; bash (make-process, taken from gptel-agent) | 238 | ;; bash (make-process, taken from gptel-agent) |
| 97 | (defun llm-tools--execute-bash (callback command) | 239 | (defun llm-tools--execute-bash (callback command) |
