Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.11-slim

WORKDIR /app

RUN python -m venv /opt/venv

ENV PATH="/opt/venv/bin:$PATH"

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY elastic_agent_builder_a2a.py .

CMD ["python", "elastic_agent_builder_a2a.py"]
133 changes: 133 additions & 0 deletions supporting-blog-content/agent-builder-a2a-agent-framework/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Elastic Agent Builder A2A App

**Getting started with Agent Builder and A2A using Microsoft Agent Framework**

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).

## Prerequisites

1. An Elasticsearch project/deployment running in [Elastic Cloud](https://cloud.elastic.co/registration?utm_source=github&utm_content=elasticsearch-labs-example-apps).
* Requires Elasticsearch serverless project (or for hosted deployments at least Elasticsearch version 9.2.0).
2. A text editor or an integrated development environment (IDE) like [Visual Studio Code](https://code.visualstudio.com/download) running on your local computer.
3. [Python version 3.10 or greater](https://www.python.org/downloads/) installed on your local computer.

## Set up your Elasticsearch project

1. Create an index named `my-docs` in your Elasticsearch project by running the following command in Elastic Developer Tools:

PUT /my-docs
{
"mappings": {
"properties": {
"title": { "type": "text" },
"content": {
"type": "semantic_text"
},
"filename": { "type": "keyword" },
"last_modified": { "type": "date" }
}
}
}
2. Insert a document into your index named `greetings.md` by running the following command in Elastic Developer Tools:

PUT /my-docs/_doc/greetings-md
{
"title": "Greetings",
"content": "
# Greetings
## Basic Greeting
Hello!

## Helloworld Greeting
Hello World! 🌎

## Not Greeting
I'm only a greeting agent. 🤷

",
"filename": "greetings.md",
"last_modified": "2025-11-04T12:00:00Z"
}

3. In Elastic Agent Builder, create a **tool** with the following values:
* **Type**: `ES|QL`
* **Tool ID**: `example.get_greetings`
* **Description**: `Get greetings doc from Elasticsearch my-docs index.`
* **ES|QL**:

FROM my-docs | WHERE filename == "greetings.md"

4. In Elastic Agent Builder, create an **agent** with the following values:
* **Agent ID**: `helloworld_agent`
* **Custom Instructions**:

If the prompt contains greeting text like "Hi" or "Hello" then respond with only the Basic Hello text from your documents.

If the prompt contains the text “Hello World” then respond with only the Hello World text from your documents.

In all other cases where the prompt does not contain greeting words, then respond with only the Not Greeting text from your documents.

* **Display Name**: `HelloWorld Agent`
* **Display Description**: `An agent that responds to greetings.`



## Clone the example app

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:

git clone https://github.com/elastic/elasticsearch-labs

3. `cd` to change directory to the example code located in the `supporting-blog-content/agent-builder-a2a-agent-framework` subdirectory.

cd elasticsearch-labs/supporting-blog-content/agent-builder-a2a-agent-framework

## Set up the environment variables

1. Set up the environment variables with values copied from your Elastic project.
1. Make a copy of the file `env.example` and name the new file `.env `
2. Edit the `.env` file to set the values of the environment variables to use the values copied from your Elastic project.
* Replace <YOUR-ELASTIC-AGENT-BUILDER-URL\>
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.**
2. Add the **MCP Server URL** value to the `.env` file.
* 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

`https://example-project-a123.kb.westus2.azure.elastic.cloud/api/agent_builder/a2a`

* Replace <YOUR-ELASTIC-API-KEY\>
1. In your Elastic project, click **Elasticsearch** in the navigation menu to go to your project’s home page.
2. Click **Create API key** to create a new API key.
3. After the API key is created, copy the API Key value.
4. Add the API Key value to the `.env` file.
* Find where the placeholder text “**<YOUR-ELASTIC-API-KEY\>**” appears and paste in the copied API Key value to replace the placeholder text.

3. Save the changes to the `.env` file.

## Running the example app with Python

1. Create a Python virtual environment by running the following code in the terminal.

python -m venv .venv

2. Activate the Python virtual environment.
* If you’re running MacOS, the command to activate the virtual environment is:

source .venv/bin/activate

* If you’re on Windows, the command to activate the virtual environment is:

.venv\Scripts\activate

3. Install the Microsoft Agent Framework along with its necessary Python packages by running the following `pip` command:

pip install -r requirements.txt

4. Run the example app by entering the following command into the terminal:

python elastic_agent_builder_a2a.py

## Running the example app with Docker

1. Run the example app with Docker by entering the following command into the terminal:

docker compose run elastic-agent-builder-a2a
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
services:
elastic-agent-builder-a2a:
build: .
container_name: elastic-agent-builder-a2a
stdin_open: true
tty: true
environment:
- ES_AGENT_URL=${ES_AGENT_URL}
- ES_API_KEY=${ES_API_KEY}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import asyncio
from dotenv import load_dotenv
import httpx
import os
from a2a.client import A2ACardResolver
from agent_framework.a2a import A2AAgent


async def main():
load_dotenv()
a2a_agent_host = os.getenv("ES_AGENT_URL")
a2a_agent_key = os.getenv("ES_API_KEY")

print(f"Connection to Elastic A2A agent at: {a2a_agent_host}")

custom_headers = {"Authorization": f"ApiKey {a2a_agent_key}"}

async with httpx.AsyncClient(timeout=60.0, headers=custom_headers) as http_client:
# Resolve the A2A Agent Card
resolver = A2ACardResolver(httpx_client=http_client, base_url=a2a_agent_host)
agent_card = await resolver.get_agent_card(
relative_card_path="/helloworld_agent.json"
)
print(f"Found Agent: {agent_card.name} - {agent_card.description}")

# Use the Agent
agent = A2AAgent(
name=agent_card.name,
description=agent_card.description,
agent_card=agent_card,
url=a2a_agent_host,
http_client=http_client,
)
prompt = input("Enter Greeting >>> ")
print("\nSending message to Elastic A2A agent...")
response = await agent.run(prompt)
print("\nAgent Response:")
for message in response.messages:
print(message.text)


if __name__ == "__main__":
asyncio.run(main())
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ES_AGENT_URL=<YOUR-ELASTIC-AGENT-BUILDER-URL>
ES_API_KEY=<YOUR-ELASTIC-API-KEY>
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
a2a-sdk~=0.3.14
ag-ui-protocol~=0.1.10
agent-framework~=1.0.0b251114
agent-framework-a2a~=1.0.0b251114
agent-framework-ag-ui~=1.0.0b251117
agent-framework-anthropic~=1.0.0b251114
agent-framework-azure-ai~=1.0.0b251114
agent-framework-azurefunctions~=1.0.0b251114
agent-framework-chatkit~=1.0.0b251114
agent-framework-copilotstudio~=1.0.0b251114
agent-framework-core~=1.0.0b251114
agent-framework-devui~=1.0.0b251114
agent-framework-lab~=1.0.0b251024
agent-framework-mem0~=1.0.0b251114
agent-framework-purview~=1.0.0b251114
agent-framework-redis~=1.0.0b251114
aiohappyeyeballs~=2.6.1
aiohttp~=3.13.2
aiosignal~=1.4.0
annotated-doc~=0.0.4
annotated-types~=0.7.0
anthropic~=0.74.0
anyio~=4.11.0
attrs~=25.4.0
azure-ai-agents~=1.2.0b5
azure-ai-projects~=2.0.0b2
azure-core~=1.36.0
azure-functions~=1.24.0
azure-functions-durable~=1.4.0
azure-identity~=1.25.1
azure-storage-blob~=12.27.1
backoff~=2.2.1
cachetools~=6.2.2
certifi~=2025.11.12
cffi~=2.0.0
charset-normalizer~=3.4.4
click~=8.3.1
colorama~=0.4.6
cryptography~=46.0.3
distro~=1.9.0
docstring_parser~=0.17.0
fastapi~=0.121.2
frozenlist~=1.8.0
furl~=2.1.4
google-api-core~=2.28.1
google-auth~=2.43.0
googleapis-common-protos~=1.72.0
griffe~=1.15.0
grpcio~=1.76.0
h11~=0.16.0
h2~=4.3.0
hpack~=4.1.0
httpcore~=1.0.9
httptools~=0.7.1
httpx~=0.28.1
httpx-sse~=0.4.3
hyperframe~=6.1.0
idna~=3.11
importlib_metadata~=8.7.0
isodate~=0.7.2
jiter~=0.12.0
jsonpath-ng~=1.7.0
jsonschema~=4.25.1
jsonschema-specifications~=2025.9.1
MarkupSafe~=3.0.3
mcp~=1.21.2
mem0ai~=1.0.1
microsoft-agents-activity~=0.6.0
microsoft-agents-copilotstudio-client~=0.6.0
microsoft-agents-hosting-core~=0.6.0
ml_dtypes~=0.5.4
msal~=1.34.0
msal-extensions~=1.3.1
multidict~=6.7.0
numpy~=2.3.5
openai~=2.8.1
openai-agents~=0.6.0
openai-chatkit~=1.3.0
opentelemetry-api~=1.38.0
opentelemetry-exporter-otlp-proto-common~=1.38.0
opentelemetry-exporter-otlp-proto-grpc~=1.38.0
opentelemetry-proto~=1.38.0
opentelemetry-sdk~=1.38.0
opentelemetry-semantic-conventions~=0.59b0
opentelemetry-semantic-conventions-ai~=0.4.13
orderedmultidict~=1.0.2
packaging~=25.0
ply~=3.11
portalocker~=3.2.0
posthog~=7.0.1
propcache~=0.4.1
proto-plus~=1.26.1
protobuf~=5.29.5
pyasn1~=0.6.1
pyasn1_modules~=0.4.2
pycparser~=2.23
pydantic~=2.12.4
pydantic-settings~=2.12.0
pydantic_core~=2.41.5
PyJWT~=2.10.1
python-dateutil~=2.9.0.post0
python-dotenv~=1.2.1
python-multipart~=0.0.20
python-ulid~=3.1.0
pytz~=2025.2
PyYAML~=6.0.3
qdrant-client~=1.16.0
redis~=6.4.0
redisvl~=0.11.0
referencing~=0.37.0
requests~=2.32.5
rpds-py~=0.29.0
rsa~=4.9.1
six~=1.17.0
sniffio~=1.3.1
SQLAlchemy~=2.0.44
sse-starlette~=3.0.3
starlette~=0.49.3
tenacity~=9.1.2
tqdm~=4.67.1
types-requests~=2.32.4.20250913
typing-inspection~=0.4.2
typing_extensions~=4.15.0
urllib3~=2.5.0
uvicorn~=0.38.0
uvloop~=0.22.1
watchfiles~=1.1.1
websockets~=15.0.1
Werkzeug~=3.1.3
yarl~=1.22.0
zipp~=3.23.0