diff --git a/hermes_cli/model_normalize.py b/hermes_cli/model_normalize.py index 8c4a31b25d2..c2865b0364b 100644 --- a/hermes_cli/model_normalize.py +++ b/hermes_cli/model_normalize.py @@ -245,6 +245,14 @@ def _strip_matching_provider_prefix(model_name: str, target_provider: str) -> st This prevents arbitrary slash-bearing model IDs from being mangled on native providers while still repairing manual config values like ``zai/glm-5.1`` for the ``zai`` provider. + + ``custom`` is a generic bucket for arbitrary user-defined endpoints, not + a vendor identity like ``zai``/``gemini``/``xai``. An alias that merely + *resolves to* ``custom`` (e.g. ``ollama``, via ``_PROVIDER_ALIASES``) + does not mean a ``ollama/`` prefix is redundant -- it may be the actual + routing prefix a proxy in front of the custom endpoint (e.g. LiteLLM) + requires, as in ``ollama/glm-5.2``. Only a literal ``custom/`` prefix -- + the bucket's own name -- is treated as redundant here. """ if "/" not in model_name: return model_name @@ -253,8 +261,13 @@ def _strip_matching_provider_prefix(model_name: str, target_provider: str) -> st if not prefix.strip() or not remainder.strip(): return model_name - normalized_prefix = _normalize_provider_alias(prefix) normalized_target = _normalize_provider_alias(target_provider) + if normalized_target == "custom": + if prefix.strip().lower() == "custom": + return remainder.strip() + return model_name + + normalized_prefix = _normalize_provider_alias(prefix) if normalized_prefix and normalized_prefix == normalized_target: return remainder.strip() return model_name diff --git a/tests/hermes_cli/test_model_normalize.py b/tests/hermes_cli/test_model_normalize.py index 564c188e96e..a11389aef1d 100644 --- a/tests/hermes_cli/test_model_normalize.py +++ b/tests/hermes_cli/test_model_normalize.py @@ -182,6 +182,27 @@ class TestIssue6211NativeProviderPrefixNormalization: assert normalize_model_for_provider(model, target_provider) == expected +class TestCustomProviderIsNotAVendorIdentity: + """``custom`` is a generic bucket, not a vendor -- an alias that merely + *resolves to* ``custom`` (e.g. ``ollama`` -> ``custom`` in + ``_PROVIDER_ALIASES``) must not be treated as a redundant prefix the + way ``zai/``, ``gemini/``, etc. are for their own native providers. + + Regression for: a named custom provider (e.g. a LiteLLM proxy fronting + Ollama) registers its own routing name as ``ollama/glm-5.2``. Stripping + the ``ollama/`` prefix because it happens to alias to ``custom`` + produced a bare ``glm-5.2`` the proxy doesn't recognise. + """ + + @pytest.mark.parametrize("model,expected", [ + ("ollama/glm-5.2", "ollama/glm-5.2"), + ("ollama/llama3.2", "ollama/llama3.2"), + ("custom/some-model", "some-model"), + ]) + def test_only_literal_custom_prefix_is_stripped(self, model, expected): + assert normalize_model_for_provider(model, "custom") == expected + + # ── detect_vendor ────────────────────────────────────────────────────── class TestDetectVendor: