diff --git a/.changeset/friendly-yaks-float.md b/.changeset/friendly-yaks-float.md new file mode 100644 index 00000000000..04a0958c4ba --- /dev/null +++ b/.changeset/friendly-yaks-float.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Prevent sending thinkingLevel to unsupporting Gemini models diff --git a/src/api/transform/__tests__/reasoning.spec.ts b/src/api/transform/__tests__/reasoning.spec.ts index 352aac8e7bb..fb60d2f8bcd 100644 --- a/src/api/transform/__tests__/reasoning.spec.ts +++ b/src/api/transform/__tests__/reasoning.spec.ts @@ -838,6 +838,65 @@ describe("reasoning.ts", () => { const result = getGeminiReasoning(options) as GeminiReasoningParams | undefined expect(result).toEqual({ thinkingLevel: "medium", includeThoughts: true }) }) + + // kilocode_change start + it("should return undefined for budget-only models when budget is not enabled (fixes issue #4490)", () => { + // This test covers the bug where gemini-2.5-flash would fail with + // "Thinking level is not supported for this model" because thinkingLevel + // was being sent to a model that only supports thinkingBudget + const geminiFlashModel: ModelInfo = { + ...baseModel, + // gemini-2.5-flash supports budget but NOT effort-based reasoning + supportsReasoningBudget: true, + // Note: no supportsReasoningEffort, no requiredReasoningBudget + } + + const settings: ProviderSettings = { + apiProvider: "gemini", + // User may have a reasoningEffort set from a different model + reasoningEffort: "high", + // But enableReasoningEffort is not true, so budget won't be used + } + + const options: GetModelReasoningOptions = { + model: geminiFlashModel, + reasoningBudget: 4096, + reasoningEffort: "high", + settings, + } + + const result = getGeminiReasoning(options) + // Should return undefined, NOT { thinkingLevel: "high", includeThoughts: true } + // because this model doesn't support thinkingLevel + expect(result).toBeUndefined() + }) + + it("should return undefined for budget-only models even with explicit effort setting", () => { + // Models like gemini-2.5-flash only support budget-based reasoning + const budgetOnlyModel: ModelInfo = { + ...baseModel, + supportsReasoningBudget: true, + maxThinkingTokens: 24576, + // Critically: no supportsReasoningEffort + } + + const settings: ProviderSettings = { + apiProvider: "gemini", + reasoningEffort: "medium", + } + + const options: GetModelReasoningOptions = { + model: budgetOnlyModel, + reasoningBudget: 8192, + reasoningEffort: "medium", + settings, + } + + const result = getGeminiReasoning(options) + // Must not send thinkingLevel to a model that doesn't support it + expect(result).toBeUndefined() + }) + // kilocode_change end }) describe("Integration scenarios", () => { diff --git a/src/api/transform/reasoning.ts b/src/api/transform/reasoning.ts index 552f2de582b..201f7c28a6a 100644 --- a/src/api/transform/reasoning.ts +++ b/src/api/transform/reasoning.ts @@ -147,6 +147,12 @@ export const getGeminiReasoning = ({ return { thinkingBudget: reasoningBudget!, includeThoughts: true } } + // kilocode_change start + if (!model.supportsReasoningEffort) { + return undefined + } + // kilocode_change end + // For effort-based Gemini models, rely directly on the selected effort value. // We intentionally ignore enableReasoningEffort here so that explicitly chosen // efforts in the UI (e.g. "High" for gemini-3-pro-preview) always translate