diff --git a/tests/harness_suites/chat_live_azure/test_azure_ai_chat_live.py b/tests/harness_suites/chat_live_azure/test_azure_ai_chat_live.py new file mode 100644 index 00000000000..6f02e9eb43b --- /dev/null +++ b/tests/harness_suites/chat_live_azure/test_azure_ai_chat_live.py @@ -0,0 +1,328 @@ +# What is this? +## Unit tests for Azure AI integration + +import os +import sys +import traceback + +from dotenv import load_dotenv + +import litellm.types +import litellm.types.utils +import json +from litellm.llms.custom_httpx.http_handler import HTTPHandler + +# from base_rerank_unit_tests import BaseLLMRerankTest + +load_dotenv() + +sys.path.insert( + 0, os.path.abspath("../..") +) # Adds the parent directory to the system path +from unittest.mock import MagicMock, patch + +import pytest + +import litellm +from litellm import completion + +AZURE_AI_API_BASE = os.getenv("AZURE_AI_API_BASE") + +class AzureModelRouterStreamingCallback( + litellm.integrations.custom_logger.CustomLogger +): + """ + Custom callback to capture streaming cost tracking for Azure Model Router. + """ + + def __init__(self): + self.standard_logging_payload = None + self.response_cost = None + self.async_success_called = False + self.complete_streaming_response = None + super().__init__() + + async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): + print(f"async_log_success_event called") + self.async_success_called = True + self.standard_logging_payload = kwargs.get("standard_logging_object") + self.complete_streaming_response = kwargs.get("complete_streaming_response") + + if self.standard_logging_payload: + self.response_cost = self.standard_logging_payload.get("response_cost") + print( + f"standard_logging_payload model: {self.standard_logging_payload.get('model')}" + ) + print(f"standard_logging_payload response_cost: {self.response_cost}") + + if self.complete_streaming_response: + print( + f"complete_streaming_response model: {self.complete_streaming_response.model}" + ) + print( + f"complete_streaming_response usage: {self.complete_streaming_response.usage}" + ) + + +@pytest.mark.asyncio +async def test_azure_ai_request_format(): + """ + Test that Azure AI requests are formatted correctly with the proper endpoint and parameters + for both synchronous and asynchronous calls + """ + + litellm._turn_on_debug() + + # Set up the test parameters + api_key = os.getenv("AZURE_AI_API_KEY") + api_base = os.getenv("AZURE_AI_API_BASE") + model = "azure_ai/gpt-4.1-mini" + messages = [ + {"role": "user", "content": "hi"}, + {"role": "assistant", "content": "Hello! How can I assist you today?"}, + {"role": "user", "content": "hi"}, + ] + + await litellm.acompletion( + custom_llm_provider="azure_ai", + api_key=api_key, + api_base=api_base, + model=model, + messages=messages, + ) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("model", ["azure/gpt5_series/gpt-5-mini", "azure/gpt-5-mini"]) +async def test_azure_gpt5_reasoning(model): + litellm._turn_on_debug() + response = await litellm.acompletion( + model=model, + messages=[{"role": "user", "content": "What is the capital of France?"}], + reasoning_effort="minimal", + max_tokens=10, + api_base=os.getenv("AZURE_AI_API_BASE"), + api_key=os.getenv("AZURE_AI_API_KEY"), + ) + print("response: ", response) + assert response.choices[0].message.content is not None + + +def test_completion_azure(): + try: + from litellm import completion_cost + + litellm.set_verbose = False + ## Test azure call + response = completion( + model="azure_ai/gpt-4.1-mini", + api_base=os.getenv("AZURE_AI_API_BASE"), + messages=[ + { + "role": "user", + "content": "Hello, how are you?", + } + ], + api_key=os.getenv("AZURE_AI_API_KEY"), + ) + print(f"response: {response}") + print(f"response hidden params: {response._hidden_params}") + print(response) + + cost = completion_cost(completion_response=response) + assert cost > 0.0 + print("Cost for azure completion request", cost) + except Exception as e: + pytest.fail(f"Error occurred: {e}") + + +@pytest.mark.parametrize( + "api_base", + [ + AZURE_AI_API_BASE, + f"{AZURE_AI_API_BASE}/openai/deployments/gpt-4.1-mini/chat/completions?api-version=2023-03-15-preview", + ], +) +def test_completion_azure_ai_gpt_4o_with_flexible_api_base(api_base): + try: + litellm.set_verbose = True + + response = completion( + model="azure_ai/gpt-4.1-mini", + api_base=api_base, + api_key=os.getenv("AZURE_AI_API_KEY"), + messages=[{"role": "user", "content": "What is the meaning of life?"}], + ) + + print(response) + except litellm.Timeout as e: + pass + except Exception as e: + pytest.fail(f"Error occurred: {e}") + + +@pytest.mark.asyncio +async def test_azure_ai_model_router(): + """ + Test Azure AI model router non-streaming response cost tracking. + Verifies that the flat cost of $0.14 per M input tokens is applied. + + Tests the pattern: azure_ai/model_router/ + Where deployment-name is the Azure deployment (e.g., "azure-model-router"). + The model_router prefix is stripped before sending to Azure API. + """ + from litellm.llms.azure_ai.cost_calculator import ( + calculate_azure_model_router_flat_cost, + ) + + litellm._turn_on_debug() + response = await litellm.acompletion( + model="azure_ai/model_router/azure-model-router", + messages=[{"role": "user", "content": "hi who is this"}], + api_base=os.getenv("AZURE_MODEL_ROUTER_API_BASE"), + api_key=os.getenv("AZURE_MODEL_ROUTER_API_KEY"), + ) + print("response: ", response) + + # Check response cost + tracked_cost = response._hidden_params["response_cost"] + assert tracked_cost > 0 + print("Tracked cost: ", tracked_cost) + + # Verify flat cost is included using the helper function + usage = response.usage + if usage and usage.prompt_tokens: + expected_flat_cost = calculate_azure_model_router_flat_cost( + model="model_router/azure-model-router", prompt_tokens=usage.prompt_tokens + ) + print(f"Prompt tokens: {usage.prompt_tokens}") + print(f"Expected flat cost: ${expected_flat_cost:.9f}") + print(f"Total tracked cost: ${tracked_cost:.9f}") + + # Total cost should be at least the flat cost + assert ( + tracked_cost >= expected_flat_cost + ), f"Cost ${tracked_cost:.9f} should be >= flat cost ${expected_flat_cost:.9f}" + + # Verify the flat cost is non-zero + assert expected_flat_cost > 0, "Flat cost should be greater than 0" + + +@pytest.mark.asyncio +async def test_azure_ai_model_router_streaming_model_in_chunk(): + """ + Test that Azure AI model router streaming returns the actual model in each chunk. + The response should contain the actual model used (e.g., gpt-4.1-nano) not the request model (azure-model-router). + """ + litellm._turn_on_debug() + response = await litellm.acompletion( + model="azure_ai/azure-model-router", + messages=[{"role": "user", "content": "hi"}], + api_base=os.getenv("AZURE_MODEL_ROUTER_API_BASE"), + api_key=os.getenv("AZURE_MODEL_ROUTER_API_KEY"), + stream=True, + ) + + # Collect chunks and check model field + chunks_with_model = [] + async for chunk in response: + print(f"Chunk model: {chunk.model}") + if chunk.model and chunk.model.strip(): + chunks_with_model.append(chunk.model) + + print(f"All chunk models: {chunks_with_model}") + + # At least some chunks should have a model + assert len(chunks_with_model) > 0, "No chunks had a model field set" + + # The model should NOT be azure-model-router (the request model) + # It should be the actual model from the response (e.g., gpt-4.1-nano, gpt-5-nano, etc.) + for model in chunks_with_model: + assert ( + model != "azure-model-router" + ), f"Chunk model should be actual model, not request model. Got: {model}" + # The actual model should be a real model name like gpt-4.1-nano, gpt-5-nano, etc. + print(f"Verified chunk has actual model: {model}") + + +@pytest.mark.asyncio +async def test_azure_ai_model_router_streaming_cost_with_stream_options(): + """ + Test Azure AI model router streaming cost tracking with stream_options include_usage=True. + This tests the specific case where cost tracking fails with stream_options. + """ + litellm.logging_callback_manager._reset_all_callbacks() + test_callback = AzureModelRouterStreamingCallback() + litellm.callbacks = [test_callback] + + try: + litellm._turn_on_debug() + response = await litellm.acompletion( + model="azure_ai/azure-model-router", + messages=[{"role": "user", "content": "hi"}], + api_base=os.getenv("AZURE_MODEL_ROUTER_API_BASE"), + api_key=os.getenv("AZURE_MODEL_ROUTER_API_KEY"), + stream=True, + stream_options={"include_usage": True}, + ) + + # Consume the stream and check chunks + full_response = "" + chunks_with_model = [] + async for chunk in response: + print( + f"Chunk: model={chunk.model}, choices={len(chunk.choices) if chunk.choices else 0}" + ) + if chunk.model: + chunks_with_model.append(chunk.model) + if ( + chunk.choices + and chunk.choices[0].delta + and chunk.choices[0].delta.content + ): + full_response += chunk.choices[0].delta.content + + print(f"Full streamed response: {full_response}") + print(f"Chunks with model: {chunks_with_model}") + + # Give async logging time to complete + import asyncio + + await asyncio.sleep(1) + + # Verify callback was called + assert ( + test_callback.async_success_called is True + ), "async_log_success_event was not called" + assert ( + test_callback.standard_logging_payload is not None + ), "standard_logging_payload is None" + + # Check response cost + print(f"Final response_cost: {test_callback.response_cost}") + + # The first chunk may have the request model (azure-model-router) because it's created + # before the API response is received. Subsequent chunks should have the actual model. + # At least some chunks should have the actual model (not azure-model-router) + actual_model_chunks = [ + m for m in chunks_with_model if m != "azure-model-router" + ] + assert ( + len(actual_model_chunks) > 0 + ), "No chunks had the actual model from the API response" + print(f"Chunks with actual model: {actual_model_chunks}") + + # Verify response cost is tracked - this is the main goal of this test + assert ( + test_callback.response_cost is not None + ), "response_cost is None with stream_options" + assert ( + test_callback.response_cost > 0 + ), f"response_cost should be > 0, got {test_callback.response_cost}" + print( + f"Streaming cost tracking with stream_options passed. Cost: {test_callback.response_cost}" + ) + + finally: + litellm.logging_callback_manager._reset_all_callbacks() + litellm.callbacks = [] diff --git a/tests/harness_suites/chat_live_azure/test_azure_o_series_live.py b/tests/harness_suites/chat_live_azure/test_azure_o_series_live.py new file mode 100644 index 00000000000..5f68f37e547 --- /dev/null +++ b/tests/harness_suites/chat_live_azure/test_azure_o_series_live.py @@ -0,0 +1,39 @@ +import os +import sys + +sys.path.insert( + 0, os.path.abspath("../..") +) # Adds the parent directory to the system path + + + +import litellm +from base_llm_unit_tests import BaseLLMChatTest + +class TestAzureOpenAIO3Mini(BaseLLMChatTest): + def get_base_completion_call_args(self): + # Clear the LLM client cache to prevent test pollution from cached clients + litellm.in_memory_llm_clients_cache.flush_cache() + return { + "model": "azure/o3-mini", + "api_key": os.getenv("AZURE_AI_API_KEY"), + "api_base": os.getenv("AZURE_AI_API_BASE"), + "api_version": "2024-12-01-preview", + } + + def get_client(self): + from openai import AzureOpenAI + + return AzureOpenAI( + api_key="my-fake-o1-key", + base_url="https://openai-prod-test.openai.azure.com", + api_version="2024-02-15-preview", + ) + + def test_basic_tool_calling(self): + pass + + def test_prompt_caching(self): + """Temporary override. o1 prompt caching is not working.""" + pass + diff --git a/tests/harness_suites/chat_live_azure/test_azure_openai_chat_live.py b/tests/harness_suites/chat_live_azure/test_azure_openai_chat_live.py new file mode 100644 index 00000000000..9e41e58bba2 --- /dev/null +++ b/tests/harness_suites/chat_live_azure/test_azure_openai_chat_live.py @@ -0,0 +1,64 @@ +import sys +import os + +sys.path.insert( + 0, os.path.abspath("../../") +) # Adds the parent directory to the system path + +import pytest +from litellm.llms.azure.common_utils import process_azure_headers +from httpx import Headers +from base_embedding_unit_tests import BaseLLMEmbeddingTest +import litellm +from litellm import completion + +def test_azure_safety_result(): + """Bubble up safety result from Azure OpenAI""" + from litellm import completion + + litellm._turn_on_debug() + + response = completion( + model="azure/gpt-4.1-mini", + api_key=os.getenv("AZURE_AI_API_KEY"), + api_base=os.getenv("AZURE_AI_API_BASE"), + api_version="2024-12-01-preview", + messages=[{"role": "user", "content": "Hello world"}], + ) + print(f"response: {response}") + assert response.choices[0].message.content is not None + assert response.choices[0].provider_specific_fields is not None + + +def test_completion_azure_deployment_id(): + """ + Ensure deployment_id takes precedence over model. + """ + litellm.set_verbose = True + response = completion( + deployment_id="gpt-4.1-mini", + model="gpt-3.5-turbo", + messages=[ + { + "role": "user", + "content": "Hello, how are you?", + } + ], + ) + # Add any assertions here to check the response + print(response) + + +def test_azure_openai_with_prompt_cache_key(): + """ + E2E test for Azure OpenAI with prompt cache key param on /chat/completions API. + """ + litellm._turn_on_debug() + response = litellm.completion( + model="azure/gpt-4.1-mini", + api_key=os.getenv("AZURE_AI_API_KEY"), + api_base=os.getenv("AZURE_AI_API_BASE"), + api_version="2024-12-01-preview", + messages=[{"role": "user", "content": "What is the weather in San Francisco?"}], + prompt_cache_key="test_streaming_azure_openai", + ) diff --git a/tests/llm_translation/test_azure_ai.py b/tests/llm_translation/test_azure_ai.py index 4a3f2c37336..62c9379fdbf 100644 --- a/tests/llm_translation/test_azure_ai.py +++ b/tests/llm_translation/test_azure_ai.py @@ -24,7 +24,6 @@ from unittest.mock import MagicMock, patch import pytest import litellm -from litellm import completion AZURE_AI_API_BASE = os.getenv("AZURE_AI_API_BASE") @@ -163,301 +162,3 @@ def test_azure_deepseek_reasoning_content(): # } -@pytest.mark.asyncio -async def test_azure_ai_request_format(): - """ - Test that Azure AI requests are formatted correctly with the proper endpoint and parameters - for both synchronous and asynchronous calls - """ - - litellm._turn_on_debug() - - # Set up the test parameters - api_key = os.getenv("AZURE_AI_API_KEY") - api_base = os.getenv("AZURE_AI_API_BASE") - model = "azure_ai/gpt-4.1-mini" - messages = [ - {"role": "user", "content": "hi"}, - {"role": "assistant", "content": "Hello! How can I assist you today?"}, - {"role": "user", "content": "hi"}, - ] - - await litellm.acompletion( - custom_llm_provider="azure_ai", - api_key=api_key, - api_base=api_base, - model=model, - messages=messages, - ) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("model", ["azure/gpt5_series/gpt-5-mini", "azure/gpt-5-mini"]) -async def test_azure_gpt5_reasoning(model): - litellm._turn_on_debug() - response = await litellm.acompletion( - model=model, - messages=[{"role": "user", "content": "What is the capital of France?"}], - reasoning_effort="minimal", - max_tokens=10, - api_base=os.getenv("AZURE_AI_API_BASE"), - api_key=os.getenv("AZURE_AI_API_KEY"), - ) - print("response: ", response) - assert response.choices[0].message.content is not None - - -def test_completion_azure(): - try: - from litellm import completion_cost - - litellm.set_verbose = False - ## Test azure call - response = completion( - model="azure_ai/gpt-4.1-mini", - api_base=os.getenv("AZURE_AI_API_BASE"), - messages=[ - { - "role": "user", - "content": "Hello, how are you?", - } - ], - api_key=os.getenv("AZURE_AI_API_KEY"), - ) - print(f"response: {response}") - print(f"response hidden params: {response._hidden_params}") - print(response) - - cost = completion_cost(completion_response=response) - assert cost > 0.0 - print("Cost for azure completion request", cost) - except Exception as e: - pytest.fail(f"Error occurred: {e}") - - -@pytest.mark.parametrize( - "api_base", - [ - AZURE_AI_API_BASE, - f"{AZURE_AI_API_BASE}/openai/deployments/gpt-4.1-mini/chat/completions?api-version=2023-03-15-preview", - ], -) -def test_completion_azure_ai_gpt_4o_with_flexible_api_base(api_base): - try: - litellm.set_verbose = True - - response = completion( - model="azure_ai/gpt-4.1-mini", - api_base=api_base, - api_key=os.getenv("AZURE_AI_API_KEY"), - messages=[{"role": "user", "content": "What is the meaning of life?"}], - ) - - print(response) - except litellm.Timeout as e: - pass - except Exception as e: - pytest.fail(f"Error occurred: {e}") - - -@pytest.mark.asyncio -async def test_azure_ai_model_router(): - """ - Test Azure AI model router non-streaming response cost tracking. - Verifies that the flat cost of $0.14 per M input tokens is applied. - - Tests the pattern: azure_ai/model_router/ - Where deployment-name is the Azure deployment (e.g., "azure-model-router"). - The model_router prefix is stripped before sending to Azure API. - """ - from litellm.llms.azure_ai.cost_calculator import ( - calculate_azure_model_router_flat_cost, - ) - - litellm._turn_on_debug() - response = await litellm.acompletion( - model="azure_ai/model_router/azure-model-router", - messages=[{"role": "user", "content": "hi who is this"}], - api_base=os.getenv("AZURE_MODEL_ROUTER_API_BASE"), - api_key=os.getenv("AZURE_MODEL_ROUTER_API_KEY"), - ) - print("response: ", response) - - # Check response cost - tracked_cost = response._hidden_params["response_cost"] - assert tracked_cost > 0 - print("Tracked cost: ", tracked_cost) - - # Verify flat cost is included using the helper function - usage = response.usage - if usage and usage.prompt_tokens: - expected_flat_cost = calculate_azure_model_router_flat_cost( - model="model_router/azure-model-router", prompt_tokens=usage.prompt_tokens - ) - print(f"Prompt tokens: {usage.prompt_tokens}") - print(f"Expected flat cost: ${expected_flat_cost:.9f}") - print(f"Total tracked cost: ${tracked_cost:.9f}") - - # Total cost should be at least the flat cost - assert ( - tracked_cost >= expected_flat_cost - ), f"Cost ${tracked_cost:.9f} should be >= flat cost ${expected_flat_cost:.9f}" - - # Verify the flat cost is non-zero - assert expected_flat_cost > 0, "Flat cost should be greater than 0" - - -@pytest.mark.asyncio -async def test_azure_ai_model_router_streaming_model_in_chunk(): - """ - Test that Azure AI model router streaming returns the actual model in each chunk. - The response should contain the actual model used (e.g., gpt-4.1-nano) not the request model (azure-model-router). - """ - litellm._turn_on_debug() - response = await litellm.acompletion( - model="azure_ai/azure-model-router", - messages=[{"role": "user", "content": "hi"}], - api_base=os.getenv("AZURE_MODEL_ROUTER_API_BASE"), - api_key=os.getenv("AZURE_MODEL_ROUTER_API_KEY"), - stream=True, - ) - - # Collect chunks and check model field - chunks_with_model = [] - async for chunk in response: - print(f"Chunk model: {chunk.model}") - if chunk.model and chunk.model.strip(): - chunks_with_model.append(chunk.model) - - print(f"All chunk models: {chunks_with_model}") - - # At least some chunks should have a model - assert len(chunks_with_model) > 0, "No chunks had a model field set" - - # The model should NOT be azure-model-router (the request model) - # It should be the actual model from the response (e.g., gpt-4.1-nano, gpt-5-nano, etc.) - for model in chunks_with_model: - assert ( - model != "azure-model-router" - ), f"Chunk model should be actual model, not request model. Got: {model}" - # The actual model should be a real model name like gpt-4.1-nano, gpt-5-nano, etc. - print(f"Verified chunk has actual model: {model}") - - -class AzureModelRouterStreamingCallback( - litellm.integrations.custom_logger.CustomLogger -): - """ - Custom callback to capture streaming cost tracking for Azure Model Router. - """ - - def __init__(self): - self.standard_logging_payload = None - self.response_cost = None - self.async_success_called = False - self.complete_streaming_response = None - super().__init__() - - async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): - print(f"async_log_success_event called") - self.async_success_called = True - self.standard_logging_payload = kwargs.get("standard_logging_object") - self.complete_streaming_response = kwargs.get("complete_streaming_response") - - if self.standard_logging_payload: - self.response_cost = self.standard_logging_payload.get("response_cost") - print( - f"standard_logging_payload model: {self.standard_logging_payload.get('model')}" - ) - print(f"standard_logging_payload response_cost: {self.response_cost}") - - if self.complete_streaming_response: - print( - f"complete_streaming_response model: {self.complete_streaming_response.model}" - ) - print( - f"complete_streaming_response usage: {self.complete_streaming_response.usage}" - ) - - -@pytest.mark.asyncio -async def test_azure_ai_model_router_streaming_cost_with_stream_options(): - """ - Test Azure AI model router streaming cost tracking with stream_options include_usage=True. - This tests the specific case where cost tracking fails with stream_options. - """ - litellm.logging_callback_manager._reset_all_callbacks() - test_callback = AzureModelRouterStreamingCallback() - litellm.callbacks = [test_callback] - - try: - litellm._turn_on_debug() - response = await litellm.acompletion( - model="azure_ai/azure-model-router", - messages=[{"role": "user", "content": "hi"}], - api_base=os.getenv("AZURE_MODEL_ROUTER_API_BASE"), - api_key=os.getenv("AZURE_MODEL_ROUTER_API_KEY"), - stream=True, - stream_options={"include_usage": True}, - ) - - # Consume the stream and check chunks - full_response = "" - chunks_with_model = [] - async for chunk in response: - print( - f"Chunk: model={chunk.model}, choices={len(chunk.choices) if chunk.choices else 0}" - ) - if chunk.model: - chunks_with_model.append(chunk.model) - if ( - chunk.choices - and chunk.choices[0].delta - and chunk.choices[0].delta.content - ): - full_response += chunk.choices[0].delta.content - - print(f"Full streamed response: {full_response}") - print(f"Chunks with model: {chunks_with_model}") - - # Give async logging time to complete - import asyncio - - await asyncio.sleep(1) - - # Verify callback was called - assert ( - test_callback.async_success_called is True - ), "async_log_success_event was not called" - assert ( - test_callback.standard_logging_payload is not None - ), "standard_logging_payload is None" - - # Check response cost - print(f"Final response_cost: {test_callback.response_cost}") - - # The first chunk may have the request model (azure-model-router) because it's created - # before the API response is received. Subsequent chunks should have the actual model. - # At least some chunks should have the actual model (not azure-model-router) - actual_model_chunks = [ - m for m in chunks_with_model if m != "azure-model-router" - ] - assert ( - len(actual_model_chunks) > 0 - ), "No chunks had the actual model from the API response" - print(f"Chunks with actual model: {actual_model_chunks}") - - # Verify response cost is tracked - this is the main goal of this test - assert ( - test_callback.response_cost is not None - ), "response_cost is None with stream_options" - assert ( - test_callback.response_cost > 0 - ), f"response_cost should be > 0, got {test_callback.response_cost}" - print( - f"Streaming cost tracking with stream_options passed. Cost: {test_callback.response_cost}" - ) - - finally: - litellm.logging_callback_manager._reset_all_callbacks() - litellm.callbacks = [] diff --git a/tests/llm_translation/test_azure_o_series.py b/tests/llm_translation/test_azure_o_series.py index e6db69c7b27..592a3f3ee7b 100644 --- a/tests/llm_translation/test_azure_o_series.py +++ b/tests/llm_translation/test_azure_o_series.py @@ -5,67 +5,35 @@ sys.path.insert( 0, os.path.abspath("../..") ) # Adds the parent directory to the system path - - import litellm -from base_llm_unit_tests import BaseLLMChatTest -class TestAzureOpenAIO3Mini(BaseLLMChatTest): - def get_base_completion_call_args(self): - # Clear the LLM client cache to prevent test pollution from cached clients - litellm.in_memory_llm_clients_cache.flush_cache() - return { - "model": "azure/o3-mini", - "api_key": os.getenv("AZURE_AI_API_KEY"), - "api_base": os.getenv("AZURE_AI_API_BASE"), - "api_version": "2024-12-01-preview", - } +def test_azure_o1_override_fake_stream(): + """Test that native streaming is not supported for o1.""" + router = litellm.Router( + model_list=[ + { + "model_name": "azure/o1-preview", + "litellm_params": { + "model": "azure/o1-preview", + "api_key": "my-fake-o1-key", + "api_base": "https://openai-gpt-4-test-v-1.openai.azure.com", + }, + "model_info": { + "supports_native_streaming": True, + }, + } + ] + ) - def get_client(self): - from openai import AzureOpenAI - - return AzureOpenAI( - api_key="my-fake-o1-key", - base_url="https://openai-prod-test.openai.azure.com", - api_version="2024-02-15-preview", - ) - - def test_basic_tool_calling(self): - pass - - def test_prompt_caching(self): - """Temporary override. o1 prompt caching is not working.""" - pass - - def test_override_fake_stream(self): - """Test that native streaming is not supported for o1.""" - router = litellm.Router( - model_list=[ - { - "model_name": "azure/o1-preview", - "litellm_params": { - "model": "azure/o1-preview", - "api_key": "my-fake-o1-key", - "api_base": "https://openai-gpt-4-test-v-1.openai.azure.com", - }, - "model_info": { - "supports_native_streaming": True, - }, - } - ] - ) - - ## check model info - - model_info = litellm.get_model_info( - model="azure/o1-preview", custom_llm_provider="azure" - ) - assert model_info["supports_native_streaming"] is True - - fake_stream = litellm.AzureOpenAIO1Config().should_fake_stream( - model="azure/o1-preview", stream=True - ) - assert fake_stream is False + ## check model info + model_info = litellm.get_model_info( + model="azure/o1-preview", custom_llm_provider="azure" + ) + assert model_info["supports_native_streaming"] is True + fake_stream = litellm.AzureOpenAIO1Config().should_fake_stream( + model="azure/o1-preview", stream=True + ) + assert fake_stream is False diff --git a/tests/llm_translation/test_azure_openai.py b/tests/llm_translation/test_azure_openai.py index 236f3744c69..28d52b372d2 100644 --- a/tests/llm_translation/test_azure_openai.py +++ b/tests/llm_translation/test_azure_openai.py @@ -99,7 +99,6 @@ def test_process_azure_headers_with_dict_input(): from unittest.mock import MagicMock import litellm -from litellm import completion import os @@ -244,43 +243,6 @@ def test_map_openai_params(): assert len(optional_params["tools"]) > 1 -def test_azure_safety_result(): - """Bubble up safety result from Azure OpenAI""" - from litellm import completion - - litellm._turn_on_debug() - - response = completion( - model="azure/gpt-4.1-mini", - api_key=os.getenv("AZURE_AI_API_KEY"), - api_base=os.getenv("AZURE_AI_API_BASE"), - api_version="2024-12-01-preview", - messages=[{"role": "user", "content": "Hello world"}], - ) - print(f"response: {response}") - assert response.choices[0].message.content is not None - assert response.choices[0].provider_specific_fields is not None - - -def test_completion_azure_deployment_id(): - """ - Ensure deployment_id takes precedence over model. - """ - litellm.set_verbose = True - response = completion( - deployment_id="gpt-4.1-mini", - model="gpt-3.5-turbo", - messages=[ - { - "role": "user", - "content": "Hello, how are you?", - } - ], - ) - # Add any assertions here to check the response - print(response) - - def test_azure_with_content_safety_error(): """ Verify user can access innererror from the Azure OpenAI exception @@ -338,16 +300,3 @@ def test_azure_with_content_safety_error(): ) -def test_azure_openai_with_prompt_cache_key(): - """ - E2E test for Azure OpenAI with prompt cache key param on /chat/completions API. - """ - litellm._turn_on_debug() - response = litellm.completion( - model="azure/gpt-4.1-mini", - api_key=os.getenv("AZURE_AI_API_KEY"), - api_base=os.getenv("AZURE_AI_API_BASE"), - api_version="2024-12-01-preview", - messages=[{"role": "user", "content": "What is the weather in San Francisco?"}], - prompt_cache_key="test_streaming_azure_openai", - )