Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
269 changes: 164 additions & 105 deletions src/core/assistant-message/presentAssistantMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,16 @@ export async function presentAssistantMessage(cline: Task) {
const handleError = async (action: string, error: Error) => {
const errorString = `Error ${action}: ${JSON.stringify(serializeError(error))}`

await cline.say(
"error",
`Error ${action}:\n${error.message ?? JSON.stringify(serializeError(error), null, 2)}`,
)
// Enhanced error logging for debugging
console.error(`[Tool Error] ${block.name} - ${action}:`, error)

// More detailed error message for user
const userErrorMessage = `Error ${action}:\n${error.message ?? JSON.stringify(serializeError(error), null, 2)}\n\nTool: ${block.name}\nAction: ${action}`

await cline.say("error", userErrorMessage)

// Record the tool error for tracking
cline.recordToolError(block.name as ToolName, errorString)

pushToolResult(formatResponse.toolError(errorString))
}
Expand Down Expand Up @@ -406,116 +412,169 @@ export async function presentAssistantMessage(cline: Task) {
}
}

switch (block.name) {
case "write_to_file":
await writeToFileTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "apply_diff": {
// Get the provider and state to check experiment settings
const provider = cline.providerRef.deref()
let isMultiFileApplyDiffEnabled = false

if (provider) {
const state = await provider.getState()
isMultiFileApplyDiffEnabled = experiments.isEnabled(
state.experiments ?? {},
EXPERIMENT_IDS.MULTI_FILE_APPLY_DIFF,
)
}
// Wrap tool execution in try-catch to ensure errors are properly handled
try {
switch (block.name) {
case "write_to_file":
await writeToFileTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "apply_diff": {
// Get the provider and state to check experiment settings
const provider = cline.providerRef.deref()
let isMultiFileApplyDiffEnabled = false

if (provider) {
const state = await provider.getState()
isMultiFileApplyDiffEnabled = experiments.isEnabled(
state.experiments ?? {},
EXPERIMENT_IDS.MULTI_FILE_APPLY_DIFF,
)
}

if (isMultiFileApplyDiffEnabled) {
await applyDiffTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
} else {
await applyDiffToolLegacy(
if (isMultiFileApplyDiffEnabled) {
await applyDiffTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
} else {
await applyDiffToolLegacy(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
}
break
}
case "insert_content":
await insertContentTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
}
break
break
case "search_and_replace":
await searchAndReplaceTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "read_file":
await readFileTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "fetch_instructions":
await fetchInstructionsTool(cline, block, askApproval, handleError, pushToolResult)
break
case "list_files":
await listFilesTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "codebase_search":
await codebaseSearchTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "list_code_definition_names":
await listCodeDefinitionNamesTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "search_files":
await searchFilesTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "browser_action":
await browserActionTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "execute_command":
await executeCommandTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "use_mcp_tool":
await useMcpToolTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "access_mcp_resource":
await accessMcpResourceTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "ask_followup_question":
await askFollowupQuestionTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "switch_mode":
await switchModeTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "new_task":
await newTaskTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "attempt_completion":
await attemptCompletionTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
toolDescription,
askFinishSubTaskApproval,
)
break
default:
// Handle unknown tool names
const unknownToolError = new Error(`Unknown tool: ${block.name}`)
await handleError(`executing unknown tool '${block.name}'`, unknownToolError)
break
}
case "insert_content":
await insertContentTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "search_and_replace":
await searchAndReplaceTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "read_file":
await readFileTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)

break
case "fetch_instructions":
await fetchInstructionsTool(cline, block, askApproval, handleError, pushToolResult)
break
case "list_files":
await listFilesTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "codebase_search":
await codebaseSearchTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "list_code_definition_names":
await listCodeDefinitionNamesTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "search_files":
await searchFilesTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "browser_action":
await browserActionTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "execute_command":
await executeCommandTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "use_mcp_tool":
await useMcpToolTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "access_mcp_resource":
await accessMcpResourceTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "ask_followup_question":
await askFollowupQuestionTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
)
break
case "switch_mode":
await switchModeTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "new_task":
await newTaskTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "attempt_completion":
await attemptCompletionTool(
cline,
block,
askApproval,
handleError,
pushToolResult,
removeClosingTag,
toolDescription,
askFinishSubTaskApproval,
)
break
} catch (toolExecutionError) {
// Catch any unhandled errors during tool execution
console.error(`[Tool Execution Error] ${block.name}:`, toolExecutionError)
await handleError(`executing tool '${block.name}'`, toolExecutionError as Error)
}

break
Expand Down
30 changes: 27 additions & 3 deletions src/core/tools/applyDiffTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,33 @@ export async function applyDiffToolLegacy(

// Show diff view before asking for approval
cline.diffViewProvider.editType = "modify"
await cline.diffViewProvider.open(relPath)
await cline.diffViewProvider.update(diffResult.content, true)
await cline.diffViewProvider.scrollToFirstDiff()

try {
await cline.diffViewProvider.open(relPath)
} catch (openError) {
console.error(`[applyDiffTool] Failed to open diff view for '${relPath}':`, openError)
cline.consecutiveMistakeCount++
cline.recordToolError("apply_diff", `Failed to open diff view: ${openError.message}`)
pushToolResult(
formatResponse.toolError(`Failed to open file editor for '${relPath}': ${openError.message}`),
)
await cline.diffViewProvider.reset()
return
}

try {
await cline.diffViewProvider.update(diffResult.content, true)
await cline.diffViewProvider.scrollToFirstDiff()
} catch (updateError) {
console.error(`[applyDiffTool] Failed to update diff view for '${relPath}':`, updateError)
cline.consecutiveMistakeCount++
cline.recordToolError("apply_diff", `Failed to update diff view: ${updateError.message}`)
pushToolResult(
formatResponse.toolError(`Failed to update file editor for '${relPath}': ${updateError.message}`),
)
await cline.diffViewProvider.reset()
return
}

const completeMessage = JSON.stringify({
...sharedMessageProps,
Expand Down
50 changes: 44 additions & 6 deletions src/core/tools/insertContentTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,35 @@ export async function insertContentTool(
// 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)

try {
// First open with original content
await cline.diffViewProvider.open(relPath)
} catch (openError) {
console.error(`[insertContentTool] Failed to open diff view for '${relPath}':`, openError)
cline.consecutiveMistakeCount++
cline.recordToolError("insert_content", `Failed to open diff view: ${openError.message}`)
pushToolResult(
formatResponse.toolError(`Failed to open file editor for '${relPath}': ${openError.message}`),
)
await cline.diffViewProvider.reset()
return
}

try {
await cline.diffViewProvider.update(fileContent, false)
cline.diffViewProvider.scrollToFirstDiff()
await delay(200)
} catch (updateError) {
console.error(`[insertContentTool] Failed to update diff view for '${relPath}':`, updateError)
cline.consecutiveMistakeCount++
cline.recordToolError("insert_content", `Failed to update diff view: ${updateError.message}`)
pushToolResult(
formatResponse.toolError(`Failed to update file editor for '${relPath}': ${updateError.message}`),
)
await cline.diffViewProvider.reset()
return
}
}

const diff = formatResponse.createPrettyPatch(relPath, fileContent, updatedContent)
Expand All @@ -121,7 +145,21 @@ export async function insertContentTool(
return
}

await cline.diffViewProvider.update(updatedContent, true)
try {
await cline.diffViewProvider.update(updatedContent, true)
} catch (updateError) {
console.error(
`[insertContentTool] Failed to update diff view with new content for '${relPath}':`,
updateError,
)
cline.consecutiveMistakeCount++
cline.recordToolError("insert_content", `Failed to update diff view: ${updateError.message}`)
pushToolResult(
formatResponse.toolError(`Failed to update file editor for '${relPath}': ${updateError.message}`),
)
await cline.diffViewProvider.reset()
return
}

const completeMessage = JSON.stringify({
...sharedMessageProps,
Expand Down
Loading