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

Subagent delegation hardcoded api_mode='chat_completions' for any
delegation.base_url that didn't match three specific hostnames
(chatgpt.com, api.anthropic.com, api.kimi.com/coding), and never
read delegation.api_mode from config. Azure AI Foundry's
https://foundry.services.ai.azure.com/anthropic endpoint fell through
and got chat_completions, causing 404s on every delegate_task call.

The main agent already handles this correctly via the shared
_detect_api_mode_for_url() helper (anything ending in /anthropic →
anthropic_messages); delegation reimplemented its own narrower check.

Reuse the shared detector and honor an explicit delegation.api_mode
when set so users can also force the transport on non-standard
endpoints the URL heuristic can't classify.

Fixes #10213.

Co-authored-by: HiddenPuppy <HiddenPuppy@users.noreply.github.com>
This commit is contained in:
Teknium 2026-05-16 01:00:27 -07:00 committed by GitHub
parent 74d0b392e7
commit c445f48b78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 76 additions and 1 deletions

View file

@ -890,6 +890,63 @@ class TestDelegationCredentialResolution(unittest.TestCase):
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).