diff --git a/packages/llm/src/route/executor.ts b/packages/llm/src/route/executor.ts index b2f679c68354..60b7d6475cc3 100644 --- a/packages/llm/src/route/executor.ts +++ b/packages/llm/src/route/executor.ts @@ -88,7 +88,8 @@ const requestId = (headers: Record) => { ) } -const retryableStatus = (status: number) => status === 429 || status === 503 || status === 504 || status === 529 +const retryableStatus = (status: number) => + status === 408 || status === 409 || status === 429 || status === 503 || status === 504 || status === 529 const retryAfterMs = (headers: Record) => { const millis = Number(headers["retry-after-ms"]) @@ -250,13 +251,7 @@ const statusReason = (input: { http: input.http, }) } - if ( - input.status === 400 || - input.status === 404 || - input.status === 409 || - input.status === 413 || - input.status === 422 - ) { + if (input.status === 400 || input.status === 404 || input.status === 413 || input.status === 422) { return new InvalidRequestReason({ message: input.message, classification: isContextOverflow(body) ? "context-overflow" : undefined, diff --git a/packages/llm/test/executor.test.ts b/packages/llm/test/executor.test.ts index 811f7a9ffe7b..4b432482471c 100644 --- a/packages/llm/test/executor.test.ts +++ b/packages/llm/test/executor.test.ts @@ -264,8 +264,30 @@ describe("RequestExecutor", () => { ), ), ) + ;[408, 409].forEach((status) => { + it.effect(`retries HTTP ${status} before returning a successful response`, () => + Effect.gen(function* () { + const attempts = yield* Ref.make(0) + yield* Effect.gen(function* () { + const executor = yield* RequestExecutor.Service + const response = yield* executor.execute(request) + + expect(response.status).toBe(200) + expect(yield* response.text).toBe("ok") + expect(yield* Ref.get(attempts)).toBe(2) + }).pipe( + Effect.provide( + countedResponsesLayer(attempts, [ + new Response("transient failure", { status, headers: { "retry-after-ms": "0" } }), + new Response("ok", { status: 200 }), + ]), + ), + ) + }), + ) + }) - it.effect("marks 504 and 529 status responses retryable", () => + it.effect("marks 408, 409, 504 and 529 status responses retryable", () => Effect.gen(function* () { const failWith = (status: number) => Effect.gen(function* () { @@ -290,6 +312,8 @@ describe("RequestExecutor", () => { ), ) + yield* failWith(408) + yield* failWith(409) yield* failWith(504) yield* failWith(529) }),