From 5a55ce7dd5d382c1bbdaa724252c62cb92ad9369 Mon Sep 17 00:00:00 2001 From: homelab-ha-agent Date: Wed, 1 Jul 2026 18:45:55 -0400 Subject: [PATCH] fix(model): don't strip alias-derived prefixes for the custom provider bucket _MATCHING_PREFIX_STRIP_PROVIDERS includes "custom" so that manually typed config values like "zai/glm-5.1" repair themselves for their matching native provider. But "custom" is a generic bucket for arbitrary user-defined endpoints, not a vendor identity -- unlike zai/gemini/xai, where a matching alias really does mean "this prefix names the same backend as the target provider." _PROVIDER_ALIASES maps "ollama" -> "custom", so a model configured as "ollama/glm-5.2" against a named custom provider (e.g. a LiteLLM proxy fronting Ollama, which registers its routes as "ollama/") had its prefix stripped to bare "glm-5.2" -- a name the proxy doesn't recognize. _strip_matching_provider_prefix now only strips a literal "custom/" prefix when the target resolves to "custom"; an alias that merely resolves to custom (ollama) no longer qualifies, since custom has no vendor identity for it to redundantly repeat. Co-Authored-By: Claude Sonnet 5 --- hermes_cli/model_normalize.py | 15 ++++++++++++++- tests/hermes_cli/test_model_normalize.py | 21 +++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) 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: