diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 6c95a3e5f..993cc8493 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -23,6 +23,7 @@ - Fixed whitespace-only tool output (for example a bare `\r\n` from bash) being sent as-is to OpenAI Completions, OpenAI Responses, and Google providers; it now uses the same placeholder as empty output, since some providers reject whitespace-only tool content with a 400 ([#8720](https://github.com/earendil-works/pi/issues/8720)) - Fixed automatic retry not triggering for gateway upstream failures such as `upstream_error: Upstream request failed`, `upstream_stream_read_error`, and `Upstream HTTP/2 stream failed` ([#10920](https://github.com/earendil-works/pi/issues/10920)) - Fixed automatic retry not triggering for `stream disconnected before completion` errors relayed by proxies that wrap the Codex CLI ([#11057](https://github.com/earendil-works/pi/issues/11057)) +- Fixed automatic retry treating digits inside request ids or other numbers (for example `req_011CU503xyz` or `5242880 bytes`) as retryable HTTP status codes ([#11057](https://github.com/earendil-works/pi/issues/11057)) - Fixed OpenAI Responses deferred tool loads rewriting the top-level tool list, and losing the prompt cache, on every load after a tool removal. Models with `additional_tools` now declare all tools in `additional_tools` items, starting with one at the head of the input, so removals (announced as text) and redefinitions no longer rewrite the prefix. Tool search and Kimi tool messages rewrite the top-level tools once per removal or redeclaration and keep later loads anchored ([#10940](https://github.com/earendil-works/pi/issues/10940)) ## [1.3.0] - 2026-10-15 diff --git a/packages/ai/src/utils/retry.ts b/packages/ai/src/utils/retry.ts index af71de78f..a1e984032 100644 --- a/packages/ai/src/utils/retry.ts +++ b/packages/ai/src/utils/retry.ts @@ -39,13 +39,8 @@ const RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([ "model is at capacity", "rate.?limit", "too many requests", - "429", - "500", - "502", - "503", - "504", - "520", - "524", + // Status codes must not be part of a longer word or number, e.g. a request id or byte count (#11057). + "(? { ).toBe(true); expect(isRetryableAssistantError(fauxAssistantMessage("not an error"))).toBe(false); }); + + it.each([ + // Regression for #11057: status codes inside ids or other numbers are not status codes. + '401 {"type":"error","error":{"type":"authentication_error","message":"invalid x-api-key"},"request_id":"req_011CU503xyz"}', + "400 image exceeds 5 MB maximum: 5316784 bytes > 5242880 bytes", + ])("does not match status codes inside ids or longer numbers: %s", (errorMessage) => { + expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(false); + }); }); describe("retryDelayMs", () => {