From c1b62ae7fe70db757a349104c60c97b4a1a4eee8 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Fri, 24 Apr 2026 14:18:35 +0200 Subject: [PATCH] fix(ai,coding-agent): omit undefined provider request options closes #3627 --- packages/ai/CHANGELOG.md | 4 ++++ packages/ai/src/providers/anthropic.ts | 16 ++++++---------- .../ai/src/providers/azure-openai-responses.ts | 13 ++++++------- packages/ai/src/providers/openai-completions.ts | 11 ++++++----- packages/ai/src/providers/openai-responses.ts | 13 ++++++------- packages/coding-agent/CHANGELOG.md | 4 ++++ 6 files changed, 32 insertions(+), 29 deletions(-) diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 0503314f..389dd9d1 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed OpenAI/Azure/Anthropic provider request option forwarding to omit undefined `timeout`/`maxRetries`, avoiding SDK validation errors such as `timeout must be an integer` when provider controls are not set ([#3627](https://github.com/badlogic/pi-mono/issues/3627)) + ## [0.70.1] - 2026-04-24 ### Added diff --git a/packages/ai/src/providers/anthropic.ts b/packages/ai/src/providers/anthropic.ts index 78f552f9..4173f20a 100644 --- a/packages/ai/src/providers/anthropic.ts +++ b/packages/ai/src/providers/anthropic.ts @@ -456,16 +456,12 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti if (nextParams !== undefined) { params = nextParams as MessageCreateParamsStreaming; } - const response = await client.messages - .create( - { ...params, stream: true }, - { - signal: options?.signal, - timeout: options?.timeoutMs, - maxRetries: options?.maxRetries, - }, - ) - .asResponse(); + const requestOptions = { + ...(options?.signal ? { signal: options.signal } : {}), + ...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}), + ...(options?.maxRetries !== undefined ? { maxRetries: options.maxRetries } : {}), + }; + const response = await client.messages.create({ ...params, stream: true }, requestOptions).asResponse(); await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model); stream.push({ type: "start", partial: output }); diff --git a/packages/ai/src/providers/azure-openai-responses.ts b/packages/ai/src/providers/azure-openai-responses.ts index 10d86ae6..418e2099 100644 --- a/packages/ai/src/providers/azure-openai-responses.ts +++ b/packages/ai/src/providers/azure-openai-responses.ts @@ -91,13 +91,12 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses" if (nextParams !== undefined) { params = nextParams as ResponseCreateParamsStreaming; } - const { data: openaiStream, response } = await client.responses - .create(params, { - signal: options?.signal, - timeout: options?.timeoutMs, - maxRetries: options?.maxRetries, - }) - .withResponse(); + const requestOptions = { + ...(options?.signal ? { signal: options.signal } : {}), + ...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}), + ...(options?.maxRetries !== undefined ? { maxRetries: options.maxRetries } : {}), + }; + const { data: openaiStream, response } = await client.responses.create(params, requestOptions).withResponse(); await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model); stream.push({ type: "start", partial: output }); diff --git a/packages/ai/src/providers/openai-completions.ts b/packages/ai/src/providers/openai-completions.ts index aecdad1d..5404bb8c 100644 --- a/packages/ai/src/providers/openai-completions.ts +++ b/packages/ai/src/providers/openai-completions.ts @@ -144,12 +144,13 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions", OpenA if (nextParams !== undefined) { params = nextParams as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming; } + const requestOptions = { + ...(options?.signal ? { signal: options.signal } : {}), + ...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}), + ...(options?.maxRetries !== undefined ? { maxRetries: options.maxRetries } : {}), + }; const { data: openaiStream, response } = await client.chat.completions - .create(params, { - signal: options?.signal, - timeout: options?.timeoutMs, - maxRetries: options?.maxRetries, - }) + .create(params, requestOptions) .withResponse(); await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model); stream.push({ type: "start", partial: output }); diff --git a/packages/ai/src/providers/openai-responses.ts b/packages/ai/src/providers/openai-responses.ts index 2e11d292..1cb68ac5 100644 --- a/packages/ai/src/providers/openai-responses.ts +++ b/packages/ai/src/providers/openai-responses.ts @@ -98,13 +98,12 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses", OpenAIRes if (nextParams !== undefined) { params = nextParams as ResponseCreateParamsStreaming; } - const { data: openaiStream, response } = await client.responses - .create(params, { - signal: options?.signal, - timeout: options?.timeoutMs, - maxRetries: options?.maxRetries, - }) - .withResponse(); + const requestOptions = { + ...(options?.signal ? { signal: options.signal } : {}), + ...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}), + ...(options?.maxRetries !== undefined ? { maxRetries: options.maxRetries } : {}), + }; + const { data: openaiStream, response } = await client.responses.create(params, requestOptions).withResponse(); await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model); stream.push({ type: "start", partial: output }); diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index fa85a52c..7a0ee351 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed provider retry/timeout forwarding to omit undefined provider request controls, avoiding downstream SDK validation errors such as `timeout must be an integer` when `retry.provider.timeoutMs` is not configured ([#3627](https://github.com/badlogic/pi-mono/issues/3627)) + ## [0.70.1] - 2026-04-24 ### New Features