Skip to content

fix: propagate child activity to parent during delegate_task#7295

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-8f5f6063
Apr 10, 2026
Merged

fix: propagate child activity to parent during delegate_task#7295
teknium1 merged 1 commit into
mainfrom
hermes/hermes-8f5f6063

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Fixes the gateway inactivity timeout firing during delegate_task execution. When a subagent runs, the parent agent's activity tracker freezes because child.run_conversation() blocks synchronously and the child's own _touch_activity() never propagates back to the parent. The gateway polls the parent's seconds_since_activity, sees it growing, and fires a spurious 'No activity for 15 min' warning — eventually killing the agent at the 30-min timeout even though the subagent is actively working.

Reported by community user Josh on Discord — running delegate_task from Telegram, getting inactivity warnings while subagent actively iterates.

Changes

tools/delegate_tool.py:

  • Added a heartbeat daemon thread in _run_single_child() that calls parent._touch_activity() every 30 seconds (configurable via _HEARTBEAT_INTERVAL)
  • Heartbeat reads the child's get_activity_summary() and propagates rich detail: current tool, iteration count, last activity description
  • Thread starts before child.run_conversation() and is stopped + joined in the finally block (handles both success and error paths)
  • Thread-safe: _touch_activity only sets two attributes (atomic under GIL)

tests/tools/test_delegate.py:

  • 4 new tests in TestDelegateHeartbeat:
    • Heartbeat fires and touches parent activity during child execution
    • Heartbeat stops after child completes (no leak)
    • Heartbeat stops after child error (no leak)
    • Heartbeat includes last_activity_desc when no tool is active

Impact

  • Gateway users running delegate_task no longer get spurious inactivity warnings
  • 'Still working...' status messages now show what the subagent is doing (e.g., 'delegate_task: subagent running terminal (iteration 5/50)') instead of just 'running: delegate_task'
  • Zero impact on CLI (no inactivity timeout there)
  • Zero impact on non-delegate tool calls

Test plan

python -m pytest tests/tools/test_delegate.py -v -o 'addopts='
# 68 passed in 1.98s (4 new heartbeat tests + 64 existing)

When delegate_task runs, the parent agent's activity tracker freezes
because child.run_conversation() blocks and the child's own
_touch_activity() never propagates back to the parent. The gateway
inactivity timeout then fires a spurious 'No activity' warning and
eventually kills the agent, even though the subagent is actively working.

Fix: add a heartbeat thread in _run_single_child that calls
parent._touch_activity() every 30 seconds with detail from the child's
activity summary (current tool, iteration count). The thread is a daemon
that starts before child.run_conversation() and is cleaned up in the
finally block.

This also improves the gateway 'Still working...' status messages —
instead of just 'running: delegate_task', users now see what the
subagent is actually doing (e.g., 'delegate_task: subagent running
terminal (iteration 5/50)').
@teknium1 teknium1 merged commit a093eb4 into main Apr 10, 2026
3 of 4 checks passed
Tommyeds pushed a commit to Tommyeds/hermes-agent that referenced this pull request Apr 12, 2026
…earch#7295)

When delegate_task runs, the parent agent's activity tracker freezes
because child.run_conversation() blocks and the child's own
_touch_activity() never propagates back to the parent. The gateway
inactivity timeout then fires a spurious 'No activity' warning and
eventually kills the agent, even though the subagent is actively working.

Fix: add a heartbeat thread in _run_single_child that calls
parent._touch_activity() every 30 seconds with detail from the child's
activity summary (current tool, iteration count). The thread is a daemon
that starts before child.run_conversation() and is cleaned up in the
finally block.

This also improves the gateway 'Still working...' status messages —
instead of just 'running: delegate_task', users now see what the
subagent is actually doing (e.g., 'delegate_task: subagent running
terminal (iteration 5/50)').
ulasbilgen pushed a commit to ulasbilgen/hermes-adhd-agent that referenced this pull request May 1, 2026
…earch#7295)

When delegate_task runs, the parent agent's activity tracker freezes
because child.run_conversation() blocks and the child's own
_touch_activity() never propagates back to the parent. The gateway
inactivity timeout then fires a spurious 'No activity' warning and
eventually kills the agent, even though the subagent is actively working.

Fix: add a heartbeat thread in _run_single_child that calls
parent._touch_activity() every 30 seconds with detail from the child's
activity summary (current tool, iteration count). The thread is a daemon
that starts before child.run_conversation() and is cleaned up in the
finally block.

This also improves the gateway 'Still working...' status messages —
instead of just 'running: delegate_task', users now see what the
subagent is actually doing (e.g., 'delegate_task: subagent running
terminal (iteration 5/50)').
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
…earch#7295)

When delegate_task runs, the parent agent's activity tracker freezes
because child.run_conversation() blocks and the child's own
_touch_activity() never propagates back to the parent. The gateway
inactivity timeout then fires a spurious 'No activity' warning and
eventually kills the agent, even though the subagent is actively working.

Fix: add a heartbeat thread in _run_single_child that calls
parent._touch_activity() every 30 seconds with detail from the child's
activity summary (current tool, iteration count). The thread is a daemon
that starts before child.run_conversation() and is cleaned up in the
finally block.

This also improves the gateway 'Still working...' status messages —
instead of just 'running: delegate_task', users now see what the
subagent is actually doing (e.g., 'delegate_task: subagent running
terminal (iteration 5/50)').
olympus-terminal pushed a commit to olympus-terminal/hermes-agent that referenced this pull request May 16, 2026
…earch#7295)

When delegate_task runs, the parent agent's activity tracker freezes
because child.run_conversation() blocks and the child's own
_touch_activity() never propagates back to the parent. The gateway
inactivity timeout then fires a spurious 'No activity' warning and
eventually kills the agent, even though the subagent is actively working.

Fix: add a heartbeat thread in _run_single_child that calls
parent._touch_activity() every 30 seconds with detail from the child's
activity summary (current tool, iteration count). The thread is a daemon
that starts before child.run_conversation() and is cleaned up in the
finally block.

This also improves the gateway 'Still working...' status messages —
instead of just 'running: delegate_task', users now see what the
subagent is actually doing (e.g., 'delegate_task: subagent running
terminal (iteration 5/50)').
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
…earch#7295)

When delegate_task runs, the parent agent's activity tracker freezes
because child.run_conversation() blocks and the child's own
_touch_activity() never propagates back to the parent. The gateway
inactivity timeout then fires a spurious 'No activity' warning and
eventually kills the agent, even though the subagent is actively working.

Fix: add a heartbeat thread in _run_single_child that calls
parent._touch_activity() every 30 seconds with detail from the child's
activity summary (current tool, iteration count). The thread is a daemon
that starts before child.run_conversation() and is cleaned up in the
finally block.

This also improves the gateway 'Still working...' status messages —
instead of just 'running: delegate_task', users now see what the
subagent is actually doing (e.g., 'delegate_task: subagent running
terminal (iteration 5/50)').
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
…earch#7295)

When delegate_task runs, the parent agent's activity tracker freezes
because child.run_conversation() blocks and the child's own
_touch_activity() never propagates back to the parent. The gateway
inactivity timeout then fires a spurious 'No activity' warning and
eventually kills the agent, even though the subagent is actively working.

Fix: add a heartbeat thread in _run_single_child that calls
parent._touch_activity() every 30 seconds with detail from the child's
activity summary (current tool, iteration count). The thread is a daemon
that starts before child.run_conversation() and is cleaned up in the
finally block.

This also improves the gateway 'Still working...' status messages —
instead of just 'running: delegate_task', users now see what the
subagent is actually doing (e.g., 'delegate_task: subagent running
terminal (iteration 5/50)').
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant