
    `gjW                      d Z ddlmZ ddl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mZmZ ddlmZ ddlmZ ddlmZmZmZ dd	lmZmZ ddlZdd
lmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZE ddlFmGZGmHZHmIZI ddlJmKZKmLZLmMZMmNZNmOZO ddlPmQZQ ddlRmSZS ddlTmUZUmVZVmWZW ddlXmYZYmZZZ ddl[m\Z\m]Z]  e	j                  e_      Z`	 ddlambZc  edd      ZedZfdZgdZhh dZid+d,dZjd-dZkd-dZld.dZmd/dZnd0d Zod1d!Zpdddd"	 	 	 	 	 	 	 	 	 	 	 d2d#Zqd3d$Zrd4d%Zs	 	 	 	 d5d&Ztd6d'Zu	 	 	 	 d7d(Zv G d) d*ej                        Zxy# ed$ r dZcY w xY w)8uH   ACP agent server — exposes Hermes Agent via the Agent Client Protocol.    )annotationsN)datetimetimezone)defaultdictdeque)ThreadPoolExecutor)Path)AnyDequeOptional)unquoteurlparse)+AgentCapabilitiesAgentMessageChunkAgentThoughtChunkAuthenticateResponseAvailableCommandAvailableCommandsUpdateBlobResourceContentsClientCapabilitiesEmbeddedResourceContentBlockForkSessionResponseImageContentBlockAudioContentBlockImplementationInitializeResponseListSessionsResponseLoadSessionResponseMcpServerHttpMcpServerSseMcpServerStdio	ModelInfoNewSessionResponsePromptCapabilitiesPromptResponseResumeSessionResponseSetSessionConfigOptionResponseSetSessionModelResponseSetSessionModeResponseResourceContentBlockSessionCapabilitiesSessionForkCapabilitiesSessionInfoUpdateSessionListCapabilitiesSessionModeSessionModeStateSessionModelStateSessionResumeCapabilitiesSessionInfoTextContentBlockTextResourceContentsUnstructuredCommandInputUsageUsageUpdateUserMessageChunk)TERMINAL_SETUP_AUTH_METHOD_IDbuild_auth_methodsdetect_provider)#_build_plan_update_from_todo_resultmake_message_cbmake_step_cbmake_thinking_cbmake_tool_progress_cb)make_approval_callback)session_provenance_meta)SessionManagerSessionState_expand_acp_enabled_toolsets)build_tool_completebuild_tool_start) reset_hermes_interactive_contextset_hermes_interactive_context)__version__z0.0.0   z	acp-agent)max_workersthread_name_prefix2   i   )ztext/>   application/sqlapplication/xmlapplication/jsonapplication/tomlapplication/yamlapplication/x-yamlapplication/javascriptapplication/typescriptc                   |xs dj                         }|xs dj                         }|r|r||k7  r| d| dS |r|S |r|S t        |       }|j                  r|j                  n| }t	        t        |            j                  xs | xs dS )z2Human-readable attachment name for prompt context.  ()resource)stripr   schemepathr	   r   name)urir`   titleraw_name	raw_titleparsed	candidates          E/root/.hermes/venv/lib/python3.12/site-packages/acp_adapter/server.py_resource_display_namerh   n   s    
!!#H"##%IX)x"7Bxj**c]F%}}#I	"#((=C=:=    c                    | xs dj                  dd      d   j                         j                         }|sy|j                  t              xs |t
        v S )NrY   ;   r   F)splitr]   lower
startswith_TEXT_RESOURCE_MIME_PREFIXES_TEXT_RESOURCE_MIME_TYPES	mime_typemimes     rg   _is_text_resourceru   }   sP    O""3*1-335;;=D??78]DD]<]]ri   c                    | xs dj                  dd      d   j                         j                         }|j                  d      S )NrY   rk   rl   r   zimage/)rm   r]   rn   ro   rr   s     rg   _is_image_resourcerw      s>    O""3*1-335;;=D??8$$ri   c                h    | j                   j                         }ddddddddj                  |      S )N	image/pngz
image/jpegz	image/gifz
image/webpz	image/bmpzimage/svg+xml)z.pngz.jpgz.jpegz.gifz.webpz.bmpz.svg)suffixrn   get)r_   rz   s     rg   _guess_image_mime_from_pathr|      s>    [[ F 
c&kri   c                V    d| dt        j                  |       j                  d       S )Ndata:;base64,ascii)base64	b64encodedecode)datars   s     rg   _image_data_urlr      s,    9+Xf&6&6t&<&C&CG&L%MNNri   c                   | xs dj                         }|syt        |      }|j                  r|j                  dk7  ry|j                  dk(  r5|j                  r|j                  dvryt	        |j
                  xs d      }nt	        |      }t        |      dk\  rk|d   dk(  rc|d   d	k(  r[|d
   j                         rH|d
   j                         }|dd j                  d      j                  dd      }t        d      |z  |z  S t        |      dk\  rc|d
   d	k(  r[|d   j                         rH|d   j                         }|dd j                  d      j                  dd      }t        d      |z  |z  S t        |      S )a#  Convert local file URIs/paths from ACP clients into a readable Path.

    Zed may send POSIX file URIs from Linux/WSL workspaces or Windows-ish paths
    when launched through wsl.exe. Translate the common Windows drive form to
    /mnt/<drive>/... so Hermes running in WSL can read it.
    rY   Nfile>   rY   	localhost   r   /   :rl   z/\\z/mnt)r]   r   r^   netlocr   r_   lenisalpharn   lstripreplacer	   )ra   rawre   	path_textdriverests         rg   _path_from_file_urir      sn    9"


Cc]F}}&0}}==V]]2CCFKK-2.	CL	 9~y|s2y|s7JyYZ|OcOcOe!""$}##E*224=F|e#d**
9~y|s2y|7K7K7M!""$}##E*224=F|e#d**	?ri   c                    d| v rt        |      sydD ]  }	 | j                  |      c S  | j                  dd      S # t        $ r Y 6w xY w)zHDecode resource bytes if they are probably text; return None for binary.    N)z	utf-8-sigutf-8zlatin-1r   r   errors)ru   r   UnicodeDecodeError)r   rs   encodings      rg   _decode_text_bytesr      s`    $0;5 	;;x((
 ;;wy;11 " 		s   >	A
	A
)r`   rb   notec                T    t        | ||      }d| d}|r	|d| dz  }| d|  d| S )Nr`   rb   z[Attached file: ]rZ   r[   
URI: z

)rh   )ra   bodyr`   rb   r   displayheaders          rg   _format_resource_textr      sL     %St5AGy*FBtfA,XWSEdV,,ri   c                   t        t        | dd      xs d      j                         }|sg S t        t        | dd      xs d      j                         xs d}t        t        | dd      xs d      j                         xs d}t        t        | dd      xs d      j                         xs d}t        |      }|dt	        |||d	      d
gS t        |      r|n
t        |      }|rt        |      r	 |j                         j                  }|t        kD  rdt	        |||d| dt         d	      d
gS |j                  d      5 }|j                         }	ddd       t        |||      }dd| d| d
ddt!        	|      idgS 	 |j                         j                  }t#        |t              }|j                  d      5 }|j                  |      }	ddd       t%        	|      }|dt	        |||d| d|xs d d	      d
gS d}|t        kD  rdt         d| d}dt	        |||||      d
gS # 1 sw Y   xY w# t        $ r9}
t        j                  d|d       dt	        |||d|
 d	      d
gcY d}
~
S d}
~
ww xY w# 1 sw Y   xY w# t        $ r9}
t        j                  d |d       dt	        |||d!|
 d	      d
gcY d}
~
S d}
~
ww xY w)"ar  Convert an ACP resource_link block to OpenAI content parts.

    Returns a list of {"type": "text", ...} and/or {"type": "image_url", ...}
    parts. Image resources produce an image_url part with a small text header
    so the model knows which attachment it is. Non-image resources return a
    single text part with the inlined file body (or a binary-omit note).
    ra   rY   r`   Nrb   rs   textzM[Resource link only; Hermes cannot read non-file ACP resource URIs directly.])ra   r`   rb   r   typer   z[Image too large to inline:  bytes, cap=r   rbz"ACP image resource read failed: %sTexc_infoz [Could not read attached image: r   [Attached image: z]
URI: 	image_urlurlr   r   z[Binary file omitted:  bytes, mime=unknownztruncated to  of z bytes)ra   r`   rb   r   r   zACP resource read failed: %sz[Could not read attached file: )strgetattrr]   r   r   rw   r|   statst_size_MAX_ACP_RESOURCE_BYTESopenreadOSErrorloggerwarningrh   r   minr   )blockra   r`   rb   rs   r_   
image_mimesizefhr   excr   	read_sizer   r   s                  rg   _resource_link_to_partsr      sP    geUB'-2
.
4
4
6C	wufb)/R0668@DDw+1r288:BdEGE;39r:@@BJdIs#D|)d	
  	 1;A\]aAbJ(4	99;&&D--"1!#;D6NeMffgh	   4 !Bwwy! )4uE'8	#%OP tZ7X/YZ
 	

!yy{""56	YYt_ 	&779%D	&!$	2<-1$}YE[R[D\\]^	   ))"#:";4vVLD)cEPT[_`
  	M! ! 
	NN?tNT-;C5B	  
	(	& 	&(  
5sTJ)6se1=	
  	
sy   7A I 8I 	H:I ;J J3J +J :I?I 	J.J=JJJJ 	K .KKKc           	        t        | dd       }|g S t        t        |dd      xs d      j                         }t        t        |dd      xs d      j                         xs d }t        |t              rdt        ||j                        dgS t        |t              r|j                  xs d}	 t        j                  |d	      }t        |      rjt        |      t        kD  r%dt        |dt        |       dt         d      dgS t!        |      }dd| d|rd| ndz   dddt#        ||xs d      idgS t%        |d t         |      }|dt        |       d|xs d d}n-|}t        |      t        kD  r|dt         dt        |       dz  }dt        ||      dgS t        |dd       }|rdt        |t        |            dgS g S # t        $ r |j                  d
d      }Y )w xY w)Nr\   ra   rY   rs   r   )ra   r   r   T)validater   r   r   z%[Embedded image too large to inline: r   r   r   r   r   r   ry   r   z[Binary embedded file omitted: r   r   z

[Truncated to r   z bytes])r   r   r]   
isinstancer5   r   r   r   blobr   	b64decode	Exceptionencoderw   r   r   rh   r   r   )	r   r\   ra   rs   r   r   r   r   r   s	            rg   _embedded_resource_to_partsr   ;  s3   uj$/H	
ghr*0b
1
7
7
9CGHk26<"=CCEMI(01)>3X]])[\]](01}}"	:##D48D
 i(4y22"1DSYK|\s[ttuv   -S1G+<WIQ)G^aWUXTY?gi)jk$E?4QZQi^i;j3kl 
 "$'?(?"@)L<4SYK}YMcZcLddefDD4y22,-D,ET#d)T[\\)>3T)RSTT8VT*D)>3SQUY)WXYYI?  	:;;wy;9D	:s   3G G43G4c                    g }| D ]_  }t        |t              r|j                  |j                         /t	        |d      s<|j                  t        |j                               a dj                  |      S )z@Extract plain text from ACP content blocks for display/commands.r   
)r   r4   appendr   hasattrr   join)promptpartsr   s      rg   _extract_textr   l  sb     E *e-.LL$UF#LLUZZ)	*
 99Uri   c                P   t        t        | dd      xs d      j                         }t        t        | dd      xs d      j                         }t        t        | dd      xs d      j                         xs d}|r|j                  d      r|nd| d| }n|r|}nyd	d
|idS )zFConvert an ACP image content block to OpenAI-style multimodal content.r   rY   ra   rs   ry   r~   r   Nr   r   r   )r   r   r]   ro   )r   r   ra   rs   r   s        rg   _image_block_to_openai_partr     s    wufb)/R0668D
geUB'-2
.
4
4
6CGE;3B{CIIKZ{Ioog.deI;htf4U	ucl;;ri   c                   g }g }| D ]B  }t        |t              rF|j                  r9|j                  d|j                  d       |j                  |j                         Zt        |t              rt        |      }||j                  |       t        |t              rMt        |      }|D ]<  }|j                  |       |j                  d      dk(  s)|j                  |d          > t        |t              st        |      }|D ]<  }|j                  |       |j                  d      dk(  s)|j                  |d          > E |st        |       S t        d |D              rdj                  |      S |S )zOConvert ACP prompt blocks into a Hermes/OpenAI-compatible user content payload.r   r   r   c              3  D   K   | ]  }|j                  d       dk(    yw)r   r   Nr{   .0parts     rg   	<genexpr>z9_content_blocks_to_openai_user_content.<locals>.<genexpr>  s     
8$488Fv%
8s    r   )r   r4   r   r   r   r   r*   r   r{   r   r   r   allr   )r   r   
text_partsr   
image_partresource_partsr   s          rg   &_content_blocks_to_openai_user_contentr     sg    #%EJ e-.zzfejjAB!!%**-e./4U;J%Z(e124U;N& 4T"88F#v-%%d6l34 e9:8?N& 4T"88F#v-%%d6l34 14 V$$
 
8%
88yy$$Lri   c                     e Zd ZdZdddddddd	d
d	Z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f	ZdZdZd Zd!Z	d"Z
ede	d#e
d$iZej                         D  ci c]  \  }}||
 c}}} ZdUdVfd&ZdWd'ZdXd(ZdYd)ZedZd*       Zd[d+Zed\d,       Zed]d-       Zd^d.Z	 dU	 	 	 	 	 	 	 d_d/Zd%d%d0	 	 	 	 	 	 	 d`d1Zd^d2Z	 	 	 	 	 	 dad3Z	 	 	 db	 	 	 	 	 	 	 	 	 dcd4Zddd5Zeded6       Zedfd7       Z edfd8       Z!e	 	 	 	 	 	 dgd9       Z"edhd:       Z#edid;       Z$edjd<       Z%d^d=Z&	 dU	 	 	 	 	 	 	 dkd>Z'	 dU	 	 	 	 	 	 	 	 	 dld?Z(	 dU	 	 	 	 	 	 	 	 	 dmd@Z)dndAZ*	 dU	 	 	 	 	 	 	 	 	 dodBZ+	 	 dp	 	 	 	 	 	 	 dqdCZ,	 	 	 	 	 	 	 	 drdDZ-edsdE       Z.dtdFZ/dtdGZ0dudHZ1dvdIZ2dvdJZ3dvdKZ4dvdLZ5dvdMZ6dvdNZ7dvdOZ8dvdPZ9dvdQZ:	 	 	 	 	 	 	 	 dwdRZ;	 	 	 	 	 	 	 	 dxdSZ<	 	 	 	 	 	 	 	 	 	 dydTZ=xZ>S c c}}} w )zHermesACPAgentz1ACP Agent implementation wrapping Hermes AIAgent.zShow available commandszShow or change current modelzList available toolszShow conversation context infozClear conversation historyzCompress conversation contextz5Inject guidance into the currently running agent turnz5Queue a prompt to run after the current turn finisheszShow Hermes version	helpmodeltoolscontextresetcompactsteerqueueversionr   zList available commands)r`   descriptionr   z1Show current model and provider, or switch modelszmodel name to switch to)r`   r   
input_hintr   z&List available tools with descriptionsr   z(Show conversation message counts by roler   r   r   zguidance for the active turnr   zprompt to run nextr   edit_approval_policyaskdefaultaccept_editsdont_askworkspace_sessionsessionNc                V    t         |           |xs
 t               | _        d | _        y N)super__init__rD   session_manager_conn)selfr  	__class__s     rg   r   zHermesACPAgent.__init__	  s%    .B.2B+/
ri   c                <    || _         t        j                  d       y)z8Store the client connection for sending session updates.zACP client connectedN)r  r   info)r  conns     rg   
on_connectzHermesACPAgent.on_connect  s    
*+ri   c           
     "   t        t        |dd      xs | j                        }|| j                  vr| j                  }t	        |t        | j                  dd      t        | j                  dd      t        | j                  dd	      g
      S )a  Return ACP session modes while preserving Zed's separate model picker.

        Zed renders ``config_options`` in the prominent selector slot where the
        model picker was visible. Claude/Codex expose policy-like controls as ACP
        modes, which coexist with the model picker, so Hermes maps edit approval
        policy onto modes instead of advertising config options.
        moderY   DefaultzAsk before edits.)idr`   r   zAccept EditszDAuto-allow workspace and /tmp edits; still asks for sensitive paths.z	Don't Askz>Auto-allow file edits for this session except sensitive paths.)current_mode_idavailable_modes)r   r   _MODE_DEFAULT_MODE_TO_EDIT_APPROVAL_POLICYr0   r/   _MODE_ACCEPT_EDITS_MODE_DONT_ASK)r  statecurrents      rg   _session_modeszHermesACPAgent._session_modes  s     geVR0FD4F4FG$<<<((G#))" 3
 ..' f
 **$ `
 	
ri   c                    t        t        |dd      xs | j                        }| j                  j	                  || j
                        }||j                  fS )Nr
  rY   )r   r   r  r  r{   _EDIT_APPROVAL_POLICY_DEFAULTcwd)r  r  r
  policys       rg   _edit_approval_policy_for_statez.HermesACPAgent._edit_approval_policy_for_state7  sM    75&"-C1C1CD3377d>`>`auyy  ri   c                    t        |xs d      j                         }|syt        | xs d      j                         j                         }|s|S | d| S )zBEncode a model selection so ACP clients can keep provider context.rY   r   )r   r]   rn   )providerr   	raw_modelraw_providers       rg   _encode_model_choicez#HermesACPAgent._encode_model_choice<  s[     $**,	8>r*00288:q,,ri   c                   t        |j                  xs t        |j                  dd      xs d      j	                         }t        |j                  dd      xs t               xs d}	 ddlm}m}m	}  ||      } ||      }g }	t               }
 ||      D ]  \  }}t        |xs d      j	                         }|s&| j                  ||      }||
v r=d| g}|r(|j                  t        |      j	                                ||k(  r|j                  d	       |	j                  t        ||d
j                  d |D                           |
j                  |        | j                  ||      }|r&||
vr"|	j!                  dt        ||d| d             |	rt#        |	|xs |	d   j$                        S 	 |sy| j                  ||      }t#        t        ||      g|      S # t&        $ r t(        j+                  dd       Y Pw xY w)z;Return the ACP model selector payload for editors like Zed.r   rY   r  N
openrouterr   )curated_models_for_providernormalize_providerprovider_label
Provider: r  u    • c              3  &   K   | ]	  }|s|  y wr    r   s     rg   r   z4HermesACPAgent._build_model_state.<locals>.<genexpr>d  s     0U$PT0Us   )model_idr`   r   u    • current)available_modelscurrent_model_idzCould not build ACP model stateTr   )r(  r`   )r   r   r   agentr]   r<   hermes_cli.modelsr"  r#  r$  setr  r   r"   r   addinsertr1   r(  r   r   debug)r  r  r   r  r"  r#  r$  normalized_providerprovider_namer)  seen_idsr(  r   rendered_model	choice_id
desc_partsr*  fallback_choices                     rg   _build_model_statez!HermesACPAgent._build_model_stateG  s)   EKKJ75;;#DJKQQS5;;
D9^_=N^R^.	Kii"4X">*+>?M02!$H)DEX)Y (%+!$X^!4!:!:!<% 556I>Z	( *=/:;
%%c+&6&<&<&>?!U*%%i0 ''!*+$+LL0U*0U$U Y''(*  $889LeT$4H$D ''!1"&0|$L  (%5%5%U9I!9L9U9U    33HeD 'uMN,
 	
  	KLL:TLJ	Ks   )EG) ) HHc                    |}| j                         }	 ddlm}m}  |||      \  }}||k(  r |||      }|r|\  }}||fS # t        $ r t
        j                  dd       Y ||fS w xY w)zKResolve ``provider:model`` input into the provider and normalized model id.r   )detect_provider_for_modelparse_model_inputz,Provider detection failed, using model as-isTr   )r]   r,  r:  r;  r   r   r0  )r  current_providertarget_provider	new_modelr:  r;  detecteds          rg   _resolve_model_selectionz'HermesACPAgent._resolve_model_selection  s     +OO%			XV):9FV)W&OY"224Y@PQ19.OY 	))  	XLLGRVLW	))	Xs   )A  A'&A'c           	        | j                   }t        |dd      }t        t        |dd      xs d      }|dk  ry	 ddlm}  || j
                  t        |dd      xs dt        |dd      xs d	      }t        dt        |d      t        |d            S # t        $ r4 t        j                  d
d       t        t        |dd      xs d      }Y ^w xY w)a  Build ACP native context-usage data for clients like Zed.

        Zed's circular context indicator is driven by ACP ``usage_update``
        session updates: ``size`` is the model context window and ``used`` is
        the current request pressure.  Hermes estimates ``used`` from the same
        buckets it sends to providers: system prompt, conversation history, and
        tool schemas.
        context_compressorNcontext_lengthr   estimate_request_tokens_rough_cached_system_promptrY   r   system_promptr   z+Could not estimate ACP native context usageTr   last_prompt_tokensusage_update)session_updater   used)r+  r   intagent.model_metadatarE  historyr   r   r0  r8   max)r  r+  
compressorr   rE  rL  s         rg   _build_usage_updatez"HermesACPAgent._build_usage_update  s     U$8$?
7:'7;@qA19
	JJ0%e-DbIOReWd3;tD )T1T1
 	
	  	JLLFQULVwz+?CHqID	Js   9B :CCc                  K   | j                   sy| j                  |      }|y	 | j                   j                  |j                  |       d{    y7 # t        $ r% t
        j                  d|j                  d       Y yw xY ww)z6Send ACP native context usage to the connected client.N
session_idupdatez.Failed to send ACP usage update for session %sTr   )r  rR  rK  rU  r   r   r   )r  r  rV  s      rg   _send_usage_updatez!HermesACPAgent._send_usage_update  s     zz))%0>
	**++ ++ ,     	NN@    	s:   "B*A AA BA +BBBBc                    	 t        | j                  j                         |||      S # t        $ r t        j                  d|d       Y yw xY w)zBBest-effort ``_meta.hermes.sessionProvenance`` for an ACP session.)previous_hermes_session_idz-Could not build ACP session provenance for %sTr   N)rC   r  _get_dbr   r   r0  )r  acp_session_idcurrent_hermes_session_idrY  s       rg   _provenance_metazHermesACPAgent._provenance_meta  s^    	*$$,,.)+E	   	LL?Z^   		s   &) !AAr\  rY  c                 K   | j                   sy	 | j                  j                         j                  |      }|sy|j                  d      }t        j                  t        j                        j                         }| j                  ||xs ||      }t        dt        |t               r|j#                         r|nd||      }	 | j                   j%                  ||       d{    y# t        $ r t
        j                  d|d       Y yw xY w7 ,# t        $ r t
        j                  d	|d       Y yw xY ww)
a*  Send ACP native session metadata after Hermes changes it.

        When the internal Hermes head rotated (e.g. compression-driven session
        split during a turn), pass ``previous_hermes_session_id`` so the
        attached ``_meta.hermes.sessionProvenance`` flags the rotation reason.
        Nz&Could not read ACP session info for %sTr   rb   session_info_update)rK  rb   
updated_at
field_metarT  z-Could not send ACP session info update for %s)r  r  rZ  get_sessionr   r   r0  r{   r   nowr   utc	isoformatr]  r-   r   r   r]   rK  )	r  rU  r\  rY  rowrb   ra  metarV  s	            rg   _send_session_info_updatez(HermesACPAgent._send_session_info_update  s2     zz	&&..0<<ZHC  
 \\(,,/99;
$$%3&

 #0%eS1ekkm%!	
	e**++% ,   1  	LLA:X\L]	0  	eLLH*_cLd	es^   D>)C. BD> D (D)D -D>.!DD>DD>D !D;8D>:D;;D>c                    | j                   syt        j                         }|j                  t        j                  | j                  |             y)z>Schedule native context indicator refresh after ACP responses.N)r  asyncioget_running_loop	call_sooncreate_taskrW  )r  r  loops      rg   _schedule_usage_updatez%HermesACPAgent._schedule_usage_update  s9    zz'')w**D,C,CE,JKri   c                L  K   |sy	 ddl m} i }|D ]  }|j                  }t        |t              rQ|j
                  t        |j                        |j                  D ci c]  }|j                  |j                   c}d}n<|j                  |j                  D ci c]  }|j                  |j                   c}d}|||<    t        j                  ||       d{    	 dd	lm}	 dd
lm}
 t-        t/        |j0                  dd      xs dg|D cg c]  }|j                   c}      }||j0                  _        t/        |j0                  dd      } |	||d      |j0                  _        |j0                  j4                  xs g D ch c]
  }|d   d    c}|j0                  _         |
|j0                         t/        |j0                  dd      }t9        |      r |        t        j;                  d|j"                  t=        |j0                  j4                  xs g              yc c}w c c}w 7 X# t        $ r% t        j!                  d|j"                  d       Y yw xY wc c}w c c}w # t        $ r% t        j!                  d|j"                  d       Y yw xY ww)zERegister ACP-provided MCP servers and refresh the agent tool surface.Nr   )register_mcp_servers)commandargsenv)r   headersz.Session %s: failed to register ACP MCP serversTr   get_tool_definitionsinject_memory_provider_toolsenabled_toolsets
hermes-acp)mcp_server_namesdisabled_toolsets)r{  r~  
quiet_modefunctionr`   _invalidate_system_promptzHSession %s: refreshed tool surface after ACP MCP registration (%d tools)zESession %s: failed to refresh tool surface after ACP MCP registration)tools.mcp_toolrr  r`   r   r!   rs  listrt  ru  valuer   rv  rk  	to_threadr   r   r   rU  model_toolsrx  agent.memory_managerrz  rF   r   r+  r{  r   valid_tool_namescallabler  r   )r  r  mcp_serversrr  
config_mapserverr`   itemconfigrx  rz  r{  r~  tool
invalidates                  rg   _register_session_mcp_serversz,HermesACPAgent._register_session_mcp_servers  s[     	;*,J% *{{fn5#)>> $V[[ 1BH**M$		4:: 5MF  &zzFLnn#UdDIItzz$9#UF $*
4 * ##$8*EEE 	8I;%7>P<.<G!H&&++!H  ,<EKK( '5H$ O 4!1"3!EKK 6;[[5F5F5L",-1Z (,EKK( )5 .I4PJ
#KKZ  EKK%%+,Q  N
 $V F 	NN@    
 	 "I,  	NNW    	s   J$AH8 H+
;H8 H08%H8 H5H8 #0I3 I)
&A&I3 I.BI3 *J$+H8 8+I&#J$%I&&J$)
I3 3+J!J$ J!!J$c                |  K   t        |t              r|nt        j                  }t	               }|r|j
                  nd}t        j                  d||       t        t        j                  t        dt              t        dt        d      t        t               t               t!                           |	      S w)
Nr   z!Initialize from %s (protocol v%s)zhermes-agent)r`   r   T)image)forkr  resume)load_sessionprompt_capabilitiessession_capabilities)protocol_version
agent_infoagent_capabilitiesauth_methods)r   rM  acpPROTOCOL_VERSIONr;   r`   r   r  r   r   HERMES_VERSIONr   r$   r+   r,   r.   r2   )r  r  client_capabilitiesclient_infokwargsresolved_protocol_versionr  client_names           rg   
initializezHermesACPAgent.initializea  s      !++;S AsG[G[ 	" *+*5k&&9/%	
 " 11%>>R0!$6T$B%8020246&  &
 	
s   B:B<c                   K   t        |t              sy |j                         j                         }t	               }|t
        k(  r|r
t               S d S |r||k7  ry t               S wr   )r   r   r]   rn   r<   r:   r   )r  	method_idr  normalized_methodr  s        rg   authenticatezHermesACPAgent.authenticate  sf      )S)%OO-335"$ == .6')?4?,8#%%s   A#A%c                    t        | t              r| j                         S t        | t              rg }| D ]  }t        |t              r}|j                  d      }t        |t              r|j                  |       F|j                  d      dk(  s[t        |j                  d      t              s{|j                  |d          t        |t              s|j                  |        dj                  d |D              j                         S y)a  Normalize a persisted text-or-text-parts value into a single string.

        OpenAI-style assistant content (and provider reasoning fields) can arrive
        as either a scalar string or a list of ``{"text": ...}`` /
        ``{"type": "text", "content": ...}`` parts. Whitespace-only inputs
        collapse to an empty string so callers can treat ``""`` as "nothing to
        emit".
        r   r   contentr   c              3  d   K   | ](  }|s|j                         s|j                          * y wr   )r]   r   s     rg   r   z7HermesACPAgent._flatten_history_text.<locals>.<genexpr>  s      Udt

TZZ\Us   000rY   )r   r   r]   r  dictr{   r   r   )r  r   r  r   s       rg   _flatten_history_textz$HermesACPAgent._flatten_history_text  s     eS!;;= eT"!E 'dD)88F+D!$,T*&)V3
488ICVX[8\T)_5c*LL&' 99UeUU[[]]ri   c                B    | j                  |j                  d            S )z?Extract displayable text from a persisted OpenAI-style message.r  r  r{   )clsmessages     rg   _history_message_textz$HermesACPAgent._history_message_text  s     ((Y)?@@ri   c                ^    dD ](  }| j                  |j                  |            }|s&|c S  y)u  Extract displayable reasoning/thought text from a persisted assistant message.

        Returns the first non-empty value among ``reasoning_content`` (the
        canonical field used by DeepSeek / Moonshot and the post-#16892
        chat-completions normalizer) and ``reasoning`` (used by the codex
        event projector and several other transports). Both keys are
        actively written by live code paths, so neither branch is
        deprecated — they cover different transports rather than old vs.
        new sessions.
        )reasoning_content	reasoningrY   r  )r  r  keyr   s       rg   _history_reasoning_textz&HermesACPAgent._history_reasoning_text  s9     6 	C,,W[[-=>D	 ri   c                f    t        d|      }| dk(  rt        d|      S | dk(  rt        d|      S y)	z@Build an ACP history replay update for a user/assistant message.r   r   useruser_message_chunk)rK  r  	assistantagent_message_chunkN)r4   r9   r   )roler   r   s      rg   _history_message_updatez&HermesACPAgent._history_message_update  sL     !f486>#3  ;$4  ri   c                ,    t        j                  |       S )z<Build an ACP history replay update for an assistant thought.)r  update_agent_thought_text)r   s    rg   _history_thought_updatez&HermesACPAgent._history_thought_update  s     ,,T22ri   c                   t        | j                  d      t              r| j                  d      ni }t        |j                  d      xs | j                  d      xs d      }|j                  d      xs( | j                  d      xs | j                  d      xs i }t        |t              r	 t	        j
                  |      }|}t        |t              si }||fS # t        $ r d|i}Y 'w xY w)z?Extract function name/arguments from an OpenAI-style tool_call.r  r`   unknown_tool	argumentsrt  r   )r   r{   r  r   jsonloadsr   )	tool_callr  r`   raw_argsre   s        rg   _history_tool_call_name_argsz+HermesACPAgent._history_tool_call_name_args  s     1;9==;TVZ0[9==,ac8<<'R9==+@RNS<<,i	k0Jiimm\bNcigih$+H- H(D)HX~  +*+s   0C C-,C-c                    t        | j                  d      xs( | j                  d      xs | j                  d      xs d      j                         S )z?Return the stable provider tool call id for ACP history replay.r  call_idtool_call_idrY   )r   r{   r]   )r  s    rg   _history_tool_call_idz$HermesACPAgent._history_tool_call_id  sR     MM$ }}Y'}}^, 	

 %'	ri   c           	     "   K    j                   rj                  syi }d fd}j                  D ]G  }t        |j                  d      xs d      }|dk(  r; j	                  |      }|r' j                  ||      }| ||       d{   s yb|dk(  r j                  |      }|r! | j                  |             d{   s y j	                  |      }|r' j                  ||      }| ||       d{   s y|j                  d      }	t        |	t              re|	D ]`  }
t        |
t              s j                  |
      }|s( j                  |
      \  }}||f||<    |t        |||             d{   r_  y ]|d	k(  sdt        |j                  d
      xs d      j                         }t        |j                  d      xs d      j                         }d}||v r|j                  |      \  }}|r|s|j                  d      }t        |t              r|nd} |t!        ||||             d{   s y|dk(  s't#        |      }|6 ||       d{   rH y y7 7 7 7 7 >7 w)u  Replay persisted user/assistant history during session/load or session/resume.

        Invoked inline (``await``) from both ``load_session`` and
        ``resume_session`` so that spec-compliant ACP clients receive the
        full transcript within the request's lifetime — see the comment at
        the call sites for the rationale and prior-art citations.

        Replays the conversation as user/assistant chunks, thinking-mode
        thought chunks, plus reconstructed tool-call start/completion
        notifications. Merely restoring server-side state makes Hermes
        remember context, but leaves the editor looking like a clean thread.
        Nc                   K   	 j                   j                  j                  |        d {    y7 # t        $ r% t        j                  dj                  d       Y yw xY ww)NrT  Tz+Failed to replay ACP history for session %sr   F)r  rK  rU  r   r   r   )rV  r  r  s    rg   _sendz5HermesACPAgent._replay_session_history.<locals>._send  sl     	jj//5;K;KTZ/[[[ \ A$$!  
 s1   A(*7 57 A(7 +A%"A($A%%A(r  rY   r  )r  r   r  
tool_callsr  r  	tool_namer  )resultfunction_argstodo)rV  r
   returnbool)r  rO  r   r{   r  r  r  r  r   r  r  r  r  rH   r]   poprG   r=   )r  r  active_tool_callsr  r  r  r   rV  thoughtr  r  r  r  rt  r  r  result_textplan_updates   ``                rg   _replay_session_historyz&HermesACPAgent._replay_session_history  s     zzCE
	 }} :	Gw{{6*0b1Dv~11':!99t$9OF)f2E2E{"66w?t/K/KG/T)U#U#U11':!99t$9OF)f2E2E$[[6
j$/%/ 	#	))T:$'+'A'A)'L+$*.*K*KI*V	4;Dd:K),7%*+;L)UY+Z%[[["	# v~"7;;~#>#D"EKKMK 8 >B?EEG	7;#44/@/D/D\/R,I}#9 Y/(263(?fT"'$!*&3	   &"Ek"RK".U;=O7O7Ou:	 3F $V 3F  \ 8Ps   B	JI?9JJ9JJBJJJ
JB5JJJJ)J4J5J;JJJJJJc                  K   | j                   j                  |      }| j                  ||       d {    t        j	                  d|j
                  |       | j                  |j
                         | j                  |       t        |j
                  | j                  |      | j                  |      | j                  |j
                  t        |j                  d|j
                                    S 7 w)Nr  zNew session %s (cwd=%s)rU  )rU  modelsmodesrb  )r  create_sessionr  r   r  rU  #_schedule_available_commands_updaterp  r#   r8  r  r]  r   r+  )r  r  r  r  r  s        rg   new_sessionzHermesACPAgent.new_sessionY  s      $$333<00DDD-u/?/?E001A1AB##E*!''**51%%e,,,  '%++|UEUEU"V	
 	
	 	Es   2C8C6CC8c                D  K   | j                   j                  ||      }|t        j                  d|       y | j	                  ||       d {    t        j                  d|       	 | j                  |       d {    | j                  |       | j                  |       t        | j                  |      | j                  |      | j                  |t        |j                  d|                  S 7 7 y# t        $ r t        j                  d|d       Y w xY ww)Nz"load_session: session %s not foundzLoaded session %sus   ACP history replay raised during session/load for %s — load will still succeed, partial transcript may be missingTr   rU  r  r  rb  )r  
update_cwdr   r   r  r  r  r   r  rp  r   r8  r  r]  r   r+  r  r  rU  r  r  r  s         rg   r  zHermesACPAgent.load_sessionm  s     $$//
C@=NN?L00DDD'4	..u555 	00<##E*"**51%%e,,,GEKKzJ
 	
9 	E 6 	 NNM	  	sI   AD C5D )C9 =C7>C9 A4D 7C9 9!DD DD c                  K   | j                   j                  ||      }|2t        j                  d|       | j                   j	                  |      }| j                  ||       d {    t        j                  d|j                         	 | j                  |       d {    | j                  |j                         | j                  |       t        | j                  |      | j                  |      | j                  |j                  t!        |j"                  d|j                                    S 7 7 # t        $ r% t        j                  d|j                  d       Y w xY ww)	Nz2resume_session: session %s not found, creating newr  zResumed session %suw   ACP history replay raised during session/resume for %s — resume will still succeed, partial transcript may be missingTr   rU  r  )r  r  r   r   r  r  r  rU  r  r   r  rp  r&   r8  r  r]  r   r+  r  s         rg   resume_sessionzHermesACPAgent.resume_session  sH     $$//
C@=NNOQ[\((77C7@E00DDD(%*:*:;	..u555 	001A1AB##E*$**51%%e,,,  '%++|UEUEU"V
 	
! 	E 6 	NNO  	  	sI   A&E-(D8)$E-D< "D:#D< 'BE-:D< <+E*'E-)E**E-c                   K   | j                   j                  |      }|r|j                  r|j                  5  |j                  r|j
                  r|j
                  |_        d d d        |j                  j                          	 t        |dd       r0t        |j                  d      r|j                  j                          t        j                  d|       y y y # 1 sw Y   zxY w# t        $ r t        j                  d|d       Y Hw xY ww)Nr+  	interruptz"Failed to interrupt ACP session %sTr   zCancelled session %s)r  rc  cancel_eventruntime_lock
is_runningcurrent_prompt_textinterrupted_prompt_textr-  r   r   r+  r  r   r   r0  r  )r  rU  r  r  s       rg   cancelzHermesACPAgent.cancel  s     $$00<U''## N##(A(A494M4ME1N ""$^5'40WU[[+5VKK))+ KK.
; (5N N  ^A:X\]^s@   6D*C""D=C' DC$ D'!DD
DDc                f  K   | j                   j                  ||      }|r|j                  nd}|| j                  ||       d {    t        j                  d||       |r| j                  |       t        ||| j                  |      nd || j                  |            S d       S 7 gw)Nr  rY   zForked session %s -> %s)rU  r  r  )
r  fork_sessionrU  r  r   r  r  r   r8  r  )r  r  rU  r  r  r  new_ids          rg   r  zHermesACPAgent.fork_session  s      $$11*#1F%*!!44UKHHH-z6B44V<"5:5F4**51D050A$%%e,
 	
 HL
 	
	 Is   AB1B/A(B1c           
       K   | j                   j                  |      }|r't        |      D ]  \  }}|d   |k(  s||dz   d } n g }t        |      t        kD  }|dt         }g }|D ]c  }|j                  d      }	|	t        |	t              st        |	      }	|j                  t        |d   |d   |j                  d      |	             e |r|r|d	   j                  nd}
t        ||

      S w)a  List ACP sessions with optional ``cwd`` filtering and cursor pagination.

        ``cwd`` is passed through to ``SessionManager.list_sessions`` which already
        normalizes and filters by working directory. ``cursor`` is a ``session_id``
        previously returned as ``next_cursor``; results resume after that entry.
        Server-side page size is capped at ``_LIST_SESSIONS_PAGE_SIZE``; when more
        results remain, ``next_cursor`` is set to the last returned ``session_id``.
        r  rU  rl   Nra  r  rb   )rU  r  rb   ra  )sessionsnext_cursor)r  list_sessions	enumerater   _LIST_SESSIONS_PAGE_SIZEr{   r   r   r   r3   rU  r   )r  cursorr  r  infosidxshas_morer  ra  r  s              rg   r  zHermesACPAgent.list_sessions  s     $$22s2;#E* Q\?f,!#'(OE u: 88//0 	A|,J%jS.I _
OO %%%.)			 2:hhrl--D#X;OOs   8C/B4C/c                h   "#$%&'()*+,-./012K    j                   j                        //"t        j                  d       t	        d      S t        |      j                         2t        |      1t        d |D              }t        2      xs t        1t              xr t        1      }|st	        d      S |rt        1t              r2j                  d      rt        2j                  d	            dkD  r#2j                  d	      d   j                         nd
}d
}d}/j                   5  /j"                  s$|r"/j$                  r/j$                  }d
/_        nd}ddd       |r
| d| 221n|r|2|1|rt        1t              r2j                  d      r~ j'                  2/      }	|	j j(                  rRt+        j,                  |	      }
 j(                  j/                  |
       d{     j1                  /       d{    t	        d      S /j                   5  /j"                  r2xs d}/j2                  j5                  |       t        /j2                        } j(                  r=t+        j,                  d| d      }
 j(                  j/                  |
       d{    t	        d      cddd       S d/_        2xs d/_        ddd       t        j9                  d2dd         j(                  &t;        j<                         */j>                  r/j>                  jA                          tC        tD              }i }d,d'd0&r~tG        &*|| /fd      }tI        &*      }tK        &*||      }tM        &*      +d?+0fd}tO        &jP                  *      %	 ddl)m*}  |&jP                  * /fd      'n
d}d}d}d}d%/jZ                  $|$_.        d$_/        |$_0        |$_1        |$_2        d,d)d(d-d@$%'(),-/12fd}	 tg        /jZ                  dd      }ti        jj                         }*jm                  tn        |jp                  |       d{   ..ju                  d!      r%.d!   /_;         j                   jy                         tg        /jZ                  dd      }&r&|r$|r"||k7  r	  j{                  ||"       d{    .ju                  d$d
      }t        /j>                  xr /j>                  j}                               }t        .ju                  d%            xs |}dd&l?m@} |xr |j                  |      }|r|s	 dd'lAmB} dA&* fd(}tg        /jZ                  d)d      "tg        /jZ                  d*d      # | j                   j                         2|/jv                  tg        /jZ                  d)d      tg        /jZ                  d*d      tg        /jZ                  d+d      tg        /jZ                  d,d      tg        /jZ                  d-d      d."#/fd/|0       |rF&rD|sB0r.ju                  d2      r/t+        j,                  |      }
&j/                  |
       d{    /j                   5  d/_        d
/_        ddd       	 /j                   5  /j2                  s
	 ddd       nz/j2                  j                  d      }ddd       &r-&j/                  t+        j                               d{     j                  t        d3      g4       d{    d} t        .fd5d6D              r^t        .ju                  d7d      .ju                  d8d      .ju                  d9d      .ju                  d:      .ju                  d;      <      }  j1                  /       d{    |rd=nd}!t	        |!| >      S # 1 sw Y   xY w7 7 7 f# 1 sw Y   ?xY w# tV        $ r t        jY                  dd       Y dw xY w7 # tV        $ rU t        js                  d        /j                   5  d/_        d
/_        ddd       n# 1 sw Y   nxY wt	        d      cY S w xY w7 # tV        $ r t        jY                  d#d       Y w xY w# tV        $ r t        jY                  d1d       Y w xY w7 g# 1 sw Y   LxY w# 1 sw Y   xY w7 7 7 <w)BzERun Hermes on the user's prompt and stream events back to the editor.Nzprompt: session %s not foundrefusal)stop_reasonc              3  <   K   | ]  }t        |t                y wr   )r   r4   )r   r   s     rg   r   z(HermesACPAgent.prompt.<locals>.<genexpr>$  s     Wuz%1ABWs   end_turnz/steerrl   maxsplitrY   FTz,

User correction/guidance after interrupt: r   [Image attachment]Queued for the next turn. ( queued)zPrompt on session %s: %sd   c                 &     j                        S r   r  r  r  s   rg   <lambda>z'HermesACPAgent.prompt.<locals>.<lambda>  s    D4X4XY^4_ ri   )edit_approval_policy_getterr   c                    | rd |        y )NTr'  )r   
message_cbstreamed_messages    rg   stream_delta_cbz.HermesACPAgent.prompt.<locals>.stream_delta_cb  s    '+$4 ri   r   ) make_acp_edit_approval_requesterc                 &     j                        S r   r  r  s   rg   r  z'HermesACPAgent.prompt.<locals>.<lambda>  s    0T0TUZ0[ ri   )auto_approve_getterz,Could not create ACP edit approval requesterr   c                    	 ddl m} m}  |      }	r(	 ddlm} |j                         |j                  	       
r	 dd	l
m}  |
      t        d      t        j                  j                  d      t        j                  d<   	 j!                  j"                  xs d      }|t%               !t        j                  j'                  dd        nt        j                  d<   	r	 ddlm} |j                         	 ddl
m}  |       || 
	  | |       S S S # t        $ r d }d } t        j                  dd       Y Bw xY w# t        $ r t        j                  dd       Y ?w xY w# t        $ r t        j                  d
d       Y Uw xY w# t        $ r t        j                  dd       Y w xY w# t        $ r t        j                  dd       Y w xY w# t        $ r t        j                  dd       Y S w xY w# t        $ r#}t        j+                  d       d| j"                  dcY d }~t%               !t        j                  j'                  dd        nt        j                  d<   	r?	 ddlm} |j                         n&# t        $ r t        j                  dd       Y nw xY w6	 ddl
m}  |       n&# t        $ r t        j                  dd       Y nw xY w|3| 0	  | |       S # t        $ r t        j                  dd       Y S w xY wS S d }~ww xY w# t%               !t        j                  j'                  dd        nt        j                  d<   	r?	 ddlm} |j                         n&# t        $ r t        j                  dd       Y nw xY w6	 ddl
m}  |       n&# t        $ r t        j                  dd       Y nw xY w|3| 0	  | |       w # t        $ r t        j                  dd       Y w w xY ww w xY w)Nr   )clear_session_varsset_session_vars)session_keyz!Could not set ACP session contextTr   )terminal_toolz#Could not set ACP approval callback)set_edit_approval_requesterz)Could not set ACP edit approval requesterHERMES_SESSION_IDr
  )user_messageconversation_historytask_idpersist_user_messagez#Could not restore approval callback)reset_edit_approval_requesterz-Could not restore ACP edit approval requesterz#Could not clear ACP session contextzAgent error in session %szError: )final_responsemessages)gateway.session_contextr  r  r   r   r0  r   r  _get_approval_callbackset_approval_callbackacp_adapter.edit_approvalr  rJ   osenvironr{   run_conversationrO  rI   r  r%  	exception)r  r  session_tokens_terminal_toolr  r  r%  er+  approval_cbedit_approval_requesteredit_approval_tokeninteractive_tokenprevious_approval_cbprevious_session_idrU  r  user_content	user_texts           rg   
_run_agentz)HermesACPAgent.prompt.<locals>._run_agent  si   	Q "2j!I
 WE+9+P+P+R("88E ']U*EF]*^' !?t D #%**..1D"E.8BJJ*+%[//!-).&)2)J6J	 0   %045FG&.JJNN#6=6IBJJ23[I&<<=QR '2e[56IJ "-2D2P[*>: 3Q-  Q!%%)"@4PQ ! WLL!FQULVW ! ]LL!LW[L\]L % [%JUYZ[ % e%T_cde
 % [%JUYZ[9  T  !<jI,3A3-U]]SS %045FG&.JJNN#6=6IBJJ23[I&<<=QR$ [%JUYZ[&2e[56IJ$ e%T_cde!-2D2P[*>:$ [%JUYZ[ 3Q-3T
 %045FG&.JJNN#6=6IBJJ23[I&<<=QR$ [%JUYZ[&2e[56IJ$ e%T_cde!-2D2P[*>:$ [%JUYZ[ 3Q-s=  D/ 'E F $H 7F(G$G4/$EE E>=E> F%$F%( G
G G10G14 HH
M$'MMM
 J.. KKK&& L	L	L L=<L=MM
 
AP=N)(P=) O	P=OP=O! P=! PP=PP=PP= P85P=7P88P=rU  zExecutor error for session %sr'  r^  z:Could not emit ACP provenance update after rotation for %sr&  interrupted)"INTERRUPT_WAITING_FOR_MODEL_PREFIX)maybe_auto_titlec                j    r0j                  t        j                  j                               y y r   )call_soon_threadsaferk  rn  ri  )_titler  ro  r  rU  s    rg   _notify_title_updatez3HermesACPAgent.prompt.<locals>._notify_title_updateM  s0    11#// :::F ri   r   r  base_urlapi_keyapi_mode)r   r  rC  rD  rE  c                 p    t        j                  dd        k(  xr t        j                  dd       k(  S )Nr   r  )r   r+  )_title_model_title_providerr  s   rg   r  z'HermesACPAgent.prompt.<locals>.<lambda>f  s8    Wd;|K V#EKKTBoU ri   )main_runtimeruntime_validatortitle_callbackz#Failed to auto-title ACP session %sresponse_transformedr   )r   rU  c              3  D   K   | ]  }j                  |      d u  y wr   r   )r   r  r  s     rg   r   z(HermesACPAgent.prompt.<locals>.<genexpr>  s     msvzz#d*ms    )prompt_tokenscompletion_tokenstotal_tokensrN  rO  rP  reasoning_tokenscache_read_tokens)input_tokensoutput_tokensrP  thought_tokenscached_read_tokens	cancelled)r  usage)r   r   r  None)r  r  )rA  r   r  rY  )Jr  rc  r   errorr%   r   r]   r   r   r  r   r  r   ro   r   rm   r  r  r  _handle_slash_commandr  r  update_agent_message_textrK  rW  queued_promptsr   r  r  rk  rl  r  clearr   r   rA   r@   r?   r>   rB   request_permissionr+  r  r   r0  r+  tool_progress_callbackthinking_callbackreasoning_callbackstep_callbackstream_delta_callbackr   contextvarscopy_contextrun_in_executor	_executorrunr/  r{   rO  save_sessionri  is_setagent.conversation_loopr=  agent.title_generatorr>  rZ  r  update_user_message_textr   r4   anyr7   )3r  r   rU  r  text_only_prompthas_content
steer_textinterrupted_promptrewrite_idleresponse_textrV  queued_textdepthtool_call_idstool_call_metatool_progress_cbreasoning_cbstep_cbr  r  r;  pre_turn_hermes_idctxpost_turn_hermes_idr&  rW  r<  r=  suppress_interrupt_responser>  rB  next_promptrX  r  rG  rH  r+  r3  r  r4  r5  r6  ro  r  r7  r8  r  r  r  r9  r:  s3   ` `                               @@@@@@@@@@@@@@@@@rg   r   zHermesACPAgent.prompt  s	     $$00<=LL7D!i88!&)//1	=fEWPVWW9o 
|T*AtL/A 	 !j99 
< =)BVBVW_B`CFy`aGbCcfgCg!4Q7==?moJ!# L## ,''J44-2-J-J*8:5'+, ")* +AAKN   )&	) 
< =)BVBVWZB[ 66y%HM(:: ::=IF**33JGGG11%888%*==  	J'?+?$$++K8E001:: ::5eWHEF **33JGGG%*=	J 	J  $E(1(I5IE%	J 	.
IdsOLzz'')$$&/:5/A46#"& 4,_  ,D*dCL"4T=.YG(z4@J! 11H1H$PZ[K
\V*J++([	+'  $LG"OK'7$ #'#/ %&5#  $ ""Q	[ Q	[f	:
 ")lD!I
 **,C//	377JOOF ::j!":.EM  --j9 &ekk<F#"#'9944.A/A 5     $4b9++K0B0B0I0I0KL	6::m45B 	O&1 '
n6O6O.7
# "=#_B   'u{{GTB")%++z4"H ((002"MM!(gt!D$+EKKT$J$+EKKT$J#*5;;	4#H$+EKKT$J"' $8#, /%4J)K 22>BF%%j&999
  	+$E(*E%	+ ## :++: : $2266q9: ))00=   ++(f;GH%      m6lmm#ZZ;$jj)<a@#ZZ:%zz*<=#)::.A#BE %%e,,,%.kJ+UCCG, ,4 H8  H	J 	Jt  \KVZ[\F P 	:<jI## /#( ,.)/ / / "j99	:0
  P!  h  _BJY]^_ :
	+ 	+
: :
 	-s  D$d291`*Bd2;`<d2`d21B`!8`9`!
d2`!$Cd2 `. "Ad25Aa aa 	Ad2"b< 9b9:b< >B d2?C#c$ "Ad2%d&d26dd2d(	d21d2d2>d)?&d2%d,&Bd23d/4d2`	d2d2`!!`+&d2. ad2ad2a +b6b	b6b$	 b63d25b66d29b< <!c!d2 c!!d2$!d	d2d		d2dd2d&!	d2,d2/d2c           
         g }| j                   D ]D  }|j                  d      }|j                  t        |d   |d   |rt	        |      nd              F |S )Nr   r`   r   )hint)r`   r   input)_ADVERTISED_COMMANDSr{   r   r   r6   )r  commandsspecr   s       rg   _available_commandsz"HermesACPAgent._available_commands  sd    +-,, 
	D,/JOO f $] 3! 3
C
	 ri   c                   K   | j                   sy	 | j                   j                  |t        d| j                                      d{    y7 # t        $ r t
        j                  d|d       Y yw xY ww)z?Advertise supported slash commands to the connected ACP client.Navailable_commands_update)rK  available_commandsrT  z5Failed to advertise ACP slash commands for session %sTr   )r  rK  r   r  r   r   r   )r  rU  s     rg   _send_available_commands_updatez.HermesACPAgent._send_available_commands_update  sz     zz	**++%.#>'+'?'?'A ,     	NNG  	s:   A99A 
AA A9A !A63A95A66A9c                    | j                   syt        j                         }|j                  t        j                  | j                  |             y)zDSend the command advertisement after the session response is queued.N)r  rk  rl  rm  rn  r  )r  rU  ro  s      rg   r  z2HermesACPAgent._schedule_available_commands_update  s<    zz'')!E!Ej!Q	
ri   c           
     "   |j                  d      }|d   j                  d      j                         }t        |      dkD  r|d   j	                         nd}| j
                  | j                  | j                  | j                  | j                  | j                  | j                  | j                  | j                  d	j                  |      }|y	  |||      S # t        $ r+}t         j#                  d||d	
       d| d| cY d}~S d}~ww xY w)zDispatch a slash command and return the response text.

        Returns ``None`` for unrecognized commands so they fall through
        to the LLM (the user may have typed ``/something`` as prose).
        rl   r  r   r   rY   r   NzSlash command /%s error: %sTr   zError executing /: )rm   r   rn   r   r]   	_cmd_help
_cmd_model
_cmd_tools_cmd_context
_cmd_reset_cmd_compact
_cmd_steer
_cmd_queue_cmd_versionr{   r   r   rZ  )r  r   r  r   cmdrt  handlerr2  s           rg   r[  z$HermesACPAgent._handle_slash_command  s     

A
&Ahooc"((*#&u:>uQx~~r NN____((__((____((

 #c( 	 ?	24'' 	2LL6QLN&se2aS11	2s   C 	D# D	D	Dc                    ddg}| j                   j                         D ]  \  }}|j                  d|dd|         |j                  d       |j                  d       dj                  |      S )NzAvailable commands:rY   z  /10s  z@Unrecognized /commands are sent to the model as normal messages.r   )_SLASH_COMMANDSitemsr   r   )r  rt  r  linesr  descs         rg   r  zHermesACPAgent._cmd_help  sq    &+--335 	2ICLL3s3ir$01	2RWXyyri   c                N   |sH|j                   xs t        |j                  dd      }t        |j                  dd       xs d}d| d| S t        |j                  dd       xs d}| j                  ||      \  }}||_         | j                  j                  |j                  |j                  ||      |_        | j                  j                  |j                         t        |j                  dd       xs |xs |}t        j                  d	|j                  |       d
| d| S )Nr   r   r  autozCurrent model: z
Provider: r!  )rU  r  r   requested_providerz Session %s: model switched to %szModel switched to: )r   r   r+  r@  r  _make_agentrU  r  rj  r   r  )	r  rt  r  r   r  r<  r=  r>  r$  s	            rg   r  zHermesACPAgent._cmd_model  s   KKK75;;#KEu{{J=GH$UG<zBB"5;;
DAQ\%)%B%B4IY%Z"**66''		.	 7 
 	))%*:*:; j$?f?fVf68H8H)T$YK|N;KLLri   c           
        	 ddl m} ddlm} ddlm} t        t        |j                  dd       xs dg      } ||d      } |t        |xs g       |xs g D ch c]3  }t        |t              r!|j                  d	i       j                  d
      5 c}|t        |j                  dd             }	 ||	       |	j                  }|sydt        |       dg}
|D ]s  }|j                  d	i       j                  d
d      }|j                  d	i       j                  dd      }t        |      dkD  r|d d dz   }|
j                  d| d|        u dj!                  |
      S c c}w # t"        $ r}d| cY d }~S d }~ww xY w)Nr   rw  )SimpleNamespacery  r{  r|  T)r{  r  r  r`   _memory_manager)r   r  r{  r  zNo tools available.zAvailable tools (z):?r   rY   P   M   ...r  r  r   zCould not list tools: )r  rx  typesr  r  rz  rF   r   r+  r  r   r  r{   r   r   r   r   r   )r  rt  r  rx  r  rz  toolsetsr   r  	tool_viewr  tr`   r  r2  s                  rg   r  zHermesACPAgent._cmd_tools  s   !	08-I3%7>P<.H )(tTE'5;B' !&"!$- HHZ,008"
 "* '5F M	I )3OOE,(UB78E 2uuZ,00=uuZ,00Ct9r>9u,Dr$r$012 99U##)"*  	0+A3//	0s7   AE' 8E"
5E' 	BE' "E' '	E?0E:4E?:E?c                   t        |j                        }i }|j                  D ],  }|j                  dd      }|j                  |d      dz   ||<   . |j                  }|j                  xs t        |dd      }t        |dd      xs d	}	t        |d
d      }
t        t        |
dd      xs d      }t        t        |
dd      xs d      }	 ddlm} t        |dd      xs d}t        |dd      xs d} ||j                  ||      }|dk  r|dkD  rt        |dz        }|rd| dndd|j                  dd       d|j                  dd       d|j                  dd       d|j                  dd       g}|r|j                  d |        |j                  d!|	        |dkD  rB|dkD  r'||z  d"z  }|j                  d#|d$d%|d$d&|d'd(       n|j                  d#|d$d)       |dkD  r|dkD  rq|dkD  r||z  d"z  nd}t        ||z
  d      }||k\  r%|j                  d*|d$|rd+|d,d-ndz   d.z          n?|j                  d/|d$d0|d$|rd+|d,d-ndz   d1z          n|j                  d2|d$d)       t        |d3d      d4u r|j                  d5       n|j                  d6       d7j                  |      S # t        $ r t        j                  dd       d}Y w xY w)8z;Show ACP session context pressure and compression guidance.r  r   r   rl   r   rY   r  Nr  rB  rC  threshold_tokensrD  rF  r   rG  z$Could not estimate ACP context usageTr   g?zConversation: z	 messagesz(Conversation is empty (no messages yet).z  user: r  z, assistant: r  z, tool: r  z
, system: systemzModel: r%  r  zContext usage: ~,z / z	 tokens (z.1fz%) tokensz!Compression: due now (threshold ~z, z.0f%z). Run /compact.zCompression: ~z tokens until threshold (~z).zCompression threshold: ~compression_enabledFz'Compression is disabled for this agent.z<Tip: run /compact to compress manually before the threshold.r   )r   rO  r{   r+  r   r   rM  rN  rE  r   r   r0  r   rP  r   )r  rt  r  
n_messagesrolesmsgr  r+  r   r  rQ  rC  r  rE  rH  r   approx_tokensr  	usage_pctthreshold_pct	remainings                        rg   r  zHermesACPAgent._cmd_context/  s   '
 !#== 	1C7769-D))D!,q0E$K	1 :wugr:5*d3=vU$8$?
WZ1A1EJKwz3EqINQO	J#E+BBGM2ME7D19TE9+M q ^a%7">D#89  ZL	2;uyy+,M%))KQR:S9T UYYvq)**UYYx5K4LN	
 LL75'*+z(,-1!*^;sB	&}Q&7s>!:LIV_`cUddfg /a/@HIaq M[^_M_!1N!Bc Ief 0= @!D	 $44LL;<LQ;OP8ERc2!42O,- LL(1 6-a028ERc2!42O  78H7K7ST5/6%?LLBCLLWXyyi  	LL?$LOM	s   =J? ?"K%$K%c                   |j                   j                          d}	 t        |j                  dd       }t	        |      r |        | j                  j                  |j                         |ryy# t
        $ r' d}t        j                  d|j                  d       Y Xw xY w# | j                  j                  |j                         w xY w)NFreset_session_stateTz%ACP session state reset failed for %sr   zIConversation history cleared. Agent session state reset failed; see logs.zConversation history cleared.)rO  r^  r   r+  r  r   r   r   rU  r  rj  )r  rt  r  reset_failedr  s        rg   r  zHermesACPAgent._cmd_reset  s    	@")%++7Ld"S+,#%
   --e.>.>?^.  	eLNNBEDTDT_cNd	e   --e.>.>?s#   )A0 0-B B# B  B# #'C
c           	        |j                   sy	 |j                  }t        |dd      syt        |d      syddlm} t        |j                         }t        |d	d
      xs d
}t        |dd       xs d } ||j                   ||      }t        |dd       }		 d |_        |j                  |j                   t        |d	d
      xs d
||j                        \  }
}|	|_        |
|_         | j                  j                  |j                         t        |j                         }t        |d	d
      xs |}t        |dd       xs |} ||j                   ||      }d| d| d|dd|dd	S # |	|_        w xY w# t        $ r}d| cY d }~S d }~ww xY w)Nu.   Nothing to compress — conversation is empty.r  Tz/Context compression is disabled for this agent._compress_contextz1Context compression not available for this agent.r   rD  rF  rY   r   rG  _session_db)r  r#  zContext compressed: z -> z messages
~r  z -> ~r  zCompression failed: )rO  r+  r   r   rN  rE  r   r  r  rU  r  rj  r   )r  rt  r  r+  rE  original_count_sys_prompt_toolsr  original_session_db
compressed_	new_count_sys_prompt_after_tools_after
new_tokensr2  s                    rg   r  zHermesACPAgent._cmd_compact  s   }}C0	.KKE5"7>H5"56JJ /N "%)@"EKKUGT2:dF9[M #*%"E8 %)! % 7 7MME#:B?E2"/!,,	 !8 !
A %8!&EM  --e.>.>?EMM*I '/F K Z{"5'48BFL6/"J '~&6d9+ F!!$E*Qw@ %8!"  	.)!--	.sB   E4 E4 AE4 AE( BE4 (	E11E4 4	F=FFFc                   |j                         }|sy|j                  rPt        |j                  d      r:	 |j                  j	                  |      r|d d t        |      dkD  rdndz   }d| S 	 |j                  5  |j                  j                  |       t        |j                        }d d d        d	 d
S # t        $ r0}t        j                  d|j                  |       d| cY d }~S d }~ww xY w# 1 sw Y   KxY w)NzUsage: /steer <guidance>r   r  r  rY   u&   ⏩ Steer queued for the active turn: z#ACP steer failed for session %s: %su   ⚠️ Steer failed: u.   No active turn — queued for the next turn. (r  )r]   r  r   r+  r   r   r   r   r   rU  r  r]  r   )r  rt  r  rr  previewr   rw  s          rg   r  zHermesACPAgent._cmd_steer  s    ZZ\
-W =5;;$$Z0("o#j/B:NTVWGCG9MM 1  	.  ''
3,,-E	. @whOO  5DeFVFVX[\.se445	. 	.s)   7B; <1C7;	C4%C/)C4/C47D c                    |j                         }|sy|j                  5  |j                  j                  |       t	        |j                        }d d d        d dS # 1 sw Y   xY w)NzUsage: /queue <prompt>r  r  )r]   r  r]  r   r   )r  rt  r  rv  rw  s        rg   r  zHermesACPAgent._cmd_queue  sf    jjl+ 	.  ''4,,-E	. -UG8<<	. 	.s   1AA(c                    dt          S )NzHermes Agent v)r  )r  rt  r  s      rg   r  zHermesACPAgent._cmd_version  s    /00ri   c                J  K   | j                   j                  |      }|rt        |j                  dd      }| j	                  ||xs d      \  }}||_        t        |xr ||k7        }|rdnt        |j                  dd      }	|rdnt        |j                  dd      }
| j                   j                  ||j                  |||	|
      |_        | j                   j                  |       t        j                  d|||       t               S t        j                  d|       yw)	z8Switch the model for a session (called by ACP protocol).r  Nr!  rC  rE  )rU  r  r   r  rC  rE  z0Session %s: model switched to %s via provider %sz6Session %s: model switch requested for missing session)r  rc  r   r+  r@  r   r  r  r  rj  r   r  r(   r   )r  r(  rU  r  r  r<  r  resolved_modelprovider_changedcurrent_base_urlcurrent_api_modes              rg   set_session_modelz HermesACPAgent.set_session_model  s'     $$00<&u{{JE151N1N 0L2. )EK#$4$_9KO_9_`'7tWU[[R\^b=c'7tWU[[R\^b=c..::%II$#5)) ; EK   --j9KKB"	 +,,OQ[\s   D!D#c                r  K   | j                   j                  |      }|t        j                  d|       yt	        |xs d      j                         }|| j                  vr| j                  }t        |d|       | j                   j                  |       t        j                  d||       t               S w)zNPersist the editor-requested mode so ACP clients do not fail on mode switches.Nz5Session %s: mode switch requested for missing sessionrY   r
  zSession %s: mode switched to %s)r  rc  r   r   r   r]   r  r  setattrrj  r  r)   )r  mode_idrU  r  r  normalized_modes         rg   set_session_modezHermesACPAgent.set_session_mode  s      $$00<=NNRT^_gm,224$"D"DD"00Ov/))*55z?S%''s   B5B7c                  K   | j                   j                  |      }|t        j                  d|       yt	        |      | j
                  k(  r=| j                  j                  t	        |      | j                        }t        |d|       n:t        |dd      }t        |t              si }||t	        |      <   t        |d|       | j                   j                  |       t        j                  d||       t        g       S w)zVAccept ACP config option updates even when Hermes has no typed ACP config surface yet.Nz7Session %s: config update requested for missing sessionr
  config_optionsz$Session %s: config option %s updated)r  )r  rc  r   r   r   _EDIT_APPROVAL_POLICY_CONFIG_ID_EDIT_APPROVAL_POLICY_TO_MODEr{   r  r  r   r   r  rj  r  r'   )r  	config_idrU  r  r  r  r
  optionss           rg   set_config_optionz HermesACPAgent.set_config_option  s      $$00<=NNTV`ay>TAAA5599#e*dFXFXYDE64(e%5t<Ggt,&+GC	N#E+W5))*5:J	R-R@@s   DDr   )r  zSessionManager | None)r  z
acp.Clientr  rY  )r  rE   r  r0   )r  rE   r  ztuple[str, str | None])r  
str | Noner   r  r  r   )r  rE   r  zSessionModelState | None)r  r   r<  r   r  ztuple[str, str])r  rE   r  zUsageUpdate | None)r  rE   r  rY  )r[  r   r\  r   rY  Optional[str]r  zOptional[dict])rU  r   r\  r  rY  r  r  rY  )r  rE   r  z:list[McpServerStdio | McpServerHttp | McpServerSse] | Noner  rY  )NNN)
r  z
int | Noner  zClientCapabilities | Noner  zImplementation | Noner  r
   r  r   )r  r   r  r
   r  zAuthenticateResponse | None)r  r
   r  r   )r  dict[str, Any]r  r   )r  r   r   r   r  z+UserMessageChunk | AgentMessageChunk | None)r   r   r  r   )r  r  r  ztuple[str, dict[str, Any]])r  r  r  r   )r  r   r  list | Noner  r
   r  r#   )
r  r   rU  r   r  r  r  r
   r  zLoadSessionResponse | None)
r  r   rU  r   r  r  r  r
   r  r&   )rU  r   r  r
   r  rY  )
r  r   rU  r   r  r  r  r
   r  r   NN)r  r  r  r  r  r
   r  r   )r   tlist[TextContentBlock | ImageContentBlock | AudioContentBlock | ResourceContentBlock | EmbeddedResourceContentBlock]rU  r   r  r
   r  r%   )r  zlist[AvailableCommand])rU  r   r  rY  )r   r   r  rE   r  r  )rt  r   r  rE   r  r   )r(  r   rU  r   r  r
   r  zSetSessionModelResponse | None)r  r   rU  r   r  r
   r  zSetSessionModeResponse | None)
r  r   rU  r   r  r   r  r
   r  z%SetSessionConfigOptionResponse | None)?__name__
__module____qualname____doc__r  r  r  r  r  r  r  r  r  r  r   r  r  r  staticmethodr  r8  r@  rR  rW  r]  ri  rp  r  r  r  r  classmethodr  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  r[  r  r  r  r  r  r  r  r  r  r  r  r  __classcell__)r   r  r  r  s   000@rg   r   r     s1   ; */'3-2HH(
O 4	

 N3	
 C	

 E	

 7	

 :	

 R8	
 R.	
 0	
I(T '=#$)!M'Nu/	%! &C%H%H%J% %!sEs
%!0,
B!
 - -<
| * *$ 
 
B. 59	 $' %2	
 
0 4848.e.e $1	.e
 %2.e 
.e`LEE PE 
	EV (,9=-1	 
$ 
 7 
 +	 

  
 
 
D&0  2 A A  "   
5	 & 3 3    Xz $(

 !
 	

 

0 $(	-
-
 -
 !	-

 -
 
$-
f $(	!
!
 !
 !	!

 !
 
!
F<$ $(	

 
 !	

 
 

, "+P+P +P 	+P
 
+P^ND
ND ND ND 
NDd  (
2> M*"0HO b/ 3.jP&=1
  ), 8; 	' D(((+(7:(	&( AA*-A69AEHA	.Ag0%s   #G.r   r  )ra   r   r`   r  rb   r  r  r   )rs   r  r  r  )r_   r	   r  r  )r   bytesrs   r   r  r   )ra   r   r  zPath | None)r   r  rs   r  r  r  )ra   r   r   r   r`   r  rb   r  r   r  r  r   )r   r*   r  list[dict[str, Any]])r   r   r  r  )r   r  r  r   )r   r   r  zdict[str, Any] | None)r   r  r  zstr | list[dict[str, Any]])yr  
__future__r   rk  r   r   r   re  r  loggingr,  collectionsr   r   concurrent.futuresr   pathlibr	   typingr
   r   r   urllib.parser   r   r  
acp.schemar   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   acp_adapter.authr:   r;   r<   acp_adapter.eventsr=   r>   r?   r@   rA   acp_adapter.permissionsrB   acp_adapter.provenancerC   acp_adapter.sessionrD   rE   rF   acp_adapter.toolsrG   rH   tools.approvalrI   rJ   	getLoggerr  r   
hermes_clirK   r  r   rh  r  r   rp   rq   rh   ru   rw   r|   r   r   r   r   r   r   r   r   r   Agentr   r'  ri   rg   <module>r     s   N "  '     	 * 1  ' ' * 
, , , , , , , , , , , ,\ ` _  ; : Z Z C
 
		8	$8
 1M	
  $ ) 	 >^%

O F	2  -	- - 	-
 - - 	-`F.b 	&< 00  0fjASYY jAY  Ns   >E; ;FF