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_cloud", "ollama-cloud"),
# Local OpenAI-compatible servers route through the generic "custom" provider
# (parity with hermes_cli.auth and hermes_cli.providers). Issue #62213.
("local", "custom"), ("vllm", "custom"), ("llamacpp", "custom"),
("llama.cpp", "custom"), ("llama-cpp", "custom"),
# (parity with hermes_cli.auth and hermes_cli.providers). Issue #62213. The llamacpp
# aliases stay unmapped: they are the managed local runtime's picker id, and the model
# 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",
"upstage": "Upstage Solar", "actual": "Actual Computer", "tencent-tokenhub": "Tencent TokenHub",
"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+)",
}

View File

@@ -8,33 +8,29 @@ different table:
* ``hermes_cli.auth.resolve_provider`` (credential resolution)
Historically these disagreed for the local self-hosted server aliases: bare
``vllm`` / ``llamacpp`` resolved to ``"local"`` in ``providers`` (an orphan id
with no ``ProviderDef``), stayed ``"vllm"`` in ``models`` (unknown), yet mapped
to ``"custom"`` in ``auth`` — the "custom, local, custom:local" confusion the
bug report describes. They must all agree on the generic ``"custom"`` provider.
``local`` stayed ``"local"`` in ``providers`` and ``models`` while ``auth`` mapped
it to ``"custom"``, and ``vllm`` got three answers (``local`` / ``vllm`` /
``custom``) — the "custom, local, custom:local" confusion the bug report
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
from hermes_cli.auth import resolve_provider
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.
#
# ``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")
_CUSTOM_ALIASES = tuple(get_provider_profile("custom").aliases)
@pytest.mark.parametrize("alias", _LOCAL_ALIASES)
def test_local_aliases_normalize_to_custom_in_every_table(alias):
@pytest.mark.parametrize("alias", _CUSTOM_ALIASES)
def test_custom_profile_aliases_normalize_to_custom_in_every_table(alias):
assert providers_normalize(alias) == "custom"
assert models_normalize(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"