fix: queue messages when ask is superseded during command_output

When a user sends a message during command_output (e.g., while a command
like `sleep 10` is running), a race condition can occur where the command
completes and updates lastMessageTs just as the user response arrives.
This causes the ask to throw AskIgnoredError("superseded") and the user
message is silently discarded.

This fix captures the pending response content (text and images) before
throwing AskIgnoredError and queues it via messageQueueService so the
message can be processed when the next ask is ready. This ensures user
messages are never lost during rapid state transitions.

Fixes EXT-674
This commit is contained in:
Roo Code 2026-01-28 19:36:36 +00:00
parent fe722dad23
commit c6b866c9dd

View file

@ -1473,6 +1473,25 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
// Could happen if we send multiple asks in a row i.e. with
// command_output. It's important that when we know an ask could
// fail, it is handled gracefully.
//
// If there's a pending response with user content, queue it so the
// message isn't lost. This handles the race condition where a user
// sends a message during command_output but the command completes
// at nearly the same time (causing say("command_output") to update
// lastMessageTs before we can return the response).
//
// Use type assertions to break TypeScript's control flow narrowing
// from the pWaitFor callback, which incorrectly narrows these
// properties to 'never' in this branch.
const pendingText = this.askResponseText as string | undefined
const pendingImages = this.askResponseImages as string[] | undefined
if (this.askResponse === "messageResponse" && (pendingText?.trim() || pendingImages?.length)) {
this.messageQueueService.addMessage(pendingText || "", pendingImages)
}
// Clear response fields to prevent stale data affecting subsequent asks
this.askResponse = undefined
this.askResponseText = undefined
this.askResponseImages = undefined
throw new AskIgnoredError("superseded")
}