# NousResearch/hermes-agent · delegate_task per-call model/provider override and config handling

## Open now

- 1 issue, 1 PR open on GitHub.
- #51540: delegation.model ignored for opencode-go provider
- PR #58337: fix(delegate): keep child credential pools provider-scoped

Most members concern delegate_task: requests and PRs to accept per-call model/provider overrides, plus reports that subagents inherit the parent model or ignore delegation config such as base_url. A few related items touch endpoint, credential-pool, and ACP command handling during delegation.

## TL;DR

- 80 member(s): 1 open issue(s), 44 closed issue(s), 1 open PR(s), 3 merged PR(s), 31 PR(s) closed without merging.
- A fix was merged to main in PR #41730. Verify it addresses your case.
- **Recommended:** read PR #41730 (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-16894,pr-41730`. 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.03`: 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.

## Open related issues

- #51540: delegation.model ignored for opencode-go provider

## Closed / duplicate issues

- #3719: Feature: Per-call model/provider override on delegate_task
- #5012: \[Feature\]: Allow delegate_task to accept provider/model parameters
- #5508: feat: per-skill model routing + supervisor/execution model config
- #6306: Feature: Allow per-task model selection in delegate_task
- #6825: Bug: delegation.base_url correctly resolved but overwritten before first API call
- #7833: delegate_task can overwrite delegated custom endpoint with parent custom credential pool
- #10995: feat: delegate_task should support per-task model selection
- #14974: \[Feature\]: delegation-per-task-endpoint-overrides
- #15789: feat: per-task model/provider overrides in delegate_task
- #16816: \[Bug\]: Add delegation.acp_command: none config option
- #17685: delegate_task: per-task model override is silently ignored — children always use parent's model
- #17732: Feature: per-call model/provider override in delegate_task
- #18591: Feature: Per-task model override for delegate_task subagents
- #19567: TUI delegation subagent incorrectly routed to copilot-acp instead of configured deepseek provider
- #23467: delegate_task model parameter silently discarded — subagents always inherit parent model
- #24263: Feature: Per-sub-agent provider/model selection in delegate_task
- #26482: delegation model override ignored — subagents always inherit parent provider/model
- #27294: \[Bug\] delegate_task ignores delegation.base_url — subagent always inherits parent model
- #27295: \[Bug\] delegate_task ignores delegation.base_url — subagent always inherits parent model
- #27296: \[Bug\] delegate_task ignores delegation.base_url — subagent always inherits parent model
- #31155: delegation.model override ignored — subagents always inherit parent model
- #32711: delegate_task() lacks model and provider parameters — prevents per-call subagent routing
- #34462: \[TASK\] Implement Per-Call Provider and Model Overrides for delegate_task
- #34489: Per-Task Model Override in delegate_task
- #34727: \[FEATURE\] Task Delegation + Intelligent Model Selection (Phases 7 & 3)
- #34764: feat(delegate): per-task model/provider override in delegate_task tasks array
- #35437: feat: add model/provider/base_url/api_format parameters to delegate_task (consolidating #5012, #10995, #17685, #23467, #32711)
- #37574: feat: add model/provider override param to delegate_task tool
- #41814: Feature: Per-task model override for delegate_task
- #44900: feat(delegation): add model override to delegate_task
- #47014: Feature Request: Per-call model override for delegate_task
- #47295: feat: per-call model routing in delegate_task (multi-model delegation)
- #49332: delegate_task model override ignored — subagents use wrong model, consume unauthorized credits
- #50202: \[Feature\]: per-call model/provider override for delegate_task (multi-model subagent orchestration)
- #51401: Feature Request: Per-Task Model Override in delegate_task
- #52331: \[Feature\]: Per-call model routing for delegate_task subagents
- #53846: delegate_task model parameter not honored — child agents always inherit parent session model
- #56891: Feature: Expose model parameter on delegate_task for per-call model selection
- #58298: Subagent delegation ignores config, always uses credential-pool model (glm-4-flash)
- #58731: Feature Request: Per-subagent model override in delegate_task
- #61195: \[Bug\]: delegation.base_url correctly resolved through init_agent() but subagent's actual API call still routes to OpenRouter → 401
- #61622: feat: support per-subagent model selection in delegate_task
- #62731: Feature Request: Allow delegate_task to use different models per subtask
- #66536: \[Feature\]: Per-call model/provider override for delegate_task

## Prior & competing PRs

- **#7360: fix(delegate): salvage delegate PRs #6933 #6881**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `run_agent.py`, `tests/run_agent/test_agent_guardrails.py`, `tests/tools/test_delegate.py`, `tools/delegate_tool.py`
- **#10996: feat(tools): add model parameter to delegate_task for per-task model selection**. closed without merge · fix tier `suggested`
  - maintainer direction: category `uncategorized`; implication `needs_llm`; refs `#9737`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#16894: fix(delegate): clear acp_command when override_provider is set**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `tools/delegate_tool.py`
- **#17581: Fix delegate_task model/provider precedence and expose per-task overrides**. closed without merge · fix tier `suggested`
  - maintainer direction: category `uncategorized`; implication `needs_llm`; refs `a6f08ff0c`, `#10995`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#17718: fix: honor per-task model override in delegate_task**. 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._
- **#37578: feat: add model/provider override param to delegate_task tool**. 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._
- **#39282: feat(delegate_task): add per-task model/provider override**. 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._
- **#41730: fix(delegate): resolve custom-endpoint subagent pools by endpoint identity**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `agent/credential_pool.py`, `tests/tools/test_delegate.py`, `tools/delegate_tool.py`
  - fix hunks:
  - `agent/credential_pool.py`

    ```diff
    @@ -374,7 +374,7 @@ def _iter_custom_providers(config: Optional[dict] = None):
             yield _normalize_custom_pool_name(name), entry
     
     
    -def get_custom_provider_pool_key(base_url: str, provider_name: Optional[str] = None) -> Optional[str]:
    +def get_custom_provider_pool_key(base_url: Optional[str], provider_name: Optional[str] = None) -> Optional[str]:
         """Look up the custom_providers list in config.yaml and return 'custom:<name>' for a matching base_url.
     
         When provider_name is given, prefer matching by name first (solving the case where
    ```
  - `tests/tools/test_delegate.py`

    ```diff
    @@ -1518,6 +1518,73 @@ def test_different_provider_load_failure_returns_none(self):
     
             self.assertIsNone(result)
     
    +    # --- Custom-endpoint identity resolution (issue #7833) ---
    +
    +    def test_custom_different_endpoint_does_not_inherit_parent_pool(self):
    +        """A child on custom endpoint B must not inherit the parent's custom
    +        endpoint A pool just because both normalize to provider='custom'."""
    +        parent = _make_mock_parent()
    +        parent.provider = "custom"
    +        parent.base_url = "https://endpoint-a.example.com/v1"
    +        parent._credential_pool = [redacted:secret-assignment]"parent_custom_a_pool")
    +
    +        child_pool = MagicMock(name="endpoint_b_pool")
    +        child_pool.has_credentials.return_value = True
    +
    +        def fake_key(base_url, provider_name=None):
    +            return {
    +                "https://endpoint-a.example.com/v1": "custom:endpoint-a",
    +                "https://endpoint-b.example.com/v1": "custom:endpoint-b",
    +            }.get(base_url)
    +
    +        with patch("agent.credential_pool.get_custom_provider_pool_key", side_effect=fake_key), \
    +             patch("agent.credential_pool.load_pool", return_value=child_pool) as load_mock:
    +            result = _resolve_child_credential_pool(
    +                "custom", parent, "https://endpoint-b.example.com/v1"
    +            )
    +
    +        # Loaded the child's OWN endpoint pool, not the parent's.
    +        load_mock.assert_called_once_with("custom:endpoint-b")
    +        self.assertIs(result, child_pool)
    +        self.assertIsNot(result, parent._credential_pool)
    +
    +    def test_custom_same_endpoint_shares_parent_pool(self):
    +        """A child on the SAME custom endpoint as the parent reuses the parent's
    +        pool so rotation/cooldown state stays synchronized."""
    +        parent = _make_mock_parent()
    +        parent.provider = "custom"
    +        parent.base_url = "https://endpoint-a.example.com/v1"
    +        parent._credential_pool = [redacted:secret-assignment]"parent_custom_a_pool")
    +
    +        with patch(
    +            "agent.credential_pool.get_custom_provider_pool_key",
    +            return_value="custom:endpoint-a",
    +        ):
    +            result = _resolve_child_credential_pool(
    +                "custom", parent, "https://endpoint-a.example.com/v1"
    +            )
    +
    +        self.assertIs(result, parent._credential_pool)
    +
    +    def test_custom_unregistered_endpoint_returns_none(self):
    +        """A raw delegation.base_url with no matching custom_providers entry
    +        must NOT inherit the parent's pool — return None so the child keeps its
    +        fixed delegated credential."""
    +        parent = _make_mock_parent()
    +        parent.provider = "custom"
    +        parent.base_url = "https://endpoint-a.example.com/v1"
    +        parent._credential_pool = [redacted:secret-assignment]"parent_custom_a_pool")
    +
    +        with patch(
    +            "agent.credential_pool.get_custom_provider_pool_key",
    +            return_value=None,
    +        ):
    +            result = _resolve_child_credential_pool(
    +                "custom", parent, "https://raw-unregistered.example.com/v1"
    +            )
    +
    +        self.assertIsNone(result)
    +
         def test_build_child_agent_assigns_parent_pool_when_shared(self):
             parent = _make_mock_parent()
             mock_pool = MagicMock()
    ```
  - `tools/delegate_tool.py`

    ```diff
    @@ -1184,7 +1184,9 @@ def _child_thinking(text: str) -> None:
     
         # Share a credential pool with the child when possible so subagents can
         # rotate credentials on rate limits instead of getting pinned to one key.
    -    child_pool = _resolve_child_credential_pool(effective_provider, parent_agent)
    +    child_pool = _resolve_child_credential_pool(
    +        effective_provider, parent_agent, effective_base_url
    +    )
         if child_pool is not None:
             child._credential_pool = [redacted:secret-assignment]
     
    ```

    ```diff
    @@ -2368,7 +2370,11 @@ def delegate_task(
         )
     
     
    -def _resolve_child_credential_pool(effective_provider: Optional[str], parent_agent):
    +def _resolve_child_credential_pool(
    +    effective_provider: Optional[str],
    +    parent_agent,
    +    effective_base_url: Optional[str] = None,
    +):
         """Resolve a credential pool for the child agent.
     
         Rules:
    ```

    ```diff
    @@ -2377,12 +2383,60 @@ def _resolve_child_credential_pool(effective_provider: Optional[str], parent_age
         2. Different provider -> try to load that provider's own pool.
         3. No pool available -> return None and let the child keep the inherited
            fixed credential behavior.
    +
    +    Custom endpoints are a special case: every direct ``delegation.base_url``
    +    runtime collapses to ``provider="custom"``, so bare provider equality would
    +    treat two *different* custom endpoints as interchangeable and let the child
    +    inherit the parent's pool. Leasing from that pool then overwrites the
    +    child's delegated ``base_url`` with the parent's endpoint (issue #7833).
    +    We therefore resolve custom runtimes by endpoint identity (the
    +    ``custom:<name>`` pool key derived from the base_url) and only share the
    +    parent's pool when both resolve to the *same* custom endpoint.
         """
         if not effective_provider:
             return getattr(parent_agent, "_credential_pool", None)
     
         parent_provider = getattr(parent_agent, "provider", None) or ""
         parent_pool = getattr(parent_agent, "_credential_pool", None)
    +
    +    # Custom endpoints: distinguish by endpoint identity, not the bare "custom"
    +    # provider string. Two custom runtimes are only interchangeable when they
    +    # resolve to the same custom:<name> pool key.
    +    if effective_provider == "custom":
    +        try:
    +            from agent.credential_pool import get_custom_provider_pool_key, load_pool
    +
    +            child_key = get_custom_provider_pool_key(effective_base_url)
    +            if child_key is None:
    +                # Unregistered endpoint (raw delegation.base_url with no
    +                # matching custom_providers entry) -> no shared pool exists.
    +                # Keep the child's fixed delegated credential rather than
    +                # risk inheriting the parent's custom endpoint.
    +                return None
    +
    +            # Reuse the parent's pool only when it is the same custom endpoint.
    +            parent_key = get_custom_provider_pool_key(
    +                getattr(parent_agent, "base_url", None)
    +            )
    +            if (
    +                parent_pool is not None
    +                and parent_provider == "custom"
    +                and parent_key is not None
    +                and parent_key == child_key
    +            ):
    +                return parent_pool
    +
    +            pool = load_pool(child_key)
    +            if pool is not None and pool.has_credentials():
    +                return pool
    +        except Exception as exc:
    +            logger.debug(
    +                "Could not resolve custom credential pool for child endpoint '%s': %s",
    +                effective_base_url,
    +                exc,
    +            )
    +        return None
    +
         if parent_pool is not None and effective_provider == parent_provider:
             return parent_pool
     
    ```
- **#41865: fix(delegate): honor model parameter end-to-end (fixes #41821, closes #41814)**. closed without merge · fix tier `suggested`
  - maintainer direction: category `uncategorized`; implication `needs_llm`; refs `#41814`, `#53846`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#43134: feat(delegate_tool): per-task model/provider override**. closed without merge · fix tier `suggested`
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#43185`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#51650: fix(delegation): fix opencode-go subagents ignoring delegation.model config**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `9ae1fa9e39057517ef4cb70511e3e294f39e1a2f`, `#51540`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#59670: fix(tools): respect config model in delegate_task subagent spawn (#58298)**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `0263f1d12`, `#58298`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#61258: fix(delegation): prevent credential pool from overriding explicit delegation.base_url**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `f2c11ff30cd5601a4017cae64cbbeac0a481f5c9`, `#61195`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#61275: fix(delegate): keep delegation.base_url authoritative against credential-pool rotation**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `f2c11ff30cd5601a4017cae64cbbeac0a481f5c9`
- **#64299: feat(delegate): per-call and per-task model/provider overrides for delegate_task**. closed without merge · fix tier `suggested`
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#63461`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#3734: feat: per-call model/provider override on delegate_task**. closed without merge
  - maintainer direction: category `silent_close`; implication `active`
- **#6933: fix(delegate): sync self.base_url with client_kwargs after credential resolution**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#7360`
- **#8485: feat: per-skill model routing + supervisor/execution model config**. closed without merge
  - maintainer direction: category `uncategorized`; implication `needs_llm`
- **#9255: feat(delegate): add task-tier profiles with per-task reasoning_effort and pool validation**. closed without merge
  - maintainer direction: category `stale_abandoned`; implication `active`
- **#9737: feat(delegate): automatic tier routing + task-tier profiles with per-task reasoning_effort**. closed without merge
  - maintainer direction: category `stale_abandoned`; implication `active`
- **#16503: fix(delegate): detect /anthropic URL suffix for proxy endpoints (#7833)**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#13567`
- **#16839: fix(delegate): clear acp_command when override_provider is set**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#16894`
- **#23769: fix(delegation): accept per-call model override on delegate_task**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#23649`
- **#25026: feat(delegate): per-task model and provider override for delegate_task subagents**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#3172`, `#16163`, `#17756`, `#15789`, `#14974`
- **#26486: fix(delegation): honor provider overrides for subagents**. closed without merge
  - maintainer direction: category `silent_close`; implication `active`
- **#34773: feat(delegate): per-task model/provider override in delegate_task tasks array**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#14974`, `#17756`, `#20000`, `#23266`, `#32555`, `#34752`, `#34764`, `#15789`
- **#34776: feat(phase34754): Centralized Model Complexity Configuration**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#34752`, `#34727`, `#10995`, `#13663`
- **#35033: feat(delegate): per-task model/provider overrides (+ fix two latent delegation bugs)**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#14974`, `#25530`, `#23649`, `#17756`
- **#36790: feat(delegate): add per-task model/provider routing**. closed without merge
  - maintainer direction: category `wontfix_bydesign`; implication `wontfix`
- **#41826: feat(delegation): add per-task model override for delegate_task**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#6771`, `#14974`, `#15789`, `#12794`, `#16163`
- **#43185: fix(delegate_tool): address PR #43134 multi-provider review feedback**. closed without merge
  - maintainer direction: category `uncategorized`; implication `needs_llm`
- **#50015: feat(delegate_task): per-call model/provider overrides**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#6771`, `#15789`, `#47014`, `#47295`, `#46880`, `#32711`, `#6306`, `#23769`, `#12715`, `#12794`, `#12503`, `#7586`
- **#55175: fix(delegation): resolve api_key from provider env when base_url + provider set**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `efc1c2d33`
- **#58337: fix(delegate): keep child credential pools provider-scoped**. open
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `bdbb94dc4`
  - files: `tests/tools/test_delegate.py`, `tools/delegate_tool.py`
- **#72834: feat: add per-call model/provider override to delegate_task**. closed without merge
  - maintainer direction: category `uncategorized`; implication `needs_llm`

## Fix status

- Merged to main in PR #41730 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-06-08`.
- Subsystem: `agent`
