feat: GPT-5.2 support
This commit is contained in:
@@ -228,10 +228,10 @@ Some integration tests maintain cassettes for multiple model variants to ensure
|
||||
|
||||
### Consensus Tool Cassettes
|
||||
|
||||
The `test_consensus_integration.py` test uses parameterized fixtures to test both `gpt-5` and `gpt-5.1` models:
|
||||
The `test_consensus_integration.py` test uses parameterized fixtures to test both `gpt-5` and `gpt-5.2` models:
|
||||
|
||||
- `tests/openai_cassettes/consensus_step1_gpt5_for.json` - Cassette for gpt-5 model
|
||||
- `tests/openai_cassettes/consensus_step1_gpt51_for.json` - Cassette for gpt-5.1 model
|
||||
- `tests/openai_cassettes/consensus_step1_gpt52_for.json` - Cassette for gpt-5.2 model
|
||||
|
||||
**When updating consensus cassettes:**
|
||||
|
||||
@@ -249,9 +249,9 @@ rm tests/openai_cassettes/consensus_step1_gpt5_for.json
|
||||
# Run the test with real API key (it will record for gpt-5)
|
||||
OPENAI_API_KEY="your-real-key" python -m pytest tests/test_consensus_integration.py::test_consensus_multi_model_consultations[gpt-5] -v
|
||||
|
||||
# Or for gpt-5.1
|
||||
rm tests/openai_cassettes/consensus_step1_gpt51_for.json
|
||||
OPENAI_API_KEY="your-real-key" python -m pytest tests/test_consensus_integration.py::test_consensus_multi_model_consultations[gpt-5.1] -v
|
||||
# Or for gpt-5.2
|
||||
rm tests/openai_cassettes/consensus_step1_gpt52_for.json
|
||||
OPENAI_API_KEY="your-real-key" python -m pytest tests/test_consensus_integration.py::test_consensus_multi_model_consultations[gpt-5.2] -v
|
||||
```
|
||||
|
||||
This dual-coverage approach ensures that both model families continue to work correctly as the codebase evolves.
|
||||
|
||||
File diff suppressed because one or more lines are too long
82
tests/openai_cassettes/consensus_step1_gpt52_for.json
Normal file
82
tests/openai_cassettes/consensus_step1_gpt52_for.json
Normal file
File diff suppressed because one or more lines are too long
@@ -95,8 +95,8 @@ class TestAutoModeComprehensive:
|
||||
},
|
||||
{
|
||||
"EXTENDED_REASONING": "gpt-5.1-codex", # GPT-5.1 Codex prioritized for coding tasks
|
||||
"FAST_RESPONSE": "gpt-5.1", # Prefer gpt-5.1 for speed
|
||||
"BALANCED": "gpt-5.1", # Prefer gpt-5.1 for balanced
|
||||
"FAST_RESPONSE": "gpt-5.2", # Prefer gpt-5.2 for speed
|
||||
"BALANCED": "gpt-5.2", # Prefer gpt-5.2 for balanced
|
||||
},
|
||||
),
|
||||
# Only X.AI API available
|
||||
|
||||
@@ -83,7 +83,7 @@ def test_error_listing_respects_env_restrictions(monkeypatch, reset_registry):
|
||||
pass
|
||||
|
||||
monkeypatch.setenv("GOOGLE_ALLOWED_MODELS", "gemini-2.5-pro")
|
||||
monkeypatch.setenv("OPENAI_ALLOWED_MODELS", "gpt-5.1")
|
||||
monkeypatch.setenv("OPENAI_ALLOWED_MODELS", "gpt-5.2")
|
||||
monkeypatch.setenv("OPENROUTER_ALLOWED_MODELS", "gpt5nano")
|
||||
monkeypatch.setenv("XAI_ALLOWED_MODELS", "")
|
||||
|
||||
@@ -104,7 +104,7 @@ def test_error_listing_respects_env_restrictions(monkeypatch, reset_registry):
|
||||
("OPENAI_API_KEY", "test-openai"),
|
||||
("OPENROUTER_API_KEY", "test-openrouter"),
|
||||
("GOOGLE_ALLOWED_MODELS", "gemini-2.5-pro"),
|
||||
("OPENAI_ALLOWED_MODELS", "gpt-5.1"),
|
||||
("OPENAI_ALLOWED_MODELS", "gpt-5.2"),
|
||||
("OPENROUTER_ALLOWED_MODELS", "gpt5nano"),
|
||||
("XAI_ALLOWED_MODELS", ""),
|
||||
):
|
||||
@@ -139,7 +139,7 @@ def test_error_listing_respects_env_restrictions(monkeypatch, reset_registry):
|
||||
assert payload["status"] == "error"
|
||||
|
||||
available_models = _extract_available_models(payload["content"])
|
||||
assert set(available_models) == {"gemini-2.5-pro", "gpt-5.1", "gpt5nano", "openai/gpt-5-nano"}
|
||||
assert set(available_models) == {"gemini-2.5-pro", "gpt-5.2", "gpt5nano", "openai/gpt-5-nano"}
|
||||
|
||||
|
||||
@pytest.mark.no_mock_provider
|
||||
@@ -225,6 +225,6 @@ def test_error_listing_without_restrictions_shows_full_catalog(monkeypatch, rese
|
||||
|
||||
available_models = _extract_available_models(payload["content"])
|
||||
assert "gemini-2.5-pro" in available_models
|
||||
assert any(model in available_models for model in {"gpt-5.1", "gpt-5"})
|
||||
assert any(model in available_models for model in {"gpt-5.2", "gpt-5"})
|
||||
assert "grok-4" in available_models
|
||||
assert len(available_models) >= 5
|
||||
|
||||
@@ -99,8 +99,8 @@ class TestAutoModeProviderSelection:
|
||||
|
||||
# Should select appropriate OpenAI models based on new preference order
|
||||
assert extended_reasoning == "gpt-5.1-codex" # GPT-5.1 Codex prioritized for extended reasoning
|
||||
assert fast_response == "gpt-5.1" # gpt-5.1 comes first in fast response preference
|
||||
assert balanced == "gpt-5.1" # gpt-5.1 for balanced
|
||||
assert fast_response == "gpt-5.2" # gpt-5.2 comes first in fast response preference
|
||||
assert balanced == "gpt-5.2" # gpt-5.2 for balanced
|
||||
|
||||
finally:
|
||||
# Restore original environment
|
||||
|
||||
@@ -20,7 +20,7 @@ CASSETTE_DIR.mkdir(exist_ok=True)
|
||||
# Mapping of OpenAI model names to their cassette files
|
||||
CONSENSUS_CASSETTES = {
|
||||
"gpt-5": CASSETTE_DIR / "consensus_step1_gpt5_for.json",
|
||||
"gpt-5.1": CASSETTE_DIR / "consensus_step1_gpt51_for.json",
|
||||
"gpt-5.2": CASSETTE_DIR / "consensus_step1_gpt52_for.json",
|
||||
}
|
||||
|
||||
GEMINI_REPLAY_DIR = Path(__file__).parent / "gemini_cassettes"
|
||||
@@ -32,11 +32,11 @@ GEMINI_REPLAY_PATH = GEMINI_REPLAY_DIR / "consensus" / "step2_gemini25_flash_aga
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.no_mock_provider
|
||||
@pytest.mark.parametrize("openai_model", ["gpt-5", "gpt-5.1"])
|
||||
@pytest.mark.parametrize("openai_model", ["gpt-5", "gpt-5.2"])
|
||||
async def test_consensus_multi_model_consultations(monkeypatch, openai_model):
|
||||
"""Exercise ConsensusTool against OpenAI model (supporting) and gemini-2.5-flash (critical).
|
||||
|
||||
Tests both gpt-5 and gpt-5.1 to ensure regression coverage for both model families.
|
||||
Tests both gpt-5 and gpt-5.2 to ensure regression coverage for both model families.
|
||||
"""
|
||||
|
||||
# Get the cassette path for this model
|
||||
|
||||
@@ -37,14 +37,14 @@ class TestIntelligentFallback:
|
||||
|
||||
@patch.dict(os.environ, {"OPENAI_API_KEY": "sk-test-key", "GEMINI_API_KEY": ""}, clear=False)
|
||||
def test_prefers_openai_o3_mini_when_available(self):
|
||||
"""Test that gpt-5.1 is preferred when OpenAI API key is available (based on new preference order)"""
|
||||
"""Test that gpt-5.2 is preferred when OpenAI API key is available (based on new preference order)"""
|
||||
# Register only OpenAI provider for this test
|
||||
from providers.openai import OpenAIModelProvider
|
||||
|
||||
ModelProviderRegistry.register_provider(ProviderType.OPENAI, OpenAIModelProvider)
|
||||
|
||||
fallback_model = ModelProviderRegistry.get_preferred_fallback_model()
|
||||
assert fallback_model == "gpt-5.1" # Based on new preference order: gpt-5.1 before o4-mini
|
||||
assert fallback_model == "gpt-5.2" # Based on new preference order: gpt-5.2 before o4-mini
|
||||
|
||||
@patch.dict(os.environ, {"OPENAI_API_KEY": "", "GEMINI_API_KEY": "test-gemini-key"}, clear=False)
|
||||
def test_prefers_gemini_flash_when_openai_unavailable(self):
|
||||
@@ -147,8 +147,8 @@ class TestIntelligentFallback:
|
||||
|
||||
history, tokens = build_conversation_history(context, model_context=None)
|
||||
|
||||
# Verify that ModelContext was called with gpt-5.1 (the intelligent fallback based on new preference order)
|
||||
mock_context_class.assert_called_once_with("gpt-5.1")
|
||||
# Verify that ModelContext was called with gpt-5.2 (the intelligent fallback based on new preference order)
|
||||
mock_context_class.assert_called_once_with("gpt-5.2")
|
||||
|
||||
def test_auto_mode_with_gemini_only(self):
|
||||
"""Test auto mode behavior when only Gemini API key is available"""
|
||||
|
||||
@@ -50,7 +50,7 @@ class TestOpenAIProvider:
|
||||
assert provider.validate_model_name("o4-mini") is True
|
||||
assert provider.validate_model_name("gpt-5") is True
|
||||
assert provider.validate_model_name("gpt-5-mini") is True
|
||||
assert provider.validate_model_name("gpt-5.1") is True
|
||||
assert provider.validate_model_name("gpt-5.2") is True
|
||||
assert provider.validate_model_name("gpt-5.1-codex") is True
|
||||
assert provider.validate_model_name("gpt-5.1-codex-mini") is True
|
||||
|
||||
@@ -62,6 +62,7 @@ class TestOpenAIProvider:
|
||||
assert provider.validate_model_name("gpt5") is True
|
||||
assert provider.validate_model_name("gpt5-mini") is True
|
||||
assert provider.validate_model_name("gpt5mini") is True
|
||||
assert provider.validate_model_name("gpt5.2") is True
|
||||
assert provider.validate_model_name("gpt5.1") is True
|
||||
assert provider.validate_model_name("gpt5.1-codex") is True
|
||||
assert provider.validate_model_name("codex-mini") is True
|
||||
@@ -83,7 +84,8 @@ class TestOpenAIProvider:
|
||||
assert provider._resolve_model_name("gpt5") == "gpt-5"
|
||||
assert provider._resolve_model_name("gpt5-mini") == "gpt-5-mini"
|
||||
assert provider._resolve_model_name("gpt5mini") == "gpt-5-mini"
|
||||
assert provider._resolve_model_name("gpt5.1") == "gpt-5.1"
|
||||
assert provider._resolve_model_name("gpt5.2") == "gpt-5.2"
|
||||
assert provider._resolve_model_name("gpt5.1") == "gpt-5.2"
|
||||
assert provider._resolve_model_name("gpt5.1-codex") == "gpt-5.1-codex"
|
||||
assert provider._resolve_model_name("codex-mini") == "gpt-5.1-codex-mini"
|
||||
|
||||
@@ -95,7 +97,8 @@ class TestOpenAIProvider:
|
||||
assert provider._resolve_model_name("o4-mini") == "o4-mini"
|
||||
assert provider._resolve_model_name("gpt-5") == "gpt-5"
|
||||
assert provider._resolve_model_name("gpt-5-mini") == "gpt-5-mini"
|
||||
assert provider._resolve_model_name("gpt-5.1") == "gpt-5.1"
|
||||
assert provider._resolve_model_name("gpt-5.2") == "gpt-5.2"
|
||||
assert provider._resolve_model_name("gpt-5.1") == "gpt-5.2"
|
||||
assert provider._resolve_model_name("gpt-5.1-codex") == "gpt-5.1-codex"
|
||||
assert provider._resolve_model_name("gpt-5.1-codex-mini") == "gpt-5.1-codex-mini"
|
||||
|
||||
@@ -158,12 +161,12 @@ class TestOpenAIProvider:
|
||||
assert capabilities.supports_function_calling is True
|
||||
assert capabilities.supports_temperature is True
|
||||
|
||||
def test_get_capabilities_gpt51(self):
|
||||
"""Test GPT-5.1 capabilities reflect new metadata."""
|
||||
def test_get_capabilities_gpt52(self):
|
||||
"""Test GPT-5.2 capabilities reflect new metadata."""
|
||||
provider = OpenAIModelProvider("test-key")
|
||||
|
||||
capabilities = provider.get_capabilities("gpt-5.1")
|
||||
assert capabilities.model_name == "gpt-5.1"
|
||||
capabilities = provider.get_capabilities("gpt-5.2")
|
||||
assert capabilities.model_name == "gpt-5.2"
|
||||
assert capabilities.supports_streaming is True
|
||||
assert capabilities.supports_function_calling is True
|
||||
assert capabilities.supports_json_mode is True
|
||||
|
||||
@@ -133,8 +133,8 @@ class TestModelSelection:
|
||||
ModelProviderRegistry.register_provider(ProviderType.OPENAI, OpenAIModelProvider)
|
||||
|
||||
model = ModelProviderRegistry.get_preferred_fallback_model(ToolModelCategory.FAST_RESPONSE)
|
||||
# OpenAI now prefers gpt-5.1 for fast response (based on our new preference order)
|
||||
assert model == "gpt-5.1"
|
||||
# OpenAI now prefers gpt-5.2 for fast response (based on our new preference order)
|
||||
assert model == "gpt-5.2"
|
||||
|
||||
def test_fast_response_with_gemini_only(self):
|
||||
"""Test FAST_RESPONSE prefers flash when only Gemini is available."""
|
||||
@@ -167,8 +167,8 @@ class TestModelSelection:
|
||||
ModelProviderRegistry.register_provider(ProviderType.OPENAI, OpenAIModelProvider)
|
||||
|
||||
model = ModelProviderRegistry.get_preferred_fallback_model(ToolModelCategory.BALANCED)
|
||||
# OpenAI prefers gpt-5.1 for balanced (based on our new preference order)
|
||||
assert model == "gpt-5.1"
|
||||
# OpenAI prefers gpt-5.2 for balanced (based on our new preference order)
|
||||
assert model == "gpt-5.2"
|
||||
|
||||
def test_no_category_uses_balanced_logic(self):
|
||||
"""Test that no category specified uses balanced logic."""
|
||||
@@ -209,7 +209,7 @@ class TestFlexibleModelSelection:
|
||||
"env": {"OPENAI_API_KEY": "test-key"},
|
||||
"provider_type": ProviderType.OPENAI,
|
||||
"category": ToolModelCategory.FAST_RESPONSE,
|
||||
"expected": "gpt-5.1", # Based on new preference order
|
||||
"expected": "gpt-5.2", # Based on new preference order
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ class TestOpenAIProvider:
|
||||
assert provider.validate_model_name("o4-mini")
|
||||
assert provider.validate_model_name("o4mini")
|
||||
assert provider.validate_model_name("o4-mini")
|
||||
assert provider.validate_model_name("gpt-5.1")
|
||||
assert provider.validate_model_name("gpt-5.2")
|
||||
assert provider.validate_model_name("gpt-5.1-codex")
|
||||
assert provider.validate_model_name("gpt-5.1-codex-mini")
|
||||
assert not provider.validate_model_name("gpt-4o")
|
||||
@@ -223,11 +223,11 @@ class TestOpenAIProvider:
|
||||
for alias in aliases:
|
||||
assert not provider.get_capabilities(alias).supports_extended_thinking
|
||||
|
||||
def test_gpt51_family_capabilities(self):
|
||||
"""Ensure GPT-5.1 family exposes correct capability flags."""
|
||||
def test_gpt52_family_capabilities(self):
|
||||
"""Ensure GPT-5.2 base model exposes correct capability flags."""
|
||||
provider = OpenAIModelProvider(api_key="test-key")
|
||||
|
||||
base = provider.get_capabilities("gpt-5.1")
|
||||
base = provider.get_capabilities("gpt-5.2")
|
||||
assert base.supports_streaming
|
||||
assert base.allow_code_generation
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class TestSupportedModelsAliases:
|
||||
assert "o3mini" in provider.MODEL_CAPABILITIES["o3-mini"].aliases
|
||||
assert "o3pro" in provider.MODEL_CAPABILITIES["o3-pro"].aliases
|
||||
assert "gpt4.1" in provider.MODEL_CAPABILITIES["gpt-4.1"].aliases
|
||||
assert "gpt5.1" in provider.MODEL_CAPABILITIES["gpt-5.1"].aliases
|
||||
assert "gpt5.2" in provider.MODEL_CAPABILITIES["gpt-5.2"].aliases
|
||||
assert "gpt5.1-codex" in provider.MODEL_CAPABILITIES["gpt-5.1-codex"].aliases
|
||||
assert "codex-mini" in provider.MODEL_CAPABILITIES["gpt-5.1-codex-mini"].aliases
|
||||
|
||||
@@ -64,14 +64,15 @@ class TestSupportedModelsAliases:
|
||||
assert provider._resolve_model_name("o3pro") == "o3-pro" # o3pro resolves to o3-pro
|
||||
assert provider._resolve_model_name("o4mini") == "o4-mini"
|
||||
assert provider._resolve_model_name("gpt4.1") == "gpt-4.1" # gpt4.1 resolves to gpt-4.1
|
||||
assert provider._resolve_model_name("gpt5.1") == "gpt-5.1"
|
||||
assert provider._resolve_model_name("gpt5.2") == "gpt-5.2"
|
||||
assert provider._resolve_model_name("gpt5.1") == "gpt-5.2"
|
||||
assert provider._resolve_model_name("gpt5.1-codex") == "gpt-5.1-codex"
|
||||
assert provider._resolve_model_name("codex-mini") == "gpt-5.1-codex-mini"
|
||||
|
||||
# Test case insensitive resolution
|
||||
assert provider._resolve_model_name("Mini") == "gpt-5-mini" # mini -> gpt-5-mini now
|
||||
assert provider._resolve_model_name("O3MINI") == "o3-mini"
|
||||
assert provider._resolve_model_name("Gpt5.1") == "gpt-5.1"
|
||||
assert provider._resolve_model_name("Gpt5.1") == "gpt-5.2"
|
||||
|
||||
def test_xai_provider_aliases(self):
|
||||
"""Test XAI provider's alias structure."""
|
||||
|
||||
Reference in New Issue
Block a user