From 70f7fa05caf880ba3ae2bac4e13655cfde1dfca5 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Thu, 24 Sep 2026 23:13:53 -0500 Subject: [PATCH] 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. --- hermes_cli/models_catalog_static.py | 7 ++-- hermes_cli/providers.py | 2 +- .../test_local_provider_alias_parity.py | 34 ++++++++----------- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/hermes_cli/models_catalog_static.py b/hermes_cli/models_catalog_static.py index c73fcd5145..c196ed9bdd 100644 --- a/hermes_cli/models_catalog_static.py +++ b/hermes_cli/models_catalog_static.py @@ -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"), )) diff --git a/hermes_cli/providers.py b/hermes_cli/providers.py index 302d56ea80..6329cbc6f7 100644 --- a/hermes_cli/providers.py +++ b/hermes_cli/providers.py @@ -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+)", } diff --git a/tests/hermes_cli/test_local_provider_alias_parity.py b/tests/hermes_cli/test_local_provider_alias_parity.py index 31715874c3..4d2fc4700a 100644 --- a/tests/hermes_cli/test_local_provider_alias_parity.py +++ b/tests/hermes_cli/test_local_provider_alias_parity.py @@ -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"