Skip to content
Closed
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
16 changes: 10 additions & 6 deletions litellm/llms/azure/responses/o_series_transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

from litellm._logging import verbose_logger
from litellm.types.llms.openai import ResponsesAPIOptionalRequestParams
from litellm.utils import supports_reasoning

from .transformation import AzureOpenAIResponsesAPIConfig

Expand Down Expand Up @@ -79,15 +78,20 @@ def is_o_series_model(self, model: str) -> bool:
"""
Check if the model is an O-series model.

O-series models include o1, o3, o4, etc. families (e.g., o1-preview, o3-mini).
Note: This is different from models that support reasoning - GPT-5 supports
reasoning but is NOT an O-series model.

Args:
model: The model name to check

Returns:
True if it's an O-series model, False otherwise
"""
# Check if model name contains o_series or if it's a known O-series model
if "o_series" in model.lower():
# Check if path contains o_series/ routing prefix (e.g., azure/responses/o_series/model)
if "o_series/" in model:
return True

# Check if the model supports reasoning (which is O-series specific)
return supports_reasoning(model)

# Check if the base model name starts with o1/o3/o4 prefixes
model_basename = model.split("/")[-1] # could be "azure/o3" or "o3"
return any(model_basename.startswith(pfx) for pfx in ("o1", "o3", "o4"))
17 changes: 12 additions & 5 deletions litellm/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7396,11 +7396,18 @@ def get_provider_responses_api_config(
if litellm.LlmProviders.OPENAI == provider:
return litellm.OpenAIResponsesAPIConfig()
elif litellm.LlmProviders.AZURE == provider:
# Check if it's an O-series model
if model and ("o_series" in model.lower() or supports_reasoning(model)):
return litellm.AzureOpenAIOSeriesResponsesAPIConfig()
else:
return litellm.AzureOpenAIResponsesAPIConfig()
# Check if it's an O-series model (o1, o3, o4, etc.)
# Note: We check for specific O-series model names, not just "supports_reasoning"
# since GPT-5 supports reasoning but is NOT an O-series model
if model:
# Check if path contains o_series/ routing prefix
if "o_series/" in model:
return litellm.AzureOpenAIOSeriesResponsesAPIConfig()
# Check if the base model name starts with o1/o3/o4 prefixes
_model = model.split("/")[-1] # could be "azure/o3" or "o3"
if any(_model.startswith(pfx) for pfx in ("o1", "o3", "o4")):
return litellm.AzureOpenAIOSeriesResponsesAPIConfig()
return litellm.AzureOpenAIResponsesAPIConfig()
elif litellm.LlmProviders.LITELLM_PROXY == provider:
return litellm.LiteLLMProxyResponsesAPIConfig()
return None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,31 @@ def test_o_series_model_detection():
assert config.is_o_series_model("o_series/gpt-o1") == True
assert config.is_o_series_model("azure/o_series/gpt-o3") == True

# Test O1 models
assert config.is_o_series_model("o1") == True
assert config.is_o_series_model("o1-preview") == True
assert config.is_o_series_model("o1-mini") == True
assert config.is_o_series_model("azure/o1-preview") == True

# Test O3 models
assert config.is_o_series_model("o3") == True
assert config.is_o_series_model("o3-mini") == True
assert config.is_o_series_model("azure/o3-mini") == True

# Test regular models
assert config.is_o_series_model("gpt-4o") == False
assert config.is_o_series_model("gpt-3.5-turbo") == False

# Test GPT-5 (supports reasoning but is NOT an O-series model)
assert config.is_o_series_model("gpt-5") == False
assert config.is_o_series_model("gpt-5-turbo") == False
assert config.is_o_series_model("azure/gpt-5") == False

# Edge cases: Models with "o1", "o3", "o4" in the middle or end should NOT match
# (using startswith ensures only models that START with these prefixes match)
assert config.is_o_series_model("gpt-4o1") == False # has "o1" but doesn't start with it
assert config.is_o_series_model("gpto1") == False # has "o1" but doesn't start with it
assert config.is_o_series_model("model-o3-test") == False # has "o3" but doesn't start with it


@pytest.mark.serial
Expand All @@ -211,13 +233,35 @@ def test_provider_config_manager_o_series_selection():
)
assert isinstance(o_series_config, AzureOpenAIOSeriesResponsesAPIConfig)

# Test O1 model selection
o1_config = ProviderConfigManager.get_provider_responses_api_config(
provider=litellm.LlmProviders.AZURE, model="o1-preview"
)
assert isinstance(o1_config, AzureOpenAIOSeriesResponsesAPIConfig)

# Test O3 model selection
o3_config = ProviderConfigManager.get_provider_responses_api_config(
provider=litellm.LlmProviders.AZURE, model="o3-mini"
)
assert isinstance(o3_config, AzureOpenAIOSeriesResponsesAPIConfig)

# Test regular model selection
regular_config = ProviderConfigManager.get_provider_responses_api_config(
provider=litellm.LlmProviders.AZURE, model="gpt-4o"
)
assert isinstance(regular_config, AzureOpenAIResponsesAPIConfig)
assert not isinstance(regular_config, AzureOpenAIOSeriesResponsesAPIConfig)

# Test GPT-5 model selection (supports reasoning but is NOT O-series)
gpt5_config = ProviderConfigManager.get_provider_responses_api_config(
provider=litellm.LlmProviders.AZURE, model="gpt-5"
)
assert isinstance(gpt5_config, AzureOpenAIResponsesAPIConfig)
assert not isinstance(gpt5_config, AzureOpenAIOSeriesResponsesAPIConfig)
# Verify temperature is supported for GPT-5
gpt5_params = gpt5_config.get_supported_openai_params("gpt-5")
assert "temperature" in gpt5_params, "GPT-5 should support temperature parameter"

# Test with no model specified (should default to regular)
default_config = ProviderConfigManager.get_provider_responses_api_config(
provider=litellm.LlmProviders.AZURE, model=None
Expand Down
Loading