mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix: include custom_providers in /model command listings and resolution
Custom providers defined in config.yaml under were completely invisible to the /model command in both gateway (Telegram, Discord, etc.) and CLI. The provider listing skipped them and explicit switching via --provider failed with "Unknown provider". Root cause: gateway/run.py, cli.py, and model_switch.py only read the dict from config, ignoring entirely. Changes: - providers.py: add resolve_custom_provider() and extend resolve_provider_full() to check custom_providers after user_providers - model_switch.py: propagate custom_providers through switch_model(), list_authenticated_providers(), and get_authenticated_provider_slugs(); add custom provider section to provider listings - gateway/run.py: read custom_providers from config, pass to all model-switch calls - cli.py: hoist config loading, pass custom_providers to listing and switch calls Tests: 4 new regression tests covering listing, resolution, and gateway command handler. All 71 tests pass.
This commit is contained in:
parent
7d426e6536
commit
a2f46e4665
6 changed files with 294 additions and 10 deletions
104
tests/hermes_cli/test_model_switch_custom_providers.py
Normal file
104
tests/hermes_cli/test_model_switch_custom_providers.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
"""Regression tests for /model support of config.yaml custom_providers.
|
||||
|
||||
The terminal `hermes model` flow already exposes `custom_providers`, but the
|
||||
shared slash-command pipeline (`/model` in CLI/gateway/Telegram) historically
|
||||
only looked at `providers:`.
|
||||
"""
|
||||
|
||||
import hermes_cli.providers as providers_mod
|
||||
from hermes_cli.model_switch import list_authenticated_providers, switch_model
|
||||
from hermes_cli.providers import resolve_provider_full
|
||||
|
||||
|
||||
_MOCK_VALIDATION = {
|
||||
"accepted": True,
|
||||
"persist": True,
|
||||
"recognized": True,
|
||||
"message": None,
|
||||
}
|
||||
|
||||
|
||||
def test_list_authenticated_providers_includes_custom_providers(monkeypatch):
|
||||
"""No-args /model menus should include saved custom_providers entries."""
|
||||
monkeypatch.setattr("agent.models_dev.fetch_models_dev", lambda: {})
|
||||
monkeypatch.setattr(providers_mod, "HERMES_OVERLAYS", {})
|
||||
|
||||
providers = list_authenticated_providers(
|
||||
current_provider="openai-codex",
|
||||
user_providers={},
|
||||
custom_providers=[
|
||||
{
|
||||
"name": "Local (127.0.0.1:4141)",
|
||||
"base_url": "http://127.0.0.1:4141/v1",
|
||||
"model": "rotator-openrouter-coding",
|
||||
}
|
||||
],
|
||||
max_models=50,
|
||||
)
|
||||
|
||||
assert any(
|
||||
p["slug"] == "custom:local-(127.0.0.1:4141)"
|
||||
and p["name"] == "Local (127.0.0.1:4141)"
|
||||
and p["models"] == ["rotator-openrouter-coding"]
|
||||
and p["api_url"] == "http://127.0.0.1:4141/v1"
|
||||
for p in providers
|
||||
)
|
||||
|
||||
|
||||
def test_resolve_provider_full_finds_named_custom_provider():
|
||||
"""Explicit /model --provider should resolve saved custom_providers entries."""
|
||||
resolved = resolve_provider_full(
|
||||
"custom:local-(127.0.0.1:4141)",
|
||||
user_providers={},
|
||||
custom_providers=[
|
||||
{
|
||||
"name": "Local (127.0.0.1:4141)",
|
||||
"base_url": "http://127.0.0.1:4141/v1",
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
assert resolved is not None
|
||||
assert resolved.id == "custom:local-(127.0.0.1:4141)"
|
||||
assert resolved.name == "Local (127.0.0.1:4141)"
|
||||
assert resolved.base_url == "http://127.0.0.1:4141/v1"
|
||||
assert resolved.source == "user-config"
|
||||
|
||||
|
||||
def test_switch_model_accepts_explicit_named_custom_provider(monkeypatch):
|
||||
"""Shared /model switch pipeline should accept --provider for custom_providers."""
|
||||
monkeypatch.setattr(
|
||||
"hermes_cli.runtime_provider.resolve_runtime_provider",
|
||||
lambda requested: {
|
||||
"api_key": "no-key-required",
|
||||
"base_url": "http://127.0.0.1:4141/v1",
|
||||
"api_mode": "chat_completions",
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr("hermes_cli.models.validate_requested_model", lambda *a, **k: _MOCK_VALIDATION)
|
||||
monkeypatch.setattr("hermes_cli.model_switch.get_model_info", lambda *a, **k: None)
|
||||
monkeypatch.setattr("hermes_cli.model_switch.get_model_capabilities", lambda *a, **k: None)
|
||||
|
||||
result = switch_model(
|
||||
raw_input="rotator-openrouter-coding",
|
||||
current_provider="openai-codex",
|
||||
current_model="gpt-5.4",
|
||||
current_base_url="https://chatgpt.com/backend-api/codex",
|
||||
current_api_key="",
|
||||
explicit_provider="custom:local-(127.0.0.1:4141)",
|
||||
user_providers={},
|
||||
custom_providers=[
|
||||
{
|
||||
"name": "Local (127.0.0.1:4141)",
|
||||
"base_url": "http://127.0.0.1:4141/v1",
|
||||
"model": "rotator-openrouter-coding",
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
assert result.target_provider == "custom:local-(127.0.0.1:4141)"
|
||||
assert result.provider_label == "Local (127.0.0.1:4141)"
|
||||
assert result.new_model == "rotator-openrouter-coding"
|
||||
assert result.base_url == "http://127.0.0.1:4141/v1"
|
||||
assert result.api_key == "no-key-required"
|
||||
Loading…
Add table
Add a link
Reference in a new issue