[LiteLLM] role='tool_responses' for Gemma 4 breaks tool calling on Vertex AI Model Garden MaaS (400 INVALID_ARGUMENT)
Les mainteneurs répondent en général sous 4 jours
Évaluation
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Accessibilité débutants
- 72/100
Piste de recherche
Le bogue se trouve dans google/adk/models/lite_llm.py, dans _is_gemma4_model et dans l'ensemble _STANDARD_TOOL_ROLE_PROVIDERS, qui décide si les résultats d'outils reçoivent role="tool" ou role="tool_responses". Commence par lire comment le fournisseur effectif est déduit pour une chaîne de modèle vertex_ai/, puis vérifie les tests existants qui couvrent les exclusions openai, azure et lm_studio. C'est terminé quand Gemma 4 sur vertex_ai envoie role="tool", que ollama et hosted_vllm conservent tool_responses, et qu'un test couvre le cas vertex_ai.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
🔴 Required Information
Describe the Bug:
_is_gemma4_model in google/adk/models/lite_llm.py causes ADK to emit tool results with role="tool_responses" whenever the model string matches gemma-?4, except when the effective provider is in _STANDARD_TOOL_ROLE_PROVIDERS ({"openai", "azure", "lm_studio"}, added in 7d190e6e for #6482).
When calling Gemma 4 on Vertex AI Model Garden MaaS via LiteLLM (model="vertex_ai/google/gemma-4-26b-a4b-it-maas"), LiteLLM routes the request to Vertex AI's OpenAI-compatible chat-completions endpoint (.../endpoints/openapi/chat/completions), which strictly validates OpenAI message roles. Because "vertex_ai" is not in _STANDARD_TOOL_ROLE_PROVIDERS, ADK sends role="tool_responses" and Vertex AI rejects every tool-result turn with HTTP 400 INVALID_ARGUMENT:
Unrecognized 'role' field for a message; found: 'tool_responses'.
Steps to Reproduce:
- Configure ADC with a GCP project that has Vertex AI API enabled.
- Instantiate
LiteLlm(model="vertex_ai/google/gemma-4-26b-a4b-it-maas", vertex_project="<gcp-project>", vertex_location="global"). - Send a tool-calling round trip (
userprompt ->modelFunctionCall->userFunctionResponse). - Observe
litellm.BadRequestError(400 INVALID_ARGUMENT).
Expected Behavior:
ADK sends tool results with role="tool" for vertex_ai Gemma 4 models, and Vertex AI returns a 200 OK completion grounded in the tool result.
Observed Behavior:
ADK sends role="tool_responses" and Vertex AI returns:
{
"error": {
"code": 400,
"message": "Unrecognized 'role' field for a message; found: 'tool_responses'.",
"status": "INVALID_ARGUMENT"
}
}
Environment Details:
- ADK Library Version (
pip show google-adk):2.13.0andmain(76627586) - Desktop OS: Linux
- Python Version (
python -V): Python 3.12
Model Information:
- Are you using LiteLLM: Yes
- Which model is being used:
vertex_ai/google/gemma-4-26b-a4b-it-maas
🟡 Optional Information
Regression:
Introduced when gemma-?4 matching was broadened in 49301558 (#6334 / #6340); 7d190e6e (#6482 / #7042) excluded openai, azure, and lm_studio, but did not include vertex_ai.
Logs:
roles sent: ['user', 'assistant', 'tool_responses']
EXCEPTION: BadRequestError litellm.BadRequestError: Vertex_aiException BadRequestError - [{
"error": {
"code": 400,
"message": "Unrecognized 'role' field for a message; found: 'tool_responses'.",
"status": "INVALID_ARGUMENT"
}
}]
Additional Context:
We also verified a self-deployed Vertex AI Model Garden Gemma 4 vLLM endpoint (google/gemma4@gemma-4-e2b-it via vertex_ai/gemma/... :predict with @requestFormat="chatCompletions" and dedicated /chat/completions): it accepts role="tool" with 200 OK and produces the expected final answer without re-calling the tool. Adding "vertex_ai" to _STANDARD_TOOL_ROLE_PROVIDERS therefore fixes Vertex MaaS without regressing self-deployed Vertex Model Garden endpoints, while preserving role="tool_responses" for ollama/... and hosted_vllm/....
Minimal Reproduction Code:
import asyncio
from google.adk.models.lite_llm import LiteLlm
from google.adk.models.llm_request import LlmRequest
from google.genai import types
async def main() -> None:
model = "vertex_ai/google/gemma-4-26b-a4b-it-maas"
llm = LiteLlm(
model=model,
vertex_project="<gcp-project>",
vertex_location="global",
)
weather = types.FunctionDeclaration(
name="get_weather",
description="Returns the weather for a city.",
parameters=types.Schema(
type=types.Type.OBJECT,
properties={"city": types.Schema(type=types.Type.STRING)},
required=["city"],
),
)
req = LlmRequest(
model=model,
contents=[
types.Content(
role="user",
parts=[types.Part(text="What is the weather in Paris?")],
),
types.Content(
role="model",
parts=[
types.Part(
function_call=types.FunctionCall(
id="call_1",
name="get_weather",
args={"city": "Paris"},
)
)
],
),
types.Content(
role="user",
parts=[
types.Part(
function_response=types.FunctionResponse(
id="call_1",
name="get_weather",
response={"result": "sunny, 21 C"},
)
)
],
),
],
config=types.GenerateContentConfig(
tools=[types.Tool(function_declarations=[weather])],
max_output_tokens=64,
),
)
async for r in llm.generate_content_async(req):
print(r.finish_reason, r.content)
asyncio.run(main())
How often has this issue occurred?:
- Always (100%)
- Langage dominant
- Python
- Étoiles
- 22.1k
- Forks
- 4.3k
- Merge moyen
- 1 j 10 h
- PR mergées (30 j)
- 5
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de google/adk-python
-
FileArtifactService changes CRLF and CR line endings in text artifactsPeut-être pris @sanketpatil06 l’a pris il y a 3 jours. Ouverterequest clarification services
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
google/adk-python#7914 · 1 commentaire · 1 personne assignée ·
Les mainteneurs répondent en général sous 4 jours
-
ContainerCodeExecutor drops output files that are hard linksPeut-être pris @llalitkumarrr l’a pris il y a 3 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
google/adk-python#7906 · 2 commentaires · 1 personne assignée ·
Les mainteneurs répondent en général sous 4 jours
-
GCS skill loaders ignore a skill.md manifest that the local and zip loaders acceptPeut-être pris @surajksharma07 l’a pris il y a 5 jours. Ouvertetools
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
google/adk-python#7842 · 2 commentaires · 1 personne assignée ·
Les mainteneurs répondent en général sous 4 jours
-
RestApiTool crashes on a request body media type that has no schemaPeut-être pris @llalitkumarrr l’a pris il y a 5 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
google/adk-python#7838 · 1 commentaire · 1 personne assignée ·
Les mainteneurs répondent en général sous 4 jours
-
LiteLlm with SSE streaming records the answer twice in gen_ai.output.messagesPeut-être pris @surajksharma07 l’a pris il y a 13 jours. Ouvertemodels
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
google/adk-python#7630 · 11 commentaires · 1 personne assignée ·
Les mainteneurs répondent en général sous 4 jours
Toutes les issues de google/adk-python
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
autowarefoundation/autoware_carla_scenario#1485 ·
Les mainteneurs répondent en général sous 1 jour
-
needs-area-label
Difficulté 2/5 1-3 heures Accessibilité débutants 66/100
Les mainteneurs répondent en général sous 2 jours
-
enhancement good first issue
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
Official-Space-AI/OpenPhysGraspGen#114 ·
Les mainteneurs répondent en général sous 2 jours
-
changelog investigate
Difficulté 2/5 1-3 heures Accessibilité débutants 62/100
ramnes/notion-sdk-py#441 ·
-
copy_tree splits same-file errors into charactersPeut-être pris @Gambit-Checkmate l’a pris aujourd’hui. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
Les mainteneurs répondent en général sous 14 jours