evals run_inference (local ADK agent): strips multimodal prompt parts (inline_data) before Runner.run_async
@jscud is already working on this.
Since Aug 13, 2026.
Assessment
This issue has not been assessed yet.
Description
Environment
google-cloud-aiplatform1.157.0google-agents-cli0.4.0 (agents-cli eval generate)google-adk2.2.0
Summary
vertexai.Client().evals.run_inference(agent=<local_adk_agent>) — the path used by agents-cli eval generate — drops non-text prompt parts before calling ADK Runner.run_async. Eval cases with multimodal prompt.parts[] (e.g. PDF inline_data per agents-cli multimodal eval schema) reach the agent as text-only user content. Tools that depend on tool_context.user_content.parts[].inline_data never see the attachment.
Repro
- Create a one-case eval dataset with multimodal prompt (text + PDF
inline_data), e.g. agents-cli multimodal schema:
{
"eval_cases": [{
"eval_case_id": "pdf_smoke",
"prompt": {
"role": "user",
"parts": [
{"text": "Process this document."},
{"inline_data": {"mime_type": "application/pdf", "data": "<base64>"}}
]
}
}]
}
- Run local inference via agents-cli:
agents-cli eval generate --dataset <dataset.json> --output traces.json
- Inspect trace: agent tool that reads
user_content.partsforinline_datareturns an error like "No document found" — only the text part survived inference.
Contrast (works)
ADK AgentEvaluator / pytest evaluation passes the full Content (text + inline_data) into Runner.run_async, and the same tool succeeds.
Root cause
In vertexai/_genai/_evals_common.py:
1. DataFrame build flattens prompt to text
_eval_cases_to_dataframe stores:
row[PROMPT] = _evals_data_converters._get_content_text(case.prompt)
_get_content_text (_evals_data_converters.py) concatenates part.text and ignores inline_data, file_data, etc.
2. Local agent run wraps string as single text Part
_execute_local_agent_run_with_retry_async calls:
new_message_content = genai_types.Content(
role="user",
parts=[genai_types.Part(text=contents)],
)
So even if contents were a full Content, this stringifies it into one text part. Today contents is already the plain text string.
3. N+1 / agent_data path — same bug
When inference uses agent_data turns, the code still calls _get_content_text(last_user_content) before the local agent run.
Expected behavior
Preserve full multimodal Content (all parts, including inline_data / file_data) through the local-agent inference path and call:
Runner.run_async(new_message=Content.model_validate(full_content))
instead of Part(text=...).
Suggested fix locations
vertexai/_genai/_evals_common.py:
_eval_cases_to_dataframe— store full promptContentdict (withparts) when multimodal, not_get_content_text()only._extract_contents_for_inference— if dict hasparts, pass through (do not require nestedcontentskey)._execute_local_agent_run_with_retry_async— useContent.model_validate(contents)whencontentsis a Content dict; keepPart(text=...)fallback for plain strings.- N+1
agent_databranch — same helper instead of_get_content_text(last_user_content).
Impact
Blocks multimodal agent eval via agents-cli eval generate for any tool that reads uploaded bytes from user_content (PDF invoices, images, etc.). Workaround today is ADK AgentEvaluator pytest path, which preserves inline_data.
References
- agents-cli multimodal eval schema: https://github.com/google/agents-cli/blob/main/skills/google-agents-cli-eval/references/multimodal-eval.md
- Related open eval issues: #6785
- Dominant language
- Python
- Stars
- 907
- Forks
- 467
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 40
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from googleapis/python-aiplatform
-
api: vertex-ai
Difficulty 1/5 Under an hour Newbie friendliness 85/100
googleapis/python-aiplatform#7132 ·
-
api: vertex-ai
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
googleapis/python-aiplatform#7097 ·
-
CustomContainerTrainingJob.run drops max_wait_duration=0 instead of requesting indefinite DWS wait Openapi: vertex-ai
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
googleapis/python-aiplatform#7067 · 1 comment ·
-
api: vertex-ai
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
googleapis/python-aiplatform#6877 ·
-
api: vertex-ai
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
googleapis/python-aiplatform#6865 · 1 comment ·
All issues in googleapis/python-aiplatform
Similar issues
-
bug confirmed issue
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
open-webui/open-webui#30750 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
OpenwaterHealth/openmotion-bloodflow-app#604 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
good first issue
Difficulty 1/5 Under an hour Newbie friendliness 90/100