# NousResearch/hermes-agent · delegate_task 404 errors and provider routing fixes

## Open now

- Nothing open on GitHub.

Multiple bug reports and fixes addressing HTTP 404 errors from the delegate_task tool, particularly with DeepSeek and other providers. Fixes cover provider auto-detection, API mode handling for direct endpoints, and URL classification for delegation routing.

## TL;DR

- 6 member(s): 0 open issue(s), 2 closed issue(s), 0 open PR(s), 1 merged PR(s), 3 PR(s) closed without merging.
- A fix was merged to main in PR #26824. Verify it addresses your case.
- **Recommended:** read PR #26824 (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: `unresolved`. 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.29`: 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.

## Closed / duplicate issues

- #17945: \[Bug\] delegate_task tool returning HTTP 404
- #26210: delegate_task returns HTTP 404 with DeepSeek provider

## Prior & competing PRs

- **#26824: fix(delegation): honor api_mode + auto-detect anthropic_messages URLs**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `hermes_cli/config.py`, `tests/tools/test_delegate.py`, `tools/delegate_tool.py`
  - fix hunks:
  - `hermes_cli/config.py`

    ```diff
    @@ -1146,6 +1146,10 @@ def _ensure_hermes_home_managed(home: Path):
             "provider": "",    # e.g. "openrouter" (empty = inherit parent provider + credentials)
             "base_url": "",    # direct OpenAI-compatible endpoint for subagents
             "api_key": "",     # API key for delegation.base_url (falls back to OPENAI_API_KEY)
    +        "api_mode": "",    # wire protocol for delegation.base_url: "chat_completions",
    +                           # "codex_responses", or "anthropic_messages". Empty = auto-detect
    +                           # from URL (e.g. /anthropic suffix → anthropic_messages). Set this
    +                           # explicitly for non-standard endpoints the heuristic can't detect.
             # When delegate_task narrows child toolsets explicitly, preserve any
             # MCP toolsets the parent already has enabled. On by default so
             # narrowing (e.g. toolsets=["web","browser"]) expresses "I want these
    ```
  - `tests/tools/test_delegate.py`

    ```diff
    @@ -890,6 +890,63 @@ def test_direct_endpoint_uses_configured_base_url_and_api_key(self):
             self.assertEqual(creds["api_key"], "local-key")
             self.assertEqual(creds["api_mode"], "chat_completions")
     
    +    def test_direct_endpoint_auto_detects_anthropic_messages_suffix(self):
    +        # Issue #10213: Azure AI Foundry exposes Anthropic-compatible models at
    +        # a /anthropic URL suffix. Subagents must pick anthropic_messages
    +        # automatically, matching the main agent's runtime resolver.
    +        parent = _make_mock_parent(depth=0)
    +        cfg = {
    +            "model": "claude-opus-4-6",
    +            "provider": "custom",
    +            "base_url": "https://myfoundry.services.ai.azure.com/anthropic",
    +            "api_key": "foundry-key",
    +        }
    +        creds = _resolve_delegation_credentials(cfg, parent)
    +        self.assertEqual(creds["provider"], "custom")
    +        self.assertEqual(creds["base_url"], "https://myfoundry.services.ai.azure.com/anthropic")
    +        self.assertEqual(creds["api_key"], "foundry-key")
    +        self.assertEqual(creds["api_mode"], "anthropic_messages")
    +
    +    def test_direct_endpoint_honors_explicit_api_mode(self):
    +        # When delegation.api_mode is set explicitly, it overrides URL-based
    +        # detection so users can force a transport on non-standard endpoints.
    +        parent = _make_mock_parent(depth=0)
    +        cfg = {
    +            "model": "claude-opus-4-6",
    +            "provider": "custom",
    +            "base_url": "https://proxy.example.com/v1",
    +            "api_key": "proxy-key",
    +            "api_mode": "anthropic_messages",
    +        }
    +        creds = _resolve_delegation_credentials(cfg, parent)
    +        self.assertEqual(creds["api_mode"], "anthropic_messages")
    +
    +    def test_direct_endpoint_explicit_api_mode_overrides_url_detection(self):
    +        # Explicit api_mode in config always wins over auto-detection.
    +        parent = _make_mock_parent(depth=0)
    +        cfg = {
    +            "model": "claude-opus-4-6",
    +            "provider": "custom",
    +            "base_url": "https://myfoundry.services.ai.azure.com/anthropic",
    +            "api_key": "foundry-key",
    +            "api_mode": "chat_completions",
    +        }
    +        creds = _resolve_delegation_credentials(cfg, parent)
    +        self.assertEqual(creds["api_mode"], "chat_completions")
    +
    +    def test_direct_endpoint_invalid_api_mode_falls_back_to_detection(self):
    +        # An invalid api_mode string must not break detection; fall back to URL heuristic.
    +        parent = _make_mock_parent(depth=0)
    +        cfg = {
    +            "model": "claude-opus-4-6",
    +            "provider": "custom",
    +            "base_url": "https://myfoundry.services.ai.azure.com/anthropic",
    +            "api_key": "foundry-key",
    +            "api_mode": "garbage",
    +        }
    +        creds = _resolve_delegation_credentials(cfg, parent)
    +        self.assertEqual(creds["api_mode"], "anthropic_messages")
    +
         def test_direct_endpoint_returns_none_api_key_when_not_configured(self):
             # When base_url is set without api_key, api_key should be None so
             # _build_child_agent inherits the parent's key (effective_api_key = override or parent).
    ```
  - `tools/delegate_tool.py`

    ```diff
    @@ -2362,6 +2362,7 @@ def _resolve_delegation_credentials(cfg: dict, parent_agent) -> dict:
         configured_provider = str(cfg.get("provider") or "").strip() or None
         configured_base_url = str(cfg.get("base_url") or "").strip() or None
         configured_api_key = [redacted:secret-assignment]"api_key") or "").strip() or None
    +    configured_api_mode = str(cfg.get("api_mode") or "").strip().lower() or None
     
         if configured_base_url:
             # When delegation.api_key is not set, return None so _build_child_agent
    ```

    ```diff
    @@ -2372,9 +2373,17 @@ def _resolve_delegation_credentials(cfg: dict, parent_agent) -> dict:
             # callers to duplicate the key under delegation.api_key.
             api_key = [redacted:secret-assignment]  # None → inherited from parent in _build_child_agent
     
    +        # Use the shared URL-based api_mode detector (same path the main agent's
    +        # runtime resolver uses) so Anthropic-compatible direct endpoints with a
    +        # /anthropic suffix — Azure AI Foundry, MiniMax, Zhipu GLM, LiteLLM
    +        # proxies — pick the right transport automatically. Without this,
    +        # subagents would default to chat_completions and hit 404s on endpoints
    +        # that only speak the Anthropic Messages protocol. Fixes #10213.
    +        from hermes_cli.runtime_provider import _detect_api_mode_for_url
    +
             base_lower = configured_base_url.lower()
             provider = "custom"
    -        api_mode = "chat_completions"
    +        api_mode = _detect_api_mode_for_url(configured_base_url) or "chat_completions"
             if (
                 base_url_hostname(configured_base_url) == "chatgpt.com"
                 and "/backend-api/codex" in base_lower
    ```

    ```diff
    @@ -2388,6 +2397,11 @@ def _resolve_delegation_credentials(cfg: dict, parent_agent) -> dict:
                 provider = "custom"
                 api_mode = "anthropic_messages"
     
    +        # Explicit delegation.api_mode in config always wins. Lets users force
    +        # a transport for non-standard endpoints the URL heuristic can't detect.
    +        if configured_api_mode in {"chat_completions", "codex_responses", "anthropic_messages"}:
    +            api_mode = configured_api_mode
    +
             return {
                 "model": configured_model,
                 "provider": provider,
    ```
- **#26331: fix(delegate): honor custom provider api mode for direct endpoints**. closed without merge
  - maintainer direction: category `uncategorized`; implication `needs_llm`; refs `#10273`, `#5697`, `#11756`
- **#26376: fix(delegate): honor api mode for direct endpoints**. closed without merge
  - maintainer direction: category `uncategorized`; implication `needs_llm`; refs `#26210`, `#26331`
- **#33324: fix(tools): recognize api.deepseek.com as deepseek provider in delegate_task**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `c445f48b78ad9dfb142d2337b51f227bde66cc84`, `#26824`

## Fix status

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