fix: bypass active-session queue for /approve and /deny commands - #4911
fix: bypass active-session queue for /approve and /deny commands#4911kagura-agent wants to merge 1 commit into
Conversation
…sResearch#4898) When an agent session is running, BasePlatformAdapter.handle_message() queues incoming messages instead of dispatching them. This causes /approve and /deny commands to be silently dropped — the agent thread is blocked on a threading.Event in tools/approval.py waiting for user input, but the control command never reaches the handler. Add _CONTROL_COMMANDS frozenset to BasePlatformAdapter containing commands that must bypass the active-session queue: approve, deny, stop, new, reset. When handle_message() detects one of these during an active session, it spawns a lightweight fire-and-forget background task that calls the handler directly, instead of queuing the message. The _process_message_background() method gains an is_control flag that skips session-lifecycle bookkeeping (interrupt events, pending message drain, _active_sessions cleanup) since another task already owns the session. Tests verify that /approve, /deny, /stop bypass the queue during active sessions while regular text messages continue to be queued.
|
This PR matches what I'm seeing on a live Telegram deployment ( Current user-visible symptom is often not "silent forever" but " From the logs on Thoth:
That strongly suggests the same underlying problem this PR addresses:
So from operational experience: yes, this is not theoretical. It is a real Telegram pain point in day-to-day use, especially when driving long Codex-style tasks over the gateway. The one thing I'd explicitly watch in review is interaction with the existing interrupt-recursion path, because that's the warning line that consistently precedes the delayed approval behavior in this deployment. |
|
Closing — this was already fixed on main via PR #4926 (merged). The approach there uses direct inline dispatch via |
Problem
When an agent session is actively running,
BasePlatformAdapter.handle_message()ingateway/platforms/base.pyqueues all incoming messages instead of dispatching them immediately. This is correct for regular messages (they get processed after the current task), but/approveand/denyare control commands that signal athreading.Eventintools/approval.pyto unblock the agent thread.When these commands are queued instead of dispatched, the agent hangs indefinitely waiting for approval that will never arrive — a silent deadlock.
The handler in
gateway/run.py(_handle_message()) already has early-intercept logic (line ~1829) that routes/approveand/denydirectly to their handlers. But this code is never reached becausehandle_message()inbase.pyreturns early after queuing the message.Fix
Added a
_CONTROL_COMMANDSfrozenset toBasePlatformAdaptercontaining commands that must bypass the active-session queue:approve,deny— signal approval threading.Eventstop— force-kill hung sessionsnew,reset— session managementWhen
handle_message()detects a control command during an active session, it spawns a lightweight fire-and-forget background task that calls the handler directly, instead of queuing the message.The
_process_message_background()method gains anis_controlflag that skips session-lifecycle bookkeeping (interrupt events, pending message drain,_active_sessionscleanup) since another_process_message_backgroundalready owns the session.Tests
Added 5 tests in
tests/gateway/test_platform_base.py:/approvedispatched during active session ✅/denydispatched during active session ✅/stopdispatched during active session ✅/approve@BotNamesuffix handled correctly ✅Full test suite: 7704 passed (10 pre-existing failures, all unrelated).
Closes #4898