Skip to content

Commit 05a1c41

Browse files
authored
Merge pull request #175 from UiPath/feature/demo-a2a-agents
feat(samples): add remote a2a samples
2 parents 60eadd5 + fec4fab commit 05a1c41

7 files changed

Lines changed: 251 additions & 0 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Multi-Agent Remote (A2A) Sample
2+
3+
This sample demonstrates how to orchestrate **remote UiPath agents** via the [A2A protocol](https://google.github.io/A2A/) using Google ADK. A local coordinator agent delegates tasks to remote specialist agents hosted in UiPath, combining local orchestration with remote execution.
4+
5+
## Architecture
6+
7+
```
8+
SequentialAgent (pipeline)
9+
+-- Agent (coordinator) ........... local, delegates to remote sub-agents
10+
| +-- RemoteA2aAgent (research_agent) ... UiPath Studio Web agent
11+
| +-- RemoteA2aAgent (code_agent) ....... UiPath Studio Web agent
12+
+-- Agent (formatter) ............. local, structures output as JSON
13+
```
14+
15+
## Prerequisites
16+
17+
- [UiPath CLI](https://docs.uipath.com/cli) installed and configured
18+
- Access to [UiPath Studio Web](https://cloud.uipath.com/)
19+
- Python 3.10+
20+
21+
## Step 1: Create the Agents in UiPath Studio Web
22+
23+
Go to **UiPath Studio Web** and create a new solution (e.g. `MultiAgentSolution 1`) with two agents:
24+
25+
![UiPath Studio Web - ResearcherAgent](studio_web_screenshot.png)
26+
27+
### ResearcherAgent (Conversational Agent)
28+
29+
- **Model:** `anthropic.claude-sonnet-4-5-20250929-v1:0` (or any supported model)
30+
- **System prompt:**
31+
32+
```
33+
You are a research specialist. Use the search_web tool to find information about the given topic. Provide a thorough summary of your findings.
34+
```
35+
36+
### PythonCoderAgent (Conversational Agent)
37+
38+
- **Model:** any supported model
39+
- **System prompt:**
40+
41+
```
42+
You are a Python developer. Given a topic, write a short, practical Python code example that demonstrates or relates to the topic. Use the run_python tool to execute your code and verify it works. Return both the code and its output.
43+
```
44+
45+
## Step 2: Deploy and Configure
46+
47+
1. **Publish** the solution from Studio Web
48+
2. **Deploy** the solution to a folder in Orchestrator
49+
3. Note down the **folder key** (from the folder URL) and the **release IDs** for each agent
50+
4. Update [main.py](main.py) with your values:
51+
52+
```python
53+
ORG_NAME = "YourOrgName"
54+
TENANT_NAME = "YourTenantName"
55+
RESEARCH_AGENT_FOLDER_KEY = "<your-folder-key>"
56+
RESEARCH_AGENT_RELEASE_ID = "<your-release-id>"
57+
CODE_AGENT_FOLDER_KEY = "<your-folder-key>"
58+
CODE_AGENT_RELEASE_ID = "<your-release-id>"
59+
```
60+
61+
## Step 3: Run
62+
63+
```bash
64+
uipath auth
65+
uipath dev web
66+
```
67+
68+
This authenticates with UiPath Cloud and starts the local dev server with the ADK agent pipeline.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
flowchart TB
2+
__start__(__start__)
3+
pipeline(pipeline)
4+
coordinator(coordinator)
5+
research_agent(research_agent)
6+
code_agent(code_agent)
7+
formatter(formatter)
8+
__end__(__end__)
9+
coordinator --> research_agent
10+
research_agent --> coordinator
11+
coordinator --> code_agent
12+
code_agent --> coordinator
13+
pipeline --> coordinator
14+
coordinator --> pipeline
15+
pipeline --> formatter
16+
formatter --> pipeline
17+
__start__ --> |input|pipeline
18+
pipeline --> |output|__end__
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"agents": {
3+
"agent": "main.py:agent"
4+
}
5+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
"""Google ADK multi-agent-remote example: same pipeline as multi-agent but with sub-agents hosted remotely via A2A.
2+
3+
Demonstrates how to mix local orchestration with remote agent implementations:
4+
- Coordinator and formatter run locally (they hold the orchestration logic)
5+
- Specialist sub-agents (research, code) are RemoteA2aAgent instances hosted elsewhere
6+
- The remote services don't need to know about each other — coordination stays local
7+
8+
Compare with the multi-agent sample:
9+
multi-agent: Agent(tools=[search_web]) Agent(tools=[run_python])
10+
multi-agent-remote: RemoteA2aAgent(agent_card=...) for each specialist
11+
12+
The key insight: RemoteA2aAgent cannot have sub_agents (it's not an LlmAgent),
13+
but a local Agent CAN have RemoteA2aAgent instances as its sub_agents. This lets
14+
you keep orchestration logic local while moving implementations to remote services.
15+
"""
16+
17+
import os
18+
19+
import httpx
20+
from a2a.client.client import ClientConfig as A2AClientConfig
21+
from a2a.client.client_factory import ClientFactory as A2AClientFactory
22+
from a2a.types import TransportProtocol as A2ATransport
23+
from google.adk.agents import Agent, SequentialAgent
24+
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
25+
from pydantic import BaseModel, Field
26+
27+
28+
class ReportInput(BaseModel):
29+
"""Structured input for the report generation pipeline."""
30+
31+
topic: str = Field(
32+
default="Natural Language Processing fundamentals",
33+
description="The topic to research and analyze",
34+
)
35+
depth: str = Field(
36+
default="standard",
37+
description="How deep the analysis should be: 'brief', 'standard', or 'detailed'",
38+
)
39+
40+
41+
class ReportOutput(BaseModel):
42+
"""Structured output from the report generation pipeline."""
43+
44+
title: str = Field(description="Report title")
45+
summary: str = Field(description="Executive summary of findings")
46+
key_findings: list[str] = Field(description="Key findings as bullet points")
47+
code_snippet: str = Field(description="A relevant Python code example")
48+
49+
50+
# UIPATH_ACCESS_TOKEN is set automatically by `uipath auth`
51+
_access_token = os.environ.get("UIPATH_ACCESS_TOKEN", "")
52+
53+
_http_client = httpx.AsyncClient(
54+
headers={"Authorization": f"Bearer {_access_token}"},
55+
timeout=httpx.Timeout(300.0),
56+
)
57+
58+
_a2a_client_factory = A2AClientFactory(
59+
config=A2AClientConfig(
60+
httpx_client=_http_client,
61+
supported_transports=[A2ATransport.jsonrpc],
62+
streaming=False,
63+
polling=False,
64+
accepted_output_modes=["text"],
65+
),
66+
)
67+
68+
# --- Remote Sub-agents ---
69+
# Replace the URLs with your actual deployed agent endpoints.
70+
ORG_NAME = "YourOrgName"
71+
TENANT_NAME = "YourTenantName"
72+
RESEARCH_AGENT_FOLDER_KEY = "a11f72b1-90fd-4b30-b733-f0285cbf4a19"
73+
RESEARCH_AGENT_RELEASE_ID = "1234"
74+
CODE_AGENT_FOLDER_KEY = "b22f83c2-91fe-5c41-c844-g1396dcg5b2a"
75+
CODE_AGENT_RELEASE_ID = "5678"
76+
77+
research_agent = RemoteA2aAgent(
78+
name="research_agent",
79+
agent_card=f"https://cloud.uipath.com/{ORG_NAME}/{TENANT_NAME}/agenthub_/a2a/{RESEARCH_AGENT_FOLDER_KEY}/{RESEARCH_AGENT_RELEASE_ID}/.well-known/agent-card.json",
80+
description="Remote research specialist that searches the web and summarizes findings",
81+
a2a_client_factory=_a2a_client_factory,
82+
)
83+
84+
code_agent = RemoteA2aAgent(
85+
name="code_agent",
86+
agent_card=f"https://cloud.uipath.com/{ORG_NAME}/{TENANT_NAME}/agenthub_/a2a/{CODE_AGENT_FOLDER_KEY}/{CODE_AGENT_RELEASE_ID}/.well-known/agent-card.json",
87+
description="Remote Python developer that writes and executes code examples",
88+
a2a_client_factory=_a2a_client_factory,
89+
)
90+
91+
92+
# --- Coordinator (local Agent, sub_agents are remote) ---
93+
coordinator = Agent(
94+
name="coordinator",
95+
model="gemini-2.5-flash",
96+
instruction=(
97+
"You are a report coordinator. Given a topic:\n"
98+
"1. Delegate research to research_agent to gather information\n"
99+
"2. Delegate to code_agent to write a relevant Python code example\n"
100+
"3. Compile all findings into a comprehensive text report\n"
101+
"Include the research findings and the code example in your response."
102+
),
103+
sub_agents=[research_agent, code_agent],
104+
input_schema=ReportInput,
105+
output_key="research_results",
106+
)
107+
108+
109+
# --- Formatter (local Agent with output_schema) ---
110+
formatter = Agent(
111+
name="formatter",
112+
model="gemini-2.5-flash",
113+
instruction=(
114+
"You are a report formatter. Take the research results from the previous "
115+
"step and format them into a structured report with a title, summary, "
116+
"key findings, and a code snippet. Output valid JSON matching the schema."
117+
),
118+
output_schema=ReportOutput,
119+
output_key="report",
120+
)
121+
122+
123+
# --- Root: SequentialAgent pipeline ---
124+
agent = SequentialAgent(
125+
name="pipeline",
126+
sub_agents=[coordinator, formatter],
127+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[project]
2+
name = "multi-agent-remote"
3+
version = "0.0.1"
4+
description = "Google ADK multi-agent example with RemoteA2aAgent sub-agents via A2A protocol"
5+
readme = "README.md"
6+
requires-python = ">=3.11"
7+
dependencies = [
8+
"uipath-google-adk",
9+
"google-adk[a2a]>=1.25.0",
10+
"uipath>=2.8.18, <2.9.0",
11+
]
12+
13+
[dependency-groups]
14+
dev = [
15+
"uipath-dev",
16+
]
17+
18+
[tool.uv]
19+
override-dependencies = ["opentelemetry-sdk>=1.39.0,<1.40.0"]
198 KB
Loading
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"$schema": "https://cloud.uipath.com/draft/2024-12/uipath",
3+
"runtimeOptions": {
4+
"isConversational": false
5+
},
6+
"packOptions": {
7+
"fileExtensionsIncluded": [],
8+
"filesIncluded": [],
9+
"filesExcluded": [],
10+
"directoriesExcluded": [],
11+
"includeUvLock": true
12+
},
13+
"functions": {}
14+
}

0 commit comments

Comments
 (0)