Skip to content

Commit 4d36750

Browse files
committed
fix: improve diff editing error messages for Qwen3 model compatibility
- Clarified error messages to distinguish between diff structure markers and file content - Added explicit guidance that diff markers should NEVER be escaped in the structure - Emphasized that escaping is only needed for markers within file content being modified - Maintained backward compatibility with existing test expectations This fixes issue #7247 where Qwen3 235B model was confused by error messages and tried to escape diff structure markers, causing diff editing to fail.
1 parent 9461749 commit 4d36750

File tree

2 files changed

+48
-26
lines changed

2 files changed

+48
-26
lines changed

src/core/diff/strategies/multi-file-search-replace.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ If you're not confident in the exact content to search for, use the read_file to
104104
When applying the diffs, be extra careful to remember to change any closing brackets or other syntax that may be affected by the diff farther down in the file.
105105
ALWAYS make as many changes in a single 'apply_diff' request as possible using multiple SEARCH/REPLACE blocks
106106
107+
**IMPORTANT ESCAPING RULES:**
108+
- The diff structure markers (<<<<<<< SEARCH, =======, >>>>>>> REPLACE) should NEVER be escaped - they define the diff structure
109+
- ONLY escape these patterns when they appear in the actual file content you're searching for or replacing
110+
- Example: If you're removing merge conflict markers from a file, escape them in the SEARCH content: \\=======
111+
- Do NOT escape the ======= that separates your SEARCH and REPLACE sections
112+
107113
Parameters:
108114
- args: Contains one or more file elements, where each file contains:
109115
- path: (required) The path of the file to modify (relative to the current workspace directory ${args.cwd})
@@ -266,37 +272,42 @@ Each file requires its own path, start_line, and diff elements.
266272
`ERROR: Special marker '${found}' found in your diff content at line ${state.line}:\n` +
267273
"\n" +
268274
`When removing merge conflict markers like '${found}' from files, you MUST escape them\n` +
269-
"in your SEARCH section by prepending a backslash (\\) at the beginning of the line:\n" +
275+
"in your SEARCH section by prepending a backslash (\\) at the beginning of the line.\n" +
276+
"\n" +
277+
"IMPORTANT CLARIFICATION:\n" +
278+
"- ONLY escape these patterns when they appear in the actual file content you're modifying\n" +
279+
"- The diff structure markers themselves (<<<<<<< SEARCH, =======, >>>>>>> REPLACE) should NEVER be escaped\n" +
270280
"\n" +
271281
"CORRECT FORMAT:\n\n" +
272282
"<<<<<<< SEARCH\n" +
273283
"content before\n" +
274-
`\\${found} <-- Note the backslash here in this example\n` +
284+
`\\${found} <-- Escape ONLY when this is part of the file content\n` +
275285
"content after\n" +
276286
"=======\n" +
277287
"replacement content\n" +
278288
">>>>>>> REPLACE\n" +
279289
"\n" +
280-
"Without escaping, the system confuses your content with diff syntax markers.\n" +
281-
"You may use multiple diff blocks in a single diff request, but ANY of ONLY the following separators that occur within SEARCH or REPLACE content must be escaped, as follows:\n" +
282-
`\\${SEARCH}\n` +
283-
`\\${SEP}\n` +
284-
`\\${REPLACE}\n`,
290+
"Without escaping, the system confuses your content with diff syntax markers.",
285291
})
286292

287293
const reportInvalidDiffError = (found: string, expected: string) => ({
288294
success: false,
289295
error:
290296
`ERROR: Diff block is malformed: marker '${found}' found in your diff content at line ${state.line}. Expected: ${expected}\n` +
291297
"\n" +
292-
"CORRECT FORMAT:\n\n" +
298+
"CORRECT DIFF STRUCTURE:\n" +
293299
"<<<<<<< SEARCH\n" +
294-
":start_line: (required) The line number of original content where the search block starts.\n" +
295-
"-------\n" +
296-
"[exact content to find including whitespace]\n" +
297-
"=======\n" +
300+
":start_line:NUMBER (optional - specify line number)\n" +
301+
"------- (optional separator)\n" +
302+
"[exact content to find]\n" +
303+
"======= (required - separates search from replace)\n" +
298304
"[new content to replace with]\n" +
299-
">>>>>>> REPLACE\n",
305+
">>>>>>> REPLACE (required - ends the diff block)\n" +
306+
"\n" +
307+
"The markers above (<<<<<<< SEARCH, =======, >>>>>>> REPLACE) are part of the diff syntax.\n" +
308+
"They should appear exactly as shown, without any escaping.\n" +
309+
"\n" +
310+
"Make sure you're following this exact structure for your diff blocks.",
300311
})
301312

302313
const reportLineMarkerInReplaceError = (marker: string) => ({

src/core/diff/strategies/multi-search-replace.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ If you're not confident in the exact content to search for, use the read_file to
9999
When applying the diffs, be extra careful to remember to change any closing brackets or other syntax that may be affected by the diff farther down in the file.
100100
ALWAYS make as many changes in a single 'apply_diff' request as possible using multiple SEARCH/REPLACE blocks
101101
102+
**IMPORTANT ESCAPING RULES:**
103+
- The diff structure markers (<<<<<<< SEARCH, =======, >>>>>>> REPLACE) should NEVER be escaped - they define the diff structure
104+
- ONLY escape these patterns when they appear in the actual file content you're searching for or replacing
105+
- Example: If you're removing merge conflict markers from a file, escape them in the SEARCH content: \\=======
106+
- Do NOT escape the ======= that separates your SEARCH and REPLACE sections
107+
102108
Parameters:
103109
- path: (required) The path of the file to modify (relative to the current workspace directory ${args.cwd})
104110
- diff: (required) The search/replace block defining the changes.
@@ -213,37 +219,42 @@ Only use a single line of '=======' between search and replacement content, beca
213219
`ERROR: Special marker '${found}' found in your diff content at line ${state.line}:\n` +
214220
"\n" +
215221
`When removing merge conflict markers like '${found}' from files, you MUST escape them\n` +
216-
"in your SEARCH section by prepending a backslash (\\) at the beginning of the line:\n" +
222+
"in your SEARCH section by prepending a backslash (\\) at the beginning of the line.\n" +
223+
"\n" +
224+
"IMPORTANT CLARIFICATION:\n" +
225+
"- ONLY escape these patterns when they appear in the actual file content you're modifying\n" +
226+
"- The diff structure markers themselves (<<<<<<< SEARCH, =======, >>>>>>> REPLACE) should NEVER be escaped\n" +
217227
"\n" +
218228
"CORRECT FORMAT:\n\n" +
219229
"<<<<<<< SEARCH\n" +
220230
"content before\n" +
221-
`\\${found} <-- Note the backslash here in this example\n` +
231+
`\\${found} <-- Escape ONLY when this is part of the file content\n` +
222232
"content after\n" +
223233
"=======\n" +
224234
"replacement content\n" +
225235
">>>>>>> REPLACE\n" +
226236
"\n" +
227-
"Without escaping, the system confuses your content with diff syntax markers.\n" +
228-
"You may use multiple diff blocks in a single diff request, but ANY of ONLY the following separators that occur within SEARCH or REPLACE content must be escaped, as follows:\n" +
229-
`\\${SEARCH}\n` +
230-
`\\${SEP}\n` +
231-
`\\${REPLACE}\n`,
237+
"Without escaping, the system confuses your content with diff syntax markers.",
232238
})
233239

234240
const reportInvalidDiffError = (found: string, expected: string) => ({
235241
success: false,
236242
error:
237243
`ERROR: Diff block is malformed: marker '${found}' found in your diff content at line ${state.line}. Expected: ${expected}\n` +
238244
"\n" +
239-
"CORRECT FORMAT:\n\n" +
245+
"CORRECT DIFF STRUCTURE:\n" +
240246
"<<<<<<< SEARCH\n" +
241-
":start_line: (required) The line number of original content where the search block starts.\n" +
242-
"-------\n" +
243-
"[exact content to find including whitespace]\n" +
244-
"=======\n" +
247+
":start_line:NUMBER (optional - specify line number)\n" +
248+
"------- (optional separator)\n" +
249+
"[exact content to find]\n" +
250+
"======= (required - separates search from replace)\n" +
245251
"[new content to replace with]\n" +
246-
">>>>>>> REPLACE\n",
252+
">>>>>>> REPLACE (required - ends the diff block)\n" +
253+
"\n" +
254+
"The markers above (<<<<<<< SEARCH, =======, >>>>>>> REPLACE) are part of the diff syntax.\n" +
255+
"They should appear exactly as shown, without any escaping.\n" +
256+
"\n" +
257+
"Make sure you're following this exact structure for your diff blocks.",
247258
})
248259

249260
const reportLineMarkerInReplaceError = (marker: string) => ({

0 commit comments

Comments
 (0)