
    `gjSh                       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mZ dd
lmZ ddlmZ dZdZ ej>                  dej@                        Z! ej>                  dej@                        Z"dZ#dZ$d%dZ%d&dZ&d'dZ'd&dZ(d(dZ)d)dZ*d*dZ+	 	 	 d+	 	 	 	 	 	 	 	 	 d,dZ,d-dZ-	 	 	 	 	 	 	 	 d.dZ.d/dZ/d0dZ0d1dZ1 G d d       Z2 G d! d"      Z3 G d# d$      Z4y)2at  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ChatCompletionMessageToolCallFunction)get_read_block_errorget_write_denied_error)redact_sensitive_text)hermes_subprocess_envz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*\})z
gh-copilot)zhas been deprecatedzno commands will be executedc                    | j                         t        fdt        D              syt        fdt        D              S )zHTrue iff stderr looks like the deprecated gh-copilot extension's banner.c              3  &   K   | ]  }|v  
 y wN ).0reqlowers     K/root/.hermes/venv/lib/python3.12/site-packages/agent/copilot_acp_client.py	<genexpr>z5_is_gh_copilot_deprecation_message.<locals>.<genexpr>9   s     =se|=   Fc              3  &   K   | ]  }|v  
 y wr   r   )r   markerr   s     r   r   z5_is_gh_copilot_deprecation_message.<locals>.<genexpr>;   s     B6vBr   )r   any_DEPRECATION_REQUIRED_DEPRECATION_MARKERS)stderr_textr   s    @r   "_is_gh_copilot_deprecation_messager   5   s7     E='<==B-ABBB    c                     t        j                  dd      j                         xs( t        j                  dd      j                         xs dS )NHERMES_COPILOT_ACP_COMMAND COPILOT_CLI_PATHcopilot)osgetenvstripr   r    r   _resolve_commandr)   >   sD    
		.399; 	99',224	r    c                     t        j                  dd      j                         } | 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/   F   s9    
))-r
2
8
8
:C##;;sr    c                 `   t         j                  j                  dd      j                         } | r| S t         j                  j                  d      }|r|dk7  r|S 	 ddl}|j                  t        j                               j                  j                         }|r|S 	 y# t        $ r Y yw xY w)z-Return a stable HOME for child ACP processes.HOMEr#   ~r   Nz/tmp)r&   environgetr(   path
expanduserpwdgetpwuidgetuidpw_dir	Exception)homeexpandedr7   resolveds       r   _resolve_home_dirr?   M   s    ::>>&"%++-Dww!!#&HHO<<		,3399;O    
 s   AB! !	B-,B-c                 X    t        d      } t               }|| d<   ddlm}  ||        | S )NT)inherit_credentialsr1   r   )apply_subprocess_home_env)r   r?   hermes_constantsrB   )envr<   rB   s      r   _build_subprocess_envrE   f   s/      D
9CDCK:c"Jr    c                    d| ||ddS )N2.0)codemessage)jsonrpciderrorr   )
message_idrH   rI   s      r   _jsonrpc_errorrN   r   s    
 r    c                    d| dddiidS )NrG   outcome	cancelledrJ   rK   resultr   )rM   s    r   _permission_deniedrT   }   s$    ;
 r    c           	        g d}|r|j                  d|        t        |t              r|rg }|D ]  }t        |t              s|j	                  d      xs i }t        |t              s:|j	                  d      }t        |t
              r|j                         sl|j                  |j                         |j	                  dd      |j	                  di       d        |r)|j                  d	t        j                  |d
      z          |)|j                  dt        j                  |d
              g }	| D ]  }
t        |
t              st        |
j	                  d      xs d      j                         j                         }|dk(  rd}n|dvrd}|
j	                  d      }t        |      }|s{ddddddj	                  ||j                               }|	j                  | d|         |	r#|j                  ddj                  |	      z          |j                  d       dj                  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)rW   rX   rY   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`   r_   ra   r^   rb   z:
zConversation transcript:

z

z7Continue the conversation from the latest user request.c              3  d   K   | ](  }|s|j                         s|j                          * y wr   r(   )r   sections     r   r   z-_format_messages_as_prompt.<locals>.<genexpr>   s      ^7'gmmow}}^   000)append
isinstancelistdictr4   strr(   jsondumpsr   _render_message_contenttitlejoin)messagesmodeltoolstool_choicesections
tool_specstfnrW   
transcriptrI   r\   rc   renderedlabels                  r   _format_messages_as_promptr      s-   H 7w?@%5+-
 	Aa&z"(bBb$'66&>DdC(

 JJL#%66-#<"$&&r":	  OOb **Ze<= ,TZZRW-X,YZ[J 3'4(7;;v&3)4::<BBD6>D88D++i(*73 $ 
 #dDJJL
! 	 	UG3xj12+3. 6Z9PPQOOMN;;^h^^^r    c                @   | yt        | t              r| j                         S t        | t              rd| v r,t        | j	                  d      xs d      j                         S d| v rKt        | j	                  d      t              r,t        | j	                  d      xs d      j                         S t        j                  | d      S t        | t              rg }| D ]  }t        |t              r|j                  |       %t        |t              s6|j	                  d      }t        |t              sX|j                         si|j                  |j                                 dj                  |      j                         S t        |       j                         S )Nr#   textrc   TrZ   
)
rn   rq   r(   rp   r4   rr   rs   ro   rm   rv   )rc   partsitemr   s       r   rt   rt      s>   '3}}'4 Ww{{6*0b17799Jw{{9/Es$Kw{{9-34::<<zz'55'4  	/D$$T"D$'xx'dC(TZZ\LL.	/ yy%%''w<r    c           
     8    t        | | ddt        ||            S )zDBuild an OpenAI-compatible tool-call object for downstream handling.NrV   rW   	arguments)rK   call_idresponse_item_idtyperV   r   r   rW   r   s      r   _build_openai_tool_callr      s'     )ty9 r    c                r   | j                   d   }|j                  }d}|j                  rg }t        |j                        D ]n  \  }}|j	                  t        |t        |dd      t        |dd      t        t        |j                  dd      t        |j                  dd            	             p t        d
|j                  xs d||j                  |j                        }t        t        d||j                        g| j                  d      }t        g | j                  | j                        }||gS )z@Convert a one-shot ACP response into OpenAI-style stream chunks.r   NrK   r   rV   rW   r   r   )indexrK   r   rV   ra   )r\   rc   
tool_callsreasoning_content	reasoning)r   deltafinish_reason)choicesrx   usage)r   rI   r   	enumeraterm   r   getattrrV   rc   r   r   r   rx   r   )	
completionchoicerI   tool_call_deltasr   	tool_callr   
data_chunkusage_chunks	            r   _completion_to_stream_chunksr      s@   "FnnG )'*<*< = 	E9##y$5 FJ?,$Y%7%7F"))*<*<k4"P	
	 '4#!33##E !$22
 
J "K
 $$r    c                   t        | t              r| j                         sg dfS g g }dfd}t        j	                  |       D ]J  }|j                  d      } ||       |j                  |j                         |j                         f       L sbt        j	                  |       D ]J  }|j                  d      } ||       |j                  |j                         |j                         f       L |s| j                         fS |j                          g }|D ]C  \  }}|r||d   d   kD  r|j                  ||f       '|d   d   t        |d   d   |      f|d<   E g }d}	|D ]*  \  }}|	|k  r|j                  | |	|        t        |	|      }	, |	t        |       k  r|j                  | |	d         dj                  d |D              j                         }
|
fS )	Nr#   c                f   	 t        j                  |       }t        |t              sy |j                  d      }t        |t              sy |j                  d      }t        |t              r|j                         sy |j                  dd      }t        |t              st        j                  |d      }|j                  d      }t        |t              r|j                         sdt              d	z    }j                  t        ||j                         |
             y # t        $ r Y y w xY w)NrV   rW   r   z{}FrZ   rK   	acp_call_   r   )rr   loadsr;   rn   rp   r4   rq   r(   rs   lenrm   r   )raw_jsonobjr~   fn_namefn_argsr   	extracteds         r   _try_add_tool_callz9_extract_tool_calls_from_text.<locals>._try_add_tool_call1  s    	**X&C #t$WWZ "d#&&.'3'w}}&&d+'3'jju=G''$-'3'w}}!#i."2!34G#]]_!	
#  		s   D$ $	D0/D0r   r   r   c              3  d   K   | ](  }|s|j                         s|j                          * y wr   rj   )r   ps     r   r   z0_extract_tool_calls_from_text.<locals>.<genexpr>m  s      DaA!'')	Drl   )r   rq   returnNone)rn   rq   r(   _TOOL_CALL_BLOCK_REfinditergrouprm   startend_TOOL_CALL_JSON_REsortmaxr   rv   )r   consumed_spansr   mr.   mergedr   r   r   cursorcleanedr   s              @r   _extract_tool_calls_from_textr   *  s   dC 

2v57I,.N
8 !))$/ 4ggaj3qwwy!%%'234 #,,T2 	8A''!*Cs#!!1779aeeg"67	8
 $**,&&$&F$ B
sA.MM5#,' *Q-VBZ]C)@AF2J	B EF "
sE>LLfU+,VS!" D	T&']#iiD5DDJJLGgr    c                   t        |       }|j                         st        d      |j                         }t        |      j                         }	 |j	                  |       |S # t
        $ r}t        d| d| d      |d }~ww xY w)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)	path_textcwd	candidater>   rootexcs         r   _ensure_path_within_cwdr   r  s    YI  "GHH  "H9DbT" O  bxj0NtfTVWX^aabs   A$ $	B-B  Bc                      e Zd ZddZddZy)_ACPChatCompletionsc                    || _         y r   )_clientselfclients     r   __init__z_ACPChatCompletions.__init__  s	    r    c                :     | j                   j                  di |S )Nr   )r   _create_chat_completion)r   kwargss     r   createz_ACPChatCompletions.create  s    3t||33=f==r    Nr   z'CopilotACPClient')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y)_ACPChatNamespacec                $    t        |      | _        y r   )r   completionsr   s     r   r   z_ACPChatNamespace.__init__  s    .v6r    Nr   )r   r   r   r   r   r    r   r   r     s    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dZdd	Z	 	 	 	 	 	 	 	 	 	 	 	 dd
Zy)CopilotACPClientz8Minimal OpenAI-client-compatible facade for Copilot ACP.N)api_keybase_urldefault_headersacp_commandacp_argsacp_cwdcommandargsc                  |xs d| _         |xs t        | _        t        |xs i       | _        |xs |xs
 t               | _        t        |xs |xs
 t                     | _	        t        t        |xs t        j                               j                               | _        t!        |       | _        d| _        d | _        t)        j*                         | _        y )Ncopilot-acpF)r   ACP_MARKER_BASE_URLr   rp   _default_headersr)   _acp_commandro   r/   	_acp_argsrq   r   r&   getcwdr   _acp_cwdr   chat	is_closed_active_process	threadingLock_active_process_lock)
r   r   r   r   r   r   r   r   r   _s
             r   r   zCopilotACPClient.__init__  s     /- 7$7 $_%: ;'H7H6F6HhA$A-/BD!7BIIK8@@BC%d+	=A$-NN$4!r    c                &   | j                   5  | j                  }d | _        d d d        d| _        y 	 |j                          |j	                  d       y # 1 sw Y   7xY w# t
        $ r$ 	 |j                          Y y # t
        $ r Y Y y w xY ww xY w)NT   timeout)r   r   r   	terminatewaitr;   kill)r   procs     r   closezCopilotACPClient.close  s    && 	(''D#'D 	( <	NNIIaI 	( 	(  			 	s4   A"A# A #	B-A??	BBBBF)rx   rw   r   ry   rz   streamc               ^   t        |xs g |||      }|t        }	n~t        |t        t        f      rt	        |      }	n\dD 
cg c]  }
t        ||
d        }}
|D cg c]$  }t        |t        t        f      st	        |      & }}|rt        |      nt        }	| j                  ||	      \  }}t        |      \  }}t        dddt        d            }t        |||xs d |xs d d       }|rdnd	}t        ||
      }t        |g||xs d      }|rt        |      S |S c c}
w c c}w )N)rx   ry   rz   )readwriteconnectpoolr   )timeout_secondsr   )cached_tokens)prompt_tokenscompletion_tokenstotal_tokensprompt_tokens_details)rc   r   r   r   reasoning_detailsr   stop)rI   r   r   )r   r   rx   )r   _DEFAULT_TIMEOUT_SECONDSrn   intfloatr   r   _run_promptr   r   r   )r   rx   rw   r   ry   rz   r  r   prompt_text_effective_timeoutattr_candidatesv_numericresponse_textreasoning_textr   cleaned_textr   assistant_messager   r   r   s                          r   r   z(CopilotACPClient._create_chat_completion  sh    1N#	
 ?!9#u.!&w L t,K  +6UQAU|9TaUHU2:X@X(,(8(8. )9 )
%~
 $A#O 
L"1"B	
 , !$,,4"
 )3 ):-X$H(=


 /
;;I Vs   D%D*9D*c                   	 t        j                   j                  g j                  z   t         j                  t         j                  t         j                  dd j
                  t                     j                  j                  j                          t        d      d _         j                  5   _        d d d        t        j                          t#        d	      d!fd
}d!fd}t%        j&                  |d      }t%        j&                  |d      }|j)                          |j)                          dd d dd" fd}	  |ddddddiddddd        |d j
                  g d      xs i }	t+        |	j-                  d      xs d      j/                         }
|
st        d      g }g } |d|
d|dgd ||       dj1                  |      dj1                  |      f j3                          S # t        $ r}t        d j                   d      |d }~ww xY w# 1 sw Y   uxY w#  j3                          w xY w)#NTr   )stdinstdoutstderrr   bufsizer   rD   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(   )maxlenc                     j                   y j                   D ]'  } 	 j                  t        j                  |              ) y # t        $ r% j                  d| j                  d      i       Y Xw xY w)Nr.   r   )r!  putrr   r   r;   rstrip)lineinboxr  s    r   _stdout_readerz4CopilotACPClient._run_prompt.<locals>._stdout_reader  sh    {{" ::IIdjj./: ! :IIudkk$&789:s   $A+A43A4c                     j                   y j                   D ]"  } j                  | j                  d             $ y )Nr   )r"  rm   r(  )r)  r  stderr_tails    r   _stderr_readerz4CopilotACPClient._run_prompt.<locals>._stderr_reader  s:    {{" 6""4;;t#456r    )targetdaemonr   )
text_partsreasoning_partsc               d   dz  }d|| |d}j                   j                  t        j                  |      dz          j                   j	                          t        j                         z   }t        j                         |k  rj                         n	 
j                  d      }j                  |j                  ||      r\|j                  d      |k7  rqd	|v r9|j                  d	      xs i }t        d
|  d|j                  d      xs |       |j                  d      S dj                        j                         }	j                         )|	r't!        |	      rt        d|	       t        d|	       t#        d|  d      # t        j                  $ r Y <w xY w)Nr   rG   )rJ   rK   methodparamsr   g?r   )processr   r1  r2  rK   rL   zCopilot ACP z	 failed: rI   rS   a0  Hermes ACP mode requires the NEW GitHub Copilot CLI (github.com/github/copilot-cli), but the binary it just spawned is the deprecated `gh copilot` extension.

Install the new CLI:
  npm install -g @github/copilot
  # then verify with: copilot --help

If `copilot` already resolves to the new CLI but you still see this,
point Hermes at it explicitly:
  export HERMES_COPILOT_ACP_COMMAND=/path/to/new/copilot

Alternative: use the `copilot` provider (no ACP, hits the Copilot API
directly with a Copilot subscription token) via `hermes setup`.

Original error:
z"Copilot ACP process exited early: z.Timed out waiting for Copilot ACP response to .)r   r  rr   rs   flushtime	monotonicpollr4   queueEmpty_handle_server_messager   RuntimeErrorrv   r(   r   TimeoutError)r4  r5  r1  r2  
request_idpayloaddeadlinemsgerrr   r*  next_idr  r   r-  r	  s             r   _requestz.CopilotACPClient._run_prompt.<locals>._request+  s   qLG J    	G JJTZZ0478JJ~~'/9H.."X-99;*))C)0C .. )$3 /  774=J.c>'''*0bC&&vhi	8J8Qc7RS  wwx(())K0668Kyy{&;5kB&, -8=:  #%G}#UVV!OPVxWXYZZO {{ s   F F/.F/
initializefs)readTextFilewriteTextFilezhermes-agentzHermes Agentz0.0.0)rW   ru   version)protocolVersionclientCapabilities
clientInfozsession/new)r   
mcpServers	sessionIdr#   z'Copilot ACP did not return a sessionId.zsession/promptr   )r   r   )rQ  promptr   r   )
r4  rq   r5  dict[str, Any]r1  list[str] | Noner2  rU  r   r   )
subprocessPopenr   r   PIPEr   rE   FileNotFoundErrorr?  r   r!  r   r   r   r   r<  Queuer   r   Threadr   rq   r4   r(   rv   r  )r   r  r	  r   r+  r.  
out_thread
err_threadrG  session
session_idr1  r2  r*  rF  r  r-  s   ` `          @@@@r   r  zCopilotACPClient._run_prompt  sh   	##""#dnn4 oo!!MM)+	D  ::!4IIKWXX&& 	(#'D 	( .3[[]"'r"2	:	6 %%^DI
%%^DI
\`  GK :	[ :	[x/	'(,0-1+ !/!/#*#" =="$    W[[5;<BBDJ"#LMM$&J)+O !+ %+$/ & / 77:&(@@JJLe ! 	78I8I7J Ka a 		( 	(N JJLs1   A1H ?H:B!I 	H7H22H7:IIc               6   |j                  d      }t        |t              sy|dk(  r|j                  d      xs i }|j                  d      xs i }t        |j                  d      xs d      j                         }	|j                  d      xs i }
d}t        |
t              rt        |
j                  d	      xs d      }|	d
k(  r|r||j                  |       y|	dk(  r|r||j                  |       y|j                  y|j                  d      }|j                  d      xs i }|dk(  rt        |      }n|dk(  r	 t        t        |j                  d      xs d      |      }t        t        |            }|rt        |      	 |j                         }
|j                  d      }|j                  d      }t        |t              rL|dkD  rG|
j                  d      }|dz
  }t        |t              r
|dkD  r||z   nd }dj                  |||       }
|
rt!        |
d      }
d|d|
id}n|dk(  r	 t        t        |j                  d      xs d      |      }t'        t        |            }|rt        |      |j(                  j+                  dd       |j-                  t        |j                  d      xs d             d|d d}nt%        |dd| d      }|j                  j/                  t1        j2                  |      dz          |j                  j5                          y# t        $ r d}
Y w xY w# t"        $ r }t%        |dt        |            }Y d }~d }~ww xY w# t"        $ r }t%        |dt        |            }Y d }~d }~ww xY w) Nr4  Fzsession/updater5  updatesessionUpdater#   rc   r   agent_message_chunkagent_thought_chunkTrK   zsession/request_permissionzfs/read_text_filer5   r)  limitr   )keependsr   )forcerG   rR   izfs/write_text_file)parentsexist_okizACP client method 'z!' is not supported by Hermes yet.r   )r4   rn   rq   r(   rp   rm   r   rT   r   r   r   	read_textrY  r  
splitlinesrv   r   r;   rN   r   parentmkdir
write_textr  rr   rs   r8  )r   rD  r6  r   r1  r2  r4  r5  ra  kindrc   
chunk_textrM   responser5   block_errorr)  re  linesr   r   r   denieds                          r   r>  z'CopilotACPClient._handle_server_message  sq    "&#&%%WWX&,"FZZ)/RFvzz/28b9??ADjj+1rGJ'4( V!4!:;
,,
@V!!*-  ..:/B]&&z2== WWT]
"(b11)*5H**H.s6::f3E3K/LcR23t9=)+66!"nn.G zz&)

7+dC(TAX#...=E 1HE+5eS+Aeai%%-UYC ggeE#&67G3G4HG$$!7 ++H.s6::f3E3K/LcR/D	:)&11!!$!>FJJy$9$?R @A$$" &%fX-NOH 	DJJx0478Y ) ! G!$  H)*fc#hGH  H)*fc#hGHsW   A	M L1 BM :BM/ 1M <M ?M  M 	M,M''M,/	N8NN)r   
str | Noner   ru  r   zdict[str, str] | Noner   ru  r   rU  r   ru  r   ru  r   rU  r   r   rS  )rx   ru  rw   list[dict[str, Any]] | Noner   zfloat | Nonery   rv  rz   r   r  boolr   r   r   r   )r  rq   r	  r  r   ztuple[str, str])rD  rT  r6  zsubprocess.Popen[str]r   rq   r1  rU  r2  rU  r   rw  )	r   r   r   __doc__r   r  r   r  r>  r   r    r   r   r     s:   B
 ##15"&%)""!%5 5 	5
 /5  5 #5 5 5 5 50( !04 $-1> > .	>
 > +> > > > 
>@^@WW '	W
 W %W *W 
Wr    r   )r   rq   r   rw  )r   rq   )r   z	list[str])r   zdict[str, str])rM   r   rH   r  rI   rq   r   rT  )rM   r   r   rT  )NNN)
rw   zlist[dict[str, Any]]rx   ru  ry   rv  rz   r   r   rq   )rc   r   r   rq   )r   rq   rW   rq   r   rq   r   r	   )r   r   r   zlist[SimpleNamespace])r   rq   r   z/tuple[list[ChatCompletionMessageToolCall], str])r   rq   r   rq   r   r   )5rx  
__future__r   rr   r&   r<  rer,   rV  r   r9  collectionsr   pathlibr   typesr   typingr   3openai.types.chat.chat_completion_message_tool_callr	   r
   agent.file_safetyr   r   agent.redactr   tools.environments.localr   r   r  compileDOTALLr   r   r   r   r   r)   r/   r?   rE   rN   rT   r   rt   r   r   r   r   r   r   r   r   r    r   <module>r     sv   #  	  	       ! 
 K . :%    bjj!JBIIV RZZ  !H  JL  JS  JS  T  (  C2		 )-	H_"H_H_ 'H_ 	H_
 	H_V 0  	
 # +%\DP
> >7 7
c cr    