Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 94f754d

Browse files
committed
fix: omit temperature from OpenAI-compatible requests when not explicitly set
When no custom temperature is configured, the OpenAI handler was always sending temperature: 0 in API requests. Some OpenAI-compatible APIs (e.g. Kimi Coding) require specific temperature values and reject others. This change omits the temperature parameter entirely when the user has not explicitly set one, letting upstream APIs use their own model-specific defaults. When a user configures a custom temperature, it is still sent. Fixes #12141
1 parent cb83656 commit 94f754d

2 files changed

Lines changed: 82 additions & 2 deletions

File tree

src/api/providers/__tests__/openai.spec.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,74 @@ describe("OpenAiHandler", () => {
497497
const callArgs = mockCreate.mock.calls[0][0]
498498
expect(callArgs.max_completion_tokens).toBe(4096)
499499
})
500+
501+
it("should omit temperature when modelTemperature is not set (streaming)", async () => {
502+
// When no custom temperature is configured, temperature should not be sent
503+
// so that OpenAI-compatible APIs (e.g. Kimi) can use their own defaults
504+
const handlerNoTemp = new OpenAiHandler({
505+
...mockOptions,
506+
// modelTemperature is not set (undefined)
507+
})
508+
const stream = handlerNoTemp.createMessage(systemPrompt, messages)
509+
for await (const _chunk of stream) {
510+
}
511+
expect(mockCreate).toHaveBeenCalled()
512+
const callArgs = mockCreate.mock.calls[0][0]
513+
expect(callArgs).not.toHaveProperty("temperature")
514+
})
515+
516+
it("should include temperature when modelTemperature is explicitly set (streaming)", async () => {
517+
const handlerWithTemp = new OpenAiHandler({
518+
...mockOptions,
519+
modelTemperature: 0.6,
520+
})
521+
const stream = handlerWithTemp.createMessage(systemPrompt, messages)
522+
for await (const _chunk of stream) {
523+
}
524+
expect(mockCreate).toHaveBeenCalled()
525+
const callArgs = mockCreate.mock.calls[0][0]
526+
expect(callArgs.temperature).toBe(0.6)
527+
})
528+
529+
it("should include temperature 0 when modelTemperature is explicitly set to 0 (streaming)", async () => {
530+
const handlerWithZeroTemp = new OpenAiHandler({
531+
...mockOptions,
532+
modelTemperature: 0,
533+
})
534+
const stream = handlerWithZeroTemp.createMessage(systemPrompt, messages)
535+
for await (const _chunk of stream) {
536+
}
537+
expect(mockCreate).toHaveBeenCalled()
538+
const callArgs = mockCreate.mock.calls[0][0]
539+
expect(callArgs.temperature).toBe(0)
540+
})
541+
542+
it("should omit temperature when modelTemperature is not set (non-streaming)", async () => {
543+
const handlerNoTemp = new OpenAiHandler({
544+
...mockOptions,
545+
openAiStreamingEnabled: false,
546+
})
547+
const stream = handlerNoTemp.createMessage(systemPrompt, messages)
548+
for await (const _chunk of stream) {
549+
}
550+
expect(mockCreate).toHaveBeenCalled()
551+
const callArgs = mockCreate.mock.calls[0][0]
552+
expect(callArgs).not.toHaveProperty("temperature")
553+
})
554+
555+
it("should include temperature when modelTemperature is explicitly set (non-streaming)", async () => {
556+
const handlerWithTemp = new OpenAiHandler({
557+
...mockOptions,
558+
openAiStreamingEnabled: false,
559+
modelTemperature: 0.6,
560+
})
561+
const stream = handlerWithTemp.createMessage(systemPrompt, messages)
562+
for await (const _chunk of stream) {
563+
}
564+
expect(mockCreate).toHaveBeenCalled()
565+
const callArgs = mockCreate.mock.calls[0][0]
566+
expect(callArgs.temperature).toBe(0.6)
567+
})
500568
})
501569

502570
describe("error handling", () => {
@@ -632,7 +700,6 @@ describe("OpenAiHandler", () => {
632700
],
633701
stream: true,
634702
stream_options: { include_usage: true },
635-
temperature: 0,
636703
tools: undefined,
637704
tool_choice: undefined,
638705
parallel_tool_calls: true,

src/api/providers/openai.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,13 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
154154

155155
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
156156
model: modelId,
157-
temperature: this.options.modelTemperature ?? (deepseekReasoner ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
157+
// Only include temperature when explicitly configured or for deepseek reasoner models.
158+
// Omitting it lets OpenAI-compatible APIs (e.g. Kimi) use their own model-specific defaults.
159+
...(this.options.modelTemperature != null
160+
? { temperature: this.options.modelTemperature }
161+
: deepseekReasoner
162+
? { temperature: DEEP_SEEK_DEFAULT_TEMPERATURE }
163+
: {}),
158164
messages: convertedMessages,
159165
stream: true as const,
160166
...(isGrokXAI ? {} : { stream_options: { include_usage: true } }),
@@ -223,6 +229,13 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
223229
} else {
224230
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
225231
model: modelId,
232+
// Only include temperature when explicitly configured or for deepseek reasoner models.
233+
// Omitting it lets OpenAI-compatible APIs (e.g. Kimi) use their own model-specific defaults.
234+
...(this.options.modelTemperature != null
235+
? { temperature: this.options.modelTemperature }
236+
: deepseekReasoner
237+
? { temperature: DEEP_SEEK_DEFAULT_TEMPERATURE }
238+
: {}),
226239
messages: deepseekReasoner
227240
? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
228241
: [systemMessage, ...convertToOpenAiMessages(messages)],

0 commit comments

Comments
 (0)