fix(gemini): strip version suffix from modelVersion and keep it on blocked streams

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
kerry 2026-09-16 01:42:36 +00:00
parent 44a6d19889
commit c4c96180e3
2 changed files with 46 additions and 5 deletions

View file

@ -124,6 +124,12 @@ def _unsupported_reasoning_effort(reasoning_effort: str) -> UnsupportedParamsErr
)
def _served_model_name(model_version: object) -> str | None:
if not isinstance(model_version, str) or not model_version:
return None
return model_version.split("@", 1)[0]
class VertexAIBaseConfig:
def get_mapped_special_auth_params(self) -> dict:
"""
@ -1951,6 +1957,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
def _check_prompt_level_content_filter(
processed_chunk: GenerateContentResponseBody,
response_id: str | None,
model: str | None = None,
) -> Optional["ModelResponseStream"]:
"""
Check if prompt is blocked due to content filtering at the prompt level.
@ -1990,7 +1997,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
enhancements=None,
)
model_response: Final = ModelResponseStream(choices=[choice], id=response_id)
model_response: Final = ModelResponseStream(choices=[choice], id=response_id, model=model)
return model_response
return None
@ -2434,8 +2441,8 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
completion_response = GenerateContentResponseBody(**completion_response)
## GET MODEL ##
model_version: Final = completion_response.get("modelVersion")
model_response.model = model_version if isinstance(model_version, str) else model
served: Final = _served_model_name(completion_response.get("modelVersion"))
model_response.model = served if served is not None else model
## CHECK IF RESPONSE FLAGGED
if "promptFeedback" in completion_response and "blockReason" in completion_response["promptFeedback"]:
@ -3265,17 +3272,18 @@ class ModelResponseIterator:
processed_chunk: Final = GenerateContentResponseBody(**chunk)
response_id: Final = processed_chunk.get("responseId")
chunk_model_version: Final = processed_chunk.get("modelVersion")
served: Final = _served_model_name(processed_chunk.get("modelVersion"))
model_response = ModelResponseStream(
choices=[],
id=response_id,
model=chunk_model_version if isinstance(chunk_model_version, str) else None,
model=served,
)
# Check if prompt is blocked due to content filtering
blocked_response: Final = VertexGeminiConfig._check_prompt_level_content_filter(
processed_chunk=processed_chunk,
response_id=response_id,
model=served,
)
if blocked_response is not None:
model_response = blocked_response

View file

@ -5926,3 +5926,36 @@ def test_served_model_version_reaches_assembled_stream_through_custom_stream_wra
assert chunk._hidden_params["provider_response_model"] == served_model
assembled: Final = litellm.stream_chunk_builder(chunks=list(chunks), messages=[{"role": "user", "content": "hi"}])
assert assembled._hidden_params["provider_response_model"] == served_model
def test_generate_content_transform_strips_version_suffix_from_model_version():
import httpx
body: Final = {**_generate_content_body(), "modelVersion": "gemini-3.8-flash-001@default"}
response: Final = VertexGeminiConfig()._transform_google_generate_content_to_openai_model_response(
completion_response=body,
model_response=ModelResponse(),
model="gemini-3.8-flash",
logging_obj=MagicMock(),
raw_response=httpx.Response(200, headers={}),
)
assert response.model == "gemini-3.8-flash-001"
def test_prompt_blocked_chunk_keeps_served_model_version():
from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
ModelResponseIterator,
)
chunk: Final = {
"promptFeedback": {"blockReason": "SAFETY", "blockReasonMessage": "prompt was blocked"},
"modelVersion": "gemini-3.8-flash-001",
"responseId": "resp-1",
}
iterator: Final = ModelResponseIterator(streaming_response=[], sync_stream=True, logging_obj=MagicMock())
streaming_chunk: Final = iterator.chunk_parser(chunk)
assert streaming_chunk.model == "gemini-3.8-flash-001"
assert streaming_chunk.choices[0].finish_reason == "content_filter"