mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat(gemini): add minimal and medium reasoning effort levels (#9973)
Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: cte <cestreich@gmail.com>
This commit is contained in:
parent
0cf5b28569
commit
048e7f3502
3 changed files with 214 additions and 4 deletions
5
.changeset/silly-cycles-enjoy.md
Normal file
5
.changeset/silly-cycles-enjoy.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"roo-cline": patch
|
||||
---
|
||||
|
||||
Adds support for minimal and medium reasoning effort levels in the Gemini provider implementation
|
||||
|
|
@ -14,6 +14,7 @@ import {
|
|||
OpenAiReasoningParams,
|
||||
RooReasoningParams,
|
||||
GeminiReasoningParams,
|
||||
GeminiThinkingLevel,
|
||||
} from "../reasoning"
|
||||
|
||||
describe("reasoning.ts", () => {
|
||||
|
|
@ -642,6 +643,201 @@ describe("reasoning.ts", () => {
|
|||
const result = getGeminiReasoning(options) as GeminiReasoningParams | undefined
|
||||
expect(result).toEqual({ thinkingLevel: "high", includeThoughts: true })
|
||||
})
|
||||
|
||||
it("should return thinkingLevel for minimal effort", () => {
|
||||
const geminiModel: ModelInfo = {
|
||||
...baseModel,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"] as ModelInfo["supportsReasoningEffort"],
|
||||
reasoningEffort: "high",
|
||||
}
|
||||
|
||||
const settings: ProviderSettings = {
|
||||
apiProvider: "gemini",
|
||||
reasoningEffort: "minimal",
|
||||
}
|
||||
|
||||
const options: GetModelReasoningOptions = {
|
||||
model: geminiModel,
|
||||
reasoningBudget: undefined,
|
||||
reasoningEffort: "minimal",
|
||||
settings,
|
||||
}
|
||||
|
||||
const result = getGeminiReasoning(options) as GeminiReasoningParams | undefined
|
||||
expect(result).toEqual({ thinkingLevel: "minimal", includeThoughts: true })
|
||||
})
|
||||
|
||||
it("should return thinkingLevel for medium effort", () => {
|
||||
const geminiModel: ModelInfo = {
|
||||
...baseModel,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"] as ModelInfo["supportsReasoningEffort"],
|
||||
reasoningEffort: "low",
|
||||
}
|
||||
|
||||
const settings: ProviderSettings = {
|
||||
apiProvider: "gemini",
|
||||
reasoningEffort: "medium",
|
||||
}
|
||||
|
||||
const options: GetModelReasoningOptions = {
|
||||
model: geminiModel,
|
||||
reasoningBudget: undefined,
|
||||
reasoningEffort: "medium",
|
||||
settings,
|
||||
}
|
||||
|
||||
const result = getGeminiReasoning(options) as GeminiReasoningParams | undefined
|
||||
expect(result).toEqual({ thinkingLevel: "medium", includeThoughts: true })
|
||||
})
|
||||
|
||||
it("should handle all four Gemini thinking levels", () => {
|
||||
const levels: GeminiThinkingLevel[] = ["minimal", "low", "medium", "high"]
|
||||
|
||||
levels.forEach((level) => {
|
||||
const geminiModel: ModelInfo = {
|
||||
...baseModel,
|
||||
supportsReasoningEffort: [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
] as ModelInfo["supportsReasoningEffort"],
|
||||
reasoningEffort: "low",
|
||||
}
|
||||
|
||||
const settings: ProviderSettings = {
|
||||
apiProvider: "gemini",
|
||||
reasoningEffort: level,
|
||||
}
|
||||
|
||||
const options: GetModelReasoningOptions = {
|
||||
model: geminiModel,
|
||||
reasoningBudget: undefined,
|
||||
reasoningEffort: level,
|
||||
settings,
|
||||
}
|
||||
|
||||
const result = getGeminiReasoning(options) as GeminiReasoningParams | undefined
|
||||
expect(result).toEqual({ thinkingLevel: level, includeThoughts: true })
|
||||
})
|
||||
})
|
||||
|
||||
it("should return undefined for disable effort", () => {
|
||||
const geminiModel: ModelInfo = {
|
||||
...baseModel,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"] as ModelInfo["supportsReasoningEffort"],
|
||||
reasoningEffort: "low",
|
||||
}
|
||||
|
||||
const settings: ProviderSettings = {
|
||||
apiProvider: "gemini",
|
||||
reasoningEffort: "disable",
|
||||
}
|
||||
|
||||
const options: GetModelReasoningOptions = {
|
||||
model: geminiModel,
|
||||
reasoningBudget: undefined,
|
||||
reasoningEffort: "disable",
|
||||
settings,
|
||||
}
|
||||
|
||||
const result = getGeminiReasoning(options)
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should return undefined for none effort (invalid for Gemini)", () => {
|
||||
const geminiModel: ModelInfo = {
|
||||
...baseModel,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"] as ModelInfo["supportsReasoningEffort"],
|
||||
reasoningEffort: "low",
|
||||
}
|
||||
|
||||
const settings: ProviderSettings = {
|
||||
apiProvider: "gemini",
|
||||
reasoningEffort: "none",
|
||||
}
|
||||
|
||||
const options: GetModelReasoningOptions = {
|
||||
model: geminiModel,
|
||||
reasoningBudget: undefined,
|
||||
reasoningEffort: "none",
|
||||
settings,
|
||||
}
|
||||
|
||||
const result = getGeminiReasoning(options)
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should use thinkingBudget for budget-based models", () => {
|
||||
const geminiModel: ModelInfo = {
|
||||
...baseModel,
|
||||
supportsReasoningBudget: true,
|
||||
requiredReasoningBudget: true,
|
||||
}
|
||||
|
||||
const settings: ProviderSettings = {
|
||||
apiProvider: "gemini",
|
||||
enableReasoningEffort: true,
|
||||
}
|
||||
|
||||
const options: GetModelReasoningOptions = {
|
||||
model: geminiModel,
|
||||
reasoningBudget: 4096,
|
||||
reasoningEffort: "high",
|
||||
settings,
|
||||
}
|
||||
|
||||
const result = getGeminiReasoning(options) as GeminiReasoningParams | undefined
|
||||
expect(result).toEqual({ thinkingBudget: 4096, includeThoughts: true })
|
||||
})
|
||||
|
||||
it("should prioritize budget over effort when model has requiredReasoningBudget", () => {
|
||||
const geminiModel: ModelInfo = {
|
||||
...baseModel,
|
||||
supportsReasoningBudget: true,
|
||||
requiredReasoningBudget: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"] as ModelInfo["supportsReasoningEffort"],
|
||||
}
|
||||
|
||||
const settings: ProviderSettings = {
|
||||
apiProvider: "gemini",
|
||||
enableReasoningEffort: true,
|
||||
reasoningEffort: "high",
|
||||
}
|
||||
|
||||
const options: GetModelReasoningOptions = {
|
||||
model: geminiModel,
|
||||
reasoningBudget: 8192,
|
||||
reasoningEffort: "high",
|
||||
settings,
|
||||
}
|
||||
|
||||
const result = getGeminiReasoning(options) as GeminiReasoningParams | undefined
|
||||
// Budget should take precedence
|
||||
expect(result).toEqual({ thinkingBudget: 8192, includeThoughts: true })
|
||||
})
|
||||
|
||||
it("should fall back to model default effort when settings.reasoningEffort is undefined", () => {
|
||||
const geminiModel: ModelInfo = {
|
||||
...baseModel,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"] as ModelInfo["supportsReasoningEffort"],
|
||||
reasoningEffort: "medium",
|
||||
}
|
||||
|
||||
const settings: ProviderSettings = {
|
||||
apiProvider: "gemini",
|
||||
}
|
||||
|
||||
const options: GetModelReasoningOptions = {
|
||||
model: geminiModel,
|
||||
reasoningBudget: undefined,
|
||||
reasoningEffort: undefined,
|
||||
settings,
|
||||
}
|
||||
|
||||
const result = getGeminiReasoning(options) as GeminiReasoningParams | undefined
|
||||
expect(result).toEqual({ thinkingLevel: "medium", includeThoughts: true })
|
||||
})
|
||||
})
|
||||
|
||||
describe("Integration scenarios", () => {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,17 @@ export type AnthropicReasoningParams = BetaThinkingConfigParam
|
|||
|
||||
export type OpenAiReasoningParams = { reasoning_effort: OpenAI.Chat.ChatCompletionCreateParams["reasoning_effort"] }
|
||||
|
||||
// Valid Gemini thinking levels for effort-based reasoning
|
||||
const GEMINI_THINKING_LEVELS = ["minimal", "low", "medium", "high"] as const
|
||||
|
||||
export type GeminiThinkingLevel = (typeof GEMINI_THINKING_LEVELS)[number]
|
||||
|
||||
export function isGeminiThinkingLevel(value: unknown): value is GeminiThinkingLevel {
|
||||
return typeof value === "string" && GEMINI_THINKING_LEVELS.includes(value as GeminiThinkingLevel)
|
||||
}
|
||||
|
||||
export type GeminiReasoningParams = GenerateContentConfig["thinkingConfig"] & {
|
||||
thinkingLevel?: "low" | "high"
|
||||
thinkingLevel?: GeminiThinkingLevel
|
||||
}
|
||||
|
||||
export type GetModelReasoningOptions = {
|
||||
|
|
@ -136,13 +145,13 @@ export const getGeminiReasoning = ({
|
|||
| "disable"
|
||||
| undefined
|
||||
|
||||
// Respect “off” / unset semantics from the effort selector itself.
|
||||
// Respect "off" / unset semantics from the effort selector itself.
|
||||
if (!selectedEffort || selectedEffort === "disable") {
|
||||
return undefined
|
||||
}
|
||||
|
||||
// Effort-based models on Google GenAI currently support only explicit low/high levels.
|
||||
if (selectedEffort !== "low" && selectedEffort !== "high") {
|
||||
// Effort-based models on Google GenAI support minimal/low/medium/high levels.
|
||||
if (!isGeminiThinkingLevel(selectedEffort)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue