diff --git a/python/packages/kagent-adk/src/kagent/adk/_a2a.py b/python/packages/kagent-adk/src/kagent/adk/_a2a.py index 7b08e6f17..a62f00d67 100644 --- a/python/packages/kagent-adk/src/kagent/adk/_a2a.py +++ b/python/packages/kagent-adk/src/kagent/adk/_a2a.py @@ -52,6 +52,19 @@ def thread_dump(request: Request) -> PlainTextResponse: kagent_url_override = os.getenv("KAGENT_URL") +def _configure_anthropic_client() -> None: + """ + Configure the Anthropic client to use ANTHROPIC_BASE_URL. + + Reads ANTHROPIC_BASE_URL from the environment (matching the Go-side + env.AnthropicAPIBaseURL registration) and logs its presence. The Anthropic + SDK natively reads ANTHROPIC_BASE_URL, so no explicit remapping is needed. + """ + anthropic_api_base = os.getenv("ANTHROPIC_BASE_URL") + if anthropic_api_base: + logger.info(f"Configured Anthropic client with base URL: {anthropic_api_base}") + + class KAgentApp: def __init__( self, @@ -86,6 +99,8 @@ def __init__( self.agent_config = agent_config def build(self, local=False) -> FastAPI: + _configure_anthropic_client() + session_service = InMemorySessionService() token_service = None http_client: Optional[httpx.AsyncClient] = None diff --git a/python/packages/kagent-adk/src/kagent/adk/models/_anthropic.py b/python/packages/kagent-adk/src/kagent/adk/models/_anthropic.py index b8e9e68cd..b1313fd8d 100644 --- a/python/packages/kagent-adk/src/kagent/adk/models/_anthropic.py +++ b/python/packages/kagent-adk/src/kagent/adk/models/_anthropic.py @@ -44,11 +44,12 @@ def _create_http_client(self): @cached_property def _anthropic_client(self) -> AsyncAnthropic: api_key = self._api_key or os.environ.get("ANTHROPIC_API_KEY") + base_url = self.base_url or os.environ.get("ANTHROPIC_BASE_URL") kwargs = {} if api_key: kwargs["api_key"] = api_key - if self.base_url: - kwargs["base_url"] = self.base_url + if base_url: + kwargs["base_url"] = base_url if self.extra_headers: kwargs["default_headers"] = self.extra_headers diff --git a/python/packages/kagent-adk/tests/unittests/models/test_anthropic.py b/python/packages/kagent-adk/tests/unittests/models/test_anthropic.py index c69739c12..1e7f8f5d9 100644 --- a/python/packages/kagent-adk/tests/unittests/models/test_anthropic.py +++ b/python/packages/kagent-adk/tests/unittests/models/test_anthropic.py @@ -35,6 +35,23 @@ def test_client_uses_base_url(self): _ = llm._anthropic_client assert mock_anthropic.call_args.kwargs["base_url"] == "https://proxy.internal/anthropic" + def test_client_falls_back_to_env_base_url(self): + llm = KAgentAnthropicLlm(model="claude-3-sonnet-20240229") + with mock.patch.dict("os.environ", {"ANTHROPIC_BASE_URL": "https://env-proxy.internal/anthropic"}): + with mock.patch("kagent.adk.models._anthropic.AsyncAnthropic") as mock_anthropic: + mock_anthropic.return_value = mock.MagicMock(spec=AsyncAnthropic) + _ = llm._anthropic_client + assert mock_anthropic.call_args.kwargs["base_url"] == "https://env-proxy.internal/anthropic" + + def test_explicit_base_url_takes_precedence_over_env(self): + llm = KAgentAnthropicLlm(model="claude-3-sonnet-20240229", base_url="https://explicit.internal/anthropic") + with mock.patch.dict("os.environ", {"ANTHROPIC_BASE_URL": "https://env.internal/anthropic"}): + with mock.patch("kagent.adk.models._anthropic.AsyncAnthropic") as mock_anthropic: + mock_anthropic.return_value = mock.MagicMock(spec=AsyncAnthropic) + _ = llm._anthropic_client + # Explicit base_url wins over env + assert mock_anthropic.call_args.kwargs["base_url"] == "https://explicit.internal/anthropic" + def test_client_uses_extra_headers(self): llm = KAgentAnthropicLlm(model="claude-3-sonnet-20240229", extra_headers={"X-Org": "test-org"}) with mock.patch("kagent.adk.models._anthropic.AsyncAnthropic") as mock_anthropic: