Skip to content

fix(conversation_loop): route _pool_may_recover_from_rate_limit through _ra() - #4

Merged
pai-scaffolde merged 1 commit into
mainfrom
fix/conversation-loop-pool-recover-import
May 19, 2026
Merged

fix(conversation_loop): route _pool_may_recover_from_rate_limit through _ra()#4
pai-scaffolde merged 1 commit into
mainfrom
fix/conversation-loop-pool-recover-import

Conversation

@pai-scaffolde

Copy link
Copy Markdown
Collaborator

Bug

The eager rate-limit fallback path in agent/conversation_loop.py (line 2335) calls _pool_may_recover_from_rate_limit(...) directly, but the helper is defined in run_agent.py and is never imported into conversation_loop. Any 429 / quota error that classifies as FailoverReason.rate_limit or FailoverReason.billing — with a configured fallback model — raises:

NameError: name '_pool_may_recover_from_rate_limit' is not defined

…masking the real provider failure and aborting the turn instead of failing over.

Why it slipped through

The test suite imports the helper directly from run_agent (tests/run_agent/test_provider_fallback.py, tests/agent/test_gemini_fast_fallback.py), so the unit tests for the function pass — but the production call site in the extracted loop module has no path to the symbol. Likely regression from when the conversation loop was carved out of run_agent.py without porting the call through the lazy _ra() accessor that the rest of this file already uses.

Fix

Route the call through the existing _ra() helper (defined at line 76 of the same file), matching the established pattern for reaching run_agent symbols without an import cycle and while keeping monkey-patched symbols reachable in tests.

-                    pool_may_recover = _pool_may_recover_from_rate_limit(
+                    pool_may_recover = _ra()._pool_may_recover_from_rate_limit(
                         agent._credential_pool,
                         provider=agent.provider,
                         base_url=getattr(agent, "base_url", None),
                     )

One-line change. Lint clean. No test changes needed — the existing tests still exercise the helper directly via run_agent.

Repro

Trigger any rate-limit/billing error on a provider that has a fallback configured. Pre-fix: NameError aborts the turn. Post-fix: eager fallback branch evaluates correctly and either rotates the pool or activates the fallback model as designed (NousResearch#11314, NousResearch#13636 behavior preserved).

Verified

  • Live-patched on Gary's runtime (~/.hermes/hermes-agent/agent/conversation_loop.py); no more NameError on rate-limit branch.
  • Lint clean via patch tool's auto-syntax-check.

…gh _ra()

The eager rate-limit fallback path in agent/conversation_loop.py calls
_pool_may_recover_from_rate_limit() directly, but that helper is defined
in run_agent.py and never imported into this module. Any 429/quota error
that triggers the eager-fallback branch raises:

    NameError: name '_pool_may_recover_from_rate_limit' is not defined

masking the real provider failure and aborting the turn.

The file already uses the lazy _ra() accessor (line 76) for exactly this
kind of cross-module reach — both to avoid an import cycle with
run_agent.py and to keep monkey-patched run_agent symbols reachable in
tests. Route the call through _ra() so the production code path matches
what the test suite already validates (tests import the helper directly
from run_agent, which is why this regressed silently when the
conversation loop was extracted out of run_agent.py).

Repro: any rate-limit (FailoverReason.rate_limit / billing) with a
configured fallback chain — the branch fires and NameErrors instead of
switching providers.
@github-actions

Copy link
Copy Markdown

🔎 Lint report: fix/conversation-loop-pool-recover-import vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 8842 on HEAD, 8843 on base (✅ -1)

🆕 New issues: none

✅ Fixed issues (1):

Rule Count
unresolved-reference 1
First entries
agent/conversation_loop.py:2335: [unresolved-reference] unresolved-reference: Name `_pool_may_recover_from_rate_limit` used when not defined

Unchanged: 4650 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@pai-scaffolde
pai-scaffolde merged this pull request into main May 19, 2026
16 of 17 checks passed
pai-scaffolde pushed a commit that referenced this pull request Jun 12, 2026
…eSessionPage (NousResearch#43487)

When auto-compression rotates the session tip (old #4 → new #5), the
incoming page carries the new tip but the previous list still holds the
old one. The old tip's id differs from the new tip's id, so the existing
id-only dedup in mergeSessionPage() preserves both as separate sidebar
rows.

Add lineage-level dedup: build a set of incoming lineage keys
(`_lineage_root_id ?? id`) and filter survivors whose lineage key
matches any incoming row. This mirrors the existing sessionPinId()
logic used for pin stability.

Fixes NousResearch#43483
@pai-scaffolde
pai-scaffolde deleted the fix/conversation-loop-pool-recover-import branch July 16, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants