diff --git a/agent/credential_pool.py b/agent/credential_pool.py index 6fbb553d2..98064a85f 100644 --- a/agent/credential_pool.py +++ b/agent/credential_pool.py @@ -739,8 +739,11 @@ class CredentialPool: if self._strategy == STRATEGY_LEAST_USED and len(available) > 1: entry = min(available, key=lambda e: e.request_count) + # Increment usage counter so subsequent selections distribute load + updated = replace(entry, request_count=entry.request_count + 1) + self._replace_entry(entry, updated) self._current_id = entry.id - return entry + return updated if self._strategy == STRATEGY_ROUND_ROBIN and len(available) > 1: entry = available[0] diff --git a/tests/agent/test_credential_pool.py b/tests/agent/test_credential_pool.py index ce7b1a22d..6baee3d04 100644 --- a/tests/agent/test_credential_pool.py +++ b/tests/agent/test_credential_pool.py @@ -1171,3 +1171,33 @@ def test_nous_seed_from_singletons_preserves_obtained_at_timestamps(tmp_path, mo assert e.agent_key_expires_in == 86400 assert e.agent_key_reused is False + +class TestLeastUsedStrategy: + """Regression: least_used strategy must increment request_count on select.""" + + def test_request_count_increments(self): + """Each select() call should increment the chosen entry's request_count.""" + from unittest.mock import patch as _patch + from agent.credential_pool import CredentialPool, PooledCredential, STRATEGY_LEAST_USED + + entries = [ + PooledCredential(provider="test", id="a", label="a", auth_type="api_key", + source="a", access_token="tok-a", priority=0, request_count=0), + PooledCredential(provider="test", id="b", label="b", auth_type="api_key", + source="b", access_token="tok-b", priority=1, request_count=0), + ] + with _patch("agent.credential_pool.get_pool_strategy", return_value=STRATEGY_LEAST_USED): + pool = CredentialPool("test", entries) + + # First select should pick entry with lowest count (both 0 → first) + e1 = pool.select() + assert e1 is not None + count_after_first = e1.request_count + assert count_after_first == 1, f"Expected 1 after first select, got {count_after_first}" + + # Second select should pick the OTHER entry (now has lower count) + e2 = pool.select() + assert e2 is not None + assert e2.id != e1.id or e2.request_count == 2, ( + "least_used should alternate or increment" + )