
    `gjy                    &   U d Z ddlmZ ddlZddlmZ ddlmZ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ZddlmZmZmZmZmZ 	 ddlmZ dZddlZdd
lm Z! ejD                  jG                  d e$ e!e%      jM                         jN                  d                ddl(m)Z)m*Z* ddl+m,Z,m-Z-m.Z.m/Z/m0Z0 ddl1m2Z2  e
jf                  e4      Z5dZ6dZ7dZ8dZ9dZ:dZ;dZ<dZ=dZ>dZ?h dZ@ ej                  d      ZBdZCh dZD ej                         ZFdeGd<    ej                         ZI ej                         ZJ eK       ZLdeGd<    eK       ZMdeGd <    eK       ZNdeGd!<   dBd"ZOdCd#ZPdDd$ZQdCd%ZRdEdFd&ZSdGd'ZTdHd(ZUdId)ZVd*dddddd+	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dJd,ZWdKd-ZX G d. d/      ZYdEdLd0ZZdEd	d1dMd2Z[dNd3Z\dOd4Z]dPd5Z^dPd6Z_dPd7Z`dPd8ZadPd9ZbdPd:ZcdPd;Zd G d< d=e,      ZedQd>ZfdRd?ZgdSd@ZhdSdAZiy# e$ r d	ZdZY w xY w)Ta  Raft channel platform adapter.

Starts a local wake endpoint, spawns ``raft agent bridge`` as a child process,
and injects content-free wake hints into Hermes' normal gateway session pipeline.
Token and port are auto-generated when not provided via env/config.
The bridge remains responsible for Raft message cursors and body materialization;
the agent uses the Raft CLI according to the Raft manual.
    )annotationsN)deque)datetimetimezone)AnyDequeDictListOptional)webTF)Path   )PlatformPlatformConfig)BasePlatformAdapterMessageEventMessageType
SendResultmerge_pending_message_event)build_session_key	127.0.0.1z/wakedefaulti @  i  i   zraft-activity.v1zraft-activity-drain.v1zx-raft-bridge-token>   bodytextcontentmessagepreviewsnippetmessagesz^[a-zA-Z0-9._:@/ -]+$x   >   schemastatuseventIdtoolName	sessionId	toolInput	truncated
durationMs
errorClass
occurredAt
toolOutputhookEventNametoolInputTruncatedtoolOutputTruncatedz'weakref.WeakSet[RaftAdapter]'_ACTIVE_ADAPTERSzset[str]_RAFT_SESSION_IDS_RAFT_TURN_IDS_RAFT_PROMPT_TURN_IDSc                 >    t         syt        j                  d      syy)ui  Check if Raft channel dependencies are available.

    Intentionally silent on failure — this is a passive probe registered as
    the platform's ``check_fn``. It is called on every
    ``load_gateway_config()`` (message handling, display lookups, agent
    turns), so logging here floods the logs for every user without the
    ``raft`` CLI installed. The caller (``gateway/platform_registry.py``
    ``create_adapter()``) emits its own warning when requirements are not met
    and an adapter is actually requested. This matches the convention used by
    other platform adapters (e.g. ``teams/adapter.py``).
    FraftT)AIOHTTP_AVAILABLEshutilwhich     Q/root/.hermes/venv/lib/python3.12/site-packages/plugins/platforms/raft/adapter.pycheck_raft_requirementsr;   d   s     <<r9   c                    t        | xs t              j                         xs t        }|j                  d      sd| }|S )N/)strDEFAULT_PATHstrip
startswith)valuepaths     r:   _path_valuerD   w   s;    u$%++-=D??34&zKr9   c                   t        | t              rU| j                         D ]A  \  }}t        |      j	                         j                         t        v r yt        |      sA y yt        | t              rt        d | D              S y)NTc              3  2   K   | ]  }t        |        y wN)_has_content_field).0items     r:   	<genexpr>z%_has_content_field.<locals>.<genexpr>   s     >%d+>s   F)

isinstancedictitemsr>   r@   lower_CONTENT_FIELD_NAMESrH   listany)rB   keynesteds      r:   rH   rH   ~   su    % ;;= 	KC3x~~%%'+??!&)		  
E4	 >>>>r9   c                6    t        t        | d|       xs d      S )NrB    )r>   getattr)rB   s    r:   _platform_valuerX      s    wugu-344r9   c                    t        | t              s|S | rt        |       t        kD  r|S t        j                  |       s|S | S rG   )rL   r>   len_MAX_SCALAR_LENGTH_SAFE_SCALAR_REmatch)rB   r   s     r:   _safe_scalarr^      s=    eS!CJ!33  'Lr9   c                     t        j                  t        j                        j	                         j                  dd      S )Nz+00:00Z)r   nowr   utc	isoformatreplacer8   r9   r:   _now_isore      s+    <<%//199(CHHr9   c                    | y t        | t              r| }n	 t        j                  | dd      }|sy t        |      t        kD  r|d t         dfS |dfS # t        $ r Y y w xY w)NFT)ensure_ascii	sort_keys)rL   r>   jsondumps	ExceptionrZ   ACTIVITY_CONTENT_CAP)rB   r   s     r:   _content_stringrm      sw    }%	::e%4HD 
4y''))*D00;  		s   A 	A A c                v    t        | t        t        f      rt        | t              ry t        |       }|dk  ry |S )Nr   )rL   intfloatbool)rB   durations     r:   _duration_msrs      s4    ec5\*j.E5zH!|Or9   ok)r"   	tool_name
tool_inputtool_outputerror_classduration_msc                z   t         dt        j                          t        |d      xs d| |dk(  rdndt	               d}t        |      }	|	r|	|d<   t        |      }
|
r|
|d<   t        |      }|||d<   d	}t        |      }|r|\  |d
<   }|rd|d<   d}t        |      }|r|\  |d<   }|rd|d<   d}|rd|d<   |S )Nzhermes-unknownerrorrt   )r!   r#   r%   r,   r"   r*   r$   r)   r(   Fr&   Tr-   r+   r.   r'   )ACTIVITY_EVENT_SCHEMAuuiduuid4r^   re   rs   rm   )hook_event_name
session_idr"   ru   rv   rw   rx   ry   eventsafe_tool_namesafe_error_classsafe_duration_msr'   input_valueinput_truncatedoutput_valueoutput_truncateds                    r:   _make_activity_eventr      s    (TZZ\N+!*i8EI(#w.'DjE "),N*j#K0.l#K0#.lI!*-K.9+kO*.E&'I";/L0<-l-+/E'(I!kLr9   c                t   t        | t              st        d      | j                  d      t        k7  rt        d      t        |       t        z
  }|rt        dt        |      d    d      dD ]+  }t        | j                  |            rt        d| d	       | j                  d
      dvrt        d      | j                  d      %t        | j                  d            st        d      | j                  d      %t        | j                  d            st        d      | j                  d      %t        | j                  d            t        d      dD ]B  }| j                  |      t        | j                  |      t              r5t        d| d       t        |       }|j                  d      t        |d         |d<   dD ]a  }|j                  |      }|t        |t              st        d| d      t        |      t        kD  sI|d t         ||<   d|d<   d|| d<   c |S )Nz activity event must be an objectr!   z!unsupported activity event schemazactivity event field r   z is not allowed)r#   r%   r,   r*   zactivity event z  must be a safe non-empty stringr"   >   rt   r|   z&activity event status must be ok|errorr$   z-activity event toolName must be a safe stringr)   z/activity event errorClass must be a safe stringr(   z7activity event durationMs must be a non-negative number)r'   r-   r.   z must be a boolean)r&   r+   z must be a stringTr'   	Truncated)rL   rM   
ValueErrorgetr}   set_ACTIVITY_ALLOWED_FIELDSsortedr^   rs   rq   r>   rZ   rl   )rB   r{   rS   r   r   s        r:   _validate_activity_eventr      s7   eT";<<yy33<==%j33G01C0DOTUUF VEIIcN+se3STUUV yy/1ABByy(eii
>S1THIIyy*<		,@W3XJKKyy*|EIIl<S/T/\RSSI H99S>%j3.Nse3EFGGH KEyy**5+>?l* 	,))C.?'3'se3DEFFw<.. !6"67E#J!%E+'+ESE#$	, Lr9   c                  @    e Zd ZdZefddZddZd	d
dZedd       Z	y)ActivityQueuez@Bounded at-most-once queue for Raft external activity telemetry.c                    t        dt        |xs t                    | _        t	               | _        d| _        t        j                         | _	        y )N   r   )
maxro   DEFAULT_ACTIVITY_QUEUE_CAP_capr   _events_dropped_since_drain	threadingLock_lock)selfcaps     r:   __init__zActivityQueue.__init__  s:    3s@&@AB	.3g$%!^^%
r9   c                z   t        |      }| j                  5  | j                  j                  |       t	        | j                        | j
                  kD  rR| j                  j                          | xj                  dz  c_        t	        | j                        | j
                  kD  rRd d d        y # 1 sw Y   y xY w)Nr   )r   r   r   appendrZ   r   popleftr   )r   r   	validateds      r:   pushzActivityQueue.push  s    ,U3	ZZ 	/LL	*dll#dii/$$&))Q.) dll#dii/	/ 	/ 	/s   BB11B:c                p   t        dt        |xs d            }| j                  5  g }| j                  rRt	        |      |k  rD|j                  | j                  j                                | j                  rt	        |      |k  rD| j                  }d| _        d d d        t        dS # 1 sw Y   xY w)Nr      r   )r!   eventsdropped)	r   ro   r   r   rZ   r   r   r   ACTIVITY_DRAIN_SCHEMA)r   
max_eventslimitr   r   s        r:   drainzActivityQueue.drain  s    As:,-.ZZ 	*+-F,,3v;#6dll2245 ,,3v;#6//G()D%	* 06gVV	* 	*s   A B,B,,B5c                p    | j                   5  t        | j                        cd d d        S # 1 sw Y   y xY wrG   )r   rZ   r   r   s    r:   sizezActivityQueue.size'  s*    ZZ 	%t||$	% 	% 	%s   ,5N)r   ro   r   Dict[str, Any]returnNone)r   )r   ro   r   r   )r   ro   )
__name__
__module____qualname____doc__r   r   r   r   propertyr   r8   r9   r:   r   r     s,    J"< &/W % %r9   r   c                    t        |       }t        |      }t        5  |rt        j                  |       |rt        j                  |       d d d        y # 1 sw Y   y xY wrG   )r^   _RAFT_CONTEXT_LOCKr0   addr1   )r   turn_idsafe_session_idsafe_turn_ids       r:   _remember_raft_contextr   -  sP    ":.O(L	 -!!/2|,	- - -s   /AAforget_sessionc                   t        |       }t        |      }t        5  |r*t        j                  |       t        j                  |       |r|rt
        j                  |       d d d        y # 1 sw Y   y xY wrG   )r^   r   r1   discardr2   r0   )r   r   r   r   r   s        r:   _forget_raft_contextr   7  s`    ":.O(L	 7""<0!)),7o%%o67 7 7s   AA,,A5c                 x   t        | j                  d            dk(  r+t        | j                  d      | j                  d             yt        | j                  d            }t        | j                  d            }t        5  t        |xr |t        v xs |xr |t        v       cd d d        S # 1 sw Y   y xY w)Nplatformr4   r   r   T)rX   r   r   r^   r   rq   r1   r0   )kwargsr   r   s      r:   _is_raft_contextr   B  s    vzz*-.&8vzz,7I9NO"6::l#;<O

9 56L	 
<ln< JHO7H$H

 
 
s   #B00B9c                    t         5  t        t              }d d d        D ]  }|j                  |         y # 1 sw Y   "xY wrG   )_ACTIVE_ADAPTERS_LOCKrQ   r/   report_activity)r   adaptersadapters      r:   _report_activityr   O  sB    	 *()* '&'* *s	   8Ac                     t        d
i | sy 	 ddlm}  |dg       t        t        d| j                  d      	             y # t        $ r t        j                  dd       Y Hw xY w)Nr   )register_env_passthroughRAFT_PROFILEz6[raft] failed to register RAFT_PROFILE env passthroughTexc_infoSessionStartr   r   r   r8   )	r   tools.env_passthroughr   rk   loggerdebugr   r   r   )r   r   s     r:   _on_session_startr   V  sj    %f%^B .!12 *zz,/	
  ^MX\]^s   A  A&%A&c                 "   t        di | sy t        | j                  d            }|r6t        5  |t        v r
	 d d d        y t        j                  |       d d d        t        t        d| j                  d                   y # 1 sw Y   /xY w)Nr   UserPromptSubmitr   r   r8   )r   r^   r   r   r2   r   r   r   )r   r   s     r:   _on_pre_llm_callr   g  s    %f%

9 56L 	444	4 	4 "%%l3	4 .zz,/	
		4 	4s   
BBBc            
         t        di | sy t        t        d| j                  d      | j                  d      | j                  d                   y )N
PreToolUser   ru   args)r   r   ru   rv   r8   r   r   r   r   r   s    r:   _on_pre_tool_callr   x  sG    %f%(zz,/jj-zz&)		
r9   c                    t        di | sy | j                  d      dv s| j                  d      rdnd}|dk(  rdnd}t        t        || j                  d      || j                  d	      | j                  d
      | j                  d      xs | j                  d      | j                  d      xs	 |dk(  rdnd | j                  d                   y )Nr"   >   r|   blocked
error_typer|   rt   PostToolUseFailurePostToolUser   ru   r   error_messageresulttool_failurery   )r   r   r"   ru   rv   rw   rx   ry   r8   )r   r   r   r   )r   r"   	hook_names      r:   _on_post_tool_callr     s    %f%

8,0DD

S_H`WfjF(.'(9$}I%zz,/jj-zz&)

?3Kvzz(7K

<0cvQXGX^^b

=1		
r9   c                 f    t        di | sy t        t        d| j                  d                   y )NStopr   r   r8   r   r   s    r:   _on_post_llm_callr     s/    %f%"zz,/	
r9   c            
     ,   t        d
i | sy | j                  d      s| j                  d      du r:t        t        d| j                  d      d| j                  d      rdnd             t	        | j                  d      | j                  d	             y )Ninterrupted	completedFr   r   r|   
incomplete)r   r   r"   rx   r   r8   )r   r   r   r   r   r   s    r:   _on_session_endr     s|    %f%zz- FJJ{$;u$D  &!::l3-3ZZ-FML		
 L16::i3HIr9   c                     t        di | sy t        t        d| j                  d                   t	        | j                  d      | j                  d      d       y )N
SessionEndr   r   r   Tr   r8   )r   r   r   r   r   r   s    r:   _on_session_finalizer     sP    %f%(zz,/	
 L16::i3HY]^r9   c                       e Zd ZdZd fdZedd       ZddddZddZddZ	dd	Z
	 	 d	 	 	 	 	 	 	 	 	 dd
ZddZddZddZddZddZddZddZd  fdZedd       Zd!dZ xZS )"RaftAdapterz5Local HTTP endpoint for Raft channel bridge delivery.c                J   t         |   |t        d             |j                  xs i }t	        |j                  dt                    | _        t        |j                  dt                    | _
        t        |j                  dt                    | _        t	        |j                  dd            | _        t	        |j                  dt              xs t              | _        t        |j                  dt"                    | _        d | _        d | _        t+               | _        y )	Nr4   hostportrC   bridge_tokenrV   runtime_sessionmax_body_bytes)superr   r   extrar>   r   DEFAULT_HOST_hostro   DEFAULT_PORT_portrD   r?   _path_bridge_tokenDEFAULT_RUNTIME_SESSION_runtime_sessionDEFAULT_MAX_BODY_BYTES_max_body_bytes_runner_bridge_processr   _activity_queue)r   configr  	__class__s      r:   r   zRaftAdapter.__init__  s    &!12"eii=>
eii=>
%eii&EF
"%eii&C"D%(II')@A '&&
 %(II&(>?%
 ;?,r9   c                    | j                   S rG   )r  r   s    r:   r   zRaftAdapter.runtime_session  s    $$$r9   F)is_reconnectc               @  K   | j                   s/t        j                  d      | _         t        j	                  d       t        j                  | j                        }|j                  j                  d| j                         |j                  j                  | j                  | j                         |j                  j                  d| j                         |j                  j                  d| j                         | j                   dk7  rdd l}	 |j#                  |j$                  |j&                        5 }|j)                  d       |j+                  d	| j                   f       d d d        t        j-                  d
| j                          yt        j2                  |      | _        | j4                  j7                          d {    t        j8                  | j4                  | j:                  | j                         }|j=                          d {    | j                   }|dk(  rL|j>                  r@|j>                  j@                  r*|j>                  j@                  d   jC                         d   }| jE                          tF        5  tH        jK                  |        d d d        t        j	                  d| j:                  || j                         | jM                  |       y# 1 sw Y   xY w# t.        t0        f$ r Y ww xY w7 D7 # 1 sw Y   oxY ww)N    z"[raft] Auto-generated bridge token)client_max_sizez/health	/activity/activity/drainr   r   r   zF[raft] Port %d already in use. Set platforms.raft.extra.port in configFz([raft] Raft channel listening on %s:%d%sT)'r	  secrets	token_hexr   infor   Applicationr  routeradd_get_handle_healthadd_postr  _handle_wake_handle_activity_handle_activity_drainr  socketAF_INETSOCK_STREAM
settimeoutconnectr|   ConnectionRefusedErrorOSError	AppRunnerr  setupTCPSiter  start_serversocketsgetsockname_mark_connectedr   r/   r   _spawn_bridge)r   r  app_socketsocksite
bound_ports          r:   r)  zRaftAdapter.connect  sM    !!!(!2!22!6DKK<= ood.B.BC

9d&9&9:

DJJ(9(9:

K)>)>?

,d.I.IJ::?$
^^GOOW5H5HI <TOOA&LL+tzz!:;< \JJ  }}S)ll  """{{4<<TZZ@jjlZZ
?t||0D0D--a0<<>qAJ" 	'  &	'>

JX\XbXbc:&5< < +G4  	#	' 	's{   DL&K7 :/K*)(K7 8L	L
ALLA7LL$AL*K4/K7 7L
L	L

LLLLc                D  K   | j                          | j                  r)| j                  j                          d {    d | _        t        5  t        j                  |        d d d        | j                          t        j                  d       y 7 U# 1 sw Y   1xY ww)Nz[raft] Disconnected)	_stop_bridger  cleanupr   r/   r   _mark_disconnectedr   r  r   s    r:   
disconnectzRaftAdapter.disconnect  sz     <<,,&&(((DL" 	+$$T*	+!)* )	+ 	+s'   :B BB B$/B BB c           	     X   t        j                  d      }|st        j                  d       y t        j
                  j                  dd      }|st        j                  d       y d| j                   d| | j                   }|d|d	d
ddd|g	}i t        j
                  d| j                  i}	 t        j                  ||t        j                        | _        t        j                  d| j                  j                  ||       y # t         $ r t        j#                  d       Y y w xY w)Nr4   uP   [raft] raft CLI not found in PATH; bridge not spawned — wake-only polling moder   rV   z/[raft] RAFT_PROFILE not set; bridge not spawnedzhttp://:z	--profileagentbridgez--wake-adapterzwake-channelz--wake-channel-endpointRAFT_CHANNEL_TOKEN)envstdinz3[raft] Spawned bridge pid=%d profile=%s endpoint=%sz[raft] Failed to spawn bridge)r6   r7   r   warningosenvironr   r  r  r	  
subprocessPopenDEVNULLr  r  pidrk   	exception)r   r   raft_binprofileendpointcmdrD  s          r:   r4  zRaftAdapter._spawn_bridge  s
   <<'NNmn**..4NNLMTZZL$

|<k7Xn%x	
 GF143E3EF	>#-#3#3J$6$6$D  KKMtOcOcOgOgiprz{ 	><=	>s   0AD D)(D)c                   | j                   }|y d | _         	 |j                          |j                  d       t        j	                  d|j
                         y # t        j                  $ r3 |j                          t        j                  d|j
                         Y y t        $ r t        j                  d       Y y w xY w)N   )timeoutz)[raft] Bridge process terminated (pid=%d)z3[raft] Bridge process killed after timeout (pid=%d)z[raft] Error stopping bridge)r  	terminatewaitr   r  rL  rI  TimeoutExpiredkillrF  rk   rM  )r   procs     r:   r;  zRaftAdapter._stop_bridge+  s    ##<#	=NNIIaI KKCTXXN(( 	\IIKNNPRVRZRZ[ 	=;<	=s   AA AC  C ?C c                L   K   t         j                  d       t        d      S w)Nz;[raft] adapter send is a no-op; agent delivers via raft CLIT)success)r   r   r   )r   chat_idr   reply_tometadatas        r:   sendzRaftAdapter.send:  s       	RS$''s   "$c                   K   d| ddS w)Nzraft/r4   )nametyper8   )r   r\  s     r:   get_chat_infozRaftAdapter.get_chat_infoD  s     y)6::s   	c           	        K   t        j                  dd| j                  | j                  j                  dddd      S w)Nrt   r4   r  r  )	queueSizerP  drainEndpoint)r"   r   runtimeSessionactivity)r   json_responser  r  r   )r   requests     r:   r   zRaftAdapter._handle_healthG  sG       ""&"7"7!%!5!5!:!: +%6		
 	
s   =?c                |  K   | j                  |j                  j                  t        d            st	        j
                  dddd      S |j                  xs d}|| j                  kD  rt	        j
                  dddd	      S 	 |j                          d {   }t        |      | j                  kD  rt	        j
                  dddd	      S i }|j                         rB	 t        j                  |      }t!        |t"              st	        j
                  dddd      S |}t%        |      rt	        j
                  dddd      S | j'                  |       d {   }|s%t	        j
                  dd| j(                  dd      S t	        j
                  d| j(                  dd      S 7 # t        j                  $ r t	        j
                  dddd	      cY S t        $ r t	        j
                  dd
dd      cY S w xY w# t        j                  $ r t	        j
                  dddd      cY S w xY w7 ܭw)NrV   Funauthorizedrt   r|     r"   r   payload_too_large  bad_request  invalid_jsoninvalid_payloadcontent_not_allowed	not_ready)rt   r|   rg  i  T)rt   rg     )_validate_bridge_tokenheadersr   BRIDGE_TOKEN_HEADERr   ri  content_lengthr  readHTTPRequestEntityTooLargerk   rZ   r@   ri   loadsJSONDecodeErrorrL   rM   rH   _accept_waker  )r   rj  r|  raw_bodypayloadparsedaccepteds          r:   r"  zRaftAdapter._handle_wakeU  s,    **7??+>+>?RTV+WX$$EN%KTWXX //41D000$$E<O%PY\]]	X$\\^+H x=4/// $$E<O%PY\]]"$>>]H- fd+((@Q)R[^__G g&$$E<Q%R[^__**733$$(&*&;&;
     "&"7"7 
 	
M ,,, 	^ $$E<O%PY\]] 	X$$EM%JSVWW	X '' ](()OX[\\] 4s{   BH<F0 F-F0 AH<#H 8A%H<H:AH<-F0 0-HH<"HH<HH<-H74H<6H77H<c                  K   | j                  |j                  j                  t        d            st	        j
                  dddd      S |j                  xs d}|| j                  kD  rt	        j
                  dddd	      S 	 |j                          d {   }t        |j                  d            | j                  kD  rt	        j
                  dddd	      S 	 t        j                  |      }| j                   j#                  |       t	        j
                  ddid      S 7 # t        j                  $ r t	        j
                  dddd	      cY S t        $ r-}t	        j
                  dt        |      dd
      cY d }~S d }~ww xY w# t        j$                  $ r t	        j
                  dddd
      cY S t        $ r-}t	        j
                  dt        |      dd
      cY d }~S d }~ww xY ww)NrV   Frl  rm  rn  ro  r   rp  rq  rs  zutf-8rt  rt   Trx  )ry  rz  r   r{  r   ri  r|  r  r   r~  rk   r>   rZ   encoderi   r  r  r   r  )r   rj  r|  raw_textexcr  s         r:   r#  zRaftAdapter._handle_activity  s    **7??+>+>?RTV+WX$$EN%KTWXX //41D000$$E<O%PY\]]	S$\\^+H xw'(4+?+?? $$E<O%PY\]]	Sjj*G  %%g.   $c::) ,,, 	^ $$E<O%PY\]] 	S$$ECH%EcRR	S ## 	Y$$EN%KTWXX 	S$$ECH%EcRR	Ss   BG9D+ D)D+ AG9 0F G9)D+ +-FG9F""F
FG9
FG9-G6?G9G6	"G1+G6,G91G66G9c                f  K   | j                  |j                  j                  t        d            st	        j
                  dddd      S 	 t        |j                  j                  dd            }t	        j
                  | j                  j                  |            S # t        $ r d	}Y ;w xY ww)
NrV   Frl  rm  rn  ro  r   200r   )ry  rz  r   r{  r   ri  ro   queryr   r  r   )r   rj  r   s      r:   r$  z"RaftAdapter._handle_activity_drain  s     **7??+>+>?RTV+WX$$EN%KTWXX	W]]..ue<=J   !5!5!;!;J!GHH  	J	s*   A
B1%B  2.B1 B.+B1-B..B1c                    | j                   r|syt        j                  |j                         | j                   j                               S )NF)r	  hmaccompare_digestr  )r   tokens     r:   ry  z"RaftAdapter._validate_bridge_token  s:    !! ""5<<>43E3E3L3L3NOOr9   c                  K   | j                   st        j                  d       yt        |j	                  d      xs |j	                  d      xso |j	                  d      xs\ |j	                  d      xsI |j	                  d      xs6 |j	                  d      xs# d	t        t        j                         d
z               }| j                  | j                  dddd      }t        | j                         t        j                  |||d      }	 | j                  |       d {    y7 # t        $ r t        j                  d       Y yw xY ww)Nz@[raft] Wake received before gateway message handler was attachedFr#   	attemptId	messageIddelivery_idwake_ididz
raft-wake-i  zRaft channeldmzraft-bridgezRaft Bridge)r\  	chat_name	chat_typeuser_id	user_nameT)r   message_typesourceraw_message
message_idinternalz"[raft] Failed to inject wake event)_message_handlerr   rF  r>   r   ro   timebuild_sourcer  r   _wake_promptr   TEXThandle_messagerk   rM  )r   r  r  r  r   s        r:   r  zRaftAdapter._accept_wake  sN    $$NN]^KK	" 6{{;'6{{;'6 {{=)6 {{9%	6
 {{4 6 C		d 2345
 ""))$!# # 
 ""$$))"
	%%e,,, 	 - 	AB	s<   DED- %D+&D- *E+D- -EEEEc                  K   | j                   syt        |j                  | j                  j                  j                  dd      | j                  j                  j                  dd            }|| j                  v r.t        j                  d|       t        | j                  ||       yt        | 1  |       d{    y7 w)zBAccept Raft wake hints without interrupting an active Hermes turn.Ngroup_sessions_per_userTthread_sessions_per_userF)r  r  z&[raft] Wake queued for busy session %s)r  r   r  r  r  r   _active_sessionsr   r   r   _pending_messagesr  r  )r   r   session_keyr  s      r:   r  zRaftAdapter.handle_message  s     $$'LL$(KK$5$5$9$9:SUY$Z%)[[%6%6%:%:;UW\%]
 $///LLA;O'(>(>USg$U+++s   B<C?C Cc                      	 y)NzRaft wake hint received. New Raft messages may be pending. If you have not read the Raft manual in this session, run `raft manual get raft-cli-overview` before using Raft commands.r8   r8   r9   r:   r  zRaftAdapter._wake_prompt  s    N	
r9   c                    	 | j                   j                  |       y # t        $ r t        j	                  dd       Y y w xY w)Nz/[raft] activity event dropped during validationTr   )r  r   rk   r   r   )r   r   s     r:   r   zRaftAdapter.report_activity  s?    	[  %%e, 	[LLJUYLZ	[s     A A)r  r   r   r>   )r  rq   r   rq   r   r   )r   ro   r   r   )NN)
r\  r>   r   r>   r]  Optional[str]r^  zOptional[Dict[str, Any]]r   r   )r\  r>   r   r   )rj  z'web.Request'r   z'web.Response')r  r>   r   rq   )r  r   r   rq   )r   r   r   r   r   )r   r   r   r   r   r   r   r)  r>  r4  r;  r_  rc  r   r"  r#  r$  ry  r  r  staticmethodr  r   __classcell__)r  s   @r:   r   r     s    ?/$ % % 5: -^+>6=& #'-1(( (  	(
 +( 
(;
5
n;>IP"H,$ 
 
[r9   r   c                |    | j                   xs i }t        |j                  d      xs |j                  d            S )Nenabledr   )r  rq   r   )r  r  s     r:   _is_connectedr     s2    LLBE		)$A		.(ABBr9   c                 6    t        j                  d      syddiS )zSeed PlatformConfig.extra from env vars during gateway config load.

    Auto-enables when RAFT_PROFILE is set (the adapter needs it anyway).
    r   Nr  T)rG  getenvr8   r9   r:   _env_enablementr    s    
 99^$tr9   c                 t   ddl m} m}m}m}m}m} ddlm}m	}  | d        |d      }|r" |d| d        |dd	      s |d
| d       y |d        |d        |d       t                 |d|xs d      }	|	s	 |d       y |d|	j                                t                 |d        |d       y)a$  Interactive ``hermes gateway setup`` flow for the Raft platform.

    Lazy-imports CLI helpers so the plugin stays importable in gateway runtime
    and test contexts. The flow persists ``RAFT_PROFILE`` to the Hermes env
    file so the Raft adapter auto-enables after a gateway restart.
    r   )print_header
print_infoprint_successprint_warningpromptprompt_yes_no)get_env_valuesave_env_valueRaftr   z#Raft: already configured (profile: )zReconfigure Raft?FzKeeping RAFT_PROFILE=.Nz,Connect Hermes to Raft as an external agent.z2Create the External Agent in Raft first, then run:zQ  raft agent login --server <server-url> --agent <agent-id> --profile-slug <slug>zRaft profile slugrV   )r   z2Raft profile slug is required; skipping Raft setupzRaft configuration savedzFRestart the gateway for changes to take effect: hermes gateway restart)hermes_cli.cli_outputr  r  r  r  r  r  hermes_cli.configr  r  printr@   )
r  r  r  r  r  r  r  r  existing_profilerO  s
             r:   interactive_setupr    s      @$^489I8J!LM0%8./?.@BC=>CDbc	G(2B2HbIGJK>7==?3	G,-WXr9   c                   | j                  ddd t        t        dgdt        t        ddj                  t        j                  j                  dd      	      
       | j                  dt               | j                  dt               | j                  dt               | j                  dt               | j                  dt               | j                  dt               | j                  dt                y)u:   Plugin entry point — called by the Hermes plugin system.r4   r  c                    t        |       S rG   )r   )cfgs    r:   <lambda>zregister.<locals>.<lambda>?  s    K$4 r9   r   z,Install the Raft CLI from https://raft.buildu   🔔a&  You are connected to Raft via an external-agent channel. Run `raft --profile {profile} profile show` to confirm which agent profile is active. Run `raft --profile {profile} manual get raft-cli-overview` to learn available Raft commands. Always pass `--profile {profile}` to every raft CLI call.zyour-agent-profile)rO  )ra  labeladapter_factorycheck_fnis_connectedrequired_envinstall_hintsetup_fnenv_enablement_fnemojiplatform_hinton_session_startpre_llm_callpre_tool_callpost_tool_callpost_llm_callon_session_endon_session_finalizeN)register_platformr;   r  r  r  formatrG  rH  r   register_hookr   r   r   r   r   r   r   )ctxs    r:   registerr  :  s    4("$%C")H &8LM&
N!  $ (*;<n&67o'89&(:;o'89&8+-ABr9   )r   rq   )rB   r   r   r>   )rB   r   r   rq   rG   )rB   r   r   r  r   r  r  )rB   r   r   zOptional[tuple[str, bool]])rB   r   r   zOptional[int])r   r>   r   r   r"   r>   ru   r   rv   r   rw   r   rx   r   ry   r   r   r   )rB   r   r   r   )r   r   r   r   r   r   )r   r   r   r   r   rq   r   r   )r   r   r   rq   r   )r   r   r   r   )r  r   r   rq   )r   zOptional[dict]r  )jr   
__future__r   asynciocollectionsr   r   r   r  ri   loggingrG  rer  r6   rI  r   r  r~   weakreftypingr   r   r	   r
   r   aiohttpr   r5   ImportErrorsyspathlibr   _PathrC   insertr>   __file__resolveparentsgateway.configr   r   gateway.platforms.baser   r   r   r   r   gateway.sessionr   	getLoggerr   r   r  r  r?   r
  r  r   rl   r}   r   r{  rP   compiler\   r[   r   WeakSetr/   __annotations__r   r   r   r   r0   r1   r2   r;   rD   rH   rX   r^   re   rm   rs   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r8   r9   r:   <module>r     s   #   '    	 	        3 3
  ! 3uX..088;< = 3  .			8	$#     * 0 +   "**56    4C7??3D 0 D&	( #Y^^% !e 8 #5  "%% x '&	5I" ,, , 	,
 , , , , , ,^$N% %B-7Y^ 7

'""
&J	_[% [D
C
'YTCs  
Cs   H 	HH