diff --git a/tools/approval.py b/tools/approval.py index 4d619d435d7..d1f62d05eef 100644 --- a/tools/approval.py +++ b/tools/approval.py @@ -20,6 +20,7 @@ import unicodedata from typing import Optional from hermes_cli.config import cfg_get +from tools.interrupt import is_interrupted from utils import env_var_enabled, is_truthy_value logger = logging.getLogger(__name__) @@ -1343,6 +1344,23 @@ def _await_gateway_decision(session_key: str, notify_cb, approval_data: dict, _activity_state = {"last_touch": _now, "start": _now} resolved = False while True: + # Respect interrupt signals (e.g. /stop, /new, or an inactivity + # timeout from the gateway) so a pending approval doesn't keep the + # session wedged on threading.Event.wait() until the 5-minute approval + # timeout. The wait runs on the agent's execution thread, which is the + # exact thread AIAgent.interrupt() flags — so is_interrupted() here + # sees the signal. Resolve as "deny" so the agent loop receives a + # normal denial and unwinds cleanly (#8697). + if is_interrupted(): + logger.info( + "Approval wait interrupted by user signal — " + "returning deny for session %s", + session_key, + ) + entry.result = "deny" + entry.event.set() + resolved = True + break _remaining = _deadline - time.monotonic() if _remaining <= 0: break