# NousResearch/hermes-agent · delegate_task tool-name state scoping and concurrency bugs

## Open now

- 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.

## TL;DR

- 12 member(s): 0 open issue(s), 4 closed issue(s), 0 open PR(s), 2 merged PR(s), 6 PR(s) closed without merging.
- A fix was merged to main in PR #1894. Verify it addresses your case.
- **Recommended:** read PR #1894 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `partially_resolved` · deciding PR(s): `pr-1894,pr-2083`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_PARTIAL`): 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 member 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.

## Closed / duplicate issues

- #1802: delegate_task fails: _saved_tool_names not in scope after _build_child_agent/_run_single_child split
- #2027: fix(delegate): _saved_tool_names used before assignment in _build_child_agent
- #2079: delegate_task saves child's tool names instead of parent's (post-mutation timing bug)
- #34442: _last_resolved_tool_names global causes race condition in concurrent sessions

## Prior & competing PRs

- **#1804: fix: delegate_task NameError — _saved_tool_names scope**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#1864: fix: restore parent tool-name state after delegated runs**. closed without merge · fix tier `suggested`
  - maintainer direction: category `uncategorized`; implication `needs_llm`; refs `#1804`, `#1804`, `#1864`, `#1804`, `#1864`, `#1804`, `#1864`, `#1804`, `#1864`, `#1802`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#1894: fix(delegate): move _saved_tool_names save/restore to _run_single_child scope**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `tools/delegate_tool.py`
- **#2028: fix(delegate): fix _saved_tool_names used before assignment in _build_child_agent**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`
- **#2083: fix(delegate): save parent tool names before child construction mutates global**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `tools/delegate_tool.py`
  - fix hunks:
  - `tools/delegate_tool.py`

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

    ```diff
    @@ -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):
    ```

    ```diff
    @@ -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]
    ```
- **#34451: fix(tools): make _last_resolved_tool_names per-context (#34442)**. closed without merge · fix tier `suggested`
  - maintainer direction: category `uncategorized`; implication `needs_llm`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#1884: fix(delegate): move _saved_tool_names save/restore to _run_single_child scope**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#1894`
- **#2030: fix(delegate): remove _saved_tool_names used before assignment in _bu…**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`

## Fix status

- Merged to main in PR #1894 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-03-20`. This confirmation is old and may be out of date (a revert/reopen would not have invalidated it here); re-verify.
- Subsystem: `agent`
