diff --git a/hermes_cli/model_switch.py b/hermes_cli/model_switch.py index d0071c7489ad..f83089b83853 100644 --- a/hermes_cli/model_switch.py +++ b/hermes_cli/model_switch.py @@ -1496,6 +1496,7 @@ def list_authenticated_providers( refresh: bool = False, probe_custom_providers: bool = True, probe_current_custom_provider: bool = False, + for_picker: bool = False, ) -> List[dict]: """Detect which providers have credentials and list their curated models. @@ -1843,6 +1844,20 @@ def list_authenticated_providers( try: if _credential_pool_is_usable(hermes_slug): has_creds = True + elif for_picker: + # For the interactive /model picker, also show providers + # whose credential pool has entries but all are temporarily + # rate-limited. Rate limits are per-model for many + # providers (e.g. Google Gemini) — switching to a different + # model under the same provider may work even when all keys + # are in cooldown. + try: + from agent.credential_pool import load_pool + _pool = load_pool(hermes_slug) + if _pool.has_credentials(): + has_creds = True + except Exception: + pass except Exception as exc: logger.debug("Credential pool check failed for %s: %s", hermes_slug, exc) # Fallback: check external credential files directly. @@ -2488,6 +2503,7 @@ def list_picker_providers( custom_providers=custom_providers, max_models=max_models, current_model=current_model, + for_picker=True, ) if include_moa: providers = _prepend_moa_picker_provider(providers, current_provider=current_provider) diff --git a/tests/hermes_cli/test_authenticated_providers_exhausted_pool.py b/tests/hermes_cli/test_authenticated_providers_exhausted_pool.py index eeb1a44056c3..988de9c72f10 100644 --- a/tests/hermes_cli/test_authenticated_providers_exhausted_pool.py +++ b/tests/hermes_cli/test_authenticated_providers_exhausted_pool.py @@ -95,3 +95,22 @@ def test_opaque_legacy_pool_value_stays_visible(monkeypatch): ) assert _credential_pool_is_usable("opencode-go", raw_pool_present=True) + + +def test_picker_shows_exhausted_pool_provider(monkeypatch): + """The interactive picker must include providers whose credential pool + entries are all exhausted, so the user can still switch to a different + model under the same provider.""" + from hermes_cli.model_switch import list_picker_providers + + _patch_opencode_pool(monkeypatch, available=False) + providers = list_picker_providers( + current_provider="alibaba", + user_providers={}, + custom_providers=[], + ) + slugs = [p["slug"] for p in providers] + assert "opencode-go" in slugs, ( + "Picker must show exhausted-pool providers so the user can select " + "a different model under the same provider" + )