Merge pull request #220 from ggozad/fix/openai-non-reasoning-model

Fix non-reasoning OpenAI models that do not support reasoning config
This commit is contained in:
Yiorgis Gozadinos 2026-01-08 10:18:50 +02:00 committed by GitHub
commit af380c8e52
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 27 additions and 5 deletions

View file

@ -1,6 +1,11 @@
# Changelog # Changelog
## [Unreleased] ## [Unreleased]
### Fixed
- **OpenAI Non-Reasoning Models**: Fixed `reasoning_effort` parameter being sent to non-reasoning OpenAI models (gpt-4o, gpt-4o-mini), causing 400 errors. Now correctly detects reasoning models (o1, o3 series) using pydantic-ai's model profile.
- **Bedrock Non-Reasoning Models**: Fixed same issue for OpenAI models on Bedrock.
## [0.24.0] - 2026-01-07 ## [0.24.0] - 2026-01-07
### Added ### Added

View file

@ -2,7 +2,7 @@ import sys
from datetime import UTC, datetime from datetime import UTC, datetime
from importlib import metadata from importlib import metadata
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any, cast
from dateutil import parser as dateutil_parser from dateutil import parser as dateutil_parser
from packaging.version import Version, parse from packaging.version import Version, parse
@ -145,10 +145,16 @@ def get_model(
) )
elif provider == "openai": elif provider == "openai":
from pydantic_ai.profiles.openai import OpenAIModelProfile, openai_model_profile
openai_settings: Any = None openai_settings: Any = None
# Apply thinking control # Apply thinking control only for reasoning models (o-series, gpt-5)
if model_config.enable_thinking is not None: profile = cast(OpenAIModelProfile, openai_model_profile(model))
if (
model_config.enable_thinking is not None
and profile.openai_supports_encrypted_reasoning_content
):
if model_config.enable_thinking is False: if model_config.enable_thinking is False:
openai_settings = OpenAIChatModelSettings(openai_reasoning_effort="low") openai_settings = OpenAIChatModelSettings(openai_reasoning_effort="low")
else: else:
@ -247,8 +253,8 @@ def get_model(
} }
else: else:
additional_fields = {"thinking": {"type": "disabled"}} additional_fields = {"thinking": {"type": "disabled"}}
elif "gpt" in model or "o1" in model or "o3" in model: elif "o1" in model or "o3" in model:
# OpenAI models on Bedrock # OpenAI reasoning models on Bedrock (o-series only, not gpt-4o)
additional_fields = { additional_fields = {
"reasoning_effort": "high" "reasoning_effort": "high"
if model_config.enable_thinking if model_config.enable_thinking

View file

@ -176,6 +176,17 @@ def test_get_model_openai_with_thinking():
assert isinstance(result, OpenAIChatModel) assert isinstance(result, OpenAIChatModel)
def test_get_model_openai_non_reasoning_model_ignores_thinking():
"""Test that non-reasoning OpenAI models don't get reasoning_effort setting."""
model_config = ModelConfig(
provider="openai", name="gpt-4o-mini", enable_thinking=False
)
result = get_model(model_config)
assert isinstance(result, OpenAIChatModel)
# Non-reasoning models should not have reasoning_effort set
assert result._settings is None
@pytest.mark.skipif(not HAS_ANTHROPIC, reason="Anthropic not installed") @pytest.mark.skipif(not HAS_ANTHROPIC, reason="Anthropic not installed")
def test_get_model_anthropic(): def test_get_model_anthropic():
"""Test get_model returns AnthropicModel for Anthropic.""" """Test get_model returns AnthropicModel for Anthropic."""