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/<model>") 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 <noreply@anthropic.com>
This commit is contained in:
homelab-ha-agent 2026-07-01 18:45:55 -04:00 committed by kshitij
parent 4be89059ae
commit 5a55ce7dd5
2 changed files with 35 additions and 1 deletions

View file

@ -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

View file

@ -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: