
    epj                       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	Z	ddl
Z
ddlZddlZddlZddlmZ ddlmZ ddlmZ ddlmZmZ ddlmZmZmZ dd	lmZmZmZm Z m!Z! dd
l"m#Z# ddl$m%Z%m&Z&  ej'        e(          Z)dZ*dZ+dZ,dZ-dZ.d-dZ/d.dZ0d/dZ1d0dZ2d.dZ3d1dZ4d2d3d#Z5d4d&Z6 G d' d(e          Z7 G d) d*e          Z8 G d+ d,e          Z9dS )5uX  
A2A inbound platform adapter — exposes Hermes as an A2A-discoverable agent.

Design (the #11025 insight, done as a plugin with zero core edits):
  - Runs a stdlib http.server in a daemon thread (no a2a-sdk, no asyncio loop
    dependency at register() time — avoids the a2a_fleet "register outside a
    loop" bug class).
  - Serves the A2A v1.0 Agent Card at GET /.well-known/agent-card.json (and legacy agent.json).
  - JSON-RPC at POST /: message/send, message/stream (SSE), tasks/get,
    tasks/list, tasks/cancel, tasks/subscribe, tasks/pushNotificationConfig/create,
    tasks/pushNotificationConfig/get, tasks/pushNotificationConfig/list,
    tasks/pushNotificationConfig/delete.
  - Push notifications: config accepted inline in message/send
    (configuration.taskPushNotificationConfig) or via the create method;
    payloads are v1.0 StreamResponse objects, HMAC-signed.
  - Metrics at GET /metrics.
  - Each inbound task is filtered + framed (security.wrap_inbound) and routed
    into the agent's LIVE gateway session via the normal MessageEvent path, so
    the agent that replies is the same one talking to its user — full memory
    and context, not a throwaway clone.
  - The agent's reply comes back through ``adapter.send()``; we override that to
    fulfil a per-task Future the HTTP handler is blocked on, turning the
    async gateway into a synchronous request/response for the A2A caller.
    ``on_processing_complete`` resolves failures/cancellations promptly.
  - Every exchange is persisted to disk and audit-logged.

Bind safety: with no token configured, the server binds 127.0.0.1 only.
    )annotationsN)deque)Future)TimeoutError)BaseHTTPRequestHandlerThreadingHTTPServer)AnyDictOptional)BasePlatformAdapterMessageEventMessageTypeProcessingOutcome
SendResult)Platform   )protocolsecurityi&  ,  <   i      returnfloatc            	         	 t          dt          t          j        dd                              S # t          t
          f$ r Y dS w xY w)z8Seconds to wait for the agent to answer an inbound task.g      ?A2A_REPLY_TIMEOUT300g     r@)maxr   osgetenv
ValueError	TypeError     C/home/thesage/.hermes/hermes-agent/plugins/platforms/a2a/adapter.py_reply_timeoutr%   E   sS    3bi(;UCCDDEEE	"   uus   /2 AAstrc                     t          j        dd                                          } | r| S 	 dd l}d|                                 S # t
          $ r Y dS w xY w)NA2A_AGENT_NAME r   zhermes-zhermes-agent)r   r   stripsocketgethostname	Exception)namer+   s     r$   _default_agent_namer/   M   sw    9%r**0022D /++--///   ~~s   A 
AAvaluec                    t          | pd                                                              d          }|dv rdn|                    d          d         S )z=Return a URL-safe-ish single-segment slug for a served agent.r)   /)r)   defaultrootr   )r&   r*   split)r0   slugs     r$   _clean_slugr7   X   sQ    u{!!##))#..D00022djjooa6HHr#   baseprefixc                    | pd                                 pd} |                     d          s| dz  } |pd                     d          }|s| S t          j                            | |dz             S )Nr)   r2   )r*   endswithurllibparseurljoin)r8   r9   s     r$   	_join_urlr?   ^   sy    JB&3D== l!!#&&F <fsl333r#   c                 v    	 ddl m}   |             pdS # t          $ r t          j        dd          pdcY S w xY w)Nr   get_active_profile_namer3   HERMES_PROFILE)hermes_cli.profilesrB   r-   r   r   rA   s    r$   _active_profile_namerE   h   sk    C??????&&((5I5 C C Cy)955BBBBCs    !88profileOptional[str]c                   	 ddl m} t           ||                     S # t          $ r_ | r| dk    r2	 ddlm} t           |                      cY S # t          $ r Y Y d S w xY wt          j                            d|            cY S w xY w)Nr   )get_profile_dirr3   )get_hermes_homez~/.hermes/profiles/)	rD   rI   r&   r-   hermes_cli.configrJ   r   path
expanduser)rF   rI   rJ   s      r$   _profile_homerN   p   s    
C777777??7++,,, C C C 	'Y..======??,,-----   tttw!!"A"A"ABBBBBCs2     B	AB	
A!B	 A!!%B	B	`   max_lenintc                    t          j        ddt          | pd                                        d          }|pdd|         S )zFSanitize attacker-provided context ids before using in session titles.z[^A-Za-z0-9_.-]+-r)   z-._ctxN)resubr&   r*   )r0   rP   r6   s      r$   _safe_context_slugrW   }   sC    6%sC,<,<==CCEJJDME8G8$$r#   methodtuple[str, bool]c                    i ddddddddd	d
dddddddddddddddddddddddd d!d"d#d$d%d&}|                     | d'          S )(u   Return (canonical_operation, is_v1_method).

    Canonical operation names are lowercase internal labels. v1 methods use the
    PascalCase names from A2A v1.0 §5.3/§9.4; legacy aliases remain accepted.
    SendMessage)sendTzmessage/send)r\   FSendStreamingMessage)streamTzmessage/stream)r^   FGetTask)getTz	tasks/get)r`   F	ListTasks)listTz
tasks/list)rb   F
CancelTask)cancelTztasks/cancel)rd   FSubscribeToTask)	subscribeTztasks/subscribe)rf   F CreateTaskPushNotificationConfig)push_createTz#tasks/pushNotificationConfig/create)rh   Fz tasks/pushNotificationConfig/setztasks/pushNotification/setGetTaskPushNotificationConfig)push_getT)rj   F)	push_listT)rk   F)push_deleteT)rl   F)z tasks/pushNotificationConfig/getListTaskPushNotificationConfigsz!tasks/pushNotificationConfig/list DeleteTaskPushNotificationConfigz#tasks/pushNotificationConfig/delete)r)   Fr`   )rX   mappings     r$   _method_inforq      s   ~ 	 0 	+	
 	= 	^ 	^ 	o 	& 	) 	. 	/ 	+,A 	./E 	+,B  	%&<!" 	();#$ -@+>-A,A/E-  G0 ;;v{+++r#   c                  (     e Zd ZdZdZd fdZ xZS )
_A2AServerz<ThreadingHTTPServer that carries a reference to its adapter.Tadapter'A2AAdapter'c                Z    t                                          ||           || _        d S N)super__init__rt   )selfaddrhandler_clsrt   	__class__s       r$   ry   z_A2AServer.__init__   s(    {+++r#   )rt   ru   )__name__
__module____qualname____doc__daemon_threadsry   __classcell__r}   s   @r$   rs   rs      sH        FFN         r#   rs   c                  L    e Zd ZdZedd            Zd Zdd
ZddZd Z	d Z
dS )A2ARequestHandlerzHTTP handler for the A2A JSON-RPC surface.

    Module-level (not a closure) so request routing is unit-testable; all
    state lives on ``self.server.adapter``.
    r   ru   c                    | j         j        S rw   )serverrt   rz   s    r$   rt   zA2ARequestHandler.adapter   s    {""r#   c                0    t          j        d|z   g|R   d S )Nz
A2A http: )loggerdebug)rz   formatargss      r$   log_messagezA2ARequestHandler.log_message   s%    \F*2T222222r#   coderQ   payloaddictc                f   t          j        |                              d          }|                     |           |                     dd           |                     dt          t          |                               |                                  | j        	                    |           d S )Nutf-8Content-Typeapplication/jsonContent-Length)
jsondumpsencodesend_responsesend_headerr&   lenend_headerswfilewrite)rz   r   r   bodys       r$   _jsonzA2ARequestHandler._json   s    z'""))'224   );<<<)3s4yy>>:::
r#   r&   c                   t          j        dd                                          }|r|S | j                            dd          p| j                            dd          }|sdS |                    d          d                                         }| j                            dd          pd                    d          d                                         }| d	| d
S )a+  Derive the routable URL for this request.

        Priority: A2A_PUBLIC_URL env > X-Forwarded-Host / Host header (with
        scheme from X-Forwarded-Proto) > empty. Empty means "caller has no
        info, fall back to bind host". See gfdsa's k8s bind-host bug report
        (PR #41711).
        A2A_PUBLIC_URLr)   zX-Forwarded-HostHost,r   zX-Forwarded-Protohttpz://r2   )r   r   r*   headersr`   r5   )rz   explicithostschemes       r$   _request_public_urlz%A2ARequestHandler._request_public_url   s     9-r2288:: 	O| 2B77W4<;K;KFTV;W;W 	2zz#q!'')),""#6;;EvLLSQQRSTZZ\\$$T$$$$r#   c                X   | j                             | j                  }|d         }|d                             d          pd}|dv rH|                                 pd }|                     d| j                             ||                     d S |dv rd|                    d	          p| j         j        d
}t          j
                    sBt          j        | j                            d          | j        r| j        d         nd          	 2| j                             |                                 pd           |d<   |                     d|           d S |dk    r4|                     dt          j                                                   d S |                     dddi           d S )Nagentsubpathr2   )z/.well-known/agent.jsonz/.well-known/agent-card.json   r   )r2   z/healthokr.   )statusr   Authorizationr   r)   )
public_urlserved_agentsz/metricsi  errorz	not found)rt   _route_for_pathrL   rstripr   r   _build_cardr`   
agent_namer   localhost_onlyauthenticater   client_address_served_agent_summaryr   metricssnapshot)rz   router   r   r   r   s         r$   do_GETzA2ARequestHandler.do_GET   s   ,,TY77g	"))#..5#QQQ1133;tJJJsDL44Zu4MMNNNF&&&6**Edl.E G &(( CH,A  11*.*=E#A&&2- - - ,0<+M+M#7799AT ,N ,C ,C(JJsG$$$Fj  JJsH,5577888F

3+./////r#   c           
     Z   | j         }| j        r| j        d         nd}t          j        | j                            d          |          }|6|                     dt          j        d t          j	        d                     d S 	 t          | j                            dd                    }|t          k    r6|                     dt          j        d t          j        d                     d S |r| j                            |          nd	}t          j        |                    d
                    }nE# t$          $ r8 |                     dt          j        d t          j        d                     Y d S w xY wt'          |t(                    s6|                     dt          j        d t          j        d                     d S |                    d          }t-          |                    dd                    }|                    di           }	|	i }	t'          |	t(                    s6|                     dt          j        |t          j        d                     d S | j                            d          pd                                }
|
r=|
dvr9|                     dt          j        |t          j        d|
                      d S t1          |          \  }}|                    | j        |	          }|                    d          r<|                     dt          j        |t          j        |d                              d S |d         }|j                            |          sPt          j        xj        dz  c_        |                     dt          j        |t          j        d                     d S t          j         |          s:|                     dt          j        |t          j!        d| d                     d S |s9|                     dt          j        |t          j"        d|                      d S |dk    r0|                     d|#                    ||	|||                      d S |d!k    r|$                    | ||	||"           d S |d#k    r.|                     d|%                    ||	|"                     d S |d$k    r.|                     d|&                    ||	|"                     d S |d%k    r.|                     d|'                    ||	|"                     d S |d&k    r|(                    | ||	|"           d S |d'k    r.|                     d|)                    ||	|"                     d S |d(k    r.|                     d|*                    ||	|"                     d S |d)k    r.|                     d|+                    ||	|"                     d S |d*k    r.|                     d|,                    ||	|"                     d S d S )+Nr   r)   r   i  unauthorizedr   i  zpayload too larges   {}r   i  zparse errorz"JSON-RPC request must be an objectidrX   paramsr   zparams must be an objectzA2A-Version>   1.01.0.0zunsupported A2A-Version: r   r   r   i  zrate limit exceededi  zpeer 'z' not trustedzmethod not found: r\   )r   v1_responser^   r   r`   rb   rd   rf   rh   rj   rk   rl   )-rt   r   r   r   r   r`   r   r   jsonrpc_errorERR_UNAUTHORIZEDrQ   	_MAX_BODY	ERR_PARSErfilereadr   loadsdecoder-   
isinstancer   ERR_INVALID_PARAMSr&   r*   rq   _route_for_requestrL   _rate_limiterallowr   rate_limit_triggersERR_RATE_LIMITEDis_trusted_peerERR_UNTRUSTED_PEERERR_METHOD_NOT_FOUND_rpc_message_send_rpc_message_stream_rpc_tasks_get_rpc_tasks_list_rpc_tasks_cancel_rpc_tasks_subscribe_rpc_push_config_create_rpc_push_config_get_rpc_push_config_list_rpc_push_config_delete)rz   rt   	client_ipidentitylengthrawreqreq_idrX   r   version	operationis_v1r   r   s                  r$   do_POSTzA2ARequestHandler.do_POST   s9   ,.2.AID'**r	 ()9)9/)J)JIVVJJsH249RTbccdddF		))*:A>>??F	!!

3 6tX=OQd e efff-3>$*//&)))C*SZZ0011CC 	 	 	JJsH249K][[\\\FF	 #t$$ 	JJsH249TVz{{|||FSWWXr**++2&&>F&$'' 	JJsH268;VXrsstttF<##M228b??AA 	w&666JJsH268;VX}t{X}X}~~F'//	5**49f==99W 	JJsH268;VX]^eXfgghhhFg$**844 	00A500JJsH268;TVkllmmmF'11 	JJsH235Uh5U5U5UW W X X XF 	JJsH257TF7T7TV V W W WFJJsG55ffhV[in5oopppF  ''ffhe'TTTFJJsG22662OOPPPFJJsG33FF%3PPQQQF  JJsG55ffE5RRSSSF##((vvU(KKKF%%JJsG;;FFRW;XXYYYF
""JJsG88u8UUVVVF##JJsG99&&PU9VVWWWF%%JJsG;;FFRW;XXYYYF &%s   A'D3 -AD3 3>E54E5N)r   ru   )r   rQ   r   r   r   r&   )r~   r   r   r   propertyrt   r   r   r   r   r   r"   r#   r$   r   r      s          # # # X#3 3 3   % % % %$0 0 08[ [ [ [ [r#   r   c                      e Zd ZdZ fdZedad            Zedbd            ZdbdZdcd
Z	dcdZ
dddZdedZdfdgdZdhdZdidZdjdkdZdfdldZdmd!Zdnd"Zdod%Zdpd&Zdqd(Zdrd,Zdfdsd/Zdtd1Zdud3Zdvd6Zdwd8Zdxd:Zdyd=Zdfdzd>Zd{d|dCZ e!dcdD            Z"e!d}dF            Z#	 dfd~dGZ$dfddHZ%dfddIZ&dfddJZ'dfddKZ(dfddLZ)dfddMZ*dfddNZ+dfddOZ,dfddPZ-dfddQZ.ddRZ/	 	 djddXZ0dd]Z1dfdd^Z2dd`Z3 xZ4S )
A2AAdapterzInbound A2A server adapter.c                
   t          d          }t                                          ||           t          |di           pi }t	          t          j        d          p|                    dt                              | _	        t          j                    | _        t                      | _        d t          |                    d          pg           p't          j        dd	                              d
          D             | _        t%                      | _        |                     |          | _        d | _        d | _        d | _        t3          j                    | _        t3          j                    | _        t3          j                    | _        i | _         i | _!        tE          j#                    | _$        i | _%        i | _&        tE          j#                    | _'        tE          j(                    | _)        d | _*        d S )Na2a)configplatformextraA2A_PORTportc                x    g | ]7}t          |                                          #|                                8S r"   )r&   r*   .0ts     r$   
<listcomp>z'A2AAdapter.__init__.<locals>.<listcomp>]  sF     %
 %
 %
 Q	%
GGII%
 %
 %
r#   advertised_toolsetsA2A_ADVERTISED_TOOLSETSr)   r   )+r   rx   ry   getattrrQ   r   r   r`   _DEFAULT_PORTr   r   resolve_bind_hostr   r/   r   rb   r5   _advertised_toolsetsrE   _active_profile_load_served_agents_agents_httpd_server_thread_loopr   	TaskStoretasksTurnTracker_turnsRateLimiterr   _profile_sessions_profile_session_locks	threadingLock_profile_session_locks_guard_pending_pending_order_pending_lockEvent_watchdog_stop_watchdog_thread)rz   r   kwargsr   r   r}   s        r$   ry   zA2AAdapter.__init__U  s   E??:::,,2	*--Q6=1Q1QRR	.00	-//%
 %
UYY455;<< G96;;AA#FF%
 %
 %
!  455//66,0:>:>
 '))
*,,%133 CERT#,5N,<,<) 8:57&^-- (o//<@r#   r   r&   c                    dS )NA2Ar"   r   s    r$   r.   zA2AAdapter.name  s    ur#   boolc                    dS )u  A2A authenticates every inbound request via bearer token (or
        localhost-only binding) in ``do_POST`` before dispatch — the identity
        is already authorized upstream. Without this override, the gateway's
        per-platform user allow-list (``{PLATFORM}_ALLOWED_USERS``) rejects
        A2A peers because their identity is a token-derived name or pod IP,
        not a platform account the operator configures in an env allow-list.

        This is authorization delegated to the A2A bearer-token transport,
        not a fail-open: every request is 401'd if the credential is wrong.
        Reported by kuangmi-bit (PR #41711 comment, Jun 27).
        Tr"   r   s    r$   authorization_is_upstreamz$A2AAdapter.authorization_is_upstream  s	     tr#   c           
     l  K   	 t          j                    | _        n# t          $ r
 d | _        Y nw xY w	 t	          | j        | j        ft          |           | _        nZ# t          $ rM}t                              d| j        | j        |           |                     dd| d           Y d }~dS d }~ww xY wt          j        | j        j        dd          | _        | j                                         | j                                         t          j        | j        d	d          | _        | j                                         |                                  t/          j                    rd
nd}t                              d| j        | j        || j        t7          | j                             dS )Nu    A2A: could not bind %s:%s — %sbind_failedzA2A bind failed: T)	retryableFza2a-http)targetr.   daemonza2a-watchdogzlocalhost-onlyzREMOTE (bearer auth)zQA2A: serving Agent Card + JSON-RPC on http://%s:%s (%s) as %r; %d routed agent(s))asyncioget_running_loopr  RuntimeErrorrs   r   r   r   r
  OSErrorr   r   _set_fatal_errorr  Threadserve_foreverr  startr  clear_watchdog_loopr  _mark_connectedr   r   infor   r   r	  )rz   _kwargseexposures       r$   connectzA2AAdapter.connect  s     	 133DJJ 	 	 	DJJJ		$di%;=NPTUUDKK 	 	 	LL;TY	STUUU!!-1HQ1H1HTX!YYY55555	
 (.;,
 
 

 	!!### 	!!### ) 0&!
 !
 !

 	##%%%'/'>'@'@\##F\_Ity(DOS=N=N	
 	
 	
 ts$    11'A 
B4'AB//B4Nonec                T  K   |                                   | j                                         | j        K	 | j                                         | j                                         n# t          $ r Y nw xY wd | _        | j        5  | j        	                                D ]:\  }}|
                                s!|                    t          j        df           ;| j                                         | j                                         d d d            d S # 1 swxY w Y   d S )Nz[agent shutting down])_mark_disconnectedr  setr
  shutdownserver_closer-   r  r  valuesdone
set_resultr   STATE_FAILEDr0  r  )rz   _ctxfuts      r$   
disconnectzA2AAdapter.disconnect  sr     !!!!!!;"$$&&&((****   DK 	( 	(!]1133 U U	cxxzz UNNH$9;R#STTTM!!!%%'''	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	(s$   2A+ +
A87A8	BDD!$D!c                   | j                             t                    s	 | j                            t
                    D ]=}t                              d|t
                     t          j	        xj
        dz  c_
        >n,# t          $ r t                              dd           Y nw xY w| j                             t                    dS dS )zCBackground thread that fails orphaned tasks (keeps them queryable).z1A2A: orphaned task %s marked failed (timeout %ds)r   zA2A: watchdog errorTexc_infoN)r  wait_WATCHDOG_INTERVALr  fail_orphans_ORPHAN_TIMEOUTr   warningr   r   tasks_failedr-   r   )rz   tids     r$   r1  zA2AAdapter._watchdog_loop  s    %**+=>> 	CC:22?CC 7 7CNN#VX[]lmmm$11Q61117  C C C2TBBBBBC %**+=>> 	C 	C 	C 	C 	Cs   AA? ?&B('B(r   c                ~    	 ddl m}  |            pi }t          |t                    r|ni S # t          $ r i cY S w xY w)Nr   )load_config)rK   rP  r   r   r-   )rz   rP  cfgs      r$   _load_global_a2a_configz"A2AAdapter._load_global_a2a_config  sf    	555555+--%2C$S$//733R7 	 	 	III	s   *- <<r   dict[str, dict]c                R   |                     d          p|                     d          }|S|                                 }|                     d          p)|                     d          pi                      d          }i }t          j        dd          }ddd| j        d	| j        || j        d
|d<   h d}i }t          |t                    r|	                                n't          |t                    rt          |pg           ng }|D ]\  }	}
t          |
t                    st          t          |
                     d          p|
                     d          p|	                    }|set          t          |
                     d          p|                    }|r||v rt                              d||           t          |
                     d          p|                                          }d|z   }|
                     d          p+|
                     d          p|
                     d          pg }t          |t                    rd |                    d          D             }t%          |
                     d                    p|dd| j        fv }t          |
                     d          p|                                          }|r.||v r%t                              d||||                    |||<   ||||p||t          |
                     d          pd|           t          |
                     d          pd|p| d          t          |pg           t'          |
                     d           pt)                                d!	||<   |S )"a  Load served-agent routing config.

        Preferred config location is ``platforms.a2a.extra.agents``. A top-level
        ``a2a_served_agents`` fallback is accepted for scripts/tests. Root/default
        always maps to the live gateway session for backward compatibility.
        agentsr   Na2a_served_agentsr   A2A_AGENT_DESCRIPTION<   Hermes Agent — a general-purpose agent reachable over A2A.r)   T)r6   rL   tenantrF   localr.   descriptionr  >   .well-knownhealthr   r6   r   rL   z;A2A: ignoring served agent %r with reserved/invalid path %rrF   r2   r  toolsetscapabilitiesc                ^    g | ]*}|                                 |                                 +S r"   )r*   r   s     r$   r   z2A2AAdapter._load_served_agents.<locals>.<listcomp>  s-    PPP!aggiiPAGGIIPPPr#   r   rZ  r3   rY  zIA2A: ignoring served agent %r with duplicate tenant %r already used by %rr.   zHermes r[  zHermes profile 'z' exposed over A2A.timeout)	r6   rL   rY  rF   rZ  r.   r[  r  ra  )r`   rR  r   r   r  r   r  r   r   itemsrb   	enumerater7   r&   r   rL  r*   r5   r   rQ   r%   )rz   r   r   rQ  rU  default_descreservedtenantsrb  keyvalr6   path_segmentrF   rL   r^  rZ  rY  s                     r$   r  zA2AAdapter._load_served_agents  s    ii!!?UYY%?%?;..00C''-..]3775>>3GR2L2L_2]2]C"$y#J
 

 +O'#'#<	
 	
r
 877"$)#t44o		R\]`bfRgRg:o)CI2:N:N:Nmo #	 #	HCc4(( s3776??#Jcggdmm#JsKKLLD &s3776??+Bd'C'CDDL <8#;#;\^bdpqqq#''),,455;;==G%Dww455m9L9LmPSPWPWXfPgPgmkmH(C(( QPPx~~c/B/BPPP))**^g"iI]9^.^E**2d3399;;F 'W$$NNcfgfo   "& "?dCGGFOO?/?/?/?@@"377=#9#9#t=tPWP_[_=t=t=tuu'+HN';';swwy11E^5E5EFF
 
F4LL r#   Nr   rG   
list[dict]c                    |pd                                 pd| j         d| j         dfd| j                                        D             S )Nr)   http://:r2   c                ,   g | ]}|d          pd|                     d          t          |                     dd                    |                     d          pd|                     d          t          |                     d                    d	S )
r6   r3   r.   rL   r)   rY  NrF   rZ  )r6   r.   urlrY  rF   rZ  )r`   r?   r   )r   ar8   s     r$   r   z4A2AAdapter._served_agent_summary.<locals>.<listcomp>1  s     

 

 

  &	.Yf quuVR'8'899%%//1T55++aeeGnn-- 

 

 

r#   )r*   r   r   r	  r>  )rz   r   r8   s     @r$   r   z A2AAdapter._served_agent_summary/  sq     b''))O-Oty-O-O49-O-O-O

 

 

 

 \((**

 

 

 
	
r#   raw_pathc                   t           j                            |pd          j        pd}t	          | j                                        d d          D ]t}|                    dd          pd}|rX||k    s|                    |dz             r:|t          |          d          pd}|                    d          sd|z   }||dc S u| j        d         |dS )Nr2   c                H    t          |                     dd                    S )NrL   r)   )r   r`   )rp  s    r$   <lambda>z,A2AAdapter._route_for_path.<locals>.<lambda>@  s    QUU6SUEVEVAWAW r#   T)rg  reverserL   r)   r   r   )
r<   r=   urlsplitrL   sortedr	  r>  r`   
startswithr   )rz   rq  rL   r   r9   r   s         r$   r   zA2AAdapter._route_for_path=  s    |$$X_55:AcDL//117W7Waefff 	< 	<EYYvr**0bF <46>>T__Vc\-J-J>s6{{||,3))#.. ,!GmG!&7;;;;;b)d;;;r#   r   c                   |                      |          }|d         }t          |pi                     d          pd          |                    d          dk    rBr@fd| j                                        D             }|r|d         |d         d}|d         }t          |                    d          pd          }r'|r%|k    rd	d
d|                    d          pd iS |S )Nr   rY  r)   r6   c                F    g | ]}|                     d           k    |S )rY  ro   )r   rp  rY  s     r$   r   z1A2AAdapter._route_for_request.<locals>.<listcomp>O  s-    UUUQ155??f;T;Tq;T;T;Tr#   r   r   rv  r   ztenant z does not match routed agent r3   )r   r&   r`   r	  r>  )rz   rq  r   r   r   matchesexpectedrY  s          @r$   r   zA2AAdapter._route_for_requestI  s   $$X..gfl''117R8899V""v"UUUU$,"5"5"7"7UUUG #")!*y9IJJ
uyy**0b11 	ph 	p6X#5#5nvnneiiX^N_N_Nlclnnoor#   r   Optional[dict]c                    |p| j         d         }|pd                                pd| j         d| j         d}t	          ||                    dd                    }t          j        |                    d          p| j        ||                    d          pd| 	                    |          t          |                    d	d
                    d
t          j                     t          |                    d          pd                    S )Nr)   rl  rm  r2   rL   r.   r[  rX  rZ  TrY  )r.   ro  r[  skills	streamingpush_notificationsauth_requiredrY  )r	  r*   r   r   r?   r`   r   build_agent_cardr   _advertised_skillsr   r   r   r&   )rz   r   r   r8   ro  s        r$   r   zA2AAdapter._build_cardX  s    )b) b''))O-Oty-O-O49-O-O-Oeii3344(6""5do		-00r4r**511599Wd3344#&5777uyy**0b11	
 	
 	
 		
r#   c                   	 ddl m                                 }|r|pi                     d          n| j        }t          |pg           pdfd|D             }|rt          j        |          S n,# t          $ r t          
                    dd           Y nw xY w|r|pi                     d          n| j        }t          j        |pg           S )	a6  Dynamic Agent Card skills from the live tool registry.

        The card reflects what the agent can actually do right now. An
        explicit ``advertised_toolsets`` config (or A2A_ADVERTISED_TOOLSETS)
        restricts what we advertise; without a registry we fall back to that
        static list.
        r   )registryr  Nc                H    i | ]}|v |                     |          S rw   )get_tool_names_for_toolset)r   nallowedtool_registrys     r$   
<dictcomp>z1A2AAdapter._advertised_skills.<locals>.<dictcomp>w  s>       ?a7ll =;;A>>&2llr#   z-A2A: tool registry unavailable for Agent CardTrF  )tools.registryr  get_registered_toolset_namesr`   r  r;  r   skills_from_toolsetsr-   r   r   )rz   r   names
configuredrp   r  r  s        @@r$   r  zA2AAdapter._advertised_skillsj  s/   	Y@@@@@@!>>@@EEJi%+2**+@AAAPTPiJ**++3tG      G
  >4W===> 	Y 	Y 	YLLHSWLXXXXX	YAFeekr&&'<===DLe
,Z-=2>>>s   A1A7 7&B B task_id
context_idr   c                    t                      }| j        5  ||f| j        |<   | j                            |t                                                    |           d d d            n# 1 swxY w Y   |S rw   )r   r  r  r  
setdefaultr   append)rz   r  r  rC  s       r$   _add_pendingzA2AAdapter._add_pending  s    hh 	P 	P&0#%6DM'"**:uww??FFwOOO	P 	P 	P 	P 	P 	P 	P 	P 	P 	P 	P 	P 	P 	P 	P 
s   AA))A-0A-c                X   | j         5  | j                            |d           }|rl| j                            |d                   }|rJ	 |                    |           n# t          $ r Y nw xY w|s!| j                            |d         d            d d d            d S # 1 swxY w Y   d S )Nr   )r  r  popr  r`   remover    )rz   r  entryorders       r$   _pop_pendingzA2AAdapter._pop_pending  s&    
	@ 
	@M%%gt44E @+//a99 @W----%     @+//a$???
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@ 
	@s6   A B	AB
A,)B+A,,&BB#&B#statetextc                   | j         5  | j                            |          }|rE|d                                         s+|d                             ||f           	 d d d            dS d d d            n# 1 swxY w Y   dS )Nr   TF)r  r  r`   r?  r@  )rz   r  r  r  r  s        r$   _resolve_taskzA2AAdapter._resolve_task  s     	 	M%%g..E U1X]]__ a##UDM222		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	
 us   AA66A:=A:c                D   | j         5  | j                            |d          D ]c}| j                            |          }|rE|d                                         s+|d                             ||f            d d d            dS d	 d d d            n# 1 swxY w Y   dS )Nr"   r   TF)r  r  r`   r  r?  r@  )rz   r  r  r  r  r  s         r$   _resolve_oldest_for_contextz&A2AAdapter._resolve_oldest_for_context  s    	  	 .22:rBB    ))'22  q  !H''666	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  us   A2BBBBtuple[str, str]c                    |p| j         d         }t          |                    d          pd          t          |                    d          pd          fS )Nr)   r6   rY  )r	  r&   r`   )rz   r   s     r$   _scope_for_agentzA2AAdapter._scope_for_agent  sP    )b)599V$$*++S81D1D1J-K-KKKr#   rg  tuple[str, str, str]threading.Lockc                    | j         5  | j                            |          }|t          j                    }|| j        |<   |cd d d            S # 1 swxY w Y   d S rw   )r  r  r`   r  r  )rz   rg  locks      r$   _forward_lockzA2AAdapter._forward_lock  s    . 	 	.22377D| ~''37+C0	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   ;AAApeer%tuple[Optional[dict], Optional[dict]]c                
   |p| j         d         }t          j        |          }t          j        |          pt          j                    }t          j                    }| j                            |          }|t          j                    k    rt          j	        xj
        dz  c_
        t                              d||t          j                                | j        j        |||g|                     |          R  }| j                            |t          j        d           t          j        ||t          j        d| dt          j                     d|d                   d	fS |sy | j        j        |||g|                     |          R  }| j                            |t          j        d           t          j        ||t          j        d
|d                   d	fS t'          j        ||          }	t'          j        d|||           t          j        |d||           t          j	        xj        dz  c_         | j        j        |||g|                     |          R  }|                     |||           |                    dd          s|                     ||||	          \  }
}| j                            |||
           t          j        |d|
|           t'          j        d|||
           |t          j        k    r5t          j	        xj        dz  c_        t          j	        xj        dz  c_        nt          j	        xj        dz  c_        |                     |||
|           t          j        ||||
|d                   d	fS | j         | j!        k| j                            |t          j"        d           t          j	        xj        dz  c_        t          j        ||t          j"        d|d                   d	fS | #                    ||          }tI          |	tJ          j&        | '                    |d| d||          |          }	 tQ          j)        | *                    |          | j                    n# tV          $ r}| ,                    |           t'          j-        d|           }| j                            |t          j"        |           t          j	        xj        dz  c_        t          j        ||t          j"        ||d                   d	fcY d	}~S d	}~ww xY w| j        .                    |t          j/                   d	|||||d         ta          j0                    dfS )a  Validate, register, and dispatch an inbound message.

        Returns (terminal_task, None) when the task ends immediately
        (rejected / not ready), else (None, pending) where pending carries
        the future the caller must wait on. Runs on an HTTP worker thread.
        r)   r   z6A2A: anti-loop triggered for context %s (turn %d > %d)zAnti-loop protection: context z
 exceeded z? turns. Start a new context or increase A2A_MAX_PINGPONG_TURNS.created_iso
created_atNu   Empty task — nothing to do.inbounduserr   rZ  Tr   outboundz,Agent gateway not ready to accept A2A tasks.a2a:dm)chat_id	chat_name	chat_typeuser_id	user_name)r  message_typesource
message_idzDispatch failed: )r  r  r  futurer  started)1r	  r   extract_textextract_context_idnew_context_idnew_task_idr  trackmax_pingpong_turnsr   anti_loop_triggersr   rL  r  creater  completeSTATE_REJECTED
build_taskr   wrap_inboundauditpersist_messageinbound_total_register_inline_pushr`   _forward_to_profileSTATE_COMPLETEDoutbound_totaltasks_completedrM  _send_push_notificationr  _message_handlerrA  r  r   r   TEXTbuild_sourcer(  run_coroutine_threadsafehandle_messager-   r  redact_outbound	set_stateSTATE_WORKINGtime)rz   r   r  r   r  r  r  turnrecframedreplyr  rC  eventr5  msgs                   r$   _prepare_taskzA2AAdapter._prepare_task  s    )b)$V,,088UH<S<U<U
&(( {  ,,(-//////14//NNS%tX-H-J-JL L L#$*#GZ]@U@UV[@\@\]]]CJ)@"EEE&X%<4 4 4.004 4 4 }-      	#$*#GZ]@U@UV[@\@\]]]CJ)@"EEE&X%</C<N    
 &tT22y$666 VT7CCC&&!+&&djTYD<Q<QRW<X<XYYY""7F%"@@@yy$'' 	o33E4VTTLE5J666$Z%IIIN:tWe<<<000 //14// 00A5000 --2--((*eUKKK&w
E5UXYfUghhhjnnn:!6!>J)>CCC))Q.))&X%:>}-   	  44$)$$"'-- %   
 
 

	,T-@-@-G-GTTTT 	 	 	g&&&*+Bq+B+BCCCJ)>DDD))Q.))&X%:C}-         	 	
Wh&<===$}-y{{
 
 
 	
s   -R	 	
T4BT/)T4/T4rF   c                h    t          |          }|sd S t          j                            |d          S )Nzstate.db)rN   r   rL   join)rz   rF   homes      r$   _profile_state_dbzA2AAdapter._profile_state_db  s2    W%% 	4w||D*---r#   titlec                   |                      |          }|rt          j                            |          sdS 	 t	          j        |d          }|                    d|f                                          }|                                 |rt          |d                   ndS # t          $ r  t                              dd           Y dS w xY w)	Nr)   r   ra  zHSELECT id FROM sessions WHERE title = ? ORDER BY started_at DESC LIMIT 1r   z'A2A: could not lookup forwarded sessionTrF  r  r   rL   existssqlite3r7  executefetchonecloser&   r-   r   r   )rz   rF   r  dbconrows         r$   _lookup_forward_sessionz"A2AAdapter._lookup_forward_session%  s    ##G,, 	++ 	2
	/"a000C++Z  hjj  IIKKK"%-3s1v;;;2- 	 	 	LLBTLRRR22	s   A+B& &&CCstarted_afterr   c                   |                      |          }|rt          j                            |          sdS 	 t	          j        |d          }|                    d|dz
  f                                          }|                                 |rt          |d                   ndS # t          $ r  t                              dd	           Y dS w xY w)
Nr)   r   r  zaSELECT id FROM sessions WHERE source = 'a2a' AND started_at >= ? ORDER BY started_at DESC LIMIT 1g       @r   z,A2A: could not find latest forwarded sessionTrF  r  )rz   rF   r  r  r  r  s         r$   _latest_a2a_sessionzA2AAdapter._latest_a2a_session5  s    ##G,, 	++ 	2
	/"a000C++s$&  hjj  IIKKK"%-3s1v;;;2- 	 	 	LLGRVLWWW22	s   A.B) )&CC
session_idc                   |                      |          }|r!t          j                            |          r|sd S 	 t	          j        |d          }|                    d||f           |                                 |                                 d S # t          $ r  t                              dd           Y d S w xY w)Nr   r  z*UPDATE sessions SET title = ? WHERE id = ?z&A2A: could not title forwarded sessionTrF  )r  r   rL   r  r  r7  r  commitr  r-   r   r   )rz   rF   r  r  r  r  s         r$   _title_forward_sessionz!A2AAdapter._title_forward_sessionE  s    ##G,, 	++ 	: 	F	R/"a000CKKDujFYZZZJJLLLIIKKKKK 	R 	R 	RLLADLQQQQQQ	Rs   AB &B>=B>framed_textc           
        t          |                    d          p|                    d          pd                                          }t          |                    d          p|pd          }t          |          }d| d| }|pd||f}	t	          |                    d          pt                                }
|                     |	          }|5  | j                            |	          p|                     ||          }d	d
d|dddg}|r|	                    d|g           t          j                                        }t          |          }|r||d<   ||d<   t          j                    }	 t          j        |dd|
|dt          j                  }np# t          j        $ r dt&          j        fcY cddd           S t*          $ r9}t-          j        d|           t&          j        fcY d}~cddd           S d}~ww xY w|j        dk    r^|j        p|j        p	d|j                                         }t-          j        |dd                   t&          j        fcddd           S |s9|                     ||          }|r!|| j        |	<   |                     |||           t-          j        |j        pd                                          t&          j        fcddd           S # 1 swxY w Y   dS )a  Forward a routed A2A task to another local Hermes profile.

        First contact creates a normal ``source=a2a`` CLI session, records its
        session id, and titles it deterministically. Later turns resume by the
        concrete session id, not by a non-existent name. The public CLI boundary
        is preserved while giving A2A contexts stable multi-turn continuity.
        rF   r6   r)   r   za2a-rS   r3   ra  hermeschatz-qz-Qz--sourcer   z--resumeHERMES_HOMEHERMES_A2A_PEERTF)capture_outputr  ra  envcheckstdinz[profile did not reply in time]NzProfile dispatch failed: r   zprofile exited i0)r&   r`   r*   rW   rQ   r%   r  r  r  extendr   environcopyrN   r  
subprocessrunDEVNULLTimeoutExpiredr   rA  r-   r   r  
returncodestderrstdoutr  r  r  )rz   r   r  r  r  rF   r6   safe_ctxsession_titlerg  ra  r  r  cmdr  r  r/  procr5  r  s                       r$   r  zA2AAdapter._forward_to_profileQ  s    eii	**Eeii.?.?E2FFLLNN599V$$::7;;%j110t00h00#)T84eii	**>n.>.>??!!#&& 	c 	c/33C88pD<X<XY`bo<p<pJVT;j%PC 5

J
3444*//##C ))D *%)M"%)C!"IKKEh!~45
0B   , P P P8(:OOOO%	c 	c 	c 	c 	c 	c 	c 	c&  h h h/0OA0O0OPPRZRggggggg)	c 	c 	c 	c 	c 	c 	c 	c&h!##{XdkX5Xt5X5X__aa/EFF<<h>SS/	c 	c 	c 	c 	c 	c 	c 	c0  T!55guEE
 T2<D*3///]SSS+T[->B,E,E,G,GHH(Jbb;	c 	c 	c 	c 	c 	c 	c 	c 	c 	c 	c 	c 	c 	c 	c 	c 	c 	csW   BK67%FK6H
:K6	H
"H3H
4K6H

AK66A3K66K:=K:pendingr  c                   |d         }|d         }|d         }|                      |           t          j        |pd          }|t          j        k    r|                                }|                                                    t          j                  r?t          j	        }|t          t          j                  d                                         }t          j        |d||           t          j        d|||           |t          j        t          j	        fv rnt          j        xj        dz  c_        t          j        xj        dz  c_        t          j                            t%          j                    |d	         z
             nt          j        xj        dz  c_        | j                            |||           |                     ||||           ||fS )
zuRecord the outcome of a dispatched task. Returns (state, reply) after
        redaction and input-required detection.r  r  r  r)   Nr   r  r   r  )r  r   r  r   r  lstripupperry  INPUT_REQUIRED_MARKERSTATE_INPUT_REQUIREDr   r*   r  r  r   r  r  record_latencyr  rM  r  r  r  )rz   r  r  r  r  r  r  strippeds           r$   _finalize_taskzA2AAdapter._finalize_task  s    )$\*
v'"""("55 H,,,||~~H~~**8+IJJ O 5 X%C!D!D!E!EFLLNN WeWEEEz4%888X-x/LMMM++q0++,,1,,++DIKK'):L,LMMMM))Q.))
GUE222$$Wj%GGGe|r#   c                   |d         }|d         t                      z   }	 	 |                    |rt          n#t          d|t	          j                    z
                      S # t
          $ rX t	          j                    |k    rt          j        dfcY S |r,	  |             n # t          $ r t          j        dfcY cY S w xY wY nt          $ r t          j        dfcY S w xY w)a	  Block until the task's future resolves (or times out).

        ``keepalive`` is an optional zero-arg callable invoked every
        _SSE_KEEPALIVE seconds while waiting (used by the SSE paths); if it
        raises, the client is gone and we stop waiting.
        r  r  Tg        r  z[agent did not reply in time]z[client disconnected])	r%   result_SSE_KEEPALIVEr   r  FuturesTimeoutr   rA  r-   )rz   r  	keepaliverC  deadlines        r$   _await_replyzA2AAdapter._await_reply  s3    h'9%(8(88	PPzzI*k..3sT\_c_h_j_jTjKkKkzlll! P P P9;;(**$13RSSSS PP!	$ P P P ( 57NOOOOOOP P P P -/NOOOOP	PsB   A A# #/CC
B"!C"B?:C>B??CCCFr   r	   r   c                   |                      |||          \  }}|-|rt          j        |          n|}t          j        ||          S |                     |          \  }	}
|                     ||	|
          \  }	}
t          j        |d         |d         |	|
|d                   }|rt          j        |          n|}t          j        ||          S )Nr   r  r  r  r  )r  r   send_message_responsejsonrpc_resultr&  r  r  )rz   r   r   r  r   r   terminalr  r!  r  r  tasks               r$   r   zA2AAdapter._rpc_message_send  s     ..vt5.II'ALZX3H===RZF*66:::((11u**7E5AAu"I 5ue}-
 
 
 :EN/555$&vv666r#   c                    |                      d           |                     dd           |                     dd           |                                  d| _        d S )Nr   r   ztext/event-streamzCache-Controlzno-cacheT)r   r   r   close_connection)handlers    r$   _sse_headerszA2AAdapter._sse_headers  se    c"""N,?@@@OZ888 $(   r#   chunkc                    | j                             |                    d                     | j                                          d S )Nr   )r   r   r   flush)r.  r0  s     r$   
_sse_writezA2AAdapter._sse_write  s>    ELL11222r#   c                   |r|t           j        k    r{|                     |t          j        t          j        |||          |                     |                     |t          j        t          j        |||          |                     n>|                     |t          j        t          j        ||||          |                     |                     |t          j                               dS )u   Emit the final artifact/status events and close the stream (v1.0:
        closure signals terminal state, no ``final`` field).

        ``req_id`` is threaded into JSON-RPC-wrapped SSE frames per §9.4.N)r   r  r3  sse_dataartifact_updatestatus_updatesse_done)rz   r.  r  r  r  r  r   s          r$   _emit_terminalzA2AAdapter._emit_terminal  s     	TUh666OOGX%6(*eDDf&N &N O O OOOGX%6&w
EBBF&L &L M M M M OOGX%6&w
E5II6&S &S T T T!2!4!455555r#   c                     t           j        xj        dz  c_                                        	                      |||          \  }}|q                     |d         |d         |d         d         t          j        |                    di                               di           pi           |	           dS |d
         |d         }	}                     t          j	        t          j
        t          j        ||	t           j        |d                             |                                          t          j	        t          j        ||	t           j                  |                                          | fd          \  }
}                     ||
|          \  }
}                     ||	|
||	           dS # t"          t$          f$ r t&                              d           Y dS w xY w)ul   Handle message/stream as an SSE response of JSON-RPC-wrapped
        StreamResponse events (A2A v1.0 §9.4).r   r   Nr   	contextIdr   r  messager   r  r  r  r  c                 0                          d          S )N: keepalive

)r3  )r.  rz   s   r$   rt  z0A2AAdapter._rpc_message_stream.<locals>.<lambda>  s    4??7DU+V+V r#   )r$  zA2A: stream client disconnected)r   r   streams_startedr/  r  r9  r  r`   r3  r5  stream_taskr  STATE_SUBMITTEDr7  r  r&  r  BrokenPipeErrorConnectionResetErrorr   r   )rz   r.  r   r   r  r   r*  r  r  r  r  r  s   ``          r$   r   zA2AAdapter._rpc_message_stream  s;    	((A-(('"""	< $ 2 264u 2 M MHg###Xd^Xk-BX&w/)(,,x*D*D*H*HTV*W*W*][]^^!	 $    "))"4gl6KZGOOGX%6x7K#GZ9Q^efs^tuuu8w 8w& &    OOGX%6&w
H<RSSU[&] &] ^ ^ ^  ,,#V#V#V#V#V - X XLE5..wuEELE5*eUSYZZZZZ!56 	< 	< 	<LL:;;;;;;	<s   BG DG +G=<G=c           	        t          |                    d          p|                    d          pd          } | j        j        |g|                     |          R  }|s9|                    dt          j        |t
          j        d|                      dS |                     |           	  | j        j	        |g|                     |          R  }|)| 
                    |t          j                               dS t          j                    t                      z   }	 	 |                    t                    \  }	}
n^# t           $ rP t          j                    |k    r |d	         |                    d
d          }
}	Y n| 
                    |d           Y nw xY w~|                     |||d         |	|
|           dS # t$          t&          f$ r t(                              d           Y dS w xY w)z>Reconnect to an existing task's stream (v1.0 SubscribeToTask).taskIdr   r)   r   task not found: NTr  r  r  r?  r  r=  z"A2A: subscribe client disconnected)r&   r`   r  r  r   r   r   ERR_TASK_NOT_FOUNDr/  watchr3  r8  r  r%   r!  r"  r#  r9  rC  rD  r   r   )rz   r.  r   r   r   r  r  rC  r%  r  r  s              r$   r   zA2AAdapter._rpc_tasks_subscribe  s)   fjj**Dfjj.>.>D"EEdjnWDt'<'<U'C'CDDD 	MM#x535Q5Q5Q S  S T T TF'"""	?"$*"7JT-B-B5-I-IJJJC{):)<)<===y{{^%5%55H@@#&::n:#E#ELE5% @ @ @y{{h..'*7|SWWWb5I5IuOOG->?????	@	@ #l2CUEZ`aaaaa!56 	? 	? 	?LL=>>>>>>	?sI   1AG #G &E G ?FG FG F%G +G54G5c                   t          |                    d          p|                    d          pd          } | j        j        |g|                     |          R  }|s#t	          j        |t          j        d|           S |                    d          }	 |t          |          nd }n# t          t          f$ r d }Y nw xY wt	          j
        |t          j                            ||                    S )NrF  r   r)   rG  historyLength)history_length)r&   r`   r  r  r   r   rH  rQ   r!   r    r)  r  to_task)rz   r   r   r   r  r  history_lens          r$   r   zA2AAdapter._rpc_tasks_get$  s   fjj**Dfjj.>.>D"EEdjnWDt'<'<U'C'CDDD 	S)35Q5Q5QS S Sjj11	.9.E#k***4KK:& 	 	 	KKK	&vx/A/I/I#^i/I/j/jkkks   B/ /CCc                  	
 	 t          |                    d          pd          }n# t          t          f$ r d}Y nw xY w	 t          |                    d          pd          }n# t          t          f$ r d}Y nw xY w| j                            t          |                    d          pd          t          |                    d          p|                    d          pd          |t          d|          |                     |          d         |                     |          d	         d
          \  }}}t          |                    dd                    
|                    d          		 	t          	          nd 	n# t          t          f$ r d 	Y nw xY wt          j        |	
fd|D             |rt          |          ndt          d	t          |d                    |d          S )N	pageTokenr   pageSize2   r;  r)   r   r  r   T)r  r  	page_sizeoffset
agent_slugrY  
with_totalincludeArtifactsFrK  c                T    g | ]$}t           j                            |           %S ))rL  include_artifacts)r   r  rM  )r   rrN  rY  s     r$   r   z.A2AAdapter._rpc_tasks_list.<locals>.<listcomp>J  sE      D  D  Dyzh(00;bs0tt  D  D  Dr#   d   )r  nextPageTokenrQ  	totalSize)rQ   r`   r    r!   r  rb   r&   r   r  r   r   r)  min)rz   r   r   r   rT  rS  recsnext_offsettotalrN  rY  s            @@r$   r   zA2AAdapter._rpc_tasks_list1  sE   	K005A66FFI& 	 	 	FFF		FJJz228b99III& 	 	 	III	#':??6::k228b99fjj**Gfjj.A.AGRHHq&>>,,U33A6((//2 $3 $
 $
 k5 !,>!F!FGGjj11	.9.E#k***4KK:& 	 	 	KKK	&v D  D  D  D  D  C  D  D  D1<DS---"As9c2233	0
 0
   	s0   $) ??$A( (A>=A>8F F"!F"c           	        t          |                    d          p|                    d          pd          } | j        j        |g|                     |          R  }|s#t	          j        |t          j        d|           S |d         t          j        v r,t	          j        |t          j        d| d|d                    S | j        	                    |t          j
        d           | j                            |d                    |                     |t          j
        d            | j        j        |g|                     |          R  p|}t	          j        |t          j                            |                    S )	NrF  r   r)   rG  r  ztask z	 already r  )r&   r`   r  r  r   r   rH  TERMINAL_STATESERR_TASK_NOT_CANCELABLEr  STATE_CANCELEDr  resetr  r)  r  rM  )rz   r   r   r   r  r  s         r$   r   zA2AAdapter._rpc_tasks_cancelP  s{   fjj**Dfjj.>.>D"EEdjnWDt'<'<U'C'CDDD 	S)35Q5Q5QS S Sw<8333)8888#g,88: : : 	
GX%<bAAA#l+,,,7H$;R@@@djnWDt'<'<U'C'CDDDK&vx/A/I/I#/N/NOOOr#   c                ~   |                     d          pi                      d          pi }t          |t                    sdS |                     d          p+|                     d          pi                      d          pd}|r6 | j        j        |t          |          g|                     |          R   dS dS )zFv1.0: message/send can carry configuration.taskPushNotificationConfig.configurationtaskPushNotificationConfigNro  pushNotificationConfigr)   )r`   r   r   r  set_push_configr&   r  )rz   r  r   r   rQ  ro  s         r$   r  z A2AAdapter._register_inline_pushb  s    zz/**0b556RSSYWY#t$$ 	FggennZ)A!B!B!Hb M Me T TZXZ 	Y&DJ&wCX4;P;PQV;W;WXXXXXX	Y 	Yr#   c                   t          |                    d          pd          }|                    d          p|                    d          pi }t          |pi                     d          pd          }|r|s t          j        |t          j        d          S  | j        j        ||g|                     |          R  }|#t          j        |t          j        d|           S t          j	        ||          S )NrF  r)   rj  r   ro  z.taskId and pushNotificationConfig.url requiredrG  )
r&   r`   r   r   r   r  rk  r  rH  r)  )rz   r   r   r   r  rQ  ro  storeds           r$   r   z"A2AAdapter._rpc_push_config_createk  s   fjj**0b11jj122Pfjj6J6JPb39"//%((.B// 	Bc 	B)3@B B B ,+GSX4;P;PQV;W;WXXX>)35Q5Q5QS S S&vv666r#   c                   t          |                    d          pd          }t          |                    d          p|                    d          pd          }|s t          j        |t          j        d          S  | j        j        ||g|                     |          R  }|#t          j        |t          j        d|           S t          j	        ||          S )uD   GetTaskPushNotificationConfig — retrieve a push config by task id.rF  r)   r   configIdtaskId requiredN push config not found for task: )
r&   r`   r   r   r   r  get_push_configr  rH  r)  )rz   r   r   r   r  	config_idrQ  s          r$   r   zA2AAdapter._rpc_push_config_gety  s    fjj**0b11

4((HFJJz,B,BHbII	 	H)35FH H H(dj()[d>S>STY>Z>Z[[[;)3<7<<> > > &vs333r#   c                
   t          |                    d          pd          }|s t          j        |t          j        d          S  | j        j        |g|                     |          R  }t          j        ||dd          S )uA   ListTaskPushNotificationConfigs — list push configs for a task.rF  r)   rp  )configsr\  )	r&   r`   r   r   r   r  list_push_configsr  r)  )rz   r   r   r   r  ru  s         r$   r   z A2AAdapter._rpc_push_config_list  s    fjj**0b11 	H)35FH H H.$*.wV9N9Nu9U9UVVV&v7UW/X/XYYYr#   c                   t          |                    d          pd          }t          |                    d          p|                    d          pd          }|s t          j        |t          j        d          S  | j        j        ||g|                     |          R  }|s#t          j        |t          j        d|           S t          j	        |ddi          S )	u:   DeleteTaskPushNotificationConfig — remove a push config.rF  r)   r   ro  rp  rq  deletedT)
r&   r`   r   r   r   r  delete_push_configr  rH  r)  )rz   r   r   r   r  rs  rx  s          r$   r   z"A2AAdapter._rpc_push_config_delete  s    fjj**0b11

4((HFJJz,B,BHbII	 	H)35FH H H/$*/bTEZEZ[`EaEabbb 	>)3<7<<> > > &v	4/@AAAr#   c                   | j                             |          }|sdS t          j        |          s8t                              d||           t          j        xj        dz  c_        dS t          j	        ||||pddd                   }t          j
        |          }ddi}|r||d<   	 t          j        |                              d	          }	t          j                            ||	|d
          }
t          j                            |
d          5 }d|j        cxk    rdk     r9n n6t          j        xj        dz  c_        t                              d|           n;t          j        xj        dz  c_        t                              d||j                   ddd           dS # 1 swxY w Y   dS # t*          $ rA}t          j        xj        dz  c_        t                              d||           Y d}~dS d}~ww xY w)u:  POST a v1.0 StreamResponse payload to the task's registered callback.

        Validates the callback URL to prevent SSRF — blocks internal/private
        addresses (169.254.x.x metadata, loopback, RFC1918 private ranges)
        unless we're in localhost-only mode (where internal access is expected).
        NuF   A2A: push notification for task %s blocked — unsafe callback URL: %sr   r)   i  r   r   zX-A2A-Signaturer   POST)datar   rX   
   r  r   r   z'A2A: push notification sent for task %sz.A2A: push notification for task %s got HTTP %dz-A2A: push notification for task %s failed: %s)r  pop_push_urlr   is_safe_callback_urlr   rL  r   r   push_failedr7  sign_push_payloadr   r   r   r<   requestRequesturlopenr   	push_sentr   r-   )rz   r  r  r  r  callback_urlr   	signaturer   r|  r   respr5  s                r$   r  z"A2AAdapter._send_push_notification  s    z..w77 	F,\:: 	NNc"L2 2 2((A-((F (*eekrSXTXSXEYZZ.w77	!#56 	3)2G%&	X:g&&--g66D.((D'Z`(aaC''R'88 kD$++++++++++$..!3..LL!JGTTTT$00A500NN#SU\^b^ijjjk k k k k k k k k k k k k k k k k k  	X 	X 	X((A-((NNJGUVWWWWWWWWW	Xs>   ,A+F8 BF+F8 +F//F8 2F/3F8 8
H6G>>Hr  contentreply_tometadataOptional[Dict[str, Any]]c                  K   t          t          t          j                    dz                      }|pi                     d          s,t                              d|           t          d|          S |                     |t          j	        |pd          st                              d|           t          d|          S )u{  Fulfil the pending reply Future for this context.

        ``chat_id`` is the A2A context id we set as the source chat_id; the
        oldest outstanding task for that context receives the reply (the
        gateway session processes messages in order).

        The gateway marks final user-visible replies with ``metadata['notify']``
        (see ``_mark_notify_metadata`` in gateway.platforms.base — this is the
        base adapter's documented reply marker, not an incidental field).
        Progress, status, and editable preview sends intentionally lack the
        marker; those must not satisfy the JSON-RPC caller.
        i  notifyz+A2A: ignoring non-final send for context %sT)successr  r)   z0A2A: send() for context %s had no pending waiter)
r&   rQ   r  r`   r   r   r   r  r   r  )rz   r  r  r  r  r  s         r$   r\   zA2AAdapter.send  s      & TY[[4/0011
B##H-- 	CLLFPPPdzBBBB//9QSZS`^`aa 	VLLKWUUU$:>>>>r#   r  r   outcomer   c                `  K   t          t          |dd          pd          }|sdS |t          j        k    r#|                     |t
          j        d           dS |t          j        k    r#|                     |t
          j        d           dS |                     |t
          j	        d           dS )a  Resolve the task future when processing ends without a reply send.

        The success path resolves via send(); this hook catches failures,
        cancellations, and empty runs so the HTTP thread returns promptly
        instead of waiting out the reply timeout.
        r  r)   Nz[agent processing failed])
r&   r  r   FAILUREr  r   rA  	CANCELLEDre  r  )rz   r  r  r  s       r$   on_processing_completez!A2AAdapter.on_processing_complete  s       ge\266<"== 	F'///w(=?Z[[[[[)333w(?DDDDDw(@"EEEEEr#   c                
   K   d S rw   r"   )rz   r  r  s      r$   send_typingzA2AAdapter.send_typing  s      tr#   Dict[str, Any]c                   K   d| ddS )Nr  r  )r.   typer"   )rz   r  s     r$   get_chat_infozA2AAdapter.get_chat_info  s      (w(($777r#   r   )r   r   )r   r8  )r   r   )r   r   r   rS  rw   )r   rG   r   rj  )rq  r&   r   r   )rq  r&   r   r   r   r   )NN)r   rG   r   r~  r   r   )r   r~  r   rj  )r  r&   r  r&   r   r   )r  r&   r   r8  )r  r&   r  r&   r  r&   r   r   )r  r&   r  r&   r  r&   r   r   )r   r~  r   r  )rg  r  r   r  )r   r   r  r&   r   r~  r   r  rF   r&   r   rG   )rF   r&   r  r&   r   r&   )rF   r&   r  r   r   r&   )rF   r&   r  r&   r  r&   r   r8  )
r   r   r  r&   r  r&   r  r&   r   r  )r  r   r  r&   r  r&   r   r  )r  r   r   r  )NF)r   r	   r   r   r  r&   r   r~  r   r   r   r   )r0  r&   r   r8  )r  r&   r  r&   r  r&   r  r&   r   r	   r   r8  )
r   r	   r   r   r  r&   r   r~  r   r8  )r   r	   r   r   r   r~  r   r8  )r   r	   r   r   r   r~  r   r   )r  r&   r   r   r   r~  r   r8  )
r  r&   r  r&   r  r&   r  r&   r   r8  )r  r&   r  r&   r  rG   r  r  )r  r   r  r   r   r8  )r  r&   r   r8  )r  r&   r   r  )5r~   r   r   r   ry   r   r.   r"  r7  rD  r1  rR  r  r   r   r   r   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r&  r   staticmethodr/  r3  r9  r   r   r   r   r   r  r   r   r   r   r  r\   r  r  r  r   r   s   @r$   r   r   R  s       %%+A +A +A +A +AZ    X    X ) ) ) )V( ( ( ((C C C C   C C C CJ
 
 
 
 

< 
< 
< 
<   
 
 
 
 
$? ? ? ? ?6   @ @ @ @      L L L L   e
 e
 e
 e
 e
N. . . .        
R 
R 
R 
R-c -c -c -c^   @P P P P P.7 7 7 7 7  ( ( ( \(    \
 &*6 6 6 6 6 < < < < <>? ? ? ? ?>l l l l l    >P P P P P$Y Y Y Y Y7 7 7 7 74 4 4 4 4Z Z Z Z ZB B B B B%X %X %X %XZ #'-1? ? ? ? ?8F F F F"    8 8 8 8 8 8 8 8r#   r   )r   r   r   )r0   r&   r   r&   )r8   r&   r9   r&   r   r&   r  )rO   )r0   r&   rP   rQ   r   r&   )rX   r&   r   rY   ):r   
__future__r   r(  r   loggingr   rU   r  r  r  r  urllib.parser<   urllib.requestcollectionsr   concurrent.futuresr   r   r#  http.serverr   r   typingr	   r
   r   gateway.platforms.baser   r   r   r   r   gateway.configr   r)   r   r   	getLoggerr~   r   r  rK  rI  r   r"  r%   r/   r7   r?   rE   rN   rW   rq   rs   r   r   r"   r#   r$   <module>r     s   : # " " " " "    				 				                         % % % % % % = = = = = = C C C C C C C C & & & & & & & & & &              $ # # # # #                		8	$	$ 	      I I I I4 4 4 4C C C CC C C C% % % % %, , , ,B    $   ` ` ` ` `. ` ` `Hf8 f8 f8 f8 f8$ f8 f8 f8 f8 f8r#   