§
    øžyj*\  ã                  óž  — 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m	Z	m
Z
 ddlmZmZmZ ddlmZmZ  ej        e¦  «        ZdZd	Zdhd„Zdid„Zdjd„Zdkd„Zdld„Zdmd„Zdmd„Zdnd„Zdod„Zdpd „Z dqd"„Z!drd$„Z"dsd)„Z#dtd,„Z$dud/„Z%dud0„Z&dvdwd2„Z'dud3„Z(dxd6„Z)dydzd;„Z*dud<„Z+ ed=e,e,e-e,ef         d>œd?¬@¦  «        Z. edAe,e.dBœd?¬@¦  «        Z/dCdDdEdFddGdHdIœidgdJœd>œdBœdCdKdLdFdGdMdIœdGdNdIœdGdOdIœdPœdd&gdJœd>œdBœdCdQdRdFi dSœd>œdBœdCdTdUdFdGdVdIœdWdXdIœdYœd'gdJœd>œdBœdCdZd[dFdGd\dIœdGd]dIœdGg d^¢d_d`œdGdadIœdbœd4d&gdJœd>œdBœdcœZ0dde1de<   e%e&e'e(e+dcœZ2d{dg„Z3dS )|u  
A2A client tools â€” let the Hermes agent talk to *other* agents as a peer.

Tools (registered in the ``a2a`` toolset):
  - a2a_discover(url)         -> fetch + summarize a peer's Agent Card
  - a2a_call(agent, message)  -> send a task to a peer, return its reply
  - a2a_list()                -> list configured peers + persisted conversations
  - a2a_history(context_id)   -> recall a persisted A2A conversation
  - a2a_orchestrate(...)      -> fan-out task to multiple peers by capability

Peers are resolved from config.yaml under ``a2a_agents``::

    a2a_agents:
      researcher:
        url: "http://localhost:9999"
        auth: { type: bearer, token: "sk-..." }
        timeout: 120
        capabilities: [web_search, research]

Transport is stdlib urllib (no a2a-sdk dependency). The wire format is the A2A
v1.0 JSON-RPC ``message/send`` method; replies from v0.3 peers still parse.
é    )ÚannotationsN)ÚThreadPoolExecutorÚas_completed)ÚAnyÚOptionalÚ	TypedDicté   )ÚprotocolÚsecurityéx   é   ÚreturnÚdictc                 óL   — 	 ddl m}   | ¦   «         pi S # t          $ r i cY S w xY w)Nr   ©Úload_config)Úhermes_cli.configr   Ú	Exceptionr   s    úA/home/ragecks/.hermes/hermes-agent/plugins/platforms/a2a/tools.pyÚ_load_configr   -   sN   € ðØ1Ð1Ð1Ð1Ð1Ð1Øˆ{‰}Œ}Ð" Ð"øÝð ð ð Øˆ	ˆ	ˆ	ðøøøs   ‚ ”#¢#ÚagentÚstrúOptional[dict]c                óî  — |                       d¦  «        s|                       d¦  «        r| i t          g dœS t          ¦   «         }|                     d¦  «        pi }|                     | ¦  «        }|sdS |                     dd¦  «        |                     di ¦  «        pi t	          |                     d	t          ¦  «        ¦  «        |                     d
g ¦  «        pg |                     dd¦  «        dœS )zWResolve a peer name to {url, auth, timeout, capabilities}, or treat ``agent`` as a URL.zhttp://zhttps://)ÚurlÚauthÚtimeoutÚcapabilitiesÚ
a2a_agentsNr   Ú r   r   r   Útenant)r   r   r   r   r!   )Ú
startswithÚ_DEFAULT_TIMEOUTr   ÚgetÚint)r   ÚcfgÚpeersÚentrys       r   Ú_resolve_peerr)   5   s÷   € à×Ò˜	Ñ"Ô"ð [ e×&6Ò&6°zÑ&BÔ&Bð [Ø bÕ5EÐWYÐZÐZÐZÝ
‰.Œ.€CØ�GŠG�LÑ!Ô!Ð' R€EØ�IŠI�eÑÔ€EØð Øˆtà�yŠy˜ Ñ#Ô#Ø—	’	˜& "Ñ%Ô%Ð+¨Ý�u—y’y Õ,<Ñ=Ô=Ñ>Ô>ØŸ	š	 .°"Ñ5Ô5Ð;¸Ø—)’)˜H bÑ)Ô)ðð ð ó    r   c                ó€   — | r;|                       d¦  «        dk    r"|                       d¦  «        rdd| d         › �iS i S )NÚtypeÚbearerÚtokenÚAuthorizationzBearer )r$   )r   s    r   Ú_auth_headerr0   G   sN   € Øð <�—’˜Ñ Ô  HÒ,Ð,°·²¸'Ñ1BÔ1BÐ,ØÐ!:¨4°¬=Ð!:Ð!:Ð;Ð;Ø€Ir*   r   Úheadersr   r%   c                ó.  — t           j                             | |d¬¦  «        }t           j                             ||¬¦  «        5 }t	          j        |                     ¦   «                              d¦  «        ¦  «        cd d d ¦  «         S # 1 swxY w Y   d S )NÚGET)r1   Úmethod©r   úutf-8)ÚurllibÚrequestÚRequestÚurlopenÚjsonÚloadsÚreadÚdecode)r   r1   r   ÚreqÚresps        r   Ú_http_get_jsonrA   Q   s½   € Ý
Œ.×
 Ò
  ¨g¸eÐ
 Ñ
DÔ
D€CÝ	Œ×	Ò	 ¨WÐ	Ñ	5Ô	5ð 7¸ÝŒz˜$Ÿ)š)™+œ+×,Ò,¨WÑ5Ô5Ñ6Ô6ð7ð 7ð 7ð 7ñ 7ô 7ð 7ð 7ð 7ð 7ð 7ð 7øøøð 7ð 7ð 7ð 7ð 7ð 7s   Á9B
Â
BÂBÚbodyc                ó   — t          j        |¦  «                             d¦  «        }dt          j        dœ|¥}t
          j                             | ||d¬¦  «        }t
          j                             ||¬¦  «        5 }t          j	        | 
                    ¦   «                              d¦  «        ¦  «        cd d d ¦  «         S # 1 swxY w Y   d S )Nr6   zapplication/json)zContent-TypezA2A-VersionÚPOST)Údatar1   r4   r5   )r;   ÚdumpsÚencoder
   ÚPROTOCOL_VERSIONr7   r8   r9   r:   r<   r=   r>   )r   rB   r1   r   rE   Úhdrsr?   r@   s           r   Ú_http_post_jsonrJ   W   sò   € ÝŒ:�dÑÔ×"Ò" 7Ñ+Ô+€DØ.½xÔ?XÐdÐdÐ\cÐd€DÝ
Œ.×
 Ò
  ¨4¸ÀfÐ
 Ñ
MÔ
M€CÝ	Œ×	Ò	 ¨WÐ	Ñ	5Ô	5ð 7¸ÝŒz˜$Ÿ)š)™+œ+×,Ò,¨WÑ5Ô5Ñ6Ô6ð7ð 7ð 7ð 7ñ 7ô 7ð 7ð 7ð 7ð 7ð 7ð 7øøøð 7ð 7ð 7ð 7ð 7ð 7s   Á=9CÃCÃ
CÚbase_urlc                ó2   — |                       d¦  «        dz   S )Nú/z/.well-known/agent-card.json©Úrstrip©rK   s    r   Ú	_card_urlrQ   _   s   € ð �?Š?˜3ÑÔÐ"@Ñ@Ð@r*   c                ó2   — |                       d¦  «        dz   S )NrM   z/.well-known/agent.jsonrN   rP   s    r   Ú_legacy_card_urlrS   e   s   € Ø�?Š?˜3ÑÔÐ";Ñ;Ð;r*   c                óÖ   — 	 t          t          | ¦  «        ||¦  «        S # t          j        j        $ r}|j        dk    r‚ Y d }~nd }~ww xY wt          t          | ¦  «        ||¦  «        S )Ni”  )rA   rQ   r7   ÚerrorÚ	HTTPErrorÚcoderS   )rK   r1   r   Úes       r   Ú_fetch_cardrY   i   s}   € ðÝ�i¨Ñ1Ô1°7¸GÑDÔDÐDøÝŒ<Ô!ð ð ð ØŒ6�SŠ=ˆ=Øð ˆ=ˆ=ˆ=ˆ=øøøøðøøøõ Õ*¨8Ñ4Ô4°g¸wÑGÔGÐGs   ‚   A
´AÁA
Úcardc                óô   — t          | t          ¦  «        rb|                      dg ¦  «        pg D ]I}t          |t          ¦  «        r2|                     d¦  «        dk    r|                     d¦  «        r|c S ŒJd S )NÚsupportedInterfacesÚprotocolBindingÚJSONRPCr   ©Ú
isinstancer   r$   )rZ   Úifaces     r   Ú_select_jsonrpc_interfacerb   r   s„   € Ý�$�ÑÔð Ø—X’XÐ3°RÑ8Ô8Ð>¸Bð 	ð 	ˆEÝ˜%¥Ñ&Ô&ð ¨5¯9ª9Ð5FÑ+GÔ+GÈ9Ò+TÐ+TÐY^×YbÒYbÐchÑYiÔYiÐ+TØ���øØˆ4r*   c                ó  — t          |¦  «        }|rt          |d         ¦  «        S t          |t          ¦  «        r8t          |                     d¦  «        t          ¦  «        r|d         r|d         S |                      d¦  «        S )zƒPrefer the card's JSONRPC interface (v1.0 supportedInterfaces), then the
    card's legacy top-level url, then the configured base.r   rM   )rb   r   r`   r   r$   rO   )rK   rZ   ra   s      r   Ú_rpc_urlrd   z   s   € õ & dÑ+Ô+€EØð !Ý�5˜”<Ñ Ô Ð Ý�$�ÑÔð ¥*¨T¯XªX°e©_¬_½cÑ"BÔ"Bð ÀtÈEÄ{ð Ø�EŒ{ÐØ�?Š?˜3ÑÔÐr*   Úpeerc                óÀ   — t          | ¦  «        }|r*|                     d¦  «        rt          |d         ¦  «        S t          |                     d¦  «        pd¦  «        S )Nr!   r    )rb   r$   r   )rZ   re   ra   s      r   Ú_interface_tenantrg   …   s[   € Ý% dÑ+Ô+€EØð $�—’˜8Ñ$Ô$ð $Ý�5˜”?Ñ#Ô#Ð#Ýˆt�xŠx˜Ñ!Ô!Ð' RÑ(Ô(Ð(r*   Ústatec                ó‚   — | r<|                       dd¦  «                              dd¦  «                             ¦   «         ndS )zDTASK_STATE_COMPLETED -> completed (also passes through v0.3 states).ÚTASK_STATE_r    Ú_Ú-)ÚreplaceÚlower)rh   s    r   Ú_short_statero   �   s=   € àINÐVˆ5�=Š=˜¨Ñ+Ô+×3Ò3°C¸Ñ=Ô=×CÒCÑEÔEÐEÐTVÐVr*   Úagent_labelÚmessageÚ
context_idútuple[str, str, str]c           	     ó  — |                      dd¦  «        }t          |                      di ¦  «        pi ¦  «        }t          |                      dt          ¦  «        ¦  «        }d}	 t	          ||t          |d¦  «        ¦  «        }n# t          $ r Y nw xY w|pt          j        ¦   «         }t          j
        |¦  «        }	dt          j        ¦   «         dd	t          j        t          j        |	|¬
¦  «        idœ}
t          ||¦  «        }|r||
d         d<   t          j        d| |
d         |	¦  «         t          j        |d|	|
d         ¦  «         t          j        xj        dz  c_        t'          t)          ||¦  «        |
||¦  «        }d|v r1|d         }t+          d| › d|                      d	|¦  «        › �¦  «        ‚|                      di ¦  «        }t          j        |¦  «        }t/          |¦  «        }|d}}t1          |t2          ¦  «        rA|                      d|¦  «        }|                      d¦  «        pi                       dd¦  «        }t          j        |d||
d         ¦  «         t          j        xj        dz  c_        |||fS )zÐSend one message/send to a peer. Returns (reply_text, context_id, state).

    Raises urllib errors / ValueError for the caller to format. Handles
    outbound redaction, audit, persistence, and metrics.
    r   r    r   r   Né   z2.0ÚSendMessagerq   )rr   )ÚjsonrpcÚidr4   Úparamsry   r!   Úoutboundrx   Úuserr	   rU   zPeer 'z' returned an error: ÚresultÚ	contextIdÚstatusrh   r   )r$   r0   r%   r#   rY   Úminr   r
   Únew_context_idr   Úredact_outboundÚnew_task_idÚtext_messageÚ	ROLE_USERrg   ÚauditÚpersist_messageÚmetricsÚoutbound_totalrJ   rd   Ú
ValueErrorÚunwrap_send_message_responseÚ_reply_text_from_resultr`   r   Úinbound_total)rp   re   rq   rr   rK   r1   r   rZ   ÚctxÚsafe_messageÚrpc_bodyr!   r@   Úerrr|   ÚpayloadÚreplyÚ	reply_ctxrh   s                      r   Ú
_send_taskr”   •   s•  € ð �xŠx˜˜rÑ"Ô"€HÝ˜4Ÿ8š8 F¨BÑ/Ô/Ð5°2Ñ6Ô6€GÝ�$—(’(˜9Õ&6Ñ7Ô7Ñ8Ô8€Gð €DðÝ˜8 W­c°'¸2Ñ.>Ô.>Ñ?Ô?ˆˆøÝð ð ð Øˆðøøøð Ð
1�Ô/Ñ1Ô1€CÝÔ+¨GÑ4Ô4€Lð ÝÔ"Ñ$Ô$Øà•xÔ,­XÔ-?ÀÐZ]Ð^Ñ^Ô^ð
ð	ð €Hõ ˜t TÑ*Ô*€FØð .Ø'-ˆ�Ô˜8Ñ$å„N�:˜{¨H°T¬N¸LÑIÔIÐIÝÔ˜S &¨,¸À¼ÑGÔGÐGÝÔÐ#Ô# qÑ(Ð#Ô#å�8 H¨dÑ3Ô3°X¸wÈÑPÔP€DØ�$€€Ø�7ŒmˆÝÐ] +Ð]Ð]ÀCÇGÂGÈIÐWZÑD[ÔD[Ð]Ð]Ñ^Ô^Ð^à�XŠX�h Ñ#Ô#€FÝÔ3°FÑ;Ô;€GÝ# GÑ,Ô,€EØ˜Bˆu€IÝ�'�4Ñ Ô ð ?Ø—K’K ¨SÑ1Ô1ˆ	Ø—’˜XÑ&Ô&Ð,¨"×1Ò1°'¸2Ñ>Ô>ˆÝÔ˜Y¨°¸À¼ÑGÔGÐGÝÔÐ"Ô" aÑ'Ð"Ô"Ø�)˜UÐ"Ð"s   Á'B Â
BÂBr|   r   c                óŠ  — t          j        | ¦  «        } t          | t          ¦  «        st	          | ¦  «        S |                      dg ¦  «        pg D ]}t          j        |¦  «        }|r|c S Œ|                      di ¦  «        pi }|                     d¦  «        }|rt          j        |¦  «        S t          j        | ¦  «        S )NÚ	artifactsr~   rq   )r
   rŠ   r`   r   r   r$   Úextract_text)r|   ÚartifactÚtxtr~   Úmsgs        r   r‹   r‹   Ë   sË   € ÝÔ2°6Ñ:Ô:€FÝ�f�dÑ#Ô#ð Ý�6‰{Œ{Ðà—J’J˜{¨BÑ/Ô/Ð5°2ð ð ˆÝÔ# HÑ-Ô-ˆØð 	ØˆJˆJˆJð	à�ZŠZ˜ "Ñ%Ô%Ð+¨€FØ
�*Š*�YÑ
Ô
€CØ
ð *ÝÔ$ SÑ)Ô)Ð)åÔ  Ñ(Ô(Ð(r*   Úargsrk   c                ó°  — t          |                      d¦  «        pd¦  «                             ¦   «         }|sdS 	 t          |i t          ¦  «        }nJ# 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|                     d
d¦  «        }|                     dd¦  «        }|                     di ¦  «        pi }|                     dg ¦  «        pg }|                     d¦  «        rdnd}	|                     dg ¦  «        pg }
d 
                    d„ |
D ¦   «         ¦  «        pd|                     dd¦  «        › d�}d|› �d|› �dt          ||¦  «        › �d|› �dt          |                     d¦  «        ¦  «        › dt          |                     d¦  «        ¦  «        › d |	› �d!t          |¦  «        › d"�g}|dd#…         D ]Y}|                     d$|                     d
|                     d%d¦  «        ¦  «        › d&|                     dd¦  «        › �¦  «         ŒZd' 
                    |¦  «        S )(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    â€” Únameú?Údescriptionr   Úskillsr   ÚyesÚnor\   ú, c              3  óž   K  — | ]H}t          |t          ¦  «        ¯|                     d d¦  «        › d|                     dd¦  «        › �V — ŒIdS )r]   rŸ   z vÚprotocolVersionNr_   )Ú.0Úis     r   ú	<genexpr>za2a_discover.<locals>.<genexpr>ò   sq   è è € ð ð à�: a­Ñ.Ô.ðØ�5Š5Ð" CÑ(Ô(ÐKÐK¨A¯EªEÐ2CÀSÑ,IÔ,IÐKÐKðð ð ð ð ð r*   Úvr¦   z (pre-1.0 card)zAgent: zDescription: zURL: z
Protocol: zStreaming: Ú	streamingz  Push: ÚpushNotificationsz  Auth required: zSkills (ú):é   ú  - rx   ú: Ú
)r   r$   ÚstriprY   r#   r7   rU   rV   rW   r   Újoinrd   ÚboolÚlenÚappend)r›   rk   r   rZ   rX   rž   ÚdescÚcapsr¡   r   ÚifacesÚprotoÚlinesÚss                 r   Úa2a_discoverr½   à   sØ  € å
ˆd�hŠh�u‰oŒoÐ# Ñ
$Ô
$×
*Ò
*Ñ
,Ô
,€CØð HØGÐGð8Ý˜3 Õ$4Ñ5Ô5ˆˆøÝŒ<Ô!ð Hð Hð HØG°1´6ÐGÐGÀÐGÐGÐGÐGÐGÐGÐGÐGÐGøøøøÝð 8ð 8ð 8Ø7¨Ð7Ð7°1Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7øøøøð8øøøð �8Š8�F˜CÑ Ô €DØ�8Š8�M 2Ñ&Ô&€DØ�8Š8�N BÑ'Ô'Ð-¨2€DØ�XŠX�h Ñ#Ô#Ð) r€FØ—H’H˜ZÑ(Ô(Ð2ˆ5ˆ5¨d€DØ�XŠXÐ+¨RÑ0Ô0Ð6°B€FØ�IŠIð ð àðñ ô ñ ô ð ?ð 
?ˆT�XŠXÐ'¨Ñ-Ô-Ð	>Ð	>Ð	>ð 
ð
 	�$ÐÐØ˜ÐÐØ%•˜˜dÑ#Ô#Ð%Ð%Ø�UÐÐØw•d˜4Ÿ8š8 KÑ0Ô0Ñ1Ô1ÐwÐw½4ÀÇÂÐI\Ñ@]Ô@]Ñ;^Ô;^ÐwÐwÐquÐwÐwØ"•3�v‘;”;Ð"Ð"Ð"ð€Eð �C�R�CŒ[ð [ð [ˆØ�ŠÐY˜AŸEšE &¨!¯%ª%°°cÑ*:Ô*:Ñ;Ô;ÐYÐY¸q¿uºuÀ]ÐTVÑ?WÔ?WÐYÐYÑZÔZÐZÐZØ�9Š9�UÑÔÐs/   ¼A ÁBÁ'A:Á4BÁ:BÂBÂBÂBc                óv  — t          |                      d¦  «        p+|                      d¦  «        p|                      d¦  «        pd¦  «                             ¦   «         }t          |                      d¦  «        p+|                      d¦  «        p|                      d¦  «        pd¦  «                             ¦   «         }t          |                      d¦  «        p|                      d	¦  «        pd¦  «                             ¦   «         }|r|sd
S t          |¦  «        }|r|                     d¦  «        sd|› d�S 	 t	          ||||¦  «        \  }}}n�# t
          j        j        $ rJ}	|	j        dv rd|› d|	j        › d�cY d}	~	S |	j        dk    rd|› d�cY d}	~	S d|› d|	j        › d�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d|› d|› �}
|r|
dt          |¦  «        › �z  }
|
dz  }
|pd}|t          j        k    r	|d|› d�z  }|
› d |› �S )!zÐSend a task to a peer agent and return its reply.

    ``agent`` is a configured peer name (from ``a2a_agents``) or a direct URL.
    ``context_id`` continues a prior exchange (multi-turn) when provided.
    r   Ú
agent_namerž   r    rq   ÚtextÚtaskrr   r}   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.)i‘  i“  zError: peer 'z' rejected auth (HTTP z). Check the configured token.Ni­  z*' rate limited us (HTTP 429). Retry later.zError: call to 'u   ' failed â€” HTTP r�   u   ' failed â€” Ú[u    Â· context u    Â· Ú]z(no text reply)uS   

(The peer needs more input â€” answer by calling a2a_call again with context_id 'z'.)r±   )r   r$   r²   r)   r”   r7   rU   rV   rW   r‰   r   ro   r
   ÚSTATE_INPUT_REQUIRED)r›   rk   r   rq   rr   re   r’   r“   rh   rX   ÚheaderrB   s               r   Úa2a_callrÆ     s  € õ �—’˜Ñ!Ô!ÐU T§X¢X¨lÑ%;Ô%;ÐU¸t¿xºxÈÑ?OÔ?OÐUÐSUÑVÔV×\Ò\Ñ^Ô^€EÝ�$—(’(˜9Ñ%Ô%ÐS¨¯ª°&Ñ)9Ô)9ÐS¸T¿XºXÀfÑ=MÔ=MÐSÐQSÑTÔT×ZÒZÑ\Ô\€GÝ�T—X’X˜lÑ+Ô+ÐJ¨t¯xªx¸Ñ/DÔ/DÐJÈÑKÔK×QÒQÑSÔS€JØð A˜ð AØ@Ð@å˜ÑÔ€DØð 
�t—x’x ‘”ð 
ð: Uð :ð :ð :ð	
ð
;Ý",¨U°D¸'À:Ñ"NÔ"NÑˆˆy˜%˜%øÝŒ<Ô!ð Eð Eð EØŒ6�ZÐÐØf 5ÐfÐfÀÄÐfÐfÐfÐfÐfÐfÐfÐfÐfØŒ6�SŠ=ˆ=ØT 5ÐTÐTÐTÐTÐTÐTÐTÐTÐTØD %ÐDÐD¸1¼6ÐDÐDÐDÐDÐDÐDÐDÐDÐDøøøøÝð ð ð Ý�1‰vŒvˆˆˆˆˆˆøøøøÝð ;ð ;ð ;Ø: %Ð:Ð:°aÐ:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:øøøøð;øøøð 0�Ð/Ð/ IÐ/Ð/€FØð /ØÐ.� eÑ,Ô,Ð.Ð.Ñ.ˆØ
ˆc�M€FØÐ%Ð%€DØ•Ô-Ò-Ð-Øð/Ø )ð/ð /ð /ñ	
ˆð ÐÐ˜ÐÐÐsZ   Ä?E ÅG0Å*F/Æ G0ÆF/ÆG0ÆF/Æ)G0Æ/G0Æ<GÇ
G0ÇG0ÇG+Ç%G0Ç+G0údict | Nonec                ól  — t          ¦   «         }|                     d¦  «        pi }g }|rÓ|                     dt          |¦  «        › d�¦  «         |                     ¦   «         D ]—\  }}|                     d¦  «        pi                      dd¦  «        }|                     dg ¦  «        }|rdd	                     |¦  «        › �nd
}	|                     d|› d|                     dd¦  «        › d|› d|	› �¦  «         Œ˜n|                     d¦  «         t          j        ¦   «         }
|
r`|                     d
¦  «         |                     dt          |
¦  «        › d�¦  «         |
dd…         D ]}|                     d|› �¦  «         Œt          j         	                    ¦   «         }|                     d
¦  «         |                     d|d         › d|d         › d|d         › d|d         › d|d         › d |d!         › d"|d#         › d$|d%         › d&|d'         › d(�¦  «         d)                     |¦  «        S )*z:List configured A2A peers and any persisted conversations.r   zConfigured peers (r­   r   r,   Únoner   z caps: r¤   r    r¯   r°   r   rŸ   z (auth: ú)z@No peers configured. Add them under 'a2a_agents' in config.yaml.zPersisted conversations (u   ) â€” recall with a2a_history: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   r$   r¶   rµ   Úitemsr³   r
   Úlist_conversationsr‡   Úsnapshot)r›   rk   r&   r'   r»   rž   r(   r   r¸   Úcap_strÚconvosÚcÚms                r   Úa2a_listrÛ   1  s¯  € å
‰.Œ.€CØ�GŠG�LÑ!Ô!Ð' R€EØ€EØð YØ�ŠÐ8­#¨e©*¬*Ð8Ð8Ð8Ñ9Ô9Ð9Ø Ÿ;š;™=œ=ð 	Yð 	Y‰KˆD�%Ø—I’I˜fÑ%Ô%Ð+¨×0Ò0°¸Ñ@Ô@ˆDØ—9’9˜^¨RÑ0Ô0ˆDØ59ÐAÐ1 §	¢	¨$¡¤Ð1Ð1Ð1¸rˆGØ�LŠLÐW ÐWÐW¨¯	ª	°%¸Ñ(=Ô(=ÐWÐWÀtÐWÐWÈgÐWÐWÑXÔXÐXÐXð		Yð 	�ŠÐWÑXÔXÐXåÔ(Ñ*Ô*€FØð %Ø�Š�RÑÔÐØ�ŠÐ\µ°V±´Ð\Ð\Ð\Ñ]Ô]Ð]Ø˜˜˜”ð 	%ð 	%ˆAØ�LŠL˜ ˜˜Ñ$Ô$Ð$Ð$õ 	Ô×!Ò!Ñ#Ô#€AØ	‡L‚L�ÑÔÐØ	‡L‚Lð 0˜Q˜Ô/ð 0ð 0°qÐ9IÔ7Jð 0ð 0ØÐ'Ô(ð0ð 0Ø67¸Ô6Gð0ð 0àÐ'Ô(ð0ð 0à45°k´Nð0ð 0ð Ð*Ô+ð0ð 0ð :;Ð;PÔ9Qð0ð 0ð Ð*Ô+ð	0ð 0ð 0ñ 1ô 1ð 1ð �9Š9�UÑÔÐr*   c           
     óè  — t          |                      d¦  «        p|                      d¦  «        pd¦  «                             ¦   «         }|sdS 	 t          dt	          t          |                      d¦  «        pd¦  «        d¦  «        ¦  «        }n# t          t          f$ r d}Y nw xY wt          j	        ||¬	¦  «        }|sd
|› d�S d|› dt          |¦  «        › d�g}|D ]|}|                     dd¦  «        }|                     d¦  «        pd                     ¦   «         }t          |¦  «        dk    r|dd…         dz   }|                     d|› d|› �¦  «         Œ}d                     |¦  «        S )zàRecall a persisted A2A conversation by context_id.

    This is how prior A2A exchanges survive compaction/restarts: every turn is
    written to ~/.hermes/a2a_conversations/<context>.jsonl and can be reloaded
    here.
    rr   r}   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):ÚrolerŸ   rÀ   iè  Nu    â€¦[truncated]rÂ   z] r±   )r   r$   r²   Úmaxr   r%   r‰   Ú	TypeErrorr
   Úload_conversationrµ   r¶   r³   )	r›   rk   rr   rÝ   Úmessagesr»   rÚ   rá   rÀ   s	            r   Úa2a_historyræ   S  sž  € õ �T—X’X˜lÑ+Ô+ÐJ¨t¯xªx¸Ñ/DÔ/DÐJÈÑKÔK×QÒQÑSÔS€JØð YØXÐXðÝ�A•s�3˜tŸxšx¨Ñ0Ô0Ð6°BÑ7Ô7¸Ñ=Ô=Ñ>Ô>ˆˆøÝ�	Ð"ð ð ð ØˆˆˆðøøøåÔ)¨*¸EÐBÑBÔB€HØð HØG¸ÐGÐGÐGÐGØJ˜ZÐJÐJµ°H±´ÐJÐJÐJÐK€EØð )ð )ˆØ�uŠu�V˜SÑ!Ô!ˆØ—’�f‘”Ð# ×*Ò*Ñ,Ô,ˆÝˆt‰9Œ9�tÒÐØ˜˜˜”;Ð!2Ñ2ˆDØ�ŠÐ'˜Ð'Ð' Ð'Ð'Ñ(Ô(Ð(Ð(Ø�9Š9�UÑÔÐs   ÁA B ÂB(Â'B(Ú
capabilityúlist[tuple[str, dict]]c                óú   — t          ¦   «         }|                     d¦  «        pi }g }|                     ¦   «         D ]>\  }}|                     dg ¦  «        pg }| |v s| dk    r|                     ||f¦  «         Œ?|S )z:Find configured peers that advertise the given capability.r   r   Ú*)r   r$   rÔ   r¶   )rç   r&   r'   Úmatchesrž   r(   r¸   s          r   Ú_match_peers_by_capabilityrì   r  sŠ   € å
‰.Œ.€CØ�GŠG�LÑ!Ô!Ð' R€EØ€GØ—{’{‘}”}ð *ð *‰ˆˆeØ�yŠy˜¨Ñ,Ô,Ð2°ˆØ˜ÐÐ ¨sÒ!2Ð!2Ø�NŠN˜D %˜=Ñ)Ô)Ð)øØ€Nr*   r    r¿   Ú
peer_entryútuple[str, str]c                ó$  — 	 |                      dd¦  «        |                      di ¦  «        pi t          |                      dt          ¦  «        ¦  «        dœ}t          | |||¦  «        \  }}}| |pdfS # t          $ r}| d|› �fcY d}~S d}~ww xY w)	zCCall a single peer synchronously. Returns (agent_name, reply_text).r   r    r   r   )r   r   r   z
(no reply)úError: N)r$   r%   r#   r”   r   )	r¿   rí   rq   rr   re   r’   Ú_ctxÚ_staterX   s	            r   Ú_call_peer_syncró   ~  s¿   € ð	+à—>’> %¨Ñ,Ô,Ø—N’N 6¨2Ñ.Ô.Ð4°"Ý˜:Ÿ>š>¨)Õ5EÑFÔFÑGÔGð
ð 
ˆõ
 )¨°T¸7ÀJÑOÔOÑˆˆt�VØ˜EÐ1 \Ð2Ð2øÝð +ð +ð +Ø˜M a˜M˜MÐ*Ð*Ð*Ð*Ð*Ð*Ð*øøøøð+øøøs   ‚A1A4 Á4
BÁ>B
ÂBÂ
Bc                ó@  ‡‡‡‡— t          |                      d¦  «        pd¦  «                             ¦   «         }t          |                      d¦  «        p|                      d¦  «        pd¦  «                             ¦   «         Št          |                      d¦  «        pd¦  «                             ¦   «                              ¦   «         }t          |                      d¦  «        pd¦  «                             ¦   «         Š‰sdS |sd	S t	          |¦  «        }|sd
|› d�S |dvrd}g Št          t          t          |¦  «        t          ¦  «        ¬¦  «        5 Šˆˆˆfd„|D ¦   «         }t          |¦  «        D ]¥}||         }	 ‰ 
                    |                     ¦   «         ¦  «         |dk    r<‰d         d                              d¦  «        s|D ]}|                     ¦   «          Œ n2Œu# t          $ r$}	‰ 
                    |d|	› �f¦  «         Y d}	~	Œžd}	~	ww xY wddd¦  «         n# 1 swxY w Y   ‰                     d„ ¬¦  «         d„ ‰D ¦   «         }
d'ˆfd„}|dk    r2|
s
 |¦   «         S t!          |
d„ ¬¦  «        }d|d         › d|d         › �S |dk    r|
s
 |¦   «         S |
d         \  }}d |› d|› �S d!|› d"t          |¦  «        › d#�g}‰D ]3\  }}| 
                    d$|› d%�¦  «         | 
                    |¦  «         Œ4d&                     |¦  «        S )(u—  Fan-out a task to multiple peer agents by capability.

    Modes:
      - ``all``: send to all peers matching the capability, return all replies.
      - ``first``: send to all matching peers, return the first successful reply.
      - ``best``: send to all, return the longest successful reply (a coarse
        detail heuristic â€” use ``all`` when you want to judge yourself).

    Configured peers advertise capabilities in config.yaml::

      a2a_agents:
        researcher:
          url: "http://localhost:9991"
          capabilities: [web_search, research]
        coder:
          url: "http://localhost:9992"
          capabilities: [code, debug]
    rç   r    rq   rÁ   ÚmodeÚallrr   zError: 'message' is required.z;Error: 'capability' is required (or use '*' for all peers).z1Error: no configured peers advertise capability 'rà   ©rö   ÚfirstÚbest)Úmax_workersc           	     óT   •— i | ]$\  }}‰                      t          ||‰‰¦  «        |“Œ%S © )Úsubmitró   )r§   rž   r(   rr   rq   Úpools      €€€r   ú
<dictcomp>z#a2a_orchestrate.<locals>.<dictcomp>³  sC   ø€ ð 
ð 
ð 
á��eð �KŠK�¨¨u°g¸zÑJÔJÈDð
ð 
ð 
r*   rø   éÿÿÿÿr	   úError:rð   Nc                ó   — | d         S )Nr   rü   ©Úrs    r   ú<lambda>z!a2a_orchestrate.<locals>.<lambda>Ä  s
   € ˜q œt€ r*   )Úkeyc                óF   — g | ]\  }}|                      d ¦  «        °||f‘ŒS )r  )r"   )r§   rž   r’   s      r   ú
<listcomp>z#a2a_orchestrate.<locals>.<listcomp>Å  s4   € Ð\Ð\Ð\¡; 4¨À×AQÒAQÐRZÑA[ÔA[Ð\�$˜�Ð\Ð\Ð\r*   r   r   c                 óz   •— dg} ‰D ] \  }}|                       d|› d|› �¦  «         Œ!d                     | ¦  «        S )NzAll peers failed:z  r°   r±   )r¶   r³   )r»   rž   r’   Úresultss      €r   Ú_all_failedz$a2a_orchestrate.<locals>._all_failedÇ  sV   ø€ Ø$Ð%ˆØ"ð 	/ð 	/‰KˆD�%Ø�LŠLÐ-˜dÐ-Ð- eÐ-Ð-Ñ.Ô.Ð.Ð.Ø�yŠy˜ÑÔÐr*   rù   c                ó,   — t          | d         ¦  «        S )Nr	   )rµ   r  s    r   r  z!a2a_orchestrate.<locals>.<lambda>Ð  s   € ­C°°!´©I¬I€ r*   z[best: r   z]
z[first: zOrchestrated 'z' to z	 peer(s):z
--- z ---r±   )r   r   )r   r$   r²   rn   rì   r   r   rµ   Ú_ORCHESTRATE_MAX_WORKERSr   r¶   r|   r"   Úcancelr   Úsortrâ   r³   )r›   rk   rç   rõ   rë   ÚfuturesÚfutrž   ÚfrX   Ú	successesr  rù   r’   r»   rr   rq   rþ   r
  s                  @@@@r   Úa2a_orchestrater  Œ  sø  øøøø€ õ& �T—X’X˜lÑ+Ô+Ð1¨rÑ2Ô2×8Ò8Ñ:Ô:€JÝ�$—(’(˜9Ñ%Ô%Ð?¨¯ª°&Ñ)9Ô)9Ð?¸RÑ@Ô@×FÒFÑHÔH€GÝˆt�xŠx˜ÑÔÐ( 5Ñ)Ô)×/Ò/Ñ1Ô1×7Ò7Ñ9Ô9€DÝ�T—X’X˜lÑ+Ô+Ð1¨rÑ2Ô2×8Ò8Ñ:Ô:€Jàð /Ø.Ð.Øð MØLÐLå(¨Ñ4Ô4€GØð RØQÀ:ÐQÐQÐQÐQàÐ+Ð+Ð+Øˆð &(€GÝ	­­C°©L¬LÕ:RÑ(SÔ(SÐ	TÑ	TÔ	Tð 6ÐX\ð
ð 
ð 
ð 
ð 
ð 
à&ð
ñ 
ô 
ˆõ   Ñ(Ô(ð 
	6ð 
	6ˆCØ˜3”<ˆDð6Ø—’˜sŸzšz™|œ|Ñ,Ô,Ð,Ø˜7’?�?¨7°2¬;°q¬>×+DÒ+DÀXÑ+NÔ+N�?à$ð #ð #˜ØŸš™
œ
˜
˜
Ø�EøøÝð 6ð 6ð 6Ø—’  m° m mÐ4Ñ5Ô5Ð5Ð5Ð5Ð5Ð5Ð5øøøøð6øøøð6ð 6ð 6ñ 6ô 6ð 6ð 6ð 6ð 6ð 6ð 6øøøð 6ð 6ð 6ð 6ð$ ‡L‚L�^�^€LÑ$Ô$Ð$Ø\Ð\°'Ð\Ñ\Ô\€Ið ð  ð  ð  ð  ð  ð ˆv‚~€~Øð 	!Ø�;‘=”=Ð Ý�9Ð"5Ð"5Ð6Ñ6Ô6ˆØ.˜˜aœÐ.Ð. T¨!¤WÐ.Ð.Ð.Ø	�ŠˆØð 	!Ø�;‘=”=Ð Ø ”l‰ˆˆeØ*˜$Ð*Ð* 5Ð*Ð*Ð*àJ *ÐJÐJµ3°w±<´<ÐJÐJÐJÐKˆØ"ð 	 ð 	 ‰KˆD�%Ø�LŠLÐ, $Ð,Ð,Ð,Ñ-Ô-Ð-Ø�LŠL˜ÑÔÐÐØ�yŠy˜ÑÔÐs=   Å*H-ÆA'G0Ç-H-Ç0
HÇ:HÈH-ÈHÈH-È-H1È4H1Ú_FunctionSchema)rž   r    Ú
parametersF)ÚtotalÚ_ToolSchema)r,   Úfunctionr  r½   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.ÚobjectÚstringz<Base URL of the remote A2A agent, e.g. http://localhost:9999)r,   r    )r,   Ú
propertiesÚrequiredrÆ   zã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   rq   rr   rÛ   zJList configured A2A peer agents, persisted A2A conversations, and metrics.)r,   r  ræ   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).)rr   rÝ   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÷   z)How to aggregate results. Default: 'all'.)r,   Úenumr    z*Optional: shared context id for all peers.)rç   rq   rõ   rr   )r½   rÆ   rÛ   ræ   r  zdict[str, _ToolSchema]Ú_SCHEMASÚNonec           	     ó¨   — t                                ¦   «         D ]7\  }}|                      |d|t          |         |d         d         d¬¦  «         Œ8dS )z1Register the client tools in the ``a2a`` toolset.Úa2ar  r    u   ðŸ§©)rž   ÚtoolsetÚschemaÚhandlerr    ÚemojiN)r   rÔ   Úregister_toolÚ	_HANDLERS)r�   rž   r%  s      r   Úregister_toolsr*  I  sk   € å ŸšÑ(Ô(ð 
ð 
‰ˆˆfØ×ÒØØØÝ˜d”OØ˜zÔ*¨=Ô9Øð 	ñ 	
ô 	
ð 	
ð 	
ð
ð 
r*   )r   r   )r   r   r   r   )r   r   r   r   )r   r   r1   r   r   r%   r   r   )
r   r   rB   r   r1   r   r   r%   r   r   )rK   r   r   r   )rK   r   r1   r   r   r%   r   r   )rZ   r   r   r   )rK   r   rZ   r   r   r   )rZ   r   re   r   r   r   )rh   r   r   r   )
rp   r   re   r   rq   r   rr   r   r   rs   )r|   r   r   r   )r›   r   rk   r   r   r   )N)r›   rÇ   rk   r   r   r   )rç   r   r   rè   )r    )
r¿   r   rí   r   rq   r   rr   r   r   rî   )r   r!  )4Ú__doc__Ú
__future__r   r;   ÚloggingÚurllib.errorr7   Úurllib.requestÚconcurrent.futuresr   r   Útypingr   r   r   r    r
   r   Ú	getLoggerÚ__name__Úloggerr#   r  r   r)   r0   rA   rJ   rQ   rS   rY   rb   rd   rg   ro   r”   r‹   r½   rÆ   rÛ   ræ   rì   ró   r  r   r   r  r  r   Ú__annotations__r)  r*  rü   r*   r   ú<module>r6     s  ððð ð ð. #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø Ð Ð Ð Ø Ð Ð Ð Ø ?Ð ?Ð ?Ð ?Ð ?Ð ?Ð ?Ð ?Ø +Ð +Ð +Ð +Ð +Ð +Ð +Ð +Ð +Ð +à  Ð  Ð  Ð  Ð  Ð  Ð  Ð  à	ˆÔ	˜8Ñ	$Ô	$€àÐ ØÐ ðð ð ð ðð ð ð ð$ð ð ð ð7ð 7ð 7ð 7ð7ð 7ð 7ð 7ðAð Að Að Að<ð <ð <ð <ðHð Hð Hð Hðð ð ð ð ð  ð  ð  ð)ð )ð )ð )ðWð Wð Wð Wð
3#ð 3#ð 3#ð 3#ðl)ð )ð )ð )ð* ð  ð  ð  ðF+ð +ð +ð +ð\ð ð ð ð ðDð ð ð ð>	ð 	ð 	ð 	ð+ð +ð +ð +ð +ðP ð P ð P ð P ðn �)Ð-¸ÈCÐ_cÐdgÐilÐdlÔ_mÐ/nÐ/nÐv{Ð|Ñ|Ô|€Øˆi˜°ÀÐ'QÐ'QÐY^Ð_Ñ_Ô_€ð à"ðIð
 !à HÐ={Ð|Ð|ðð #˜Gðð ð
ð 
ðð ð& àð;ð !à&.ð  @Bð  Cð  CØ(0ÐA|Ð}Ð}Ø+3ð  EMð  #Nð  #Nðð ð
 % iÐ0ðð ð
ð 
ðð ð, àØgØ#+¸2Ð>Ð>ð
ð 
ðð ð à!ð)ð
 !à+3ÐDoÐ"pÐ"pØ&/Ð@oÐpÐpðð ð *˜Nðð ð
ð 
ðð ð( à%ð%ð !à+3ð  EJð  #Kð  #KØ(0ÐAjÐkÐkØ%-Ð7OÐ7OÐ7Oð  aLð  Mð  MØ+3ÐDpÐ"qÐ"qð	ð ð *¨9Ð5ð	ð 	ð
ð 
ðð ðGY$ð Y$€ð Yð Yð Yñ Yðx !ØØØØ&ðð €	ð

ð 

ð 

ð 

ð 

ð 

r*   