fix(delegate): move heartbeat thread start inside try block to prevent orphan

_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
This commit is contained in:
sprmn24 2026-05-15 18:53:52 +03:00 committed by Teknium
parent 42070ecefb
commit 2d7182f72c

View file

@ -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)