fix(providers): resolve plugin-registered provider profiles in get_provider

Plugin-only providers (commandcode, tencent-tokenhub, ...) are absent from
models.dev and HERMES_OVERLAYS, so resolve_provider_full returned None and
/model switches failed with "Unknown provider ..." even though the picker
lists them (CANONICAL_PROVIDERS auto-extends from the same registry).

Fall back to providers.get_provider_profile() before giving up, mapping the
profile api_mode to the ProviderDef transport.
This commit is contained in:
greyvito
2026-08-18 09:10:36 +07:00
committed by Teknium
parent f5ea3fa9cb
commit 7072fc4f87
2 changed files with 44 additions and 0 deletions

View File

@@ -525,6 +525,31 @@ def get_provider(name: str, *, allow_network: bool = True) -> Optional[ProviderD
source="hermes",
)
# Plugin-registered provider profiles (plugins/model-providers/<name>/).
# 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

View File

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