From 202bc371d118dd827b26f01d1cae0b52fb320295 Mon Sep 17 00:00:00 2001 From: Yufeng He <40085740+universeplayer@users.noreply.github.com> Date: Thu, 23 Apr 2026 12:16:26 +0800 Subject: [PATCH] Python: fix FoundryChatClient/FoundryAgent dropping default_headers default_headers was accepted by the constructor and stored on the instance but never forwarded to the AsyncOpenAI client obtained from AIProjectClient.get_openai_client(), so custom headers never reached outbound requests. Forward default_headers through get_openai_client(**kwargs) -- the Azure SDK already supports this kwarg and passes it on to AsyncOpenAI. Added two regression tests and updated the mock-based header test so we cover both the stored-attribute path and the actually-forwarded path. Fixes #5416. --- .../foundry/agent_framework_foundry/_agent.py | 5 ++- .../agent_framework_foundry/_chat_client.py | 6 ++- .../tests/foundry/test_foundry_chat_client.py | 37 +++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/python/packages/foundry/agent_framework_foundry/_agent.py b/python/packages/foundry/agent_framework_foundry/_agent.py index 0c7f93ba1f..09dba4743a 100644 --- a/python/packages/foundry/agent_framework_foundry/_agent.py +++ b/python/packages/foundry/agent_framework_foundry/_agent.py @@ -198,7 +198,10 @@ def __init__( self._should_close_client = True # Get OpenAI client from project - async_client = self.project_client.get_openai_client() + openai_client_kwargs: dict[str, Any] = {} + if default_headers: + openai_client_kwargs["default_headers"] = dict(default_headers) + async_client = self.project_client.get_openai_client(**openai_client_kwargs) super().__init__( async_client=async_client, diff --git a/python/packages/foundry/agent_framework_foundry/_chat_client.py b/python/packages/foundry/agent_framework_foundry/_chat_client.py index 7c9eb3a68c..021b29edb5 100644 --- a/python/packages/foundry/agent_framework_foundry/_chat_client.py +++ b/python/packages/foundry/agent_framework_foundry/_chat_client.py @@ -204,9 +204,13 @@ def __init__( project_client_kwargs["allow_preview"] = allow_preview project_client = AIProjectClient(**project_client_kwargs) + openai_client_kwargs: dict[str, Any] = {} + if default_headers: + openai_client_kwargs["default_headers"] = dict(default_headers) + super().__init__( model=resolved_model, - async_client=project_client.get_openai_client(), + async_client=project_client.get_openai_client(**openai_client_kwargs), default_headers=default_headers, instruction_role=instruction_role, compaction_strategy=compaction_strategy, diff --git a/python/packages/foundry/tests/foundry/test_foundry_chat_client.py b/python/packages/foundry/tests/foundry/test_foundry_chat_client.py index a7c5beb822..9e519b10c7 100644 --- a/python/packages/foundry/tests/foundry/test_foundry_chat_client.py +++ b/python/packages/foundry/tests/foundry/test_foundry_chat_client.py @@ -180,6 +180,43 @@ def test_init_with_default_header() -> None: assert client.default_headers[key] == value +def test_default_headers_forwarded_to_openai_client() -> None: + """Regression: ``default_headers`` must be forwarded to the underlying AsyncOpenAI client. + + Previously, ``FoundryChatClient(default_headers=...)`` stored the headers on the instance + but called ``project_client.get_openai_client()`` without forwarding them, so the headers + never reached outbound HTTP requests. + """ + default_headers = {"x-custom-header": "repro-value"} + mock_openai_client = _make_mock_openai_client() + project_client = MagicMock() + project_client.get_openai_client.return_value = mock_openai_client + + FoundryChatClient( + project_client=project_client, + model=_TEST_FOUNDRY_MODEL, + default_headers=default_headers, + ) + + project_client.get_openai_client.assert_called_once() + forwarded = project_client.get_openai_client.call_args.kwargs.get("default_headers") + assert forwarded is not None + for key, value in default_headers.items(): + assert forwarded.get(key) == value + + +def test_get_openai_client_not_called_with_headers_kwarg_when_unset() -> None: + """When ``default_headers`` is not passed, don't inject an empty dict into the Azure call.""" + mock_openai_client = _make_mock_openai_client() + project_client = MagicMock() + project_client.get_openai_client.return_value = mock_openai_client + + FoundryChatClient(project_client=project_client, model=_TEST_FOUNDRY_MODEL) + + project_client.get_openai_client.assert_called_once() + assert "default_headers" not in project_client.get_openai_client.call_args.kwargs + + def test_init_with_project_endpoint_creates_project_client() -> None: credential = MagicMock() mock_openai_client = _make_mock_openai_client()