Skip to content

system_interface: guard interrupt-and-send against concurrent restarts#170

Draft
pseay-imbue wants to merge 1 commit into
mainfrom
mngr/frontend-guard-interrupt-resend
Draft

system_interface: guard interrupt-and-send against concurrent restarts#170
pseay-imbue wants to merge 1 commit into
mainfrom
mngr/frontend-guard-interrupt-resend

Conversation

@pseay-imbue

Copy link
Copy Markdown

Problem

In the chat web UI, a queued message exposes an "interrupt and send" action (interruptAndResend in PendingMessageView.ts), which restarts the agent and then re-sends the message. Each queued message bubble renders its own button, and interruptAndResend had no per-agent in-flight guard. With multiple queued messages, triggering the action on more than one fires several interrupt+send sequences concurrently against the same agent. The overlapping restarts repeatedly tear down and re-spawn the agent, so a send from one sequence lands while another's restart is mid-flight, producing:

Failed to interrupt and send to agent : Failed to send message to agent '' (0 successful agents)

MessageInput.ts's handleInterrupt already guards against this with isInterruptInFlight; interruptAndResend was missing the equivalent.

Fix

Add a per-agent in-flight guard to interruptAndResend:

  • Module-level const interruptResendInFlight = new Set<string>().
  • Return early (no-op) if the agentId is already in the set; otherwise add it and remove it in a finally, so the guard clears on both success and error.
  • Existing optimistic-bubble logic (markPendingMessageSending / markPendingMessageQueued / removePendingMessage / failure alert) is unchanged.

Tests

Added three tests to PendingMessageView.test.ts: a held/deferred interruptAgent proves a second concurrent resend for the same agent is a no-op (interruptAgent/sendMessage each called once), plus two asserting the guard clears after success and after failure so a later resend still runs.

Checks (from apps/system_interface/frontend): npm test 153 passed / 0 failed; npm run lint clean; npm run format:check clean.

Scope / follow-ups

  • This is the web UI half of a two-part fix. The deeper fix to the mngr send path (waiting for the agent's TUI to be ready before sending) is being made separately against the mngr repo.
  • Out of scope: "resend all queued messages after one interrupt" (a restart clears the agent's queue, so only the resent message survives) remains a possible future enhancement.

🤖 Generated with Claude Code

Each queued-message bubble renders its own "interrupt and send" button, and
interruptAndResend had no per-agent in-flight guard. Triggering the action on
several queued messages at once fired overlapping restarts of the same agent;
a send from one sequence landed mid-restart of another, failing with
"0 successful agents".

Add a module-level per-agent in-flight set: interruptAndResend now returns
early if a resend is already running for that agent, and releases the guard in
a finally so it clears on success and error alike. Mirrors MessageInput's
isInterruptInFlight guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant