NousResearch/hermes-agent
Subagent iteration budget isolation bug and fixes
Cluster 2873 · agent. Data as of
Nothing open on GitHub. Fix merged in #3004 on 25 Mar 2026. Check it covers your case.
The short answer
0open issues
0open PRs
4items grouped
- Known?
- Yes. 4 related items grouped here, 1 issue already closed.
- Fix event
- A fix was merged to main in PR #3004. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
resolved, deciding PR #3004. That is separate from the fix event. - Still open
- Nothing open on GitHub.
A bug where subagents share the parent agent's iteration budget, causing premature max_iterations cutoffs. Multiple fix attempts address giving subagents independent, isolated iteration budgets.
Open issues0
Open PRs0
Fixes on record
-
#3004 fix(delegate): give subagents independent iteration budgets
files:
hermes_cli/config.py,run_agent.py,tools/delegate_tool.pyShow the diff
-
hermes_cli/config.py@@ -317,6 +317,8 @@ def ensure_hermes_home(): "provider": "", # e.g. "openrouter" (empty = inherit parent provider + credentials) "base_url": "", # direct OpenAI-compatible endpoint for subagents "api_key": "", # API key for delegation.base_url (falls back to OPENAI_API_KEY) + "max_iterations": 50, # per-subagent iteration cap (each subagent gets its own budget, + # independent of the parent's max_iterations) }, # Ephemeral prefill messages file — JSON list of {role, content} dicts -
run_agent.py@@ -162,11 +162,15 @@ def _install_safe_stdio() -> None: class IterationBudget: - """Thread-safe shared iteration counter for parent and child agents. + """Thread-safe iteration counter for an agent. - Tracks total LLM-call iterations consumed across a parent agent and all - its subagents. A single ``IterationBudget`` is created by the parent - and passed to every child so they share the same cap. + Each agent (parent or subagent) gets its own ``IterationBudget``. + The parent's budget is capped at ``max_iterations`` (default 90). + Each subagent gets an independent budget capped at + ``delegation.max_iterations`` (default 50) — this means total + iterations across parent + subagents can exceed the parent's cap. + Users control the per-subagent limit via ``delegation.max_iterations`` + in config.yaml. ``execute_code`` (programmatic tool calling) iterations are refunded via :meth:`refund` so they don't eat into the budget. @@ -5719,7 +5723,7 @@ def run_conversation( api_call_count += 1 if not self.iteration_budget.consume(): if not self.quiet_mode: - self._safe_print(f"\n⚠️ Session iteration budget exhausted ({self.iteration_budget.max_total} total across agent + subagents)") + self._safe_print(f"\n⚠️ Iteration budget exhausted ({self.iteration_budget.used}/{self.iteration_budget.max_total} iterations used)") break # Fire step_callback for gateway hooks (agent:step event) @@ -7178,7 +7182,7 @@ def _stop_spinner(): or self.iteration_budget.remaining <= 0 ): if self.iteration_budget.remaining <= 0 and not self.quiet_mode: - print(f"\n⚠️ Session iteration budget exhausted ({self.iteration_budget.used}/{self.iteration_budget.max_total} used, including subagents)") + print(f"\n⚠️ Iteration budget exhausted ({self.iteration_budget.used}/{self.iteration_budget.max_total} iterations used)") final_response = self._handle_max_iterations(messages, api_call_count) # Determine if conversation completed successfully -
tools/delegate_tool.py@@ -191,9 +191,10 @@ def _build_child_agent( # Build progress callback to relay tool calls to parent display child_progress_cb = _build_child_progress_callback(task_index, parent_agent) - # Share the parent's iteration budget so subagent tool calls - # count toward the session-wide limit. - shared_budget = getattr(parent_agent, "iteration_budget", None) + # Each subagent gets its own iteration budget capped at max_iterations + # (configurable via delegation.max_iterations, default 50). This means + # total iterations across parent + subagents can exceed the parent's + # max_iterations. The user controls the per-subagent cap in config.yaml. # Resolve effective credentials: config override > parent inherit effective_model = model or parent_agent.model @@ -230,7 +231,7 @@ def _build_child_agent( providers_order=parent_agent.providers_order, provider_sort=parent_agent.provider_sort, tool_progress_callback=child_progress_cb, - iteration_budget=shared_budget, + iteration_budget=None, # fresh budget per subagent ) # Set delegation depth so children can't spawn grandchildren child._delegate_depth = getattr(parent_agent, '_delegate_depth', 0) + 1
-
2 PRs closed without merging
From the close comments: done elsewhere 2
Closed issues · 1
- Closed#2873[Bug]: Subagents hit max_iterations prematurely — shared IterationBudget drains parent's remaining quota
How this cluster was grouped
-
Link evidence (
structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference. -
Pairwise link density
0.50: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36.1.00means every pair is linked.
Pick up a Lab task
Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.
Open the LabAt a glance
- Subsystem
- agent
- Merged PRs
- #3004
- Closed issues
- 1
- Attempts
- 2 PRs closed without merging
- Fix link checked
- 25 Mar 2026. This confirmation is old and may be out of date (a revert or reopen would not have invalidated it here); re-verify.