From 5bb3ac842760f16cdb6348f4ce6b1fa571426bc5 Mon Sep 17 00:00:00 2001 From: Armando Vaquera <263793884+proyectoauraorg@users.noreply.github.com> Date: Fri, 22 May 2026 00:01:12 -0600 Subject: [PATCH] fix(openai): omit temperature when no custom value is set (#242) When "use custom temperature" is off, the OpenAI-Compatible provider still sent temperature: 0 (the fallback), so the model's server-side default never applied. Per the discussion on #242 (option A), omit the temperature field in that case. Preserves the supportsTemperature gate (#233), model-required defaults (deepseek-reasoner), and a deliberately-set 0. --- .changeset/omit-temperature-when-unset.md | 5 +++++ src/api/providers/__tests__/openai.spec.ts | 19 ++++++++++++++++--- src/api/providers/openai.ts | 12 ++++++++---- 3 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 .changeset/omit-temperature-when-unset.md diff --git a/.changeset/omit-temperature-when-unset.md b/.changeset/omit-temperature-when-unset.md new file mode 100644 index 0000000000..033755c336 --- /dev/null +++ b/.changeset/omit-temperature-when-unset.md @@ -0,0 +1,5 @@ +--- +"zoo-code": patch +--- + +OpenAI-Compatible provider: omit the `temperature` field when no custom temperature is set, so the model's server-side default applies instead of forcing `0` (#242). Model-required defaults (e.g. `deepseek-reasoner`) and the existing `supportsTemperature` capability gate are preserved, and a deliberately-set `0` is still sent. diff --git a/src/api/providers/__tests__/openai.spec.ts b/src/api/providers/__tests__/openai.spec.ts index ccbbb870df..28524f40f8 100644 --- a/src/api/providers/__tests__/openai.spec.ts +++ b/src/api/providers/__tests__/openai.spec.ts @@ -409,13 +409,15 @@ describe("OpenAiHandler", () => { expect(callArgs).not.toHaveProperty("temperature") }) - it("should include temperature by default when supportsTemperature is not set", async () => { + it("should omit temperature by default when no custom temperature is set (#242)", async () => { + // Option A: when "use custom temperature" is off (modelTemperature unset) and the model has no + // required default, omit `temperature` so the server's own default applies instead of forcing 0. const stream = handler.createMessage(systemPrompt, messages) for await (const _chunk of stream) { } expect(mockCreate).toHaveBeenCalled() const callArgs = mockCreate.mock.calls[0][0] - expect(callArgs).toHaveProperty("temperature") + expect(callArgs).not.toHaveProperty("temperature") }) it("should use the configured modelTemperature when supportsTemperature is not false", async () => { @@ -438,6 +440,17 @@ describe("OpenAiHandler", () => { expect(callArgs.temperature).toBe(DEEP_SEEK_DEFAULT_TEMPERATURE) }) + it("should still send temperature when the user sets a custom value of 0 (#242)", async () => { + // A deliberate 0 must be distinguished from "unset" — it is sent, not omitted. + const zeroTempHandler = new OpenAiHandler({ ...mockOptions, modelTemperature: 0 }) + const stream = zeroTempHandler.createMessage(systemPrompt, messages) + for await (const _chunk of stream) { + } + expect(mockCreate).toHaveBeenCalled() + const callArgs = mockCreate.mock.calls[0][0] + expect(callArgs.temperature).toBe(0) + }) + it("should include max_tokens when includeMaxTokens is true", async () => { const optionsWithMaxTokens: ApiHandlerOptions = { ...mockOptions, @@ -679,7 +692,7 @@ describe("OpenAiHandler", () => { ], stream: true, stream_options: { include_usage: true }, - temperature: 0, + // #242 (option A): no custom temperature set → `temperature` is omitted. tools: undefined, tool_choice: undefined, parallel_tool_calls: true, diff --git a/src/api/providers/openai.ts b/src/api/providers/openai.ts index 7ea33196f9..e6e5abf13a 100644 --- a/src/api/providers/openai.ts +++ b/src/api/providers/openai.ts @@ -157,10 +157,14 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl // Some OpenAI-Compatible models (e.g. claude-opus-4-7) reject `temperature` as // deprecated/unsupported. Honor the model's `supportsTemperature` flag and omit it // when explicitly set to false (undefined still sends temperature, preserving behavior). - ...(modelInfo.supportsTemperature !== false && { - temperature: - this.options.modelTemperature ?? (deepseekReasoner ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0), - }), + // Include `temperature` only when the model supports it (#233) AND either the user set a + // custom temperature or the model needs a specific default (deepseek-reasoner). When "use + // custom temperature" is off and the model has no required default, omit it so the server's + // own default applies instead of forcing 0 (#242 — option A). + ...(modelInfo.supportsTemperature !== false && + (this.options.modelTemperature != null || deepseekReasoner) && { + temperature: this.options.modelTemperature ?? DEEP_SEEK_DEFAULT_TEMPERATURE, + }), messages: convertedMessages, stream: true as const, ...(isGrokXAI ? {} : { stream_options: { include_usage: true } }),