This commit is contained in:
roomote-v0[bot] 2026-04-24 11:33:16 +01:00 committed by GitHub
commit 1a05bd3b3f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 82 additions and 2 deletions

View file

@ -497,6 +497,74 @@ describe("OpenAiHandler", () => {
const callArgs = mockCreate.mock.calls[0][0]
expect(callArgs.max_completion_tokens).toBe(4096)
})
it("should omit temperature when modelTemperature is not set (streaming)", async () => {
// When no custom temperature is configured, temperature should not be sent
// so that OpenAI-compatible APIs (e.g. Kimi) can use their own defaults
const handlerNoTemp = new OpenAiHandler({
...mockOptions,
// modelTemperature is not set (undefined)
})
const stream = handlerNoTemp.createMessage(systemPrompt, messages)
for await (const _chunk of stream) {
}
expect(mockCreate).toHaveBeenCalled()
const callArgs = mockCreate.mock.calls[0][0]
expect(callArgs).not.toHaveProperty("temperature")
})
it("should include temperature when modelTemperature is explicitly set (streaming)", async () => {
const handlerWithTemp = new OpenAiHandler({
...mockOptions,
modelTemperature: 0.6,
})
const stream = handlerWithTemp.createMessage(systemPrompt, messages)
for await (const _chunk of stream) {
}
expect(mockCreate).toHaveBeenCalled()
const callArgs = mockCreate.mock.calls[0][0]
expect(callArgs.temperature).toBe(0.6)
})
it("should include temperature 0 when modelTemperature is explicitly set to 0 (streaming)", async () => {
const handlerWithZeroTemp = new OpenAiHandler({
...mockOptions,
modelTemperature: 0,
})
const stream = handlerWithZeroTemp.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 omit temperature when modelTemperature is not set (non-streaming)", async () => {
const handlerNoTemp = new OpenAiHandler({
...mockOptions,
openAiStreamingEnabled: false,
})
const stream = handlerNoTemp.createMessage(systemPrompt, messages)
for await (const _chunk of stream) {
}
expect(mockCreate).toHaveBeenCalled()
const callArgs = mockCreate.mock.calls[0][0]
expect(callArgs).not.toHaveProperty("temperature")
})
it("should include temperature when modelTemperature is explicitly set (non-streaming)", async () => {
const handlerWithTemp = new OpenAiHandler({
...mockOptions,
openAiStreamingEnabled: false,
modelTemperature: 0.6,
})
const stream = handlerWithTemp.createMessage(systemPrompt, messages)
for await (const _chunk of stream) {
}
expect(mockCreate).toHaveBeenCalled()
const callArgs = mockCreate.mock.calls[0][0]
expect(callArgs.temperature).toBe(0.6)
})
})
describe("error handling", () => {
@ -632,7 +700,6 @@ describe("OpenAiHandler", () => {
],
stream: true,
stream_options: { include_usage: true },
temperature: 0,
tools: undefined,
tool_choice: undefined,
parallel_tool_calls: true,

View file

@ -154,7 +154,13 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
model: modelId,
temperature: this.options.modelTemperature ?? (deepseekReasoner ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
// Only include temperature when explicitly configured or for deepseek reasoner models.
// Omitting it lets OpenAI-compatible APIs (e.g. Kimi) use their own model-specific defaults.
...(this.options.modelTemperature != null
? { temperature: this.options.modelTemperature }
: deepseekReasoner
? { temperature: DEEP_SEEK_DEFAULT_TEMPERATURE }
: {}),
messages: convertedMessages,
stream: true as const,
...(isGrokXAI ? {} : { stream_options: { include_usage: true } }),
@ -223,6 +229,13 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
} else {
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
model: modelId,
// Only include temperature when explicitly configured or for deepseek reasoner models.
// Omitting it lets OpenAI-compatible APIs (e.g. Kimi) use their own model-specific defaults.
...(this.options.modelTemperature != null
? { temperature: this.options.modelTemperature }
: deepseekReasoner
? { temperature: DEEP_SEEK_DEFAULT_TEMPERATURE }
: {}),
messages: deepseekReasoner
? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
: [systemMessage, ...convertToOpenAiMessages(messages)],