diff --git a/hermes_cli/providers.py b/hermes_cli/providers.py index 999d78815d..6754b3f58e 100644 --- a/hermes_cli/providers.py +++ b/hermes_cli/providers.py @@ -525,6 +525,31 @@ def get_provider(name: str, *, allow_network: bool = True) -> Optional[ProviderD source="hermes", ) + # Plugin-registered provider profiles (plugins/model-providers//). + # Providers that ship only as plugin profiles (e.g. commandcode, + # tencent-tokenhub) are absent from models.dev and HERMES_OVERLAYS, so + # without this fallback they resolve as "Unknown provider" in /model, + # --provider, and the model-switch path even though the picker lists them + # (CANONICAL_PROVIDERS auto-extends from the same plugin registry). + try: + from providers import get_provider_profile as _profile + + _prof = _profile(canonical) + if _prof is not None: + _api_mode_to_transport = {v: k for k, v in TRANSPORT_TO_API_MODE.items()} + _transport = _api_mode_to_transport.get(_prof.api_mode, "openai_chat") + return ProviderDef( + id=canonical, + name=_prof.display_name or _prof.name or canonical, + transport=_transport, + api_key_env_vars=tuple(_prof.env_vars or ()), + base_url=_prof.base_url or "", + auth_type=_prof.auth_type or "api_key", + source="plugin-profile", + ) + except Exception: + pass + return None diff --git a/tests/plugins/model_providers/test_commandcode_profile.py b/tests/plugins/model_providers/test_commandcode_profile.py index 300e7a3d01..a2ce05fd74 100644 --- a/tests/plugins/model_providers/test_commandcode_profile.py +++ b/tests/plugins/model_providers/test_commandcode_profile.py @@ -256,3 +256,22 @@ class TestCommandCodeFetchModelsPickerContract: profile = providers.get_provider_profile(profile_name) assert profile is not None assert "base_url" in inspect.signature(profile.fetch_models).parameters + + def test_resolve_provider_full(self): + """Both profiles must resolve through the model-switch path. + + Regression: ``resolve_provider_full`` only knew models.dev + overlay + providers, so plugin-only providers (commandcode) failed with + "Unknown provider" on /model switches even though the picker listed + them. + """ + from hermes_cli.providers import resolve_provider_full + + chat = resolve_provider_full("commandcode", {}, []) + assert chat is not None and chat.id == "commandcode" + assert chat.transport == "openai_chat" + assert "COMMANDCODE_API_KEY" in chat.api_key_env_vars + + anth = resolve_provider_full("commandcode-anthropic", {}, []) + assert anth is not None and anth.id == "commandcode-anthropic" + assert anth.transport == "anthropic_messages"