mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: process queued user messages during endless loop recovery (Issue #10814)
When the model gets stuck in a repetitive loop (repeating the same tool call or not using tools), user messages sent during this time are queued but never processed because the model keeps receiving the same error feedback. This fix adds queue processing at two critical points: 1. In Task.ts when consecutiveNoToolUseCount >= 2: Check for queued messages and inject them as user feedback to break the loop. 2. In presentAssistantMessage.ts when tool repetition is detected: Check for queued messages before asking the user, allowing previously queued messages to provide the intervention needed. Both fixes reset the mistake counters when user guidance is received, giving the model a fresh start with the user-provided direction. Fixes #10814
This commit is contained in:
parent
802b40a790
commit
3da18c7712
2 changed files with 59 additions and 12 deletions
|
|
@ -824,24 +824,48 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
|
||||
// If execution is not allowed, notify user and break.
|
||||
if (!repetitionCheck.allowExecution && repetitionCheck.askUser) {
|
||||
// Handle repetition similar to mistake_limit_reached pattern.
|
||||
const { response, text, images } = await cline.ask(
|
||||
repetitionCheck.askUser.messageKey as ClineAsk,
|
||||
repetitionCheck.askUser.messageDetail.replace("{toolName}", block.name),
|
||||
)
|
||||
let feedbackText: string | undefined
|
||||
let feedbackImages: string[] | undefined
|
||||
|
||||
if (response === "messageResponse") {
|
||||
// Add user feedback to userContent.
|
||||
// CRITICAL FIX (GitHub #10814): Check for queued user messages first.
|
||||
// When auto-approve is enabled and the model gets stuck in a loop,
|
||||
// user messages are queued but never processed because the model
|
||||
// keeps repeating the same tool call. By checking the queue here,
|
||||
// we allow user intervention to break the loop.
|
||||
if (!cline.messageQueueService.isEmpty()) {
|
||||
const queuedMessage = cline.messageQueueService.dequeueMessage()
|
||||
if (queuedMessage) {
|
||||
feedbackText = queuedMessage.text
|
||||
feedbackImages = queuedMessage.images
|
||||
// Show the user's feedback in chat
|
||||
await cline.say("user_feedback", feedbackText, feedbackImages)
|
||||
}
|
||||
}
|
||||
|
||||
// If no queued message, ask the user for feedback
|
||||
if (!feedbackText) {
|
||||
const { response, text, images } = await cline.ask(
|
||||
repetitionCheck.askUser.messageKey as ClineAsk,
|
||||
repetitionCheck.askUser.messageDetail.replace("{toolName}", block.name),
|
||||
)
|
||||
|
||||
if (response === "messageResponse") {
|
||||
feedbackText = text
|
||||
feedbackImages = images
|
||||
// Add user feedback to chat.
|
||||
await cline.say("user_feedback", text, images)
|
||||
}
|
||||
}
|
||||
|
||||
// If we have user feedback (from queue or ask), add it to userContent
|
||||
if (feedbackText) {
|
||||
cline.userMessageContent.push(
|
||||
{
|
||||
type: "text" as const,
|
||||
text: `Tool repetition limit reached. User feedback: ${text}`,
|
||||
text: `Tool repetition limit reached. User feedback: ${feedbackText}`,
|
||||
},
|
||||
...formatResponse.imageBlocks(images),
|
||||
...formatResponse.imageBlocks(feedbackImages),
|
||||
)
|
||||
|
||||
// Add user feedback to chat.
|
||||
await cline.say("user_feedback", text, images)
|
||||
}
|
||||
|
||||
// Track tool repetition in telemetry via PostHog exception tracking and event.
|
||||
|
|
|
|||
|
|
@ -3540,6 +3540,29 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
await this.say("error", "MODEL_NO_TOOLS_USED")
|
||||
// Only count toward mistake limit after second consecutive failure
|
||||
this.consecutiveMistakeCount++
|
||||
|
||||
// CRITICAL: Check for queued user messages when the model appears stuck.
|
||||
// This allows user intervention to break out of endless loops where the model
|
||||
// keeps trying the same approach without using tools (GitHub issue #10814).
|
||||
if (!this.messageQueueService.isEmpty()) {
|
||||
const queuedMessage = this.messageQueueService.dequeueMessage()
|
||||
if (queuedMessage) {
|
||||
// Add user's message as feedback to break the loop
|
||||
await this.say("user_feedback", queuedMessage.text, queuedMessage.images)
|
||||
this.userMessageContent.push({
|
||||
type: "text",
|
||||
text: formatResponse.tooManyMistakes(queuedMessage.text),
|
||||
})
|
||||
if (queuedMessage.images && queuedMessage.images.length > 0) {
|
||||
this.userMessageContent.push(
|
||||
...formatResponse.imageBlocks(queuedMessage.images),
|
||||
)
|
||||
}
|
||||
// Reset mistake counter since user provided guidance
|
||||
this.consecutiveMistakeCount = 0
|
||||
this.consecutiveNoToolUseCount = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use the task's locked protocol for consistent behavior
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue