From a648772ae5c09d2ab4b08ecd2c3642a2c47eba35 Mon Sep 17 00:00:00 2001 From: elliotllliu <55885132+elliotllliu@users.noreply.github.com> Date: Tue, 10 Mar 2026 02:28:16 -0400 Subject: [PATCH] fix: auto-retry on OpenAI stream stall errors (#355) When the OpenAI responses stream stalls (e.g. with github-copilot/ gpt-5.4), the error message "stream stalled while waiting for the next event" is now recognized as a retryable transient error. Two locations updated: - packages/ai/src/utils/retry.ts: add "stream stall" to TRANSIENT_MESSAGE_PATTERN (used by provider-level retry logic) - packages/coding-agent/src/session/agent-session.ts: add "stream stall" to #isRetryableErrorMessage() regex (used by agent-session retry loop for both thrown errors and error AssistantMessages) Fixes #348 Co-authored-by: GitHub User --- packages/ai/src/utils/retry.ts | 2 +- packages/coding-agent/src/session/agent-session.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ai/src/utils/retry.ts b/packages/ai/src/utils/retry.ts index 985f8affb..c48fec470 100644 --- a/packages/ai/src/utils/retry.ts +++ b/packages/ai/src/utils/retry.ts @@ -8,7 +8,7 @@ type ErrorLike = { }; const TRANSIENT_MESSAGE_PATTERN = - /overloaded|rate.?limit|usage.?limit|too many requests|service.?unavailable|server error|internal error|connection.?error|unable to connect|fetch failed/i; + /overloaded|rate.?limit|usage.?limit|too many requests|service.?unavailable|server error|internal error|connection.?error|unable to connect|fetch failed|stream stall/i; const VALIDATION_MESSAGE_PATTERN = /invalid|validation|bad request|unsupported|schema|missing required|not found|unauthorized|forbidden/i; diff --git a/packages/coding-agent/src/session/agent-session.ts b/packages/coding-agent/src/session/agent-session.ts index 2507004b5..f8a574f7e 100644 --- a/packages/coding-agent/src/session/agent-session.ts +++ b/packages/coding-agent/src/session/agent-session.ts @@ -4113,8 +4113,8 @@ export class AgentSession { } #isRetryableErrorMessage(errorMessage: string): boolean { - // Match: overloaded_error, rate limit, usage limit, 429, 500, 502, 503, 504, service unavailable, connection error, fetch failed, retry delay exceeded - return /overloaded|rate.?limit|usage.?limit|too many requests|429|500|502|503|504|service.?unavailable|server error|internal error|connection.?error|unable to connect|fetch failed|retry delay/i.test( + // Match: overloaded_error, rate limit, usage limit, 429, 500, 502, 503, 504, service unavailable, connection error, fetch failed, retry delay exceeded, stream stall + return /overloaded|rate.?limit|usage.?limit|too many requests|429|500|502|503|504|service.?unavailable|server error|internal error|connection.?error|unable to connect|fetch failed|retry delay|stream stall/i.test( errorMessage, ); }