From 43724a168564d2e4a23f1a952b91198a9c447ed4 Mon Sep 17 00:00:00 2001 From: Fabricio Malta Date: Tue, 22 Sep 2026 15:52:25 -0300 Subject: [PATCH] feat: support GPT-6 Astra, GPT-6 Sol, GPT-6 Luna --- README.md | 3 +++ chatmock/fast_mode.py | 5 ++++- chatmock/model_catalog.py | 4 +++- chatmock/model_registry.py | 21 +++++++++++++++++++++ tests/test_model_catalog.py | 35 +++++++++++++++++++++++++++++++++++ tests/test_routes.py | 4 ++++ 6 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/test_model_catalog.py diff --git a/README.md b/README.md index 0df3503a..bff0eac1 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,9 @@ The server runs at `http://127.0.0.1:8000` by default. Use `http://127.0.0.1:800 ChatMock automatically discovers the models available to the signed-in ChatGPT account. The current catalog commonly includes: +- `gpt-6-astra` +- `gpt-6-sol` +- `gpt-6-luna` - `gpt-5.6-sol` - `gpt-5.6-terra` - `gpt-5.6-luna` diff --git a/chatmock/fast_mode.py b/chatmock/fast_mode.py index 498b70b8..a3cf4d26 100644 --- a/chatmock/fast_mode.py +++ b/chatmock/fast_mode.py @@ -12,6 +12,9 @@ "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", + "gpt-6-astra", + "gpt-6-sol", + "gpt-6-luna", "gpt-5.2", "gpt-5.1", "gpt-5", @@ -78,7 +81,7 @@ def resolve_service_tier( normalized = normalize_model_name(model) message = ( f"Fast mode is not supported for model '{normalized}'. " - "Use a supported GPT-5 priority-processing model or disable fast mode for this request." + "Use a model with priority processing or disable fast mode for this request." ) if explicit_request: return ServiceTierResolution( diff --git a/chatmock/model_catalog.py b/chatmock/model_catalog.py index 89459608..f57453ec 100644 --- a/chatmock/model_catalog.py +++ b/chatmock/model_catalog.py @@ -26,7 +26,7 @@ FETCH_TIMEOUT_SECONDS = 5 MODEL_CACHE_FILE = "chatmock_models_cache.json" # Bump only after verifying ChatMock against a newer Codex catalog contract. -CODEX_MODELS_CLIENT_VERSION = "0.146.0" +CODEX_MODELS_CLIENT_VERSION = "0.160.0" @dataclass(frozen=True) @@ -248,6 +248,8 @@ def _load_cache(self) -> None: return if not isinstance(payload, dict): return + if payload.get("client_version") != CODEX_MODELS_CLIENT_VERSION: + return cached_account_id = payload.get("account_id") current_account_id = _account_id_from_auth_file() diff --git a/chatmock/model_registry.py b/chatmock/model_registry.py index 0768b5ee..25698e33 100644 --- a/chatmock/model_registry.py +++ b/chatmock/model_registry.py @@ -83,6 +83,27 @@ class ModelSpec: allowed_efforts=frozenset(("low", "medium", "high", "xhigh", "max")), variant_efforts=("low", "medium", "high", "xhigh", "max"), ), + ModelSpec( + public_id="gpt-6-astra", + upstream_id="gpt-6-astra", + aliases=("gpt6-astra", "gpt-6-astra-latest"), + allowed_efforts=frozenset(("low", "medium", "high", "xhigh", "max", "ultra")), + variant_efforts=("low", "medium", "high", "xhigh", "max", "ultra"), + ), + ModelSpec( + public_id="gpt-6-sol", + upstream_id="gpt-6-sol", + aliases=("gpt6-sol", "gpt-6-sol-latest"), + allowed_efforts=frozenset(("low", "medium", "high", "xhigh", "max", "ultra")), + variant_efforts=("low", "medium", "high", "xhigh", "max", "ultra"), + ), + ModelSpec( + public_id="gpt-6-luna", + upstream_id="gpt-6-luna", + aliases=("gpt6-luna", "gpt-6-luna-latest"), + allowed_efforts=frozenset(("low", "medium", "high", "xhigh", "max")), + variant_efforts=("low", "medium", "high", "xhigh", "max"), + ), ModelSpec( public_id="gpt-5.3-codex", upstream_id="gpt-5.3-codex", diff --git a/tests/test_model_catalog.py b/tests/test_model_catalog.py new file mode 100644 index 00000000..69d86e7f --- /dev/null +++ b/tests/test_model_catalog.py @@ -0,0 +1,35 @@ +from __future__ import annotations + +import json +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch + +from chatmock.model_catalog import CODEX_MODELS_CLIENT_VERSION, ModelCatalog + + +class ModelCatalogCacheTests(unittest.TestCase): + def test_cache_from_older_client_version_is_ignored(self) -> None: + with tempfile.TemporaryDirectory() as directory: + cache_path = Path(directory) / "models.json" + payload = { + "account_id": "test-account", + "client_version": "0.146.0", + "fetched_at": "2026-09-22T00:00:00Z", + "models": [{"slug": "gpt-5.6-sol", "visibility": "list"}], + } + cache_path.write_text(json.dumps(payload), encoding="utf-8") + + with patch("chatmock.model_catalog._account_id_from_auth_file", return_value="test-account"): + old_catalog = ModelCatalog(cache_path=cache_path) + self.assertEqual(old_catalog._models, ()) + + payload["client_version"] = CODEX_MODELS_CLIENT_VERSION + cache_path.write_text(json.dumps(payload), encoding="utf-8") + current_catalog = ModelCatalog(cache_path=cache_path) + self.assertEqual([model.slug for model in current_catalog._models], ["gpt-5.6-sol"]) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py index a4906705..6b9eaba1 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -65,6 +65,8 @@ def test_openai_models_list(self) -> None: self.assertIn("gpt-5.6-sol", model_ids) self.assertIn("gpt-5.6-terra", model_ids) self.assertIn("gpt-5.6-luna", model_ids) + for model in ("gpt-6-astra", "gpt-6-sol", "gpt-6-luna"): + self.assertIn(model, model_ids) def test_ollama_tags_list(self) -> None: response = self.client.get("/api/tags") @@ -76,6 +78,8 @@ def test_ollama_tags_list(self) -> None: self.assertIn("gpt-5.6-sol", model_names) self.assertIn("gpt-5.6-terra", model_names) self.assertIn("gpt-5.6-luna", model_names) + for model in ("gpt-6-astra", "gpt-6-sol", "gpt-6-luna"): + self.assertIn(model, model_names) @patch("chatmock.routes_openai.start_upstream_request") def test_chat_completions(self, mock_start) -> None: