From 2d7182f72c398496db60de5c18f8554d7ecc6d82 Mon Sep 17 00:00:00 2001 From: sprmn24 Date: Fri, 15 May 2026 18:53:52 +0300 Subject: [PATCH] fix(delegate): move heartbeat thread start inside try block to prevent orphan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _heartbeat_thread.start() was called before the try/finally block that contains _heartbeat_stop.set(). If _register_subagent() or any code between .start() and try: raised an exception, the finally block would never run — leaving the heartbeat thread as an orphan that continues calling _touch_activity() on the parent agent, incorrectly resetting gateway timeout counters. Move _heartbeat_thread.start() to be the first statement inside the try block so the finally block always reaches _heartbeat_stop.set() regardless of how the child run completes or fails. Root cause: heartbeat start outside try/finally scope Impact: orphan heartbeat thread incorrectly resets parent gateway timeouts --- tools/delegate_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/delegate_tool.py b/tools/delegate_tool.py index f4da5127a18..2cdce9cae64 100644 --- a/tools/delegate_tool.py +++ b/tools/delegate_tool.py @@ -1431,7 +1431,6 @@ def _run_single_child( pass _heartbeat_thread = threading.Thread(target=_heartbeat_loop, daemon=True) - _heartbeat_thread.start() # Register the live agent in the module-level registry so the TUI can # target it by subagent_id (kill, pause, status queries). Unregistered @@ -1462,6 +1461,7 @@ def _run_single_child( ) try: + _heartbeat_thread.start() if child_progress_cb: try: child_progress_cb("subagent.start", preview=goal)