mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(ai): retry HTTP/2 pending stream cancellation
Bedrock's HTTP/2 connection can stall until the SDK's 5-minute session timeout, which fails the request with "The pending stream has been canceled" (ERR_HTTP2_STREAM_CANCEL). The request was never sent, so it is safe to retry, but the message was only retried when a DNS cause was appended. closes #10379
This commit is contained in:
parent
b78e6a9085
commit
5b6c792b42
3 changed files with 15 additions and 0 deletions
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Bedrock requests that fail with `The pending stream has been canceled` after a stalled HTTP/2 connection not being retried automatically ([#10379](https://github.com/earendil-works/pi/issues/10379))
|
||||
|
||||
## [1.0.3] - 2026-10-05
|
||||
|
||||
### Breaking Changes
|
||||
|
|
|
|||
|
|
@ -81,6 +81,9 @@ const RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([
|
|||
"stream ended before message_stop",
|
||||
"stream ended before a terminal response event",
|
||||
"http2 request did not get a response",
|
||||
// Node ERR_HTTP2_STREAM_CANCEL: the HTTP/2 session died before the request was
|
||||
// sent, e.g. after the Bedrock SDK's 5-minute session timeout (#10379).
|
||||
"pending stream has been canceled",
|
||||
|
||||
// Provider-requested retry delay cap failures should flow through the outer
|
||||
// retry policy so callers can surface/abort the backoff (#1123).
|
||||
|
|
|
|||
|
|
@ -62,6 +62,14 @@ describe("provider retry classification", () => {
|
|||
expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(true);
|
||||
});
|
||||
|
||||
it.each(["The pending stream has been canceled", "The pending stream has been canceled (caused by: socket closed)"])(
|
||||
"matches HTTP/2 pending stream cancellation: %s",
|
||||
(errorMessage) => {
|
||||
// Regression for #10379.
|
||||
expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
it("matches OpenAI Responses streams that end before terminal events", () => {
|
||||
expect(
|
||||
isRetryableAssistantError(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue