mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
4ad96b64e7
* Python: Migrate agent-framework-a2a to a2a-sdk v1.0
Upgrade the a2a-sdk dependency from v0.3.x to v1.0.0 and migrate all
source, tests, samples, and documentation to the v1.0 API.
Key changes:
- Dependency: a2a-sdk>=1.0.0,<2 (was >=0.3.5,<0.3.24)
- Types are now protobuf-based: Part replaces TextPart/FilePart/DataPart
- Enums use SCREAMING_SNAKE_CASE (e.g. TaskState.TASK_STATE_COMPLETED)
- Roles: Role.ROLE_AGENT, Role.ROLE_USER
- Client: SendMessageRequest wrapper, subscribe() replaces resubscribe()
- Server: A2AStarletteApplication replaced by Starlette + route factories
- DefaultRequestHandler now requires agent_card parameter
- TaskUpdater: final parameter removed, add_artifact gains last_chunk
- AgentCard.url removed; use supported_interfaces with AgentInterface
- Stream yields StreamResponse with WhichOneof('payload')
Closes #5661
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review: validate fallback URL, remove unused task_id vars
- Raise ValueError with clear message when transport negotiation fails
and no fallback URL is available (neither url arg nor supported_interfaces)
- Remove unused task_id local in status_update branch
- Inline artifact_event.task_id directly in artifact_update branch
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
125 lines
3.7 KiB
Python
125 lines
3.7 KiB
Python
# Copyright (c) Microsoft. All rights reserved.
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
|
|
import uvicorn
|
|
from a2a.server.request_handlers import DefaultRequestHandler
|
|
from a2a.server.routes import create_agent_card_routes, create_jsonrpc_routes
|
|
from a2a.server.tasks import InMemoryTaskStore
|
|
from agent_definitions import AGENT_CARD_FACTORIES, AGENT_FACTORIES
|
|
from agent_executor import AgentFrameworkExecutor
|
|
from agent_framework.foundry import FoundryChatClient
|
|
from azure.identity import AzureCliCredential
|
|
from dotenv import load_dotenv
|
|
from starlette.applications import Starlette
|
|
|
|
# Load environment variables from .env file
|
|
load_dotenv()
|
|
|
|
"""
|
|
A2A Server Sample — Host an Agent Framework agent as an A2A endpoint
|
|
|
|
This sample creates a Python-based A2A-compliant server that wraps an Agent
|
|
Framework agent. The server uses the a2a-sdk's Starlette application to handle
|
|
JSON-RPC requests and serves the AgentCard at /.well-known/agent.json.
|
|
|
|
Three agent types are available:
|
|
- invoice — Answers invoice queries using mock data and function tools.
|
|
- policy — Returns a fixed policy response.
|
|
- logistics — Returns a fixed logistics response.
|
|
|
|
Usage:
|
|
uv run python a2a_server.py --agent-type policy --port 5001
|
|
uv run python a2a_server.py --agent-type invoice --port 5000
|
|
uv run python a2a_server.py --agent-type logistics --port 5002
|
|
|
|
Environment variables:
|
|
FOUNDRY_PROJECT_ENDPOINT — Your Azure AI Foundry project endpoint
|
|
FOUNDRY_MODEL — Model deployment name (e.g. gpt-4o)
|
|
"""
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="A2A Agent Server")
|
|
parser.add_argument(
|
|
"--agent-type",
|
|
choices=["invoice", "policy", "logistics"],
|
|
default="policy",
|
|
help="Type of agent to host (default: policy)",
|
|
)
|
|
parser.add_argument(
|
|
"--host",
|
|
default="localhost",
|
|
help="Host to bind to (default: localhost)",
|
|
)
|
|
parser.add_argument(
|
|
"--port",
|
|
type=int,
|
|
default=5001,
|
|
help="Port to listen on (default: 5001)",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_args()
|
|
|
|
# Validate environment
|
|
project_endpoint = os.getenv("FOUNDRY_PROJECT_ENDPOINT")
|
|
model = os.getenv("FOUNDRY_MODEL")
|
|
|
|
if not project_endpoint:
|
|
print("Error: FOUNDRY_PROJECT_ENDPOINT environment variable is not set.")
|
|
sys.exit(1)
|
|
if not model:
|
|
print("Error: FOUNDRY_MODEL environment variable is not set.")
|
|
sys.exit(1)
|
|
|
|
# Create the LLM client
|
|
credential = AzureCliCredential()
|
|
client = FoundryChatClient(
|
|
project_endpoint=project_endpoint,
|
|
model=model,
|
|
credential=credential,
|
|
)
|
|
|
|
# Create the Agent Framework agent for the chosen type
|
|
agent_factory = AGENT_FACTORIES[args.agent_type]
|
|
agent = agent_factory(client)
|
|
|
|
# Build the A2A server components
|
|
url = f"http://{args.host}:{args.port}/"
|
|
agent_card = AGENT_CARD_FACTORIES[args.agent_type](url)
|
|
executor = AgentFrameworkExecutor(agent)
|
|
task_store = InMemoryTaskStore()
|
|
request_handler = DefaultRequestHandler(
|
|
agent_executor=executor,
|
|
task_store=task_store,
|
|
agent_card=agent_card,
|
|
)
|
|
|
|
app = Starlette(
|
|
routes=[
|
|
*create_agent_card_routes(agent_card),
|
|
*create_jsonrpc_routes(request_handler),
|
|
]
|
|
)
|
|
|
|
print(f"Starting A2A server: {agent_card.name}")
|
|
print(f" Agent type : {args.agent_type}")
|
|
print(f" Listening : {url}")
|
|
print(f" Agent card : {url}.well-known/agent.json")
|
|
print()
|
|
|
|
uvicorn.run(
|
|
app,
|
|
host=args.host,
|
|
port=args.port,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|