refactor: Ap2 demo cleanup#52
Conversation
Summary of ChangesHello @jorellis, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly refactors the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request is a great refactoring that significantly improves the ap2-demo. By replacing the custom A2A communication logic with the official RemoteA2aAgent from the ADK, the code is now more maintainable, less boilerplate, and follows the recommended idiomatic patterns for multi-agent systems. The removal of _remote_agent_connection.py and _task_store.py is a major cleanup. The updated agent instructions are also much clearer and more direct for the LLM. I have a couple of suggestions to further improve code clarity and robustness.
| # Create RemoteA2aAgent instances for each remote agent. | ||
| remote_agents = [] | ||
| for address in REMOTE_AGENT_ADDRESSES: | ||
| # The server exposes the agent card at a path relative to the agent's RPC endpoint. | ||
| agent_card_url = f"{address}/.well-known/agent-card.json" | ||
| agent_name = address.split("/")[-1] | ||
| remote_agents.append( | ||
| RemoteA2aAgent( | ||
| name=agent_name, | ||
| agent_card=agent_card_url, | ||
| httpx_client=async_client, | ||
| ) | ||
| ) |
There was a problem hiding this comment.
This loop to initialize the remote agents can be made more concise and robust. Using a list comprehension is more idiomatic Python for creating a list from an iterable. Additionally, using urllib.parse.urlparse to extract the agent name from the address is more reliable than split('/'), as it correctly handles variations in URL structure (e.g., with or without a trailing slash).
# Create RemoteA2aAgent instances for each remote agent.
remote_agents = [
RemoteA2aAgent(
name=urlparse(address).path.split("/")[-1],
agent_card=f"{address}/.well-known/agent-card.json",
httpx_client=async_client,
)
for address in REMOTE_AGENT_ADDRESSES
]| # The RemoteA2aAgent returns a DataPart, which serializes to `{'data': ...}`. | ||
| # We need to unwrap the actual mandate from inside the 'data' key. | ||
| unwrapped_mandate = cart_mandate.get("data", cart_mandate) | ||
| cart_data = unwrapped_mandate.get( | ||
| "ap2.mandates.CartMandate", unwrapped_mandate | ||
| ) |
There was a problem hiding this comment.
The logic for unwrapping the nested cart_data is a bit dense. While it correctly handles the expected structure, using a more descriptive intermediate variable name would improve readability and make the data flow easier to follow, especially when debugging.
| # The RemoteA2aAgent returns a DataPart, which serializes to `{'data': ...}`. | |
| # We need to unwrap the actual mandate from inside the 'data' key. | |
| unwrapped_mandate = cart_mandate.get("data", cart_mandate) | |
| cart_data = unwrapped_mandate.get( | |
| "ap2.mandates.CartMandate", unwrapped_mandate | |
| ) | |
| # The RemoteA2aAgent returns a DataPart, which serializes to a dict | |
| # like `{'data': {'ap2.mandates.CartMandate': {...}}}`. | |
| # We need to unwrap the actual mandate from these nested keys. | |
| data_part_content = cart_mandate.get("data", cart_mandate) | |
| cart_data = data_part_content.get( | |
| "ap2.mandates.CartMandate", data_part_content | |
| ) |
…f the remote agents, async_client and client_agent_imp
This standardizes our agent-to-agent (A2A) communication in the ap2-demo by refactoring the client agent to use the official RemoteA2aAgent from the Google ADK.
Core Changes & Impact
A2A Protocol Compliance: Ensures the AP2 demo strictly adheres to the latest A2A specification by utilizing the official ADK implementation for remote agent discovery and invocation.
Reduced Boilerplate (Maintainability): Eliminates two custom, high-maintenance files:
_remote_agent_connection.py
_task_store.py
Idiomatic ADK Setup: client_agent/agent.py is updated to instantiate RemoteA2aAgent instances and pass them as tools to the orchestrator agent, following the recommended pattern for multi-agent composition.
Dependency Update: Updates uv.lock and pyproject.toml to reflect necessary ADK dependencies.
This is a clean, structural improvement that future-proofs the demo.