fix(models): OpenRouter :nitro/:floor routing variants no longer rejected by /model validation

OpenRouter's :nitro, :floor, :exacto, and :online suffixes are request-time
routing modifiers valid on any model id — /models lists only the base model.
validate_requested_model() compared the full suffixed id against the listing,
so a valid variant was either rejected outright or fuzzy-auto-corrected to
the base id, silently stripping the user's routing opt-in.

Now, for OpenRouter only, a recognized variant suffix validates the BASE id
against the live listing (and the curated-catalog soft-accept and static-
catalog fallback paths) while preserving the suffixed id for persistence and
API requests — checked BEFORE fuzzy correction. :free/:batch/:thinking
remain direct catalog SKUs and keep exact-match semantics; unknown suffixes
and unknown bases are still rejected.

Reported by JEB (Jakob's Hermes Agent) via Discord.
This commit is contained in:
Teknium
2026-08-24 11:18:37 -07:00
parent 1420176393
commit f14059fad2
2 changed files with 140 additions and 1 deletions
+59 -1
View File
@@ -3325,6 +3325,30 @@ _AGGREGATOR_PROVIDERS = frozenset(
{"nous", "openrouter", "ai-gateway", "copilot", "kilocode"}
)
# OpenRouter request-time routing variants (docs: guides/routing/model-variants).
# These suffixes are per-request routing modifiers valid on ANY model id —
# ":nitro" sorts the endpoint pool by throughput and admits priority-tier
# endpoints, ":floor" sorts by price and admits flex-tier endpoints, ":exacto"
# applies quality-first provider sorting, ":online" attaches the web plugin.
# They are never separate catalog entries: /models lists only the base id.
# NOT in this set: ":free", ":batch", ":thinking", ":extended" — those ARE
# distinct catalog SKUs that appear in /models when they exist, so absence
# from the listing is authoritative for them and the direct-membership check
# above handles the valid ones.
_OPENROUTER_VARIANT_SUFFIXES = frozenset({"nitro", "floor", "exacto", "online"})
def _openrouter_variant_base(model_id: str) -> Optional[str]:
"""Return the base model id when ``model_id`` carries a recognized
OpenRouter routing-variant suffix (e.g. ``x-ai/grok-4:nitro`` →
``x-ai/grok-4``), else ``None``."""
base, sep, suffix = (model_id or "").rpartition(":")
if not sep or not base:
return None
if suffix.lower() in _OPENROUTER_VARIANT_SUFFIXES:
return base
return None
# Subscription/OAuth providers whose catalogs RE-EXPOSE other vendors' models
# would be listed here (tried only as a last resort for bare short-alias
# resolution, after every native-vendor catalog, so they never hijack an alias
@@ -6812,6 +6836,24 @@ def validate_requested_model(
"recognized": True,
"message": None,
}
# OpenRouter routing variants (":nitro", ":floor", ...) are request-time
# modifiers, not catalog entries — /models lists only the base id.
# Validate the BASE against the listing but preserve the suffixed id,
# and do this BEFORE fuzzy auto-correction: get_close_matches would
# otherwise "correct" `model:nitro` → `model` and silently strip the
# user's routing opt-in.
_variant_base = (
_openrouter_variant_base(requested_for_lookup)
if normalized == "openrouter"
else None
)
if _variant_base is not None and _variant_base in set(api_models):
return {
"accepted": True,
"persist": True,
"recognized": True,
"message": None,
}
else:
# API responded but model is not listed. Accept anyway —
# the user may have access to models not shown in the public
@@ -6853,7 +6895,8 @@ def validate_requested_model(
_openai_listing_is_authoritative = is_official_openai_host(base_url)
if not _openai_listing_is_authoritative and _model_in_provider_catalog(
requested_for_lookup.lower(), _provider_keys(normalized)
(_variant_base or requested_for_lookup).lower(),
_provider_keys(normalized),
):
return {
"accepted": True,
@@ -6936,6 +6979,21 @@ def validate_requested_model(
"recognized": True,
"message": None,
}
# OpenRouter routing-variant suffixes: validate the base id against
# the catalog, keep the suffixed id (same rule as the live-listing
# path above — variants never appear as catalog entries).
if normalized == "openrouter":
_cat_variant_base = _openrouter_variant_base(requested_for_lookup)
if (
_cat_variant_base is not None
and _cat_variant_base.lower() in catalog_lower
):
return {
"accepted": True,
"persist": True,
"recognized": True,
"message": None,
}
catalog_lower_list = list(catalog_lower.keys())
auto = get_close_matches(
requested_for_lookup.lower(), catalog_lower_list, n=1, cutoff=0.9
+81
View File
@@ -594,3 +594,84 @@ class TestProbeApiModelsUserAgent:
assert req.get_header("Authorization") is None
# -- validate — OpenRouter routing-variant suffixes (:nitro / :floor / ...) ----
class TestValidateOpenRouterVariantSuffixes:
"""OpenRouter's `:nitro`, `:floor`, `:exacto`, `:online` are request-time
routing modifiers, not catalog models — /models lists only the base id.
Validation must accept `base:variant` when `base` is listed, preserve the
suffixed id (no auto-correct stripping the routing opt-in), and still
reject variants on unknown bases and unknown suffixes."""
_LISTING = [
"~x-ai/grok-latest",
"x-ai/grok-4.6",
"deepseek/deepseek-v4-flash",
"thinkingmachines/inkling:free",
]
def _validate(self, model):
return _validate(model, "openrouter", api_models=self._LISTING)
@pytest.mark.parametrize("suffix", ["nitro", "floor", "exacto", "online"])
def test_variant_on_listed_base_accepted_unmodified(self, suffix):
result = self._validate(f"~x-ai/grok-latest:{suffix}")
assert result["accepted"] is True
assert result["recognized"] is True
assert result.get("corrected_model") is None
assert result["message"] is None
def test_variant_not_fuzzy_corrected_to_base(self):
"""The old failure mode: get_close_matches would 'fix' model:nitro
to the bare base id and silently drop the routing behavior."""
result = self._validate("x-ai/grok-4.6:nitro")
assert result["accepted"] is True
assert result.get("corrected_model") is None
def test_variant_on_unknown_base_rejected(self):
result = self._validate("x-ai/notreal-model:nitro")
assert result["accepted"] is False
def test_unknown_suffix_keeps_old_behavior(self):
result = self._validate("x-ai/grok-4.6:bogus")
assert result["accepted"] is False
def test_free_sku_still_direct_matched(self):
"""`:free` SKUs ARE catalog entries; direct membership handles them."""
result = self._validate("thinkingmachines/inkling:free")
assert result["accepted"] is True
assert result.get("corrected_model") is None
def test_variant_uppercase_suffix_accepted(self):
result = self._validate("x-ai/grok-4.6:NITRO")
assert result["accepted"] is True
assert result.get("corrected_model") is None
def test_non_openrouter_provider_unaffected(self):
"""The variant carve-out is OpenRouter-only; other providers keep
their existing behavior for colon-suffixed names."""
result = _validate(
"x-ai/grok-4.6:nitro",
"groq",
api_models=["x-ai/grok-4.6"],
)
assert result.get("corrected_model") != "x-ai/grok-4.6:nitro"
def test_static_catalog_fallback_accepts_variant(self):
"""Gateway path: /models unreachable → static catalog validates the
base id and preserves the suffix."""
with patch("hermes_cli.models.fetch_api_models", return_value=None), \
patch(
"hermes_cli.models.provider_model_ids",
return_value=["x-ai/grok-4.6", "anthropic/claude-opus-4.6"],
):
result = validate_requested_model(
"x-ai/grok-4.6:floor",
"openrouter",
base_url="https://openrouter.ai/api/v1",
)
assert result["accepted"] is True
assert result["recognized"] is True
assert result.get("corrected_model") is None