Conversation
…ask loops A model can call delegate_task dozens of times in a single user turn, spawning 44+ sequential subagent sessions over 53 minutes with no guardrail. max_concurrent_children limits batch size per individual delegate_task call, and max_spawn_depth prevents nested delegation. But neither limits how many times the parent calls delegate_task in a single turn. Fix: add a per-turn spawn counter (_turn_spawn_count) on the parent agent, reset to 0 at the start of each user turn, and enforce a cap via delegation.max_spawns_per_turn (default 10, floor 1). When exceeded, returns an error directing the model to stop delegating and synthesize a response from collected results.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for identifying a real remaining delegation budget gap. Current main caps calls only within each assistant response (agent/conversation_loop.py:4734, run_agent.py:3863-3891) and validates each tasks batch independently (tools/delegate_tool.py:2465-2474), so cumulative same-turn fan-out is still possible.
Problems
tests/tools/test_delegate_per_turn_spawn_limit.py:50-82does not calldelegate_task; it only asserts local arithmetic. It therefore does not verify rejection, state mutation, or turn reset.- The proposed config surface is absent from
hermes_cli/config.py:2242-2301and the delegation docs atwebsite/docs/user-guide/configuration.md:1989-2011. - Existing direct-call tests construct a
MagicMockparent without_turn_spawn_count(tests/tools/test_delegate.py:41-61) and invokedelegate_task(:231-243); the new counter path needs that fixture/state handled explicitly.
Suggested changes
- Add the default, docs, and dynamic schema disclosure for the cap.
- Add executable multi-call and reset tests through patched
delegate_task, and seed the existing parent fixture with an integer counter.
The PR predates the async-concurrency refactor in 6e369a376, so salvaging the helper into current tools/delegate_tool.py needs conflict-aware transplantation rather than a clean cherry-pick.
Automated hermes-sweeper review.
| agent = self._make_mock_agent(spawn_count=0) | ||
| # We can't fully run delegate_task without heavy mocking, but we can | ||
| # verify the cap check logic by testing the condition directly | ||
| max_spawns = 10 |
There was a problem hiding this comment.
This only reimplements the comparison locally; delegate_task() is never invoked. Please test sequential patched calls through the tool and assert the second call returns its tool error without constructing children, then verify a new conversation turn resets the counter.
Problem
delegate_taskhasmax_concurrent_children(bounds batch size per call) andmax_spawn_depth(bounds nesting), but neither limits how many times the parent agent callsdelegate_taskin a single user turn. A model stuck in a loop can spawn thousands of sequential subagents, exhausting tokens and API budget.Fix
Add
delegation.max_spawns_per_turnconfig key (default: 10). Track_turn_spawn_counton the parent agent. Eachdelegate_taskcall checkscurrent_turn_spawn_count + n_tasks > max_spawns_per_turnand returns atool_errordirecting the model to synthesize a response or split work across turns.Files changed
tools/delegate_tool.py—_get_max_spawns_per_turn(), check indelegate_task(),_DEFAULT_MAX_SPAWNS_PER_TURN = 10agent/conversation_loop.py— reset_turn_spawn_countat turn starttests/tools/test_delegate_per_turn_spawn_limit.py— full test coverageConfig
Like
max_concurrent_childrenthere is no upper ceiling — but a high value multiplies API cost linearly.Verification
Rebased against
main(9be292f, 2026-07-01). Confirmed upstream does not containmax_spawns_per_turnor_turn_spawn_count.