Skip to content

Agent Engine update() drops the AgentCard: spec.agent_card missing from the update mask #7064

Description

@msteiner-google

AI generated, but the bug is personally verified

Environment details

  • OS type and version: macOS 26.5.2 (arm64)
  • Python version: 3.13.14
  • pip version: n/a (uv 0.11.26)
  • google-cloud-aiplatform version: 1.156.0 (also present on main @ 4c0c368)

Steps to reproduce

  1. Deploy an A2A agent with client.agent_engines.create(agent=reasoning_engines.A2aAgent(agent_card=card, ...), config=...), where card.version == "1.2.0".
  2. Edit the agent card: add a skill and bump version to "1.3.0".
  3. Redeploy onto the same engine with client.agent_engines.update(name=..., agent=a2a_agent, config=...).
  4. A new revision is created and updateTime moves, but GET on the reasoning engine still returns spec.agentCard exactly as it was at step 1 — old version, old skill list. The Agent Registry entry derived from the card stays stale with it.

Code example

from a2a.types import AgentCard
from vertexai.preview import reasoning_engines
import vertexai

client = vertexai.Client(project=PROJECT, location=REGION)

card = AgentCard(**json.load(open("agent-card.json")))  # version "1.3.0", new skill added
a2a_agent = reasoning_engines.A2aAgent(agent_card=card, agent_executor_builder=build_executor)

updated = client.agent_engines.update(
    name="projects/P/locations/L/reasoningEngines/E",
    agent=a2a_agent,
    config={"requirements": reqs, "extra_packages": ["agents"], "staging_bucket": BUCKET},
)

# spec.agentCard is still the card from the very first deployment.
print(updated.api_resource.spec.agent_card["version"])  # -> "1.2.0"

Analysis

In _create_config, the agent card is written into the request body but never added to update_masks, so the server drops it on a PATCH. Only spec.agent_framework is appended right after the card block:

if hasattr(agent, "agent_card"):
agent_card = getattr(agent, "agent_card")
if agent_card is not None:
try:
agent_engine_spec["agent_card"] = (
_agent_engines_utils._serialize_agent_card_to_dict(
agent_card
)
)
except Exception as e:
raise ValueError(
f"Failed to convert agent card to dict (serialization error): {e}"
) from e
update_masks.append("spec.agent_framework")

            if hasattr(agent, "agent_card"):
                agent_card = getattr(agent, "agent_card")
                if agent_card is not None:
                    try:
                        agent_engine_spec["agent_card"] = (
                            _agent_engines_utils._serialize_agent_card_to_dict(
                                agent_card
                            )
                        )
                    except Exception as e:
                        raise ValueError(
                            f"Failed to convert agent card to dict (serialization error): {e}"
                        ) from e
            update_masks.append("spec.agent_framework")   # <- no "spec.agent_card"

Every other spec field that _create_config sets registers a matching mask entry (spec.package_spec.*, spec.class_methods, spec.container_spec, spec.deployment_spec.*, spec.identity_type, spec.service_account), so spec.agent_card looks like an oversight rather than an intentional omission. The API itself accepts the field: patching the engine directly with ?updateMask=spec.agentCard updates the card as expected, which is the workaround we are currently using.

Suggested fix — append the mask inside the if agent_card: branch:

                        agent_engine_spec["agent_card"] = ...
                        update_masks.append("spec.agent_card")

Impact: an A2A agent's advertised card (skills, version, description, security schemes) can never be changed after the first deployment through the SDK. Consumers that discover the agent through the card — other A2A clients and the Agent Registry — keep seeing capabilities the deployed revision no longer matches.

Related: #6183 is the same class of bug for python_version (set in the payload, missing from the update mask), so a sweep over _create_config for other unmasked spec fields may be worthwhile.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    api: vertex-aiIssues related to the googleapis/python-aiplatform API.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions