Skip to content

fix(sessions): drop unsupported part_metadata before Vertex appendEvent#6024

Open
rynecheow wants to merge 2 commits into
google:mainfrom
rynecheow:fix/vertex-session-part-metadata-6014
Open

fix(sessions): drop unsupported part_metadata before Vertex appendEvent#6024
rynecheow wants to merge 2 commits into
google:mainfrom
rynecheow:fix/vertex-session-part-metadata-6014

Conversation

@rynecheow

Copy link
Copy Markdown

Description

google.genai Part.part_metadata is a Gemini Developer API-only field — the model path already guards it in genai's _Part_to_vertex (raises for Vertex). But VertexAiSessionService.append_event serialised it into both the content and raw_event payloads, and the Vertex AI Agent Engine Sessions appendEvent API rejects it:

400 INVALID_ARGUMENT. Invalid JSON payload received.
Unknown name "part_metadata" at 'event.content.parts[0]': Cannot find field.

This crashes every turn for agents whose events carry part_metadata. A common trigger: ADK's own A2A part converter (a2a/converters/part_converter.convert_a2a_part_to_genai_part) copies inbound A2A part metadata into Part.part_metadata, so any A2A-fronted agent using VertexAiSessionService (durable Agent Engine sessions) on Vertex fails on the first turn.

Fix

Add _drop_vertex_unsupported_part_fields, which removes part_metadata (tolerant of the partMetadata alias) from the serialised content, and apply it to both config['content'] and config['raw_event']['content'] before the appendEvent call. This mirrors the existing genai _Part_to_vertex guard for the model path.

Testing

  • New regression test test_append_event_strips_unsupported_part_metadata asserts part_metadata is absent from both the content and raw_event payloads while the part text is preserved. Verified it fails without the fix (the field is present in the dump pre-strip).
  • Full tests/unittests/sessions/test_vertex_ai_session_service.py suite passes (35 tests).
  • isort + pyink applied per repo config.

Fixes #6014

@google-cla

google-cla Bot commented Jun 9, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@adk-bot adk-bot added the services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc label Jun 9, 2026
@adk-bot

adk-bot commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Response from ADK Triaging Agent

Hello @rynecheow, thank you for creating this PR!

We noticed that the Google Contributor License Agreement (CLA) check has failed for this pull request. As part of our contribution guidelines, all submissions must be accompanied by a signed CLA before we can review and merge your changes.

Please visit https://cla.developers.google.com/ to view your current agreements or sign a new one.

Once signed, the CLA check status should automatically update. Thank you for your contribution and helping us improve the ADK!

@rynecheow rynecheow force-pushed the fix/vertex-session-part-metadata-6014 branch 2 times, most recently from ee1b928 to e03c5b2 Compare June 9, 2026 01:29
@adk-bot

adk-bot commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

⛔ Compliance Refusal: Contributor License Agreement (CLA) Verification Failed

We cannot perform the analysis, fetch the code diff, or conduct any triage operations for PR #6024 at this time.

Reason:

The contributor (@rynecheow) has not signed the Google Contributor License Agreement (CLA).

According to the established project contribution policies:

  • All pull requests must be accompanied by a signed Google CLA before they can be reviewed, triaged, or merged.
  • Automated systems (including google-cla[bot] and adk-bot) have flagged this pull request as having failed the CLA check.

Next Steps:

The author needs to visit Google CLA Portal to view or sign the Contributor License Agreement. Once the agreement is signed, the status of the PR's CLA check will update, and we will be able to proceed with the analysis.

@adk-bot

adk-bot commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

⛔ Compliance Refusal: Contributor License Agreement (CLA) Verification Failed

We cannot perform the analysis, fetch the code diff, or conduct any triage operations for PR #6024 at this time.

Reason:

The contributor (@rynecheow) has not signed the Google Contributor License Agreement (CLA).

According to the project contribution guidelines and legal compliance policy:

  • All pull requests must be accompanied by a successfully verified/signed Google CLA before they can be reviewed, triaged, or merged.
  • Automated checks (including google-cla[bot] and adk-bot) have marked this pull request as having failed the CLA check.

Next Steps:

The contributor needs to visit the Google CLA Portal to review and sign the agreement. Once the agreement is signed and the status is updated to SUCCESS, we can proceed with checking out, triaging, and analyzing the pull request.


Turn Summary

  1. Received command /adk-pr-analyze 6024 from the user.
  2. Inspected the relevant skill adk-pr-analyze via SKILL.md.
  3. Fetched the GitHub Pull Request details using the custom fetch_github_pr tool, revealing that both google-cla[bot] and adk-bot have flagged the PR as failing the Google CLA check.
  4. Refused further analysis immediately in compliance with the mandatory entry-gate rule.

google.genai Part.part_metadata is a Gemini Developer API-only field (the model
path already guards it in genai's _Part_to_vertex). VertexAiSessionService.
append_event serialised it into both the `content` and `raw_event` payloads, and
the Vertex AI Agent Engine Sessions appendEvent API rejects it with
400 INVALID_ARGUMENT ('Unknown name "part_metadata" at event.content.parts[0]'),
crashing every turn for agents that carry part_metadata (e.g. ADK's A2A part
converter copies inbound A2A part metadata into Part.part_metadata).

Strip part_metadata from the serialised content (and raw_event content) before
the appendEvent call. Adds regression tests for both the stripped append payload
and the read-back round-trip via get_session.

Fixes google#6014
@rynecheow rynecheow force-pushed the fix/vertex-session-part-metadata-6014 branch from e03c5b2 to 778eb1b Compare June 9, 2026 01:41
@adk-bot

adk-bot commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

I will view the adk-pr-analyze skill description file to understand the required steps and guidelines for performing the pull request analysis.I will run the Contributor License Agreement (CLA) verification script for PR #6024 to verify the contributor's signature before analyzing the changes.I will fetch the details of the GitHub Pull Request #6024 using the custom tool fetch_github_pr to proceed with the analysis.I will read the triage_pr.py script to understand how it performs the CLA verification and what APIs/endpoints it relies on.I will fetch the status check rollup for PR #6024 using the GitHub CLI via run_command to check the progress of the automated checks, specifically the Google CLA verification status.I will now run the compliance verification script to perform a final official check on the Google CLA signature status and display the complete JSON metadata for PR #6024.I will fetch the details of the linked GitHub issue #6014 using the custom tool fetch_github_issue to establish full context on the bug being fixed.I will fetch the complete line-by-line diff for PR #6024 using the GitHub CLI (gh pr diff) via run_command.I will view the workspace file src/google/adk/sessions/vertex_ai_session_service.py using view_file around the modified locations to verify the context, imports, types, and logging conventions in the baseline codebase.I will view src/google/adk/sessions/vertex_ai_session_service.py around the original append_event method to see exactly what logic was in place.I will view the beginning of src/google/adk/sessions/vertex_ai_session_service.py using view_file to inspect the license header and import block.I will view the beginning of tests/unittests/sessions/test_vertex_ai_session_service.py to check the license headers and imports.I will view the latter part of tests/unittests/sessions/test_vertex_ai_session_service.py to check the context of where the PR asserts behavior and how other tests are modeled.I will view src/google/adk/a2a/converters/part_converter.py to inspect how part_metadata is populated for incoming standard A2A request parts.I will run git branch and git status using the GitHub/Git CLI via run_command to check which branch the local repository is currently on.I will search for the definition of the mock_api_client_instance fixture in tests/unittests/sessions/test_vertex_ai_session_service.py using grep_search to verify its compatibility with the proposed tests.I will view lines 610 to 650 in tests/unittests/sessions/test_vertex_ai_session_service.py to confirm how the MockAsyncClient class is designed and what properties/fields (such as event_dict) are used during the mocked append_event assertion.I will search for class MockAsyncClient in tests/unittests/sessions/test_vertex_ai_session_service.py using grep_search to verify how appending is mocked.I will view the MockAsyncClient definition to verify its append method implementation.I will view lines 421 to 460 of tests/unittests/sessions/test_vertex_ai_session_service.py to see how _append_event mock handler is defined and how it populates event_dict.I will view lines 461 to 495 of tests/unittests/sessions/test_vertex_ai_session_service.py to see _append_event's handling and population of event_dict.I will view lines 496 to 520 of tests/unittests/sessions/test_vertex_ai_session_service.py using view_file to finish our walkthrough of how events are appended and returned in MockAsyncClient.# 🔍 ADK Pull Request Analysis: PR #6024

Title: fix(sessions): drop unsupported part_metadata before Vertex appendEvent
Author: @rynecheow
Status: open
Impact: 100 additions, 3 deletions across 2 files


Executive Summary

  1. Core Objective: Strips the unsupported client-only part_metadata (and camelCase alias partMetadata) field from the serialized content and raw_event parts payload in VertexAiSessionService.append_event prior to appending the event to Vertex AI Agent Engine.
  2. Justification & Value: Justified Fix - Corrects a severe schema validation crash (400 INVALID_ARGUMENT) affecting all durable sessions for A2A-fronted agents on Vertex AI.
  3. Alignment with Principles: Pass - The changes are highly conforming, use deep type/alias safety, use standard private helper naming, and include high-quality regression and round-trip unit tests.
  4. Recommendation: Approve - The implementation is clean, robust, thoroughly tested, and completely safe.
Detailed Findings & Analysis

1. Objectives & Impact ("What does it do?")

  • Context & Background: Resolves linked Issue #6014. In version 2.2.0, ADK's part_converter.py maps inbound A2A part metadata to part_metadata in Google GenAI Part structures. At runtime, when durable Vertex session persistence is active, VertexAiSessionService.append_event attempts to serialize the full event structure. The underlying Vertex AI Agent Engine Sessions REST endpoint validates the schema strictly and throws a fatal 400 INVALID_ARGUMENT exception due to the unrecognized part_metadata field, crashing the conversation on every turn.
  • Implementation Mechanism: Adds a module-level private helper _drop_vertex_unsupported_part_fields in vertex_ai_session_service.py that traverses the deserialized nested parts list blocks and pops both 'part_metadata' and 'partMetadata' keys in-place. This helper is triggered on both config['content'] and config['raw_event']['content'] during the standard append_event serialization workflow.
  • Affected Surface: No public APIs, class signatures, or configurations are altered. Internal state representation for Event serialization to Agent Engine is altered to strip the unsupported field.

2. Justification & Value ("Is it a valid and useful change?")

  • Workspace Verification:
    • Investigated current workspace files: vertex_ai_session_service.py (L339-345) (using view_file / grep_search).
    • Found that: In the baseline code, event.content.model_dump was directly assigned to config['content'] value without purification. Confirmed in part_converter.py (L67-80) that part_metadata is actively populated on Gemini parts for all textual and file media parts.
  • Value Assessment: Extremely high value. This resolves an critical regression introduced in ADK 2.2.0 that completely blocks conversation turns for A2A-communicating agents utilizing Vertex AI's Agent Engine backends.
  • Alternative Approaches:
    • Option A: Refusing to populate part_metadata during A2A conversion on setups where the agent engine backend is active. This is fragile because the converter operates in a generic context without explicit awareness of downstream persistence engines.
    • Option B (Author's Choice): Strip the fields during serialization at the boundary of VertexAiSessionService. This is extremely elegant, localized, and ensures that the REST payload conforms perfectly to Vertex schemas while leaving A2A's converters untouched.
  • Scope & Depth: Systematic Fix & Root Cause - Rather than patching only the specific caller or symptom, this fix systematically intercepts full event serialization inside the session service, removing all instances of the unsupported fields from both the monolithic config payload and the optional raw event block.

3. Principle & Style Alignment Checklist ("Does it follow rules?")

  • Public API & Visibility Boundaries:
    • Status: Pass
    • Analysis: All changed symbols are strictly internal. The introduced helper _drop_vertex_unsupported_part_fields starts with a leading underscore, conforms with private subsystem patterns, and encapsulates the logic cleanly without exposing any implementation details.
  • Code Quality, Typing & Conventions:
    • Status: Pass
    • Analysis: Fully typed (content_dict: dict[str, Any] with return None), with a clear and concise docstring. No legacy Optional types used.
  • Robustness & Edge Cases:
    • Status: Pass
    • Analysis: Utilizes get('parts') or [] and isinstance(part, dict) to prevent type-mismatch crashes. Gracefully accommodates both standard (part_metadata) and camelCase alias (partMetadata) forms using .pop(..., None) on each dictionary.
  • Test Integrity & Quality:
    • Status: Pass
    • Analysis: Includes two comprehensive testing structures:
      1. test_append_event_strips_unsupported_part_metadata: Asserts proper stripping from both the content and raw_event structures.
      2. test_append_event_with_part_metadata_round_trips: Validates full end-to-end roundtrip event persistence, fetching, and correct recovery behavior (validating that the text remains intact while part_metadata gracefully defaults to None on the Vertex reconstruction path).

Turn Summary

  1. Triggered Skill: Read and executed instructions of the read-only adk-pr-analyze skill.
  2. Compliance & Verification:
  3. Information Retrieval:
  4. Codebase Tracing:
    • Analyzed local files vertex_ai_session_service.py and part_converter.py to confirm the baseline crash vectors.
    • Evaluated the test architecture and fixtures in test_vertex_ai_session_service.py.
  5. Output: Delivered a complete, fully conforming, and formatted PR Analysis Report. No files were written or modified in compliance with the read-only constraints.

@adk-bot

adk-bot commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

I have completed a thorough, read-only architectural and style review of Pull Request #6024.

The full, structured findings have been published to the interactive artifact:
👉 analysis_report.md

Key Highlights

  • Impact & Criticality: Resolves a major blocker regression introduced in 2.2.0 (Issue #6014) that crashes (with a 400 INVALID_ARGUMENT response) every conversation turn for A2A-fronted agents utilizing durable session storage on Vertex AI (VertexAiSessionService).
  • Technical Implementation:
    • Adds a private helper _drop_vertex_unsupported_part_fields inside vertex_ai_session_service.py that cleanses both part_metadata and the serialized camelCase alias partMetadata.
    • Appended payloads under both config['content'] and config['raw_event']['content'] are successfully sanitized, resolving Vertex's strict schema validation rejection without altering the underlying user-facing event model.
  • Architectural & Style Code Alignment: Fully compliant. The code avoids breaking any public namespace contracts, enforces modern typing protocols, incorporates edge-case-safe dictionary operations, and supplies highly descriptive unit tests under test_vertex_ai_session_service.py handling both stripping correctness and stable round-trip reconstruction.

Recommendation

Approve — The PR is of exceptionally high quality, extremely localized in risk, and directly resolves a business-critical blocker regression. No requests for changes or modifications are necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Projects

None yet

2 participants