{ "stopReason": "error", "errorMessage": "terminated", "usage": {"input": 0, "output": 0, ...}}case "response.failed": { const msg = (event as { response?: { error?: { message?: string } } }).response?.error?.message; throw new Error(msg || "Codex response failed");}{ "type": "response.failed", "response": { "error": { "message": "terminated" } }}const MAX_RETRIES = 3;const BASE_DELAY_MS = 1000;
function isRetryableError(status: number, errorText: string): boolean { if (status === 429 || status === 500 || status === 502 || status === 503 || status === 504) { return true; } return /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused/i.test(errorText);}private _isRetryableError(message: AssistantMessage): boolean { if (message.stopReason !== "error" || !message.errorMessage) return false;
// Context overflow is handled by compaction, not retry const contextWindow = this.model?.contextWindow ?? 0; if (isContextOverflow(message, contextWindow)) return false;
const err = message.errorMessage; // Match: overloaded_error, rate limit, 429, 500, 502, 503, 504, service unavailable, connection errors, fetch failed return /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server error|internal error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers/i.test( err, );}return /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server error|internal error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|terminated/i.test( err,);