diff --git a/app/openai_constants.py b/app/openai_constants.py index c4a8cd6..a29f54a 100644 --- a/app/openai_constants.py +++ b/app/openai_constants.py @@ -33,6 +33,9 @@ GPT_5_MODEL = "gpt-5" GPT_5_MINI_MODEL = "gpt-5-mini" GPT_5_NANO_MODEL = "gpt-5-nano" +GPT_5_1_CHAT_LATEST_MODEL = "gpt-5.1-chat-latest" +GPT_5_1_MODEL = "gpt-5.1" +GPT_5_1_2025_11_13_MODEL = "gpt-5.1-2025-11-13" O3_MODEL = "o3" O4_MINI_MODEL = "o4-mini" GPT_5_2025_08_07_MODEL = "gpt-5-2025-08-07" @@ -77,11 +80,13 @@ GPT_4O_MINI_2024_07_18_MODEL: (3, 1), # GPT-5 chat latest GPT_5_CHAT_LATEST_MODEL: (3, 1), + GPT_5_1_CHAT_LATEST_MODEL: (3, 1), GPT_5_SEARCH_API_2025_10_14_MODEL: (3, 1), # GPT-5 family (dated) GPT_5_2025_08_07_MODEL: (3, 1), GPT_5_MINI_2025_08_07_MODEL: (3, 1), GPT_5_NANO_2025_08_07_MODEL: (3, 1), + GPT_5_1_2025_11_13_MODEL: (3, 1), # Reasoning models (dated) O3_2025_04_16_MODEL: (3, 1), O4_MINI_2025_04_16_MODEL: (3, 1), @@ -103,6 +108,7 @@ GPT_5_MODEL: GPT_5_2025_08_07_MODEL, GPT_5_MINI_MODEL: GPT_5_MINI_2025_08_07_MODEL, GPT_5_NANO_MODEL: GPT_5_NANO_2025_08_07_MODEL, + GPT_5_1_MODEL: GPT_5_1_2025_11_13_MODEL, GPT_5_SEARCH_API_MODEL: GPT_5_SEARCH_API_2025_10_14_MODEL, O3_MODEL: O3_2025_04_16_MODEL, O4_MINI_MODEL: O4_MINI_2025_04_16_MODEL, @@ -134,11 +140,13 @@ GPT_4_1_NANO_2025_04_14_MODEL: 1048576, # GPT-5 chat latest GPT_5_CHAT_LATEST_MODEL: 128000, + GPT_5_1_CHAT_LATEST_MODEL: 128000, GPT_5_SEARCH_API_2025_10_14_MODEL: 128000, # GPT-5 family (dated) GPT_5_2025_08_07_MODEL: 128000, GPT_5_MINI_2025_08_07_MODEL: 128000, GPT_5_NANO_2025_08_07_MODEL: 128000, + GPT_5_1_2025_11_13_MODEL: 128000, # Reasoning models (dated) O3_2025_04_16_MODEL: 128000, O4_MINI_2025_04_16_MODEL: 128000, diff --git a/app/openai_ops.py b/app/openai_ops.py index ae5d445..b9ef4b7 100644 --- a/app/openai_ops.py +++ b/app/openai_ops.py @@ -86,13 +86,15 @@ def messages_within_context_window( def _is_reasoning(model: str) -> bool: """Returns True if the model is a reasoning model under Chat Completions. - Excludes chat models like gpt-5-chat-latest and gpt-5-search-api. Matches o3*, o4*, and - non-chat gpt-5* families. Case-insensitive and safe with None/empty. + Excludes chat models like gpt-5-chat-latest, gpt-5.1-chat-latest, and gpt-5-search-api. + Matches o3*, o4*, and non-chat gpt-5* families. Case-insensitive and safe with None/empty. """ if not model: return False ml = model.lower() - if ml.startswith("gpt-5-chat") or ml.startswith("gpt-5-search"): + # Treat any gpt-5 family chat/search variants (including numbered updates) + # as regular chat models so they keep sampling params. + if ml.startswith("gpt-5") and ("-chat" in ml or "-search" in ml): return False return ( ml.startswith("o1") diff --git a/app/slack_ui.py b/app/slack_ui.py index 116aabd..f4a5019 100644 --- a/app/slack_ui.py +++ b/app/slack_ui.py @@ -8,6 +8,8 @@ GPT_4O_MINI_MODEL, GPT_4_1_MODEL, GPT_4_1_MINI_MODEL, + GPT_5_1_CHAT_LATEST_MODEL, + GPT_5_1_MODEL, GPT_5_CHAT_LATEST_MODEL, GPT_5_MODEL, GPT_5_MINI_MODEL, @@ -440,6 +442,14 @@ def build_configure_modal(context: BoltContext) -> dict: ) options = [ + { + "text": {"type": "plain_text", "text": "GPT-5.1-chat-latest"}, + "value": GPT_5_1_CHAT_LATEST_MODEL, + }, + { + "text": {"type": "plain_text", "text": "GPT-5.1"}, + "value": GPT_5_1_MODEL, + }, { "text": {"type": "plain_text", "text": "GPT-5-chat-latest"}, "value": GPT_5_CHAT_LATEST_MODEL, diff --git a/tests/model_constants_test.py b/tests/model_constants_test.py index 85986f3..39d1771 100644 --- a/tests/model_constants_test.py +++ b/tests/model_constants_test.py @@ -6,12 +6,19 @@ MODEL_CONTEXT_LENGTHS, GPT_4_MODEL, GPT_4_0613_MODEL, + GPT_5_1_MODEL, + GPT_5_1_2025_11_13_MODEL, ) def test_alias_resolution(): """Tests that a model alias resolves to its specific version.""" assert resolve_model_alias(GPT_4_MODEL) == GPT_4_0613_MODEL + +def test_gpt_5_1_alias_resolution(): + """Ensures the GPT-5.1 alias resolves to the dated release.""" + assert resolve_model_alias(GPT_5_1_MODEL) == GPT_5_1_2025_11_13_MODEL + def test_unregistered_model_fails(): """Tests that resolving an unregistered model raises NotImplementedError.""" # First, test the resolver diff --git a/tests/openai_ops_test.py b/tests/openai_ops_test.py index f138456..338a3cf 100755 --- a/tests/openai_ops_test.py +++ b/tests/openai_ops_test.py @@ -149,6 +149,24 @@ def fake_calculate_num_tokens(messages, model=None): # type: ignore[no-redef] assert captured["model"] == GPT_4O_MODEL +@pytest.mark.parametrize( + "model,expected", + [ + ("gpt-5-chat-latest", False), + ("gpt-5.1-chat-latest", False), + ("gpt-5-search-api", False), + ("gpt-5.1-2025-11-13", True), + ("gpt-5-nano", True), + ("o3", True), + ("o4-mini", True), + ("o1-preview", True), + ("gpt-4o", False), + ], +) +def test_is_reasoning_heuristics(model, expected): + assert ops._is_reasoning(model) is expected + + @pytest.mark.parametrize("api_type", ["openai", "azure"]) @pytest.mark.parametrize( "model,is_reasoning,temperature,timeout,user",