hermes - ✅(Solved) Fix [Bug] /model switch does not load credential pool for new provider [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#25273Fetched 2026-05-14 03:47:40
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
0
Timeline (top)
labeled ×4commented ×1cross-referenced ×1

When switching providers mid-session via /model (e.g. from zai to openai-codex), the agent's switch_model() method updates model, provider, api_key, base_url, api_mode, and rebuilds clients — but never loads or attaches the credential pool for the new provider.

The _credential_pool attribute remains None from the original provider (which may have no pool). All pool recovery paths (_recover_with_credential_pool) check if pool is None: return False and bail out. Rate limits, auth failures, and billing errors get zero pool rotation.

Root Cause

When switching providers mid-session via /model (e.g. from zai to openai-codex), the agent's switch_model() method updates model, provider, api_key, base_url, api_mode, and rebuilds clients — but never loads or attaches the credential pool for the new provider.

The _credential_pool attribute remains None from the original provider (which may have no pool). All pool recovery paths (_recover_with_credential_pool) check if pool is None: return False and bail out. Rate limits, auth failures, and billing errors get zero pool rotation.

Fix Action

Fixed

PR fix notes

PR #25277: fix: load credential pool in switch_model for new provider (#25273)

Description (problem / solution / changelog)

Problem

When switching providers mid-session via /model (e.g., from the default zai provider to openai-codex), switch_model() updates model, provider, api_key, base_url, api_mode, and rebuilds the client — but never loads the credential pool for the new provider.

The agent's _credential_pool stays as whatever was loaded at construction time (typically None for providers like zai that use a single API key from env). This silently disables pool rotation on the new provider:

  1. All 429/401/402 errors burn the same credential with no rotation
  2. After exhausting retries, the agent falls through to cross-provider fallback
  3. Zero pool rotation log entries appear (pool is None, recovery bails immediately)

This is why a user with 3 openai-codex OAuth credentials (where one has usage available) still hits rate limits — the pool never rotates because it was never loaded.

Closes #25273

Fix

run_agent.pyswitch_model() (line ~2659)

  • Call load_pool(new_provider) after swapping runtime fields, before client rebuild
  • Set self._credential_pool to the loaded pool (or None if loading fails or pool has no credentials)
  • Wrapped in try/except to avoid breaking model switch if pool loading fails

run_agent.py_primary_runtime snapshot in switch_model() (line ~2770)

  • Include credential_pool in the snapshot dict so it survives _restore_primary_runtime() across turns

run_agent.py_restore_primary_runtime() (line ~8895)

  • Restore credential_pool from snapshot when present and not None
  • Older snapshots that predate this field are handled gracefully (pool unchanged)

Test plan

8 new tests in tests/agent/test_switch_model_credential_pool.py:

  • test_switch_loads_pool_for_new_provider — verifies load_pool is called
  • test_switch_sets_pool_none_when_no_credentials — pool=None when no creds
  • test_switch_handles_load_pool_exception — pool=None on load error
  • test_switch_includes_pool_in_primary_runtime — snapshot has pool
  • test_switch_same_provider_keeps_pool — re-load on same provider
  • test_restore_primary_preserves_pool_from_snapshot — restore path works
  • test_restore_primary_keeps_pool_when_snapshot_has_none — None guard
  • test_restore_primary_keeps_pool_when_snapshot_predates_field — backward compat

All 53 existing credential pool tests still pass.

Risks

  • Low: load_pool is called once during switch_model. If it fails (e.g., corrupted auth.json), the pool is set to None and the agent operates without pool rotation — same behavior as before the fix.
  • The _primary_runtime snapshot now holds a reference to the pool object. Since the pool is a singleton per provider (loaded from auth.json), this is a shared reference, not a copy. State changes to the pool (e.g., exhaustion) are reflected in both the agent and the snapshot.

Related

  • #24173 — Codex soft-failure pool rotation (response_invalid block)
  • #25205 — _restore_primary_runtime uses stale snapshot key
  • #24159 — Codex Responses API soft failures bypass pool rotation

Changed files

  • run_agent.py (modified, +24/-0)
  • tests/agent/test_switch_model_credential_pool.py (added, +302/-0)
RAW_BUFFERClick to expand / collapse

Description

When switching providers mid-session via /model (e.g. from zai to openai-codex), the agent's switch_model() method updates model, provider, api_key, base_url, api_mode, and rebuilds clients — but never loads or attaches the credential pool for the new provider.

The _credential_pool attribute remains None from the original provider (which may have no pool). All pool recovery paths (_recover_with_credential_pool) check if pool is None: return False and bail out. Rate limits, auth failures, and billing errors get zero pool rotation.

Impact

  • Users with multi-credential pools (openai-codex, anthropic, etc.) get no rotation after switching providers
  • All retries burn the same credential
  • Falls through to cross-provider fallback instead of rotating within the pool
  • Affects any provider switch via /model in the TUI or CLI

Reproduction

  1. Configure default provider as zai (no pool)
  2. Configure openai-codex credential pool with 3 entries
  3. Start agent (loads zai, pool=None)
  4. Switch to openai-codex via /model gpt-5.5
  5. Agent uses only the initial credential; no rotation on 429/401/402

Expected Behavior

switch_model should call load_pool(new_provider) and set self._credential_pool to the new pool (or None if the new provider has no pool).

Affected Code

  • tui_gateway/server.py line 1116: _apply_model_switch calls agent.switch_model(...) without passing pool
  • run_agent.py line 2602: switch_model method never updates self._credential_pool

Related Issues

  • #24159: soft failures bypass pool rotation (different code path)
  • #25205: _restore_primary_runtime bypasses pool (different code path)

Environment

  • Hermes Agent v0.13.0 (build 2026.5.7)
  • macOS, Nix deployment
  • Config: default=zai, pool=openai-codex (3 OAuth entries, round_robin)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING