google_ai: Add Gemini 3.8 Flash (#63643)

# Objective

Add Gemini 3.8 Flash to Zed's built-in Google AI provider so it can be
selected from the model dropdown.

  ## Solution

Register `gemini-3.8-flash` with its 1 million token context window, 64k
output limit, and Low, Medium, and High thinking levels. Medium is the
default, and Low is used when thinking is disabled because the model
rejects Minimal.

Add tests covering the model metadata, serialization, token limits,
thinking levels, and disabled-thinking behavior.

  ## Testing

  Tested on Windows using Rust 1.98 GNU:

  - `cargo test -p google_ai` — 23 passed
  - `cargo fmt --all --check`
- `cargo +stable-x86_64-pc-windows-gnu clippy -p google_ai --release
--all-targets --all-features -- --deny warnings`

Reviewers can run `cargo test -p google_ai`. The pinned MSVC toolchain
was not tested locally because `link.exe` was unavailable.

  ## Self-Review Checklist:

  - [x] I've reviewed my own diff for quality, security, and reliability
  - [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
  - [x] Tests cover the new/changed behavior
  - [x] Performance impact has been considered and is acceptable

  ---

Release Notes:

- Added Gemini 3.8 Flash to the Google AI models
This commit is contained in:
Ayush authored and GitHub committed 2026-09-04 16:24:18 +00:00
1 parent 3c1fc637ad
commit 078d171ebc
2 files changed
+43 -3

No files matched your search

+7 -2
View File
@@ -250,10 +250,11 @@ fn is_google_thinking_model(model_id: &str) -> bool {
fn disabled_thinking_level(model_id: &str) -> Option<ThinkingLevel> {
match model_id {
// `gemini-3.7-flash` rejects `MINIMAL` with a validation error, so `LOW` is
// the lowest level available to it.
// Gemini 3.7 and 3.8 Flash reject `MINIMAL` with a validation error, so
// `LOW` is the lowest level available to them.
model_id
if model_id.starts_with("gemini-3.7-flash")
|| model_id.starts_with("gemini-3.8-flash")
|| (model_id.starts_with("gemini-3") && model_id.contains("-pro")) =>
{
Some(ThinkingLevel::Low)
@@ -749,6 +750,10 @@ mod tests {
#[test]
fn test_disabled_thinking_level_per_model() {
assert_eq!(
disabled_thinking_level("gemini-3.8-flash"),
Some(ThinkingLevel::Low)
);
assert_eq!(
disabled_thinking_level("gemini-3.7-flash"),
Some(ThinkingLevel::Low)
+36 -1
View File
@@ -517,6 +517,8 @@ pub enum Model {
Gemini36Flash,
#[serde(rename = "gemini-3.7-flash")]
Gemini37Flash,
#[serde(rename = "gemini-3.8-flash")]
Gemini38Flash,
#[serde(rename = "gemini-3.1-pro-preview")]
Gemini31Pro,
#[serde(rename = "custom")]
@@ -542,6 +544,7 @@ impl Model {
Self::Gemini35Flash => "gemini-3.5-flash",
Self::Gemini36Flash => "gemini-3.6-flash",
Self::Gemini37Flash => "gemini-3.7-flash",
Self::Gemini38Flash => "gemini-3.8-flash",
Self::Gemini31Pro => "gemini-3.1-pro-preview",
Self::Custom { name, .. } => name,
}
@@ -553,6 +556,7 @@ impl Model {
Self::Gemini35Flash => "gemini-3.5-flash",
Self::Gemini36Flash => "gemini-3.6-flash",
Self::Gemini37Flash => "gemini-3.7-flash",
Self::Gemini38Flash => "gemini-3.8-flash",
Self::Gemini31Pro => "gemini-3.1-pro-preview",
Self::Custom { name, .. } => name,
}
@@ -565,6 +569,7 @@ impl Model {
Self::Gemini35Flash => "Gemini 3.5 Flash",
Self::Gemini36Flash => "Gemini 3.6 Flash",
Self::Gemini37Flash => "Gemini 3.7 Flash",
Self::Gemini38Flash => "Gemini 3.8 Flash",
Self::Gemini31Pro => "Gemini 3.1 Pro",
Self::Custom {
name, display_name, ..
@@ -579,6 +584,7 @@ impl Model {
| Self::Gemini35Flash
| Self::Gemini36Flash
| Self::Gemini37Flash
| Self::Gemini38Flash
| Self::Gemini31Pro => 1_048_576,
Self::Custom { max_tokens, .. } => *max_tokens,
}
@@ -591,6 +597,7 @@ impl Model {
| Model::Gemini35Flash
| Model::Gemini36Flash
| Model::Gemini37Flash
| Model::Gemini38Flash
| Model::Gemini31Pro => Some(65_536),
Model::Custom { .. } => None,
}
@@ -612,6 +619,7 @@ impl Model {
| Self::Gemini35Flash
| Self::Gemini36Flash
| Self::Gemini37Flash
| Self::Gemini38Flash
| Self::Gemini31Pro
| Self::Custom {
mode: GoogleModelMode::Thinking { .. },
@@ -631,7 +639,7 @@ impl Model {
ThinkingLevel::Medium,
ThinkingLevel::High,
],
Self::Gemini37Flash | Self::Gemini31Pro => &[
Self::Gemini37Flash | Self::Gemini38Flash | Self::Gemini31Pro => &[
ThinkingLevel::Low,
ThinkingLevel::Medium,
ThinkingLevel::High,
@@ -647,6 +655,7 @@ impl Model {
Self::Gemini35Flash => Some(ThinkingLevel::Medium),
Self::Gemini36Flash => Some(ThinkingLevel::Medium),
Self::Gemini37Flash => Some(ThinkingLevel::Medium),
Self::Gemini38Flash => Some(ThinkingLevel::Medium),
Self::Gemini31Pro => Some(ThinkingLevel::High),
_ => None,
}
@@ -659,6 +668,7 @@ impl Model {
| Self::Gemini35Flash
| Self::Gemini36Flash
| Self::Gemini37Flash
| Self::Gemini38Flash
| Self::Gemini31Pro => GoogleModelMode::Thinking {
budget_tokens: None,
},
@@ -735,6 +745,31 @@ mod tests {
assert_eq!(deserialized, Model::Gemini37Flash);
}
#[test]
fn test_gemini_3_8_flash_model_metadata() {
let model = Model::Gemini38Flash;
assert_eq!(model.id(), "gemini-3.8-flash");
assert_eq!(model.request_id(), "gemini-3.8-flash");
assert_eq!(model.display_name(), "Gemini 3.8 Flash");
assert_eq!(model.max_token_count(), 1_048_576);
assert_eq!(model.max_output_tokens(), Some(65_536));
assert!(model.supports_thinking());
assert_eq!(
model.supported_thinking_levels(),
&[
ThinkingLevel::Low,
ThinkingLevel::Medium,
ThinkingLevel::High
]
);
assert_eq!(model.default_thinking_level(), Some(ThinkingLevel::Medium));
let serialized = serde_json::to_value(&model).unwrap();
assert_eq!(serialized, json!("gemini-3.8-flash"));
let deserialized: Model = serde_json::from_value(json!("gemini-3.8-flash")).unwrap();
assert_eq!(deserialized, Model::Gemini38Flash);
}
#[test]
fn test_function_call_part_with_signature_serializes_correctly() {
let part = FunctionCallPart {