Skip to content

fix: limit desktop model pickers to explicit providers (#56974) - #60514

Merged
teknium1 merged 3 commits into
mainfrom
hermes/hermes-7b86f902
Jul 7, 2026
Merged

fix: limit desktop model pickers to explicit providers (#56974)#60514
teknium1 merged 3 commits into
mainfrom
hermes/hermes-7b86f902

Conversation

@teknium1

@teknium1 teknium1 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Desktop chat model pickers now list only providers the user explicitly configured — ambient credentials (a GitHub CLI login surfacing Copilot, stale auth.json pool entries, residual provider state) no longer leak unconfigured providers into the picker, and switching to one of those phantom providers no longer fails and snaps back to the previous model.

Salvage of #56966 by @rarf (authorship preserved via cherry-pick), rebased onto current main, plus follow-up hardening.

Fixes #56974. Also addresses the stale-pool half of #55790 and the picker-clutter asks in #59483 / #57886 / #59733.

Root cause

list_authenticated_providers() treats any discoverable credential record as "authenticated": an env-seeded credential_pool entry whose env var no longer resolves, a gh auth token login auto-seeded as a Copilot credential, or a stub left in auth.json by an abandoned setup. The desktop chat picker rendered all of them as selectable providers; picking one failed at switch time (Could not resolve credentials for provider ...) and the optimistic UI rolled back — the "model swaps back to the original" report.

Changes

  • hermes_cli/inventory.py: new explicit_only flag on build_models_payload() + _filter_explicit_provider_rows() — keeps rows for the current provider, user-defined endpoints, and providers passing is_provider_explicitly_configured().
  • hermes_cli/auth.py: is_provider_explicitly_configured() gains a credential-pool check that counts explicit Hermes flows (manual add, device-code, PKCE) and env-seeded entries — but an env-seeded entry only counts while its env var still resolves to a usable secret, so stale auth.json records left after key removal no longer mark a provider configured ([Bug]: Stale credential pool entries cause removed providers to persist in model picker #55790). Ambient sources (gh_cli, claude_code) are excluded.
  • tui_gateway/server.py model.options + web_server.py /api/model/options: accept explicit_only / include_unconfigured params; desktop chat surfaces request explicit_only, onboarding keeps the full universe.
  • Desktop: chat picker, composer model menu, visibility dialog request explicit_only: true (routed through the shared requestModelOptions() helper added on main after the PR branched); onboarding flows opt into includeUnconfigured.
  • TUI modelPicker.tsx + dashboard ModelPickerDialog.tsx / api.getModelOptions(): pass include_unconfigured: true explicitly, preserving their full-universe setup-affordance behavior unchanged.
  • Tests: backend coverage for the filter and both RPC/REST param paths; regression tests for ambient vs explicit pool sources and stale vs live env-seeded entries.

Validation

Check Result
scripts/run_tests.sh — inventory, auth gate, tui_gateway, web_server, opencode-go picker (5 files) 392 passed, 0 failed
E2E (real HERMES_HOME with ambient gh_cli Copilot + stale anthropic pool entry) explicit_only: copilot/opencode-go/anthropic filtered, env-backed providers kept; opt-in path: full 39-row universe intact
web/src/lib/api.test.ts 2 passed
ruff + windows-footguns on touched Python clean

Infographic

PR infographic

rarf and others added 3 commits July 7, 2026 14:16
…+ non-desktop picker opt-ins

Follow-up on the #56966 salvage:

- is_provider_explicitly_configured(): an env-seeded credential-pool entry
  only counts as explicit while its env var still resolves to a usable
  secret. A stale auth.json entry left behind after the user deletes the
  var no longer keeps the provider in the picker forever (#55790).
- TUI modelPicker + dashboard ModelPickerDialog/api.getModelOptions pass
  include_unconfigured=true explicitly, preserving their full-universe
  setup-affordance behavior now that the backend defaults to the
  configured subset.
- desktop lib/model-options.ts routes explicit_only through the shared
  requestModelOptions() helper (added on main after the PR branched).
- regression tests for ambient (gh_cli) pool sources, explicit manual/
  device-code sources, and stale vs live env-seeded entries.
@alt-glitch alt-glitch added type/bug Something isn't working comp/desktop Electron desktop app (apps/desktop/*) comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery area/auth Authentication, OAuth, credential pools P3 Low — cosmetic, nice to have labels Jul 7, 2026
@teknium1
teknium1 merged commit f304f41 into main Jul 7, 2026
36 checks passed
@teknium1
teknium1 deleted the hermes/hermes-7b86f902 branch July 7, 2026 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Desktop chat model picker shows implicitly discovered providers as if they were configured

3 participants