From a686f36f0c6b4fbedd272d694ea9e5b6c41b2b2d Mon Sep 17 00:00:00 2001 From: maya-lukas Date: Mon, 17 Aug 2026 10:34:49 +0200 Subject: [PATCH] fix(gemini): read the major version instead of matching "gemini-3" The substring check would have reported Gemini 4 and later as pre-3, reintroducing the same class of bug the moment Google ships an explicitly versioned `gemini-4-*` model. Parsing the major version off the name and comparing against 3 makes every later release work without a code change, and it also excludes `gemini-2.5-flash-native-audio-latest` on version rather than by special-casing the name. The alias set now covers only names that carry no version at all. --- .../vertex_and_google_ai_studio_gemini.py | 27 +++++++++---------- ...test_vertex_and_google_ai_studio_gemini.py | 9 +++++++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py b/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py index bcc75d36482..f3de4aa30a5 100644 --- a/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py +++ b/litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py @@ -2,6 +2,7 @@ ## httpx client for vertex ai calls ## Initial implementation - covers gemini + image gen calls import json +import re import time from collections.abc import Callable, Mapping, Sequence from copy import deepcopy @@ -106,6 +107,8 @@ else: StreamingChoices = Any +GEMINI_MAJOR_VERSION_PATTERN: Final[re.Pattern[str]] = re.compile(r"gemini-(\d+)") + GEMINI_ROLLING_LATEST_ALIASES: Final[frozenset[str]] = frozenset( { "gemini-flash-latest", @@ -266,23 +269,17 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig): @staticmethod def _is_gemini_3_or_newer(model: str) -> bool: """ - Check if the model is Gemini 3 Pro or newer. + Check if the model is Gemini 3 or newer, e.g. gemini-3-pro-preview, + gemini-3.1-flash, gemini-3.5-flash, and every later major version. - Gemini 3 models include: - - gemini-3-pro-preview - - gemini-3-flash - - gemini-3-flash-preview (Gemini 3 Flash) - - gemini-3.1-pro-preview, gemini-3.1-flash, gemini-3.1-flash-lite-preview - - gemini-3.5-flash - - Any future Gemini 3.x models - - GEMINI_ROLLING_LATEST_ALIASES, which resolve to Gemini 3.x and carry - no version number of their own. Matched by exact name, since - versioned names such as `gemini-2.5-flash-native-audio-latest` also - end in `-latest` yet are not Gemini 3 + The major version is read off the model name, so Gemini 4 and beyond + satisfy this without a code change. Names carrying no version at all are + matched against GEMINI_ROLLING_LATEST_ALIASES, which always resolve to + the newest release of their tier. """ - # Check for Gemini 3 models - if "gemini-3" in model: - return True + major_version: Final = GEMINI_MAJOR_VERSION_PATTERN.search(model) + if major_version is not None: + return int(major_version.group(1)) >= 3 return model.split("/")[-1] in GEMINI_ROLLING_LATEST_ALIASES @staticmethod diff --git a/tests/test_litellm/llms/vertex_ai/gemini/test_vertex_and_google_ai_studio_gemini.py b/tests/test_litellm/llms/vertex_ai/gemini/test_vertex_and_google_ai_studio_gemini.py index caebca689b2..919d87cf1d2 100644 --- a/tests/test_litellm/llms/vertex_ai/gemini/test_vertex_and_google_ai_studio_gemini.py +++ b/tests/test_litellm/llms/vertex_ai/gemini/test_vertex_and_google_ai_studio_gemini.py @@ -2292,6 +2292,15 @@ def test_is_gemini_3_or_newer(): == False ) + # Later major versions must satisfy this without a code change + assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-4-flash") == True + assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-4.2-pro-preview") == True + assert VertexGeminiConfig._is_gemini_3_or_newer("gemini/gemini-10-flash") == True + + # Unversioned names that are not rolling aliases stay excluded + assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-embedding-001") == False + assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-exp-1206") == False + def test_thought_signature_fallback_for_rolling_latest_alias(): """