fix(refresh): stop refresh hanging on slow / reasoning models - #89
Merged
Conversation
Two changes so `ag-refresh` works out-of-the-box with slow reasoning models
(e.g. MiniMax-M3) instead of appearing to hang for many minutes:
1. A bare asyncio.wait_for timeout is no longer treated as retryable
(_is_retryable_error). Our own per-attempt deadline elapsing means the model
is slow/stalling, not transiently failing β retrying the same full-length
attempt just multiplied wall-clock by (AG_REFRESH_RETRY_COUNT + 1) (default
4x) for the same outcome. It now falls back immediately. Messaged provider
timeouts ("504" / "gateway time-out") stay retryable.
2. Raise the refresh per-attempt timeout defaults, which were tuned for fast
models and too low for reasoning models (one call may emit a long reasoning
block; conventions is a 3-hop handoff swarm):
- AG_REFRESH_AGENT_TIMEOUT_SECONDS 90 -> 300 (conventions swarm)
- AG_MODULE_AGENT_TIMEOUT_SECONDS 45 -> 240 (per-module doc)
- AG_MAP_AGENT_TIMEOUT_SECONDS 90 -> 240 (map.md)
- AG_REGISTRY_TIMEOUT_SECONDS 60 -> 120
A bare timeout no longer retries, so a higher ceiling only costs time if a
call genuinely runs that long; fast models finish well under these.
Verified end-to-end: a full multi-module refresh completes with real
(non-fallback) docs on MiniMax-M3. Adds test_refresh_retry.py and documents
the timeouts in engine/.env.example.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OOTB verification showed per-module knowledge-doc calls still timing out at 240s with MiniMax-M3 (3 modules concurrent) and falling back; the proven value is 300s (same as the conventions swarm). Raise AG_MODULE_AGENT_TIMEOUT_SECONDS and AG_MAP_AGENT_TIMEOUT_SECONDS defaults 240 -> 300 so refresh produces real (non-fallback) docs out of the box. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
ag-refreshappeared to hang for many minutes with a slow reasoning model (MiniMax-M3) β sometimes >1h β whileag-askworked fine.Root cause (diagnosed, not a deadlock)
asyncio.wait_fordoes fire; refresh always completes. The "hang" was:asyncio.TimeoutError(our own per-attempt deadline) was classified retryable β_run_with_retryran 4 attempts Γ full timeout per step (AG_REFRESH_RETRY_COUNTdefault 3). Retrying a slow model the same way just multiplied wall-clock for the same outcome.Fix
_is_retryable_error: a bare wait-for timeout is non-retryable β fall back immediately instead of 4Γ. Messaged provider timeouts (504/gateway time-out) stay retryable.90β300, module45β240, map90β240, registry60β120. A bare timeout no longer retries, so a higher ceiling only costs time if a call genuinely runs that long; fast models finish well under it.engine/.env.example(+ reasoning-model note).Verified
success).engine/tests/test_refresh_retry.pyadded (bare timeout β not retried; messaged/transient β retried). Full engine suite: 223 passed.π€ Generated with Claude Code