fix(models): mark the Anthropic curated fallback as a placeholder
_anthropic_catalog() returned the curated list as a plain list when the live /v1/models fetch failed, so a transient outage on a proxy base_url was cached with the full 1h TTL as if it were the account's/proxy's real catalog, and neither a same-credentials restart nor Refresh Models could shake it before the TTL lapsed. Wrap the fallback return in CuratedFallbackModels, the placeholder type #107391 introduced for the same class of bug. Salvaged from #121248 (the Anthropic half; the Codex half lands via the typed-fallback commit before this one).
This commit is contained in:
@@ -1436,7 +1436,9 @@ def _anthropic_catalog(normalized: str, force_refresh: bool) -> list[str]:
|
||||
live = _fetch_anthropic_models(base_url=cfg_base_url or None, api_key=cfg_api_key or None)
|
||||
curated = list(_PROVIDER_MODELS.get("anthropic", []))
|
||||
if not live:
|
||||
return curated
|
||||
# A placeholder for the outage, not this account/proxy's catalog: the disk cache must
|
||||
# never pin it over a same-credentials live row (#107391).
|
||||
return CuratedFallbackModels(curated)
|
||||
# The live /v1/models dump lags newly-routed curated aliases (reachable before enumerated):
|
||||
# curated first, then live-only extras, so a fresh curated model never disappears.
|
||||
return live if cfg_base_url else _merge_unique(curated, live)
|
||||
|
||||
@@ -123,3 +123,14 @@ def test_codex_cold_fallback_retries_after_short_ttl(monkeypatch, tmp_path):
|
||||
assert "gpt-6-astra" in mod.cached_provider_model_ids("openai-codex")
|
||||
assert "fallback" not in cache["openai-codex"]
|
||||
spawn.assert_not_called()
|
||||
|
||||
|
||||
def test_anthropic_catalog_marks_the_curated_list_as_fallback_on_a_failed_live_fetch():
|
||||
# _anthropic_catalog used to `return curated` (a plain list) on a failed live fetch, so a
|
||||
# transient outage on a proxy base_url cached the generic curated list over the account's/
|
||||
# proxy's real catalog for a full hour (same class of bug as #107391, just missed by 3fb8b3f6).
|
||||
with patch.object(mod, "_get_model_config_dict", return_value={}), \
|
||||
patch.object(mod, "_fetch_anthropic_models", return_value=None):
|
||||
rows = mod.provider_model_ids("anthropic")
|
||||
assert isinstance(rows, mod.CuratedFallbackModels)
|
||||
assert rows == list(mod._PROVIDER_MODELS["anthropic"])
|
||||
|
||||
Reference in New Issue
Block a user