From 2e4ad6a09423002f58b9a5dc2749f7db7929d0f0 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 6 Jul 2026 02:21:15 +0200 Subject: [PATCH] fix(ai): clamp OpenAI Responses max output token floor closes #6265 --- packages/ai/CHANGELOG.md | 1 + packages/ai/src/api/azure-openai-responses.ts | 4 +++- packages/ai/src/api/openai-responses.ts | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 760f349ac..1051de9d0 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -11,6 +11,7 @@ - Fixed Amazon Bedrock prompt-cache points for Claude Fable 5 and Claude Sonnet 5 ([#6235](https://github.com/earendil-works/pi/issues/6235)). - Fixed DS4 server context overflow detection for `Prompt has ... tokens, but the configured context size is ... tokens` errors ([#6262](https://github.com/earendil-works/pi/issues/6262)). - Fixed OpenAI Codex WebSocket sessions to rotate cached connections before the backend's 60-minute limit, avoiding connection-limit failures on long sessions ([#6268](https://github.com/earendil-works/pi/issues/6268)). +- Fixed OpenAI Responses and Azure OpenAI Responses requests to avoid sending `max_output_tokens` values below the provider minimum ([#6265](https://github.com/earendil-works/pi/issues/6265)). - Fixed retry classification for Cloudflare 524 timeout responses ([#6239](https://github.com/earendil-works/pi/issues/6239)). ### Added diff --git a/packages/ai/src/api/azure-openai-responses.ts b/packages/ai/src/api/azure-openai-responses.ts index 5018b7835..04533dd72 100644 --- a/packages/ai/src/api/azure-openai-responses.ts +++ b/packages/ai/src/api/azure-openai-responses.ts @@ -20,6 +20,8 @@ import { buildBaseOptions } from "./simple-options.ts"; const DEFAULT_AZURE_API_VERSION = "v1"; const AZURE_TOOL_CALL_PROVIDERS = new Set(["openai", "openai-codex", "opencode", "azure-openai-responses"]); +// OpenAI Responses rejects max_output_tokens below 16: https://github.com/earendil-works/pi/issues/6265 +const OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16; function parseDeploymentNameMap(value: string | undefined): Map { const map = new Map(); @@ -264,7 +266,7 @@ function buildParams( }; if (options?.maxTokens) { - params.max_output_tokens = options?.maxTokens; + params.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS); } if (options?.temperature !== undefined) { diff --git a/packages/ai/src/api/openai-responses.ts b/packages/ai/src/api/openai-responses.ts index 5f29ecb9a..3f235268e 100644 --- a/packages/ai/src/api/openai-responses.ts +++ b/packages/ai/src/api/openai-responses.ts @@ -25,6 +25,8 @@ import { convertResponsesMessages, convertResponsesTools, processResponsesStream import { buildBaseOptions } from "./simple-options.ts"; const OPENAI_TOOL_CALL_PROVIDERS = new Set(["openai", "openai-codex", "opencode"]); +// OpenAI Responses rejects max_output_tokens below 16: https://github.com/earendil-works/pi/issues/6265 +const OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16; function hasHeader(headers: ProviderHeaders | undefined, name: string): boolean { if (!headers) return false; @@ -232,7 +234,7 @@ function buildParams(model: Model<"openai-responses">, context: Context, options }; if (options?.maxTokens) { - params.max_output_tokens = options?.maxTokens; + params.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS); } if (options?.temperature !== undefined) {