Skip to content
Open
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
19 changes: 18 additions & 1 deletion python/samples/04-hosting/a2a/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# A2A Agent Examples

This sample demonstrates how to host and consume agents using the [A2A (Agent2Agent) protocol](https://a2a-protocol.org/latest/) with the `agent_framework` package. There are two runnable entry points:
This sample demonstrates how to host and consume agents using the [A2A (Agent2Agent) protocol](https://a2a-protocol.org/latest/) with the `agent_framework` package. There are three runnable entry points:

| Run this file | To... |
|---------------|-------|
| **[`a2a_server.py`](a2a_server.py)** | Host an Agent Framework agent as an A2A-compliant server. |
| **[`agent_with_a2a.py`](agent_with_a2a.py)** | Connect to an A2A server and send requests (non-streaming and streaming). |
| **[`a2a_agent_as_function_tools.py`](a2a_agent_as_function_tools.py)** | Convert A2A agent skills into function tools for a host agent. |

The remaining files are supporting modules used by the server:

Expand All @@ -27,6 +28,11 @@ Make sure to set the following environment variables before running the examples
### Required (Client)
- `A2A_AGENT_HOST` — URL of the A2A server (e.g. `http://localhost:5001/`)

### Required (Function Tools Sample)
- `A2A_AGENT_HOST` — URL of the A2A server (e.g. `http://localhost:5000/`)
- `AZURE_AI_PROJECT_ENDPOINT` — Your Azure AI Foundry project endpoint
- `AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME` — Model deployment name (e.g. `gpt-4o`)

## Quick Start

All commands below should be run from this directory:
Expand Down Expand Up @@ -55,3 +61,14 @@ In a separate terminal (from the same directory), point the client at a running
$env:A2A_AGENT_HOST = "http://localhost:5001/"
uv run python agent_with_a2a.py
```

### 3. Run the Function Tools Sample

This sample resolves the remote agent's skills and registers each one as a function tool
on a host OpenAI-powered agent. The host agent then autonomously selects the right skill
to handle the user's request.

```powershell
$env:A2A_AGENT_HOST = "http://localhost:5000/"
uv run python a2a_agent_as_function_tools.py
```
152 changes: 152 additions & 0 deletions python/samples/04-hosting/a2a/a2a_agent_as_function_tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Copyright (c) Microsoft. All rights reserved.

import asyncio
import os
import re

import httpx
from a2a.client import A2ACardResolver
from agent_framework.a2a import A2AAgent
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

"""
A2A Agent Skills as Function Tools

This sample demonstrates how to represent an A2A agent's skills as individual
function tools and register them with a host agent. Each skill advertised in the
remote agent's AgentCard becomes a separate tool that the host agent can invoke.

Key concepts demonstrated:
- Resolving an AgentCard from a remote A2A endpoint
- Converting each skill into a FunctionTool via as_tool()
- Registering those tools with a host agent
- Having the host agent autonomously select and invoke A2A skills

Prerequisites:
- Set A2A_AGENT_HOST to the URL of a running A2A server
- Set AZURE_AI_PROJECT_ENDPOINT to your Azure AI Foundry project endpoint
- Set AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME to the model deployment name (e.g. gpt-4o)

To run this sample:
cd python/samples/04-hosting/a2a
uv run python a2a_agent_as_function_tools.py
"""


async def main() -> None:
"""Discover A2A agent skills and register them as tools on a host agent."""
# 1. Read environment configuration.
a2a_agent_host = os.getenv("A2A_AGENT_HOST")
if not a2a_agent_host:
raise ValueError("A2A_AGENT_HOST environment variable is not set")

project_endpoint = os.getenv("AZURE_AI_PROJECT_ENDPOINT")
deployment_name = os.getenv("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME")
if not project_endpoint or not deployment_name:
raise ValueError(
"AZURE_AI_PROJECT_ENDPOINT and AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME must be set"
)

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

# 2. Resolve the remote agent card to discover its skills.
async with httpx.AsyncClient(timeout=60.0) as http_client:
resolver = A2ACardResolver(httpx_client=http_client, base_url=a2a_agent_host)
agent_card = await resolver.get_agent_card()

print(f"Found agent: {agent_card.name} ({len(agent_card.skills)} skill(s))")
for skill in agent_card.skills:
print(f" - {skill.name}: {skill.description}")

# 3. Create the A2AAgent that wraps the remote endpoint.
async with A2AAgent(
name=agent_card.name,
description=agent_card.description,
agent_card=agent_card,
url=a2a_agent_host,
) as a2a_agent:
# 4. Convert each A2A skill into a FunctionTool.
# Skill names may contain spaces or special characters, so we
# sanitize them into valid tool identifiers before passing to as_tool().
skill_tools = [
a2a_agent.as_tool(
name=re.sub(r"[^0-9A-Za-z]+", "_", skill.name),
description=skill.description or "",
)
for skill in agent_card.skills
]

# 5. Create the host agent with the skill tools.
credential = AzureCliCredential()
client = AzureOpenAIResponsesClient(
project_endpoint=project_endpoint,
deployment_name=deployment_name,
credential=credential,
)
host_agent = client.as_agent(
name="assistant",
instructions="You are a helpful assistant. Use your tools to answer questions.",
tools=skill_tools,
)

# 6. Run the host agent — it will select and invoke the appropriate A2A skill tools.
query = "Show me all invoices for Contoso"
print(f"\nUser: {query}\n")
response = await host_agent.run(query)
print(f"Agent: {response}")


if __name__ == "__main__":
asyncio.run(main())


"""
Sample output:

Connecting to A2A agent at: http://localhost:5000/
Found agent: InvoiceAgent (1 skill(s))
- InvoiceQuery: Handles requests relating to invoices.

User: Show me all invoices for Contoso

Agent: Here are the invoices for Contoso:

1. **Invoice ID:** INV789
- **Date:** 2026-02-15
- **Products:**
- T-Shirts: 150 units @ $10.00 = $1,500.00
- Hats: 200 units @ $15.00 = $3,000.00
- Glasses: 300 units @ $5.00 = $1,500.00
- **Total:** $6,000.00

2. **Invoice ID:** INV333
- **Date:** 2026-03-14
- **Products:**
- T-Shirts: 400 units @ $11.00 = $4,400.00
- Hats: 600 units @ $15.00 = $9,000.00
- Glasses: 700 units @ $5.00 = $3,500.00
- **Total:** $16,900.00

3. **Invoice ID:** INV666
- **Date:** 2026-02-06
- **Products:**
- T-Shirts: 2,500 units @ $8.00 = $20,000.00
- Hats: 1,200 units @ $10.00 = $12,000.00
- Glasses: 1,000 units @ $6.00 = $6,000.00
- **Total:** $38,000.00

4. **Invoice ID:** INV999
- **Date:** 2026-03-19
- **Products:**
- T-Shirts: 1,400 units @ $10.50 = $14,700.00
- Hats: 1,100 units @ $9.00 = $9,900.00
- Glasses: 950 units @ $12.00 = $11,400.00
- **Total:** $36,000.00

If you need more details or a specific invoice, please let me know!
"""
Loading