mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
Move insert_content to a tool file (#2095)
This commit is contained in:
parent
02f63fc522
commit
d5328770e7
2 changed files with 164 additions and 146 deletions
|
|
@ -87,6 +87,7 @@ import { parseXml } from "../utils/xml"
|
|||
import { getWorkspacePath } from "../utils/path"
|
||||
import { writeToFileTool } from "./tools/writeToFileTool"
|
||||
import { applyDiffTool } from "./tools/applyDiffTool"
|
||||
import { insertContentTool } from "./tools/insertContentTool"
|
||||
|
||||
export type ToolResponse = string | Array<Anthropic.TextBlockParam | Anthropic.ImageBlockParam>
|
||||
type UserContent = Array<Anthropic.Messages.ContentBlockParam>
|
||||
|
|
@ -1572,153 +1573,9 @@ export class Cline extends EventEmitter<ClineEvents> {
|
|||
case "apply_diff":
|
||||
await applyDiffTool(this, block, askApproval, handleError, pushToolResult, removeClosingTag)
|
||||
break
|
||||
case "insert_content": {
|
||||
const relPath: string | undefined = block.params.path
|
||||
const operations: string | undefined = block.params.operations
|
||||
|
||||
const sharedMessageProps: ClineSayTool = {
|
||||
tool: "appliedDiff",
|
||||
path: getReadablePath(this.cwd, removeClosingTag("path", relPath)),
|
||||
}
|
||||
|
||||
try {
|
||||
if (block.partial) {
|
||||
const partialMessage = JSON.stringify(sharedMessageProps)
|
||||
await this.ask("tool", partialMessage, block.partial).catch(() => {})
|
||||
break
|
||||
}
|
||||
|
||||
// Validate required parameters
|
||||
if (!relPath) {
|
||||
this.consecutiveMistakeCount++
|
||||
pushToolResult(await this.sayAndCreateMissingParamError("insert_content", "path"))
|
||||
break
|
||||
}
|
||||
|
||||
if (!operations) {
|
||||
this.consecutiveMistakeCount++
|
||||
pushToolResult(await this.sayAndCreateMissingParamError("insert_content", "operations"))
|
||||
break
|
||||
}
|
||||
|
||||
const absolutePath = path.resolve(this.cwd, relPath)
|
||||
const fileExists = await fileExistsAtPath(absolutePath)
|
||||
|
||||
if (!fileExists) {
|
||||
this.consecutiveMistakeCount++
|
||||
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 this.say("error", formattedError)
|
||||
pushToolResult(formattedError)
|
||||
break
|
||||
}
|
||||
|
||||
let parsedOperations: Array<{
|
||||
start_line: number
|
||||
content: string
|
||||
}>
|
||||
|
||||
try {
|
||||
parsedOperations = JSON.parse(operations)
|
||||
if (!Array.isArray(parsedOperations)) {
|
||||
throw new Error("Operations must be an array")
|
||||
}
|
||||
} catch (error) {
|
||||
this.consecutiveMistakeCount++
|
||||
await this.say("error", `Failed to parse operations JSON: ${error.message}`)
|
||||
pushToolResult(formatResponse.toolError("Invalid operations JSON format"))
|
||||
break
|
||||
}
|
||||
|
||||
this.consecutiveMistakeCount = 0
|
||||
|
||||
// Read the file
|
||||
const fileContent = await fs.readFile(absolutePath, "utf8")
|
||||
this.diffViewProvider.editType = "modify"
|
||||
this.diffViewProvider.originalContent = fileContent
|
||||
const lines = fileContent.split("\n")
|
||||
|
||||
const updatedContent = insertGroups(
|
||||
lines,
|
||||
parsedOperations.map((elem) => {
|
||||
return {
|
||||
index: elem.start_line - 1,
|
||||
elements: elem.content.split("\n"),
|
||||
}
|
||||
}),
|
||||
).join("\n")
|
||||
|
||||
// Show changes in diff view
|
||||
if (!this.diffViewProvider.isEditing) {
|
||||
await this.ask("tool", JSON.stringify(sharedMessageProps), true).catch(() => {})
|
||||
// First open with original content
|
||||
await this.diffViewProvider.open(relPath)
|
||||
await this.diffViewProvider.update(fileContent, false)
|
||||
this.diffViewProvider.scrollToFirstDiff()
|
||||
await delay(200)
|
||||
}
|
||||
|
||||
const diff = formatResponse.createPrettyPatch(relPath, fileContent, updatedContent)
|
||||
|
||||
if (!diff) {
|
||||
pushToolResult(`No changes needed for '${relPath}'`)
|
||||
break
|
||||
}
|
||||
|
||||
await this.diffViewProvider.update(updatedContent, true)
|
||||
|
||||
const completeMessage = JSON.stringify({
|
||||
...sharedMessageProps,
|
||||
diff,
|
||||
} satisfies ClineSayTool)
|
||||
|
||||
const didApprove = await this.ask("tool", completeMessage, false).then(
|
||||
(response) => response.response === "yesButtonClicked",
|
||||
)
|
||||
|
||||
if (!didApprove) {
|
||||
await this.diffViewProvider.revertChanges()
|
||||
pushToolResult("Changes were rejected by the user.")
|
||||
break
|
||||
}
|
||||
|
||||
const { newProblemsMessage, userEdits, finalContent } =
|
||||
await this.diffViewProvider.saveChanges()
|
||||
this.didEditFile = true
|
||||
|
||||
if (!userEdits) {
|
||||
pushToolResult(
|
||||
`The content was successfully inserted in ${relPath.toPosix()}.${newProblemsMessage}`,
|
||||
)
|
||||
await this.diffViewProvider.reset()
|
||||
break
|
||||
}
|
||||
|
||||
const userFeedbackDiff = JSON.stringify({
|
||||
tool: "appliedDiff",
|
||||
path: getReadablePath(this.cwd, relPath),
|
||||
diff: userEdits,
|
||||
} satisfies ClineSayTool)
|
||||
|
||||
console.debug("[DEBUG] User made edits, sending feedback diff:", userFeedbackDiff)
|
||||
await this.say("user_feedback_diff", userFeedbackDiff)
|
||||
pushToolResult(
|
||||
`The user made the following updates to your content:\n\n${userEdits}\n\n` +
|
||||
`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:\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 this.diffViewProvider.reset()
|
||||
} catch (error) {
|
||||
handleError("insert content", error)
|
||||
await this.diffViewProvider.reset()
|
||||
}
|
||||
case "insert_content":
|
||||
await insertContentTool(this, block, askApproval, handleError, pushToolResult, removeClosingTag)
|
||||
break
|
||||
}
|
||||
|
||||
case "search_and_replace": {
|
||||
const relPath: string | undefined = block.params.path
|
||||
const operations: string | undefined = block.params.operations
|
||||
|
|
|
|||
161
src/core/tools/insertContentTool.ts
Normal file
161
src/core/tools/insertContentTool.ts
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
import { getReadablePath } from "../../utils/path"
|
||||
import { Cline } from "../Cline"
|
||||
import { ToolUse } from "../assistant-message"
|
||||
import { AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "./types"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import path from "path"
|
||||
import { fileExistsAtPath } from "../../utils/fs"
|
||||
import { insertGroups } from "../diff/insert-groups"
|
||||
import delay from "delay"
|
||||
import fs from "fs/promises"
|
||||
|
||||
export async function insertContentTool(
|
||||
cline: Cline,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
pushToolResult: PushToolResult,
|
||||
removeClosingTag: RemoveClosingTag,
|
||||
) {
|
||||
const relPath: string | undefined = block.params.path
|
||||
const operations: string | undefined = block.params.operations
|
||||
|
||||
const sharedMessageProps: ClineSayTool = {
|
||||
tool: "appliedDiff",
|
||||
path: getReadablePath(cline.cwd, removeClosingTag("path", relPath)),
|
||||
}
|
||||
|
||||
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++
|
||||
pushToolResult(await cline.sayAndCreateMissingParamError("insert_content", "path"))
|
||||
return
|
||||
}
|
||||
|
||||
if (!operations) {
|
||||
cline.consecutiveMistakeCount++
|
||||
pushToolResult(await cline.sayAndCreateMissingParamError("insert_content", "operations"))
|
||||
return
|
||||
}
|
||||
|
||||
const absolutePath = path.resolve(cline.cwd, relPath)
|
||||
const fileExists = await fileExistsAtPath(absolutePath)
|
||||
|
||||
if (!fileExists) {
|
||||
cline.consecutiveMistakeCount++
|
||||
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
|
||||
}
|
||||
|
||||
let parsedOperations: Array<{
|
||||
start_line: number
|
||||
content: string
|
||||
}>
|
||||
|
||||
try {
|
||||
parsedOperations = JSON.parse(operations)
|
||||
if (!Array.isArray(parsedOperations)) {
|
||||
throw new Error("Operations must be an array")
|
||||
}
|
||||
} catch (error) {
|
||||
cline.consecutiveMistakeCount++
|
||||
await cline.say("error", `Failed to parse operations JSON: ${error.message}`)
|
||||
pushToolResult(formatResponse.toolError("Invalid operations JSON format"))
|
||||
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,
|
||||
parsedOperations.map((elem) => {
|
||||
return {
|
||||
index: elem.start_line - 1,
|
||||
elements: elem.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,
|
||||
} 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()
|
||||
cline.didEditFile = true
|
||||
|
||||
if (!userEdits) {
|
||||
pushToolResult(`The content was successfully inserted in ${relPath.toPosix()}.${newProblemsMessage}`)
|
||||
await cline.diffViewProvider.reset()
|
||||
return
|
||||
}
|
||||
|
||||
const userFeedbackDiff = JSON.stringify({
|
||||
tool: "appliedDiff",
|
||||
path: getReadablePath(cline.cwd, relPath),
|
||||
diff: userEdits,
|
||||
} satisfies ClineSayTool)
|
||||
|
||||
console.debug("[DEBUG] User made edits, sending feedback diff:", userFeedbackDiff)
|
||||
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, 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:\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 cline 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()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue