Skip to content

Commit 2ba12a7

Browse files
authored
Add Agent Builder A2A with Agent Framework example app (#508)
1 parent 784680f commit 2ba12a7

File tree

6 files changed

+333
-0
lines changed

6 files changed

+333
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM python:3.11-slim
2+
3+
WORKDIR /app
4+
5+
RUN python -m venv /opt/venv
6+
7+
ENV PATH="/opt/venv/bin:$PATH"
8+
9+
COPY requirements.txt .
10+
11+
RUN pip install -r requirements.txt
12+
13+
COPY elastic_agent_builder_a2a.py .
14+
15+
CMD ["python", "elastic_agent_builder_a2a.py"]
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Elastic Agent Builder A2A App
2+
3+
**Getting started with Agent Builder and A2A using Microsoft Agent Framework**
4+
5+
This is an example Python console app that demonstrates how to connect and utilize an [Elastic Agent Builder](https://www.elastic.co/elasticsearch/agent-builder) agent via the Agent2Agent (A2A) Protocol orchestrated with the [Microsoft Agent Framework](https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview).
6+
7+
## Prerequisites
8+
9+
1. An Elasticsearch project/deployment running in [Elastic Cloud](https://cloud.elastic.co/registration?utm_source=github&utm_content=elasticsearch-labs-example-apps).
10+
* Requires Elasticsearch serverless project (or for hosted deployments at least Elasticsearch version 9.2.0).
11+
2. A text editor or an integrated development environment (IDE) like [Visual Studio Code](https://code.visualstudio.com/download) running on your local computer.
12+
3. [Python version 3.10 or greater](https://www.python.org/downloads/) installed on your local computer.
13+
14+
## Set up your Elasticsearch project
15+
16+
1. Create an index named `my-docs` in your Elasticsearch project by running the following command in Elastic Developer Tools:
17+
18+
PUT /my-docs
19+
{
20+
"mappings": {
21+
"properties": {
22+
"title": { "type": "text" },
23+
"content": {
24+
"type": "semantic_text"
25+
},
26+
"filename": { "type": "keyword" },
27+
"last_modified": { "type": "date" }
28+
}
29+
}
30+
}
31+
2. Insert a document into your index named `greetings.md` by running the following command in Elastic Developer Tools:
32+
33+
PUT /my-docs/_doc/greetings-md
34+
{
35+
"title": "Greetings",
36+
"content": "
37+
# Greetings
38+
## Basic Greeting
39+
Hello!
40+
41+
## Helloworld Greeting
42+
Hello World! 🌎
43+
44+
## Not Greeting
45+
I'm only a greeting agent. 🤷
46+
47+
",
48+
"filename": "greetings.md",
49+
"last_modified": "2025-11-04T12:00:00Z"
50+
}
51+
52+
3. In Elastic Agent Builder, create a **tool** with the following values:
53+
* **Type**: `ES|QL`
54+
* **Tool ID**: `example.get_greetings`
55+
* **Description**: `Get greetings doc from Elasticsearch my-docs index.`
56+
* **ES|QL**:
57+
58+
FROM my-docs | WHERE filename == "greetings.md"
59+
60+
4. In Elastic Agent Builder, create an **agent** with the following values:
61+
* **Agent ID**: `helloworld_agent`
62+
* **Custom Instructions**:
63+
64+
If the prompt contains greeting text like "Hi" or "Hello" then respond with only the Basic Hello text from your documents.
65+
66+
If the prompt contains the text “Hello World” then respond with only the Hello World text from your documents.
67+
68+
In all other cases where the prompt does not contain greeting words, then respond with only the Not Greeting text from your documents.
69+
70+
* **Display Name**: `HelloWorld Agent`
71+
* **Display Description**: `An agent that responds to greetings.`
72+
73+
74+
75+
## Clone the example app
76+
77+
1. Open a terminal and clone the Search Labs source code repository which contains the Elastic Agent Builder A2A App example. Run the following command to clone the example app:
78+
79+
git clone https://github.com/elastic/elasticsearch-labs
80+
81+
3. `cd` to change directory to the example code located in the `supporting-blog-content/agent-builder-a2a-agent-framework` subdirectory.
82+
83+
cd elasticsearch-labs/supporting-blog-content/agent-builder-a2a-agent-framework
84+
85+
## Set up the environment variables
86+
87+
1. Set up the environment variables with values copied from your Elastic project.
88+
1. Make a copy of the file `env.example` and name the new file `.env `
89+
2. Edit the `.env` file to set the values of the environment variables to use the values copied from your Elastic project.
90+
* Replace <YOUR-ELASTIC-AGENT-BUILDER-URL\>
91+
1. In your Elastic project, go to the Elastic Agent Builder - Tools page. Click the **MCP Server** dropdown at the top of the Tools page. Select **Copy MCP Server URL.**
92+
2. Add the **MCP Server URL** value to the `.env` file.
93+
* Find where the placeholder text “**<YOUR-ELASTIC-AGENT-BUILDER-URL\>**” appears and paste in the copied **MCP Server URL** to replace the placeholder text. Now edit the pasted **MCP Server URL**. Delete the text “mcp” at the end of the URL and replace it with the text “a2a”. The edited URL should look something like this
94+
95+
`https://example-project-a123.kb.westus2.azure.elastic.cloud/api/agent_builder/a2a`
96+
97+
* Replace <YOUR-ELASTIC-API-KEY\>
98+
1. In your Elastic project, click **Elasticsearch** in the navigation menu to go to your project’s home page.
99+
2. Click **Create API key** to create a new API key.
100+
3. After the API key is created, copy the API Key value.
101+
4. Add the API Key value to the `.env` file.
102+
* Find where the placeholder text “**<YOUR-ELASTIC-API-KEY\>**” appears and paste in the copied API Key value to replace the placeholder text.
103+
104+
3. Save the changes to the `.env` file.
105+
106+
## Running the example app with Python
107+
108+
1. Create a Python virtual environment by running the following code in the terminal.
109+
110+
python -m venv .venv
111+
112+
2. Activate the Python virtual environment.
113+
* If you’re running MacOS, the command to activate the virtual environment is:
114+
115+
source .venv/bin/activate
116+
117+
* If you’re on Windows, the command to activate the virtual environment is:
118+
119+
.venv\Scripts\activate
120+
121+
3. Install the Microsoft Agent Framework along with its necessary Python packages by running the following `pip` command:
122+
123+
pip install -r requirements.txt
124+
125+
4. Run the example app by entering the following command into the terminal:
126+
127+
python elastic_agent_builder_a2a.py
128+
129+
## Running the example app with Docker
130+
131+
1. Run the example app with Docker by entering the following command into the terminal:
132+
133+
docker compose run elastic-agent-builder-a2a
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
services:
2+
elastic-agent-builder-a2a:
3+
build: .
4+
container_name: elastic-agent-builder-a2a
5+
stdin_open: true
6+
tty: true
7+
environment:
8+
- ES_AGENT_URL=${ES_AGENT_URL}
9+
- ES_API_KEY=${ES_API_KEY}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import asyncio
2+
from dotenv import load_dotenv
3+
import httpx
4+
import os
5+
from a2a.client import A2ACardResolver
6+
from agent_framework.a2a import A2AAgent
7+
8+
9+
async def main():
10+
load_dotenv()
11+
a2a_agent_host = os.getenv("ES_AGENT_URL")
12+
a2a_agent_key = os.getenv("ES_API_KEY")
13+
14+
print(f"Connection to Elastic A2A agent at: {a2a_agent_host}")
15+
16+
custom_headers = {"Authorization": f"ApiKey {a2a_agent_key}"}
17+
18+
async with httpx.AsyncClient(timeout=60.0, headers=custom_headers) as http_client:
19+
# Resolve the A2A Agent Card
20+
resolver = A2ACardResolver(httpx_client=http_client, base_url=a2a_agent_host)
21+
agent_card = await resolver.get_agent_card(
22+
relative_card_path="/helloworld_agent.json"
23+
)
24+
print(f"Found Agent: {agent_card.name} - {agent_card.description}")
25+
26+
# Use the Agent
27+
agent = A2AAgent(
28+
name=agent_card.name,
29+
description=agent_card.description,
30+
agent_card=agent_card,
31+
url=a2a_agent_host,
32+
http_client=http_client,
33+
)
34+
prompt = input("Enter Greeting >>> ")
35+
print("\nSending message to Elastic A2A agent...")
36+
response = await agent.run(prompt)
37+
print("\nAgent Response:")
38+
for message in response.messages:
39+
print(message.text)
40+
41+
42+
if __name__ == "__main__":
43+
asyncio.run(main())
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ES_AGENT_URL=<YOUR-ELASTIC-AGENT-BUILDER-URL>
2+
ES_API_KEY=<YOUR-ELASTIC-API-KEY>
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
a2a-sdk~=0.3.14
2+
ag-ui-protocol~=0.1.10
3+
agent-framework~=1.0.0b251114
4+
agent-framework-a2a~=1.0.0b251114
5+
agent-framework-ag-ui~=1.0.0b251117
6+
agent-framework-anthropic~=1.0.0b251114
7+
agent-framework-azure-ai~=1.0.0b251114
8+
agent-framework-azurefunctions~=1.0.0b251114
9+
agent-framework-chatkit~=1.0.0b251114
10+
agent-framework-copilotstudio~=1.0.0b251114
11+
agent-framework-core~=1.0.0b251114
12+
agent-framework-devui~=1.0.0b251114
13+
agent-framework-lab~=1.0.0b251024
14+
agent-framework-mem0~=1.0.0b251114
15+
agent-framework-purview~=1.0.0b251114
16+
agent-framework-redis~=1.0.0b251114
17+
aiohappyeyeballs~=2.6.1
18+
aiohttp~=3.13.2
19+
aiosignal~=1.4.0
20+
annotated-doc~=0.0.4
21+
annotated-types~=0.7.0
22+
anthropic~=0.74.0
23+
anyio~=4.11.0
24+
attrs~=25.4.0
25+
azure-ai-agents~=1.2.0b5
26+
azure-ai-projects~=2.0.0b2
27+
azure-core~=1.36.0
28+
azure-functions~=1.24.0
29+
azure-functions-durable~=1.4.0
30+
azure-identity~=1.25.1
31+
azure-storage-blob~=12.27.1
32+
backoff~=2.2.1
33+
cachetools~=6.2.2
34+
certifi~=2025.11.12
35+
cffi~=2.0.0
36+
charset-normalizer~=3.4.4
37+
click~=8.3.1
38+
colorama~=0.4.6
39+
cryptography~=46.0.3
40+
distro~=1.9.0
41+
docstring_parser~=0.17.0
42+
fastapi~=0.121.2
43+
frozenlist~=1.8.0
44+
furl~=2.1.4
45+
google-api-core~=2.28.1
46+
google-auth~=2.43.0
47+
googleapis-common-protos~=1.72.0
48+
griffe~=1.15.0
49+
grpcio~=1.76.0
50+
h11~=0.16.0
51+
h2~=4.3.0
52+
hpack~=4.1.0
53+
httpcore~=1.0.9
54+
httptools~=0.7.1
55+
httpx~=0.28.1
56+
httpx-sse~=0.4.3
57+
hyperframe~=6.1.0
58+
idna~=3.11
59+
importlib_metadata~=8.7.0
60+
isodate~=0.7.2
61+
jiter~=0.12.0
62+
jsonpath-ng~=1.7.0
63+
jsonschema~=4.25.1
64+
jsonschema-specifications~=2025.9.1
65+
MarkupSafe~=3.0.3
66+
mcp~=1.21.2
67+
mem0ai~=1.0.1
68+
microsoft-agents-activity~=0.6.0
69+
microsoft-agents-copilotstudio-client~=0.6.0
70+
microsoft-agents-hosting-core~=0.6.0
71+
ml_dtypes~=0.5.4
72+
msal~=1.34.0
73+
msal-extensions~=1.3.1
74+
multidict~=6.7.0
75+
numpy~=2.3.5
76+
openai~=2.8.1
77+
openai-agents~=0.6.0
78+
openai-chatkit~=1.3.0
79+
opentelemetry-api~=1.38.0
80+
opentelemetry-exporter-otlp-proto-common~=1.38.0
81+
opentelemetry-exporter-otlp-proto-grpc~=1.38.0
82+
opentelemetry-proto~=1.38.0
83+
opentelemetry-sdk~=1.38.0
84+
opentelemetry-semantic-conventions~=0.59b0
85+
opentelemetry-semantic-conventions-ai~=0.4.13
86+
orderedmultidict~=1.0.2
87+
packaging~=25.0
88+
ply~=3.11
89+
portalocker~=3.2.0
90+
posthog~=7.0.1
91+
propcache~=0.4.1
92+
proto-plus~=1.26.1
93+
protobuf~=5.29.5
94+
pyasn1~=0.6.1
95+
pyasn1_modules~=0.4.2
96+
pycparser~=2.23
97+
pydantic~=2.12.4
98+
pydantic-settings~=2.12.0
99+
pydantic_core~=2.41.5
100+
PyJWT~=2.10.1
101+
python-dateutil~=2.9.0.post0
102+
python-dotenv~=1.2.1
103+
python-multipart~=0.0.20
104+
python-ulid~=3.1.0
105+
pytz~=2025.2
106+
PyYAML~=6.0.3
107+
qdrant-client~=1.16.0
108+
redis~=6.4.0
109+
redisvl~=0.11.0
110+
referencing~=0.37.0
111+
requests~=2.32.5
112+
rpds-py~=0.29.0
113+
rsa~=4.9.1
114+
six~=1.17.0
115+
sniffio~=1.3.1
116+
SQLAlchemy~=2.0.44
117+
sse-starlette~=3.0.3
118+
starlette~=0.49.3
119+
tenacity~=9.1.2
120+
tqdm~=4.67.1
121+
types-requests~=2.32.4.20250913
122+
typing-inspection~=0.4.2
123+
typing_extensions~=4.15.0
124+
urllib3~=2.5.0
125+
uvicorn~=0.38.0
126+
uvloop~=0.22.1
127+
watchfiles~=1.1.1
128+
websockets~=15.0.1
129+
Werkzeug~=3.1.3
130+
yarl~=1.22.0
131+
zipp~=3.23.0

0 commit comments

Comments
 (0)