Skip to content

fix: /queue now supports multiple queued messages via FIFO - #7707

Closed
willy-scr wants to merge 1 commit into
NousResearch:mainfrom
willy-scr:fix/queue-fifo
Closed

fix: /queue now supports multiple queued messages via FIFO#7707
willy-scr wants to merge 1 commit into
NousResearch:mainfrom
willy-scr:fix/queue-fifo

Conversation

@willy-scr

Copy link
Copy Markdown
Contributor

Bug

/queue only stores one message per session. Sending /queue prompt A then /queue prompt B silently overwrites A — only B is ever processed.

Root Cause

_pending_messages is typed as Dict[str, MessageEvent] — a single value per session key. Every write (via /queue, interrupt follow-ups, or sentinel buffering) overwrites the previous entry:

adapter._pending_messages[_quick_key] = queued_event  # overwrites!

Fix

Change the data structure to a FIFO queue:

# Before
self._pending_messages: Dict[str, MessageEvent] = {}

# After  
self._pending_messages: Dict[str, list[MessageEvent]] = {}

Changes

gateway/platforms/base.py:

  • _pending_messages type: Dict[str, MessageEvent]Dict[str, list[MessageEvent]]
  • merge_pending_message_event(): appends to list (photo bursts merge into last entry)
  • get_pending_message(): pops first item (FIFO)
  • Drain loop in _process_message_background: pops first from queue, processes it, then checks if more remain

gateway/run.py:

  • /queue handler: adapter._pending_messages[key] = event.setdefault(key, []).append(event)
  • /stop and /new: drain entire queue instead of popping one
  • Sentinel buffering: same append pattern

Testing

  1. Send a long-running prompt to the agent
  2. While processing, send /queue task A
  3. Then /queue task B
  4. Then /queue task C
  5. Before fix: Only task C is processed (A and B silently lost)
  6. After fix: task A → task B → task C processed in order, one at a time

Backward Compatibility

Photo burst merging still works — consecutive PHOTO events merge into the last queue entry instead of a single slot. No behavioral change for single-message queues.

The pending message store was Dict[str, MessageEvent] — one message per
session. Sending /queue twice overwrote the first message. Only the last
queued prompt was ever processed.

Changes:
- _pending_messages: Dict[str, MessageEvent] → Dict[str, list[MessageEvent]]
- merge_pending_message_event() appends to list (photo bursts merge into last entry)
- get_pending_message() pops first item (FIFO)
- /queue handler appends instead of overwriting
- /stop and /new drain the entire queue instead of just one item
- Normal interrupt follow-ups also append (no overwrite)
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the thorough write-up and the clean fix, @willy-scr! This automated hermes-sweeper review found that the same bug was independently addressed on main before this PR could be merged.

  • Commit 1dfcc2ffcfix(gateway): /queue is now a true FIFO — each invocation gets its own turn (fix(gateway): /queue is now a true FIFO — each invocation gets its own turn #16175) — landed the FIFO fix via _enqueue_fifo / _promote_queued_event / _queued_events in gateway/run.py.
  • The /queue handler (line 3533) now calls self._enqueue_fifo(...) instead of the bare dict assignment you identified.
  • _queue_depth() (line 1280) tracks slot + overflow depth and is surfaced to the user on subsequent /queue calls.

Main's implementation kept _pending_messages: Dict[str, MessageEvent] in base.py unchanged and added an overflow list at the GatewayServer level, rather than changing the base type — a slightly different approach, but the observable bug (silent overwrite of earlier queued messages) is fixed. Closing as implemented on main.

@teknium1 teknium1 closed this Apr 27, 2026
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.

2 participants