mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: [BREAKING] Migrate agent-framework-a2a to a2a-sdk v1.0 (#5752)
* 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>
This commit is contained in:
committed by
GitHub
Unverified
parent
e3875f2c91
commit
4ad96b64e7
@@ -5,14 +5,15 @@ import os
|
||||
import sys
|
||||
|
||||
import uvicorn
|
||||
from a2a.server.apps.jsonrpc.starlette_app import A2AStarletteApplication
|
||||
from a2a.server.request_handlers.default_request_handler import DefaultRequestHandler
|
||||
from a2a.server.tasks.inmemory_task_store import InMemoryTaskStore
|
||||
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()
|
||||
@@ -96,11 +97,14 @@ def main() -> None:
|
||||
request_handler = DefaultRequestHandler(
|
||||
agent_executor=executor,
|
||||
task_store=task_store,
|
||||
agent_card=agent_card,
|
||||
)
|
||||
|
||||
a2a_app = A2AStarletteApplication(
|
||||
agent_card=agent_card,
|
||||
http_handler=request_handler,
|
||||
app = Starlette(
|
||||
routes=[
|
||||
*create_agent_card_routes(agent_card),
|
||||
*create_jsonrpc_routes(request_handler),
|
||||
]
|
||||
)
|
||||
|
||||
print(f"Starting A2A server: {agent_card.name}")
|
||||
@@ -110,7 +114,7 @@ def main() -> None:
|
||||
print()
|
||||
|
||||
uvicorn.run(
|
||||
a2a_app.build(),
|
||||
app,
|
||||
host=args.host,
|
||||
port=args.port,
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
|
||||
from a2a.types import AgentCapabilities, AgentCard, AgentInterface, AgentSkill
|
||||
from invoice_data import query_by_invoice_id, query_by_transaction_id, query_invoices
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -94,11 +94,11 @@ def get_invoice_agent_card(url: str) -> AgentCard:
|
||||
return AgentCard(
|
||||
name="InvoiceAgent",
|
||||
description="Handles requests relating to invoices.",
|
||||
url=url,
|
||||
version="1.0.0",
|
||||
default_input_modes=["text"],
|
||||
default_output_modes=["text"],
|
||||
capabilities=_CAPABILITIES,
|
||||
supported_interfaces=[AgentInterface(url=url, protocol_binding="JSONRPC")],
|
||||
skills=[
|
||||
AgentSkill(
|
||||
id="id_invoice_agent",
|
||||
@@ -116,11 +116,11 @@ def get_policy_agent_card(url: str) -> AgentCard:
|
||||
return AgentCard(
|
||||
name="PolicyAgent",
|
||||
description="Handles requests relating to policies and customer communications.",
|
||||
url=url,
|
||||
version="1.0.0",
|
||||
default_input_modes=["text"],
|
||||
default_output_modes=["text"],
|
||||
capabilities=_CAPABILITIES,
|
||||
supported_interfaces=[AgentInterface(url=url, protocol_binding="JSONRPC")],
|
||||
skills=[
|
||||
AgentSkill(
|
||||
id="id_policy_agent",
|
||||
@@ -138,11 +138,11 @@ def get_logistics_agent_card(url: str) -> AgentCard:
|
||||
return AgentCard(
|
||||
name="LogisticsAgent",
|
||||
description="Handles requests relating to logistics.",
|
||||
url=url,
|
||||
version="1.0.0",
|
||||
default_input_modes=["text"],
|
||||
default_output_modes=["text"],
|
||||
capabilities=_CAPABILITIES,
|
||||
supported_interfaces=[AgentInterface(url=url, protocol_binding="JSONRPC")],
|
||||
skills=[
|
||||
AgentSkill(
|
||||
id="id_logistics_agent",
|
||||
|
||||
@@ -21,7 +21,6 @@ from a2a.types import (
|
||||
TaskState,
|
||||
TaskStatus,
|
||||
TaskStatusUpdateEvent,
|
||||
TextPart,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -56,8 +55,7 @@ class AgentFrameworkExecutor(AgentExecutor):
|
||||
TaskStatusUpdateEvent(
|
||||
task_id=task_id,
|
||||
context_id=context_id,
|
||||
status=TaskStatus(state=TaskState.working),
|
||||
final=False,
|
||||
status=TaskStatus(state=TaskState.TASK_STATE_WORKING),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -68,10 +66,10 @@ class AgentFrameworkExecutor(AgentExecutor):
|
||||
response_parts: list[Part] = []
|
||||
for msg in response.messages:
|
||||
if msg.text:
|
||||
response_parts.append(TextPart(text=msg.text))
|
||||
response_parts.append(Part(text=msg.text))
|
||||
|
||||
if not response_parts:
|
||||
response_parts.append(TextPart(text=str(response)))
|
||||
response_parts.append(Part(text=str(response)))
|
||||
|
||||
# Publish the agent's response as a completed message
|
||||
await event_queue.enqueue_event(
|
||||
@@ -79,14 +77,13 @@ class AgentFrameworkExecutor(AgentExecutor):
|
||||
task_id=task_id,
|
||||
context_id=context_id,
|
||||
status=TaskStatus(
|
||||
state=TaskState.completed,
|
||||
state=TaskState.TASK_STATE_COMPLETED,
|
||||
message=Message(
|
||||
message_id=str(uuid.uuid4()),
|
||||
role=Role.agent,
|
||||
role=Role.ROLE_AGENT,
|
||||
parts=response_parts,
|
||||
),
|
||||
),
|
||||
final=True,
|
||||
)
|
||||
)
|
||||
except asyncio.CancelledError:
|
||||
@@ -97,14 +94,13 @@ class AgentFrameworkExecutor(AgentExecutor):
|
||||
task_id=task_id,
|
||||
context_id=context_id,
|
||||
status=TaskStatus(
|
||||
state=TaskState.failed,
|
||||
state=TaskState.TASK_STATE_FAILED,
|
||||
message=Message(
|
||||
message_id=str(uuid.uuid4()),
|
||||
role=Role.agent,
|
||||
parts=[TextPart(text=f"Agent error: {e}")],
|
||||
role=Role.ROLE_AGENT,
|
||||
parts=[Part(text=f"Agent error: {e}")],
|
||||
),
|
||||
),
|
||||
final=True,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -117,7 +113,6 @@ class AgentFrameworkExecutor(AgentExecutor):
|
||||
TaskStatusUpdateEvent(
|
||||
task_id=task_id,
|
||||
context_id=context_id,
|
||||
status=TaskStatus(state=TaskState.canceled),
|
||||
final=True,
|
||||
status=TaskStatus(state=TaskState.TASK_STATE_CANCELED),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import uvicorn
|
||||
from a2a.server.apps import A2AStarletteApplication
|
||||
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 a2a.types import (
|
||||
AgentCapabilities,
|
||||
AgentCard,
|
||||
AgentInterface,
|
||||
AgentSkill,
|
||||
)
|
||||
from agent_framework import Agent
|
||||
from agent_framework.a2a import A2AExecutor
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from dotenv import load_dotenv
|
||||
from starlette.applications import Starlette
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@@ -39,11 +41,11 @@ if __name__ == "__main__":
|
||||
public_agent_card = AgentCard(
|
||||
name="Europe Travel Agent",
|
||||
description="A helpful Europe Travel Agent that can help users search and book flights and hotels across Europe.",
|
||||
url="http://localhost:9999/",
|
||||
version="1.0.0",
|
||||
defaultInputModes=["text"],
|
||||
defaultOutputModes=["text"],
|
||||
default_input_modes=["text"],
|
||||
default_output_modes=["text"],
|
||||
capabilities=AgentCapabilities(streaming=True),
|
||||
supported_interfaces=[AgentInterface(url="http://localhost:9999/", protocol_binding="JSONRPC")],
|
||||
skills=[flight_skill, hotel_skill],
|
||||
)
|
||||
# --8<-- [end:AgentCard]
|
||||
@@ -57,14 +59,14 @@ if __name__ == "__main__":
|
||||
request_handler = DefaultRequestHandler(
|
||||
agent_executor=A2AExecutor(agent),
|
||||
task_store=InMemoryTaskStore(),
|
||||
)
|
||||
|
||||
server = A2AStarletteApplication(
|
||||
agent_card=public_agent_card,
|
||||
http_handler=request_handler,
|
||||
)
|
||||
|
||||
server = server.build()
|
||||
# print(schemas.get_schema(server.routes))
|
||||
server = Starlette(
|
||||
routes=[
|
||||
*create_agent_card_routes(public_agent_card),
|
||||
*create_jsonrpc_routes(request_handler),
|
||||
]
|
||||
)
|
||||
|
||||
uvicorn.run(server, host="0.0.0.0", port=9999)
|
||||
|
||||
Reference in New Issue
Block a user