Skip to content

Bug: Multiple rapid messages only last one processed #4469

@von-cas

Description

@von-cas

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

  1. Start a long-running agent task (e.g., "research X and Y")
  2. While agent is processing, send message A: "also check Z"
  3. Quickly send message B: "and W"
  4. 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:

  1. GatewayRunner._pending_messages (dict, line 448 in run.py)
  2. 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.pyget_pending_message() method

Recommendation

Requires fuller tracing of:

  1. When self._pending_messages is read/cleared vs adapter._pending_messages
  2. The photo burst merging logic (lines 1810-1828)
  3. The /queue command flow (line 1807)
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High — major feature broken, no workaroundcomp/gatewayGateway runner, session dispatch, deliverytype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions