feat: GPT-5.2 support

This commit is contained in:
Fahad
2025-12-11 19:11:50 +00:00
parent 5c3dd75ca6
commit 8b16405f06
33 changed files with 216 additions and 119 deletions

View File

@@ -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

File diff suppressed because one or more lines are too long

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"""

View File

@@ -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

View File

@@ -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
},
]

View File

@@ -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

View File

@@ -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."""