Skip to content

feat: dual queue — follow-up (Alt+Enter) + steering (Enter/queue mode) - #5319

Open
iRonin wants to merge 4 commits into
NousResearch:mainfrom
iRonin:feat/dual-queue-v2
Open

feat: dual queue — follow-up (Alt+Enter) + steering (Enter/queue mode)#5319
iRonin wants to merge 4 commits into
NousResearch:mainfrom
iRonin:feat/dual-queue-v2

Conversation

@iRonin

@iRonin iRonin commented Apr 5, 2026

Copy link
Copy Markdown
Contributor

Two independent message queues for interacting with a running agent:

📬 Follow-up queue (Alt+Enter)

Queue messages to send after the current response completes, without interrupting.

  • Alt+Up recalls queued follow-ups back into the input buffer (LIFO)
  • Status bar shows 📬 N count

🎯 Steering queue (Enter in queue mode)

Queue mid-run steering messages that are dispatched at the earliest opportunity.

  • Steering always takes priority over follow-up
  • Follow-up only dispatched when steering queue is empty
  • Status bar shows 🎯 N count

Configuration

display:
  busy_input_mode: queue          # Enter queues steering instead of interrupting
  steering_dispatch: one_by_one   # or all_at_once — combine into one turn
  followup_dispatch: one_by_one   # or all_at_once

Queue persistence

Both queues are saved to disk between turns and survive crashes. On resume (hermes -c or /resume), pending items are restored.

iRonin added 4 commits April 11, 2026 14:42
Both queues now hold in their list only — _pending_input is fed
exclusively by the post-turn drain, enforcing strict priority:

  1. After each turn: dispatch steering queue first (one_by_one or
     all_at_once per config). Follow-up is skipped this turn.
  2. Only when steering queue is empty: dispatch follow-up queue.

Previously, one_by_one items went directly to _pending_input at
keypress time, so follow-ups queued before a steering message would
be processed first (FIFO). Now both queues are always deferred and
the drain decides order.

Follow-up when agent is idle still sends immediately (no deferral
needed when nothing is running to steer).
display.steering_dispatch: all_at_once | one_by_one (default)
display.followup_dispatch: one_by_one (default) | all_at_once

all_at_once: items held in the queue list only until the current
agent turn completes, then drained and joined with \n---\n into
a single combined message for the next turn.

one_by_one: existing behaviour — each queued item goes straight
into _pending_input and triggers its own agent turn.
Addresses review feedback from britrik (NousResearch#4788):

- Replace text-based cancellation with UUID tags — identical messages
  queued twice no longer cancel each other incorrectly
- Wrap Alt+Enter payloads as {_followup_tag, payload} dicts so
  process_loop can identify followup items by ID, not content
- Fix phantom _followup_queue pops: display sync now only happens
  for tagged (Alt+Enter) items, not regular Enter messages
- _cancelled_followups stores UUIDs (bounded, auto-discarded on match)

Note: the image-payload cancel check was already correct in the original
— both sides extracted text via payload[0] — but UUID tagging makes the
intent unambiguous regardless of payload shape.
@iRonin
iRonin force-pushed the feat/dual-queue-v2 branch from bbf9c4a to 4b884f5 Compare April 11, 2026 18:45
@iRonin iRonin changed the title feat: dual queue — 📬 follow-up (Alt+Enter) + 🎯 steering (Enter/queue mode) feat: dual queue — follow-up (Alt+Enter) + steering (Enter/queue mode) Apr 11, 2026
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard labels May 1, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the work on busy-input queueing. The submitted head needs substantial reconstruction before its implementation can be evaluated.

Problems

  • The PR head conflicts with its stated behavior: cli.py:1480 only recognizes queue and interrupt, while cli.py:7732 keeps Alt+Enter as a multiline-newline binding. The advertised follow-up and steering queues are not present in the inspected head.
  • The patch is against an old cli.py snapshot and includes unrelated reversions/removals. Current main already routes busy input at cli.py:13502-13531 and drains interrupted input at cli.py:15295-15302.
  • No tests accompany the claimed ordering, cancellation, persistence, or resume guarantees.

Suggested changes

  • Rebuild the feature from current main, preserving the existing busy-input and drain paths.
  • Add coverage for priority, dispatch modes, cancellation, and resume persistence.
  • Clarify whether this is classic-CLI-only or should align with the existing TUI FIFO queue (ui-tui/src/hooks/useQueue.ts:15-41).

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants