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.
@@ -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:
@@ -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
- def get_agent_cards(self) -> list[dict]:
54
-
55
- items = self.table.scan().get("Items", [])
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 as_tool(self) -> StructuredTool:
60
- return StructuredTool.from_function(func=lambda: self.get_agent_cards(), name="agent_card_lookup",
61
- description="Gets all available agent cards")
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, registry_heart_beat
13
- from .server import CAPABILITIES, HEART_BEAT_INTERVAL_SEC, get_expire_at
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}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: distributed_a2a
3
- Version: 0.1.9rc8
3
+ Version: 0.1.9rc9
4
4
  Summary: A library for building A2A agents with routing capabilities
5
5
  Home-page: https://github.com/Barra-Technologies/distributed-a2a
6
6
  Author: Fabian Bell
@@ -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,,