fix(moa): route native anthropic OAuth references through provider branch

MoA's _slot_runtime() whitelists providers that must keep their provider
identity (so call_llm runs their provider branch) instead of being treated
as a plain custom endpoint via forwarded base_url/api_key. Native anthropic
was missing from this set.

Native anthropic subscription OAuth setup-tokens (sk-ant-oat*) require Bearer
auth plus the 'anthropic-beta: oauth-*' header, which only the anthropic
provider branch adds. Without the whitelist entry, the slot's base_url/api_key
were forwarded and call_llm sent the OAuth token as x-api-key, which Anthropic
rejects with a bare 429 (rate_limit_error with no quota details). This made
anthropic references in MoA presets fail every time.

Add 'anthropic' to the whitelist so native anthropic reference/aggregator
slots route through the provider branch. Extends upstream 9229d0db1 which
added 'nous' for the same reason.
This commit is contained in:
Chufeng Fan 2026-06-29 12:11:20 +08:00 committed by Teknium
parent 698c287fd0
commit 4d43669921
2 changed files with 43 additions and 1 deletions

View file

@ -99,7 +99,7 @@ def _slot_runtime(slot: dict[str, str]) -> dict[str, Any]:
# provider-backed targets whose provider branch adds auth refresh,
# request metadata, or request-shape adapters. Keep those providers
# identified by name.
if resolved_provider in {"nous", "openai-codex", "xai-oauth"}:
if resolved_provider in {"nous", "anthropic", "openai-codex", "xai-oauth"}:
return out
# Pass the resolved endpoint through so call_llm builds the request for
# the provider's actual API surface instead of auto-detecting. base_url

View file

@ -678,3 +678,45 @@ def test_moa_facade_reruns_references_on_new_turn(monkeypatch, tmp_path):
# 2 references × 2 distinct turns = 4 reference runs.
assert len(ref_runs) == 4
def test_slot_runtime_anthropic_oauth_routes_through_provider_branch(monkeypatch):
"""Native anthropic slots must NOT forward base_url/api_key.
anthropic OAuth setup-tokens (sk-ant-oat*) require Bearer auth + the
``anthropic-beta: oauth-*`` header, which only the provider branch of
call_llm adds. If _slot_runtime forwarded base_url/api_key, call_llm would
treat the slot as a plain custom endpoint and send the token as x-api-key,
which Anthropic rejects with a bare 429. So a whitelisted provider
(anthropic) returns only provider/model, while a non-whitelisted provider
(openrouter) forwards the resolved base_url/api_key.
"""
from agent import moa_loop
def fake_resolve(*, requested, target_model=None):
return {
"provider": requested,
"base_url": "https://resolved.example/v1",
"api_key": "resolved-key",
}
monkeypatch.setattr(
"hermes_cli.runtime_provider.resolve_runtime_provider", fake_resolve
)
# Whitelisted: anthropic must skip base_url/api_key forwarding.
anthropic_rt = moa_loop._slot_runtime(
{"provider": "anthropic", "model": "claude-opus-4-8"}
)
assert anthropic_rt == {"provider": "anthropic", "model": "claude-opus-4-8"}
assert "base_url" not in anthropic_rt
assert "api_key" not in anthropic_rt
# Non-whitelisted: openrouter still forwards the resolved endpoint.
other_rt = moa_loop._slot_runtime(
{"provider": "openrouter", "model": "some-model"}
)
assert other_rt["provider"] == "openrouter"
assert other_rt["model"] == "some-model"
assert other_rt["base_url"] == "https://resolved.example/v1"
assert other_rt["api_key"] == "resolved-key"