From b6f9b70afdbf05e7f99063bb11676ec3aa7e34c8 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:59:52 -0700 Subject: [PATCH] fix(gateway): route /approve and /deny through running-agent guard (#4798) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the agent is blocked on a dangerous command approval (threading.Event wait inside tools/approval.py), incoming /approve and /deny commands were falling through to the generic interrupt path instead of being dispatched to their command handlers. The interrupt sets _interrupt_requested on the agent, but the agent thread is blocked on event.wait() — not checking the flag. Result: approval times out after 300s (5 minutes) before executing. Fix: intercept /approve and /deny in the running-agent early-intercept block (alongside /stop, /new, /queue) and route directly to _handle_approve_command / _handle_deny_command. --- gateway/run.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gateway/run.py b/gateway/run.py index 225f82fa1..cdf33135e 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -1821,6 +1821,15 @@ class GatewayRunner: adapter._pending_messages[_quick_key] = queued_event return "Queued for the next turn." + # /approve and /deny must bypass the running-agent interrupt path. + # The agent thread is blocked on a threading.Event inside + # tools/approval.py — sending an interrupt won't unblock it. + # Route directly to the approval handler so the event is signalled. + if _cmd_def_inner and _cmd_def_inner.name in ("approve", "deny"): + if _cmd_def_inner.name == "approve": + return await self._handle_approve_command(event) + return await self._handle_deny_command(event) + if event.message_type == MessageType.PHOTO: logger.debug("PRIORITY photo follow-up for session %s — queueing without interrupt", _quick_key[:20]) adapter = self.adapters.get(source.platform)