mirror of
https://github.com/Aider-AI/aider.git
synced 2025-05-28 16:25:00 +00:00
Switch from "edit block" to "search/replace block"
Succeeded in tricky task in the grep-ast codebase: - checkout ed714ffe58734 / tricky-search-and-replace-state - "read and parse .gitignore once, not each time we recurse `enumerate_files`" - was having a lot of trouble creating a head/updated block that matched the actual source code - new search/replace block does much better Benchmark had *best* try 1 result and *lowest* num_error_outputs ever seen on gpt-4-0613. Low num_error_outputs means it's less likely to elide/... code in the before block (original/search). ──────────── tmp.benchmarks/2023-10-25-22-03-19--search-and-replace-and-think ───────────── test-cases: 133 model: gpt-4 edit_format: diff commit_hash: c9c2ddb num_error_outputs: 6 num_user_asks: 0 num_exhausted_context_windows 0 test_timeouts: 2 50.4% correct after try 0 66.2% correct after try 1
This commit is contained in:
parent
aa18d0f946
commit
15d3a5d581
2 changed files with 31 additions and 33 deletions
|
@ -31,10 +31,10 @@ class EditBlockCoder(Coder):
|
|||
continue
|
||||
raise ValueError(f"""InvalidEditBlock: edit failed!
|
||||
|
||||
{path} does not contain the *exact sequence* of HEAD lines you specified.
|
||||
{path} does not contain the *exact chunk* of SEARCH lines you specified.
|
||||
Try again.
|
||||
DO NOT skip blank lines, comments, docstrings, etc!
|
||||
The HEAD block needs to be EXACTLY the same as the lines in {path} with nothing missing!
|
||||
The SEARCH block needs to be EXACTLY the same as the lines in {path} with nothing missing!
|
||||
|
||||
{path} does not contain these {len(original.splitlines())} exact lines in a row:
|
||||
```
|
||||
|
@ -122,7 +122,7 @@ def try_dotdotdots(whole, part, replace):
|
|||
replace_pieces = re.split(dots_re, replace)
|
||||
|
||||
if len(part_pieces) != len(replace_pieces):
|
||||
raise ValueError("Unpaired ... in edit block")
|
||||
raise ValueError("Unpaired ... in SEARCH/REPLACE block")
|
||||
|
||||
if len(part_pieces) == 1:
|
||||
# no dots in this edit block, just return None
|
||||
|
@ -132,7 +132,7 @@ def try_dotdotdots(whole, part, replace):
|
|||
all_dots_match = all(part_pieces[i] == replace_pieces[i] for i in range(1, len(part_pieces), 2))
|
||||
|
||||
if not all_dots_match:
|
||||
raise ValueError("Unmatched ... in edit block")
|
||||
raise ValueError("Unmatched ... in SEARCH/REPLACE block")
|
||||
|
||||
part_pieces = [part_pieces[i] for i in range(0, len(part_pieces), 2)]
|
||||
replace_pieces = [replace_pieces[i] for i in range(0, len(replace_pieces), 2)]
|
||||
|
@ -148,10 +148,10 @@ def try_dotdotdots(whole, part, replace):
|
|||
whole += replace
|
||||
continue
|
||||
|
||||
if whole.count(part) != 1:
|
||||
raise ValueError(
|
||||
"No perfect matching chunk in edit block with ... or part appears more than once"
|
||||
)
|
||||
if whole.count(part) == 0:
|
||||
raise ValueError
|
||||
if whole.count(part) > 1:
|
||||
raise ValueError
|
||||
|
||||
whole = whole.replace(part, replace, 1)
|
||||
|
||||
|
@ -301,9 +301,9 @@ def do_replace(fname, content, before_text, after_text, fence=None):
|
|||
return new_content
|
||||
|
||||
|
||||
HEAD = "<<<<<<< HEAD"
|
||||
HEAD = "<<<<<<< SEARCH"
|
||||
DIVIDER = "======="
|
||||
UPDATED = ">>>>>>> updated"
|
||||
UPDATED = ">>>>>>> REPLACE"
|
||||
|
||||
separators = "|".join([HEAD, DIVIDER, UPDATED])
|
||||
|
||||
|
@ -379,10 +379,10 @@ def find_original_update_blocks(content):
|
|||
raise ValueError(f"{processed}\n^^^ {err}")
|
||||
except IndexError:
|
||||
processed = "".join(processed)
|
||||
raise ValueError(f"{processed}\n^^^ Incomplete HEAD/updated block.")
|
||||
raise ValueError(f"{processed}\n^^^ Incomplete SEARCH/REPLACE block.")
|
||||
except Exception:
|
||||
processed = "".join(processed)
|
||||
raise ValueError(f"{processed}\n^^^ Error parsing HEAD/updated block.")
|
||||
raise ValueError(f"{processed}\n^^^ Error parsing SEARCH/REPLACE block.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -14,40 +14,38 @@ If the request is ambiguous, ask questions.
|
|||
Once you understand the request you MUST:
|
||||
1. List the files you need to modify. *NEVER* suggest changes to a *read-only* file. Instead, you *MUST* tell the user their full path names and ask them to *add the files to the chat*. End your reply and wait for their approval.
|
||||
2. Think step-by-step and explain the needed changes.
|
||||
3. Describe each change with an *edit block* per the example below.
|
||||
3. Describe each change with a *SEARCH/REPLACE block* per the example below.
|
||||
"""
|
||||
|
||||
system_reminder = """You MUST format EVERY code change with an *edit block* like this:
|
||||
system_reminder = """You MUST use a *SEARCH/REPLACE block* to modify the source file:
|
||||
|
||||
{fence[0]}python
|
||||
some/dir/example.py
|
||||
<<<<<<< HEAD
|
||||
# some comment
|
||||
# Func to multiply
|
||||
def mul(a,b)
|
||||
<<<<<<< SEARCH
|
||||
# Multiplication function
|
||||
def multiply(a,b)
|
||||
"multiply 2 numbers"
|
||||
|
||||
return a*b
|
||||
=======
|
||||
# updated comment
|
||||
# Function to add
|
||||
# Addition function
|
||||
def add(a,b):
|
||||
>>>>>>> updated
|
||||
"add 2 numbers"
|
||||
|
||||
return a+b
|
||||
>>>>>>> REPLACE
|
||||
{fence[1]}
|
||||
|
||||
A program will parse the edit blocks you generate and replace the `HEAD` lines with the `updated` lines.
|
||||
So edit blocks must be precise and unambiguous!
|
||||
The *SEARCH* section must *EXACTLY MATCH* the existing source code, character for character.
|
||||
|
||||
Every *edit block* must be fenced with {fence[0]}...{fence[1]} with the correct code language.
|
||||
Every *edit block* must start with the full path! *NEVER* propose edit blocks for *read-only* files.
|
||||
Every *SEARCH/REPLACE block* must be fenced with {fence[0]} and {fence[1]}, with the correct code language.
|
||||
|
||||
The `HEAD` section must be an *exact set of sequential lines* from the file!
|
||||
NEVER SKIP LINES in the `HEAD` section!
|
||||
NEVER ELIDE LINES AND REPLACE THEM WITH A COMMENT!
|
||||
NEVER OMIT ANY WHITESPACE in the `HEAD` section!
|
||||
Every *SEARCH/REPLACE block* must start with the full path!
|
||||
NEVER try to *SEARCH/REPLACE* any *read-only* files.
|
||||
|
||||
Edits to different parts of a file each need their own *edit block*, including the full path.
|
||||
|
||||
If you want to put code in a new file, use an edit block with:
|
||||
If you want to put code in a new file, use a *SEARCH/REPLACE block* with:
|
||||
- A new file path, including dir name if needed
|
||||
- An empty `HEAD` section
|
||||
- An empty `SEARCH` section
|
||||
- The new file's contents in the `updated` section
|
||||
"""
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue