chore: Add an a2a sample agent to demo running the a2a server via unvicorn command and run remote agent as root_agent

PiperOrigin-RevId: 785629271
This commit is contained in:
Xiang (Sean) Zhou
2025-07-21 17:08:04 -07:00
committed by Copybara-Service
parent a77d68964a
commit b2c2f1bd33
4 changed files with 273 additions and 0 deletions
+123
View File
@@ -0,0 +1,123 @@
# A2A Root Sample Agent
This sample demonstrates how to use a **remote Agent-to-Agent (A2A) agent as the root agent** in the Agent Development Kit (ADK). This is a simplified approach where the main agent is actually a remote A2A service, also showcasing how to run remote agents using uvicorn command.
## Overview
The A2A Root sample consists of:
- **Root Agent** (`agent.py`): A remote A2A agent proxy as root agent that talks to a remote a2a agent running on a separate server
- **Remote Hello World Agent** (`remote_a2a/hello_world/agent.py`): The actual agent implementation that handles dice rolling and prime number checking running on remote server
## Architecture
```
┌─────────────────┐ ┌────────────────────┐
│ Root Agent │───▶│ Remote Hello │
│ (RemoteA2aAgent)│ │ World Agent │
│ (localhost:8000)│ │ (localhost:8001) │
└─────────────────┘ └────────────────────┘
```
## Key Features
### 1. **Remote A2A as Root Agent**
- The `root_agent` is a `RemoteA2aAgent` that connects to a remote A2A service
- Demonstrates how to use remote agents as the primary agent instead of local agents
- Shows the flexibility of the A2A architecture for distributed agent deployment
### 2. **Uvicorn Server Deployment**
- The remote agent is served using uvicorn, a lightweight ASGI server
- Demonstrates a simple way to deploy A2A agents without using the ADK CLI
- Shows how to expose A2A agents as standalone web services
### 3. **Agent Functionality**
- **Dice Rolling**: Can roll dice with configurable number of sides
- **Prime Number Checking**: Can check if numbers are prime
- **State Management**: Maintains roll history in tool context
- **Parallel Tool Execution**: Can use multiple tools in parallel
### 4. **Simple Deployment Pattern**
- Uses the `to_a2a()` utility to convert a standard ADK agent to an A2A service
- Minimal configuration required for remote agent deployment
## Setup and Usage
### Prerequisites
1. **Start the Remote A2A Agent server**:
```bash
# Start the remote agent using uvicorn
uvicorn contributing.samples.a2a_root.remote_a2a.hello_world.agent:a2a_app --host localhost --port 8001
```
2. **Run the Main Agent**:
```bash
# In a separate terminal, run the adk web server
adk web contributing/samples/
```
### Example Interactions
Once both services are running, you can interact with the root agent:
**Simple Dice Rolling:**
```
User: Roll a 6-sided die
Bot: I rolled a 4 for you.
```
**Prime Number Checking:**
```
User: Is 7 a prime number?
Bot: Yes, 7 is a prime number.
```
**Combined Operations:**
```
User: Roll a 10-sided die and check if it's prime
Bot: I rolled an 8 for you.
Bot: 8 is not a prime number.
```
**Multiple Rolls with Prime Checking:**
```
User: Roll a die 3 times and check which results are prime
Bot: I rolled a 3 for you.
Bot: I rolled a 7 for you.
Bot: I rolled a 4 for you.
Bot: 3, 7 are prime numbers.
```
## Code Structure
### Root Agent (`agent.py`)
- **`root_agent`**: A `RemoteA2aAgent` that connects to the remote A2A service
- **Agent Card URL**: Points to the well-known agent card endpoint on the remote server
### Remote Hello World Agent (`remote_a2a/hello_world/agent.py`)
- **`roll_die(sides: int)`**: Function tool for rolling dice with state management
- **`check_prime(nums: list[int])`**: Async function for prime number checking
- **`root_agent`**: The main agent with comprehensive instructions
- **`a2a_app`**: The A2A application created using `to_a2a()` utility
## Troubleshooting
**Connection Issues:**
- Ensure the uvicorn server is running on port 8001
- Check that no firewall is blocking localhost connections
- Verify the agent card URL in the root agent configuration
- Check uvicorn logs for any startup errors
**Agent Not Responding:**
- Check the uvicorn server logs for errors
- Verify the agent instructions are clear and unambiguous
- Ensure the A2A app is properly configured with the correct port
**Uvicorn Issues:**
- Make sure the module path is correct: `contributing.samples.a2a_root.remote_a2a.hello_world.agent:a2a_app`
- Check that all dependencies are installed
+24
View File
@@ -0,0 +1,24 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
root_agent = RemoteA2aAgent(
name="hello_world_agent",
description=(
"Helpful assistant that can roll dice and check if numbers are prime."
),
agent_card=f"http://localhost:8001/{AGENT_CARD_WELL_KNOWN_PATH}",
)
@@ -0,0 +1,15 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import agent
@@ -0,0 +1,111 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import random
from google.adk import Agent
from google.adk.a2a.utils.agent_to_a2a import to_a2a
from google.adk.tools.tool_context import ToolContext
from google.genai import types
def roll_die(sides: int, tool_context: ToolContext) -> int:
"""Roll a die and return the rolled result.
Args:
sides: The integer number of sides the die has.
tool_context: the tool context
Returns:
An integer of the result of rolling the die.
"""
result = random.randint(1, sides)
if not 'rolls' in tool_context.state:
tool_context.state['rolls'] = []
tool_context.state['rolls'] = tool_context.state['rolls'] + [result]
return result
async def check_prime(nums: list[int]) -> str:
"""Check if a given list of numbers are prime.
Args:
nums: The list of numbers to check.
Returns:
A str indicating which number is prime.
"""
primes = set()
for number in nums:
number = int(number)
if number <= 1:
continue
is_prime = True
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
is_prime = False
break
if is_prime:
primes.add(number)
return (
'No prime numbers found.'
if not primes
else f"{', '.join(str(num) for num in primes)} are prime numbers."
)
root_agent = Agent(
model='gemini-2.0-flash',
name='hello_world_agent',
description=(
'hello world agent that can roll a dice of 8 sides and check prime'
' numbers.'
),
instruction="""
You roll dice and answer questions about the outcome of the dice rolls.
You can roll dice of different sizes.
You can use multiple tools in parallel by calling functions in parallel(in one request and in one round).
It is ok to discuss previous dice roles, and comment on the dice rolls.
When you are asked to roll a die, you must call the roll_die tool with the number of sides. Be sure to pass in an integer. Do not pass in a string.
You should never roll a die on your own.
When checking prime numbers, call the check_prime tool with a list of integers. Be sure to pass in a list of integers. You should never pass in a string.
You should not check prime numbers before calling the tool.
When you are asked to roll a die and check prime numbers, you should always make the following two function calls:
1. You should first call the roll_die tool to get a roll. Wait for the function response before calling the check_prime tool.
2. After you get the function response from roll_die tool, you should call the check_prime tool with the roll_die result.
2.1 If user asks you to check primes based on previous rolls, make sure you include the previous rolls in the list.
3. When you respond, you must include the roll_die result from step 1.
You should always perform the previous 3 steps when asking for a roll and checking prime numbers.
You should not rely on the previous history on prime results.
""",
tools=[
roll_die,
check_prime,
],
# planner=BuiltInPlanner(
# thinking_config=types.ThinkingConfig(
# include_thoughts=True,
# ),
# ),
generate_content_config=types.GenerateContentConfig(
safety_settings=[
types.SafetySetting( # avoid false alarm about rolling dice.
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.OFF,
),
]
),
)
a2a_app = to_a2a(root_agent, port=8001)