
    iV                       d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlmZ ddlmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ d
ZdZ ej        dej                  Z ej        dej                  Zd5dZd6dZd5dZ d7dZ!d8dZ"d9dZ#	 	 	 d:d;d%Z$d<d'Z%d=d*Z&d>d.Z' G d/ d0          Z( G d1 d2          Z) G d3 d4          Z*dS )?at  OpenAI-compatible shim that forwards Hermes requests to `copilot --acp`.

This adapter lets Hermes treat the GitHub Copilot ACP server as a chat-style
backend. Each request starts a short-lived ACP session, sends the formatted
conversation as a single prompt, collects text chunks, and converts the result
back into the minimal shape Hermes expects from an OpenAI client.
    )annotationsN)deque)Path)SimpleNamespace)Any)get_read_block_erroris_write_denied)redact_sensitive_textzacp://copilotg      @z&<tool_call>\s*(\{.*?\})\s*</tool_call>zd\{\s*\"id\"\s*:\s*\"[^\"]+\"\s*,\s*\"type\"\s*:\s*\"function\"\s*,\s*\"function\"\s*:\s*\{.*?\}\s*\}returnstrc                     t          j        dd                                          p(t          j        dd                                          pdS )NHERMES_COPILOT_ACP_COMMAND COPILOT_CLI_PATHcopilot)osgetenvstrip     =/home/ubuntu/.hermes/hermes-agent/agent/copilot_acp_client.py_resolve_commandr   "   sL    
	.3399;; 	9',,2244	r   	list[str]c                     t          j        dd                                          } | sddgS t          j        |           S )NHERMES_COPILOT_ACP_ARGSr   z--acpz--stdio)r   r   r   shlexsplit)raws    r   _resolve_argsr   *   sC    
)-r
2
2
8
8
:
:C $##;sr   c                    	 ddl m}   |             }|r|S n# t          $ r Y nw xY wt          j                            dd                                          }|r|S t          j                            d          }|r|dk    r|S 	 ddl	}|
                    t          j                              j                                        }|r|S n# t          $ r Y nw xY wdS )z-Return a stable HOME for child ACP processes.r   )get_subprocess_homeHOMEr   ~Nz/tmp)hermes_constantsr!   	Exceptionr   environgetr   path
expanduserpwdgetpwuidgetuidpw_dir)r!   profile_homehomeexpandedr*   resolveds         r   _resolve_home_dirr2   1   s!   888888**,, 	 	     :>>&"%%++--D w!!#&&H HOO


<<	,,399;; 	O	    6s    
$$AC 
CCdict[str, str]c                 d    t           j                                        } t                      | d<   | S )Nr"   )r   r&   copyr2   )envs    r   _build_subprocess_envr7   T   s'    
*//

C#%%CKJr   
message_idr   codeintmessagedict[str, Any]c                    d| ||ddS )N2.0)r9   r;   )jsonrpciderrorr   )r8   r9   r;   s      r   _jsonrpc_errorrB   Z   s'    
 
  r   c                    d| dddiidS )Nr>   outcome	cancelledr?   r@   resultr   )r8   s    r   _permission_deniedrH   e   s)    ;
  r   messageslist[dict[str, Any]]model
str | Nonetoolslist[dict[str, Any]] | Nonetool_choicec           	     h   g d}|r|                     d|            t          |t                    r|r
g }|D ]}t          |t                    s|                    d          pi }t          |t                    sE|                    d          }t          |t
                    r|                                s|                     |                                |                    dd          |                    di           d           |r,|                     d	t          j        |d
          z              |,|                     dt          j        |d
                      g }	| D ]}
t          |
t                    st          |
                    d          pd                                          	                                }|dk    rd}n|dvrd}|
                    d          }t          |          }|sdddddd                    ||                                          }|	                     | d|            |	r+|                     dd                    |	          z              |                     d           d                    d |D                       S )N)z>You are being used as the active ACP agent backend for Hermes.z'Use ACP capabilities to complete tasks.zIMPORTANT: If you take an action with a tool, you MUST output tool calls using <tool_call>{...}</tool_call> blocks with JSON exactly in OpenAI function-call shape.z&If no tool is needed, answer normally.zHermes requested model hint: functionnamedescriptionr   
parameters)rR   rS   rT   zAvailable tools (OpenAI function schema). When using a tool, emit ONLY <tool_call>{...}</tool_call> with one JSON object containing id/type/function{name,arguments}. arguments must be a JSON string.
Fensure_asciizTool choice hint: roleunknowntool>   usersystem	assistantcontextcontentSystemUser	AssistantToolContext)r[   rZ   r\   rY   r]   z:
zConversation transcript:

z

z7Continue the conversation from the latest user request.c              3  j   K   | ].}||                                 |                                 V  /d S Nr   ).0sections     r   	<genexpr>z-_format_messages_as_prompt.<locals>.<genexpr>   s<      ^^7'^gmmoo^w}}^^^^^^r   )append
isinstancelistdictr'   r   r   jsondumpslower_render_message_contenttitlejoin)rI   rK   rM   rO   sections
tool_specstfnrR   
transcriptr;   rW   r^   renderedlabels                  r   _format_messages_as_promptr{   q   s	     H  A???@@@% 5 +-
 	 	Aa&& z""(bBb$'' 66&>>DdC(( 

  JJLL#%66-#<#<"$&&r":":      	OOb *Ze<<<=   ZTZRW-X-X-XZZ[[[J 3 3'4(( 	7;;v&&3)44::<<BBDD6>>DD888D++i((*733 	 $ 
 
 #dDJJLL
!
! 	 	U11x112222 R6Z9P9PPQQQOOMNNN;;^^h^^^^^^r   r^   c                   | dS t          | t                    r|                                 S t          | t                    rd| v r6t          |                     d          pd                                          S d| v r^t          |                     d          t                    r6t          |                     d          pd                                          S t          j        | d          S t          | t                    rg }| D ]}t          |t                    r|                    |           -t          |t                    re|                    d          }t          |t                    r;|                                r'|                    |                                           d	                    |                                          S t          |                                           S )Nr   textr^   TrU   
)
rk   r   r   rm   r'   rn   ro   rl   rj   rs   )r^   partsitemr}   s       r   rq   rq      s   r'3 }}'4   6Ww{{6**0b1177999Jw{{9/E/Es$K$Kw{{9--344::<<<z'5555'4   	( 	/ 	/D$$$ /T""""D$'' /xx''dC(( /TZZ\\ /LL...yy%%'''w<<r   r}   !tuple[list[SimpleNamespace], str]c                   t          | t                    r|                                 sg dfS g g }dfd}t                              |           D ]]}|                    d          } ||           |                    |                                |                                f           ^sxt                              |           D ]]}|                    d          } ||           |                    |                                |                                f           ^|s|                                 fS |
                                 g }|D ]^\  }}|r||d	         d         k    r|                    ||f           1|d	         d         t          |d	         d         |          f|d	<   _g }d}	|D ]8\  }}|	|k     r|                    | |	|                    t          |	|          }	9|	t          |           k     r|                    | |	d                     d
                    d |D                                                       }
|
fS )Nr   raw_jsonr   r   Nonec                   	 t          j        |           }n# t          $ r Y d S w xY wt          |t                    sd S |                    d          }t          |t                    sd S |                    d          }t          |t                    r|                                sd S |                    dd          }t          |t                    st          j        |d          }|                    d          }t          |t                    r|                                sdt                    d	z    }
                    t          ||d dt          |                                |
                               d S )NrQ   rR   	argumentsz{}FrU   r@   	acp_call_   )rR   r   )r@   call_idresponse_item_idtyperQ   )rn   loadsr%   rk   rm   r'   r   r   ro   lenrj   r   )r   objrw   fn_namefn_argsr   	extracteds         r   _try_add_tool_callz9_extract_tool_calls_from_text.<locals>._try_add_tool_call   s   	*X&&CC 	 	 	FF	#t$$ 	FWWZ  "d## 	F&&..'3'' 	w}} 	F&&d++'3'' 	>ju===G''$--'3'' 	5w}} 	54#i.."244G!%(gmmooQQQ  	
 	
 	
 	
 	
s    
&&r   r   r~   c              3  j   K   | ].}||                                 |                                 V  /d S re   rf   )rg   ps     r   ri   z0_extract_tool_calls_from_text.<locals>.<genexpr>  s<      DDaAD!''))D		DDDDDDr   )r   r   r   r   )rk   r   r   _TOOL_CALL_BLOCK_REfinditergrouprj   startend_TOOL_CALL_JSON_REsortmaxr   rs   )r}   consumed_spansr   mr   mergedr   r   r   cursorcleanedr   s              @r   _extract_tool_calls_from_textr      s   dC   

 2v')I,.N
 
 
 
 
 
< !))$// 4 4ggajj3qwwyy!%%''23333  8#,,T22 	8 	8A''!**Cs###!!17799aeegg"67777 '$**,,&&$&F$ B B
s 	BA..MM5#,'''' *Q-VBZ]C)@)@AF2JJEF " "
sE>>LLfUl+,,,VS!!D		T&'']###iiDD5DDDDDJJLLGgr   	path_textcwdr   c                T   t          |           }|                                st          d          |                                }t          |                                          }	 |                    |           n)# t
          $ r}t          d| d| d          |d }~ww xY w|S )Nz'ACP file-system paths must be absolute.zPath 'z' is outside the session cwd 'z'.)r   is_absolutePermissionErrorresolverelative_to
ValueError)r   r   	candidater1   rootexcs         r   _ensure_path_within_cwdr     s    YI  "" IGHHH  ""H99DbT"""" b b bWxWWtWWWXX^aabOs   )A? ?
B%	B  B%c                      e Zd Zd	dZd
dZdS )_ACPChatCompletionsclient'CopilotACPClient'c                    || _         d S re   )_clientselfr   s     r   __init__z_ACPChatCompletions.__init__,  s    r   kwargsr   r   c                &     | j         j        di |S )Nr   )r   _create_chat_completion)r   r   s     r   createz_ACPChatCompletions.create/  s    3t|3==f===r   Nr   r   )r   r   r   r   )__name__
__module____qualname__r   r   r   r   r   r   r   +  s<           > > > > > >r   r   c                      e Zd ZddZdS )_ACPChatNamespacer   r   c                .    t          |          | _        d S re   )r   completionsr   s     r   r   z_ACPChatNamespace.__init__4  s    .v66r   Nr   )r   r   r   r   r   r   r   r   r   3  s(        7 7 7 7 7 7r   r   c            	      \    e Zd ZdZdddddddddd-dZd.dZddddddd/dZd0d#Zd1d,ZdS )2CopilotACPClientz8Minimal OpenAI-client-compatible facade for Copilot ACP.N)api_keybase_urldefault_headersacp_commandacp_argsacp_cwdcommandargsr   rL   r   r   dict[str, str] | Noner   r   list[str] | Noner   r   r   _r   c                  |pd| _         |pt          | _        t          |pi           | _        |p|pt                      | _        t          |p|pt                                | _	        t          t          |pt          j                                                                        | _        t!          |           | _        d| _        d | _        t)          j                    | _        d S )Ncopilot-acpF)r   ACP_MARKER_BASE_URLr   rm   _default_headersr   _acp_commandrl   r   	_acp_argsr   r   r   getcwdr   _acp_cwdr   chat	is_closed_active_process	threadingLock_active_process_lock)
r   r   r   r   r   r   r   r   r   r   s
             r   r   zCopilotACPClient.__init__;  s     /- 7$7 $_%: ; ;'H7H6F6H6HhA$A-//BBD!7BIKK88@@BBCC%d++	=A$-N$4$4!!!r   r   r   c                <   | j         5  | j        }d | _        d d d            n# 1 swxY w Y   d| _        |d S 	 |                                 |                    d           d S # t
          $ r+ 	 |                                 Y d S # t
          $ r Y Y d S w xY ww xY w)NT   timeout)r   r   r   	terminatewaitr%   kill)r   procs     r   closezCopilotACPClient.closeS  s	   & 	( 	('D#'D 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( <F	NNIIaI      	 	 			   	s5   #''*A& &
B1B
BBBB)rK   rI   r   rM   rO   rK   rI   rN   r   float | NonerM   rO   c                   t          |pg |||          }t          }n^t          t          t          f          rt	                    }n2fddD             }	d |	D             }
|
rt          |
          nt          }|                     ||          \  }}t          |          \  }}t          dddt          d                    }t          |||pd |pd d 	          }|rd
nd}t          ||          }t          |g||pd          S )N)rK   rM   rO   c                2    g | ]}t          |d           S re   )getattr)rg   attrr   s     r   
<listcomp>z<CopilotACPClient._create_chat_completion.<locals>.<listcomp>}  s5        t,,  r   )readwriteconnectpoolr   c                d    g | ]-}t          |t          t          f          t          |          .S r   )rk   r:   float)rg   vs     r   r   z<CopilotACPClient._create_chat_completion.<locals>.<listcomp>  s1    UUUQAU|9T9TUaUUUr   )timeout_secondsr   )cached_tokens)prompt_tokenscompletion_tokenstotal_tokensprompt_tokens_details)r^   
tool_calls	reasoningreasoning_contentreasoning_detailsr   stop)r;   finish_reasonr   )choicesusagerK   )	r{   _DEFAULT_TIMEOUT_SECONDSrk   r:   r   r   _run_promptr   r   )r   rK   rI   r   rM   rO   r   prompt_text_effective_timeout_candidates_numericresponse_textreasoning_textr   cleaned_textr  assistant_messager  choices      `               r   r   z(CopilotACPClient._create_chat_completiond  s    1N#	
 
 
 ?!9#u.. 
	Y!&w   K  K VU+UUUH2:!XX@X(,(8(8. )9 )
 )
%~
 $A#O#O 
L"1"B"B"B	
 
 
 , !$,,4"
 
 
 )3> ):-XXXH(=
 
 
 	
r   r  r   r   r   tuple[str, str]c                   	 t          j         j        g j        z   t           j        t           j        t           j        dd j        t                                n+# t          $ r}t          d j         d          |d }~ww xY wj	        j
        #                                 t          d          d _         j        5   _        d d d            n# 1 swxY w Y   t          j                    t#          d	          d+fd}d+fd}t%          j        |d          }t%          j        |d          }|                                 |                                 dd d dd, fd}	  |ddddddidddd d!            |d" j        g d#          pi }	t+          |	                    d$          pd%                                          }
|
st          d&          g }g } |d'|
d(|d)gd*||           d%                    |          d%                    |          f                                  S #                                   w xY w)-NTr   )stdinstdoutstderrr}   bufsizer   r6   z%Could not start Copilot ACP command 'zQ'. Install GitHub Copilot CLI or set HERMES_COPILOT_ACP_COMMAND/COPILOT_CLI_PATH.z6Copilot ACP process did not expose stdin/stdout pipes.F(   )maxlenr   r   c                     j         d S j         D ]d} 	                     t          j        |                      +# t          $ r-                     d|                     d          i           Y aw xY wd S )Nr   r~   )r  putrn   r   r%   rstrip)lineinboxr   s    r   _stdout_readerz4CopilotACPClient._run_prompt.<locals>._stdout_reader  s    {" : ::IIdj..////  : : :IIudkk$&7&7899999:: :s   '=4A43A4c                 ~    j         d S j         D ]*}                     |                     d                     +d S )Nr~   )r  rj   r  )r  r   stderr_tails    r   _stderr_readerz4CopilotACPClient._run_prompt.<locals>._stderr_reader  sN    {" 6 6""4;;t#4#455556 6r   )targetdaemonr   )
text_partsreasoning_partsmethodr   paramsr<   r"  r   r#  r   c               z   dz  }d|| |d}j                             t          j        |          dz              j                                          t          j                    z   }t          j                    |k     r։                                n	 
                    d          }n# t          j	        $ r Y Uw xY w
                    |j        ||          ry|                    d          |k    rd	|v rA|                    d	          pi }t          d
|  d|                    d          p|           |                    d          S d                                                              }	                                |	rt          d|	           t          d|  d          )Nr   r>   )r?   r@   r$  r%  r~   g?r   )processr   r"  r#  r@   rA   zCopilot ACP z	 failed: r;   rG   z"Copilot ACP process exited early: z.Timed out waiting for Copilot ACP response to .)r  r   rn   ro   flushtimepollr'   queueEmpty_handle_server_messager   RuntimeErrorrs   r   TimeoutError)r$  r%  r"  r#  
request_idpayloaddeadlinemsgerrstderr_textr  next_idr   r   r  r   s             r   _requestz.CopilotACPClient._run_prompt.<locals>._request  s   qLG J    	 G JTZ0047888Jy{{_4H)++((99;;*))C)00CC{   H .. )$3 /    774==J..c>>'''**0bC&SvSS	8J8J8QcSS   wwx((())K006688Kyy{{&;&"#U#U#UVVVYPVYYYZZZs   B2 2CC
initializefs)readTextFilewriteTextFilezhermes-agentzHermes Agentz0.0.0)rR   rr   version)protocolVersionclientCapabilities
clientInfozsession/new)r   
mcpServers	sessionIdr   z'Copilot ACP did not return a sessionId.zsession/promptr}   )r   r}   )rB  promptr   r   )
r$  r   r%  r<   r"  r   r#  r   r   r   )
subprocessPopenr   r   PIPEr   r7   FileNotFoundErrorr/  r  r  r   r   r   r   r,  Queuer   r   Threadr   r   r'   r   rs   r   )r   r  r   r   r  r  
out_thread
err_threadr8  session
session_idr"  r#  r  r7  r   r  s   ` `          @@@@r   r  zCopilotACPClient._run_prompt  s   	#"#dn4 o!!M)++	 	 	DD ! 	 	 	a8I a a a  	 :!4IIKKKWXXX& 	( 	(#'D 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( .3[]]"'r"2"2"2	: 	: 	: 	: 	: 	: 	:	6 	6 	6 	6 	6 	6 	6 %^DIII
%^DIII
\`  GK +	[ +	[ +	[ +	[ +	[ +	[ +	[ +	[ +	[ +	[ +	[ +	[ +	[Z/	H'(,0-1 + !/!/#*# #   " h="$      W[[55;<<BBDDJ N"#LMMM$&J)+OH !+ %+$/   & /    77:&&(@(@@JJLLLLDJJLLLLs7   AA" "
B
,BB
C  C$'C$B9I I&r4  r<   r'  subprocess.Popen[str]r   r"  r#  boolc                  |                     d          }t          |t                    sdS |dk    r|                     d          pi }|                     d          pi }t          |                     d          pd                                          }	|                     d          pi }
d}t          |
t                    r$t          |
                     d	          pd          }|	d
k    r|r||                    |           n|	dk    r|r||                    |           dS |j        dS |                     d          }|                     d          pi }|dk    rt          |          }n|dk    r|	 t          t          |                     d          pd          |          }t          t          |                    }|rt          |          |                                r|                                nd}
|                     d          }|                     d          }t          |t                    r`|dk    rZ|
                    d          }|dz
  }t          |t                    r|dk    r||z   nd }d                    |||                   }
|
rt!          |
d          }
d|d|
id}nB# t"          $ r)}t%          |dt          |                    }Y d }~nd }~ww xY w|dk    r	 t          t          |                     d          pd          |          }t'          t          |                    rt          d| d          |j                            dd           |                    t          |                     d          pd                     d|d d}nJ# t"          $ r(}t%          |dt          |                    }Y d }~nd }~ww xY wt%          |dd| d           }|j                            t1          j        |          d!z              |j                                         dS )"Nr$  Fzsession/updater%  updatesessionUpdater   r^   r}   agent_message_chunkagent_thought_chunkTr@   zsession/request_permissionzfs/read_text_filer(   r  limitr   )keependsr   )forcer>   rF   izfs/write_text_filezWrite denied: 'z(' is a protected system/credential file.)parentsexist_okizACP client method 'z!' is not supported by Hermes yet.r~   )r'   rk   r   r   rm   rj   r  rH   r   r   r   exists	read_textr:   
splitlinesrs   r
   r%   rB   r	   parentmkdir
write_textr   rn   ro   r)  )r   r4  r'  r   r"  r#  r$  r%  rR  kindr^   
chunk_textr8   responser(   block_errorr  rV  linesr   r   r   s                         r   r.  z'CopilotACPClient._handle_server_message1  s    ""&#&& 	5%%%WWX&&,"FZZ))/RFvzz/228b99??AADjj++1rGJ'4(( < V!4!4!:;;
,,,,
@V!!*----...:./B]&&z2224= 4WWT]]
""(b111)*55HH***H.s6::f3E3E3K/L/LcRR23t99== 7)+666.2kkmmC$..***zz&))

7++dC(( 8TAXX#...==E 1HE+5eS+A+AYeaii%%--UYC ggeE#I&677G I3G4HHHG$$!7   H H H)*fc#hhGGH+++H.s6::f3E3E3K/L/LcRR"3t99-- )X$XXX   !!$!>>>FJJy$9$9$?R @ @AAA$$" 
  H H H)*fc#hhGGH &OfOOO H 	DJx0047888ts2   >EK 
K6K11K6 B:N; ;
O-O((O-)r   rL   r   rL   r   r   r   rL   r   r   r   rL   r   rL   r   r   r   r   rD  )rK   rL   rI   rN   r   r   rM   rN   rO   r   r   r   r   r   )r  r   r   r   r   r  )r4  r<   r'  rO  r   r   r"  r   r#  r   r   rP  )	r   r   r   __doc__r   r   r   r  r.  r   r   r   r   r   8  s        BB
 ##15"&%)""!%5 5 5 5 5 50   ( !04 $-1:
 :
 :
 :
 :
 :
xO O O ObU U U U U Ur   r   )r   r   )r   r   )r   r3   )r8   r   r9   r:   r;   r   r   r<   )r8   r   r   r<   )NNN)
rI   rJ   rK   rL   rM   rN   rO   r   r   r   )r^   r   r   r   )r}   r   r   r   )r   r   r   r   r   r   )+rf  
__future__r   rn   r   r,  rer   rE  r   r*  collectionsr   pathlibr   typesr   typingr   agent.file_safetyr   r	   agent.redactr
   r   r  compileDOTALLr   r   r   r   r2   r7   rB   rH   r{   rq   r   r   r   r   r   r   r   r   <module>rq     s    # " " " " "  				  				                       ! ! ! ! ! !       C C C C C C C C . . . . . .%    bj!JBIVV RZ  !H  JL  JS  T  T              F      	 	 	 	 )-	H_ H_ H_ H_ H_V       0F F F FT
 
 
 
> > > > > > > >7 7 7 7 7 7 7 7
N N N N N N N N N Nr   