mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: support simple on/off reasoning toggle for grok-4-fast on OpenRouter
- Added special handling for x-ai/grok-4-fast model in OpenRouter parser - Disabled reasoning effort for this model while keeping reasoning parameter - Updated reasoning logic to handle models with simple on/off toggle - Added comprehensive tests for the new functionality Fixes #8709
This commit is contained in:
parent
f30caf277c
commit
22e9b98ccf
4 changed files with 193 additions and 8 deletions
|
|
@ -386,5 +386,76 @@ describe("OpenRouter API", () => {
|
|||
expect(textResult.maxTokens).toBe(64000)
|
||||
expect(imageResult.maxTokens).toBe(64000)
|
||||
})
|
||||
|
||||
it("handles grok-4-fast reasoning correctly", () => {
|
||||
const mockModel = {
|
||||
name: "Grok 4 Fast",
|
||||
context_length: 32768,
|
||||
max_completion_tokens: 8192,
|
||||
}
|
||||
|
||||
// Test with reasoning in supported parameters
|
||||
const resultWithReasoning = parseOpenRouterModel({
|
||||
id: "x-ai/grok-4-fast",
|
||||
model: mockModel,
|
||||
inputModality: ["text"],
|
||||
outputModality: ["text"],
|
||||
maxTokens: 8192,
|
||||
supportedParameters: ["temperature", "max_tokens", "reasoning"],
|
||||
})
|
||||
|
||||
expect(resultWithReasoning.supportsReasoningEffort).toBe(false)
|
||||
expect(resultWithReasoning.supportedParameters).toContain("reasoning")
|
||||
expect(resultWithReasoning.supportedParameters).toContain("temperature")
|
||||
expect(resultWithReasoning.supportedParameters).toContain("max_tokens")
|
||||
|
||||
// Test without reasoning in supported parameters - should add it
|
||||
const resultWithoutReasoning = parseOpenRouterModel({
|
||||
id: "x-ai/grok-4-fast",
|
||||
model: mockModel,
|
||||
inputModality: ["text"],
|
||||
outputModality: ["text"],
|
||||
maxTokens: 8192,
|
||||
supportedParameters: ["temperature", "max_tokens"],
|
||||
})
|
||||
|
||||
expect(resultWithoutReasoning.supportsReasoningEffort).toBe(false)
|
||||
expect(resultWithoutReasoning.supportedParameters).toContain("reasoning")
|
||||
expect(resultWithoutReasoning.supportedParameters).toContain("temperature")
|
||||
expect(resultWithoutReasoning.supportedParameters).toContain("max_tokens")
|
||||
|
||||
// Test with undefined supported parameters
|
||||
const resultNoParams = parseOpenRouterModel({
|
||||
id: "x-ai/grok-4-fast",
|
||||
model: mockModel,
|
||||
inputModality: ["text"],
|
||||
outputModality: ["text"],
|
||||
maxTokens: 8192,
|
||||
})
|
||||
|
||||
expect(resultNoParams.supportsReasoningEffort).toBe(false)
|
||||
expect(resultNoParams.supportedParameters).toContain("reasoning")
|
||||
})
|
||||
|
||||
it("does not affect other models reasoning configuration", () => {
|
||||
const mockModel = {
|
||||
name: "Other Model",
|
||||
context_length: 32768,
|
||||
max_completion_tokens: 8192,
|
||||
}
|
||||
|
||||
const result = parseOpenRouterModel({
|
||||
id: "other/model",
|
||||
model: mockModel,
|
||||
inputModality: ["text"],
|
||||
outputModality: ["text"],
|
||||
maxTokens: 8192,
|
||||
supportedParameters: ["temperature", "max_tokens", "reasoning"],
|
||||
})
|
||||
|
||||
// Should not modify supportsReasoningEffort for other models
|
||||
expect(result.supportsReasoningEffort).toBe(true)
|
||||
expect(result.supportedParameters).toContain("reasoning")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -270,5 +270,16 @@ export const parseOpenRouterModel = ({
|
|||
modelInfo.maxTokens = 32768
|
||||
}
|
||||
|
||||
// Special handling for grok-4-fast on OpenRouter - it should use simple on/off reasoning toggle
|
||||
// instead of reasoning effort levels (low/medium/high)
|
||||
if (id === "x-ai/grok-4-fast") {
|
||||
// Disable reasoning effort but keep reasoning in supportedParameters for on/off toggle
|
||||
modelInfo.supportsReasoningEffort = false
|
||||
// Ensure reasoning is in supportedParameters
|
||||
if (!supportedParameters || !supportedParameters.includes("reasoning")) {
|
||||
modelInfo.supportedParameters = [...(modelInfo.supportedParameters || []), "reasoning"]
|
||||
}
|
||||
}
|
||||
|
||||
return modelInfo
|
||||
}
|
||||
|
|
|
|||
|
|
@ -284,6 +284,89 @@ describe("reasoning.ts", () => {
|
|||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should handle models with simple on/off reasoning toggle (like grok-4-fast)", () => {
|
||||
// Model with reasoning support but no effort or budget capabilities
|
||||
const modelWithSimpleToggle: ModelInfo = {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 32768,
|
||||
supportsPromptCache: false,
|
||||
supportedParameters: ["reasoning"],
|
||||
supportsReasoningEffort: false,
|
||||
supportsReasoningBudget: false,
|
||||
}
|
||||
|
||||
// Test with reasoning enabled (not minimal)
|
||||
const optionsWithReasoningEnabled = {
|
||||
...baseOptions,
|
||||
model: modelWithSimpleToggle,
|
||||
reasoningEffort: "high" as ReasoningEffortWithMinimal,
|
||||
}
|
||||
|
||||
const resultEnabled = getOpenRouterReasoning(optionsWithReasoningEnabled)
|
||||
expect(resultEnabled).toEqual({ exclude: false })
|
||||
|
||||
// Test with reasoning disabled (minimal)
|
||||
const optionsWithReasoningDisabled = {
|
||||
...baseOptions,
|
||||
model: modelWithSimpleToggle,
|
||||
reasoningEffort: "minimal" as ReasoningEffortWithMinimal,
|
||||
}
|
||||
|
||||
const resultDisabled = getOpenRouterReasoning(optionsWithReasoningDisabled)
|
||||
expect(resultDisabled).toEqual({ exclude: true })
|
||||
|
||||
// Test without reasoning effort setting (should enable by default)
|
||||
const optionsWithoutEffort = {
|
||||
...baseOptions,
|
||||
model: modelWithSimpleToggle,
|
||||
}
|
||||
|
||||
const resultDefault = getOpenRouterReasoning(optionsWithoutEffort)
|
||||
expect(resultDefault).toEqual({ exclude: false })
|
||||
})
|
||||
|
||||
it("should not apply simple toggle logic to models with effort or budget capabilities", () => {
|
||||
// Model with reasoning effort capability
|
||||
const modelWithEffort: ModelInfo = {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 32768,
|
||||
supportsPromptCache: false,
|
||||
supportedParameters: ["reasoning"],
|
||||
supportsReasoningEffort: true,
|
||||
}
|
||||
|
||||
const optionsWithEffort = {
|
||||
...baseOptions,
|
||||
model: modelWithEffort,
|
||||
settings: { reasoningEffort: "high" as ReasoningEffortWithMinimal },
|
||||
reasoningEffort: "high" as ReasoningEffortWithMinimal,
|
||||
}
|
||||
|
||||
const resultWithEffort = getOpenRouterReasoning(optionsWithEffort)
|
||||
// Should use effort logic, not simple toggle
|
||||
expect(resultWithEffort).toEqual({ effort: "high" })
|
||||
|
||||
// Model with reasoning budget capability
|
||||
const modelWithBudget: ModelInfo = {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 32768,
|
||||
supportsPromptCache: false,
|
||||
supportedParameters: ["reasoning"],
|
||||
supportsReasoningBudget: true,
|
||||
}
|
||||
|
||||
const optionsWithBudget = {
|
||||
...baseOptions,
|
||||
model: modelWithBudget,
|
||||
settings: { enableReasoningEffort: true },
|
||||
reasoningBudget: 1000,
|
||||
}
|
||||
|
||||
const resultWithBudget = getOpenRouterReasoning(optionsWithBudget)
|
||||
// Should use budget logic, not simple toggle
|
||||
expect(resultWithBudget).toEqual({ max_tokens: 1000 })
|
||||
})
|
||||
})
|
||||
|
||||
describe("getAnthropicReasoning", () => {
|
||||
|
|
|
|||
|
|
@ -30,14 +30,34 @@ export const getOpenRouterReasoning = ({
|
|||
reasoningBudget,
|
||||
reasoningEffort,
|
||||
settings,
|
||||
}: GetModelReasoningOptions): OpenRouterReasoningParams | undefined =>
|
||||
shouldUseReasoningBudget({ model, settings })
|
||||
? { max_tokens: reasoningBudget }
|
||||
: shouldUseReasoningEffort({ model, settings })
|
||||
? reasoningEffort
|
||||
? { effort: reasoningEffort }
|
||||
: undefined
|
||||
: undefined
|
||||
}: GetModelReasoningOptions): OpenRouterReasoningParams | undefined => {
|
||||
// Check if model should use reasoning budget
|
||||
if (shouldUseReasoningBudget({ model, settings })) {
|
||||
return { max_tokens: reasoningBudget }
|
||||
}
|
||||
|
||||
// Check if model should use reasoning effort
|
||||
if (shouldUseReasoningEffort({ model, settings })) {
|
||||
return reasoningEffort ? { effort: reasoningEffort } : undefined
|
||||
}
|
||||
|
||||
// Check if model supports reasoning but not effort or budget (e.g., grok-4-fast on OpenRouter)
|
||||
// These models use a simple on/off toggle via the exclude parameter
|
||||
if (
|
||||
model.supportedParameters?.includes("reasoning") &&
|
||||
!model.supportsReasoningEffort &&
|
||||
!model.supportsReasoningBudget
|
||||
) {
|
||||
// If reasoning is not explicitly disabled, enable it
|
||||
// We use exclude: false to enable reasoning, and exclude: true to disable
|
||||
// Check both settings.reasoningEffort and the passed reasoningEffort parameter
|
||||
const effectiveEffort = reasoningEffort || settings.reasoningEffort
|
||||
const reasoningEnabled = effectiveEffort !== "minimal"
|
||||
return reasoningEnabled ? { exclude: false } : { exclude: true }
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
export const getAnthropicReasoning = ({
|
||||
model,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue