Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ class CreateArguments(TypedDict, total=False):
user: str
stream_options: Optional[StreamOptions]
parallel_tool_calls: Optional[bool]
reasoning_effort: Optional[Literal["minimal", "low", "medium", "high"]]
"""Controls the amount of effort the model uses for reasoning.
Only applicable to reasoning models like o1 and o3-mini.
- 'minimal': Fastest response with minimal reasoning
- 'low': Faster responses with less reasoning
- 'medium': Balanced reasoning and speed
- 'high': More thorough reasoning, may take longer"""


AsyncAzureADTokenProvider = Callable[[], Union[str, Awaitable[str]]]
Expand Down Expand Up @@ -99,6 +106,8 @@ class CreateArgumentsConfigModel(BaseModel):
user: str | None = None
stream_options: StreamOptions | None = None
parallel_tool_calls: bool | None = None
# Controls the amount of effort the model uses for reasoning (reasoning models only)
reasoning_effort: Literal["minimal", "low", "medium", "high"] | None = None


class BaseOpenAIClientConfigurationConfigModel(CreateArgumentsConfigModel):
Expand Down
109 changes: 109 additions & 0 deletions python/packages/autogen-ext/tests/models/test_openai_model_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3269,3 +3269,112 @@ def _different_function(text: str) -> str:


# TODO: add integration tests for Azure OpenAI using AAD token.


@pytest.mark.asyncio
async def test_reasoning_effort_parameter() -> None:
"""Test that reasoning_effort parameter is properly handled in client configuration."""

# Test OpenAI client with reasoning_effort
openai_client = OpenAIChatCompletionClient(
model="gpt-5",
api_key="fake_key",
reasoning_effort="low",
)
assert openai_client._create_args["reasoning_effort"] == "low" # pyright: ignore[reportPrivateUsage]

# Test Azure OpenAI client with reasoning_effort
azure_client = AzureOpenAIChatCompletionClient(
model="gpt-5",
azure_endpoint="fake_endpoint",
azure_deployment="gpt-5-2025-08-07",
api_version="2025-02-01-preview",
api_key="fake_key",
reasoning_effort="medium",
)
assert azure_client._create_args["reasoning_effort"] == "medium" # pyright: ignore[reportPrivateUsage]

# Test load_component with reasoning_effort for OpenAI
from autogen_core.models import ChatCompletionClient

openai_config = {
"provider": "OpenAIChatCompletionClient",
"config": {
"model": "gpt-5",
"api_key": "fake_key",
"reasoning_effort": "high",
},
}

loaded_openai_client = ChatCompletionClient.load_component(openai_config)
assert loaded_openai_client._create_args["reasoning_effort"] == "high" # type: ignore[attr-defined] # pyright: ignore[reportPrivateUsage, reportUnknownMemberType, reportAttributeAccessIssue]
assert loaded_openai_client._raw_config["reasoning_effort"] == "high" # type: ignore[attr-defined] # pyright: ignore[reportPrivateUsage, reportUnknownMemberType, reportAttributeAccessIssue]

# Test load_component with reasoning_effort for Azure OpenAI
azure_config = {
"provider": "AzureOpenAIChatCompletionClient",
"config": {
"model": "gpt-5",
"azure_endpoint": "fake_endpoint",
"azure_deployment": "gpt-5-2025-08-07",
"api_version": "2025-02-01-preview",
"api_key": "fake_key",
"reasoning_effort": "low",
},
}

loaded_azure_client = ChatCompletionClient.load_component(azure_config)
assert loaded_azure_client._create_args["reasoning_effort"] == "low" # type: ignore[attr-defined] # pyright: ignore[reportPrivateUsage, reportUnknownMemberType, reportAttributeAccessIssue]
assert loaded_azure_client._raw_config["reasoning_effort"] == "low" # type: ignore[attr-defined] # pyright: ignore[reportPrivateUsage, reportUnknownMemberType, reportAttributeAccessIssue]

# Test serialization and deserialization
config_dict = openai_client.dump_component()
reloaded_client = OpenAIChatCompletionClient.load_component(config_dict)
assert reloaded_client._create_args["reasoning_effort"] == "low" # pyright: ignore[reportPrivateUsage]


@pytest.mark.asyncio
async def test_reasoning_effort_validation() -> None:
"""Test reasoning_effort parameter validation."""

# Test valid values
for valid_value in ["low", "medium", "high"]:
client = OpenAIChatCompletionClient(
model="gpt-5",
api_key="fake_key",
reasoning_effort=valid_value, # type: ignore[arg-type] # pyright: ignore[reportArgumentType]
)
assert client._create_args["reasoning_effort"] == valid_value # pyright: ignore[reportPrivateUsage]

# Test None value (should be included if explicitly set)
client_with_none = OpenAIChatCompletionClient(
model="gpt-5",
api_key="fake_key",
reasoning_effort=None,
)
# When explicitly set to None, it will be included in create_args
assert client_with_none._create_args["reasoning_effort"] is None # pyright: ignore[reportPrivateUsage]

# Test not providing reasoning_effort (should not be in create_args)
client_without_reasoning = OpenAIChatCompletionClient(
model="gpt-5",
api_key="fake_key",
)
assert "reasoning_effort" not in client_without_reasoning._create_args # pyright: ignore[reportPrivateUsage]

# Test invalid value via load_component (Pydantic validation)
from pydantic import ValidationError

with pytest.raises(ValidationError): # Should raise ValidationError
from autogen_core.models import ChatCompletionClient

config = {
"provider": "OpenAIChatCompletionClient",
"config": {
"model": "gpt-5",
"api_key": "fake_key",
"reasoning_effort": "invalid_value",
},
}

ChatCompletionClient.load_component(config)
Loading