Skip to content

_load_config() in delegate_tool.py never reads persistent config — breaks all delegation.* settings in v0.14.0 #32671

@foundation-nnet

Description

@foundation-nnet

_load_config() in delegate_tool.py never reads persistent config — breaks all delegation.* settings in v0.14.0

Problem

delegation.model, delegation.provider, delegation.base_url, and all other delegation.* settings in config.yaml are silently ignored on v0.14.0. Subagents always inherit the parent agent's model/provider regardless of what the user configured.

This was supposedly fixed in v0.11.x (commit 9423fda, March 11, 2026), but the _load_config() function in tools/delegate_tool.py still contains the original bug.

Root Cause

tools/delegate_tool.py lines 2459–2481:

def _load_config() -> dict:
    try:
        from cli import CLI_CONFIG
        cfg = CLI_CONFIG.get("delegation") or {}
        if cfg:                    # ← BUG: always truthy
            return cfg             # ← Always returns here
    except Exception:
        pass
    # Persistent config fallback — NEVER REACHED
    ...

CLI_CONFIG is loaded at gateway startup with "delegation" always present (default keys with empty-string values, set in cli.py lines 389–395). The check if cfg: passes because the dict is non-empty, so the persistent config.yaml is never consulted.

This is the exact bug described in #11999, which was marked as closed in v0.11.x. The commit 9423fda added _resolve_delegation_credentials() and credential plumbing, but _load_config() itself was never patched — the fix was incomplete or regressed.

Reproduction

  1. Set delegation config:
delegation:
  model: deepseek/deepseek-v4-pro
  provider: kilocode
  base_url: https://api.kilo.ai/api/gateway
  1. Start parent agent on a different model (e.g., kilo-auto/balanced)

  2. Call delegate_task(goal="Report your model name")

  3. Expected: Subagent uses deepseek/deepseek-v4-pro via kilocode

  4. Actual: Subagent inherits parent model (kilo-auto/balanced)

The config file is correctly written, parseable, and contains the right values — _load_config() simply never reads it.

Additional Gap: No per-call model/provider parameters

Beyond the _load_config bug, delegate_task() also lacks:

  • Top-level model and provider function parameters
  • model and provider fields in the per-task schema (batch mode)

The handler at line 2066 hardcodes model=creds["model"] with no extraction from args:

child = _build_child_agent(
    ...
    model=creds["model"],  # ← no per-call or per-task override
    ...
)

The OpenAI function-calling schema (DELEGATE_TASK_SCHEMA) also omits model and provider properties, so the JSON validator strips them even if the LLM emits them.

Relation to Existing Issues

Issue Status Relation
#11999 Closed (v0.11.x) Same root bug. Supposedly fixed but _load_config was never patched.
#26482 Open (P2) Master tracking issue. This _load_config bug is the reason config settings are ignored.
#26486 Open Fixes ACP transport leak + provider override. Does not touch _load_config.
#17685 Open (P3) Per-task model override in batch mode. Covered by the schema/handler gap.
#17718 Open Per-task model override (1-line fix). Covered by our proposal.
#5012 Open Feature request for model/provider params. Covered by our proposal.
#31155 Closed Duplicate of #26482.

Proposed Fix

1. Fix _load_config() — merge strategy

def _load_config() -> dict:
    """Load delegation config by merging persistent config with in-memory defaults."""
    # Start with CLI_CONFIG defaults (always present, may be empty values)
    result = {}
    try:
        from cli import CLI_CONFIG
        result = dict(CLI_CONFIG.get("delegation") or {})
    except Exception:
        pass

    # Overlay persistent config — non-empty values win
    try:
        from hermes_cli.config import load_config
        full = load_config()
        persisted = full.get("delegation") or {}
        for key, value in persisted.items():
            if value or isinstance(value, (bool, int)):
                result[key] = value
    except Exception:
        pass

    return result

This ensures:

  • CLI_CONFIG provides safe defaults (empty strings, iteration counts)
  • Persistent config values override defaults when non-empty
  • Boolean/int fields like max_iterations: 50 are preserved
  • Both entry points (CLI and gateway) respect user config

2. Add model and provider parameters to delegate_task()

  • Add model: Optional[str] = None and provider: Optional[str] = None to the function signature
  • Wire into credential resolution: if model: creds["model"] = model, if provider: creds["provider"] = provider
  • Update DELEGATE_TASK_SCHEMA to include these properties
  • Support per-task model/provider in the tasks array schema

3. Override Priority (after fix)

  1. Per-tasktasks[i].model / tasks[i].provider (highest)
  2. Per-calldelegate_task(model=..., provider=...)
  3. Configdelegation.model / delegation.provider in config.yaml
  4. Parent inheritance — parent agent's model/provider (lowest)

Impact

  • Breaking: No. Additive change — default values mean existing callers are unaffected.
  • Backwards compatible: Existing config.yaml delegation settings start working immediately.
  • No migration required.

Environment

  • Hermes Agent: v0.14.0 (2026.5.16)
  • Python: 3.11.15
  • OS: Linux 6.12.74+deb13+1-amd64
  • Profile: foundation-curator (profile-scoped config at ~/.hermes/profiles/foundation-curator/config.yaml)

Willing to Contribute

I have a tested diagnosis, verified the bug against source, and can submit a PR consolidating both the _load_config fix and the model/provider parameter additions. Please advise if you'd prefer this split across two PRs or if an active PR already covers any of this scope.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/toolsTool registry, model_tools, toolsetsduplicateThis issue or pull request already existstool/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