Skip to content

Commit ed41736

Browse files
Githubguy132010daniel-lxs
authored andcommitted
Fix: Allow write_to_file to handle newline-only and empty content
1 parent c10fbbc commit ed41736

File tree

1 file changed

+46
-26
lines changed

1 file changed

+46
-26
lines changed

src/core/tools/writeToFileTool.ts

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { formatResponse } from "../prompts/responses"
88
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
99
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
1010
import { fileExistsAtPath } from "../../utils/fs"
11-
import { stripLineNumbers, everyLineHasLineNumbers } from "../../integrations/misc/extract-text"
11+
import { addLineNumbers, stripLineNumbers, everyLineHasLineNumbers } from "../../integrations/misc/extract-text"
1212
import { getReadablePath } from "../../utils/path"
1313
import { isPathOutsideWorkspace } from "../../utils/pathUtils"
1414
import { detectCodeOmission } from "../../integrations/editor/detect-omission"
@@ -26,28 +26,12 @@ export async function writeToFileTool(
2626
let newContent: string | undefined = block.params.content
2727
let predictedLineCount: number | undefined = parseInt(block.params.line_count ?? "0")
2828

29-
if (block.partial && (!relPath || newContent === undefined)) {
29+
if (!relPath || newContent === undefined) {
3030
// checking for newContent ensure relPath is complete
3131
// wait so we can determine if it's a new file or editing an existing file
3232
return
3333
}
3434

35-
if (!relPath) {
36-
cline.consecutiveMistakeCount++
37-
cline.recordToolError("write_to_file")
38-
pushToolResult(await cline.sayAndCreateMissingParamError("write_to_file", "path"))
39-
await cline.diffViewProvider.reset()
40-
return
41-
}
42-
43-
if (newContent === undefined) {
44-
cline.consecutiveMistakeCount++
45-
cline.recordToolError("write_to_file")
46-
pushToolResult(await cline.sayAndCreateMissingParamError("write_to_file", "content"))
47-
await cline.diffViewProvider.reset()
48-
return
49-
}
50-
5135
const accessAllowed = cline.rooIgnoreController?.validateAccess(relPath)
5236

5337
if (!accessAllowed) {
@@ -73,11 +57,11 @@ export async function writeToFileTool(
7357
// pre-processing newContent for cases where weaker models might add artifacts like markdown codeblock markers (deepseek/llama) or extra escape characters (gemini)
7458
if (newContent.startsWith("```")) {
7559
// cline handles cases where it includes language specifiers like ```python ```js
76-
newContent = newContent.split("\n").slice(1).join("\n").trim()
60+
newContent = newContent.split("\n").slice(1).join("\n")
7761
}
7862

7963
if (newContent.endsWith("```")) {
80-
newContent = newContent.split("\n").slice(0, -1).join("\n").trim()
64+
newContent = newContent.split("\n").slice(0, -1).join("\n")
8165
}
8266

8367
if (!cline.api.getModel().id.includes("claude")) {
@@ -116,7 +100,23 @@ export async function writeToFileTool(
116100

117101
return
118102
} else {
119-
if (predictedLineCount === undefined) {
103+
if (!relPath) {
104+
cline.consecutiveMistakeCount++
105+
cline.recordToolError("write_to_file")
106+
pushToolResult(await cline.sayAndCreateMissingParamError("write_to_file", "path"))
107+
await cline.diffViewProvider.reset()
108+
return
109+
}
110+
111+
if (newContent === undefined) {
112+
cline.consecutiveMistakeCount++
113+
cline.recordToolError("write_to_file")
114+
pushToolResult(await cline.sayAndCreateMissingParamError("write_to_file", "content"))
115+
await cline.diffViewProvider.reset()
116+
return
117+
}
118+
119+
if (!predictedLineCount) {
120120
cline.consecutiveMistakeCount++
121121
cline.recordToolError("write_to_file")
122122

@@ -212,8 +212,7 @@ export async function writeToFileTool(
212212
return
213213
}
214214

215-
// Call saveChanges to update the DiffViewProvider properties
216-
await cline.diffViewProvider.saveChanges()
215+
const { newProblemsMessage, userEdits, finalContent } = await cline.diffViewProvider.saveChanges()
217216

218217
// Track file edit operation
219218
if (relPath) {
@@ -222,10 +221,31 @@ export async function writeToFileTool(
222221

223222
cline.didEditFile = true // used to determine if we should wait for busy terminal to update before sending api request
224223

225-
// Get the formatted response message
226-
const message = await cline.diffViewProvider.pushToolWriteResult(cline, cline.cwd, !fileExists)
224+
if (userEdits) {
225+
await cline.say(
226+
"user_feedback_diff",
227+
JSON.stringify({
228+
tool: fileExists ? "editedExistingFile" : "newFileCreated",
229+
path: getReadablePath(cline.cwd, relPath),
230+
diff: userEdits,
231+
} satisfies ClineSayTool),
232+
)
227233

228-
pushToolResult(message)
234+
pushToolResult(
235+
`The user made the following updates to your content:\n\n${userEdits}\n\n` +
236+
`The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file, including line numbers:\n\n` +
237+
`<final_file_content path="${relPath.toPosix()}">\n${addLineNumbers(
238+
finalContent || "",
239+
)}\n</final_file_content>\n\n` +
240+
`Please note:\n` +
241+
`1. You do not need to re-write the file with these changes, as they have already been applied.\n` +
242+
`2. Proceed with the task using this updated file content as the new baseline.\n` +
243+
`3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` +
244+
`${newProblemsMessage}`,
245+
)
246+
} else {
247+
pushToolResult(`The content was successfully saved to ${relPath.toPosix()}.${newProblemsMessage}`)
248+
}
229249

230250
await cline.diffViewProvider.reset()
231251

0 commit comments

Comments
 (0)