hermes - ✅(Solved) Fix Bug: busy_input_mode: queue silently drops messages — single-slot overwrite instead of FIFO [5 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#28503Fetched 2026-05-20 04:03:31
View on GitHub
Comments
1
Participants
2
Timeline
10
Reactions
0
Timeline (top)
cross-referenced ×6labeled ×3commented ×1

When busy_input_mode: queue is configured, Hermes is supposed to queue incoming messages while the agent is busy. However, the implementation uses a single-slot dictionary (_pending_messages[session_key]) that overwrites previous messages rather than appending them to a FIFO queue. This causes silent message loss when users send multiple messages rapidly while the agent is processing. Environment Hermes Agent version: latest (installed from NousResearch/hermes-agent.git) Platform: WeChat (Weixin) gateway, also affects all platforms Config: display.busy_input_mode: queue Steps to Reproduce Configure busy_input_mode: queue in config.yaml Send a message to the agent (triggers a long-running task) While the agent is busy, send messages 2, 3, 4, 5 rapidly Wait for the agent to finish the current task Result: The agent only processes the last message (message 5). Messages 2, 3, 4 are silently lost. Root Cause Analysis The single-slot design In gateway/platforms/base.py:1092: def merge_pending_message_event( pending_messages: Dict[str, MessageEvent], session_key: str, event: MessageEvent, *, merge_text: bool = False, ) -> None: # ... photo burst and media merge logic ...

# Plain TEXT messages with merge_text=False: REPLACE, not append
pending_messages[session_key] = event  # ← OVERWRITES previous

The pending_messages dict is keyed by session_key — it holds one event per session, not a list. Queue mode path doesn't enable text merging In gateway/run.py:5210-5212: if self._busy_input_mode == "queue": logger.debug("PRIORITY queue follow-up for session %s", _quick_key) self._queue_or_replace_pending_event(_quick_key, event) # ← calls merge WITHOUT merge_text return None _queue_or_replace_pending_event calls merge_pending_message_event with the default merge_text=False, so plain text messages are replaced, not appended. Inconsistent: one path DOES merge text In gateway/run.py:5175-5180 (agent-starting sentinel path): merge_pending_message_event( adapter._pending_messages, _quick_key, event, merge_text=True, # ← Only this path enables text merging ) This inconsistency suggests the single-slot design was intended for photo bursts only, and queue mode was later layered on top without converting to a true FIFO. Expected Behavior All queued messages should be preserved and processed sequentially (FIFO) after the agent finishes the current task. Suggested Fix Two possible approaches: Option A: Enable merge_text=True for queue mode (quick fix) In gateway/run.py:5210-5212, pass merge_text=True: if self._busy_input_mode == "queue": merge_pending_message_event( adapter._pending_messages, _quick_key, event, merge_text=True ) return None This would concatenate text messages with newlines, so they're all processed in one turn. Not perfect FIFO (they become one combined message), but at least no data loss. Option B: Convert to real FIFO queue (proper fix) Change _pending_messages from Dict[str, MessageEvent] to Dict[str, List[MessageEvent]] (or collections.deque), and process them one by one after the agent finishes. This preserves message boundaries and enables true sequential processing. Workaround Users can mitigate by: Sending all content in a single message (newline-separated) Waiting for the agent to respond before sending the next message For link collection workflows: writing links to a file and processing them in batch

Impact This is particularly painful for messaging platforms (WeChat, Telegram) where rapid-fire message sending is normal user behavior. Users have no indication that messages were lost — no warning, no error, just silent data disappearance.

Error Message

This is particularly painful for messaging platforms (WeChat, Telegram) where rapid-fire message sending is normal user behavior. Users have no indication that messages were lost — no warning, no error, just silent data disappearance.

Root Cause

Summary When busy_input_mode: queue is configured, Hermes is supposed to queue incoming messages while the agent is busy. However, the implementation uses a single-slot dictionary (_pending_messages[session_key]) that overwrites previous messages rather than appending them to a FIFO queue. This causes silent message loss when users send multiple messages rapidly while the agent is processing. Environment Hermes Agent version: latest (installed from NousResearch/hermes-agent.git) Platform: WeChat (Weixin) gateway, also affects all platforms Config: display.busy_input_mode: queue Steps to Reproduce Configure busy_input_mode: queue in config.yaml Send a message to the agent (triggers a long-running task) While the agent is busy, send messages 2, 3, 4, 5 rapidly Wait for the agent to finish the current task Result: The agent only processes the last message (message 5). Messages 2, 3, 4 are silently lost. Root Cause Analysis The single-slot design In gateway/platforms/base.py:1092: def merge_pending_message_event( pending_messages: Dict[str, MessageEvent], session_key: str, event: MessageEvent, *, merge_text: bool = False, ) -> None: # ... photo burst and media merge logic ...

Fix Action

Fix / Workaround

Plain TEXT messages with merge_text=False: REPLACE, not append

pending_messages[session_key] = event  # ← OVERWRITES previous

The pending_messages dict is keyed by session_key — it holds one event per session, not a list. Queue mode path doesn't enable text merging In gateway/run.py:5210-5212: if self._busy_input_mode == "queue": logger.debug("PRIORITY queue follow-up for session %s", _quick_key) self._queue_or_replace_pending_event(_quick_key, event) # ← calls merge WITHOUT merge_text return None _queue_or_replace_pending_event calls merge_pending_message_event with the default merge_text=False, so plain text messages are replaced, not appended. Inconsistent: one path DOES merge text In gateway/run.py:5175-5180 (agent-starting sentinel path): merge_pending_message_event( adapter._pending_messages, _quick_key, event, merge_text=True, # ← Only this path enables text merging ) This inconsistency suggests the single-slot design was intended for photo bursts only, and queue mode was later layered on top without converting to a true FIFO. Expected Behavior All queued messages should be preserved and processed sequentially (FIFO) after the agent finishes the current task. Suggested Fix Two possible approaches: Option A: Enable merge_text=True for queue mode (quick fix) In gateway/run.py:5210-5212, pass merge_text=True: if self._busy_input_mode == "queue": merge_pending_message_event( adapter._pending_messages, _quick_key, event, merge_text=True ) return None This would concatenate text messages with newlines, so they're all processed in one turn. Not perfect FIFO (they become one combined message), but at least no data loss. Option B: Convert to real FIFO queue (proper fix) Change _pending_messages from Dict[str, MessageEvent] to Dict[str, List[MessageEvent]] (or collections.deque), and process them one by one after the agent finishes. This preserves message boundaries and enables true sequential processing. Workaround Users can mitigate by: Sending all content in a single message (newline-separated) Waiting for the agent to respond before sending the next message For link collection workflows: writing links to a file and processing them in batch

PR fix notes

PR #28529: feat(telegram): support quick-command-only menus

Description (problem / solution / changelog)

Salvage of #28015 (@stevehq26-bot). Adds opt-in Telegram command menu mode for specialist profile bots: telegram.command_menu: quick_commands_only publishes only profile-defined quick_commands instead of the default 30-command core menu. Individual quick commands can opt out via show_in_telegram_menu: false.

Conflict resolution: combined with #28503's multi-scope registration (#27014 just merged) — keeps multi-scope semantics AND adds the quick-only toggle. Replaced the PR's self._config.quick_commands access with a runner-ref + PlatformConfig.extra fallback chain since PlatformConfig doesn't carry quick_commands directly (that lives on GatewayConfig).

Authorship preserved via cherry-pick. 46/46 thread + forum-commands tests passing.

Changed files

  • gateway/config.py (modified, +1/-1)
  • gateway/platforms/telegram.py (modified, +19/-2)
  • hermes_cli/commands.py (modified, +36/-0)
  • scripts/release.py (modified, +1/-0)
  • tests/gateway/test_config.py (modified, +19/-0)
  • tests/hermes_cli/test_commands.py (modified, +42/-0)
  • website/docs/reference/slash-commands.md (modified, +5/-0)
  • website/docs/user-guide/configuration.md (modified, +22/-0)

PR #28531: fix(telegram): handle channel post updates

Description (problem / solution / changelog)

Salvage of #25327 (@brndnsvr). Routes Telegram handlers through effective_message so channel_post updates build gateway events instead of being silently ignored. Preserves channel identity for channel posts without from_user so operators can allowlist by chat id.

Conflict resolution: combined with #28503 (#27014 forum-commands) — both add new methods on TelegramAdapter; kept both.

Authorship preserved across 2 commits via cherry-pick. 3/3 channel-post tests passing. Follow-up commit stubs auth in the test fixture (channel posts have from_user=None and were getting rejected by #28494's fail-closed gate).

Changed files

  • gateway/platforms/telegram.py (modified, +43/-16)
  • scripts/release.py (modified, +1/-0)
  • tests/gateway/test_telegram_channel_posts.py (added, +181/-0)

PR #28536: feat(telegram): add ignore_root_dm config to drop messages without thread_id

Description (problem / solution / changelog)

Salvage of #23928 (@ai-hana-ai). When dm_topics are configured, root DM messages without a message_thread_id cause split sessions and user confusion. New telegram.ignore_root_dm config drops these messages silently so all conversation flows through named topic threads.

Conflict resolution: combined with #28492's allowlist enforcement and #28503's allowed_topics gate. All gates run in sequence: auth → allowed_topics → ignore_root_dm → ignored_threads.

Authorship preserved across 2 commits via cherry-pick. 68/68 topic + group-gating tests passing.

Changed files

  • gateway/platforms/telegram.py (modified, +20/-0)
  • scripts/release.py (modified, +1/-0)
  • website/docs/user-guide/messaging/telegram.md (modified, +23/-1)

PR #28551: fix(gateway): busy_input_mode queue uses FIFO instead of single-slot overwrite

Description (problem / solution / changelog)

Summary

When busy_input_mode: queue is configured, rapid follow-up messages sent while the agent is busy were silently lost — only the last message was preserved because merge_pending_message_event() was overwriting the single pending slot instead of appending to a FIFO queue.

The gateway already has a proper FIFO implementation (_enqueue_fifo with slot + overflow list), but the busy message path was bypassing it.

Root cause

gateway/run.py line 2887:

# Before (bug): replaces slot → loses all intermediate messages
merge_pending_message_event(adapter._pending_messages, session_key, event)

# After (fix): uses FIFO → appends to overflow when slot occupied
self._enqueue_fifo(session_key, event, adapter)

Behavior change

ScenarioBeforeAfter
User sends msg1, then msg2-5 rapidlyOnly msg5 preservedmsg1 processed, msg2-5 queued in FIFO
Overflow after drainN/APromotes msg2 to slot for next turn

Changes

  • gateway/run.py — 1-line change
  • tests/gateway/test_busy_input_queue.py — 4 tests

Testing

  • tests/gateway/test_busy_input_queue.py — 4/4 passed
  • tests/gateway/test_steer_command.py — 5/5 passed (regression)
  • Full suite: 5627 passed, 28 failed (pre-existing unrelated failures)

Upstream gap discovered

Issue #14905 (busy_input_mode: queue only works during drain, not normal task execution) has the same root cause and no competing PR. This fix addresses both issues.

Closes #28503

Changed files

  • gateway/run.py (modified, +1/-1)
  • tests/gateway/test_busy_input_queue.py (added, +207/-0)

PR #28606: fix(gateway): pass merge_text=True in queue mode to prevent silent message drops (#28503)

Description (problem / solution / changelog)

Problem

When busy_input_mode: queue is configured, users who send multiple messages rapidly while the agent is processing only see their last message acted on. All previous messages are silently discarded.

Root cause: _queue_or_replace_pending_event called merge_pending_message_event without merge_text=True, so the plain-text path fell through to a single-slot assignment:

pending_messages[session_key] = event   # ← overwrites every time

Sending messages A, B, C while the agent is busy → only C survives.

Fix

Pass merge_text=True from _queue_or_replace_pending_event so sequential TEXT messages accumulate (newline-separated) into the pending slot instead of overwriting it.

Photo/media burst merging is unaffected — those branches in merge_pending_message_event return early before the merge_text check is reached.

Tests

Two new regression tests in tests/gateway/test_busy_session_ack.py:

  • test_queue_mode_accumulates_multiple_text_followups — verifies that A, B, C are all present in the combined pending event after three rapid queue-mode follow-ups.
  • test_queue_mode_single_message_unchanged — verifies first-message behaviour is unmodified (no regression).

All 17 existing busy-session tests continue to pass.

Closes #28503

Changed files

  • gateway/run.py (modified, +5/-1)
  • tests/gateway/test_busy_session_ack.py (modified, +99/-0)
RAW_BUFFERClick to expand / collapse

Summary When busy_input_mode: queue is configured, Hermes is supposed to queue incoming messages while the agent is busy. However, the implementation uses a single-slot dictionary (_pending_messages[session_key]) that overwrites previous messages rather than appending them to a FIFO queue. This causes silent message loss when users send multiple messages rapidly while the agent is processing. Environment Hermes Agent version: latest (installed from NousResearch/hermes-agent.git) Platform: WeChat (Weixin) gateway, also affects all platforms Config: display.busy_input_mode: queue Steps to Reproduce Configure busy_input_mode: queue in config.yaml Send a message to the agent (triggers a long-running task) While the agent is busy, send messages 2, 3, 4, 5 rapidly Wait for the agent to finish the current task Result: The agent only processes the last message (message 5). Messages 2, 3, 4 are silently lost. Root Cause Analysis The single-slot design In gateway/platforms/base.py:1092: def merge_pending_message_event( pending_messages: Dict[str, MessageEvent], session_key: str, event: MessageEvent, *, merge_text: bool = False, ) -> None: # ... photo burst and media merge logic ...

# Plain TEXT messages with merge_text=False: REPLACE, not append
pending_messages[session_key] = event  # ← OVERWRITES previous

The pending_messages dict is keyed by session_key — it holds one event per session, not a list. Queue mode path doesn't enable text merging In gateway/run.py:5210-5212: if self._busy_input_mode == "queue": logger.debug("PRIORITY queue follow-up for session %s", _quick_key) self._queue_or_replace_pending_event(_quick_key, event) # ← calls merge WITHOUT merge_text return None _queue_or_replace_pending_event calls merge_pending_message_event with the default merge_text=False, so plain text messages are replaced, not appended. Inconsistent: one path DOES merge text In gateway/run.py:5175-5180 (agent-starting sentinel path): merge_pending_message_event( adapter._pending_messages, _quick_key, event, merge_text=True, # ← Only this path enables text merging ) This inconsistency suggests the single-slot design was intended for photo bursts only, and queue mode was later layered on top without converting to a true FIFO. Expected Behavior All queued messages should be preserved and processed sequentially (FIFO) after the agent finishes the current task. Suggested Fix Two possible approaches: Option A: Enable merge_text=True for queue mode (quick fix) In gateway/run.py:5210-5212, pass merge_text=True: if self._busy_input_mode == "queue": merge_pending_message_event( adapter._pending_messages, _quick_key, event, merge_text=True ) return None This would concatenate text messages with newlines, so they're all processed in one turn. Not perfect FIFO (they become one combined message), but at least no data loss. Option B: Convert to real FIFO queue (proper fix) Change _pending_messages from Dict[str, MessageEvent] to Dict[str, List[MessageEvent]] (or collections.deque), and process them one by one after the agent finishes. This preserves message boundaries and enables true sequential processing. Workaround Users can mitigate by: Sending all content in a single message (newline-separated) Waiting for the agent to respond before sending the next message For link collection workflows: writing links to a file and processing them in batch

Impact This is particularly painful for messaging platforms (WeChat, Telegram) where rapid-fire message sending is normal user behavior. Users have no indication that messages were lost — no warning, no error, just silent data disappearance.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix Bug: busy_input_mode: queue silently drops messages — single-slot overwrite instead of FIFO [5 pull requests, 1 comments, 2 participants]