mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
test(responses): guard Azure /responses native routing (LIT-2986)
Azure OpenAI native /responses must dispatch to the native responses handler, never the chat-completions bridge. Routing it through the bridge historically collapsed streaming to delta-only events (dropping response.created, output_item.added, content_part.added and the matching .done events) and broke clients like Codex CLI that depend on the full response lifecycle. The existing bridge-flag tests all mock get_provider_responses_api_config, so none covered the real Azure resolution that was the original trigger (config is None -> bridge). These exercise the real ProviderConfigManager and assert azure/* (gpt and o-series) resolves a native responses config and dispatches to the native handler for both streaming and non-streaming, failing if Azure ever falls back to the bridge again.
This commit is contained in:
parent
a8a1472428
commit
da3f58aeed
1 changed files with 84 additions and 0 deletions
|
|
@ -10,12 +10,16 @@ import os
|
|||
import sys
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(
|
||||
0, os.path.abspath("../../..")
|
||||
) # Adds the parent directory to the system path
|
||||
|
||||
import litellm
|
||||
from litellm.types.llms.openai import ResponseAPIUsage, ResponsesAPIResponse
|
||||
from litellm.types.utils import LlmProviders
|
||||
from litellm.utils import ProviderConfigManager
|
||||
|
||||
|
||||
class TestUseResponsesApiBridgeFlag:
|
||||
|
|
@ -280,3 +284,83 @@ class TestUseResponsesApiBridgeFlag:
|
|||
|
||||
mock_native_handler.assert_called_once()
|
||||
assert result is not None
|
||||
|
||||
|
||||
class TestAzureResponsesNativeRoutingRegression:
|
||||
"""Regression coverage for LIT-2986.
|
||||
|
||||
Azure OpenAI native /responses must route to the native responses handler,
|
||||
never the chat-completions bridge. When Azure was (incorrectly) sent through
|
||||
the bridge, streaming collapsed to delta-only events and broke clients such as
|
||||
Codex CLI that depend on the full lifecycle (response.created, output_item.added,
|
||||
content_part.added, the matching .done events, response.completed).
|
||||
|
||||
The trigger was the dispatch branch `responses_api_provider_config is None or
|
||||
use_chat_completions_api is True`. Unlike the tests above, these exercise the
|
||||
*real* provider-config resolution instead of mocking it, so they fail if Azure
|
||||
ever stops resolving a native responses config (the original root cause).
|
||||
"""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model, expected_config",
|
||||
[
|
||||
("gpt-4o", litellm.AzureOpenAIResponsesAPIConfig),
|
||||
("gpt-5", litellm.AzureOpenAIResponsesAPIConfig),
|
||||
("o4-mini", litellm.AzureOpenAIOSeriesResponsesAPIConfig),
|
||||
],
|
||||
)
|
||||
def test_azure_resolves_native_responses_config(self, model, expected_config):
|
||||
config = ProviderConfigManager.get_provider_responses_api_config(
|
||||
model=model, provider=LlmProviders.AZURE
|
||||
)
|
||||
assert config is not None
|
||||
assert isinstance(config, expected_config)
|
||||
|
||||
@patch(
|
||||
"litellm.responses.main.litellm_completion_transformation_handler.response_api_handler"
|
||||
)
|
||||
@patch("litellm.responses.main.base_llm_http_handler.response_api_handler")
|
||||
def test_azure_responses_routes_native_not_bridge(
|
||||
self, mock_native_handler, mock_bridge_handler
|
||||
):
|
||||
mock_native_handler.return_value = MagicMock()
|
||||
mock_bridge_handler.return_value = MagicMock()
|
||||
|
||||
litellm.responses(
|
||||
model="azure/gpt-4o",
|
||||
input="Hello",
|
||||
api_base="https://example.openai.azure.com",
|
||||
api_key="test-key",
|
||||
api_version="2025-04-01-preview",
|
||||
litellm_logging_obj=MagicMock(),
|
||||
)
|
||||
|
||||
mock_native_handler.assert_called_once()
|
||||
mock_bridge_handler.assert_not_called()
|
||||
assert (
|
||||
mock_native_handler.call_args.kwargs["responses_api_provider_config"]
|
||||
is not None
|
||||
)
|
||||
|
||||
@patch(
|
||||
"litellm.responses.main.litellm_completion_transformation_handler.response_api_handler"
|
||||
)
|
||||
@patch("litellm.responses.main.base_llm_http_handler.response_api_handler")
|
||||
def test_azure_streaming_responses_routes_native_not_bridge(
|
||||
self, mock_native_handler, mock_bridge_handler
|
||||
):
|
||||
mock_native_handler.return_value = MagicMock()
|
||||
mock_bridge_handler.return_value = MagicMock()
|
||||
|
||||
litellm.responses(
|
||||
model="azure/gpt-4o",
|
||||
input="Hello",
|
||||
stream=True,
|
||||
api_base="https://example.openai.azure.com",
|
||||
api_key="test-key",
|
||||
api_version="2025-04-01-preview",
|
||||
litellm_logging_obj=MagicMock(),
|
||||
)
|
||||
|
||||
mock_native_handler.assert_called_once()
|
||||
mock_bridge_handler.assert_not_called()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue