Skip to content

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

Closed
Tkander1715 wants to merge 1 commit into
NousResearch:mainfrom
Tkander1715:feat/telegram-picker-credential-filter
Closed

feat(cli): add list_picker_providers for credential-filtered picker#13561
Tkander1715 wants to merge 1 commit into
NousResearch:mainfrom
Tkander1715:feat/telegram-picker-credential-filter

Conversation

@Tkander1715
Copy link
Copy Markdown

What

Adds list_picker_providers() — a thin wrapper around list_authenticated_providers() that post-processes the result so the interactive /model picker (Telegram, Discord) only surfaces models the user can actually call. _handle_model_command() in gateway/run.py switches to the new helper for the interactive picker payload only.

Why

Two failure modes today when a user opens /model:

  1. Stale OpenRouter IDsOPENROUTER_MODELS is a static snapshot. When OpenRouter drops or renames a model upstream between Hermes releases, the picker still offers it; tapping it fails at call time.
  2. Empty provider rows — a credential-pool slug can exist with no actual key material behind it (e.g. leftover from a prior provider that's been env-wiped). The picker shows the row, the user taps, nothing happens.

The filter fixes both without changing list_authenticated_providers(), which is also consumed by the CLI text fallback where the unfiltered view is arguably still the right default.

How it works

  • For the openrouter row, models are replaced with the output of fetch_openrouter_models(), which already cross-checks the curated snapshot against the live OpenRouter catalog.
  • 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.

Typed /model <name> and the text fallback list stay on list_authenticated_providers(), so nothing is hidden from power users or platforms without an interactive picker.

How to test

pytest tests/hermes_cli/test_list_picker_providers.py -v

Nine focused unit tests covering:

  • OpenRouter models replaced with live catalog
  • Fallback to base models when the live fetch raises
  • Empty live catalog drops the OpenRouter row
  • Non-OpenRouter rows passed through unchanged
  • Empty models row dropped
  • Custom endpoint with api_url kept when models empty
  • User-defined row without api_url and empty models dropped
  • max_models caps OpenRouter live output
  • All kwargs forwarded to the base function

Manual test: open /model in Telegram with a setup that exercises each branch — OpenRouter + a direct provider + a user-defined custom endpoint.

Platforms tested

  • macOS (Darwin 25.4.0, Python 3.11)

Notes

  • No config/schema changes, no new dependencies, no migration path.
  • The branch is based on an older main (fork was behind by ~800 commits and syncing required a workflow OAuth scope I didn't have). The three files touched cherry-picked onto current main cleanly in my local worktree — happy to rebase on request.

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>
@alt-glitch alt-glitch added type/feature New feature or request comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery provider/openrouter OpenRouter aggregator labels Apr 21, 2026
@alt-glitch
Copy link
Copy Markdown
Collaborator

Related to #12655 (picker_providers config filter) and #3710 (interactive model picker feature).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery provider/openrouter OpenRouter aggregator type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants