Bug Report: Multiple Rapid Messages Only Last One Processed
Summary
When a user sends multiple messages while the agent is running, only the last message is processed. Earlier messages appear to be queued but are never consumed.
Reproduction
- Start a long-running agent task (e.g., "research X and Y")
- While agent is processing, send message A: "also check Z"
- Quickly send message B: "and W"
- Agent finishes and only processes message B (the last one)
Expected Behavior
All queued messages should be accumulated and processed together when the agent resumes.
Investigation
Two Separate Queues
There are two pending message storage locations:
GatewayRunner._pending_messages (dict, line 448 in run.py)
adapter._pending_messages (adapter-level queue, used by get_pending_message())
The Bug
When messages arrive during an interrupt (lines 1848-1854):
running_agent.interrupt(event.text)
if _quick_key in self._pending_messages:
self._pending_messages[_quick_key] += "\n" + event.text
else:
self._pending_messages[_quick_key] = event.text
Messages accumulate in GatewayRunner._pending_messages.
But when the agent resumes and checks for pending messages (lines 5976-5989):
if result.get("interrupted"):
pending_event = adapter.get_pending_message(session_key)
if pending_event:
pending = pending_event.text
It reads from adapter._pending_messages via adapter.get_pending_message().
The Disconnect
get_pending_message() in base.py:
def get_pending_message(self, session_key: str) -> Optional[MessageEvent]:
return self._pending_messages.pop(session_key, None)
This reads from adapter._pending_messages, NOT GatewayRunner._pending_messages.
Result: Messages queued in GatewayRunner._pending_messages are never consumed.
What IS Processed
The last message survives because interrupt(event.text) passes only the current message to the agent:
running_agent.interrupt(event.text) # Only THIS message, not accumulated
So the agent sees the interruption with the last message text, but the accumulated queue in GatewayRunner._pending_messages is orphaned.
Failed Fix Attempt
Naively replacing self._pending_messages with adapter._pending_messages breaks the system:
# WRONG - breaks system
adapter._pending_messages[_quick_key] = event
This causes recursive interrupt loops or message duplication issues. The relationship between these two queues is more complex than it appears — there is likely coordination logic, timing, or event type handling that was not fully traced.
Additional Context
Lines 1807, 1816, 1826-1828, 1844 use adapter._pending_messages for photo bursts and other edge cases. This suggests the adapter queue is the correct place for certain scenarios but GatewayRunner._pending_messages may have other purposes (cleanup, rate limiting, etc.).
Files Involved
gateway/run.py — lines 448, 1765, 1786, 1848-1854, 5976-5989
gateway/platforms/base.py — get_pending_message() method
Recommendation
Requires fuller tracing of:
- When
self._pending_messages is read/cleared vs adapter._pending_messages
- The photo burst merging logic (lines 1810-1828)
- The
/queue command flow (line 1807)
- Any cleanup in shutdown (line 1437)
The fix likely requires both queues to be synchronized, or one should be removed entirely and the code unified to use a single pending message store.
Bug Report: Multiple Rapid Messages Only Last One Processed
Summary
When a user sends multiple messages while the agent is running, only the last message is processed. Earlier messages appear to be queued but are never consumed.
Reproduction
Expected Behavior
All queued messages should be accumulated and processed together when the agent resumes.
Investigation
Two Separate Queues
There are two pending message storage locations:
GatewayRunner._pending_messages(dict, line 448 in run.py)adapter._pending_messages(adapter-level queue, used byget_pending_message())The Bug
When messages arrive during an interrupt (lines 1848-1854):
Messages accumulate in
GatewayRunner._pending_messages.But when the agent resumes and checks for pending messages (lines 5976-5989):
It reads from
adapter._pending_messagesviaadapter.get_pending_message().The Disconnect
get_pending_message()inbase.py:This reads from
adapter._pending_messages, NOTGatewayRunner._pending_messages.Result: Messages queued in
GatewayRunner._pending_messagesare never consumed.What IS Processed
The last message survives because
interrupt(event.text)passes only the current message to the agent:So the agent sees the interruption with the last message text, but the accumulated queue in
GatewayRunner._pending_messagesis orphaned.Failed Fix Attempt
Naively replacing
self._pending_messageswithadapter._pending_messagesbreaks the system:This causes recursive interrupt loops or message duplication issues. The relationship between these two queues is more complex than it appears — there is likely coordination logic, timing, or event type handling that was not fully traced.
Additional Context
Lines 1807, 1816, 1826-1828, 1844 use
adapter._pending_messagesfor photo bursts and other edge cases. This suggests the adapter queue is the correct place for certain scenarios butGatewayRunner._pending_messagesmay have other purposes (cleanup, rate limiting, etc.).Files Involved
gateway/run.py— lines 448, 1765, 1786, 1848-1854, 5976-5989gateway/platforms/base.py—get_pending_message()methodRecommendation
Requires fuller tracing of:
self._pending_messagesis read/cleared vsadapter._pending_messages/queuecommand flow (line 1807)The fix likely requires both queues to be synchronized, or one should be removed entirely and the code unified to use a single pending message store.