This commit is contained in:
parent
9175eb0aa3
commit
8872c9095e
1 changed files with 27 additions and 0 deletions
|
|
@ -203,6 +203,28 @@ function mergeHeaders(...headerSources: (Record<string, string> | undefined)[]):
|
|||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect transient network errors that are likely to succeed on retry.
|
||||
* Covers WebSocket disconnects (Tailscale, VPN), TCP resets, and DNS failures.
|
||||
*/
|
||||
function isTransientNetworkError(error: unknown): boolean {
|
||||
if (!(error instanceof Error)) return false;
|
||||
const msg = error.message.toLowerCase();
|
||||
const code = (error as NodeJS.ErrnoException).code;
|
||||
return (
|
||||
code === 'ECONNRESET' ||
|
||||
code === 'EPIPE' ||
|
||||
code === 'ETIMEDOUT' ||
|
||||
code === 'ENOTFOUND' ||
|
||||
code === 'EAI_AGAIN' ||
|
||||
msg.includes('connector_closed') ||
|
||||
msg.includes('socket hang up') ||
|
||||
msg.includes('network') ||
|
||||
msg.includes('connection') && msg.includes('closed') ||
|
||||
msg.includes('fetch failed')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract retry delay from Anthropic error response headers (in milliseconds).
|
||||
* Checks: retry-after (seconds or RFC date), x-ratelimit-reset-requests, x-ratelimit-reset-tokens.
|
||||
|
|
@ -497,6 +519,11 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti
|
|||
output.retryAfterMs = retryAfterMs;
|
||||
}
|
||||
}
|
||||
// Mark transient network errors as retriable so auto-mode can
|
||||
// detect them and retry instead of stopping (#833).
|
||||
if (isTransientNetworkError(error)) {
|
||||
output.retryAfterMs = output.retryAfterMs ?? 5000;
|
||||
}
|
||||
stream.push({ type: "error", reason: output.stopReason, error: output });
|
||||
stream.end();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue