diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index d9457f81d3d..558a1a26fd4 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -2445,10 +2445,14 @@ export class Task extends EventEmitter implements TaskLike { ), ) - const { response, text, images } = await this.ask( - "mistake_limit_reached", - t("common:errors.mistake_limit_guidance"), - ) + // Build error message with operation context for better user understanding + const operationContext = this.getLastAttemptedOperationContext() + let errorMessage = t("common:errors.mistake_limit_guidance") + if (operationContext) { + errorMessage = `${t("common:errors.mistake_limit_operation_context", { operation: operationContext })}\n\n${errorMessage}` + } + + const { response, text, images } = await this.ask("mistake_limit_reached", errorMessage) if (response === "messageResponse") { currentUserContent.push( @@ -4557,4 +4561,43 @@ export class Task extends EventEmitter implements TaskLike { console.error(`[Task] Queue processing error:`, e) } } + + /** + * Get a human-readable description of the last attempted operation. + * This is used to provide context in the mistake_limit_reached error message + * so users can understand what operation Roo was attempting when it failed. + * + * @returns A descriptive string like "write_to_file for 'path/to/file'" or undefined if no operation found + */ + public getLastAttemptedOperationContext(): string | undefined { + // Look for the last tool_use or mcp_tool_use block in assistantMessageContent + for (let i = this.assistantMessageContent.length - 1; i >= 0; i--) { + const block = this.assistantMessageContent[i] + if (block.type === "tool_use" || block.type === "mcp_tool_use") { + const toolUse = block as import("../../shared/tools").ToolUse | import("../../shared/tools").McpToolUse + const toolName = toolUse.name + + // Try to extract a file path from common tool parameters + let filePath: string | undefined + if ("params" in toolUse && toolUse.params) { + // Cast to allow accessing any parameter name + const params = toolUse.params as Record + // Common parameter names for file paths across different tools + filePath = params.path || params.file_path + } else if ("arguments" in toolUse && toolUse.arguments) { + // MCP tools use 'arguments' instead of 'params' + const args = toolUse.arguments as Record + filePath = (args.path as string) || (args.file_path as string) + } + + // Format the operation context string + if (filePath) { + return `${toolName} for '${filePath}'` + } + return toolName + } + } + + return undefined + } } diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 90c409feb76..acd45f24995 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -57,6 +57,7 @@ "cannot_access_path": "Cannot access path {{path}}: {{error}}", "settings_import_failed": "Settings import failed: {{error}}.", "mistake_limit_guidance": "This may indicate a failure in the model's thought process or inability to use a tool properly, which can be mitigated with some user guidance (e.g. \"Try breaking down the task into smaller steps\").", + "mistake_limit_operation_context": "While attempting: {{operation}}", "violated_organization_allowlist": "Failed to run task: the current profile isn't compatible with your organization settings", "condense_failed": "Failed to condense context", "condense_not_enough_messages": "Not enough messages to condense context",