From ea17b1e878305d01d0c6c2d5422b253f589cc41f Mon Sep 17 00:00:00 2001 From: Autumn Date: Mon, 1 Jun 2026 01:33:25 +0800 Subject: [PATCH 1/3] Fix: Skip web_search_options for Azure OpenAI Chat Completions API Azure OpenAI Chat Completions API does not support the web_search_options parameter. Sending it results in a 400 error: 'Unknown parameter: web_search_options'. This fix: - Stores the use_azure_client flag during initialization - In _prepare_tools_for_openai, skips web search tools when the client is Azure-based, logging a warning that guides users to the Responses API (OpenAIChatClient) for web search support on Azure Closes #3629 Co-Authored-By: Claude Opus 4.8 --- .../_chat_completion_client.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/python/packages/openai/agent_framework_openai/_chat_completion_client.py b/python/packages/openai/agent_framework_openai/_chat_completion_client.py index a6878c9f2d..8937ab4dea 100644 --- a/python/packages/openai/agent_framework_openai/_chat_completion_client.py +++ b/python/packages/openai/agent_framework_openai/_chat_completion_client.py @@ -373,6 +373,7 @@ def __init__( else: self.default_headers = None self.instruction_role = instruction_role + self._use_azure_client = use_azure_client if use_azure_client: self.OTEL_PROVIDER_NAME = "azure.ai.openai" # type: ignore[misc] @@ -589,6 +590,12 @@ def _prepare_tools_for_openai( Converts FunctionTool to JSON schema format. Web search tools are routed to web_search_options parameter. All other tools pass through unchanged. + Note: + Azure OpenAI Chat Completions API does not support ``web_search_options``. + When configured with an Azure endpoint, web search tools are silently + excluded. Use :class:`~agent_framework.openai.OpenAIChatClient` (Responses + API) for web search support on Azure. + Args: tools: Tool(s) to prepare. @@ -603,8 +610,15 @@ def _prepare_tools_for_openai( elif isinstance(tool, MutableMapping): typed_tool = cast(MutableMapping[str, Any], tool) if typed_tool.get("type") == "web_search": - # Web search is handled via web_search_options, not tools array - web_search_options = {k: v for k, v in typed_tool.items() if k != "type"} + if self._use_azure_client: + logger.warning( + "Web search is not supported by the Azure OpenAI Chat Completions API " + "and will be ignored. Use agent_framework.openai.OpenAIChatClient " + "(Responses API) for web search support on Azure." + ) + else: + # Web search is handled via web_search_options, not tools array + web_search_options = {k: v for k, v in typed_tool.items() if k != "type"} else: # Pass through all other dict-based tools unchanged chat_tools.append(typed_tool) From 3dbe723dd3ba8da65692d6c00cf2518557a69239 Mon Sep 17 00:00:00 2001 From: Oxygen56 <1391083091@qq.com> Date: Tue, 2 Jun 2026 22:46:29 +0800 Subject: [PATCH 2/3] fix: raise ValueError instead of silently ignoring web search on Azure Address review feedback: silent logger.warning was too easy to miss. Raising ValueError ensures callers know immediately that web search is incompatible with Azure Chat Completions and directs them to the Responses API alternative. - Changed logger.warning to ValueError in _prepare_tools_for_openai - Added test_prepare_tools_with_web_search_on_azure_raises - Added test_prepare_tools_with_web_search_on_openai_allowed --- .../_chat_completion_client.py | 20 ++++++----- .../test_openai_chat_completion_client.py | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/python/packages/openai/agent_framework_openai/_chat_completion_client.py b/python/packages/openai/agent_framework_openai/_chat_completion_client.py index 8937ab4dea..6bd1235be9 100644 --- a/python/packages/openai/agent_framework_openai/_chat_completion_client.py +++ b/python/packages/openai/agent_framework_openai/_chat_completion_client.py @@ -85,6 +85,14 @@ logger = logging.getLogger("agent_framework.openai") +# Error message shared with tests — extracted to a constant to keep the +# implementation and its assertions in sync. +_AZURE_WEB_SEARCH_UNSUPPORTED_MSG = ( + "Web search is not supported by the Azure OpenAI Chat Completions API. " + "Use agent_framework.openai.OpenAIChatClient (Responses API) for " + "web search support on Azure." +) + DEFAULT_AZURE_OPENAI_CHAT_COMPLETION_API_VERSION = "2024-12-01-preview" ResponseModelBoundT = TypeVar("ResponseModelBoundT", bound=BaseModel) @@ -592,9 +600,9 @@ def _prepare_tools_for_openai( Note: Azure OpenAI Chat Completions API does not support ``web_search_options``. - When configured with an Azure endpoint, web search tools are silently - excluded. Use :class:`~agent_framework.openai.OpenAIChatClient` (Responses - API) for web search support on Azure. + When configured with an Azure endpoint, passing web search tools raises + :class:`ValueError`. Use :class:`~agent_framework.openai.OpenAIChatClient` + (Responses API) for web search support on Azure. Args: tools: Tool(s) to prepare. @@ -611,11 +619,7 @@ def _prepare_tools_for_openai( typed_tool = cast(MutableMapping[str, Any], tool) if typed_tool.get("type") == "web_search": if self._use_azure_client: - logger.warning( - "Web search is not supported by the Azure OpenAI Chat Completions API " - "and will be ignored. Use agent_framework.openai.OpenAIChatClient " - "(Responses API) for web search support on Azure." - ) + raise ValueError(_AZURE_WEB_SEARCH_UNSUPPORTED_MSG) else: # Web search is handled via web_search_options, not tools array web_search_options = {k: v for k, v in typed_tool.items() if k != "type"} diff --git a/python/packages/openai/tests/openai/test_openai_chat_completion_client.py b/python/packages/openai/tests/openai/test_openai_chat_completion_client.py index 85e12b8626..39b13e3759 100644 --- a/python/packages/openai/tests/openai/test_openai_chat_completion_client.py +++ b/python/packages/openai/tests/openai/test_openai_chat_completion_client.py @@ -27,6 +27,9 @@ from pytest import param from agent_framework_openai import OpenAIChatCompletionClient, RawOpenAIChatCompletionClient +from agent_framework_openai._chat_completion_client import ( + _AZURE_WEB_SEARCH_UNSUPPORTED_MSG, +) from agent_framework_openai._exceptions import OpenAIContentFilterException skip_if_openai_integration_tests_disabled = pytest.mark.skipif( @@ -1215,6 +1218,39 @@ def test_prepare_tools_with_web_search_no_location( assert result["web_search_options"] == {} +def test_prepare_tools_with_web_search_on_azure_raises( + openai_unit_test_env: dict[str, str], +) -> None: + """Test that web search raises ValueError when configured with Azure endpoint.""" + client = OpenAIChatCompletionClient( + azure_endpoint="https://test.openai.azure.com", + model="gpt-4o-mini", + api_key="test-key", + ) + + web_search_tool = OpenAIChatCompletionClient.get_web_search_tool() + + with pytest.raises( + ValueError, + match=_AZURE_WEB_SEARCH_UNSUPPORTED_MSG, + ): + client._prepare_tools_for_openai([web_search_tool]) + + +def test_prepare_tools_with_web_search_on_openai_allowed( + openai_unit_test_env: dict[str, str], +) -> None: + """Test that web search works normally on non-Azure client.""" + client = OpenAIChatCompletionClient() + + web_search_tool = OpenAIChatCompletionClient.get_web_search_tool() + + result = client._prepare_tools_for_openai([web_search_tool]) + + # Non-Azure client should include web_search_options + assert "web_search_options" in result + + def test_prepare_options_with_instructions( openai_unit_test_env: dict[str, str], ) -> None: From ae68444b3902521e828539bbd61c5fdbad36c8d9 Mon Sep 17 00:00:00 2001 From: Oxygen56 <1391083091@qq.com> Date: Thu, 9 Jul 2026 00:18:30 +0800 Subject: [PATCH 3/3] Fix Azure web search test regex --- .../openai/agent_framework_openai/_chat_completion_client.py | 5 ++--- .../tests/openai/test_openai_chat_completion_client.py | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/packages/openai/agent_framework_openai/_chat_completion_client.py b/python/packages/openai/agent_framework_openai/_chat_completion_client.py index 91ef2ff7ff..fee47e54da 100644 --- a/python/packages/openai/agent_framework_openai/_chat_completion_client.py +++ b/python/packages/openai/agent_framework_openai/_chat_completion_client.py @@ -620,9 +620,8 @@ def _prepare_tools_for_openai( if typed_tool.get("type") == "web_search": if self._use_azure_client: raise ValueError(_AZURE_WEB_SEARCH_UNSUPPORTED_MSG) - else: - # Web search is handled via web_search_options, not tools array - web_search_options = {k: v for k, v in typed_tool.items() if k != "type"} + # Web search is handled via web_search_options, not tools array + web_search_options = {k: v for k, v in typed_tool.items() if k != "type"} else: # Pass through all other dict-based tools unchanged chat_tools.append(typed_tool) diff --git a/python/packages/openai/tests/openai/test_openai_chat_completion_client.py b/python/packages/openai/tests/openai/test_openai_chat_completion_client.py index c2fddf3fa5..8183678a5c 100644 --- a/python/packages/openai/tests/openai/test_openai_chat_completion_client.py +++ b/python/packages/openai/tests/openai/test_openai_chat_completion_client.py @@ -3,6 +3,7 @@ import inspect import json import os +import re from typing import Any, cast from unittest.mock import MagicMock, patch @@ -1269,7 +1270,7 @@ def test_prepare_tools_with_web_search_on_azure_raises( with pytest.raises( ValueError, - match=_AZURE_WEB_SEARCH_UNSUPPORTED_MSG, + match=re.escape(_AZURE_WEB_SEARCH_UNSUPPORTED_MSG), ): client._prepare_tools_for_openai([web_search_tool])