Skip to content

fix(tui): clean force-send of queued messages#40235

Merged
OutThisLife merged 1 commit into
mainfrom
bb/tui-queue-force-send
Jun 6, 2026
Merged

fix(tui): clean force-send of queued messages#40235
OutThisLife merged 1 commit into
mainfrom
bb/tui-queue-force-send

Conversation

@OutThisLife

Copy link
Copy Markdown
Collaborator

Summary

Force-sending a queued TUI message (double-empty-enter, or interrupt-mode submit) was janky: interruptTurn flipped busy → false optimistically, so the queue drain raced the still-unwinding turn. That race produced a duplicate user bubble, a stray queued: "…" note, and the cancelled turn's Operation interrupted: waiting for model response reply leaking into the transcript.

  • turnController.interruptTurn gains a keepBusy option — hold busy until the gateway's real settle edge (message.complete, suppressed while interrupted), so the queued message drains exactly once. Mirrors the desktop "send now" flow.
  • The interrupt paths (handleBusyInput 'interrupt' branch + the submit double-empty-enter force-send) now queue + interrupt instead of optimistically send-ing. Plain Stop (empty queue) is unchanged → settles to ready.

Result: [old turn] → interrupted → one user bubble → new turn. Queue editing is untouched.

Test plan

  • Added a keepBusy invariant test (createGatewayEventHandler.test.ts): busy held after interrupt; cancelled turn's final_response suppressed; settle flips busy false.
  • createGatewayEventHandler + useQueue suites pass (58).
  • Manual: start a turn, type while busy (lands in queue panel), double-Enter to force → no duplicate bubble / queued: note / backend interrupt line.

Force-sending a queued message (double-empty-enter, or interrupt-mode
submit) flipped busy→false optimistically, so the queue drain raced the
still-unwinding turn: duplicate user bubble, a stray "queued: …" note, and
the cancelled turn's "Operation interrupted…" reply leaking in.

interruptTurn gains `keepBusy`: hold busy until the gateway's real settle
edge (message.complete, suppressed while interrupted), which drains the
queued message exactly once — desktop "send now" parity. The interrupt
paths now queue + interrupt instead of optimistically sending.
@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: bb/tui-queue-force-send vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9870 on HEAD, 9870 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 5119 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@OutThisLife OutThisLife enabled auto-merge (squash) June 6, 2026 01:36
@OutThisLife OutThisLife merged commit e375c33 into main Jun 6, 2026
20 checks passed
@OutThisLife OutThisLife deleted the bb/tui-queue-force-send branch June 6, 2026 01:39
changman pushed a commit to changman/hermes-agent that referenced this pull request Jun 10, 2026
Force-sending a queued message (double-empty-enter, or interrupt-mode
submit) flipped busy→false optimistically, so the queue drain raced the
still-unwinding turn: duplicate user bubble, a stray "queued: …" note, and
the cancelled turn's "Operation interrupted…" reply leaking in.

interruptTurn gains `keepBusy`: hold busy until the gateway's real settle
edge (message.complete, suppressed while interrupted), which drains the
queued message exactly once — desktop "send now" parity. The interrupt
paths now queue + interrupt instead of optimistically sending.
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