Skip to content

Commit d59b79f

Browse files
austinpickettoppih
andauthored
fix(model-picker): show exhausted-pool providers in interactive /model picker (NousResearch#66584)
Salvages NousResearch#66257 by @oppih (CI attribution check blocked the external branch from merging). When a provider's credential pool has entries but all are temporarily rate-limited (exhausted), list_authenticated_providers() excluded the provider from the interactive /model picker. Rate limits are per-model for many providers (e.g. Google Gemini), so an exhausted key for model-A may still work for model-B — the user should still be able to select a different model under the same provider. Adds a for_picker flag to list_authenticated_providers() that relaxes the credential-pool availability check for the picker path only, falling back to pool.has_credentials() when the pool has entries but none are currently available. The runtime resolution path (get_authenticated_provider_slugs) is unchanged, preserving the NousResearch#45759 invariant that exhausted pools do not count as authenticated. Co-authored-by: oppih <oppih@users.noreply.github.com>
1 parent 5122ddd commit d59b79f

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

hermes_cli/model_switch.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,7 @@ def list_authenticated_providers(
14961496
refresh: bool = False,
14971497
probe_custom_providers: bool = True,
14981498
probe_current_custom_provider: bool = False,
1499+
for_picker: bool = False,
14991500
) -> List[dict]:
15001501
"""Detect which providers have credentials and list their curated models.
15011502
@@ -1843,6 +1844,20 @@ def _has_aws_sdk_creds_for_listing(slug: str) -> bool:
18431844
try:
18441845
if _credential_pool_is_usable(hermes_slug):
18451846
has_creds = True
1847+
elif for_picker:
1848+
# For the interactive /model picker, also show providers
1849+
# whose credential pool has entries but all are temporarily
1850+
# rate-limited. Rate limits are per-model for many
1851+
# providers (e.g. Google Gemini) — switching to a different
1852+
# model under the same provider may work even when all keys
1853+
# are in cooldown.
1854+
try:
1855+
from agent.credential_pool import load_pool
1856+
_pool = load_pool(hermes_slug)
1857+
if _pool.has_credentials():
1858+
has_creds = True
1859+
except Exception:
1860+
pass
18461861
except Exception as exc:
18471862
logger.debug("Credential pool check failed for %s: %s", hermes_slug, exc)
18481863
# Fallback: check external credential files directly.
@@ -2488,6 +2503,7 @@ def list_picker_providers(
24882503
custom_providers=custom_providers,
24892504
max_models=max_models,
24902505
current_model=current_model,
2506+
for_picker=True,
24912507
)
24922508
if include_moa:
24932509
providers = _prepend_moa_picker_provider(providers, current_provider=current_provider)

tests/hermes_cli/test_authenticated_providers_exhausted_pool.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,22 @@ def test_opaque_legacy_pool_value_stays_visible(monkeypatch):
9595
)
9696

9797
assert _credential_pool_is_usable("opencode-go", raw_pool_present=True)
98+
99+
100+
def test_picker_shows_exhausted_pool_provider(monkeypatch):
101+
"""The interactive picker must include providers whose credential pool
102+
entries are all exhausted, so the user can still switch to a different
103+
model under the same provider."""
104+
from hermes_cli.model_switch import list_picker_providers
105+
106+
_patch_opencode_pool(monkeypatch, available=False)
107+
providers = list_picker_providers(
108+
current_provider="alibaba",
109+
user_providers={},
110+
custom_providers=[],
111+
)
112+
slugs = [p["slug"] for p in providers]
113+
assert "opencode-go" in slugs, (
114+
"Picker must show exhausted-pool providers so the user can select "
115+
"a different model under the same provider"
116+
)

0 commit comments

Comments
 (0)