Ë
    âß²j]K  ã                  ód  — U d Z ddlmZ ddlZddlZddlZddlZddlZddl	Zddl
mZmZ ddlmZmZ ddlmZ ddlmZmZ  ej,                  e«      Zd	Zd
ZdEd„ZdEd„ZdFd„ZdGd„ZdHd„ZdIdJd„Z dKd„Z!dLd„Z"dMd„Z#dNd„Z$dOd„Z%dPd„Z&dQd„Z'dZ(e(e(ddœZ)dRd„Z*dRd „Z+dIdSd!„Z,dRd"„Z-dTd$„Z.dUdVd%„Z/dRd&„Z0dWd'„Z1e*d(d e1d)«      idgfe+d* e1d+«       e1d,«       e1d-«      d.œddgfe,d/i g fe-d0 e1d1«      d2d3d4œd5œdgfe0d6 e1d7«       e1d8«      d9g d:¢d;d<œ e1d=«      d>œd#dgfd?œZ2d@e3dA<   dXdB„Z4dYdC„Z5ddDlm6Z6 y)Za(  A2A client tools (``a2a`` toolset): a2a_discover/call/list/history/orchestrate talk to *other*
agents. Peers come from config.yaml ``a2a_agents: {name: {url, auth: {type: bearer, token}, timeout,
capabilities}}``. Stdlib urllib; wire format is A2A v1.0 ``SendMessage`` (v0.3 replies still parse).é    )ÚannotationsN)ÚThreadPoolExecutorÚas_completed)ÚAnyÚOptional)Úcoerce_porté   )ÚprotocolÚsecurityéx   é   c                 ó$   — ddl m}   | «       xs i S )zORead-only view of config.yaml; peers are only read, never mutated (cache-safe).r   ©Úload_config_readonly)Úhermes_cli.configr   r   s    ú@/home/ubuntu/.hermes/hermes-agent/plugins/platforms/a2a/tools.pyÚ_load_configr      s   € å6ÙÓ!Ò' RÐ'ó    c                 ó<   — t        «       j                  d«      xs i S )NÚ
a2a_agents)r   Úget© r   r   Ú_configured_peersr       s   € Ü‹>×Ñ˜lÓ+Ò1¨rÐ1r   c                ó”   — | j                  dd«      | j                  di «      xs i t        | j                  dt        «      «      dœ|¥S )NÚurlÚ ÚauthÚtimeout)r   r   r   )r   ÚintÚ_DEFAULT_TIMEOUT)ÚentryÚextras     r   Ú_peer_from_entryr#   $   sK   € Ø—9‘9˜U BÓ'°·±¸6À2Ó1FÒ1LÈ"Ü˜5Ÿ9™9 YÔ0@ÓAÓBñMØFKðMð Mr   Úagentc                óØ   — | j                  d«      r| i t        g dœS t        «       j                  | «      }|r2t	        ||j                  dg «      xs g |j                  dd«      ¬«      S dS )zUPeer name -> {url, auth, timeout, capabilities, tenant}, or treat ``agent`` as a URL.)zhttp://zhttps://)r   r   r   Úcapabilitiesr&   Útenantr   )r&   r'   N)Ú
startswithr    r   r   r#   )r$   r!   s     r   Ú_resolve_peerr)   )   sx   € à×ÑÐ/Ô0Ø bÔ5EÐWYÑZÐZÜÓ×#Ñ# EÓ*€EÙx}Ô˜E°·	±	¸.È"Ó0MÒ0SÐQSÐ\a×\eÑ\eÐfnÐprÓ\sÔtð  Hð  DHð  Hr   c                óh   — | r/| j                  d«      dk(  r| j                  d«      r
dd| d   › �iS i S )NÚtypeÚbearerÚtokenÚAuthorizationzBearer ©r   )r   s    r   Ú_auth_headerr0   1   s@   € Ù;?ÀDÇHÁHÈVÓDTÐX`ÒD`Ðei×emÑemÐnuÔevˆO˜w t¨G¡} oÐ6Ð7Ð~Ð|~Ð~r   r   c                ó  — t         j                  j                  | |||¬«      }t         j                  j                  ||¬«      5 }t	        j
                  |j                  «       j                  d«      «      cd d d «       S # 1 sw Y   y xY w)N)ÚdataÚheadersÚmethod)r   úutf-8)ÚurllibÚrequestÚRequestÚurlopenÚjsonÚloadsÚreadÚdecode)r   r3   r   r4   r2   ÚreqÚresps          r   Ú
_http_jsonr@   5   sj   € Ü
�.‰.×
 Ñ
  ¨4¸ÈÐ
 Ó
P€CÜ	�‰×	Ñ	 ¨WÐ	Ó	5ð 7¸Ü�z‰z˜$Ÿ)™)›+×,Ñ,¨WÓ5Ó6÷7÷ 7ò 7ús   Á2BÂB
c                ó   — t        | ||d«      S )NÚGET)r@   )r   r3   r   s      r   Ú_http_get_jsonrC   ;   s   € Ü�c˜7 G¨UÓ3Ð3r   c           	     óŽ   — dt         j                  dœ|¥}t        | ||dt        j                  |«      j                  d«      «      S )Nzapplication/json)zContent-TypezA2A-VersionÚPOSTr5   )r
   ÚPROTOCOL_VERSIONr@   r:   ÚdumpsÚencode)r   Úbodyr3   r   Úhdrss        r   Ú_http_post_jsonrK   ?   s?   € Ø.¼x×?XÑ?XÑdÐ\cÐd€DÜ�c˜4 ¨&´$·*±*¸TÓ2B×2IÑ2IÈ'Ó2RÓSÐSr   c                óÚ   — | j                  d«      }	 t        |dz   ||«      S # t        j                  j                  $ r}|j
                  dk7  r‚ Y d}~nd}~ww xY wt        |dz   ||«      S )zLGET the v1.0 agent-card.json; on 404 fall back to the v0.2 agent.json alias.ú/z/.well-known/agent-card.jsoni”  Nz/.well-known/agent.json)ÚrstriprC   r6   ÚerrorÚ	HTTPErrorÚcode)Úbase_urlr3   r   ÚbaseÚes        r   Ú_fetch_cardrU   D   sn   € à�?‰?˜3Ó€DðÜ˜dÐ%CÑCÀWÈgÓVÐVøÜ�<‰<×!Ñ!ò Ø�6‰6�SŠ=Øô ûðúô ˜$Ð!:Ñ:¸GÀWÓMÐMs   “# £AÁ AÁAc                óÐ   — t        | t        «      rV| j                  dg «      xs g D ]=  }t        |t        «      sŒ|j                  d«      dk(  sŒ)|j                  d«      sŒ;|c S  y )NÚsupportedInterfacesÚprotocolBindingÚJSONRPCr   ©Ú
isinstanceÚdictr   )ÚcardÚifaces     r   Ú_select_jsonrpc_interfacer_   O   s`   € Ü�$œÔØ—X‘XÐ3°RÓ8Ò>¸Bò 	ˆEÜ˜%¤Õ&¨5¯9©9Ð5FÓ+GÈ9Ó+TÐY^×YbÑYbÐchÕYiØ’ð	ð r   c                óÌ   — t        |«      x}rt        |d   «      S t        |t        «      r)t        |j	                  d«      t        «      r
|d   r|d   S | j                  d«      S )zYCard's JSONRPC interface (v1.0 supportedInterfaces) > card's legacy top-level url > base.r   rM   )r_   Ústrr[   r\   r   rN   )rR   r]   r^   s      r   Ú_rpc_urlrb   W   s[   € ä)¨$Ó/Ð/€uÐ/Ü�5˜‘<Ó Ð Ü�$œÔ¤*¨T¯X©X°e«_¼cÔ"BÀtÈEÂ{Ø�E‰{ÐØ�?‰?˜3ÓÐr   ÚmessageÚ
context_idc           
     ó*  — |j                  dd«      }t        |j                  di «      xs i «      }t        |j                  dt        «      «      }	 t	        ||t        |d«      «      }|xs t        j                  «       }t        j                  |«      }	dt        j                  «       dd	t        j                  t        j                  |	|¬
«      idœ}
t        |«      }|r|j                  d«      rt        |d   «      nt        |j                  d«      xs d«      }|r||
d   d<   t        j                   d| |
d   |	«       t        j"                  |d|	|
d   «       t        j$                  xj&                  dz  c_        t)        t+        ||«      |
||«      }d|v r't-        d| › d|d   j                  d	|d   «      › �«      ‚t        j.                  |j                  di «      «      }t1        |«      }|d}}t3        |t4        «      r7|j                  d|«      }|j                  d«      xs i j                  dd«      }t        j"                  |d||
d   «       t        j$                  xj6                  dz  c_        |||fS # t        $ r d}Y �Œ(w xY w)z­One SendMessage to a peer -> (reply_text, context_id, state). Raises urllib errors /
    ValueError for the caller to format; handles redaction, audit, persistence, metrics.r   r   r   r   é   Nz2.0ÚSendMessagerc   )rd   )ÚjsonrpcÚidr4   Úparamsr'   rj   Úoutboundri   Úuserr	   rO   zPeer 'z' returned an error: ÚresultÚ	contextIdÚstatusÚstater$   )r   r0   r   r    rU   ÚminÚ	Exceptionr
   Únew_context_idr   Úredact_outboundÚnew_task_idÚtext_messageÚ	ROLE_USERr_   ra   ÚauditÚpersist_messageÚmetricsÚoutbound_totalrK   rb   Ú
ValueErrorÚunwrap_send_message_responseÚ_reply_text_from_resultr[   r\   Úinbound_total)Úagent_labelÚpeerrc   rd   rR   r3   r   r]   ÚctxÚsafe_messageÚrpc_bodyr^   r'   r?   ÚpayloadÚreplyÚ	reply_ctxrp   s                     r   Ú
_send_taskrˆ   `   sX  € ð �x‰x˜˜rÓ"€HÜ˜4Ÿ8™8 F¨BÓ/Ò5°2Ó6€GÜ�$—(‘(˜9Ô&6Ó7Ó8€GðÜ˜8 W¬c°'¸2Ó.>Ó?ˆð Ò
1œ×/Ñ/Ó1€CÜ×+Ñ+¨GÓ4€Là ¬×(<Ñ(<Ó(>È-Ø$¤h×&;Ñ&;¼H×<NÑ<NÐP\ÐilÔ&mÐnñp€Hä% dÓ+€EÙ%*¨u¯y©y¸Ô/BŒS��x‘Ô!ÌÈDÏHÉHÐU]ÓL^ÒLdÐbdÓHe€FÙØ'-ˆ�Ñ˜8Ñ$Ü‡N�N�:˜{¨H°T©N¸LÔIÜ×Ñ˜S &¨,¸À¹ÔGÜ×Ñ×#Ò# qÑ(Õ#Üœ8 H¨dÓ3°X¸wÈÓP€DØ�$�Ü˜6 + Ð.CÀDÈÁM×DUÑDUÐV_ÐaeÐfmÑanÓDoÐCpÐqÓrÐrÜ×3Ñ3°D·H±H¸XÀrÓ4JÓK€GÜ# GÓ,€EØ˜Bˆu€IÜ�'œ4Ô Ø—K‘K ¨SÓ1ˆ	Ø—‘˜XÓ&Ò,¨"×1Ñ1°'¸2Ó>ˆÜ×Ñ˜Y¨°¸À¹ÔGÜ×Ñ×"Ò" aÑ'Õ"Ø�)˜UÐ"Ð"øô3 ò Ø‹ðús   ÁJ ÊJÊJc                óF  — t        j                  | «      } t        | t        «      st	        | «      S | j                  dg «      xs g D ]  }t        j                  |«      }|sŒ|c S  t        j                  | j                  di «      xs i j                  d«      xs | «      S )NÚ	artifactsro   rc   )r
   r}   r[   r\   ra   r   Úextract_text)rm   ÚartifactÚtxts      r   r~   r~   „   s‘   € Ü×2Ñ2°6Ó:€FÜ�fœdÔ#Ü�6‹{Ðà—J‘J˜{¨BÓ/Ò5°2ò ˆÜ×#Ñ# HÓ-ˆÚØŠJðô × Ñ  &§*¡*¨X°rÓ":Ò"@¸b×!EÑ!EÀiÓ!PÒ!ZÐTZÓ[Ð[r   zNError: peer '{agent}' rejected auth (HTTP {code}). Check the configured token.z>Error: peer '{agent}' rate limited us (HTTP 429). Retry later.)i‘  i“  i­  c                óœ  — t        | j                  d«      xs d«      j                  «       }|sy	 t        |i t        «      }|j                  d
i «      xs i }|j                  dg «      xs g }|j                  d«      rdnd}dj                  d„ |j                  dg «      xs g D «       «      xs d|j                  dd«      › d�}d|j                  dd«      › �d|j                  dd«      › �dt        ||«      › �d|› �dt        |j                  d«      «      › dt        |j                  d«      «      › d |› �d!t        |«      › d"�g}	|	j                  d#„ |dd$ D «       «       d%j                  |	«      S # t
        j                  j                  $ r}d|j                  › d|› d�cY d}~S d}~wt        $ r}d|› d	|› d�cY d}~S d}~ww xY w)&z.Fetch and summarize the Agent Card at ``url``.r   r   z6Error: 'url' is required (e.g. http://localhost:9999).u!   Error: discovery failed â€” HTTP z from ú.NzError: could not reach u    â€” r&   Úskillsr   ÚyesÚnoú, c              3  óŠ   K  — | ];  }t        |t        «      r)|j                  d d«      › d|j                  dd«      › �–— Œ= y­w)rX   ú?z vÚprotocolVersionNrZ   )Ú.0Úis     r   ú	<genexpr>za2a_discover.<locals>.<genexpr>¡   sF   è ø€ ò àÄ
È1ÌdÔ@Sð �5‰5Ð" CÓ(Ð
)¨¨A¯E©EÐ2CÀSÓ,IÐ+JÔKñùs   ‚AArW   Úvr–   r•   z (pre-1.0 card)zAgent: ÚnamezDescription: ÚdescriptionzURL: z
Protocol: zStreaming: Ú	streamingz  Push: ÚpushNotificationsz  Auth required: zSkills (ú):c           	   3  óŒ   K  — | ]<  }d |j                  d|j                  dd«      «      › d|j                  dd«      › �–— Œ> y­w)ú  - r›   ri   r•   ú: rœ   r   Nr/   )r—   Úss     r   r™   za2a_discover.<locals>.<genexpr>©   sB   è ø€ ÒkÐZ[�4˜Ÿ™˜f a§e¡e¨D°#Ó&6Ó7Ð8¸¸1¿5¹5ÀÐPRÓ;SÐ:TÔUÑkùs   ‚AAé   Ú
)ra   r   ÚstriprU   r    r6   rO   rP   rQ   rr   Újoinrb   ÚboolÚlenÚextend)
ÚargsÚ_r   r]   rT   Úcapsr�   r   ÚprotoÚliness
             r   Úa2a_discoverr°   “   sæ  € ä
ˆd�h‰h�u‹oÒ# Ó
$×
*Ñ
*Ó
,€CÙØGð8Ü˜3 Ô$4Ó5ˆð
 �8‰8�N BÓ'Ò-¨2€DØ�X‰X�h Ó#Ò) r€FØ—H‘H˜ZÔ(‰5¨d€DØ�I‰Iñ à—(‘(Ð0°"Ó5Ò;¸ôó ò ?ð ˆT�X‰XÐ'¨Ó-Ð.¨oÐ	>ð 
ð �t—x‘x ¨Ó,Ð-Ð.°-ÀÇÁÈÐXZÓ@[Ð?\Ð0]ÐafÔgoÐpsÐuyÓgzÐf{Ð_|Ø˜%˜Ð!Øœ4 §¡¨Ó 5Ó6Ð7°xÄÀTÇXÁXÐNaÓEbÓ@cÐ?dÐduÐvzÐu{Ð|Øœ˜F›�} BÐ'ð)€Eð 
‡L�LÑkÐ_eÐfiÐgiÐ_jÔkÔkØ�9‰9�UÓÐøô! �<‰<×!Ñ!ò HØ2°1·6±6°(¸&ÀÀÀQÐGÕGûÜò 8Ø(¨¨¨U°1°#°QÐ7Õ7ûð8ús/   ±E7 Å7GÆF,Æ&GÆ,GÆ8GÇ GÇGc                óR  — t        | j                  d«      xs( | j                  d«      xs | j                  d«      xs d«      j                  «       }t        | j                  d«      xs( | j                  d«      xs | j                  d«      xs d«      j                  «       }t        | j                  d«      xs | j                  d	«      xs d«      j                  «       }|r|sy
t        |«      }|r|j                  d«      sd|› d�S 	 t	        ||||«      \  }}}|j                  dd«      j                  dd«      j                  «       }
d|› d|› �|rd|
› �ndz   dz   }|xs d}|t        j                   k(  r	|d|› d�z  }|› d|› �S # t
        j                  j                  $ rE}	t        j                  |	j                  d«      j                  ||	j                  ¬«      cY d}	~	S d}	~	wt        $ r}	t        |	«      cY d}	~	S d}	~	wt        $ r}	d|› d|	› d�cY d}	~	S d}	~	ww xY w)zaSend a task to a peer (configured name or direct URL); ``context_id`` continues a prior exchange.r$   Ú
agent_namer›   r   rc   ÚtextÚtaskrd   rn   z/Error: both 'agent' and 'message' are required.r   zError: unknown agent 'zP'. Configure it under 'a2a_agents' in config.yaml or pass a full http(s):// URL.u0   Error: call to '{agent}' failed â€” HTTP {code}.)r$   rQ   NzError: call to 'u   ' failed â€” r�   ÚTASK_STATE_r¬   Ú-ú[u    Â· context u    Â· ú]z(no text reply)uS   

(The peer needs more input â€” answer by calling a2a_call again with context_id 'z'.)r¥   )ra   r   r¦   r)   rˆ   r6   rO   rP   Ú_HTTP_CALL_ERRORSrQ   Úformatr|   rr   ÚreplaceÚlowerr
   ÚSTATE_INPUT_REQUIRED)r«   r¬   r$   rc   rd   r�   r†   r‡   rp   rT   Úshort_stateÚheaderrI   s                r   Úa2a_callrÀ   ­   s  € ô �—‘˜Ó!ÒU T§X¡X¨lÓ%;ÒU¸t¿x¹xÈÓ?OÒUÐSUÓV×\Ñ\Ó^€EÜ�$—(‘(˜9Ó%ÒS¨¯©°&Ó)9ÒS¸T¿X¹XÀfÓ=MÒSÐQSÓT×ZÑZÓ\€GÜ�T—X‘X˜lÓ+ÒJ¨t¯x©x¸Ó/DÒJÈÓK×QÑQÓS€JÙ™Ø@Ü˜Ó€DÙ�t—x‘x ”Ø'¨ wÐ.~ÐÐð;Ü",¨U°D¸'À:Ó"NÑˆˆy˜%ð —-‘- ¨rÓ2×:Ñ:¸3ÀÓD×JÑJÓL€KØ���| I ;Ð/É5°T¸+¸Ñ3GÐVXÑYÐ\_Ñ_€FØÒ%Ð%€DØ”×-Ñ-Ò-ØÐgÐhqÐgrÐruÐvÑvˆØˆX�R˜�vÐÐøô �<‰<×!Ñ!ò BÜ ×$Ñ$ Q§V¡VÐ-_Ó`×gÑgÐnsÐz{÷  {Añ  {AÐgó  Bõ  	BûÜò Ü�1‹v�ûÜò ;Ø! % ¨°a°S¸Ð:Õ:ûð;úsB   ÄF ÆH&Æ+:G+Ç%H&Ç+H&Ç7
HÈH&ÈH&ÈH!ÈH&È!H&c                óp  — t        «       }g }|r°|j                  dt        |«      › d�«       |j                  «       D ]~  \  }}|j	                  dg «      }|j                  d|› d|j	                  dd«      › d|j	                  d	«      xs i j	                  d
d«      › d�|rddj                  |«      › �ndz   «       Œ€ n|j                  d«       t        j                  «       x}rJ|j                  d«       |j                  dt        |«      › d�«       |j                  d„ |dd D «       «       t        j                  j                  «       }|j                  d«       |j                  d|d   › d|d   › d|d   › d|d   › d|d   › d |d!   › d"|d#   › d$|d%   › d&|d'   › d(�«       d)j                  |«      S )*z@List configured A2A peers, persisted conversations, and metrics.zConfigured peers (rŸ   r&   r¡   r¢   r   r•   z (auth: r   r+   Únoneú)z caps: r“   r   z@No peers configured. Add them under 'a2a_agents' in config.yaml.zPersisted conversations (u   ) â€” recall with a2a_history:c              3  ó&   K  — | ]	  }d |› �–— Œ y­w)r¡   Nr   )r—   Úcs     r   r™   za2a_list.<locals>.<genexpr>×   s   è ø€ Ò5 A�t˜A˜3”ZÑ5ùs   ‚Né   z	Metrics: r   z in / r{   z out, Útasks_completedz completed, Útasks_failedz	 failed, Ústreams_startedz
 streams, Ú	push_sentz push sent, Úanti_loop_triggersz anti-loop, Úrate_limit_triggersz rate-limited, avg Úavg_latency_msÚmsr¥   )r   Úappendr©   Úitemsr   r§   r
   Úlist_conversationsrª   rz   Úsnapshot)	r«   r¬   Úpeersr¯   r›   r!   r­   ÚconvosÚms	            r   Úa2a_listrÖ   È   sé  € äÓ€EØ€EÙØ�‰Ð)¬#¨e«*¨°RÐ8Ô9Ø Ÿ;™;›=ò 	J‰KˆD�%Ø—9‘9˜^¨RÓ0ˆDØ�L‰L˜4 ˜v R¨¯	©	°%¸Ó(=Ð'>¸hÈÏ	É	ÐRXÓHYÒH_Ð]_×GdÑGdÐekÐmsÓGtÐFuÐuvÐwÙ;?˜g d§i¡i°£oÐ%6Ñ7ÀRñIõ Jñ	Jð
 	�‰ÐWÔXÜ×,Ñ,Ó.Ð.€vÐ.Ø�‰�RÔØ�‰Ð0´°V³°Ð=[Ð\Ô]Ø�‰Ñ5¨°°¨Ô5Ô5Ü×Ñ×!Ñ!Ó#€AØ	‡L�L�ÔØ	‡L�L�9˜Q˜Ñ/Ð0°°qÐ9IÑ7JÐ6KÈ6ÐRSÐTeÑRfÐQgÐgsØ�nÑ%Ð& i°Ð2CÑ0DÐ/EÀZÐPQÐR]ÑP^ÐO_Ð_kØÐ*Ñ+Ð,¨L¸Ð;PÑ9QÐ8RÐReÐfgÐhxÑfyÐezÐz|ð~ô ð �9‰9�UÓÐr   c           
     ó@  — t        | j                  d«      xs | j                  d«      xs d«      j                  «       }|syt        dt	        t        | j                  d«      xs dd«      d«      «      }t        j                  ||¬	«      }|sd
|› d�S d|› dt        |«      › d�g}|D ]b  }|j                  d«      xs dj                  «       }|j                  d|j                  dd«      › dt        |«      dkD  r|dd dz   n|› �«       Œd dj                  |«      S )zCRecall a persisted A2A conversation (survives compaction/restarts).rd   rn   r   zGError: 'context_id' is required (see a2a_list for known conversations).r	   Úlimité2   éÈ   )rØ   z'No persisted conversation for context 'ú'.zConversation z (last z messages):r³   r·   Úroler•   z] iè  Nu    â€¦[truncated]r¥   )ra   r   r¦   Úmaxrq   Ú_coerce_intr
   Úload_conversationr©   rÏ   r§   )r«   r¬   rd   rØ   Úmessagesr¯   rÕ   r³   s           r   Úa2a_historyrá   à   s  € ä�T—X‘X˜lÓ+ÒJ¨t¯x©x¸Ó/DÒJÈÓK×QÑQÓS€JÙØXÜ�”3”{ 4§8¡8¨GÓ#4Ò#:¸¸BÓ?ÀÓEÓF€EÜ×)Ñ)¨*¸EÔB€HÙØ8¸¸ÀBÐGÐGØ˜Z˜L¨´°H³¨¸kÐJÐK€EØò pˆØ—‘�f“Ò# ×*Ñ*Ó,ˆØ�‰�q˜Ÿ™˜v sÓ+Ð,¨BÔRUÐVZÓR[Ð^bÒRb¨t°E°T¨{Ð=NÒ/NÐhlÐ.mÐnÕoðpð �9‰9�UÓÐr   Ú
capabilityc           	     ó¢   — t        «       j                  «       D ��cg c]&  \  }}| |j                  dg «      xs g v s| dk(  r||f‘Œ( c}}S c c}}w )zAConfigured peers that advertise the capability ('*' matches all).r&   Ú*)r   rÐ   r   )râ   r›   r!   s      r   Ú_match_peers_by_capabilityrå   ð   sY   € ä->Ó-@×-FÑ-FÓ-H÷ Y™k˜d EØ˜eŸi™i¨¸Ó;ÒA¸rÑBÀjÐTWÒFWð �5ŠMó Yð Yùó Ys   œ+Ac                ó„   — 	 t        | t        |«      ||«      \  }}}| |xs dfS # t        $ r}| d|› �fcY d}~S d}~ww xY w)z=Call a single peer synchronously -> (agent_name, reply_text).z
(no reply)úError: N)rˆ   r#   rr   )r²   Ú
peer_entryrc   rd   r†   Ú_ctxÚ_staterT   s           r   Ú_call_peer_syncrë   ö   sW   € ð+Ü(¨Ô5EÀjÓ5QÐSZÐ\fÓgÑˆˆt�VØ˜EÒ1 \Ð2Ð2øÜò +Ø˜g a S˜MÐ*Õ*ûð+ús   ‚"% ¥	?®:´?º?c                óÌ  — t        | j                  d«      xs d«      j                  «       }t        | j                  d«      xs | j                  d«      xs d«      j                  «       }t        | j                  d«      xs d«      j                  «       j                  «       }|dv r|nd}t        | j                  d«      xs d«      j                  «       }|sy	|sy
t	        |«      x}sd|› d�S g }t        t        t        |«      t        «      ¬«      5 }|D �	�
ci c]  \  }	}
|j                  t        |	|
||«      |	“Œ! }}	}
t        |«      D ]\  }||   }		 |j                  |j                  «       «       |dk(  r0|d   d   j                  d«      s|D ]  }|j                  «        Œ  nŒ^ ddd«       |j#                  d„ ¬«       |D �	�cg c]  \  }	}|j                  d«      rŒ|	|f‘Œ }}	}|dv rV|s.dj%                  dg|D �	�cg c]  \  }	}d|	› d|› �‘Œ c}}	z   «      S |dk(  rt'        |d„ ¬«      n|d   \  }	}d|› d|	› d|› �S dj%                  d |› d!t        |«      › d"�g|D �	��cg c]  \  }	}d#|	› d$�|fD ]  }|‘Œ Œ c}}}	z   «      S c c}
}	w # t         $ r!}|j                  |	d|› �f«       Y d}~�Œnd}~ww xY w# 1 sw Y   �ŒxY wc c}}	w c c}}	w c c}}}	w )%u©   Fan-out a task to peers matching a capability. Modes: ``all``, ``first`` (first successful),
    ``best`` (longest successful â€” coarse; use ``all`` to judge yourself).râ   r   rc   r´   ÚmodeÚall©rî   ÚfirstÚbestrd   zError: 'message' is required.z;Error: 'capability' is required (or use '*' for all peers).z1Error: no configured peers advertise capability 'rÛ   )Úmax_workersrð   éÿÿÿÿr	   zError:rç   Nc                ó   — | d   S )Nr   r   ©Úrs    r   ú<lambda>z!a2a_orchestrate.<locals>.<lambda>  s
   € ˜q ™t€ r   )Úkey)rñ   rð   r¥   zAll peers failed:z  r¢   rñ   c                ó   — t        | d   «      S )Nr	   )r©   rõ   s    r   r÷   z!a2a_orchestrate.<locals>.<lambda>  s   € ´3°q¸±t³9€ r   r   r·   z]
zOrchestrated 'z' to z	 peer(s):z
--- z ---)ra   r   r¦   r¼   rå   r   rq   r©   Ú_ORCHESTRATE_MAX_WORKERSÚsubmitrë   r   rÏ   rm   r(   Úcancelrr   Úsortr§   rÝ   )r«   r¬   râ   rc   rí   rd   ÚmatchesÚresultsÚpoolr›   r!   ÚfuturesÚfutÚfrT   r†   Ú	successesÚlines                     r   Úa2a_orchestrater  ÿ   s   € ô �T—X‘X˜lÓ+Ò1¨rÓ2×8Ñ8Ó:€JÜ�$—(‘(˜9Ó%Ò?¨¯©°&Ó)9Ò?¸RÓ@×FÑFÓH€GÜˆt�x‰x˜ÓÒ( 5Ó)×/Ñ/Ó1×7Ñ7Ó9€DØÐ3Ñ3‰4¸€DÜ�T—X‘X˜lÓ+Ò1¨rÓ2×8Ñ8Ó:€JÙØ.ÙØLÜ1°*Ó=Ð=ˆGÐ=ØBÀ:À,ÈbÐQÐQØ%'€GÜ	¬¬C°«LÔ:RÓ(SÔ	Tð 6ÐX\Økr×sÑ\gÐ\`Ðbg�4—;‘;œ°°e¸WÀjÓQÐSWÑWÐsˆÑsÜ Ó(ò 		6ˆCØ˜3‘<ˆDð6Ø—‘˜sŸz™z›|Ô,Ø˜7’?¨7°2©;°q©>×+DÑ+DÀXÔ+NØ$ò #˜ØŸ™�
ð#áøð		6÷6ð ‡L�L‘^€LÔ$Ø29×\¡; 4¨À×AQÑAQÐRZÕA[�$˜’Ð\€IÑ\ØÐ Ñ ÙØ—9‘9Ð1Ð2Ð^e×5fÉ{ÈtÐUZ¸¸4¸&ÀÀ5À'Ò6JÓ5fÑfÓgÐgØAEÈÂ”c˜)Ñ)<Õ=ÐU^Ð_`ÑUa‰ˆˆeØ�4�&˜˜4˜&  E 7Ð+Ð+Ø�9‰9˜ z l°%¼¸G»°~ÀYÐOÐPØ07×aÐa¡  uÀvÈdÈVÐSWÐEXÐZ_ÐD`Òa¸DšÐa˜Ôañbó cð cùó% tøô ò 6Ø—‘ ¨°¨s mÐ4×5Ò5ûð6ú÷6ñ 6üó ]ùó 6gùô bsa   ÄKÄ$JÅKÅAJÆ+KÇKÇ)KÈ
KÉ/KÊKÊ	KÊ"J>Ê8KÊ>KËKËKc                ó   — d| dœS )NÚstring©r+   rœ   r   )rœ   s    r   Ú_strr
  %  s   € Ø¨[Ñ9Ð9r   z³Fetch and summarize another agent's A2A Agent Card from a URL (its name, description, capabilities, and skills). Use this to find out what a remote agent can do before calling it.z<Base URL of the remote A2A agent, e.g. http://localhost:9999zãSend a natural-language task to a remote A2A agent and return its reply. The agent is a peer (any A2A-compliant framework), not a sub-agent you control. Pass 'context_id' from a previous reply to continue a multi-turn exchange.z@Configured peer name (from a2a_agents) or a full http(s):// URL.z9The task / message to send the peer, in natural language.zFOptional: context id from a prior reply, to continue the conversation.)r$   rc   rd   zJList configured A2A peer agents, persisted A2A conversations, and metrics.z�Recall a persisted A2A conversation transcript by context_id (survives restarts and context compaction). Use a2a_list to see known context ids.z)Context id of the conversation to recall.Úintegerz-Max messages to return (default 50, max 200).r	  )rd   rØ   zÕFan-out a task to multiple peer agents by capability. Peers are matched from config.yaml a2a_agents.*.capabilities. Modes: 'all' (return all replies), 'first' (first successful), 'best' (longest successful reply).zCCapability to match (e.g. 'research', 'code') or '*' for all peers.z'The task to send to all matching peers.r  rï   z)How to aggregate results. Default: 'all'.)r+   Úenumrœ   z*Optional: shared context id for all peers.)râ   rc   rí   rd   )r°   rÀ   rÖ   rá   r  z+dict[str, tuple[Any, str, dict, list[str]]]Ú_TOOLSc                 ó¢  — i } t        j                  t        «      5  t        «       } | j	                  d«      r
	 ddd«       y	 ddd«       	 t        j                  d«      ry| j	                  d«      xs i j	                  d«      xs i }t        t        |t        «      xr |j	                  d«      «      S # 1 sw Y   ŒtxY w# t        $ r Y yw xY w)	uF  check_fn: serve the client tools ONLY when the operator opted into A2A (peers under
    ``a2a_agents``, inbound platform enabled, or A2A_PORT set). Fail closed.

    Maintainer-directed (#95681): these registered unconditionally, so every session on every install paid
    ~561 tok/call for tools whose only possible output without config is 'no peers configured'. A2A is
    unrelated to Bot Mode (bots talk over gateway RPCs) â€” for most installs this toolset is foreign-agent
    plumbing they never enabled. Config adds mid-session surface at the next compaction (#97073).
    r   NTÚA2A_PORTÚ	platformsÚa2aÚenabledF)
Ú
contextlibÚsuppressrr   r   r   ÚosÚgetenvr¨   r[   r\   )ÚcfgÚa2a_cfgs     r   Ú_a2a_tools_availabler  J  s¹   € ð €CÜ	×	Ñ	œYÓ	'ñ Ü‹nˆØ�7‰7�<Ô Ø÷ð à ÷ðÜ�9‰9�ZÔ ØØ—7‘7˜;Ó'Ò-¨2×2Ñ2°5Ó9Ò?¸RˆÜ”J˜w¬Ó-ÒH°'·+±+¸iÓ2HÓIÐI÷ð ûô ò Ùðús$   œB6ÁC Á"AC Â6B?Ã	CÃCc                óž   — t         j                  «       D ]6  \  }\  }}}}d|dœ}|r||d<   | j                  |d|||||dœdt        ¬«       Œ8 y)	z@Register the client tools in the ``a2a`` toolset (config-gated).Úobject)r+   Ú
propertiesÚrequiredr  )r›   rœ   Ú
parametersu   ðŸ§©)r›   ÚtoolsetÚhandlerrœ   ÚschemaÚemojiÚcheck_fnN)r  rÐ   Úregister_toolr  )r‚   r›   r   rœ   r  r  r  s          r   Úregister_toolsr%  a  sl   € ä>D¿l¹l»nò MÑ:ˆÑ:ˆw˜ Z°Ø.6ÀjÑ%Qˆ
ÙØ%-ˆJ�zÑ"Ø×Ñ˜t¨U¸GÐQ\Ø*.¸{ÐZdÑ!eØ ,Ô7Kð 	õ 	Mñ	Mr   )Ú	TypedDict)Úreturnr\   )r!   r\   r"   r   r'  r\   )r$   ra   r'  úOptional[dict])r   r\   r'  r\   )N)r   ra   r3   r\   r   r   r4   ra   r2   zOptional[bytes]r'  r\   )r   ra   r3   r\   r   r   r'  r\   )
r   ra   rI   r\   r3   r\   r   r   r'  r\   )rR   ra   r3   r\   r   r   r'  r\   )r]   r(  r'  r(  )rR   ra   r]   r(  r'  ra   )
r€   ra   r�   r\   rc   ra   rd   ra   r'  ztuple[str, str, str])rm   r   r'  ra   )r«   r\   r¬   r   r'  ra   )r«   zdict | Noner¬   r   r'  ra   )râ   ra   r'  zlist[tuple[str, dict]])r   )
r²   ra   rè   r\   rc   ra   rd   ra   r'  ztuple[str, str])rœ   ra   r'  r\   )r'  r¨   )r'  ÚNone)7Ú__doc__Ú
__future__r   r  r:   Úloggingr  Úurllib.errorr6   Úurllib.requestÚconcurrent.futuresr   r   Útypingr   r   Úgateway.platforms._sharedr   rÞ   r   r
   r   Ú	getLoggerÚ__name__Úloggerr    rú   r   r   r#   r)   r0   r@   rC   rK   rU   r_   rb   rˆ   r~   Ú	_AUTH_ERRr¹   r°   rÀ   rÖ   rá   rå   rë   r  r
  r  Ú__annotations__r  r%  r&  r   r   r   ú<module>r7     sá  ðòhõ #ã Û Û Û 	Û Û ß ?ß  å @ç  à	ˆ×	Ñ	˜8Ó	$€àÐ ØÐ ó(ó2óMó
Hóô7ó4óTó
Nóó ó!#óH	\ð ]€	Ø#¨)Ð:zÑ{Ð óó4ô6ó0ó Yô+ó#cóL:ð "ðuà™TÐ"`ÓaÐbÐejÐdkðmð ð<ñ  Ð bÓcÙ!Ð"]Ó^Ù $Ð%mÓ nñpð ˜9Ð%ð'ð ÐgÐikÐmoÐpØðRá#'Ð(SÓ#TØ'0ÐApÑqñsà!�Nð$ð (ð=ñ (,Ð,qÓ'rÙ$(Ð)RÓ$SØ*2Ò<Tð  fQñ  "RÙ'+Ð,XÓ'Yñ[ð & yÐ1ð3ñ)7€Ð3ó ó@ó.Mö r   