1313from  a2a .client  import  ClientFactory  as  A2AClientFactory 
1414from  a2a .types  import  AgentCard , Message , Task , TaskIdParams , TaskQueryParams , TaskState 
1515from  a2a .utils .constants  import  AGENT_CARD_WELL_KNOWN_PATH , EXTENDED_AGENT_CARD_PATH , PREV_AGENT_CARD_WELL_KNOWN_PATH 
16+ from  typing_extensions  import  Self 
1617
1718from  autogen  import  ConversableAgent 
1819from  autogen .agentchat .group  import  ContextVariables 
@@ -55,9 +56,14 @@ def __init__(
5556        max_reconnects : int  =  3 ,
5657        polling_interval : float  =  0.5 ,
5758    ) ->  None :
58-         self .url  =  url 
59+         self .url  =  url    # make it public for backward compatibility 
5960
6061        self ._httpx_client_factory  =  client  or  EmptyClientFactory ()
62+         self ._card_resolver  =  A2ACardResolver (
63+             httpx_client = self ._httpx_client_factory (),
64+             base_url = url ,
65+         )
66+ 
6167        self ._max_reconnects  =  max_reconnects 
6268        self ._polling_interval  =  polling_interval 
6369
@@ -66,7 +72,7 @@ def __init__(
6672        self .__llm_config : dict [str , Any ] =  {}
6773
6874        self ._client_config  =  client_config  or  ClientConfig ()
69-         self .__agent_card : AgentCard  |  None  =  None 
75+         self ._agent_card : AgentCard  |  None  =  None 
7076
7177        self .replace_reply_func (
7278            ConversableAgent .generate_oai_reply ,
@@ -77,6 +83,48 @@ def __init__(
7783            A2aRemoteAgent .a_generate_remote_reply ,
7884        )
7985
86+     @classmethod  
87+     def  from_card (
88+         cls ,
89+         card : AgentCard ,
90+         * ,
91+         silent : bool  |  None  =  None ,
92+         client : ClientFactory  |  None  =  None ,
93+         client_config : ClientConfig  |  None  =  None ,
94+         max_reconnects : int  =  3 ,
95+         polling_interval : float  =  0.5 ,
96+     ) ->  Self :
97+         """Creates an A2aRemoteAgent instance from an existing AgentCard. 
98+ 
99+         This method allows you to instantiate an A2aRemoteAgent directly using a pre-existing 
100+         AgentCard, such as one retrieved from a discovery service or constructed manually. 
101+         The resulting agent will use the data from the given card and avoid redundant card 
102+         fetching. The agent's registryURL is set to "UNKNOWN" since it is assumed to be derived 
103+         from the card. 
104+ 
105+         Args: 
106+             card: The agent card containing metadata and configuration for the remote agent. 
107+             silent: whether to print the message sent. If None, will use the value of silent in each function. 
108+             client: An optional HTTPX client instance factory. 
109+             client_config: A2A Client configuration options. 
110+             max_reconnects: Maximum number of reconnection attempts before giving up. 
111+             polling_interval: Time in seconds between polling operations. Works for A2A Servers doesn't support streaming. 
112+ 
113+         Returns: 
114+             Self: An instance of the A2aRemoteAgent configured with the provided card. 
115+         """ 
116+         instance  =  cls (
117+             url = "UNKNOWN" ,
118+             name = card .name ,
119+             silent = silent ,
120+             client = client ,
121+             client_config = client_config ,
122+             max_reconnects = max_reconnects ,
123+             polling_interval = polling_interval ,
124+         )
125+         instance ._agent_card  =  card 
126+         return  instance 
127+ 
80128    def  generate_remote_reply (
81129        self ,
82130        messages : list [dict [str , Any ]] |  None  =  None ,
@@ -94,8 +142,8 @@ async def a_generate_remote_reply(
94142        if  messages  is  None :
95143            messages  =  self ._oai_messages [sender ]
96144
97-         if  not  self .__agent_card :
98-             self .__agent_card  =  await  self ._get_agent_card ()
145+         if  not  self ._agent_card :
146+             self ._agent_card  =  await  self ._get_agent_card ()
99147
100148        initial_message  =  request_message_to_a2a (
101149            request_message = RequestMessage (
@@ -108,9 +156,9 @@ async def a_generate_remote_reply(
108156
109157        self ._client_config .httpx_client  =  self ._httpx_client_factory ()
110158        async  with  self ._client_config .httpx_client :
111-             agent_client  =  A2AClientFactory (self ._client_config ).create (self .__agent_card )
159+             agent_client  =  A2AClientFactory (self ._client_config ).create (self ._agent_card )
112160
113-             if  self .__agent_card .capabilities .streaming :
161+             if  self ._agent_card .capabilities .streaming :
114162                reply  =  await  self ._ask_streaming (agent_client , initial_message )
115163                return  self ._apply_reply (reply , sender )
116164
@@ -142,9 +190,9 @@ async def _ask_streaming(self, client: Client, message: Message) -> ResponseMess
142190            if  task  and  connection_attemps  <  self ._max_reconnects :
143191                pass 
144192
145-             if  not  self .__agent_card :
193+             if  not  self ._agent_card :
146194                raise  A2aClientError ("Failed to connect to the agent: agent card not found" ) from  e 
147-             raise  A2aClientError (f"Failed to connect to the agent: { pformat (self .__agent_card .model_dump ())}  ) from  e 
195+             raise  A2aClientError (f"Failed to connect to the agent: { pformat (self ._agent_card .model_dump ())}  ) from  e 
148196
149197        task  =  cast (Task , task )
150198        while  connection_attemps  <  self ._max_reconnects :
@@ -159,11 +207,9 @@ async def _ask_streaming(self, client: Client, message: Message) -> ResponseMess
159207                if  connection_attemps  <  self ._max_reconnects :
160208                    pass 
161209
162-                 if  not  self .__agent_card :
210+                 if  not  self ._agent_card :
163211                    raise  A2aClientError ("Failed to connect to the agent: agent card not found" ) from  e 
164-                 raise  A2aClientError (
165-                     f"Failed to connect to the agent: { pformat (self .__agent_card .model_dump ())}  
166-                 ) from  e 
212+                 raise  A2aClientError (f"Failed to connect to the agent: { pformat (self ._agent_card .model_dump ())}  ) from  e 
167213
168214        return  None 
169215
@@ -175,9 +221,9 @@ async def _ask_polling(self, client: Client, message: Message) -> ResponseMessag
175221                    return  result 
176222                break 
177223        except  httpx .ConnectError  as  e :
178-             if  not  self .__agent_card :
224+             if  not  self ._agent_card :
179225                raise  A2aClientError ("Failed to connect to the agent: agent card not found" ) from  e 
180-             raise  A2aClientError (f"Failed to connect to the agent: { pformat (self .__agent_card .model_dump ())}  ) from  e 
226+             raise  A2aClientError (f"Failed to connect to the agent: { pformat (self ._agent_card .model_dump ())}  ) from  e 
181227
182228        started_task , connection_attemps  =  cast (Task , started_task ), 0 
183229        while  connection_attemps  <  self ._max_reconnects :
@@ -190,10 +236,10 @@ async def _ask_polling(self, client: Client, message: Message) -> ResponseMessag
190236                    if  connection_attemps  <  self ._max_reconnects :
191237                        pass 
192238
193-                     if  not  self .__agent_card :
239+                     if  not  self ._agent_card :
194240                        raise  A2aClientError ("Failed to connect to the agent: agent card not found" ) from  e 
195241                    raise  A2aClientError (
196-                         f"Failed to connect to the agent: { pformat (self .__agent_card .model_dump ())}  
242+                         f"Failed to connect to the agent: { pformat (self ._agent_card .model_dump ())}  
197243                    ) from  e 
198244
199245                else :
@@ -231,27 +277,27 @@ async def _get_agent_card(
231277        self ,
232278        auth_http_kwargs : dict [str , Any ] |  None  =  None ,
233279    ) ->  AgentCard :
234-         resolver  =  A2ACardResolver (httpx_client = self ._httpx_client_factory (), base_url = self .url )
235- 
236280        card : AgentCard  |  None  =  None 
237281
238282        try :
239-             logger .info (f"Attempting to fetch public agent card from: { self .url } { AGENT_CARD_WELL_KNOWN_PATH }  )
283+             logger .info (
284+                 f"Attempting to fetch public agent card from: { self ._card_resolver .base_url } { AGENT_CARD_WELL_KNOWN_PATH }  
285+             )
240286
241287            try :
242-                 card  =  await  resolver .get_agent_card (relative_card_path = AGENT_CARD_WELL_KNOWN_PATH )
288+                 card  =  await  self . _card_resolver .get_agent_card (relative_card_path = AGENT_CARD_WELL_KNOWN_PATH )
243289            except  A2AClientHTTPError  as  e_public :
244290                if  e_public .status_code  ==  404 :
245291                    logger .info (
246-                         f"Attempting to fetch public agent card from: { self .url } { PREV_AGENT_CARD_WELL_KNOWN_PATH }  
292+                         f"Attempting to fetch public agent card from: { self ._card_resolver . base_url } { PREV_AGENT_CARD_WELL_KNOWN_PATH }  
247293                    )
248-                     card  =  await  resolver .get_agent_card (relative_card_path = PREV_AGENT_CARD_WELL_KNOWN_PATH )
294+                     card  =  await  self . _card_resolver .get_agent_card (relative_card_path = PREV_AGENT_CARD_WELL_KNOWN_PATH )
249295                else :
250296                    raise  e_public 
251297
252298            if  card .supports_authenticated_extended_card :
253299                try :
254-                     card  =  await  resolver .get_agent_card (
300+                     card  =  await  self . _card_resolver .get_agent_card (
255301                        relative_card_path = EXTENDED_AGENT_CARD_PATH ,
256302                        http_kwargs = auth_http_kwargs ,
257303                    )
0 commit comments