diff --git a/agent/client_lifecycle.py b/agent/client_lifecycle.py index cfe6a5cd06..3af0891937 100644 --- a/agent/client_lifecycle.py +++ b/agent/client_lifecycle.py @@ -872,10 +872,13 @@ class ClientLifecycleMixin: def _try_refresh_anthropic_client_credentials(self) -> bool: # Only native Anthropic rotates OAuth tokens; other anthropic_messages providers (MiniMax, Alibaba, ...) # and Azure use static keys — a refresh would pick up the ~/.claude OAuth token and break auth. + # Third-party Anthropic-compatible endpoints under provider 'anthropic' use static keys too; + # skip them with the same detection build_anthropic_client uses. + from agent.anthropic_endpoints import _is_third_party_anthropic_endpoint if ( self.api_mode != "anthropic_messages" or not hasattr(self, "_anthropic_api_key") or self.provider != "anthropic" - or base_url_host_matches(getattr(self, "_anthropic_base_url", "") or "", "azure.com") + or _is_third_party_anthropic_endpoint(getattr(self, "_anthropic_base_url", "") or "") ): return False try: diff --git a/tests/agent/test_anthropic_third_party_oauth_guard.py b/tests/agent/test_anthropic_third_party_oauth_guard.py index 821c562e66..ad92893e8b 100644 --- a/tests/agent/test_anthropic_third_party_oauth_guard.py +++ b/tests/agent/test_anthropic_third_party_oauth_guard.py @@ -75,6 +75,28 @@ class TestOAuthFlagOnRefresh: # And the flag is untouched regardless. assert agent._is_anthropic_oauth is False + def test_third_party_endpoint_skips_refresh(self, agent): + """provider == 'anthropic' on a third-party endpoint must not refresh: the refresh + would swap in native Anthropic credentials the endpoint was never given.""" + agent.api_mode = "anthropic_messages" + agent.provider = "anthropic" + agent._anthropic_api_key = "custom-api-key" + agent._anthropic_base_url = "https://llmbox.bytedance.net" + agent._anthropic_client = MagicMock() + agent._is_anthropic_oauth = False + + with ( + patch("agent.anthropic_credentials.resolve_anthropic_token", + return_value=_OAUTH_LIKE_TOKEN), + patch("agent.anthropic_adapter.build_anthropic_client", + return_value=MagicMock()), + ): + result = agent._try_refresh_anthropic_client_credentials() + + assert result is False + assert agent._anthropic_api_key == "custom-api-key" + assert agent._is_anthropic_oauth is False + class TestOAuthFlagOnCredentialSwap: