google_ai: Add Gemini 3.7 Flash (#62670)
Follow-up to #62010, which added Gemini 3.6 Flash. Google released Gemini 3.7 Flash on August 13, 2026. It keeps the 1 million token context window and the 64k output limit, and supports thinking. Unlike 3.5 and 3.6 Flash, it does not accept `thinking_level: MINIMAL` (the API returns a validation error). So it exposes Low, Medium and High, defaulting to Medium, and `disabled_thinking_level` in `completion.rs` returns Low for it instead of Minimal when the user turns thinking off. The provider builds its model list from `google_ai::Model::iter()`, so adding the enum variant is enough for it to show up in the model dropdown. Release Notes: - Added Gemini 3.7 Flash to the Google AI models
This commit is contained in:
1 parent
3d5fb8133a
commit
da7d444cab
2 files changed
+55
-2
No files matched your search
@@ -249,7 +249,12 @@ fn is_google_thinking_model(model_id: &str) -> bool {
|
|||||||
|
|
||||||
fn disabled_thinking_level(model_id: &str) -> Option<ThinkingLevel> {
|
fn disabled_thinking_level(model_id: &str) -> Option<ThinkingLevel> {
|
||||||
match model_id {
|
match model_id {
|
||||||
model_id if model_id.starts_with("gemini-3") && model_id.contains("-pro") => {
|
// `gemini-3.7-flash` rejects `MINIMAL` with a validation error, so `LOW` is
|
||||||
|
// the lowest level available to it.
|
||||||
|
model_id
|
||||||
|
if model_id.starts_with("gemini-3.7-flash")
|
||||||
|
|| (model_id.starts_with("gemini-3") && model_id.contains("-pro")) =>
|
||||||
|
{
|
||||||
Some(ThinkingLevel::Low)
|
Some(ThinkingLevel::Low)
|
||||||
}
|
}
|
||||||
model_id if model_id.starts_with("gemini-3") => Some(ThinkingLevel::Minimal),
|
model_id if model_id.starts_with("gemini-3") => Some(ThinkingLevel::Minimal),
|
||||||
@@ -704,6 +709,23 @@ mod tests {
|
|||||||
assert_eq!(mapper.stop_reason, StopReason::Refusal);
|
assert_eq!(mapper.stop_reason, StopReason::Refusal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_disabled_thinking_level_per_model() {
|
||||||
|
assert_eq!(
|
||||||
|
disabled_thinking_level("gemini-3.7-flash"),
|
||||||
|
Some(ThinkingLevel::Low)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
disabled_thinking_level("gemini-3.1-pro-preview"),
|
||||||
|
Some(ThinkingLevel::Low)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
disabled_thinking_level("gemini-3.6-flash"),
|
||||||
|
Some(ThinkingLevel::Minimal)
|
||||||
|
);
|
||||||
|
assert_eq!(disabled_thinking_level("gemini-2.5-flash"), None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_function_call_with_signature_creates_tool_use_with_signature() {
|
fn test_function_call_with_signature_creates_tool_use_with_signature() {
|
||||||
let mut mapper = GoogleEventMapper::new();
|
let mut mapper = GoogleEventMapper::new();
|
||||||
|
|||||||
@@ -533,6 +533,8 @@ pub enum Model {
|
|||||||
Gemini35Flash,
|
Gemini35Flash,
|
||||||
#[serde(rename = "gemini-3.6-flash")]
|
#[serde(rename = "gemini-3.6-flash")]
|
||||||
Gemini36Flash,
|
Gemini36Flash,
|
||||||
|
#[serde(rename = "gemini-3.7-flash")]
|
||||||
|
Gemini37Flash,
|
||||||
#[serde(rename = "gemini-3.1-pro-preview", alias = "gemini-3-pro-preview")]
|
#[serde(rename = "gemini-3.1-pro-preview", alias = "gemini-3-pro-preview")]
|
||||||
Gemini31Pro,
|
Gemini31Pro,
|
||||||
#[serde(rename = "custom")]
|
#[serde(rename = "custom")]
|
||||||
@@ -560,6 +562,7 @@ impl Model {
|
|||||||
Self::Gemini3Flash => "gemini-3-flash-preview",
|
Self::Gemini3Flash => "gemini-3-flash-preview",
|
||||||
Self::Gemini35Flash => "gemini-3.5-flash",
|
Self::Gemini35Flash => "gemini-3.5-flash",
|
||||||
Self::Gemini36Flash => "gemini-3.6-flash",
|
Self::Gemini36Flash => "gemini-3.6-flash",
|
||||||
|
Self::Gemini37Flash => "gemini-3.7-flash",
|
||||||
Self::Gemini31Pro => "gemini-3.1-pro-preview",
|
Self::Gemini31Pro => "gemini-3.1-pro-preview",
|
||||||
Self::Custom { name, .. } => name,
|
Self::Custom { name, .. } => name,
|
||||||
}
|
}
|
||||||
@@ -573,6 +576,7 @@ impl Model {
|
|||||||
Self::Gemini3Flash => "gemini-3-flash-preview",
|
Self::Gemini3Flash => "gemini-3-flash-preview",
|
||||||
Self::Gemini35Flash => "gemini-3.5-flash",
|
Self::Gemini35Flash => "gemini-3.5-flash",
|
||||||
Self::Gemini36Flash => "gemini-3.6-flash",
|
Self::Gemini36Flash => "gemini-3.6-flash",
|
||||||
|
Self::Gemini37Flash => "gemini-3.7-flash",
|
||||||
Self::Gemini31Pro => "gemini-3.1-pro-preview",
|
Self::Gemini31Pro => "gemini-3.1-pro-preview",
|
||||||
Self::Custom { name, .. } => name,
|
Self::Custom { name, .. } => name,
|
||||||
}
|
}
|
||||||
@@ -587,6 +591,7 @@ impl Model {
|
|||||||
Self::Gemini3Flash => "Gemini 3 Flash",
|
Self::Gemini3Flash => "Gemini 3 Flash",
|
||||||
Self::Gemini35Flash => "Gemini 3.5 Flash",
|
Self::Gemini35Flash => "Gemini 3.5 Flash",
|
||||||
Self::Gemini36Flash => "Gemini 3.6 Flash",
|
Self::Gemini36Flash => "Gemini 3.6 Flash",
|
||||||
|
Self::Gemini37Flash => "Gemini 3.7 Flash",
|
||||||
Self::Gemini31Pro => "Gemini 3.1 Pro",
|
Self::Gemini31Pro => "Gemini 3.1 Pro",
|
||||||
Self::Custom {
|
Self::Custom {
|
||||||
name, display_name, ..
|
name, display_name, ..
|
||||||
@@ -603,6 +608,7 @@ impl Model {
|
|||||||
| Self::Gemini3Flash
|
| Self::Gemini3Flash
|
||||||
| Self::Gemini35Flash
|
| Self::Gemini35Flash
|
||||||
| Self::Gemini36Flash
|
| Self::Gemini36Flash
|
||||||
|
| Self::Gemini37Flash
|
||||||
| Self::Gemini31Pro => 1_048_576,
|
| Self::Gemini31Pro => 1_048_576,
|
||||||
Self::Custom { max_tokens, .. } => *max_tokens,
|
Self::Custom { max_tokens, .. } => *max_tokens,
|
||||||
}
|
}
|
||||||
@@ -617,6 +623,7 @@ impl Model {
|
|||||||
| Model::Gemini3Flash
|
| Model::Gemini3Flash
|
||||||
| Model::Gemini35Flash
|
| Model::Gemini35Flash
|
||||||
| Model::Gemini36Flash
|
| Model::Gemini36Flash
|
||||||
|
| Model::Gemini37Flash
|
||||||
| Model::Gemini31Pro => Some(65_536),
|
| Model::Gemini31Pro => Some(65_536),
|
||||||
Model::Custom { .. } => None,
|
Model::Custom { .. } => None,
|
||||||
}
|
}
|
||||||
@@ -640,6 +647,7 @@ impl Model {
|
|||||||
| Self::Gemini3Flash
|
| Self::Gemini3Flash
|
||||||
| Self::Gemini35Flash
|
| Self::Gemini35Flash
|
||||||
| Self::Gemini36Flash
|
| Self::Gemini36Flash
|
||||||
|
| Self::Gemini37Flash
|
||||||
| Self::Gemini31Pro
|
| Self::Gemini31Pro
|
||||||
| Self::Custom {
|
| Self::Custom {
|
||||||
mode: GoogleModelMode::Thinking { .. },
|
mode: GoogleModelMode::Thinking { .. },
|
||||||
@@ -659,7 +667,7 @@ impl Model {
|
|||||||
ThinkingLevel::Medium,
|
ThinkingLevel::Medium,
|
||||||
ThinkingLevel::High,
|
ThinkingLevel::High,
|
||||||
],
|
],
|
||||||
Self::Gemini31Pro => &[
|
Self::Gemini37Flash | Self::Gemini31Pro => &[
|
||||||
ThinkingLevel::Low,
|
ThinkingLevel::Low,
|
||||||
ThinkingLevel::Medium,
|
ThinkingLevel::Medium,
|
||||||
ThinkingLevel::High,
|
ThinkingLevel::High,
|
||||||
@@ -674,6 +682,7 @@ impl Model {
|
|||||||
Self::Gemini3Flash => Some(ThinkingLevel::High),
|
Self::Gemini3Flash => Some(ThinkingLevel::High),
|
||||||
Self::Gemini35Flash => Some(ThinkingLevel::Medium),
|
Self::Gemini35Flash => Some(ThinkingLevel::Medium),
|
||||||
Self::Gemini36Flash => Some(ThinkingLevel::Medium),
|
Self::Gemini36Flash => Some(ThinkingLevel::Medium),
|
||||||
|
Self::Gemini37Flash => Some(ThinkingLevel::Medium),
|
||||||
Self::Gemini31Pro => Some(ThinkingLevel::High),
|
Self::Gemini31Pro => Some(ThinkingLevel::High),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@@ -692,6 +701,7 @@ impl Model {
|
|||||||
| Self::Gemini3Flash
|
| Self::Gemini3Flash
|
||||||
| Self::Gemini35Flash
|
| Self::Gemini35Flash
|
||||||
| Self::Gemini36Flash
|
| Self::Gemini36Flash
|
||||||
|
| Self::Gemini37Flash
|
||||||
| Self::Gemini31Pro => GoogleModelMode::Thinking {
|
| Self::Gemini31Pro => GoogleModelMode::Thinking {
|
||||||
budget_tokens: None,
|
budget_tokens: None,
|
||||||
},
|
},
|
||||||
@@ -724,6 +734,27 @@ mod tests {
|
|||||||
assert_eq!(deserialized, Model::Gemini36Flash);
|
assert_eq!(deserialized, Model::Gemini36Flash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gemini_3_7_flash_model_metadata() {
|
||||||
|
let model = Model::Gemini37Flash;
|
||||||
|
assert_eq!(model.id(), "gemini-3.7-flash");
|
||||||
|
assert_eq!(model.request_id(), "gemini-3.7-flash");
|
||||||
|
assert_eq!(model.display_name(), "Gemini 3.7 Flash");
|
||||||
|
assert_eq!(
|
||||||
|
model.supported_thinking_levels(),
|
||||||
|
&[
|
||||||
|
ThinkingLevel::Low,
|
||||||
|
ThinkingLevel::Medium,
|
||||||
|
ThinkingLevel::High
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let serialized = serde_json::to_value(&model).unwrap();
|
||||||
|
assert_eq!(serialized, json!("gemini-3.7-flash"));
|
||||||
|
let deserialized: Model = serde_json::from_value(json!("gemini-3.7-flash")).unwrap();
|
||||||
|
assert_eq!(deserialized, Model::Gemini37Flash);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_function_call_part_with_signature_serializes_correctly() {
|
fn test_function_call_part_with_signature_serializes_correctly() {
|
||||||
let part = FunctionCallPart {
|
let part = FunctionCallPart {
|
||||||
|
|||||||
Reference in new issue
Block a user