Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
5 changes: 4 additions & 1 deletion chatmock/fast_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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(
Expand Down
4 changes: 3 additions & 1 deletion chatmock/model_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down
21 changes: 21 additions & 0 deletions chatmock/model_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
35 changes: 35 additions & 0 deletions tests/test_model_catalog.py
Original file line number Diff line number Diff line change
@@ -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()
4 changes: 4 additions & 0 deletions tests/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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:
Expand Down