feat(cli): add list_picker_providers for credential-filtered picker

The Telegram/Discord /model pickers currently call
list_authenticated_providers(), which returns every provider whose
credentials resolve locally and every model in its curated snapshot.
Two failure modes fall out:

- OpenRouter rows can include IDs the live catalog no longer carries.
- Provider rows can surface with zero callable models (e.g. a slug
  whose credential pool entry exists but has nothing behind it).

list_picker_providers() wraps the base function and post-processes the
result so the interactive picker only shows models the user can
actually select:

- OpenRouter's models come from fetch_openrouter_models() (live-catalog
  filtered against the curated OPENROUTER_MODELS snapshot).
- Rows with an empty models list are dropped, except custom endpoints
  (is_user_defined=True with an api_url) where the user may enter
  model ids manually.
- All other fields pass through unchanged.

The gateway /model handler switches to the new helper for the
interactive picker payload only. Typed /model <name> and the text
fallback list stay on list_authenticated_providers() so nothing is
hidden from power users or platforms without a picker.

Covered by nine focused unit tests in
tests/hermes_cli/test_list_picker_providers.py.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Traemond Anderson 2026-04-21 10:25:10 -04:00 committed by Teknium
parent cc2c820975
commit 60235dba5e
3 changed files with 274 additions and 1 deletions

View file

@ -7578,6 +7578,7 @@ class GatewayRunner:
from hermes_cli.model_switch import (
switch_model as _switch_model, parse_model_flags,
list_authenticated_providers,
list_picker_providers,
)
from hermes_cli.providers import get_label
@ -7632,7 +7633,7 @@ class GatewayRunner:
if has_picker:
try:
providers = list_authenticated_providers(
providers = list_picker_providers(
current_provider=current_provider,
current_base_url=current_base_url,
current_model=current_model,