Skip to content

fix(agent): wire up credential pool mark_used for least_used strategy#4453

Closed
dieutx wants to merge 1 commit into
NousResearch:mainfrom
dieutx:fix/credential-pool-mark-used
Closed

fix(agent): wire up credential pool mark_used for least_used strategy#4453
dieutx wants to merge 1 commit into
NousResearch:mainfrom
dieutx:fix/credential-pool-mark-used

Conversation

@dieutx

@dieutx dieutx commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Summary

The `least_used` credential pool strategy doesn't actually distribute load. All credentials stay at `request_count=0` forever, so `min()` always picks the first one — making `least_used` behave identically to `fill_first`. One key hits rate limits while others sit idle.

Root Cause

`mark_used()` in `credential_pool.py:399` increments `request_count`, but it's never called from any production code path. Searched the entire codebase (excluding tests) — zero callers. The runtime uses `mark_exhausted_and_rotate()` and `try_refresh_current()` but never `mark_used()`.

Additionally, `mark_used()` didn't call `_persist()`, so even if it were called, counts would reset on process restart.

Fix

`run_agent.py`: Call `self._credential_pool.mark_used()` after each successful API call (line 6503), right at `api_call_count += 1`.

`credential_pool.py`: Add `self._persist()` inside `mark_used()` so counts survive restarts.

Tests

4 tests: mark_used increments current, increments specific entry, persists to disk, and least_used rotates after mark.

```
4 passed
```

@dieutx dieutx force-pushed the fix/credential-pool-mark-used branch from 9e6e11d to ba40fc3 Compare April 15, 2026 14:23
@dieutx

dieutx commented Apr 15, 2026

Copy link
Copy Markdown
Contributor Author

Rebased this onto current main and refreshed the least-used/request-count path.\n\nLocal: pytest -q tests/test_credential_pool_mark_used.py tests/agent/test_credential_pool.py -k "least_used or request_count" -> 2 passed

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent loop, run_agent.py, prompt builder area/auth Authentication, OAuth, credential pools labels May 1, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #15120 (merged) — same root cause: mark_used() never called from production code, least_used degenerates to fill_first. The merged PR already addressed this. Also related to closed #14631.

@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #15120 (merged).

@teknium1

Copy link
Copy Markdown
Contributor

Automated hermes-sweeper review: this PR’s credential-pool least_used fix is already present on current main via merged PR #15120. Thanks for the clear root-cause writeup and tests here; the merged salvage addressed the same behavior.

Evidence:

  • PR fix(credential-pool): correctness + rotation + cross-process sync #15120 was merged as 3392d1e422d3bdc535b20c48621e03adb375e753 and its body calls out the same root cause: STRATEGY_LEAST_USED selected by request_count but never incremented the counter.
  • The implementation is now in agent/credential_pool.py:1354: least_used selects min(available, key=lambda e: e.request_count), replaces the entry with request_count + 1, and returns the updated credential.
  • Regression coverage exists in tests/agent/test_credential_pool.py:2384, asserting that least_used increments request_count and does not keep choosing the same zero-count entry.
  • The fixing commit is 461899894ea87a099d52329c5cecbf071e03388c and is contained in release tag v2026.4.30.

@teknium1 teknium1 closed this Jun 10, 2026
@teknium1 teknium1 added the sweeper:implemented-on-main Sweeper: behavior already present on current main label Jun 10, 2026
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/agent Core agent loop, run_agent.py, prompt builder P2 Medium — degraded but workaround exists sweeper:implemented-on-main Sweeper: behavior already present on current main type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants