fix: add Gemma 4 models to geminiModels map and stop silent model ID fallback

- Add gemma-4-31b-it, gemma-4-12b-it, gemma-4-6b-it, gemma-4-4b-it,
  and gemma-4-1b-it to the geminiModels map with correct context windows
  and capabilities
- Fix silent fallback in GeminiHandler.getModel() that replaced unknown
  model IDs with geminiDefaultModelId (gemini-3.1-pro-preview)
- Apply the same fix to VertexHandler.getModel()
- Now preserves user-provided model ID and only falls back on model info
- Update tests to verify unknown models are passed through and Gemma 4
  models are natively recognized

Closes #12166
This commit is contained in:
Roo Code 2026-04-22 18:53:14 +00:00
parent c4547d25c5
commit df31ccdf38
4 changed files with 68 additions and 6 deletions

View file

@ -283,4 +283,46 @@ export const geminiModels = {
supportsReasoningBudget: true,
maxThinkingTokens: 24_576,
},
// Gemma 4 models
// https://ai.google.dev/gemma/docs/core
"gemma-4-31b-it": {
maxTokens: 8_192,
contextWindow: 131_072,
supportsImages: true,
supportsPromptCache: false,
inputPrice: 0,
outputPrice: 0,
},
"gemma-4-12b-it": {
maxTokens: 8_192,
contextWindow: 131_072,
supportsImages: true,
supportsPromptCache: false,
inputPrice: 0,
outputPrice: 0,
},
"gemma-4-6b-it": {
maxTokens: 8_192,
contextWindow: 32_768,
supportsImages: true,
supportsPromptCache: false,
inputPrice: 0,
outputPrice: 0,
},
"gemma-4-4b-it": {
maxTokens: 8_192,
contextWindow: 32_768,
supportsImages: true,
supportsPromptCache: false,
inputPrice: 0,
outputPrice: 0,
},
"gemma-4-1b-it": {
maxTokens: 8_192,
contextWindow: 32_768,
supportsImages: false,
supportsPromptCache: false,
inputPrice: 0,
outputPrice: 0,
},
} as const satisfies Record<string, ModelInfo>

View file

@ -165,13 +165,33 @@ describe("GeminiHandler", () => {
expect(modelInfo.info).toBeDefined()
})
it("should return default model if invalid model specified", () => {
it("should preserve unknown model ID instead of silently falling back to default", () => {
const invalidHandler = new GeminiHandler({
apiModelId: "invalid-model",
geminiApiKey: "test-key",
})
const modelInfo = invalidHandler.getModel()
expect(modelInfo.id).toBe(geminiDefaultModelId) // Default model
expect(modelInfo.id).toBe("invalid-model") // Preserves user-provided ID
expect(modelInfo.info).toBeDefined() // Falls back to default model info
})
it("should use default model when no model ID is provided", () => {
const noModelHandler = new GeminiHandler({
geminiApiKey: "test-key",
})
const modelInfo = noModelHandler.getModel()
expect(modelInfo.id).toBe(geminiDefaultModelId)
})
it("should recognize Gemma 4 models natively", () => {
const gemmaHandler = new GeminiHandler({
apiModelId: "gemma-4-31b-it",
geminiApiKey: "test-key",
})
const modelInfo = gemmaHandler.getModel()
expect(modelInfo.id).toBe("gemma-4-31b-it")
expect(modelInfo.info.contextWindow).toBe(131_072)
expect(modelInfo.info.supportsImages).toBe(true)
})
it("should exclude apply_diff and include edit in tool preferences", () => {

View file

@ -348,8 +348,8 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
override getModel() {
const modelId = this.options.apiModelId
let id = modelId && modelId in geminiModels ? (modelId as GeminiModelId) : geminiDefaultModelId
let info: ModelInfo = geminiModels[id]
const id: string = modelId ?? geminiDefaultModelId
let info: ModelInfo = geminiModels[id as GeminiModelId] ?? geminiModels[geminiDefaultModelId]
const params = getModelParams({
format: "gemini",

View file

@ -14,8 +14,8 @@ export class VertexHandler extends GeminiHandler implements SingleCompletionHand
override getModel() {
const modelId = this.options.apiModelId
let id = modelId && modelId in vertexModels ? (modelId as VertexModelId) : vertexDefaultModelId
let info: ModelInfo = vertexModels[id]
const id: string = modelId ?? vertexDefaultModelId
let info: ModelInfo = vertexModels[id as VertexModelId] ?? vertexModels[vertexDefaultModelId]
const params = getModelParams({
format: "gemini",
modelId: id,