mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-15 14:22:43 +00:00
fix(model): probe no-key custom provider catalogs
This commit is contained in:
parent
46cf87be16
commit
5f00f36ba9
2 changed files with 53 additions and 6 deletions
|
|
@ -2213,6 +2213,7 @@ def list_authenticated_providers(
|
|||
"api_url": api_url,
|
||||
"api_key": api_key,
|
||||
"models": [],
|
||||
"has_explicit_models": False,
|
||||
"discover_models": discover,
|
||||
"extra_headers": entry_extra_headers,
|
||||
}
|
||||
|
|
@ -2238,6 +2239,7 @@ def list_authenticated_providers(
|
|||
for model_id in _declared_model_ids(entry.get("models", {})):
|
||||
if model_id not in groups[group_key]["models"]:
|
||||
groups[group_key]["models"].append(model_id)
|
||||
groups[group_key]["has_explicit_models"] = True
|
||||
|
||||
_section4_emitted_slugs: set = set()
|
||||
_current_base_url_group_count = sum(
|
||||
|
|
@ -2298,11 +2300,13 @@ def list_authenticated_providers(
|
|||
# the (possibly partial) ``models:`` subset configured for
|
||||
# context-length overrides with the full live catalog.
|
||||
# This is the Bifrost / aggregator-gateway case.
|
||||
# - Without an api_key but with an explicit ``models:`` list
|
||||
# (or top-level ``model:``), the user is narrowing a public
|
||||
# endpoint to a specific subset (e.g. ollama.com /v1/models
|
||||
# returns 35 models but the user only wants 4). Preserve the
|
||||
# explicit list and skip live discovery.
|
||||
# - Without an api_key but with an explicit ``models:`` list,
|
||||
# the user is narrowing a public endpoint to a specific subset
|
||||
# (e.g. ollama.com /v1/models returns 35 models but the user
|
||||
# only wants 4). Preserve the explicit list and skip live
|
||||
# discovery. The singular ``model:`` field is only the current
|
||||
# active selection and must not suppress discovery on local
|
||||
# no-key endpoints.
|
||||
# - Without an api_key AND no explicit models, fall through to
|
||||
# live discovery so bare-endpoint custom providers (local
|
||||
# llama.cpp / Ollama servers) still appear populated.
|
||||
|
|
@ -2320,7 +2324,7 @@ def list_authenticated_providers(
|
|||
should_probe = (
|
||||
_can_probe_custom_provider(row_is_current=_grp_is_current)
|
||||
and bool(api_url)
|
||||
and (bool(api_key) or not grp["models"])
|
||||
and (bool(api_key) or not grp.get("has_explicit_models"))
|
||||
and grp.get("discover_models", True)
|
||||
)
|
||||
if should_probe:
|
||||
|
|
|
|||
|
|
@ -5,11 +5,18 @@ shared slash-command pipeline (`/model` in CLI/gateway/Telegram) historically
|
|||
only looked at `providers:`.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
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
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _no_live_custom_provider_model_fetch(monkeypatch):
|
||||
monkeypatch.setattr("hermes_cli.models.fetch_api_models", lambda *args, **kwargs: [])
|
||||
|
||||
|
||||
_MOCK_VALIDATION = {
|
||||
"accepted": True,
|
||||
"persist": True,
|
||||
|
|
@ -329,6 +336,42 @@ def test_list_deduplicates_same_model_in_group(monkeypatch):
|
|||
assert my_rows[0]["total_models"] == 2
|
||||
|
||||
|
||||
def test_custom_provider_no_key_singular_model_still_probes_live_models(monkeypatch):
|
||||
"""A singular ``model:`` is the active selection, not an explicit catalog.
|
||||
|
||||
No-key local endpoints such as Ollama and llama.cpp should still be probed
|
||||
so /model matches the terminal ``hermes model`` flow.
|
||||
"""
|
||||
monkeypatch.setattr("agent.models_dev.fetch_models_dev", lambda: {})
|
||||
monkeypatch.setattr(providers_mod, "HERMES_OVERLAYS", {})
|
||||
|
||||
calls = []
|
||||
|
||||
def fake_fetch_api_models(api_key, base_url, **kwargs):
|
||||
calls.append((api_key, base_url, kwargs))
|
||||
return ["llama3", "mistral", "qwen3-coder"]
|
||||
|
||||
monkeypatch.setattr("hermes_cli.models.fetch_api_models", fake_fetch_api_models)
|
||||
|
||||
providers = list_authenticated_providers(
|
||||
current_provider="openai-codex",
|
||||
user_providers={},
|
||||
custom_providers=[
|
||||
{
|
||||
"name": "Local Ollama",
|
||||
"base_url": "http://localhost:11434/v1",
|
||||
"model": "llama3",
|
||||
}
|
||||
],
|
||||
max_models=50,
|
||||
)
|
||||
|
||||
assert calls == [("", "http://localhost:11434/v1", {"headers": None})]
|
||||
row = next(p for p in providers if p["name"] == "Local Ollama")
|
||||
assert row["models"] == ["llama3", "mistral", "qwen3-coder"]
|
||||
assert row["total_models"] == 3
|
||||
|
||||
|
||||
def test_list_enumerates_dict_format_models_alongside_default(monkeypatch):
|
||||
"""custom_providers entry with dict-format ``models:`` plus singular
|
||||
``model:`` should surface the default and every dict key.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue