Skip to content

Bug: delegate_task toolset intersection fails with composite toolsets (e.g. hermes-cli) #19447

@zts00011

Description

@zts00011

Bug Description

When the parent agent uses a composite toolset like hermes-cli in config.yaml, calling delegate_task with specific toolsets (e.g. toolsets=["web"]) results in the child agent receiving zero tools.

Root Cause

In tools/delegate_tool.py, the _build_child_agent function resolves parent_toolsets from the parent agent's enabled_toolsets attribute:

# Line 892-894
parent_enabled = getattr(parent_agent, "enabled_toolsets", None)
if parent_enabled is not None:
    parent_toolsets = set(parent_enabled)  # e.g. {"hermes-cli"}

Then when explicit toolsets are provided, it intersects with parent_toolsets:

# Line 901
child_toolsets = [t for t in toolsets if t in parent_toolsets]
# ["web"] ∩ {"hermes-cli"} = []  ← EMPTY!

The hermes-cli toolset is a composite that includes tools from many individual toolsets (web, terminal, browser, file, etc. — 44 tools total). But the intersection logic compares toolset names, not the tools within them. Since "web" != "hermes-cli", the intersection is empty.

Expected Behavior

The intersection should expand composite toolsets before comparing. A child requesting toolsets=["web"] from a parent with toolsets=["hermes-cli"] should receive the web toolset, since hermes-cli includes web_search and web_extract.

Reproduction

  1. Set config.yaml: toolsets: [hermes-cli]
  2. Call delegate_task(goal="Research X", toolsets=["web"])
  3. Child agent gets zero tools → cannot call web_search → task fails with truncated/empty result

Workaround

Don't pass explicit toolsets to delegate_task. When toolsets is None, the child inherits the parent's enabled_toolsets directly, which works correctly.

Suggested Fix

Expand composite toolsets into their constituent toolsets before intersection, or compare at the tool-name level instead of toolset-name level. For example:

Option A: Expand composite toolsets before intersection

def _expand_toolsets(toolset_names, registry):
    """Expand composite toolsets into their constituent individual toolsets."""
    expanded = set()
    for name in toolset_names:
        ts = registry.get(name)
        if ts and ts.get("includes"):
            expanded.update(ts["includes"])
        else:
            expanded.add(name)
    return expanded

Option B: Compare at tool level instead of toolset level

parent_tool_names = set(parent_agent.valid_tool_names)
requested_tools = set()
for ts_name in toolsets:
    ts = TOOLSETS.get(ts_name)
    if ts:
        requested_tools.update(ts["tools"])
child_has_tools = requested_tools.issubset(parent_tool_names)

Environment

  • Hermes Agent: latest (source install)
  • Config: toolsets: [hermes-cli]
  • Model: GLM-5.1 via Tencent Cloud API

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/toolsTool registry, model_tools, toolsetstool/delegateSubagent delegationtype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions