hermes - ✅(Solved) Fix delegate_task: per-task model override is silently ignored — children always use parent's model [2 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#17685Fetched 2026-04-30 06:46:08
View on GitHub
Comments
2
Participants
2
Timeline
8
Reactions
0
Author
Participants
Timeline (top)
labeled ×3commented ×2cross-referenced ×2referenced ×1

Error Message

The model key in the task dict is accepted without error but completely discarded.

Root Cause

Root Cause — Three-layer failure

Fix Action

Workaround

Set delegation.provider and delegation.model in config.yaml to route all subagents to a specific model. However, this is a global setting — it cannot be changed per-task in the same parent call.

PR fix notes

PR #12105: fix(delegation): _load_config falls through to hermes_cli config when CLI_CONFIG has no delegation overrides (#11999)

Description (problem / solution / changelog)

Problem

delegate_task ignores delegation.model and delegation.provider from config.yaml — subagents always inherit the parent model.

Root Cause

_load_config() in delegate_tool.py checked if cfg: on CLI_CONFIG["delegation"], but that dict always has default keys (max_iterations, model="", etc.) so it is always truthy. This prevented fallthrough to hermes_cli.config.load_config() which reads ~/.hermes/config.yaml and may contain user-configured delegation.model / delegation.provider values.

Fix

Now checks whether model, provider, or base_url contain non-empty values before using CLI_CONFIG, falling through to the persistent config otherwise.

Tests

  • Added TestLoadConfigFallthrough — verifies empty CLI_CONFIG falls through, non-empty is used
  • Added TestDelegateTaskModelConfigEndToEnd — end-to-end tests ensuring config.yaml delegation model reaches the child AIAgent

All 73 delegation tests pass.

Fixes #11999

Changed files

  • tests/tools/test_delegate.py (modified, +183/-0)
  • tools/delegate_tool.py (modified, +18/-1)

PR #17718: fix: honor per-task model override in delegate_task

Description (problem / solution / changelog)

Summary

The delegate_task tool was silently ignoring the per-task model override field, causing all child subagents to always use the parent's model regardless of per-task specification.

Root Cause

In _build_child_agent() calls within delegate_task(), the model parameter always resolved to creds["model"] (the global delegation model), ignoring any per-task model field. Other per-task fields like role and toolsets correctly used the t.get(...) or global_default pattern.

Fix

Apply the same fallback pattern used for role and toolsets:

# Before (broken):
model=creds["model"],

# After (fixed):
model=t.get("model") or creds["model"],

This allows each task dict in a batch delegation to optionally specify its own model while preserving the default behavior.

Verification

  • python3 -m py_compile tools/delegate_tool.py passes
  • 29 existing subagent/delegate tests pass (tests/agent/test_subagent_*.py, tests/cli/test_cli_interrupt_subagent.py)

Closes #17685

Changed files

  • tools/delegate_tool.py (modified, +1/-1)

Code Example

def delegate_task(
    goal: Optional[str] = None,
    context: Optional[str] = None,
    toolsets: Optional[List[str]] = None,
    tasks: Optional[List[Dict[str, Any]]] = None,
    max_iterations: Optional[int] = None,
    acp_command: Optional[str] = None,
    acp_args: Optional[List[str]]] = None,
    role: Optional[str] = None,
    parent_agent=None,
) -> str:

---

child = _build_child_agent(
    ...
    model=creds["model"],   # <-- always from config, never from task
    ...
)

---

effective_model = model or parent_agent.model

---

{
  "goal": "Return the model name you are using",
  "tasks": [
    {
      "goal": "Return just the model name you are using",
      "model": "qwen/qwen-turbo"
    }
  ]
}

---

"model": {
    "type": "string",
    "description": "Per-task model override (e.g. 'qwen/qwen-turbo'). "
        "Only used when delegation.provider is set in config.yaml, "
        "or as a shorthand that sets the model without changing provider."
},

---

model=creds["model"] if "model" not in t else t["model"],
RAW_BUFFERClick to expand / collapse

Bug Description

delegate_task accepts a model field inside each task object (e.g. model: "qwen/qwen-turbo"), but this field is completely ignored — subagents always inherit the parent agent's model. This affects both batch mode (tasks[].model) and there is no top-level model parameter on delegate_task at all.

Severity: Medium (feature gap, not a crash)


Root Cause — Three-layer failure

Layer 1: No model in the tool schema

In tools/delegate_tool.py (lines 2438–2463), the DELEGATE_TASK_SCHEMA task item properties include goal, context, toolsets, acp_command, acp_args, and role. There is no model property anywhere in the schema.

Additionally, the top-level delegate_task() function signature (line 1812) has no model parameter:

def delegate_task(
    goal: Optional[str] = None,
    context: Optional[str] = None,
    toolsets: Optional[List[str]] = None,
    tasks: Optional[List[Dict[str, Any]]] = None,
    max_iterations: Optional[int] = None,
    acp_command: Optional[str] = None,
    acp_args: Optional[List[str]]] = None,
    role: Optional[str] = None,
    parent_agent=None,
) -> str:

Layer 2: Model resolved exclusively from config

In the task loop at line 1950:

child = _build_child_agent(
    ...
    model=creds["model"],   # <-- always from config, never from task
    ...
)

creds comes from _resolve_delegation_credentials(cfg, parent_agent) (line 1890), which reads only from cfg.get("model") — the delegation.model key in config.yaml. There is no code path that reads a per-task model field.

Layer 3: Silent fallback chain

In _build_child_agent at line 982:

effective_model = model or parent_agent.model

Since model is always None (no per-task override is ever extracted), it silently falls back to the parent agent's model. No warning is logged.


Reproduction

Setup: Parent agent using any model (e.g. minimax/m2.7).

Call:

{
  "goal": "Return the model name you are using",
  "tasks": [
    {
      "goal": "Return just the model name you are using",
      "model": "qwen/qwen-turbo"
    }
  ]
}

Expected: Child uses qwen/qwen-turbo
Actual: Child uses minimax/m2.7 (parent's model), silently

The model key in the task dict is accepted without error but completely discarded.


Proposed Fix

1. Add model to task schema properties (tools/delegate_tool.py, around line 2447):

"model": {
    "type": "string",
    "description": "Per-task model override (e.g. 'qwen/qwen-turbo'). "
        "Only used when delegation.provider is set in config.yaml, "
        "or as a shorthand that sets the model without changing provider."
},

2. Extract and pass per-task model (tools/delegate_tool.py, around line 1950):

model=creds["model"] if "model" not in t else t["model"],

3. (Optional ergonomics) Add top-level model param to delegate_task() function signature for single-task mode parity.


Workaround

Set delegation.provider and delegation.model in config.yaml to route all subagents to a specific model. However, this is a global setting — it cannot be changed per-task in the same parent call.

extent analysis

TL;DR

To fix the issue, add a model property to the task schema and update the code to extract and pass the per-task model when creating child agents.

Guidance

  • Add a model field to the DELEGATE_TASK_SCHEMA in tools/delegate_tool.py to allow per-task model overrides.
  • Update the _build_child_agent function to extract the model from the task dictionary and use it if available.
  • Consider adding a top-level model parameter to the delegate_task function for single-task mode parity.
  • As a temporary workaround, set delegation.provider and delegation.model in config.yaml to route all subagents to a specific model, but note that this is a global setting.

Example

The proposed fix includes example code changes, such as adding the model property to the task schema:

"model": {
    "type": "string",
    "description": "Per-task model override (e.g. 'qwen/qwen-turbo'). "
        "Only used when delegation.provider is set in config.yaml, "
        "or as a shorthand that sets the model without changing provider."
},

And updating the _build_child_agent function to extract the model from the task dictionary:

model=creds["model"] if "model" not in t else t["model"],

Notes

The proposed fix assumes that the model field in the task dictionary takes precedence over the delegation.model setting in config.yaml. If this is not the intended behavior, additional changes may be necessary.

Recommendation

Apply the proposed fix to add support for per-task model overrides, as it provides more flexibility and control over the model used by child agents.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING