From b37ec1e0fd0f191da47db8472bf97a8553864945 Mon Sep 17 00:00:00 2001 From: liuhao1024 Date: Tue, 16 Jun 2026 07:59:18 +0800 Subject: [PATCH] fix(gateway): route plain-text approval responses instead of steering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the agent is blocked waiting for a dangerous-command approval, plain-text responses like "yes" or "approve" were being steered into the running agent instead of being delivered to the approval handler. This meant approval via messaging platforms (Signal, Telegram, etc.) never succeeded — the user's response was consumed by the steer logic and the approval timed out. Add an early check in `_handle_active_session_busy_message` that routes approval-like responses ("yes", "approve", "deny", etc.) to the approval handler when `has_blocking_approval()` is true for the session. Fixes #46866 --- gateway/run.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/gateway/run.py b/gateway/run.py index 1c29a593e3c..7e0fc7f719a 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -3856,6 +3856,40 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew ) return True + # --- Approval response routing (#46866) --- + # When the agent is blocked waiting for a dangerous-command approval, + # plain-text responses like "yes" or "approve" must be routed to the + # approval handler instead of being steered/queued/interrupted. + # Otherwise approval via messaging platforms never succeeds. + try: + from tools.approval import has_blocking_approval, resolve_gateway_approval + if has_blocking_approval(session_key): + _raw_text = (event.text or "").strip().lower() + _approval_choice = None + if _raw_text in {"approve", "yes", "ok", "confirm", "y"}: + _approval_choice = "once" + elif _raw_text in {"deny", "no", "reject", "n"}: + _approval_choice = "deny" + elif _raw_text in {"always", "approve always", "always approve"}: + _approval_choice = "always" + elif _raw_text in {"session", "approve session", "session approve"}: + _approval_choice = "session" + if _approval_choice is not None: + if _approval_choice == "deny": + resolve_gateway_approval(session_key, "deny") + else: + resolve_gateway_approval(session_key, _approval_choice) + _adapter = self.adapters.get(event.source.platform) + if _adapter: + _adapter.resume_typing_for_chat(event.source.chat_id) + logger.info( + "Approval response via plain text: session=%s choice=%s", + session_key, _approval_choice, + ) + return True + except Exception: + pass # non-fatal — fall through to normal busy handling + # Normal busy case (agent actively running a task) adapter = self.adapters.get(event.source.platform) if not adapter: