Skip to content

feat: Add a new Get Started example for A2A#511

Open
msampathkumar wants to merge 7 commits intomainfrom
sampath_getstarted
Open

feat: Add a new Get Started example for A2A#511
msampathkumar wants to merge 7 commits intomainfrom
sampath_getstarted

Conversation

@msampathkumar
Copy link
Copy Markdown

Description

Created a Google ADK-powered agent(as A2A Server) that poetically reports weather updates. It leverages Google Search to gather factual weather data and presents it in the form of haikus or short poems, making weather forecasts engaging and unique.

DEMO: Using A2A client(pure python), we will send queries and receive messages from A2A Server.


Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

Fixes #<issue_number_goes_here> 🦕

This commit introduces several enhancements to the Weather Reporting Poet agent and its project infrastructure:
- Updated Licensing and Metadata: Incorporated new copyright headers and Apache 2.0 license information across relevant files (Makefile, README.md). Version information in Makefile and app.py has been updated.
- Improved Client-Server Interaction: Refactored message handling in the client (client_app.py) for a more robust user interaction. Updated agent server configuration in app.py and agent core logic in agent.py and agent_executor.py.
- Streamlined README: Enhanced the README.md with clearer setup, installation, and usage instructions, including example interactions and contribution guidelines.

These changes aim to improve the agent's usability, maintainability, and adherence to project standards.
@msampathkumar msampathkumar changed the title feat: Add a new Get Started feat: Add a new Get Started example for A2A Apr 10, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a "Get Started" sample for the Agent-to-Agent (A2A) protocol, featuring a weather-reporting poet agent with server and client implementations. Key feedback includes replacing blocking sleep calls with asynchronous ones, fixing undefined variables and copy-paste errors in the Makefile, ensuring consistent role naming, optimizing event loop management, and correcting a model name typo and an error message.

Comment on lines +41 to +60
def sprint(text: str):
"""Print a text with a delay to simulate a long process"""
time.sleep(0.2)
print(text)


async def show_agent_card():
"""Show the agent card in the terminal"""
print("#" * 45)
agent_card = await get_agent_card()
sprint(f"Agent Card - Name: {agent_card.name}")
sprint(f"Agent Card - Capabilities: {agent_card.capabilities}")
sprint(f"Agent Card - Description: {agent_card.description}")
sprint(f"Agent Card - Skills: ")
for i, each in enumerate(agent_card.skills):
sprint(f"Agent Card - Skills[{i + 1}]:")
sprint(f"\t Skill - Id: {each.id}")
sprint(f"\t Skill - Name: {each.name}")
sprint(f"\t Skill - Description: {each.description}")
sprint(f"\t Skill - Examples: {each.examples}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using time.sleep() in an asynchronous application blocks the event loop. It is recommended to use await asyncio.sleep() and make the sprint function asynchronous. All calls to sprint should then be updated to use await.

Suggested change
def sprint(text: str):
"""Print a text with a delay to simulate a long process"""
time.sleep(0.2)
print(text)
async def show_agent_card():
"""Show the agent card in the terminal"""
print("#" * 45)
agent_card = await get_agent_card()
sprint(f"Agent Card - Name: {agent_card.name}")
sprint(f"Agent Card - Capabilities: {agent_card.capabilities}")
sprint(f"Agent Card - Description: {agent_card.description}")
sprint(f"Agent Card - Skills: ")
for i, each in enumerate(agent_card.skills):
sprint(f"Agent Card - Skills[{i + 1}]:")
sprint(f"\t Skill - Id: {each.id}")
sprint(f"\t Skill - Name: {each.name}")
sprint(f"\t Skill - Description: {each.description}")
sprint(f"\t Skill - Examples: {each.examples}")
async def sprint(text: str):
"""Print a text with a delay to simulate a long process"""
await asyncio.sleep(0.2)
print(text)
async def show_agent_card():
"""Show the agent card in the terminal"""
print("#" * 45)
agent_card = await get_agent_card()
await sprint(f"Agent Card - Name: {agent_card.name}")
await sprint(f"Agent Card - Capabilities: {agent_card.capabilities}")
await sprint(f"Agent Card - Description: {agent_card.description}")
await sprint(f"Agent Card - Skills: ")
for i, each in enumerate(agent_card.skills):
await sprint(f"Agent Card - Skills[{i + 1}]:")
await sprint(f"\t Skill - Id: {each.id}")
await sprint(f"\t Skill - Name: {each.name}")
await sprint(f"\t Skill - Description: {each.description}")
await sprint(f"\t Skill - Examples: {each.examples}")

Comment on lines +21 to +22
export APP_VERSION=${IMAGE_VERSION}
@echo "Application Version "${IMAGE_VERSION}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

The variable ${IMAGE_VERSION} is not defined in this Makefile. It should likely refer to APP_VERSION defined on line 14.

	export APP_VERSION=$(APP_VERSION)
	@echo "Application Version "$(APP_VERSION)

run_server: ## Run python a2a server
cd server && python app.py

run_client: ## Prints the Application Version
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

The help description for run_client is incorrect and appears to be a copy-paste error from the version command.

run_client: ## Run python a2a client

# create a client message object
parts = [types.Part(text=text_query)]
message = types.Message(
role=types.Role.ROLE_USER,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

To be consistent with the changes in helloworld/test_client.py, the role should be types.Role.user instead of types.Role.ROLE_USER.

Suggested change
role=types.Role.ROLE_USER,
role=types.Role.user,

Comment on lines +97 to +104
if __name__ == "__main__":
# Ensure the event loop is properly managed
try:
asyncio.run(show_agent_card())
asyncio.run(send_message("How is the Weather in Poland, Warsaw?"))
# asyncio.run(WeatherClient().run_interactive_terminal())
except KeyboardInterrupt:
print("Exiting client due to user interruption.")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

Calling asyncio.run() multiple times is inefficient as it creates and closes a new event loop for each call. It is better to wrap the logic in a single async main() function and run it once.

Suggested change
if __name__ == "__main__":
# Ensure the event loop is properly managed
try:
asyncio.run(show_agent_card())
asyncio.run(send_message("How is the Weather in Poland, Warsaw?"))
# asyncio.run(WeatherClient().run_interactive_terminal())
except KeyboardInterrupt:
print("Exiting client due to user interruption.")
if __name__ == "__main__":
async def main():
await show_agent_card()
await send_message("How is the Weather in Poland, Warsaw?")
try:
asyncio.run(main())
except KeyboardInterrupt:
print("Exiting client due to user interruption.")


def create_agent() -> LlmAgent:
return LlmAgent(
model="gemini-2.5-flash-lite",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

gemini-2.5-flash-lite appears to be a typo. It is recommended to use a valid model name like gemini-1.5-flash, gemini-2.0-flash, or gemini-3-flash-preview.

Suggested change
model="gemini-2.5-flash-lite",
model="gemini-3-flash-preview",
References
  1. 'gemini-3-flash-preview' is a valid model name.

async def cancel(
self, request: RequestContext, event_queue: EventQueue
) -> Task | None:
raise UnsupportedOperationError("Error: Streaming Operation not supported")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

The error message in the cancel method incorrectly refers to "Streaming Operation". It should be updated to reflect that the "Cancel" operation is not supported.

Suggested change
raise UnsupportedOperationError("Error: Streaming Operation not supported")
raise UnsupportedOperationError("Error: Cancel operation not supported")

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant