mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
* refactor: enhance insertGroups and insertContentTool for better handling of insertion operations * refactor: simplify insert_content tool - Remove operations-based implementation in favor of single line insertion - Update parameters from operations to line and content - Simplify insertion logic and error handling - Update tool description and documentation - Remove XML parsing for operations - Clean up code and improve error messages * refactor: remove insert_content experiment and related tests * Remove the append_to_file tool * Improvements to chat row and instructions --------- Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
173 lines
5.6 KiB
TypeScript
173 lines
5.6 KiB
TypeScript
import delay from "delay"
|
|
import fs from "fs/promises"
|
|
import path from "path"
|
|
|
|
import { getReadablePath } from "../../utils/path"
|
|
import { Cline } from "../Cline"
|
|
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
|
import { formatResponse } from "../prompts/responses"
|
|
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
|
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
|
|
import { fileExistsAtPath } from "../../utils/fs"
|
|
import { insertGroups } from "../diff/insert-groups"
|
|
|
|
export async function insertContentTool(
|
|
cline: Cline,
|
|
block: ToolUse,
|
|
askApproval: AskApproval,
|
|
handleError: HandleError,
|
|
pushToolResult: PushToolResult,
|
|
removeClosingTag: RemoveClosingTag,
|
|
) {
|
|
const relPath: string | undefined = block.params.path
|
|
const line: string | undefined = block.params.line
|
|
const content: string | undefined = block.params.content
|
|
|
|
const sharedMessageProps: ClineSayTool = {
|
|
tool: "insertContent",
|
|
path: getReadablePath(cline.cwd, removeClosingTag("path", relPath)),
|
|
lineNumber: line ? parseInt(line, 10) : undefined,
|
|
}
|
|
|
|
try {
|
|
if (block.partial) {
|
|
const partialMessage = JSON.stringify(sharedMessageProps)
|
|
await cline.ask("tool", partialMessage, block.partial).catch(() => {})
|
|
return
|
|
}
|
|
|
|
// Validate required parameters
|
|
if (!relPath) {
|
|
cline.consecutiveMistakeCount++
|
|
cline.recordToolError("insert_content")
|
|
pushToolResult(await cline.sayAndCreateMissingParamError("insert_content", "path"))
|
|
return
|
|
}
|
|
|
|
if (!line) {
|
|
cline.consecutiveMistakeCount++
|
|
cline.recordToolError("insert_content")
|
|
pushToolResult(await cline.sayAndCreateMissingParamError("insert_content", "line"))
|
|
return
|
|
}
|
|
|
|
if (!content) {
|
|
cline.consecutiveMistakeCount++
|
|
cline.recordToolError("insert_content")
|
|
pushToolResult(await cline.sayAndCreateMissingParamError("insert_content", "content"))
|
|
return
|
|
}
|
|
|
|
const absolutePath = path.resolve(cline.cwd, relPath)
|
|
const fileExists = await fileExistsAtPath(absolutePath)
|
|
|
|
if (!fileExists) {
|
|
cline.consecutiveMistakeCount++
|
|
cline.recordToolError("insert_content")
|
|
const formattedError = `File does not exist at path: ${absolutePath}\n\n<error_details>\nThe specified file could not be found. Please verify the file path and try again.\n</error_details>`
|
|
await cline.say("error", formattedError)
|
|
pushToolResult(formattedError)
|
|
return
|
|
}
|
|
|
|
const lineNumber = parseInt(line, 10)
|
|
if (isNaN(lineNumber) || lineNumber < 0) {
|
|
cline.consecutiveMistakeCount++
|
|
cline.recordToolError("insert_content")
|
|
pushToolResult(formatResponse.toolError("Invalid line number. Must be a non-negative integer."))
|
|
return
|
|
}
|
|
|
|
cline.consecutiveMistakeCount = 0
|
|
|
|
// Read the file
|
|
const fileContent = await fs.readFile(absolutePath, "utf8")
|
|
cline.diffViewProvider.editType = "modify"
|
|
cline.diffViewProvider.originalContent = fileContent
|
|
const lines = fileContent.split("\n")
|
|
|
|
const updatedContent = insertGroups(lines, [
|
|
{
|
|
index: lineNumber - 1,
|
|
elements: content.split("\n"),
|
|
},
|
|
]).join("\n")
|
|
|
|
// Show changes in diff view
|
|
if (!cline.diffViewProvider.isEditing) {
|
|
await cline.ask("tool", JSON.stringify(sharedMessageProps), true).catch(() => {})
|
|
// First open with original content
|
|
await cline.diffViewProvider.open(relPath)
|
|
await cline.diffViewProvider.update(fileContent, false)
|
|
cline.diffViewProvider.scrollToFirstDiff()
|
|
await delay(200)
|
|
}
|
|
|
|
const diff = formatResponse.createPrettyPatch(relPath, fileContent, updatedContent)
|
|
|
|
if (!diff) {
|
|
pushToolResult(`No changes needed for '${relPath}'`)
|
|
return
|
|
}
|
|
|
|
await cline.diffViewProvider.update(updatedContent, true)
|
|
|
|
const completeMessage = JSON.stringify({
|
|
...sharedMessageProps,
|
|
diff,
|
|
lineNumber: lineNumber,
|
|
} satisfies ClineSayTool)
|
|
|
|
const didApprove = await cline
|
|
.ask("tool", completeMessage, false)
|
|
.then((response) => response.response === "yesButtonClicked")
|
|
|
|
if (!didApprove) {
|
|
await cline.diffViewProvider.revertChanges()
|
|
pushToolResult("Changes were rejected by the user.")
|
|
return
|
|
}
|
|
|
|
const { newProblemsMessage, userEdits, finalContent } = await cline.diffViewProvider.saveChanges()
|
|
|
|
// Track file edit operation
|
|
if (relPath) {
|
|
await cline.getFileContextTracker().trackFileContext(relPath, "roo_edited" as RecordSource)
|
|
}
|
|
|
|
cline.didEditFile = true
|
|
|
|
if (!userEdits) {
|
|
pushToolResult(
|
|
`The content was successfully inserted in ${relPath.toPosix()} at line ${lineNumber}.${newProblemsMessage}`,
|
|
)
|
|
await cline.diffViewProvider.reset()
|
|
return
|
|
}
|
|
|
|
const userFeedbackDiff = JSON.stringify({
|
|
tool: "insertContent",
|
|
path: getReadablePath(cline.cwd, relPath),
|
|
lineNumber: lineNumber,
|
|
diff: userEdits,
|
|
} satisfies ClineSayTool)
|
|
|
|
await cline.say("user_feedback_diff", userFeedbackDiff)
|
|
|
|
pushToolResult(
|
|
`The user made the following updates to your content:\n\n${userEdits}\n\n` +
|
|
`The updated content has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file:\n\n` +
|
|
`<final_file_content path="${relPath.toPosix()}">\n${finalContent}\n</final_file_content>\n\n` +
|
|
`Please note:\n` +
|
|
`1. You do not need to re-write the file with these changes, as they have already been applied.\n` +
|
|
`2. Proceed with the task using this updated file content as the new baseline.\n` +
|
|
`3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` +
|
|
`${newProblemsMessage}`,
|
|
)
|
|
|
|
await cline.diffViewProvider.reset()
|
|
} catch (error) {
|
|
handleError("insert content", error)
|
|
await cline.diffViewProvider.reset()
|
|
}
|
|
}
|