Skip to content

fix(notifications): event-driven TUI adapter, interrupt wait, queue drain - #36089

Open
someaka wants to merge 1 commit into
NousResearch:mainfrom
someaka:fix/notification-double-delivery
Open

fix(notifications): event-driven TUI adapter, interrupt wait, queue drain#36089
someaka wants to merge 1 commit into
NousResearch:mainfrom
someaka:fix/notification-double-delivery

Conversation

@someaka

@someaka someaka commented May 31, 2026

Copy link
Copy Markdown

Three fixes for notification delivery and TUI input handling:

Changes

1. Gateway: await interrupt (tui_gateway/server.py)

session.interrupt now waits up to 5s for session['running'] to become False before returning. Previously it returned immediately while the agent was still running, causing prompt.submit to hit 'session busy'. Also added to _LONG_HANDLERS so the wait runs on the thread pool.

2. TUI: await interrupt before send (ui-tui/src/app/useSubmission.ts)

handleBusyInput now awaits the session.interrupt promise before calling send(). Previously it fired interrupt and send simultaneously, creating a race where the submit arrived before the gateway processed the cancel.

3. TUI: drain queue on enqueue (ui-tui/src/app/useMainApp.ts)

The drain useEffect now watches queuedDisplay.length so it re-fires when a message is enqueued after the drain already ran with an empty queue.

4. TUI: interruptTurn returns promise (ui-tui/src/app/turnController.ts)

interruptTurn() now returns the interrupt promise instead of fire-and-forget.

Also includes

  • Event-driven TUI platform adapter (HTTP POST, no polling)
  • Kanban→TUI notification bridge
  • Deduplication of file watcher events and adapter subscriptions
  • Test fix for always-on TUI adapter in startup failure tests

Testing

  • Spam test: rapid user messages no longer get 'queued:' — interrupt waits for agent to stop before accepting new input
  • Kanban notification: task completion → worker → notification delivers to TUI session
  • CI: fork CI green

@alt-glitch alt-glitch added type/bug Something isn't working comp/tui Terminal UI (ui-tui/ + tui_gateway/) comp/gateway Gateway runner, session dispatch, delivery tool/terminal Terminal execution and process management P2 Medium — degraded but workaround exists labels May 31, 2026

@mxnstrexgl mxnstrexgl left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — automated review passed. No security, quality, or test coverage issues detected.

@someaka
someaka force-pushed the fix/notification-double-delivery branch 3 times, most recently from e7e676e to 23ec095 Compare June 8, 2026 22:21
…rain

Three fixes for notification delivery and TUI input handling:

1. **Gateway: await interrupt** — session.interrupt now waits up to 5s for
   session['running'] to become False before returning. Previously it
   returned immediately while the agent was still running, causing
   prompt.submit to hit 'session busy'.

2. **TUI: await interrupt before send** — handleBusyInput now awaits the
   session.interrupt promise before calling send(). Previously it fired
   interrupt and send simultaneously, creating a race where the submit
   arrived before the gateway processed the cancel.

3. **TUI: drain queue on enqueue** — the drain useEffect now watches
   queuedDisplay.length so it re-fires when a message is enqueued after
   the drain already ran with an empty queue.

Also includes:
- Event-driven TUI platform adapter (HTTP POST, no polling)
- Kanban→TUI notification bridge in tui_gateway
- Deduplication of file watcher events and adapter subscriptions
- Test fix for always-on TUI adapter in startup failure tests
- session.interrupt added to _LONG_HANDLERS for thread pool dispatch
@someaka
someaka force-pushed the fix/notification-double-delivery branch from 23ec095 to e70d093 Compare June 9, 2026 00:57

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracing the TUI queue and notification paths. A narrow current-main race is still worth salvaging: session.steer fallback enqueues asynchronously in ui-tui/src/app/useSubmission.ts:199-208, while the drain effect at ui-tui/src/app/useMainApp.ts:700-716 does not depend on queuedDisplay; the PR's dependency addition addresses that.

Problems

  • gateway/platforms/tui_adapter.py:78 reports success even when _post_event() swallowed a missing-port or HTTP failure. gateway/kanban_watchers.py:415-470 retries only exceptions, so this can silently lose a claimed notification.
  • Current main deliberately queues and uses keepBusy to avoid racing a still-unwinding turn (ui-tui/src/app/turnController.ts:291-338), and prompt.submit now queues a running session rather than rejecting it (tui_gateway/server.py:8447-8452). Replacing that path with send-after-interrupt would discard newer race handling.

Suggested changes

  • Salvage the queue-effect dependency with a regression test covering async steer fallback after busy becomes false.
  • Retain main's queue/settle protocol; make any adapter failure observable to the notifier.

Automated hermes-sweeper review.

chat_id: str,
content: str,
reply_to: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_post_event() catches missing-port and HTTP failures, so this always returns success even when nothing was delivered. The kanban watcher retries only thrown adapter.send() failures; propagate a failure/exception here so its cursor can be rewound instead of silently dropping the notification.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state tool/terminal Terminal execution and process management type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants