delegate_task 404 errors and provider routing fixes

NousResearch/hermes-agent · cluster 17945 · agent

Data as of

Nothing open on GitHub. Fix merged in #26824. Check it covers your case.

The short answer

0open issues
0open PRs
6items grouped
Known?
Yes. 6 related items grouped here, 2 issues already closed.
Fix event
A fix was merged to main in PR #26824. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this unresolved. That is separate from the fix event.
Still open
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.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #26824 fix(delegation): honor api_mode + auto-detect anthropic_messages URLs

    merged to main

    files: hermes_cli/config.py, tests/tools/test_delegate.py, tools/delegate_tool.py

    Show the diff
    • hermes_cli/config.py
      @@ -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
      @@ -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
      @@ -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
      @@ -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
      @@ -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,

3 PRs closed without merging

From the close comments: done elsewhere 1 · other 2

  • #26331 fix(delegate): honor custom provider api mode for direct endpoints · other → #10273, #5697, #11756
  • #26376 fix(delegate): honor api mode for direct endpoints · other → #26210, #26331
  • #33324 fix(tools): recognize api.deepseek.com as deepseek provider in delegate_task · done elsewhere → c445f48, #26824
Closed issues · 2
  • Closed#17945[Bug] delegate_task tool returning HTTP 404
  • Closed#26210delegate_task returns HTTP 404 with DeepSeek provider
How this cluster was grouped
  • Link evidence (partly structural links): 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 item 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.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
agent
Merged PRs
#26824
Closed issues
2
Attempts
3 PRs closed without merging
Fix link checked
16 May 2026

For your agent

The same facts, typed.