mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-21 10:22:18 +00:00
fix(picker): remove max_models=50 cap in interactive model pickers
The interactive model pickers (Desktop REST API, TUI model.options, CLI /model) were hard-capped at max_models=50, which truncated large provider catalogs like Kilo Gateway (336 models) to just 50 entries. This made most models undiscoverable via the picker search box. Changes: - Change build_models_payload() default from max_models=50 to None (unlimited) - Change list_authenticated_providers() default from max_models=8 to None - Change list_picker_providers() default from max_models=8 to None - Fix all [:max_models] slicing to handle None as 'no limit' - Remove max_models=50 from 5 interactive picker callers: * web_server.py: get_model_options (Desktop /api/model/options) * web_server.py: get_recommended_default_model * model_switch.py: prewarm_picker_cache_async * tui_gateway/server.py: model.options JSON-RPC * cli.py: HermesCLI model picker - Telegram/Discord inline keyboard picker (gateway/slash_commands.py) still passes max_models=50 explicitly — unchanged behavior. The total_models field was already in the response payload and is now meaningful since models.length == total_models for interactive pickers. Fixes #48279
This commit is contained in:
parent
4ed2f33994
commit
9705e7944a
6 changed files with 37 additions and 12 deletions
2
cli.py
2
cli.py
|
|
@ -6971,7 +6971,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
|
|||
try:
|
||||
if ctx is None:
|
||||
raise RuntimeError("inventory context unavailable")
|
||||
providers = build_models_payload(ctx, max_models=50)["providers"]
|
||||
providers = build_models_payload(ctx)["providers"]
|
||||
except Exception:
|
||||
providers = []
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ def build_models_payload(
|
|||
pricing: bool = False,
|
||||
capabilities: bool = False,
|
||||
force_fresh_nous_tier: bool = False,
|
||||
max_models: int = 50,
|
||||
max_models: int | None = None,
|
||||
) -> dict:
|
||||
"""Build the ``{providers, model, provider}`` shape every consumer
|
||||
needs from a single substrate call.
|
||||
|
|
|
|||
|
|
@ -1188,7 +1188,6 @@ def prewarm_picker_cache_async() -> Optional["_threading.Thread"]:
|
|||
current_model=ctx.current_model,
|
||||
user_providers=ctx.user_providers,
|
||||
custom_providers=ctx.custom_providers,
|
||||
max_models=50,
|
||||
)
|
||||
except Exception:
|
||||
# Best-effort warmup — never surface errors into the session.
|
||||
|
|
@ -1206,7 +1205,7 @@ def list_authenticated_providers(
|
|||
custom_providers: list | None = None,
|
||||
*,
|
||||
force_fresh_nous_tier: bool = False,
|
||||
max_models: int = 8,
|
||||
max_models: int | None = None,
|
||||
current_model: str = "",
|
||||
) -> List[dict]:
|
||||
"""Detect which providers have credentials and list their curated models.
|
||||
|
|
@ -1426,7 +1425,7 @@ def list_authenticated_providers(
|
|||
if hermes_id in _MODELS_DEV_PREFERRED:
|
||||
model_ids = _merge_with_models_dev(hermes_id, model_ids)
|
||||
total = len(model_ids)
|
||||
top = model_ids[:max_models]
|
||||
top = model_ids[:max_models] if max_models else model_ids
|
||||
|
||||
slug = hermes_id
|
||||
pinfo = _mdev_pinfo(mdev_id)
|
||||
|
|
@ -1589,7 +1588,7 @@ def list_authenticated_providers(
|
|||
if hermes_slug in _MODELS_DEV_PREFERRED:
|
||||
model_ids = _merge_with_models_dev(hermes_slug, model_ids)
|
||||
total = len(model_ids)
|
||||
top = model_ids[:max_models]
|
||||
top = model_ids[:max_models] if max_models else model_ids
|
||||
|
||||
results.append({
|
||||
"slug": hermes_slug,
|
||||
|
|
@ -1664,7 +1663,7 @@ def list_authenticated_providers(
|
|||
if not _cp_model_ids:
|
||||
_cp_model_ids = curated.get(_cp.slug, [])
|
||||
_cp_total = len(_cp_model_ids)
|
||||
_cp_top = _cp_model_ids[:max_models]
|
||||
_cp_top = _cp_model_ids[:max_models] if max_models else _cp_model_ids
|
||||
|
||||
results.append({
|
||||
"slug": _cp.slug,
|
||||
|
|
@ -2040,7 +2039,7 @@ def list_picker_providers(
|
|||
current_base_url: str = "",
|
||||
user_providers: dict = None,
|
||||
custom_providers: list | None = None,
|
||||
max_models: int = 8,
|
||||
max_models: int | None = None,
|
||||
current_model: str = "",
|
||||
) -> List[dict]:
|
||||
"""Interactive-picker variant of :func:`list_authenticated_providers`.
|
||||
|
|
@ -2083,7 +2082,7 @@ def list_picker_providers(
|
|||
except Exception:
|
||||
live_ids = list(p.get("models", []))
|
||||
p = dict(p)
|
||||
p["models"] = live_ids[:max_models]
|
||||
p["models"] = live_ids[:max_models] if max_models else live_ids
|
||||
p["total_models"] = len(live_ids)
|
||||
|
||||
has_models = bool(p.get("models"))
|
||||
|
|
|
|||
|
|
@ -3323,7 +3323,6 @@ def get_model_options(profile: Optional[str] = None):
|
|||
with _profile_scope(profile):
|
||||
return build_models_payload(
|
||||
load_picker_context(),
|
||||
max_models=50,
|
||||
include_unconfigured=True,
|
||||
picker_hints=True,
|
||||
canonical_order=True,
|
||||
|
|
@ -3398,7 +3397,7 @@ def get_recommended_default_model(provider: str = ""):
|
|||
try:
|
||||
from hermes_cli.inventory import build_models_payload, load_picker_context
|
||||
|
||||
payload = build_models_payload(load_picker_context(), max_models=50)
|
||||
payload = build_models_payload(load_picker_context())
|
||||
for row in payload.get("providers", []):
|
||||
if str(row.get("slug", "")).lower() == slug:
|
||||
models = row.get("models") or []
|
||||
|
|
|
|||
|
|
@ -660,3 +660,31 @@ def test_two_custom_providers_with_overlap_both_survive():
|
|||
assert a_row["total_models"] == 2
|
||||
assert b_row["total_models"] == 2
|
||||
|
||||
|
||||
def test_build_models_payload_no_max_models_returns_full_list():
|
||||
"""When max_models is not passed (None), build_models_payload must
|
||||
return the full model list — not truncate to the old default of 50.
|
||||
Regression for #48279: Kilo Gateway picker was capped at 50 of 336
|
||||
models, making most models undiscoverable via search."""
|
||||
full_models = [f"model-{i}" for i in range(100)]
|
||||
rows = [
|
||||
{
|
||||
"slug": "kilocode",
|
||||
"name": "Kilo Code",
|
||||
"models": full_models,
|
||||
"total_models": len(full_models),
|
||||
"is_current": False,
|
||||
"is_user_defined": False,
|
||||
"source": "built-in",
|
||||
},
|
||||
]
|
||||
ctx = _empty_ctx()
|
||||
with _list_auth_returning(rows):
|
||||
# No max_models argument — should return all 100 models
|
||||
payload = build_models_payload(ctx)
|
||||
|
||||
kilo_row = next(r for r in payload["providers"] if r["slug"] == "kilocode")
|
||||
assert kilo_row["models"] == full_models
|
||||
assert kilo_row["total_models"] == 100
|
||||
assert len(kilo_row["models"]) == 100
|
||||
|
||||
|
|
|
|||
|
|
@ -9496,7 +9496,6 @@ def _(rid, params: dict) -> dict:
|
|||
canonical_order=True,
|
||||
pricing=True,
|
||||
capabilities=True,
|
||||
max_models=50,
|
||||
)
|
||||
return _ok(rid, payload)
|
||||
except Exception as e:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue