Skip to content

feat: Alt+Enter queues follow-up messages without interrupting agent#4788

Open
iRonin wants to merge 5 commits into
NousResearch:mainfrom
iRonin:feat/queue-followup
Open

feat: Alt+Enter queues follow-up messages without interrupting agent#4788
iRonin wants to merge 5 commits into
NousResearch:mainfrom
iRonin:feat/queue-followup

Conversation

@iRonin

@iRonin iRonin commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Repurposes Alt+Enter from 'insert newline' to 'queue follow-up message'.

Behaviour:

  • Enter (agent running) → interrupts/steers current response (unchanged)
  • Alt+Enter → queues message into _pending_input — sent as the next turn, no interruption
  • Ctrl+J → inserts newline for multi-line input (unchanged, was already bound)

UI feedback:

  • Status bar shows 📬 N when follow-ups are queued
  • Placeholder while agent runs: Enter to interrupt · Alt+Enter to queue follow-up · 📬 N queued
  • Placeholder while idle with queue: 📬 N follow-ups queued — Alt+Enter to add more

Implementation:

  • _followup_queue list mirrors _pending_input for display (popped in process_loop as messages are consumed)
  • Alt+Enter never interrupts regardless of busy_input_mode config

@britrik

britrik commented Apr 3, 2026

Copy link
Copy Markdown

Code Review: Alt+Enter Queue Feature

Thanks for this useful feature! I've reviewed the diff and found a few issues to address:

Critical Bugs

  1. Cancel detection fails for messages with images (line ~7750):

    • In , payload can be either or tuple
    • In , only the text is added to
    • In , the check fails when payload is a tuple because it compares the tuple against a string
  2. Duplicate text causes incorrect cancellation (line ~7711):

    • If two different follow-up messages have identical text, recalling one will incorrectly cancel both since cancellation uses simple string matching

Potential Issues

  1. **Memory leak in ** (line ~7711):

    • The set grows indefinitely as users recall messages
    • It only gets cleared when a matching item is dequeued, but if messages are consumed without matching (e.g., different payloads), the set leaks
  2. Empty text queued with images (line ~6739):

    • When is empty but exists, the message is still queued with empty string
    • Consider requiring non-empty text, or document this is intentional

Minor Suggestions

  1. Status bar emoji compatibility (line ~1582):

    • The 📬 emoji may not render in all terminals; consider a text fallback like or
  2. Use a more robust identifier for cancellation:

    • Consider using an incrementing ID or UUID per queued message instead of text for cancellation tracking

Overall

The feature is well-implemented with good UX feedback (status bar, placeholder text). The above issues are edge cases but should be fixed before merge.

@iRonin

iRonin commented Apr 3, 2026

Copy link
Copy Markdown
Contributor Author

@britrik thank you for review! I was not sure how busy you are but I started using Hermes yesterday and I asked it to add a couple of features from Claude Code and Pi that I missed and it cranked the first PR without even asking lol
we're cooked! so good! I love it! great job!
I also use it extensively for legal drafting besides coding.
Will pass your review or ask it to check it itself.

@iRonin

iRonin commented Apr 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @britrik — great review. Pushed a fix commit (f02bcb1):

#1 & #3 (duplicate text / set leak) — fixed with UUID tags. Alt+Enter now wraps each payload as {"_followup_tag": uuid, "payload": ...}. Cancellation stores and matches UUIDs, so two identical messages never cancel each other, and the set is strictly bounded (one UUID per queued message, discarded on match).

Phantom queue pops — also fixed. The display sync (_followup_queue.pop(0)) now only fires for tagged items, not for regular Enter messages. Previously every item dequeued from _pending_input would pop the display mirror, including non-followup messages.

#1 (image payload cancel) — was already correct. Both the queuing side and the process_loop side extracted text via payload[0] if isinstance(payload, tuple), so image payloads were handled correctly. The UUID approach makes this moot regardless.

#4 (empty text + images) — intentional. Allows queuing an image-only message (attach image, no text, Alt+Enter). Documented in the commit.

#5 (emoji fallback) — not changing. The 📬 emoji is used consistently with other indicators already in the codebase (📌 for stash, etc.).

@iRonin iRonin force-pushed the feat/queue-followup branch from f02bcb1 to 5ed3e5d Compare April 3, 2026 19:44
iRonin added a commit to iRonin/hermes-agent-nous that referenced this pull request Apr 3, 2026
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/queue-followup branch from 5ed3e5d to d75001f Compare April 4, 2026 19:15
@iRonin iRonin force-pushed the feat/queue-followup branch from d75001f to ce7fa7b Compare April 4, 2026 22:00
iRonin added a commit to iRonin/hermes-agent-nous that referenced this pull request Apr 4, 2026
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 added a commit to iRonin/hermes-agent-nous that referenced this pull request Apr 4, 2026
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 added a commit to iRonin/hermes-agent-nous that referenced this pull request Apr 9, 2026
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 added a commit to iRonin/hermes-agent-nous that referenced this pull request Apr 11, 2026
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 added 5 commits April 11, 2026 16:31
Alt+Enter now queues the current input as a follow-up to be sent after
the agent finishes responding, instead of inserting a newline.

- Alt+Enter → puts message into _pending_input (non-interrupting)
- Enter (agent running) → still interrupts via _interrupt_queue
- _followup_queue list mirrors pending items for display
- Status bar shows 📬 N when follow-ups are queued
- Placeholder hints update: shows queue depth while agent runs,
  and persists after it finishes until queue drains
- Ctrl+J remains the newline key for multi-line input

Closes: the need for Shift+Enter queue (terminals can't distinguish
Shift+Enter from Enter; Alt+Enter is the reliable alternative)
Alt+Up pops the most recently queued follow-up (LIFO) from
_followup_queue, appends it to the current input with a newline---
separator, and marks it cancelled so process_loop skips it.

Repeated Alt+Up recalls one at a time until queue is empty.
_cancelled_followups set is checked in process_loop and discarded
on match to avoid sending the recalled message twice.
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/queue-followup branch from 5b53c08 to ad9b4c8 Compare April 11, 2026 20:37
iRonin added a commit to iRonin/hermes-agent-nous that referenced this pull request Apr 12, 2026
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 added a commit to iRonin/hermes-agent-nous that referenced this pull request Apr 12, 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
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #5504 / #8492 — same Alt+Enter follow-up queue feature.

@alt-glitch alt-glitch added the duplicate This issue or pull request already exists label May 1, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #5504 / #8492 — same Alt+Enter follow-up queue feature.

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 duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants