Skip to content

fix: prevent interrupt mode from replaying previous assistant reply#1026

Open
BingqingLyu wants to merge 1 commit into
mainfrom
fork-pr-50147-fix-interrupt-abort-replay-old-reply
Open

fix: prevent interrupt mode from replaying previous assistant reply#1026
BingqingLyu wants to merge 1 commit into
mainfrom
fork-pr-50147-fix-interrupt-abort-replay-old-reply

Conversation

@BingqingLyu

@BingqingLyu BingqingLyu commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Fixes openclaw#50145

Problem

When messages.queue.mode is set to "interrupt", incoming messages that abort an active run cause the previous turn's assistant reply to be re-sent to the user before the new (correct) reply is delivered.

Root Cause

buildEmbeddedRunPayloads falls back to extractAssistantText(lastAssistant) when assistantTexts is empty. After an abort, assistantTexts is empty (model never generated new text), but lastAssistant still references the previous turn's message from messagesSnapshot (full session history). This stale text gets packaged as the current run's output and delivered to the user.

Fix

Two changes (defense in depth):

1. Guard lastAssistant fallback (run.ts)

When the run was aborted and produced no new assistant text, pass undefined instead of the stale lastAssistant:

lastAssistant:
  aborted && attempt.assistantTexts.length === 0 ? undefined : attempt.lastAssistant,

2. Early exit for aborted runs (agent-runner.ts)

  • Skip blockReplyPipeline.flush() when aborted (buffer may contain stale content)
  • Return early before payload delivery when wasAborted is true
const wasAborted = runResult.meta?.aborted === true;

if (blockReplyPipeline) {
  if (!wasAborted) {
    await blockReplyPipeline.flush({ force: true });
  }
  blockReplyPipeline.stop();
}

// ...

if (wasAborted) {
  return finalizeWithFollowup(undefined, queueKey, runFollowupTurn);
}

Testing

  1. Set messages.queue.mode: "interrupt"
  2. Send message A, then quickly send message B before A completes
  3. Verify: only one reply is delivered (combining context from both A and B), no stale replay of previous conversation

When messages.queue.mode is 'interrupt', aborting an active run causes
the previous turn's assistant reply to be re-sent to the user.

Root cause: buildEmbeddedRunPayloads falls back to
extractAssistantText(lastAssistant) when assistantTexts is empty.
After an abort, assistantTexts is empty but lastAssistant still
references the previous turn's message from session history.

Fix:
1. Guard lastAssistant fallback: pass undefined when aborted and no
   new assistant text was generated (run.ts)
2. Skip blockReplyPipeline flush and payload delivery entirely when
   the run was aborted (agent-runner.ts)

Fixes openclaw#50145
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

interrupt queue mode replays previous assistant reply after abort

1 participant