mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-15 04:12:25 +00:00
fix(model_switch): live model discovery for custom_providers in /model picker
custom_providers entries (section 4 of list_authenticated_providers) only read the static models: dict from config.yaml, ignoring the live /v1/models endpoint. This means gateways like Bifrost that expose hundreds of models only show the handful explicitly listed in config. Add live discovery via fetch_api_models() for custom_providers entries that have api_key + base_url, matching the existing behavior for user providers: entries (section 3). When the endpoint is reachable and returns models, the live list replaces the static subset. Fixes: /model picker showing only 9 models from a Bifrost gateway that actually exposes 581.
This commit is contained in:
parent
4e27e4e05a
commit
abe5a3c937
2 changed files with 75 additions and 1 deletions
|
|
@ -1637,7 +1637,8 @@ def list_authenticated_providers(
|
||||||
groups[group_key]["models"].append(m)
|
groups[group_key]["models"].append(m)
|
||||||
|
|
||||||
_section4_emitted_slugs: set = set()
|
_section4_emitted_slugs: set = set()
|
||||||
for grp in groups.values():
|
for grp_key, grp in groups.items():
|
||||||
|
api_url, api_key = grp_key
|
||||||
slug = grp["slug"]
|
slug = grp["slug"]
|
||||||
# If the slug is already claimed by a built-in / overlay /
|
# If the slug is already claimed by a built-in / overlay /
|
||||||
# user-provider row (sections 1-3), skip this custom group
|
# user-provider row (sections 1-3), skip this custom group
|
||||||
|
|
@ -1675,6 +1676,18 @@ def list_authenticated_providers(
|
||||||
_grp_url_norm = _pair_key[1]
|
_grp_url_norm = _pair_key[1]
|
||||||
if _grp_url_norm and _grp_url_norm in _builtin_endpoints:
|
if _grp_url_norm and _grp_url_norm in _builtin_endpoints:
|
||||||
continue
|
continue
|
||||||
|
# Live model discovery from custom provider endpoints (matches
|
||||||
|
# Section 3 behavior for user ``providers:`` entries).
|
||||||
|
if api_url and api_key:
|
||||||
|
try:
|
||||||
|
from hermes_cli.models import fetch_api_models
|
||||||
|
|
||||||
|
live_models = fetch_api_models(api_key, api_url)
|
||||||
|
if live_models:
|
||||||
|
grp["models"] = live_models
|
||||||
|
grp["total_models"] = len(live_models)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
results.append({
|
results.append({
|
||||||
"slug": slug,
|
"slug": slug,
|
||||||
"name": grp["name"],
|
"name": grp["name"],
|
||||||
|
|
|
||||||
|
|
@ -506,3 +506,64 @@ def test_lmstudio_picker_skips_probe_when_not_configured(monkeypatch):
|
||||||
)
|
)
|
||||||
|
|
||||||
assert "base_url" not in captured
|
assert "base_url" not in captured
|
||||||
|
|
||||||
|
|
||||||
|
def test_custom_providers_uses_live_models_for_multi_model_endpoint(monkeypatch):
|
||||||
|
"""Custom providers with api_key + base_url should prefer live /models.
|
||||||
|
|
||||||
|
Custom providers (section 4 of list_authenticated_providers) point at
|
||||||
|
gateways like Bifrost that expose hundreds of models. Reading only the
|
||||||
|
static ``models:`` dict from config.yaml leaves the /model picker with
|
||||||
|
a stale subset. Live discovery fills the picker with all available
|
||||||
|
models from the endpoint.
|
||||||
|
"""
|
||||||
|
monkeypatch.setattr("agent.models_dev.fetch_models_dev", lambda: {})
|
||||||
|
monkeypatch.setattr("hermes_cli.providers.HERMES_OVERLAYS", {})
|
||||||
|
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
def fake_fetch_api_models(api_key, base_url):
|
||||||
|
calls.append((api_key, base_url))
|
||||||
|
return ["gateway-model-a", "gateway-model-b", "gateway-model-c"]
|
||||||
|
|
||||||
|
monkeypatch.setattr("hermes_cli.models.fetch_api_models", fake_fetch_api_models)
|
||||||
|
|
||||||
|
custom_providers = [
|
||||||
|
{
|
||||||
|
"name": "my-gateway",
|
||||||
|
"api_key": "sk-gateway-key",
|
||||||
|
"base_url": "https://gateway.example.com/v1",
|
||||||
|
"model": "gateway-model-a",
|
||||||
|
"models": {
|
||||||
|
"gateway-model-a": {"context_length": 128000},
|
||||||
|
"gateway-model-b": {"context_length": 128000},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
providers = list_authenticated_providers(
|
||||||
|
current_provider="openrouter",
|
||||||
|
current_base_url="https://openrouter.ai/api/v1",
|
||||||
|
custom_providers=custom_providers,
|
||||||
|
max_models=50,
|
||||||
|
)
|
||||||
|
|
||||||
|
gateway_prov = next(
|
||||||
|
(
|
||||||
|
p
|
||||||
|
for p in providers
|
||||||
|
if p.get("api_url") == "https://gateway.example.com/v1"
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert gateway_prov is not None, "Custom provider group not found in results"
|
||||||
|
assert calls == [("sk-gateway-key", "https://gateway.example.com/v1")], (
|
||||||
|
"fetch_api_models must be called with the custom provider's credentials"
|
||||||
|
)
|
||||||
|
assert gateway_prov["models"] == [
|
||||||
|
"gateway-model-a",
|
||||||
|
"gateway-model-b",
|
||||||
|
"gateway-model-c",
|
||||||
|
], "Live models must replace the static subset"
|
||||||
|
assert gateway_prov["total_models"] == 3
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue