MCPcopy
hub / github.com/codeaashu/claude-code / withRetry

Function withRetry

src/services/api/withRetry.ts:170–517  ·  view source on GitHub ↗
(
  getClient: () => Promise<Anthropic>,
  operation: (
    client: Anthropic,
    attempt: number,
    context: RetryContext,
  ) => Promise<T>,
  options: RetryOptions,
)

Source from the content-addressed store, hash-verified

168}
169
170export async function* withRetry<T>(
171 getClient: () => Promise<Anthropic>,
172 operation: (
173 client: Anthropic,
174 attempt: number,
175 context: RetryContext,
176 ) => Promise<T>,
177 options: RetryOptions,
178): AsyncGenerator<SystemAPIErrorMessage, T> {
179 const maxRetries = getMaxRetries(options)
180 const retryContext: RetryContext = {
181 model: options.model,
182 thinkingConfig: options.thinkingConfig,
183 ...(isFastModeEnabled() && { fastMode: options.fastMode }),
184 }
185 let client: Anthropic | null = null
186 let consecutive529Errors = options.initialConsecutive529Errors ?? 0
187 let lastError: unknown
188 let persistentAttempt = 0
189 for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
190 if (options.signal?.aborted) {
191 throw new APIUserAbortError()
192 }
193
194 // Capture whether fast mode is active before this attempt
195 // (fallback may change the state mid-loop)
196 const wasFastModeActive = isFastModeEnabled()
197 ? retryContext.fastMode && !isFastModeCooldown()
198 : false
199
200 try {
201 // Check for mock rate limits (used by /mock-limits command for Ant employees)
202 if (process.env.USER_TYPE === 'ant') {
203 const mockError = checkMockRateLimitError(
204 retryContext.model,
205 wasFastModeActive,
206 )
207 if (mockError) {
208 throw mockError
209 }
210 }
211
212 // Get a fresh client instance on first attempt or after authentication errors
213 // - 401 for first-party API authentication failures
214 // - 403 "OAuth token has been revoked" (another process refreshed the token)
215 // - Bedrock-specific auth errors (403 or CredentialsProviderError)
216 // - Vertex-specific auth errors (credential refresh failures, 401)
217 // - ECONNRESET/EPIPE: stale keep-alive socket; disable pooling and reconnect
218 const isStaleConnection = isStaleConnectionError(lastError)
219 if (
220 isStaleConnection &&
221 getFeatureValue_CACHED_MAY_BE_STALE(
222 'tengu_disable_keepalive_on_econnreset',
223 false,
224 )
225 ) {
226 logForDebugging(
227 'Stale connection (ECONNRESET/EPIPE) — disabling keep-alive for retry',

Callers 3

verifyApiKeyFunction · 0.70
queryModelFunction · 0.70

Calls 15

getMaxRetriesFunction · 0.85
isFastModeEnabledFunction · 0.85
isFastModeCooldownFunction · 0.85
checkMockRateLimitErrorFunction · 0.85
isStaleConnectionErrorFunction · 0.85
logForDebuggingFunction · 0.85
disableKeepAliveFunction · 0.85
isOAuthTokenRevokedErrorFunction · 0.85
isBedrockAuthErrorFunction · 0.85
isVertexAuthErrorFunction · 0.85
handleOAuth401ErrorFunction · 0.85

Tested by

no test coverage detected