From 53ad7794e5810fa48cb532edf0308c647fb8d0da Mon Sep 17 00:00:00 2001 From: Julientalbot Date: Thu, 13 Aug 2026 11:27:44 +0400 Subject: [PATCH] fix(xai): drop stale 256K grok-4.6 context cache docs.x.ai (2026-08-12): grok-4.6 is the flagship, 500K context. Live GET /v1/models lists grok-4.6 at context_length 500000 (no grok-4.6-latest alias). #84661 landed the catalog. Main already lists native grok-4.6 on the xAI picker. This is only the leftover cache guard (same pattern as grok-4.3): pre-catalog builds persisted the grok-4 catch-all (256K). --- agent/model_metadata.py | 22 ++++++++++++++++++++++ tests/agent/test_model_metadata.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/agent/model_metadata.py b/agent/model_metadata.py index 8fabeb716d..ca53545f33 100644 --- a/agent/model_metadata.py +++ b/agent/model_metadata.py @@ -2021,6 +2021,19 @@ def _model_name_suggests_grok_4_3(model: str) -> bool: return "grok-4.3" in model.lower() +def _model_name_suggests_grok_4_6(model: str) -> bool: + """Return True if the model name looks like a Grok 4.6 variant. + + Catches ``grok-4.6`` and aggregator-prefixed slugs. Used as a guard + against stale cache entries seeded by pre-catalog builds that resolved + grok-4.6 via the generic ``grok-4`` catch-all (256,000) before the + 500K entry existed. Official card: docs.x.ai/developers/models/grok-4.6. + Live GET /v1/models lists ``grok-4.6`` at context_length 500000 and does + not publish a ``grok-4.6-latest`` alias. + """ + return "grok-4.6" in model.lower() + + def _query_local_context_length(model: str, base_url: str, api_key: str = "") -> Optional[int]: """Query a local server for the model's context length (short-TTL cached). @@ -2645,6 +2658,15 @@ def get_model_context_length( model, base_url, f"{cached:,}", ) _invalidate_cached_context_length(model, base_url) + # Same class of leftover as grok-4.3: grok-4.6 is 500K, but + # pre-catalog builds persisted the grok-4 catch-all (256,000). + elif cached <= 256_000 and _model_name_suggests_grok_4_6(model): + logger.info( + "Dropping stale Grok-4.6 cache entry %s@%s -> %s (pre-catalog value); " + "re-resolving via hardcoded defaults", + model, base_url, f"{cached:,}", + ) + _invalidate_cached_context_length(model, base_url) # Nous Portal: the portal /v1/models endpoint is authoritative. # Bypass the persistent cache so step 5b can always reconcile # against it — this corrects pre-fix entries seeded from the diff --git a/tests/agent/test_model_metadata.py b/tests/agent/test_model_metadata.py index bfcce7e67c..9d7ec36ff1 100644 --- a/tests/agent/test_model_metadata.py +++ b/tests/agent/test_model_metadata.py @@ -1221,6 +1221,36 @@ class TestGrok43StaleCacheGuard: assert ctx == 256_000, f"{slug} should stay 256000, got {ctx}" +class TestGrok46StaleCacheGuard: + """Pre-catalog builds resolved grok-4.6 via the generic 'grok-4' catch-all + (256,000) and persisted it before the 500K catalog entry existed. + The step-1 cache guard must drop that stale value and re-resolve to 500K. + Official card: 500,000 context (docs.x.ai/developers/models/grok-4.6). + """ + + def test_suggests_grok_4_6(self): + from agent.model_metadata import _model_name_suggests_grok_4_6 + assert _model_name_suggests_grok_4_6("grok-4.6") + assert _model_name_suggests_grok_4_6("xai/grok-4.6") + assert _model_name_suggests_grok_4_6("x-ai/grok-4.6") + assert not _model_name_suggests_grok_4_6("grok-4") + assert not _model_name_suggests_grok_4_6("grok-4-fast") + assert not _model_name_suggests_grok_4_6("grok-4.5") + assert not _model_name_suggests_grok_4_6("grok-4.3") + + def test_stale_grok_4_6_dropped_and_reresolves_to_500k(self, tmp_path, monkeypatch): + monkeypatch.setenv("HERMES_HOME", str(tmp_path)) + import importlib + import agent.model_metadata as mm + importlib.reload(mm) + base = "https://api.x.ai/v1" + mm.save_context_length("grok-4.6", base, 256_000) + ctx = mm.get_model_context_length( + "grok-4.6", base_url=base, api_key="", provider="xai" + ) + assert ctx == 500_000 + + class TestMoAContextLength: """MoA virtual provider resolves context from the aggregator slot, not 256K default."""