fix(normalize): lowercase Xiaomi model IDs for case-insensitive config (#15066)

Xiaomi's API (api.xiaomimimo.com) requires lowercase model IDs like
"mimo-v2.5-pro" but rejects mixed-case names like "MiMo-V2.5-Pro"
that users copy from marketing docs or the ProviderEntry description.

Add _LOWERCASE_MODEL_PROVIDERS set and apply .lower() to model names
for providers in this set (currently just xiaomi) after stripping the
provider prefix. This ensures any case variant in config.yaml is
normalized before hitting the API.

Other providers (minimax, zai, etc.) are NOT affected — their APIs
accept mixed case (e.g. MiniMax-M2.7).
This commit is contained in:
kshitij 2026-04-24 03:33:05 -07:00 committed by GitHub
parent 3e994e38f7
commit 7897f65a94
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 72 additions and 1 deletions

View file

@ -195,6 +195,26 @@ class TestXiaomiNormalization:
from hermes_cli.model_normalize import _MATCHING_PREFIX_STRIP_PROVIDERS
assert "xiaomi" in _MATCHING_PREFIX_STRIP_PROVIDERS
def test_lowercase_model_provider(self):
"""Xiaomi must be in _LOWERCASE_MODEL_PROVIDERS."""
from hermes_cli.model_normalize import _LOWERCASE_MODEL_PROVIDERS
assert "xiaomi" in _LOWERCASE_MODEL_PROVIDERS
def test_lowercase_subset_of_matching_prefix(self):
"""_LOWERCASE_MODEL_PROVIDERS must be a subset of _MATCHING_PREFIX_STRIP_PROVIDERS.
Otherwise the .lower() code path is unreachable dead code the
provider check at line 422 gates entry to the block.
"""
from hermes_cli.model_normalize import (
_LOWERCASE_MODEL_PROVIDERS,
_MATCHING_PREFIX_STRIP_PROVIDERS,
)
assert _LOWERCASE_MODEL_PROVIDERS.issubset(_MATCHING_PREFIX_STRIP_PROVIDERS), (
f"_LOWERCASE_MODEL_PROVIDERS has entries not in _MATCHING_PREFIX_STRIP_PROVIDERS: "
f"{_LOWERCASE_MODEL_PROVIDERS - _MATCHING_PREFIX_STRIP_PROVIDERS}"
)
def test_normalize_strips_provider_prefix(self):
from hermes_cli.model_normalize import normalize_model_for_provider
result = normalize_model_for_provider("xiaomi/mimo-v2-pro", "xiaomi")
@ -205,6 +225,40 @@ class TestXiaomiNormalization:
result = normalize_model_for_provider("mimo-v2-pro", "xiaomi")
assert result == "mimo-v2-pro"
@pytest.mark.parametrize("empty_input", ["", None, " "])
def test_normalize_empty_and_none(self, empty_input):
"""None, empty, and whitespace-only inputs return empty string."""
from hermes_cli.model_normalize import normalize_model_for_provider
result = normalize_model_for_provider(empty_input, "xiaomi")
assert result == ""
@pytest.mark.parametrize("input_name,expected", [
("MiMo-V2.5-Pro", "mimo-v2.5-pro"),
("MIMO-V2.5-PRO", "mimo-v2.5-pro"),
("MiMo-v2.5-pro", "mimo-v2.5-pro"),
("mimo-v2.5-pro", "mimo-v2.5-pro"), # already lowercase
("MiMo-V2-Pro", "mimo-v2-pro"),
("MiMo-V2-Omni", "mimo-v2-omni"),
("MiMo-V2-Flash", "mimo-v2-flash"),
("MiMo-V2.5", "mimo-v2.5"),
])
def test_normalize_lowercases_mixed_case(self, input_name, expected):
"""Xiaomi's API requires lowercase model IDs — mixed case from docs must be lowered."""
from hermes_cli.model_normalize import normalize_model_for_provider
result = normalize_model_for_provider(input_name, "xiaomi")
assert result == expected
@pytest.mark.parametrize("input_name,expected", [
("xiaomi/MiMo-V2.5-Pro", "mimo-v2.5-pro"),
("xiaomi/MIMO-V2.5-PRO", "mimo-v2.5-pro"),
("xiaomi/mimo-v2.5-pro", "mimo-v2.5-pro"),
])
def test_normalize_strips_prefix_and_lowercases(self, input_name, expected):
"""Provider prefix stripping AND lowercasing must both work together."""
from hermes_cli.model_normalize import normalize_model_for_provider
result = normalize_model_for_provider(input_name, "xiaomi")
assert result == expected
# =============================================================================
# URL mapping