fix(providers): keep llamacpp as the model table's managed-runtime id

Mapping the llamacpp aliases to custom in hermes_cli.models sent the
managed local runtime's /model validation down the custom branch before
the staged-library check, so a downloaded-but-not-running GGUF lost its
recognized verdict and an unstaged one was accepted. Keep local and vllm
on custom there, leave the llamacpp aliases on their runtime id, and
move the orphaned 'local' display label to 'custom'.

The parity test now reads the aliases from the custom provider profile
instead of a hand-written list.
This commit is contained in:
Hermes Agent
2026-09-24 23:13:53 -05:00
committed by brooklyn!
parent 7a5c715844
commit 70f7fa05ca
3 changed files with 20 additions and 23 deletions

View File

@@ -501,9 +501,10 @@ _PROVIDER_ALIASES = dict((
("ollama", "custom"), # bare "ollama" = local; use "ollama-cloud" for cloud ("ollama", "custom"), # bare "ollama" = local; use "ollama-cloud" for cloud
("ollama_cloud", "ollama-cloud"), ("ollama_cloud", "ollama-cloud"),
# Local OpenAI-compatible servers route through the generic "custom" provider # Local OpenAI-compatible servers route through the generic "custom" provider
# (parity with hermes_cli.auth and hermes_cli.providers). Issue #62213. # (parity with hermes_cli.auth and hermes_cli.providers). Issue #62213. The llamacpp
("local", "custom"), ("vllm", "custom"), ("llamacpp", "custom"), # aliases stay unmapped: they are the managed local runtime's picker id, and the model
("llama.cpp", "custom"), ("llama-cpp", "custom"), # validator must reach its staged-library branch before the custom one.
("local", "custom"), ("vllm", "custom"),
)) ))

View File

@@ -146,7 +146,7 @@ _LABEL_OVERRIDES: Dict[str, str] = {
"copilot-acp": "GitHub Copilot ACP", "stepfun": "StepFun Step Plan", "xiaomi": "Xiaomi MiMo", "gmi": "GMI Cloud", "copilot-acp": "GitHub Copilot ACP", "stepfun": "StepFun Step Plan", "xiaomi": "Xiaomi MiMo", "gmi": "GMI Cloud",
"upstage": "Upstage Solar", "actual": "Actual Computer", "tencent-tokenhub": "Tencent TokenHub", "upstage": "Upstage Solar", "actual": "Actual Computer", "tencent-tokenhub": "Tencent TokenHub",
"nebius-token-factory": "Nebius Token Factory", "tencent-tokenplan": "Tencent TokenPlan", "lmstudio": "LM Studio", "nebius-token-factory": "Nebius Token Factory", "tencent-tokenplan": "Tencent TokenPlan", "lmstudio": "LM Studio",
"local": "Local endpoint", "bedrock": "AWS Bedrock", "vertex": "Google Vertex AI", "ollama-cloud": "Ollama Cloud", "custom": "Custom endpoint", "bedrock": "AWS Bedrock", "vertex": "Google Vertex AI", "ollama-cloud": "Ollama Cloud",
"xai-oauth": "xAI Grok OAuth (SuperGrok / Premium+)", "xai-oauth": "xAI Grok OAuth (SuperGrok / Premium+)",
} }

View File

@@ -8,33 +8,29 @@ different table:
* ``hermes_cli.auth.resolve_provider`` (credential resolution) * ``hermes_cli.auth.resolve_provider`` (credential resolution)
Historically these disagreed for the local self-hosted server aliases: bare Historically these disagreed for the local self-hosted server aliases: bare
``vllm`` / ``llamacpp`` resolved to ``"local"`` in ``providers`` (an orphan id ``local`` stayed ``"local"`` in ``providers`` and ``models`` while ``auth`` mapped
with no ``ProviderDef``), stayed ``"vllm"`` in ``models`` (unknown), yet mapped it to ``"custom"``, and ``vllm`` got three answers (``local`` / ``vllm`` /
to ``"custom"`` in ``auth`` — the "custom, local, custom:local" confusion the ``custom``) — the "custom, local, custom:local" confusion the bug report
bug report describes. They must all agree on the generic ``"custom"`` provider. describes. Every alias the ``custom`` provider profile declares must land on
``custom``; the one exception is the model table's managed llama.cpp runtime id,
which the picker's Local row and the staged-library validator key on.
""" """
import pytest import pytest
from hermes_cli.auth import resolve_provider from hermes_cli.auth import resolve_provider
from hermes_cli.models import normalize_provider as models_normalize from hermes_cli.models import normalize_provider as models_normalize
from hermes_cli.providers import normalize_provider as providers_normalize from hermes_cli.providers import LLAMACPP_ALIASES, normalize_provider as providers_normalize
from providers import get_provider_profile
# Local OpenAI-compatible server aliases users are told to configure. _CUSTOM_ALIASES = tuple(get_provider_profile("custom").aliases)
#
# ``local`` is included: it is declared a ``custom`` alias in
# ``plugins/model-providers/custom/__init__.py`` and ``auth.resolve_provider``
# already mapped it to ``"custom"`` (statically and via the plugin import), so
# leaving it as the orphan ``"local"`` id (no ``ProviderDef``) in the providers
# and models tables was exactly the cross-table disagreement this contract
# guards against. Routing code already treats ``{"custom", "local"}`` as
# equivalent (e.g. ``model_switch``/``web_server``), so unifying to ``custom``
# is behaviour-preserving.
_LOCAL_ALIASES = ("local", "ollama", "vllm", "llamacpp", "llama.cpp", "llama-cpp")
@pytest.mark.parametrize("alias", _LOCAL_ALIASES) @pytest.mark.parametrize("alias", _CUSTOM_ALIASES)
def test_local_aliases_normalize_to_custom_in_every_table(alias): def test_custom_profile_aliases_normalize_to_custom_in_every_table(alias):
assert providers_normalize(alias) == "custom" assert providers_normalize(alias) == "custom"
assert models_normalize(alias) == "custom"
assert resolve_provider(alias) == "custom" assert resolve_provider(alias) == "custom"
if alias in LLAMACPP_ALIASES:
assert models_normalize(alias) in LLAMACPP_ALIASES
else:
assert models_normalize(alias) == "custom"