_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
- Set delegation config:
delegation:
model: deepseek/deepseek-v4-pro
provider: kilocode
base_url: https://api.kilo.ai/api/gateway
-
Start parent agent on a different model (e.g., kilo-auto/balanced)
-
Call delegate_task(goal="Report your model name")
-
Expected: Subagent uses deepseek/deepseek-v4-pro via kilocode
-
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)
- Per-task —
tasks[i].model / tasks[i].provider (highest)
- Per-call —
delegate_task(model=..., provider=...)
- Config —
delegation.model / delegation.provider in config.yaml
- 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.
_load_config()indelegate_tool.pynever reads persistent config — breaks alldelegation.*settings in v0.14.0Problem
delegation.model,delegation.provider,delegation.base_url, and all otherdelegation.*settings inconfig.yamlare 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 intools/delegate_tool.pystill contains the original bug.Root Cause
tools/delegate_tool.pylines 2459–2481:CLI_CONFIGis loaded at gateway startup with"delegation"always present (default keys with empty-string values, set incli.pylines 389–395). The checkif cfg:passes because the dict is non-empty, so the persistentconfig.yamlis never consulted.This is the exact bug described in #11999, which was marked as closed in v0.11.x. The commit
9423fdaadded_resolve_delegation_credentials()and credential plumbing, but_load_config()itself was never patched — the fix was incomplete or regressed.Reproduction
Start parent agent on a different model (e.g.,
kilo-auto/balanced)Call
delegate_task(goal="Report your model name")Expected: Subagent uses
deepseek/deepseek-v4-proviakilocodeActual: 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/providerparametersBeyond the
_load_configbug,delegate_task()also lacks:modelandproviderfunction parametersmodelandproviderfields in the per-task schema (batch mode)The handler at line 2066 hardcodes
model=creds["model"]with no extraction fromargs:The OpenAI function-calling schema (
DELEGATE_TASK_SCHEMA) also omitsmodelandproviderproperties, so the JSON validator strips them even if the LLM emits them.Relation to Existing Issues
_load_configwas never patched._load_configbug is the reason config settings are ignored._load_config.model/providerparams. Covered by our proposal.Proposed Fix
1. Fix
_load_config()— merge strategyThis ensures:
max_iterations: 50are preserved2. Add
modelandproviderparameters todelegate_task()model: Optional[str] = Noneandprovider: Optional[str] = Noneto the function signatureif model: creds["model"] = model,if provider: creds["provider"] = providerDELEGATE_TASK_SCHEMAto include these propertiesmodel/providerin thetasksarray schema3. Override Priority (after fix)
tasks[i].model/tasks[i].provider(highest)delegate_task(model=..., provider=...)delegation.model/delegation.providerinconfig.yamlImpact
config.yamldelegation settings start working immediately.Environment
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_configfix and themodel/providerparameter additions. Please advise if you'd prefer this split across two PRs or if an active PR already covers any of this scope.