diff --git a/src/providers/gemini.rs b/src/providers/gemini.rs index a6487934..b61ceb2c 100644 --- a/src/providers/gemini.rs +++ b/src/providers/gemini.rs @@ -454,7 +454,16 @@ impl super::Provider for GeminiProvider { } async fn chat_completion(&self, request: UnifiedRequest) -> Result { - let model = request.model.clone(); + let mut model = request.model.clone(); + + // Normalize model name: If it's a known Gemini model, use it; + // otherwise, if it starts with gemini- but is unknown (e.g. gemini-3-flash-preview), + // fallback to the default model to avoid 400 errors. + if !model.starts_with("gemini-1.5") && !model.starts_with("gemini-2.0") && model.starts_with("gemini-") { + tracing::info!("Mapping unknown Gemini model {} to default {}", model, self.config.default_model); + model = self.config.default_model.clone(); + } + let tools = Self::convert_tools(&request); let tool_config = Self::convert_tool_config(&request); let (contents, system_instruction) = Self::convert_messages(request.messages.clone()).await?; @@ -464,9 +473,13 @@ impl super::Provider for GeminiProvider { } let generation_config = if request.temperature.is_some() || request.max_tokens.is_some() { + // Some Gemini models (especially 1.5) have lower max_output_tokens limits (e.g. 8192) + // than what clients like opencode might request. Clamp to a safe maximum. + let max_tokens = request.max_tokens.map(|t| t.min(8192)); + Some(GeminiGenerationConfig { temperature: request.temperature, - max_output_tokens: request.max_tokens, + max_output_tokens: max_tokens, }) } else { None @@ -579,7 +592,14 @@ impl super::Provider for GeminiProvider { &self, request: UnifiedRequest, ) -> Result>, AppError> { - let model = request.model.clone(); + let mut model = request.model.clone(); + + // Normalize model name: fallback to default if unknown Gemini model is requested + if !model.starts_with("gemini-1.5") && !model.starts_with("gemini-2.0") && model.starts_with("gemini-") { + tracing::info!("Mapping unknown Gemini model {} to default {}", model, self.config.default_model); + model = self.config.default_model.clone(); + } + let tools = Self::convert_tools(&request); let tool_config = Self::convert_tool_config(&request); let (contents, system_instruction) = Self::convert_messages(request.messages.clone()).await?; @@ -589,9 +609,13 @@ impl super::Provider for GeminiProvider { } let generation_config = if request.temperature.is_some() || request.max_tokens.is_some() { + // Some Gemini models (especially 1.5) have lower max_output_tokens limits (e.g. 8192) + // than what clients like opencode might request. Clamp to a safe maximum. + let max_tokens = request.max_tokens.map(|t| t.min(8192)); + Some(GeminiGenerationConfig { temperature: request.temperature, - max_output_tokens: request.max_tokens, + max_output_tokens: max_tokens, }) } else { None