Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -373,6 +381,7 @@ def __init__(
else:
self.default_headers = None
self.instruction_role = instruction_role
self._use_azure_client = use_azure_client
Comment thread
Oxygen56 marked this conversation as resolved.
if use_azure_client:
self.OTEL_PROVIDER_NAME = "azure.ai.openai" # type: ignore[misc]

Expand Down Expand Up @@ -589,6 +598,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, 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.

Expand All @@ -603,6 +618,8 @@ def _prepare_tools_for_openai(
elif isinstance(tool, MutableMapping):
typed_tool = cast(MutableMapping[str, Any], tool)
if typed_tool.get("type") == "web_search":
if self._use_azure_client:
raise ValueError(_AZURE_WEB_SEARCH_UNSUPPORTED_MSG)
# 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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import inspect
import json
import os
import re
from typing import Any, cast
from unittest.mock import MagicMock, patch

Expand All @@ -28,6 +29,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(
Expand Down Expand Up @@ -1252,6 +1256,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=re.escape(_AZURE_WEB_SEARCH_UNSUPPORTED_MSG),
):
client._prepare_tools_for_openai([web_search_tool])
Comment thread
Oxygen56 marked this conversation as resolved.


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:
Expand Down
Loading