delegate_task tool-name state scoping and concurrency bugs

NousResearch/hermes-agent · cluster 1802 · agent

Data as of

Nothing open on GitHub. Fix merged in #1894. Check it covers your case.

The short answer

0open issues
0open PRs
12items grouped
Known?
Yes. 12 related items grouped here, 4 issues already closed.
Fix event
A fix was merged to main in PR #1894. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this partially resolved, deciding PRs #1894, #2083. That is separate from the fix event.
Still open
Nothing open on GitHub.

The overwhelming majority of members concern bugs in delegate_task around _saved_tool_names variable scoping, assignment-before-use errors, and a global _last_resolved_tool_names causing race conditions in concurrent sessions. One unrelated member covers a GitHub Copilot provider integration.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #1894 fix(delegate): move _saved_tool_names save/restore to _run_single_child scope

    merged to main

    files: tools/delegate_tool.py

  • #2083 fix(delegate): save parent tool names before child construction mutates global

    merged to main

    files: tools/delegate_tool.py

    Show the diff
    • tools/delegate_tool.py
      @@ -262,13 +262,11 @@ def _run_single_child(
           # Get the progress callback from the child agent
           child_progress_cb = getattr(child, 'tool_progress_callback', None)
       
      -    # Save the parent's resolved tool names before the child agent can
      -    # overwrite the process-global via get_tool_definitions().
      -    # This must be in _run_single_child (not _build_child_agent) so the
      -    # save/restore happens in the same scope as the try/finally.
      +    # Restore parent tool names using the value saved before child construction
      +    # mutated the global. This is the correct parent toolset, not the child's.
           import model_tools
      -    _saved_tool_names = list(model_tools._last_resolved_tool_names)
      -    child._delegate_saved_tool_names = _saved_tool_names
      +    _saved_tool_names = getattr(child, "_delegate_saved_tool_names",
      +                                list(model_tools._last_resolved_tool_names))
       
           try:
               result = child.run_conversation(user_message=goal)
      @@ -465,6 +463,12 @@ def delegate_task(
           # Track goal labels for progress display (truncated for readability)
           task_labels = [t["goal"][:40] for t in task_list]
       
      +    # Save parent tool names BEFORE any child construction mutates the global.
      +    # _build_child_agent() calls AIAgent() which calls get_tool_definitions(),
      +    # which overwrites model_tools._last_resolved_tool_names with child's toolset.
      +    import model_tools as _model_tools
      +    _parent_tool_names = list(_model_tools._last_resolved_tool_names)
      +
           # Build all child agents on the main thread (thread-safe construction)
           children = []
           for i, t in enumerate(task_list):
      @@ -476,8 +480,13 @@ def delegate_task(
                   override_api_key=[redacted:secret-assignment]"api_key"],
                   override_api_mode=creds["api_mode"],
               )
      +        # Override with correct parent tool names (before child construction mutated global)
      +        child._delegate_saved_tool_names = _parent_tool_names
               children.append((i, t, child))
       
      +    # Authoritative restore: reset global to parent's tool names after all children built
      +    _model_tools._last_resolved_tool_names = _parent_tool_names
      +
           if n_tasks == 1:
               # Single task -- run directly (no thread pool overhead)
               _i, _t, child = children[0]

6 PRs closed without merging

From the close comments: done elsewhere 3 · merged via another change 1 · other 2

  • #1804 fix: delegate_task NameError — _saved_tool_names scope · done elsewhere
  • #1864 fix: restore parent tool-name state after delegated runs · other → #1804, #1864, #1802
  • #1884 fix(delegate): move _saved_tool_names save/restore to _run_single_child scope · merged via another change → #1894
  • #2028 fix(delegate): fix _saved_tool_names used before assignment in _build_child_agent · done elsewhere
  • #2030 fix(delegate): remove _saved_tool_names used before assignment in _bu… · done elsewhere
Show 1 more
  • #34451 fix(tools): make _last_resolved_tool_names per-context (#34442) · other
Closed issues · 4
  • Closed#1802delegate_task fails: _saved_tool_names not in scope after _build_child_agent/_run_single_child split
  • Closed#2027fix(delegate): _saved_tool_names used before assignment in _build_child_agent
  • Closed#2079delegate_task saves child's tool names instead of parent's (post-mutation timing bug)
  • Closed#34442_last_resolved_tool_names global causes race condition in concurrent sessions
How this cluster was grouped
  • Link evidence (partly structural links): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
  • Members outside that structural core may belong to a different underlying problem.
  • Pairwise link density 0.14: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means 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 Lab

At a glance

Subsystem
agent
Merged PRs
#1894, #2083
Closed issues
4
Attempts
6 PRs closed without merging
Fix link checked
20 Mar 2026. This confirmation is old and may be out of date (a revert or reopen would not have invalidated it here); re-verify.

For your agent

The same facts, typed.