distributed-a2a 0.1.9rc8__py3-none-any.whl → 0.1.9rc9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- distributed_a2a/executors.py +25 -2
- distributed_a2a/registry.py +7 -14
- distributed_a2a/router.py +2 -15
- {distributed_a2a-0.1.9rc8.dist-info → distributed_a2a-0.1.9rc9.dist-info}/METADATA +1 -1
- distributed_a2a-0.1.9rc9.dist-info/RECORD +13 -0
- distributed_a2a-0.1.9rc8.dist-info/RECORD +0 -13
- {distributed_a2a-0.1.9rc8.dist-info → distributed_a2a-0.1.9rc9.dist-info}/WHEEL +0 -0
- {distributed_a2a-0.1.9rc8.dist-info → distributed_a2a-0.1.9rc9.dist-info}/licenses/LICENSE +0 -0
- {distributed_a2a-0.1.9rc8.dist-info → distributed_a2a-0.1.9rc9.dist-info}/top_level.txt +0 -0
distributed_a2a/executors.py
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
|
+
from logging import Logger
|
|
4
5
|
|
|
5
6
|
from a2a.server.agent_execution import AgentExecutor, RequestContext
|
|
6
7
|
from a2a.server.events import EventQueue
|
|
7
8
|
from a2a.types import TaskStatusUpdateEvent, TaskStatus, TaskState, TaskArtifactUpdateEvent, Artifact
|
|
8
9
|
from a2a.utils import new_text_artifact
|
|
9
10
|
from langchain_core.tools import BaseTool
|
|
11
|
+
from langchain_mcp_adapters.client import MultiServerMCPClient
|
|
10
12
|
|
|
11
13
|
from .agent import StatusAgent, RoutingResponse, StringResponse
|
|
12
14
|
from .model import AgentConfig, RouterConfig
|
|
15
|
+
from .registry import McpRegistryLookup
|
|
13
16
|
|
|
14
|
-
logger = logging.getLogger(__name__)
|
|
17
|
+
logger: Logger = logging.getLogger(__name__)
|
|
15
18
|
|
|
16
19
|
ROUTING_SYSTEM_PROMPT = """
|
|
17
20
|
You are a helpful routing assistant which routes user requests to specialized remote agents. Your main task is to:
|
|
@@ -27,7 +30,10 @@ class RoutingAgentExecutor(AgentExecutor):
|
|
|
27
30
|
api_key = os.environ.get(agent_config.agent.llm.api_key_env)
|
|
28
31
|
if api_key is None:
|
|
29
32
|
raise ValueError("No API key found for LLM.")
|
|
30
|
-
|
|
33
|
+
self.mcp_registry = McpRegistryLookup(registry_url=agent_config.registry.mcp.url)
|
|
34
|
+
self.agent_config = agent_config
|
|
35
|
+
self.registered_tools = {}
|
|
36
|
+
self.api_key = api_key
|
|
31
37
|
self.agent = StatusAgent[StringResponse](
|
|
32
38
|
llm_config=agent_config.agent.llm,
|
|
33
39
|
system_prompt=agent_config.agent.system_prompt,
|
|
@@ -57,6 +63,7 @@ class RoutingAgentExecutor(AgentExecutor):
|
|
|
57
63
|
final=False,
|
|
58
64
|
context_id=context.context_id,
|
|
59
65
|
task_id=context.task_id))
|
|
66
|
+
self.reinitialize_agent_with_tools()
|
|
60
67
|
agent_response: StringResponse = await self.agent(message=context.get_user_input(),
|
|
61
68
|
context_id=context.context_id)
|
|
62
69
|
|
|
@@ -97,6 +104,22 @@ class RoutingAgentExecutor(AgentExecutor):
|
|
|
97
104
|
context_id=context.context_id,
|
|
98
105
|
task_id=context.task_id))
|
|
99
106
|
|
|
107
|
+
def reinitialize_agent_with_tools(self):
|
|
108
|
+
mcp_tools = self.mcp_registry.get_mcp_tool_for_agent(self.agent_config.agent.card.name)
|
|
109
|
+
logger.info(f"Agent {self.agent_config.agent.card.name} has access to the following tools: {mcp_tools}")
|
|
110
|
+
tools = {tool["name"]: {"url": tool["url"], "transport": tool["protocol"]} for tool in mcp_tools}
|
|
111
|
+
mcp_client = MultiServerMCPClient(tools)
|
|
112
|
+
mcp_tools = mcp_client.get_tools()
|
|
113
|
+
|
|
114
|
+
self.agent = StatusAgent[StringResponse](
|
|
115
|
+
llm_config=self.agent_config.agent.llm,
|
|
116
|
+
system_prompt=self.agent_config.agent.system_prompt,
|
|
117
|
+
name=self.agent_config.agent.card.name,
|
|
118
|
+
api_key=self.api_key,
|
|
119
|
+
is_routing=False,
|
|
120
|
+
tools=mcp_tools,
|
|
121
|
+
)
|
|
122
|
+
|
|
100
123
|
|
|
101
124
|
class RoutingExecutor(AgentExecutor):
|
|
102
125
|
def __init__(self, router_config: RouterConfig, routing_tool: BaseTool) -> None:
|
distributed_a2a/registry.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import asyncio
|
|
3
|
-
import boto3
|
|
4
2
|
import requests
|
|
5
3
|
from langchain_core.tools import StructuredTool
|
|
6
4
|
from a2a.types import AgentCard
|
|
@@ -45,17 +43,12 @@ class AgentRegistryLookup:
|
|
|
45
43
|
return StructuredTool.from_function(func=lambda: self.get_agent_cards(), name="agent_card_lookup",
|
|
46
44
|
description="Gets all available agent cards")
|
|
47
45
|
|
|
48
|
-
class DynamoDbRegistryLookup:
|
|
49
|
-
def __init__(self, agent_card_tabel: str):
|
|
50
|
-
dynamo = boto3.resource("dynamodb", region_name="eu-central-1")
|
|
51
|
-
self.table = dynamo.Table(agent_card_tabel)
|
|
52
46
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
cards: list[dict] = [json.loads(it["card"]) for it in items]
|
|
57
|
-
return cards
|
|
47
|
+
class McpRegistryLookup:
|
|
48
|
+
def __init__(self, registry_url: str):
|
|
49
|
+
self.registry_url = registry_url
|
|
58
50
|
|
|
59
|
-
def
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
def get_mcp_tool_for_agent(self, agent_name: str) -> list[dict]:
|
|
52
|
+
response = requests.get(url=f"{self.registry_url}/mcp/agent/{agent_name}/tools")
|
|
53
|
+
response.raise_for_status()
|
|
54
|
+
return response.json()
|
distributed_a2a/router.py
CHANGED
|
@@ -9,8 +9,8 @@ from fastapi import FastAPI
|
|
|
9
9
|
|
|
10
10
|
from .executors import RoutingExecutor
|
|
11
11
|
from .model import RouterConfig
|
|
12
|
-
from .registry import AgentRegistryLookup
|
|
13
|
-
from .server import CAPABILITIES
|
|
12
|
+
from .registry import AgentRegistryLookup
|
|
13
|
+
from .server import CAPABILITIES
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def load_router(router_dic: dict[str, Any]) -> FastAPI:
|
|
@@ -37,18 +37,6 @@ def load_router(router_dic: dict[str, Any]) -> FastAPI:
|
|
|
37
37
|
routing_tool=AgentRegistryLookup(router_config.router.registry.agent.url).as_tool()
|
|
38
38
|
)
|
|
39
39
|
|
|
40
|
-
@asynccontextmanager
|
|
41
|
-
async def lifespan(_: FastAPI) -> AsyncGenerator[None, Any]:
|
|
42
|
-
import asyncio
|
|
43
|
-
asyncio.create_task(registry_heart_beat(
|
|
44
|
-
name=router_config.router.card.name,
|
|
45
|
-
registry_url=router_config.router.registry.agent.url,
|
|
46
|
-
agent_card=agent_card,
|
|
47
|
-
interval_sec=HEART_BEAT_INTERVAL_SEC,
|
|
48
|
-
get_expire_at=get_expire_at
|
|
49
|
-
))
|
|
50
|
-
yield
|
|
51
|
-
|
|
52
40
|
return A2ARESTFastAPIApplication(
|
|
53
41
|
agent_card=agent_card,
|
|
54
42
|
http_handler=DefaultRequestHandler(
|
|
@@ -56,5 +44,4 @@ def load_router(router_dic: dict[str, Any]) -> FastAPI:
|
|
|
56
44
|
task_store=InMemoryTaskStore() # TODO replace with dynamodb store
|
|
57
45
|
|
|
58
46
|
)).build(title=agent_card.name,
|
|
59
|
-
lifespan=lifespan,
|
|
60
47
|
root_path=f"/{router_config.router.card.name}")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
distributed_a2a/__init__.py,sha256=gO8sTT20O6XvDRzj7B322O9v6HxV-_eIlJD1wMlPYoI,171
|
|
2
|
+
distributed_a2a/agent.py,sha256=qY775N3Br2YMuaHLALU4t6MO47syuEoTtFLLPRr8TyA,2910
|
|
3
|
+
distributed_a2a/client.py,sha256=3tEBqu3HKEQyOFk5vsO1YiuKP2pZx-n6SCzsJUYNcyc,4601
|
|
4
|
+
distributed_a2a/executors.py,sha256=Y_9E4gAFBfcBlbXmxKoW_3TSFuTqV4AmqrsajNo6F7Q,9381
|
|
5
|
+
distributed_a2a/model.py,sha256=rW9jY0OIR8L_I77zz47JQMd-ucQQnnfNw_HIS-YvrcM,3533
|
|
6
|
+
distributed_a2a/registry.py,sha256=lTXdS3PHXXMPXNjZDxyNRJjhJ1uZJOxgOgpokQp7boc,2050
|
|
7
|
+
distributed_a2a/router.py,sha256=l1kDn5_iYNq6QZj8JsouLC6zz5vdK-qGSpj4KODwXY8,1834
|
|
8
|
+
distributed_a2a/server.py,sha256=-__c-BKzJWSXpW21NOp6faUIdjWV_o32jqv42_lPi2g,3352
|
|
9
|
+
distributed_a2a-0.1.9rc9.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
|
|
10
|
+
distributed_a2a-0.1.9rc9.dist-info/METADATA,sha256=meehLdwrAH4uh0yarVbNTaooEcWkIdpeSFAdTBwmpRM,3198
|
|
11
|
+
distributed_a2a-0.1.9rc9.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
12
|
+
distributed_a2a-0.1.9rc9.dist-info/top_level.txt,sha256=23qJ8n5k7796BHDK7a58uuO-X4GV0EgUWcGi8NIn-0k,16
|
|
13
|
+
distributed_a2a-0.1.9rc9.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
distributed_a2a/__init__.py,sha256=gO8sTT20O6XvDRzj7B322O9v6HxV-_eIlJD1wMlPYoI,171
|
|
2
|
-
distributed_a2a/agent.py,sha256=qY775N3Br2YMuaHLALU4t6MO47syuEoTtFLLPRr8TyA,2910
|
|
3
|
-
distributed_a2a/client.py,sha256=3tEBqu3HKEQyOFk5vsO1YiuKP2pZx-n6SCzsJUYNcyc,4601
|
|
4
|
-
distributed_a2a/executors.py,sha256=gu3MdnUldOt-9yUJA2xkmJNoDyhwH7qyznRY4lwlTys,8226
|
|
5
|
-
distributed_a2a/model.py,sha256=rW9jY0OIR8L_I77zz47JQMd-ucQQnnfNw_HIS-YvrcM,3533
|
|
6
|
-
distributed_a2a/registry.py,sha256=4OK_Zbsq38UNKliyagifKfDG6nUIhflxq0VAoqeLKgM,2368
|
|
7
|
-
distributed_a2a/router.py,sha256=D0f3xUkf5NNFBe5-6MWmSFXh3Uz_6KGu5r4K5K5Bdes,2359
|
|
8
|
-
distributed_a2a/server.py,sha256=-__c-BKzJWSXpW21NOp6faUIdjWV_o32jqv42_lPi2g,3352
|
|
9
|
-
distributed_a2a-0.1.9rc8.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
|
|
10
|
-
distributed_a2a-0.1.9rc8.dist-info/METADATA,sha256=q3GpFDoB5Lu3BRp5nveRGXLjJYLNyKZySoRGbah3krw,3198
|
|
11
|
-
distributed_a2a-0.1.9rc8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
12
|
-
distributed_a2a-0.1.9rc8.dist-info/top_level.txt,sha256=23qJ8n5k7796BHDK7a58uuO-X4GV0EgUWcGi8NIn-0k,16
|
|
13
|
-
distributed_a2a-0.1.9rc8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|