diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index 879792601..a7a463978 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -687,6 +687,15 @@ def _resolve_api_key_provider() -> Tuple[Optional[OpenAI], Optional[str]]: if pconfig.auth_type != "api_key": continue if provider_id == "anthropic": + # Only try anthropic when the user has explicitly configured it. + # Without this gate, Claude Code credentials get silently used + # as auxiliary fallback when the user's primary provider fails. + try: + from hermes_cli.auth import is_provider_explicitly_configured + if not is_provider_explicitly_configured("anthropic"): + continue + except ImportError: + pass return _try_anthropic() pool_present, entry = _select_pool_entry(provider_id) diff --git a/tests/agent/test_auxiliary_client.py b/tests/agent/test_auxiliary_client.py index 5b2da840c..17f4dc3c8 100644 --- a/tests/agent/test_auxiliary_client.py +++ b/tests/agent/test_auxiliary_client.py @@ -1111,3 +1111,45 @@ class TestCallLlmPaymentFallback: task="compression", messages=[{"role": "user", "content": "hello"}], ) + + +# --------------------------------------------------------------------------- +# Gate: _resolve_api_key_provider must skip anthropic when not configured +# --------------------------------------------------------------------------- + + +def test_resolve_api_key_provider_skips_unconfigured_anthropic(monkeypatch): + """_resolve_api_key_provider must not try anthropic when user never configured it.""" + from collections import OrderedDict + from hermes_cli.auth import ProviderConfig + + # Build a minimal registry with only "anthropic" so the loop is guaranteed + # to reach it without being short-circuited by earlier providers. + fake_registry = OrderedDict({ + "anthropic": ProviderConfig( + id="anthropic", + name="Anthropic", + auth_type="api_key", + inference_base_url="https://api.anthropic.com", + api_key_env_vars=("ANTHROPIC_API_KEY",), + ), + }) + + called = [] + + def mock_try_anthropic(): + called.append("anthropic") + return None, None + + monkeypatch.setattr("agent.auxiliary_client._try_anthropic", mock_try_anthropic) + monkeypatch.setattr("hermes_cli.auth.PROVIDER_REGISTRY", fake_registry) + monkeypatch.setattr( + "hermes_cli.auth.is_provider_explicitly_configured", + lambda pid: False, + ) + + from agent.auxiliary_client import _resolve_api_key_provider + _resolve_api_key_provider() + + assert "anthropic" not in called, \ + "_try_anthropic() should not be called when anthropic is not explicitly configured"