From c6b866c9dd36d4e8df34318afed21e7a4d496f39 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Wed, 28 Jan 2026 19:36:36 +0000 Subject: [PATCH] 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 --- src/core/task/Task.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index ff697d77a8..10efcd29e9 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -1473,6 +1473,25 @@ export class Task extends EventEmitter 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") }