mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
fix: add thinking parameter for OpenAI-compatible APIs when supportsReasoningBinary is true
Fixes #11001 When using OpenAI-compatible APIs like volcengine Ark API with reasoning effort enabled, the API requires both: 1. reasoning_effort parameter (e.g., "medium") 2. thinking parameter set to { type: "enabled" } This change adds the thinking parameter when: - Reasoning effort is being used (reasoning object is present), AND - The model's supportsReasoningBinary flag is true The fix is applied to both: - createMessage method (for regular models with streaming) - handleO3FamilyMessage method (for O3 family models) Users can enable this by setting supportsReasoningBinary: true in their custom model info configuration.
This commit is contained in:
parent
d748de6fae
commit
19bd598a78
2 changed files with 155 additions and 0 deletions
|
|
@ -374,6 +374,54 @@ describe("OpenAiHandler", () => {
|
|||
expect(callArgs.reasoning_effort).toBe("high")
|
||||
})
|
||||
|
||||
it("should include thinking parameter when supportsReasoningBinary is true and reasoning effort is enabled", async () => {
|
||||
const reasoningBinaryOptions: ApiHandlerOptions = {
|
||||
...mockOptions,
|
||||
enableReasoningEffort: true,
|
||||
openAiCustomModelInfo: {
|
||||
contextWindow: 128_000,
|
||||
supportsPromptCache: false,
|
||||
supportsReasoningEffort: true,
|
||||
supportsReasoningBinary: true,
|
||||
reasoningEffort: "medium",
|
||||
},
|
||||
}
|
||||
const reasoningBinaryHandler = new OpenAiHandler(reasoningBinaryOptions)
|
||||
const stream = reasoningBinaryHandler.createMessage(systemPrompt, messages)
|
||||
// Consume the stream to trigger the API call
|
||||
for await (const _chunk of stream) {
|
||||
}
|
||||
// Assert the mockCreate was called with both reasoning_effort and thinking
|
||||
expect(mockCreate).toHaveBeenCalled()
|
||||
const callArgs = mockCreate.mock.calls[0][0]
|
||||
expect(callArgs.reasoning_effort).toBe("medium")
|
||||
expect(callArgs.thinking).toEqual({ type: "enabled" })
|
||||
})
|
||||
|
||||
it("should not include thinking parameter when supportsReasoningBinary is false even with reasoning effort enabled", async () => {
|
||||
const noReasoningBinaryOptions: ApiHandlerOptions = {
|
||||
...mockOptions,
|
||||
enableReasoningEffort: true,
|
||||
openAiCustomModelInfo: {
|
||||
contextWindow: 128_000,
|
||||
supportsPromptCache: false,
|
||||
supportsReasoningEffort: true,
|
||||
supportsReasoningBinary: false,
|
||||
reasoningEffort: "high",
|
||||
},
|
||||
}
|
||||
const noReasoningBinaryHandler = new OpenAiHandler(noReasoningBinaryOptions)
|
||||
const stream = noReasoningBinaryHandler.createMessage(systemPrompt, messages)
|
||||
// Consume the stream to trigger the API call
|
||||
for await (const _chunk of stream) {
|
||||
}
|
||||
// Assert the mockCreate was called with reasoning_effort but NOT thinking
|
||||
expect(mockCreate).toHaveBeenCalled()
|
||||
const callArgs = mockCreate.mock.calls[0][0]
|
||||
expect(callArgs.reasoning_effort).toBe("high")
|
||||
expect(callArgs.thinking).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should not include reasoning_effort when reasoning effort is disabled", async () => {
|
||||
const noReasoningOptions: ApiHandlerOptions = {
|
||||
...mockOptions,
|
||||
|
|
@ -1138,6 +1186,103 @@ describe("OpenAiHandler", () => {
|
|||
{ path: "/models/chat/completions" },
|
||||
)
|
||||
})
|
||||
|
||||
it("should include thinking parameter for O3 model when supportsReasoningBinary is true", async () => {
|
||||
const o3ReasoningBinaryHandler = new OpenAiHandler({
|
||||
...mockOptions,
|
||||
openAiModelId: "o3-mini",
|
||||
openAiCustomModelInfo: {
|
||||
contextWindow: 128_000,
|
||||
maxTokens: 65536,
|
||||
supportsPromptCache: false,
|
||||
reasoningEffort: "medium" as "low" | "medium" | "high",
|
||||
supportsReasoningBinary: true,
|
||||
},
|
||||
})
|
||||
const systemPrompt = "You are a helpful assistant."
|
||||
const messages: Anthropic.Messages.MessageParam[] = [
|
||||
{
|
||||
role: "user",
|
||||
content: "Hello!",
|
||||
},
|
||||
]
|
||||
|
||||
const stream = o3ReasoningBinaryHandler.createMessage(systemPrompt, messages)
|
||||
const chunks: any[] = []
|
||||
for await (const chunk of stream) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
expect(mockCreate).toHaveBeenCalled()
|
||||
const callArgs = mockCreate.mock.calls[0][0]
|
||||
expect(callArgs.reasoning_effort).toBe("medium")
|
||||
expect(callArgs.thinking).toEqual({ type: "enabled" })
|
||||
})
|
||||
|
||||
it("should not include thinking parameter for O3 model when supportsReasoningBinary is false", async () => {
|
||||
const o3NoReasoningBinaryHandler = new OpenAiHandler({
|
||||
...mockOptions,
|
||||
openAiModelId: "o3-mini",
|
||||
openAiCustomModelInfo: {
|
||||
contextWindow: 128_000,
|
||||
maxTokens: 65536,
|
||||
supportsPromptCache: false,
|
||||
reasoningEffort: "high" as "low" | "medium" | "high",
|
||||
supportsReasoningBinary: false,
|
||||
},
|
||||
})
|
||||
const systemPrompt = "You are a helpful assistant."
|
||||
const messages: Anthropic.Messages.MessageParam[] = [
|
||||
{
|
||||
role: "user",
|
||||
content: "Hello!",
|
||||
},
|
||||
]
|
||||
|
||||
const stream = o3NoReasoningBinaryHandler.createMessage(systemPrompt, messages)
|
||||
const chunks: any[] = []
|
||||
for await (const chunk of stream) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
expect(mockCreate).toHaveBeenCalled()
|
||||
const callArgs = mockCreate.mock.calls[0][0]
|
||||
expect(callArgs.reasoning_effort).toBe("high")
|
||||
expect(callArgs.thinking).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should include thinking parameter for O3 model in non-streaming mode when supportsReasoningBinary is true", async () => {
|
||||
const o3NonStreamingHandler = new OpenAiHandler({
|
||||
...mockOptions,
|
||||
openAiModelId: "o3-mini",
|
||||
openAiStreamingEnabled: false,
|
||||
openAiCustomModelInfo: {
|
||||
contextWindow: 128_000,
|
||||
maxTokens: 65536,
|
||||
supportsPromptCache: false,
|
||||
reasoningEffort: "low" as "low" | "medium" | "high",
|
||||
supportsReasoningBinary: true,
|
||||
},
|
||||
})
|
||||
const systemPrompt = "You are a helpful assistant."
|
||||
const messages: Anthropic.Messages.MessageParam[] = [
|
||||
{
|
||||
role: "user",
|
||||
content: "Hello!",
|
||||
},
|
||||
]
|
||||
|
||||
const stream = o3NonStreamingHandler.createMessage(systemPrompt, messages)
|
||||
const chunks: any[] = []
|
||||
for await (const chunk of stream) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
expect(mockCreate).toHaveBeenCalled()
|
||||
const callArgs = mockCreate.mock.calls[0][0]
|
||||
expect(callArgs.reasoning_effort).toBe("low")
|
||||
expect(callArgs.thinking).toEqual({ type: "enabled" })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -159,6 +159,8 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
|
|||
stream: true as const,
|
||||
...(isGrokXAI ? {} : { stream_options: { include_usage: true } }),
|
||||
...(reasoning && reasoning),
|
||||
// Add thinking parameter for OpenAI-compatible APIs that require it when using reasoning effort
|
||||
...(reasoning && modelInfo.supportsReasoningBinary ? { thinking: { type: "enabled" } } : {}),
|
||||
tools: this.convertToolsForOpenAI(metadata?.tools),
|
||||
tool_choice: metadata?.tool_choice,
|
||||
parallel_tool_calls: metadata?.parallelToolCalls ?? false,
|
||||
|
|
@ -344,6 +346,10 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
|
|||
stream: true,
|
||||
...(isGrokXAI ? {} : { stream_options: { include_usage: true } }),
|
||||
reasoning_effort: modelInfo.reasoningEffort as "low" | "medium" | "high" | undefined,
|
||||
// Add thinking parameter for OpenAI-compatible APIs that require it when using reasoning effort
|
||||
...(modelInfo.reasoningEffort && modelInfo.supportsReasoningBinary
|
||||
? { thinking: { type: "enabled" } }
|
||||
: {}),
|
||||
temperature: undefined,
|
||||
// Tools are always present (minimum ALWAYS_AVAILABLE_TOOLS)
|
||||
tools: this.convertToolsForOpenAI(metadata?.tools),
|
||||
|
|
@ -378,6 +384,10 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
|
|||
...convertToOpenAiMessages(messages),
|
||||
],
|
||||
reasoning_effort: modelInfo.reasoningEffort as "low" | "medium" | "high" | undefined,
|
||||
// Add thinking parameter for OpenAI-compatible APIs that require it when using reasoning effort
|
||||
...(modelInfo.reasoningEffort && modelInfo.supportsReasoningBinary
|
||||
? { thinking: { type: "enabled" } }
|
||||
: {}),
|
||||
temperature: undefined,
|
||||
// Tools are always present (minimum ALWAYS_AVAILABLE_TOOLS)
|
||||
tools: this.convertToolsForOpenAI(metadata?.tools),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue