Skip to content

fix(gateway): route /queue through active-session bypass - #7221

Closed
rahimsais wants to merge 3 commits into
NousResearch:mainfrom
rahimsais:fix/queue-command-bypass-active-session-guard
Closed

fix(gateway): route /queue through active-session bypass#7221
rahimsais wants to merge 3 commits into
NousResearch:mainfrom
rahimsais:fix/queue-command-bypass-active-session-guard

Conversation

@rahimsais

@rahimsais rahimsais commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

Problem

Commands sent to the Telegram/Discord/Slack gateway while the agent is running were silently discarded. Only 9 of 32+ gateway commands were in the Level 1 bypass list in base.py. The rest triggered an interrupt and got eaten by the safety net in run.py, leaving users with no response.

Root Cause

Commit eb7c4084 (PR #5765) consolidated the bypass list but missed most commands. When a command is not in the bypass list:

  1. Level 1 (base.py) queues it as pending and signals interrupt
  2. The running agent sees the interrupt and stops
  3. Safety net (run.py line 7532) detects the pending text starts with /, recognizes it as a command, and discards it
  4. User gets no response

Fix

Three changes across 2 files (+ tests):

1. Expand bypass list (gateway/platforms/base.py:1359)

From 10 entries to 27 — all gateway commands including raw alias forms (bg, fork, set-home, reload_mcp)

2. Add Level 2 reject handler (gateway/run.py:~2037)

12 commands that need an idle agent now return "Agent is running — wait or /stop first." instead of being silently discarded

3. 23 new parametrized tests

Covering both execute-immediately and reject-with-message categories

Command Behavior Categories

Category Commands Behavior during active session
Execute immediately /help, /commands, /profile, /provider, /usage, /insights, /sethome, /voice, /yolo, /btw Runs normally
Reject with message /model, /retry, /undo, /title, /branch, /compress, /rollback, /resume, /reasoning, /fast, /personality, /update, /reload-mcp Returns "Agent is running"
Session control /stop, /new, /reset, /approve, /deny, /status, /background, /queue Already working
Default interrupt skill commands, /plan, regular text Interrupts agent (unchanged)

Test Results

  • 23 new tests all pass
  • 0 new failures in gateway test suite (18 pre-existing failures unrelated to this change)
  • Total: 2471 passed, 18 failed (pre-existing), 4 skipped

Fixes #7220

The base adapter's Level 1 guard (handle_message in base.py) intercepts
ALL messages while an agent is running. When /queue arrives during active
processing, it falls through to the default interrupt path which:

1. Triggers an unwanted agent interrupt (the whole point of /queue is
   to NOT interrupt)
2. The pending text '/queue <prompt>' is then caught by the safety net
   in run.py (added in PR NousResearch#5765) which discards it silently:
   'Discarding command from pending queue — commands must not be passed
   as agent input'

The run.py Level 2 handler already correctly handles /queue — it stores
the prompt without interrupting and returns 'Queued for the next turn.'
But it is never reached because base.py intercepts first.

Fix: Add 'queue' and 'q' (its alias) to the active-session bypass set
in base.py, alongside /stop, /new, /reset, /background, /approve,
/deny, and /status. This routes /queue through to the gateway runner's
Level 2 handler which handles it correctly without interrupting.

Introduced by eb7c408 (PR NousResearch#5765) which consolidated the bypass list
and added the safety net that now discards /queue.

Refs: NousResearch#5765
Same issue as /queue — /model has a Level 2 handler that returns
'Agent is running — wait or /stop first, then switch models.' but it
is unreachable because base.py's Level 1 guard intercepts it first,
triggers an unwanted interrupt, and the safety net silently discards it.

Log evidence:
  Discarding command '/model' from pending queue — commands must not
  be passed as agent input

Add 'model' to the active-session bypass set so the Level 2 handler
is reached and the user gets a helpful rejection message instead of
silent discard.

Refs: NousResearch#7220
… active session

Commands sent while the agent is running were silently discarded because
only 9 of 32+ gateway commands were in the Level 1 bypass list. This
caused confusing behavior: /help, /usage, /yolo, etc. would trigger an
interrupt and then get discarded by the safety net, leaving the user
with no response.

Changes:
- Expand bypass list in base.py from 10 to 27 raw command forms
  (includes aliases like /bg, /fork, /set-home, /reload_mcp)
- Add Level 2 reject handler for 12 commands that need an idle agent
  (/retry, /undo, /title, /branch, /compress, /rollback, /resume,
   /reasoning, /fast, /personality, /update, /reload-mcp)
- Add 23 parametrized tests covering both categories

Three categories of behavior:
1. Execute immediately (10): /help, /commands, /profile, /provider,
   /usage, /insights, /sethome, /voice, /yolo, /btw
2. Reject with message (13): /model, /retry, /undo, /title, /branch,
   /compress, /rollback, /resume, /reasoning, /fast, /personality,
   /update, /reload-mcp
3. Default interrupt (unchanged): skill commands, /plan, regular text

Fixes NousResearch#7220
@rahimsais rahimsais closed this Apr 13, 2026
@rahimsais
rahimsais deleted the fix/queue-command-bypass-active-session-guard branch April 13, 2026 08:09
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.

/queue command triggers unwanted interrupt and silently discards queued prompt

2 participants