Merge pull request #33817 from sweetcornna/fix/28503-busy-input-fifo
fix(gateway): use FIFO queue for busy_input_mode pending messages
This commit is contained in:
+51
-7
@@ -3427,11 +3427,52 @@ class GatewayRunner(GatewayKanbanWatchersMixin, GatewaySlashCommandsMixin):
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# Hard cap on per-session pending follow-ups for busy_input_mode=queue
|
||||
# (and the draining/steer-fallback/subagent-demotion paths that share
|
||||
# this entry point). Without a cap, a stuck agent + a rapid-fire user
|
||||
# could grow the overflow list unboundedly. 32 turns of queued
|
||||
# follow-ups is far beyond any realistic conversational backlog while
|
||||
# still small enough to never threaten memory.
|
||||
_BUSY_QUEUE_MAX_PENDING = 32
|
||||
|
||||
def _queue_or_replace_pending_event(self, session_key: str, event: MessageEvent) -> None:
|
||||
adapter = self.adapters.get(event.source.platform)
|
||||
if not adapter:
|
||||
return
|
||||
merge_pending_message_event(adapter._pending_messages, session_key, event)
|
||||
# #28503 — Previously this called ``merge_pending_message_event``
|
||||
# with the default ``merge_text=False``, which silently OVERWROTE
|
||||
# the single pending slot when consecutive text messages arrived
|
||||
# in ``busy_input_mode: queue``. Route through the FIFO
|
||||
# infrastructure shared with ``/queue`` so each follow-up gets
|
||||
# its own turn in arrival order. Photo bursts still merge into
|
||||
# the head slot via ``merge_pending_message_event`` (album
|
||||
# semantics); everything else appends to the overflow tail.
|
||||
pending_slot = getattr(adapter, "_pending_messages", None)
|
||||
existing = pending_slot.get(session_key) if isinstance(pending_slot, dict) else None
|
||||
if existing is not None and (
|
||||
getattr(existing, "message_type", None) == MessageType.PHOTO
|
||||
or event.message_type == MessageType.PHOTO
|
||||
or bool(getattr(existing, "media_urls", None))
|
||||
or bool(getattr(event, "media_urls", None))
|
||||
):
|
||||
# Preserve photo-burst / media-merge semantics for the head slot.
|
||||
merge_pending_message_event(
|
||||
adapter._pending_messages,
|
||||
session_key,
|
||||
event,
|
||||
merge_text=event.message_type == MessageType.TEXT,
|
||||
)
|
||||
return
|
||||
|
||||
if self._queue_depth(session_key, adapter=adapter) >= self._BUSY_QUEUE_MAX_PENDING:
|
||||
logger.warning(
|
||||
"Dropping busy-mode follow-up for session %s — pending queue at cap (%d).",
|
||||
session_key,
|
||||
self._BUSY_QUEUE_MAX_PENDING,
|
||||
)
|
||||
return
|
||||
|
||||
self._enqueue_fifo(session_key, event, adapter)
|
||||
|
||||
async def _handle_active_session_busy_message(self, event: MessageEvent, session_key: str) -> bool:
|
||||
# --- Authorization gate (#17775) ---
|
||||
@@ -7024,12 +7065,15 @@ class GatewayRunner(GatewayKanbanWatchersMixin, GatewaySlashCommandsMixin):
|
||||
)
|
||||
adapter = self.adapters.get(source.platform)
|
||||
if adapter:
|
||||
merge_pending_message_event(
|
||||
adapter._pending_messages,
|
||||
_quick_key,
|
||||
event,
|
||||
merge_text=True,
|
||||
)
|
||||
if self._busy_input_mode == "queue":
|
||||
self._enqueue_fifo(_quick_key, event, adapter)
|
||||
else:
|
||||
merge_pending_message_event(
|
||||
adapter._pending_messages,
|
||||
_quick_key,
|
||||
event,
|
||||
merge_text=True,
|
||||
)
|
||||
return None
|
||||
|
||||
running_agent = self._running_agents.get(_quick_key)
|
||||
|
||||
Reference in New Issue
Block a user