Skip to content

Commit 379810d

Browse files
seanzhougooglecopybara-github
authored andcommitted
chore: Add a human in the loop a2a agent demo sample
PiperOrigin-RevId: 776660876
1 parent 1cf5cf0 commit 379810d

File tree

6 files changed

+299
-0
lines changed

6 files changed

+299
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# A2A Human-in-the-Loop Sample Agent
2+
3+
This sample demonstrates the **Agent-to-Agent (A2A)** architecture with **Human-in-the-Loop** workflows in the Agent Development Kit (ADK). The sample implements a reimbursement processing agent that automatically handles small expenses while requiring remote agent to process for larger amounts. The remote agent will require a human approval for large amounts, thus surface this request to local agent and human interacting with local agent can approve the request.
4+
5+
## Overview
6+
7+
The A2A Human-in-the-Loop sample consists of:
8+
9+
- **Root Agent** (`root_agent`): The main reimbursement agent that handles expense requests and delegates approval to remote Approval Agent for large amounts
10+
- **Approval Agent** (`approval_agent`): A remote A2A agent that handles the human approval process via long-running tools (which implements asynchronous approval workflows that can pause execution and wait for human input), this agent is running on a separate A2A server
11+
12+
13+
## Architecture
14+
15+
```
16+
┌─────────────────┐ ┌────────────────────┐ ┌──────────────────┐
17+
│ Human Manager │───▶│ Root Agent │───▶│ Approval Agent │
18+
│ (External) │ │ (Local) │ │ (Remote A2A) │
19+
│ │ │ │ │ (localhost:8001) │
20+
│ Approval UI │◀───│ │◀───│ │
21+
└─────────────────┘ └────────────────────┘ └──────────────────┘
22+
```
23+
24+
## Key Features
25+
26+
### 1. **Automated Decision Making**
27+
- Automatically approves reimbursements under $100
28+
- Uses business logic to determine when human intervention is required
29+
- Provides immediate responses for simple cases
30+
31+
### 2. **Human-in-the-Loop Workflow**
32+
- Seamlessly escalates high-value requests (>$100) to remote approval agent
33+
- Remote approval agent uses long-running tools to surface approval requests back to the root agent
34+
- Human managers interact directly with the root agent to approve/reject requests
35+
36+
### 3. **Long-Running Tool Integration**
37+
- Demonstrates `LongRunningFunctionTool` for asynchronous operations
38+
- Shows how to handle pending states and external updates
39+
- Implements proper tool response handling for delayed approvals
40+
41+
### 4. **Remote A2A Agent Communication**
42+
- The approval agent runs as a separate service that processes approval workflows
43+
- Communicates via HTTP at `http://localhost:8001/a2a/human_in_loop`
44+
- Surfaces approval requests back to the root agent for human interaction
45+
46+
## Setup and Usage
47+
48+
### Prerequisites
49+
50+
1. **Start the Remote Approval Agent server**:
51+
```bash
52+
# Start the remote a2a server that serves the human-in-the-loop approval agent on port 8001
53+
adk api_server --a2a --port 8001 contributing/samples/a2a_human_in_loop/remote_a2a
54+
```
55+
56+
2. **Run the Main Agent**:
57+
```bash
58+
# In a separate terminal, run the adk web server
59+
adk web contributing/samples/
60+
```
61+
62+
### Example Interactions
63+
64+
Once both services are running, you can interact with the root agent through the approval workflow:
65+
66+
**Automatic Approval (Under $100):**
67+
```
68+
User: Please reimburse $50 for meals
69+
Agent: I'll process your reimbursement request for $50 for meals. Since this amount is under $100, I can approve it automatically.
70+
Agent: ✅ Reimbursement approved and processed: $50 for meals
71+
```
72+
73+
**Human Approval Required (Over $100):**
74+
```
75+
User: Please reimburse $200 for conference travel
76+
Agent: I'll process your reimbursement request for $200 for conference travel. Since this amount exceeds $100, I need to get manager approval.
77+
Agent: 🔄 Request submitted for approval (Ticket: reimbursement-ticket-001). Please wait for manager review.
78+
[Human manager interacts with root agent to approve the request]
79+
Agent: ✅ Great news! Your reimbursement has been approved by the manager. Processing $200 for conference travel.
80+
```
81+
82+
## Code Structure
83+
84+
### Main Agent (`agent.py`)
85+
86+
- **`reimburse(purpose: str, amount: float)`**: Function tool for processing reimbursements
87+
- **`approval_agent`**: Remote A2A agent configuration for human approval workflows
88+
- **`root_agent`**: Main reimbursement agent with automatic/manual approval logic
89+
90+
### Remote Approval Agent (`remote_a2a/human_in_loop/`)
91+
92+
- **`agent.py`**: Implementation of the approval agent with long-running tools
93+
- **`agent.json`**: Agent card of the A2A agent
94+
95+
- **`ask_for_approval()`**: Long-running tool that handles approval requests
96+
97+
## Long-Running Tool Workflow
98+
99+
The human-in-the-loop process follows this pattern:
100+
101+
1. **Initial Call**: Root agent delegates approval request to remote approval agent for amounts >$100
102+
2. **Pending Response**: Remote approval agent returns immediate response with `status: "pending"` and ticket ID and serface the approval request to root agent
103+
3. **Agent Acknowledgment**: Root agent informs user about pending approval status
104+
4. **Human Interaction**: Human manager interacts with root agent to review and approve/reject the request
105+
5. **Updated Response**: Root agent receives updated tool response with approval decision and send it to remote agent
106+
6. **Final Action**: Remote agent processes the approval and completes the reimbursement and send the result to root_agent
107+
108+
## Extending the Sample
109+
110+
You can extend this sample by:
111+
112+
- Adding more complex approval hierarchies (multiple approval levels)
113+
- Implementing different approval rules based on expense categories
114+
- Creating additional remote agent for budget checking or policy validation
115+
- Adding notification systems for approval status updates
116+
- Integrating with external approval systems or databases
117+
- Implementing approval timeouts and escalation procedures
118+
119+
## Troubleshooting
120+
121+
**Connection Issues:**
122+
- Ensure the local ADK web server is running on port 8000
123+
- Ensure the remote A2A server is running on port 8001
124+
- Check that no firewall is blocking localhost connections
125+
- Verify the agent.json URL matches the running A2A server
126+
127+
**Agent Not Responding:**
128+
- Check the logs for both the local ADK web server on port 8000 and remote A2A server on port 8001
129+
- Verify the agent instructions are clear and unambiguous
130+
- Ensure long-running tool responses are properly formatted with matching IDs
131+
132+
**Approval Workflow Issues:**
133+
- Verify that updated tool responses use the same `id` and `name` as the original function call
134+
- Check that the approval status is correctly updated in the tool response
135+
- Ensure the human approval process is properly simulated or integrated
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from . import agent
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
from google.adk import Agent
17+
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
18+
from google.genai import types
19+
20+
21+
def reimburse(purpose: str, amount: float) -> str:
22+
"""Reimburse the amount of money to the employee."""
23+
return {
24+
'status': 'ok',
25+
}
26+
27+
28+
approval_agent = RemoteA2aAgent(
29+
name='approval_agent',
30+
description='Help approve the reimburse if the amount is greater than 100.',
31+
agent_card='http://localhost:8001/a2a/human_in_loop/.well-known/agent.json',
32+
)
33+
34+
35+
root_agent = Agent(
36+
model='gemini-1.5-flash',
37+
name='reimbursement_agent',
38+
instruction="""
39+
You are an agent whose job is to handle the reimbursement process for
40+
the employees. If the amount is less than $100, you will automatically
41+
approve the reimbursement. And call reimburse() to reimburse the amount to the employee.
42+
43+
If the amount is greater than $100. You will hand over the request to
44+
approval_agent to handle the reimburse.
45+
""",
46+
tools=[reimburse],
47+
sub_agents=[approval_agent],
48+
generate_content_config=types.GenerateContentConfig(temperature=0.1),
49+
)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from . import agent
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"capabilities": {},
3+
"defaultInputModes": ["text/plain"],
4+
"defaultOutputModes": ["application/json"],
5+
"description": "A reimbursement agent that handles employee expense reimbursement requests. Automatically approves amounts under $100 and requires manager approval for larger amounts using long-running tools for human-in-the-loop workflows.",
6+
"name": "reimbursement_agent",
7+
"skills": [
8+
{
9+
"id": "automatic_reimbursement",
10+
"name": "Automatic Reimbursement",
11+
"description": "Automatically process and approve reimbursements under $100",
12+
"tags": ["reimbursement", "automation", "finance"]
13+
},
14+
{
15+
"id": "approval_workflow",
16+
"name": "Approval Workflow",
17+
"description": "Request manager approval for reimbursements over $100 using long-running tools",
18+
"tags": ["approval", "workflow", "human-in-loop"]
19+
},
20+
{
21+
"id": "expense_processing",
22+
"name": "Expense Processing",
23+
"description": "Process employee expense claims and handle reimbursement logic",
24+
"tags": ["expenses", "processing", "employee-services"]
25+
}
26+
],
27+
"url": "http://localhost:8000/a2a/human_in_loop",
28+
"version": "1.0.0"
29+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from typing import Any
16+
17+
from google.adk import Agent
18+
from google.adk.tools import ToolContext
19+
from google.adk.tools.long_running_tool import LongRunningFunctionTool
20+
from google.genai import types
21+
22+
23+
def reimburse(purpose: str, amount: float) -> str:
24+
"""Reimburse the amount of money to the employee."""
25+
return {
26+
'status': 'ok',
27+
}
28+
29+
30+
def ask_for_approval(
31+
purpose: str, amount: float, tool_context: ToolContext
32+
) -> dict[str, Any]:
33+
"""Ask for approval for the reimbursement."""
34+
return {
35+
'status': 'pending',
36+
'amount': amount,
37+
'ticketId': 'reimbursement-ticket-001',
38+
}
39+
40+
41+
root_agent = Agent(
42+
model='gemini-1.5-flash',
43+
name='reimbursement_agent',
44+
instruction="""
45+
You are an agent whose job is to handle the reimbursement process for
46+
the employees. If the amount is less than $100, you will automatically
47+
approve the reimbursement.
48+
49+
If the amount is greater than $100, you will
50+
ask for approval from the manager. If the manager approves, you will
51+
call reimburse() to reimburse the amount to the employee. If the manager
52+
rejects, you will inform the employee of the rejection.
53+
""",
54+
tools=[reimburse, LongRunningFunctionTool(func=ask_for_approval)],
55+
generate_content_config=types.GenerateContentConfig(temperature=0.1),
56+
)

0 commit comments

Comments
 (0)