Skip to content

Commit 87b1a4d

Browse files
authored
Merge pull request #416 from daniel-lxs/improve_diff_prompt
Improve apply_diff prompt to encourage the model to generate better diffs
2 parents 012ca09 + 54fb38f commit 87b1a4d

File tree

2 files changed

+52
-59
lines changed

2 files changed

+52
-59
lines changed

src/core/diff/strategies/__tests__/new-unified.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ describe("main", () => {
2929
const cwd = "/test/path"
3030
const description = strategy.getToolDescription({ cwd })
3131

32-
expect(description).toContain("apply_diff")
32+
expect(description).toContain("apply_diff Tool - Generate Precise Code Changes")
3333
expect(description).toContain(cwd)
34+
expect(description).toContain("Step-by-Step Instructions")
35+
expect(description).toContain("Requirements")
36+
expect(description).toContain("Examples")
3437
expect(description).toContain("Parameters:")
35-
expect(description).toContain("Format Requirements:")
3638
})
3739
})
3840

src/core/diff/strategies/new-unified/index.ts

Lines changed: 48 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -108,77 +108,68 @@ export class NewUnifiedDiffStrategy implements DiffStrategy {
108108
}
109109

110110
getToolDescription(args: { cwd: string; toolOptions?: { [key: string]: string } }): string {
111-
return `# apply_diff Tool Rules:
111+
return `# apply_diff Tool - Generate Precise Code Changes
112112
113-
Generate a unified diff similar to what "diff -U0" would produce.
113+
Generate a unified diff that can be cleanly applied to modify code files.
114114
115-
The first two lines must include the file paths, starting with "---" for the original file and "+++" for the updated file. Do not include timestamps with the file paths.
115+
## Step-by-Step Instructions:
116116
117-
Each hunk of changes must start with a line containing only "@@ ... @@". Do not include line numbers or ranges in the "@@ ... @@" lines. These are not necessary for the user's patch tool.
117+
1. Start with file headers:
118+
- First line: "--- {original_file_path}"
119+
- Second line: "+++ {new_file_path}"
118120
119-
Your output must be a correct, clean patch that applies successfully against the current file contents. Mark all lines that need to be removed or changed with "-". Mark all new or modified lines with "+". Ensure you include all necessary changes; missing or unmarked lines will result in a broken patch.
121+
2. For each change section:
122+
- Begin with "@@ ... @@" separator line without line numbers
123+
- Include 2-3 lines of context before and after changes
124+
- Mark removed lines with "-"
125+
- Mark added lines with "+"
126+
- Preserve exact indentation
120127
121-
Indentation matters! Make sure to preserve the exact indentation of both removed and added lines.
128+
3. Group related changes:
129+
- Keep related modifications in the same hunk
130+
- Start new hunks for logically separate changes
131+
- When modifying functions/methods, include the entire block
122132
123-
Start a new hunk for each section of the file that requires changes. However, include only the hunks that contain actual changes. If a hunk consists entirely of unchanged lines, skip it.
133+
## Requirements:
124134
125-
Group related changes together in the same hunk whenever possible. Output hunks in whatever logical order makes the most sense.
135+
1. MUST include exact indentation
136+
2. MUST include sufficient context for unique matching
137+
3. MUST group related changes together
138+
4. MUST use proper unified diff format
139+
5. MUST NOT include timestamps in file headers
140+
6. MUST NOT include line numbers in the @@ header
126141
127-
When editing a function, method, loop, or similar code block, replace the *entire* block in one hunk. Use "-" lines to delete the existing block and "+" lines to add the updated block. This ensures accuracy in your diffs.
128-
129-
If you need to move code within a file, create two hunks: one to delete the code from its original location and another to insert it at the new location.
130-
131-
To create a new file, show a diff from "--- /dev/null" to "+++ path/to/new/file.ext".
132-
133-
Format Requirements:
142+
## Examples:
134143
144+
✅ Good diff (follows all requirements):
135145
\`\`\`diff
136-
--- mathweb/flask/app.py
137-
+++ mathweb/flask/app.py
146+
--- src/utils.ts
147+
+++ src/utils.ts
138148
@@ ... @@
139-
-class MathWeb:
140-
+import sympy
149+
def calculate_total(items):
150+
- total = 0
151+
- for item in items:
152+
- total += item.price
153+
+ return sum(item.price for item in items)
154+
\`\`\`
141155
142-
+
143-
+class MathWeb:
144-
@@ ... @@
145-
-def is_prime(x):
146-
- if x < 2:
147-
- return False
148-
- for i in range(2, int(math.sqrt(x)) + 1):
149-
- if x % i == 0:
150-
- return False
151-
- return True
156+
❌ Bad diff (violates requirements #1 and #2):
157+
\`\`\`diff
158+
--- src/utils.ts
159+
+++ src/utils.ts
152160
@@ ... @@
153-
[email protected]('/prime/<int:n>')
154-
-def nth_prime(n):
155-
- count = 0
156-
- num = 1
157-
- while count < n:
158-
- num += 1
159-
- if is_prime(num):
160-
- count += 1
161-
- return str(num)
162-
[email protected]('/prime/<int:n>')
163-
+def nth_prime(n):
164-
+ count = 0
165-
+ num = 1
166-
+ while count < n:
167-
+ num += 1
168-
+ if sympy.isprime(num):
169-
+ count += 1
170-
+ return str(num)
161+
-total = 0
162+
-for item in items:
163+
+return sum(item.price for item in items)
171164
\`\`\`
172165
173-
Be precise, consistent, and follow these rules carefully to generate correct diffs!
174-
175166
Parameters:
176-
- path: (required) The path of the file to apply the diff to (relative to the current working directory ${args.cwd})
177-
- diff: (required) The diff content in unified format to apply to the file.
167+
- path: (required) File path relative to ${args.cwd}
168+
- diff: (required) Unified diff content in unified format to apply to the file.
178169
179170
Usage:
180171
<apply_diff>
181-
<path>File path here</path>
172+
<path>path/to/file.ext</path>
182173
<diff>
183174
Your diff here
184175
</diff>
@@ -242,7 +233,7 @@ Your diff here
242233
originalContent: string,
243234
diffContent: string,
244235
startLine?: number,
245-
endLine?: number,
236+
endLine?: number
246237
): Promise<DiffResult> {
247238
const parsedDiff = this.parseUnifiedDiff(diffContent)
248239
const originalLines = originalContent.split("\n")
@@ -280,7 +271,7 @@ Your diff here
280271
subHunkResult,
281272
subSearchResult.index,
282273
subSearchResult.confidence,
283-
this.confidenceThreshold,
274+
this.confidenceThreshold
284275
)
285276
if (subEditResult.confidence >= this.confidenceThreshold) {
286277
subHunkResult = subEditResult.result
@@ -302,12 +293,12 @@ Your diff here
302293
const contextRatio = contextLines / totalLines
303294

304295
let errorMsg = `Failed to find a matching location in the file (${Math.floor(
305-
confidence * 100,
296+
confidence * 100
306297
)}% confidence, needs ${Math.floor(this.confidenceThreshold * 100)}%)\n\n`
307298
errorMsg += "Debug Info:\n"
308299
errorMsg += `- Search Strategy Used: ${strategy}\n`
309300
errorMsg += `- Context Lines: ${contextLines} out of ${totalLines} total lines (${Math.floor(
310-
contextRatio * 100,
301+
contextRatio * 100
311302
)}%)\n`
312303
errorMsg += `- Attempted to split into ${subHunks.length} sub-hunks but still failed\n`
313304

@@ -339,7 +330,7 @@ Your diff here
339330
} else {
340331
// Edit failure - likely due to content mismatch
341332
let errorMsg = `Failed to apply the edit using ${editResult.strategy} strategy (${Math.floor(
342-
editResult.confidence * 100,
333+
editResult.confidence * 100
343334
)}% confidence)\n\n`
344335
errorMsg += "Debug Info:\n"
345336
errorMsg += "- The location was found but the content didn't match exactly\n"

0 commit comments

Comments
 (0)