+
    i                     a  0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIHtHt ^ RIHtHt ^ RIHt ^ RIHtHtHtHt ^ RIt^ RI t ^ RI!H"t"H#t# ^ R	I$H%t% ]PL                  ! ]'4      t( ^ RI)t) ^ RI+t+^t,R
t-Rt.Rt/Rt0Rt1ERt2^xt3^t4Rt5Rt6Rt7Rt8Rt9Rt:^xt;] ! R R4      4       t</ R]<! RRR].]/]0]1R7      bR]<! RRR]5R7      bR]<! RR R!]6ERR"7      bR#]<! R#R$R%]7R&R'7      bR(]<! R(R)R!RERR*R+7      bR,]<! R,R-R!R.ERR/R+7      bR0]<! R0R1R!R2ERR3R+7      bR4]<! R4R5R!R6ERR7R+7      bR8]<! R8R9R!R:ER	R"7      bR;]<! R;R<R!R=ER
R>R+7      bR?]<! R?R@R!RAERRBR+7      bRC]<! RCRDR!REERRFR+7      bRG]<! RGRHR!RIERRJR+7      bRK]<! RKRLR!RMERRNR+7      bRO]<! RORPR!RQERRRR+7      bRS]<! RSRTR!RUERRVR+7      bRW]<! RWRXR!RYERRZR+7      bt=R[]>R\&   R]t?R^ R_ lt@R` Ra ltARb Rc ltB0 ERmtCRd^/Re Rf lltDRg Rh ltE. EROtFERRi Rj lltG ! Rk Rl]H4      tIRm Rn ltJRo Rp ltKRq Rr ltLRsR/Rt Ru lltMRv Rw ltNRx Ry ltO]P                  ! 4       tQ]]-3Rz R{ ll4       tRERR| R} lltSR~ R ltTR R ltUR R ltVERR R lltWR R ltXR R ltYR R ltZERR R llt[R R lt\R R lt]ERRRRR/R R lllt^R R lt_R R lt`R R ltaR R ltbR R ltcR R ltdR R lteRR/R R lltfERR R lltgRR/R R llthR R ltiR R ltjRRRRR];/R R lltkRRRRRR/R R lltlR R ltmR R ltnR R ltoR R ltpRR
RR/R R lltqR R ltrRR
RRRRR]3/R R lltsRRR]1RRRRRRRRR]2RR
RRRRRRRR/R R llttR]2RR
RRRR/R R lltuR]2RR
RRRRRR/R R lltvR R ltwR R ltxR R ltyR R ltzERR R llt{R R lt|R R lt}R R lt~ERR R lltR R ltERR R lltR R ltR R ltR R ltR R ltRRRRRRRRRRRR
RRRRRER/	R R lltR ER  ltER ER ltR#   ]* d    Rt) ELi ; i  ]* d    Rt+ ELi ; i(  aZ  
Multi-provider authentication system for Hermes Agent.

Supports OAuth device code flows (Nous Portal, future: OpenAI Codex) and
traditional API key providers (OpenRouter, custom endpoints). Auth state
is persisted in ~/.hermes/auth.json with cross-process file locking.

Architecture:
- ProviderConfig registry defines known OAuth providers
- Auth store (auth.json) holds per-provider credential state
- resolve_provider() picks the active provider via priority chain
- resolve_*_runtime_credentials() handles token refresh and key minting
- logout_command() is the CLI entry point for clearing auth
)annotationsN)contextmanager)	dataclassfield)datetimetimezone)Path)AnyDictListOptional)get_hermes_homeget_config_path)OPENROUTER_BASE_URL      .@zhttps://portal.nousresearch.comz)https://inference-api.nousresearch.com/v1
hermes-clizinference:mint_agent_keyz%https://chatgpt.com/backend-api/codexzhttps://api.githubcopilot.comzacp://copilotz7https://generativelanguage.googleapis.com/v1beta/openaiapp_EMoamEEZ73f0CkXaXp7hrannz#https://auth.openai.com/oauth/tokenc                      ] tR t^Rt$ RtR]R&   R]R&   R]R&   RtR]R&   RtR]R&   RtR]R	&   Rt	R]R
&   ]
! ]R7      tR]R&   RtR]R&   RtR]R&   RtR# )ProviderConfigz%Describes a known inference provider.stridname	auth_type portal_base_urlinference_base_url	client_idscope)default_factoryDict[str, Any]extratupleapi_key_env_varsbase_url_env_var N)__name__
__module____qualname____firstlineno____doc____annotations__r   r   r   r   r   dictr    r"   r#   __static_attributes__r$       ,/home/ubuntu/hermes-agent/hermes_cli/auth.pyr   r   R   sa    /G
INOS  IsE3O!$7E>7 e cr-   r   nouszNous Portaloauth_device_code)r   r   r   r   r   r   r   openai-codexzOpenAI Codexoauth_external)r   r   r   r   copilotzGitHub Copilotapi_key)r   r   r   r   r"   copilot-acpzGitHub Copilot ACPexternal_processCOPILOT_ACP_BASE_URL)r   r   r   r   r#   geminizGoogle AI StudioGEMINI_BASE_URL)r   r   r   r   r"   r#   zaiz
Z.AI / GLMhttps://api.z.ai/api/paas/v4GLM_BASE_URLkimi-codingzKimi / Moonshotzhttps://api.moonshot.ai/v1KIMI_BASE_URLminimaxMiniMaxz https://api.minimax.io/anthropicMINIMAX_BASE_URL	anthropic	Anthropiczhttps://api.anthropic.comalibabazAlibaba Cloud (DashScope)z6https://dashscope-intl.aliyuncs.com/compatible-mode/v1DASHSCOPE_BASE_URL
minimax-cnzMiniMax (China)z"https://api.minimaxi.com/anthropicMINIMAX_CN_BASE_URLdeepseekDeepSeekzhttps://api.deepseek.com/v1DEEPSEEK_BASE_URL
ai-gatewayz
AI Gatewayzhttps://ai-gateway.vercel.sh/v1AI_GATEWAY_BASE_URLopencode-zenzOpenCode Zenzhttps://opencode.ai/zen/v1OPENCODE_ZEN_BASE_URLopencode-gozOpenCode Gozhttps://opencode.ai/zen/go/v1OPENCODE_GO_BASE_URLkilocodez	Kilo Codezhttps://api.kilo.ai/api/gatewayKILOCODE_BASE_URLhuggingfacezHugging Facez https://router.huggingface.co/v1HF_BASE_URLzDict[str, ProviderConfig]PROVIDER_REGISTRYzhttps://api.kimi.com/coding/v1c               (    V ^8  d   QhRRRRRRRR/# )   r4   r   default_urlenv_overridereturnr$   )formats   "r.   __annotate__r\      s)     
 
C 
c 
 
QT 
r-   c                T    V'       d   V# V P                  R4      '       d   \        # V# )zReturn the correct Kimi base URL based on the API key prefix.

If the user has explicitly set KIMI_BASE_URL, that always wins.
Otherwise, sk-kimi- prefixed keys route to api.kimi.com/coding/v1.
zsk-kimi-)
startswithKIMI_CODE_BASE_URL)r4   rX   rY   s   &&&r.   _resolve_kimi_base_urlr`      s*     *%%!!r-   c                   V ^8  d   QhRR/# )rW   rZ   z	list[str]r$   )r[   s   "r.   r\   r\     s      I r-   c                    . p \         P                  ! R4      pV'       d   V P                  V4       RR\        \        P
                  ! 4       R,          R,          R,          4      3 Fp  pW 9   d   K  \        P                  P                  V4      '       g   K2  \        P                  ! V\        P                  4      '       g   K_  V P                  V4       Kr  	  V # )zIReturn candidate ``gh`` binary paths, including common Homebrew installs.ghz/opt/homebrew/bin/ghz/usr/local/bin/ghz.localbin)shutilwhichappendr   r   homeospathisfileaccessX_OK)
candidatesresolved	candidates      r.   _gh_cli_candidatesrq     s    J||D!H(# 	DIIK("U*T12	
 "77>>)$$9bgg)F)Fi( r-   c                   V ^8  d   QhRR/# rW   rZ   Optional[str]r$   )r[   s   "r.   r\   r\     s      = r-   c                    \        4        Fp  p  \        P                  ! V RR.RR^R7      pTP                  ^ 8X  g   K4  TP                  P                  4       '       g   KV  TP                  P                  4       u # 	  R#   \        \        P                  3 d"   p\
        P                  RY4        Rp?K  Rp?ii ; i)zGReturn a token from ``gh auth token`` when the GitHub CLI is available.authtokenT)capture_outputtexttimeoutz#gh CLI token lookup failed (%s): %sN)
rq   
subprocessrunFileNotFoundErrorTimeoutExpiredloggerdebug
returncodestdoutstrip)gh_pathresultexcs      r.   _try_gh_cli_tokenr     s    %'		^^&'*#	F !fmm&9&9&;&;==&&(( (  ":#<#<= 	LL>M	s   BB=B88B=
min_lengthc               $    V ^8  d   QhRRRRRR/# )rW   valuer	   r   intrZ   boolr$   )r[   s   "r.   r\   r\   =  s!     	 	S 	 	T 	r-   c                   \        V \        4      '       g   R# V P                  4       p\        V4      V8  d   R# VP	                  4       \
        9   d   R# R# )zIReturn True when a configured secret looks usable, not empty/placeholder.FT)
isinstancer   r   lenlower_PLACEHOLDER_SECRET_VALUES)r   r   cleaneds   &$ r.   has_usable_secretr   =  sA    eS!!kkmG
7|j }}44r-   c               $    V ^8  d   QhRRRRRR/# )rW   provider_idr   pconfigr   rZ   ztuple[str, str]r$   )r[   s   "r.   r\   r\   I  s$      -r-   c                d   V R8X  d    ^ RI Hp V! 4       w  r4V'       d   W43#  R# VP                   F>  p\        P                  ! VR4      P                  4       p\        V4      '       g   K;  Wv3u # 	  R#   \         d"   p\        P	                  RT4        Rp?R# Rp?i\
         d     R# i ; i)zDResolve an API-key provider's token and indicate where it came from.r3   )resolve_copilot_tokenz#Copilot token validation failed: %sNr   )r   r   )hermes_cli.copilot_authr   
ValueErrorr   warning	Exceptionr"   ri   getenvr   r   )r   r   r   rw   sourcer   env_varvals   &&      r.    _resolve_api_key_provider_secretr   I  s     i	E13ME}$  ++ii$**,S!!< ,
 M  	GNN@#FF   		s#   A6 6B/BB/*B/.B/c               $    V ^8  d   QhRRRRRR/# )rW   r4   r   rz   floatrZ   Optional[Dict[str, str]]r$   )r[   s   "r.   r\   r\   s  s"     ! ! !u !?W !r-   c                   \          F  w  r#rE \        P                  ! V R2RRV  2RR/RVRRR	^R
RRRR/./VR7      pVP                  ^8X  d#   \        P                  RW#4       RVRVRVRV/u # \        P                  RW&P                  4       K  	  R#   \         d"   p\        P                  RY'4        Rp?K  Rp?ii ; i)zProbe z.ai endpoints to find one that accepts this API key.

Returns {"id": ..., "base_url": ..., "model": ..., "label": ...} for the
first working endpoint, or None if all fail.
z/chat/completionsAuthorizationBearer Content-Typeapplication/jsonmodelstreamF
max_tokensmessagesroleusercontentping)headersjsonrz   zZ.AI endpoint probe: %s (%s) OKr   base_urllabelz#Z.AI endpoint probe: %s returned %sz"Z.AI endpoint probe: %s failed: %sN)ZAI_ENDPOINTShttpxpoststatus_coder   r   r   )r4   rz   ep_idr   r   r   respr   s   &&      r.   detect_zai_endpointr   s  s     *7%	K::*-.#wwi%8"$6
 Ue !&&)V!D E	  D 3&>P%UU	  LL>GWGWX1 *76   	KLL=uJJ	Ks   A!B2 BC#B??Cc                  B   a  ] tR tRtRtRRRRRR/R	 V 3R
 llltRtV ;t# )	AuthErrori  z,Structured auth error with UX mapping hints.providerr   codeNrelogin_requiredFc          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
rW   messager   r   r   rt   r   r   rZ   Noner$   )r[   s   "r.   r\   AuthError.__annotate__  s<     1 11 	1
 1 1 
1r-   c               	J   < \         SV `  V4       W n        W0n        W@n        R # N)super__init__r   r   r   )selfr   r   r   r   	__class__s   &&$$$r.   r   AuthError.__init__  s"     	! 	 0r-   )r   r   r   )r%   r&   r'   r(   r)   r   r,   __classcell__)r   s   @r.   r   r     s3    61 	1
 #1 "'1 1 1r-   r   c                    V ^8  d   QhRRRR/# )rW   errorr   rZ   r   r$   )r[   s   "r.   r\   r\     s      Y 3 r-   c                   \        V \        4      '       g   \        V 4      # V P                  '       d   V  R2# V P                  R8X  d    R# V P                  R8X  d    R# V P                  R8X  d   V  R2# \        V 4      # )z2Map auth failures to concise user-facing guidance.z' Run `hermes model` to re-authenticate.subscription_requiredzfNo active paid subscription found on Nous Portal. Please purchase/activate a subscription, then retry.insufficient_creditszTSubscription credits are exhausted. Top up/renew credits in Nous Portal, then retry.temporarily_unavailablez Please retry in a few seconds.)r   r   r   r   r   )r   s   &r.   format_auth_errorr     s    eY''5z?@@zz,,C	

 zz++?	

 zz..788u:r-   c                    V ^8  d   QhRRRR/# )rW   rw   r	   rZ   rt   r$   )r[   s   "r.   r\   r\     s     D Dc Dm Dr-   c                    \        V \        4      '       g   R# V P                  4       pV'       g   R# \        P                  ! VP                  R4      4      P                  4       R,          # )zJReturn a short hash fingerprint for telemetry without leaking token bytes.Nutf-8N   N)r   r   r   hashlibsha256encode	hexdigest)rw   r   s   & r.   _token_fingerprintr     sI    eS!!kkmG>>'..12<<>sCCr-   c                   V ^8  d   QhRR/# rW   rZ   r   r$   )r[   s   "r.   r\   r\     s     - -d -r-   c                 r    \         P                  ! R R4      P                  4       P                  4       p V R9   # )HERMES_OAUTH_TRACEr   >   1onyestrue)ri   r   r   r   )raws    r.   _oauth_trace_enabledr     s1    
))("
-
3
3
5
;
;
=C,,,r-   sequence_idc               (    V ^8  d   QhRRRRRRRR/# )	rW   eventr   r   rt   fieldsr	   rZ   r   r$   )r[   s   "r.   r\   r\     s/     [ [ [] [S [UY [r-   c          	         \        4       '       g   R # RV /pV'       d   WR&   VP                  V4       \        P                  R\        P
                  ! VRRR7      4       R # )Nr   r   zoauth_trace %sTF)	sort_keysensure_ascii)r   updater   infor   dumps)r   r   r   payloads   &$, r.   _oauth_tracer     sL    !!&.G!,NN6
KK $**WSX"YZr-   c                   V ^8  d   QhRR/# rW   rZ   r   r$   )r[   s   "r.   r\   r\     s     + + +r-   c                 $    \        4       R ,          # )	auth.json)r   r$   r-   r.   _auth_file_pathr     s    {**r-   c                   V ^8  d   QhRR/# r   r$   )r[   s   "r.   r\   r\     s     2 2 2r-   c                 4    \        4       P                  R 4      # )z.lock)r   with_suffixr$   r-   r.   _auth_lock_pathr     s    ((11r-   c                   V ^8  d   QhRR/# )rW   timeout_secondsr   r$   )r[   s   "r.   r\   r\     s     6 6e 6r-   c           	   #  0  "   \        \        R^ 4      ^ 8  dB   \        ;P                  ^,          un         Rx  \        ;P                  ^,          un        R# \        4       pVP                  P                  RRR7       \        f&   \        f   ^\        n         Rx  ^ \        n        R# \        '       dI   VP                  4       '       d    VP                  4       P                  ^ 8X  d   VP                  RRR7       TP                  \        '       d   RMR	4      ;_uu_ 4       p\        P                  ! 4       \        R
V 4      ,           p  \        '       dJ   \        P                  ! VP!                  4       \        P"                  \        P$                  ,          4       MEVP'                  ^ 4       \        P(                  ! VP!                  4       \        P*                  ^4        ^\        n         Rx  ^ \        n        \        '       d5   \        P                  ! TP!                  4       \        P6                  4       MT\        '       dH    TP'                  ^ 4       \        P(                  ! TP!                  4       \        P8                  ^4       M RRR4       R#   \        ;P                  ^,          un        i ; i  ^ \        n        i ; i  \,        \.        \0        3 dA    \        P                  ! 4       T8  d   \3        R4      h\        P4                  ! R4        EK  i ; i  \.        \:        3 d     Li ; i  ^ \        n        \        '       d5   \        P                  ! TP!                  4       \        P6                  4       i \        '       d_    TP'                  ^ 4       \        P(                  ! TP!                  4       \        P8                  ^4       i   \.        \:        3 d     i i ; ii ; i  + '       g   i     R# ; i5i)zCCross-process advisory lock for auth.json reads+writes.  Reentrant.depthNTparentsexist_ok r   encodingzr+za+g      ?z%Timed out waiting for auth store lockg?)getattr_auth_lock_holderr  r   parentmkdirfcntlmsvcrtexistsstatst_size
write_textopentimemaxflockfilenoLOCK_EXLOCK_NBseeklockingLK_NBLCKBlockingIOErrorOSErrorPermissionErrorTimeoutErrorsleepLOCK_UNLK_UNLCKIOError)r   	lock_path	lock_filedeadlines   &   r.   _auth_store_lockr'    s      '1-11$	)##q(#!I4$7}"#	(&'# vy''))Y^^-=-E-E-JS73	D	1	1Y99;S/!::
!5KK	 0 0 2EMMEMM4QRNN1%NN9#3#3#5vJ #$	&'#uI,,.>NN1%NN9#3#3#5vJ - 
2	1' ##q(# '(#$ $Wo> !99;(*&'NOO

4  !   )  '(#uI,,.>NN1%NN9#3#3#5vJ) 	 - 
2	1	1s   4PJ& A!PK !P:PAPP)(PKBK,P9M=APAL1P
P&KPKPAL.)P-L..P1MPMPAO?!AO'&O?'O;8O?:O;;O??PP		Pc                    V ^8  d   QhRRRR/# )rW   	auth_filezOptional[Path]rZ   r   r$   )r[   s   "r.   r\   r\   '  s     < < <. <r-   c                   T ;'       g    \        4       p V P                  4       '       g   R \        R/ /#  \        P                  ! V P                  4       4      p\        T\        4      '       d_   \        TP                  R4      \        4      '       g&   \        TP                  R4      \        4      '       d   TP                  R/ 4       T# \        T\        4      '       d[   \        TP                  R4      \        4      '       d6   TR,          p/ pRT9   d   TR,          TR&   R \        RTRT'       d   R/# R/# R \        R/ /#   \         d    R \        R/ /u # i ; i)version	providerscredential_poolsystemsnous_portalr/   active_providerN)r   r  AUTH_STORE_VERSIONr   loads	read_textr   r   r+   get
setdefault)r)  r   r.  r,  s   &   r.   _load_auth_storer6  '  sG   .._.I-{B??@jj,,./ #t377;'..cgg/0$77{B'
 #tCGGI,>!E!Ei.	G# ' 6If-{I!Y6B 	B<@B 	B );;;'  @-{B??@s   $E E E c                    V ^8  d   QhRRRR/# )rW   
auth_storer   rZ   r   r$   )r[   s   "r.   r\   r\   D  s     ! ! !D !r-   c                   \        4       pVP                  P                  R R R7       \        V R&   \        P
                  ! \        P                  4      P                  4       V R&   \        P                  ! V ^R7      R,           pVP                  VP                   R\        P                  ! 4        R\        P                   ! 4       P"                   24      p VP%                  RR	R
7      ;_uu_ 4       pVP'                  V4       VP)                  4        \        P*                  ! VP-                  4       4       RRR4       \        P.                  ! W14        \        P$                  ! \1        VP                  4      \        P2                  4      pVe.    \        P*                  ! V4       \        P6                  ! V4        VP9                  4       '       d   VP;                  4         TP=                  \>        P@                  \>        PB                  ,          4       T#   + '       g   i     L; i  \4         d    Rp Li ; i  \        P6                  ! T4       i ; i  \4         d     Li ; i   TP9                  4       '       d   TP;                  4        i i   \4         d     i i ; i; i  \4         d     T# i ; i)Tr  r+  
updated_at)indent
z.tmp..wr   r  N)"r   r
  r  r1  r   nowr   utc	isoformatr   r   	with_namer   ri   getpiduuiduuid4hexr  writeflushfsyncr  replacer   O_RDONLYr  closer  unlinkchmodr  S_IRUSRS_IWUSR)r8  r)  r   tmp_pathhandledir_fds   &     r.   _save_auth_storerT  D  s   !I4$7.Jy'||HLL9CCEJ|jjA.5G""inn%5U299;-qIYIYHZ#[\H]]3]11VLL!LLNHHV]]_% 2 	

8'	WWS!1!12BKK@F !  	  !t||34 3 21  	F	  
  			  ! ! 		
  s   I2 4AH :I2 8H3 I2 I ,I2 &I! *4J0  H0	+I2 3I I2 II2 II2 !I/.I/2J-4&JJ-J*'J-)J**J-0J?>J?c               $    V ^8  d   QhRRRRRR/# )rW   r8  r   r   r   rZ   Optional[Dict[str, Any]]r$   )r[   s   "r.   r\   r\   h  s"     < <^ <# <Jb <r-   c                    V P                  R 4      p\        V\        4      '       g   R# VP                  V4      p\        V\        4      '       d   \        V4      # R# )r,  N)r4  r   r+   )r8  r   r,  states   &&  r.   _load_provider_staterY  h  sI    {+Ii&&MM+&E$UD114;;t;r-   c               (    V ^8  d   QhRRRRRRRR/# )rW   r8  r   r   r   rX  rZ   r   r$   )r[   s   "r.   r\   r\   p  s)     0 0^ 0# 0n 0ae 0r-   c                    V P                  R / 4      p\        V\        4      '       g   / V R &   V R ,          pW#V&   WR&   R# )r,  r0  N)r5  r   r+   )r8  r   rX  r,  s   &&& r.   _save_provider_stater\  p  sF    %%k26Ii&&"$
;{+	"k$/ !r-   c                    V ^8  d   QhRRRR/# rW   r   rt   rZ   r   r$   )r[   s   "r.   r\   r\   y  s     	P 	Pm 	P~ 	Pr-   c                    \        4       pVP                  R4      p\        V\        4      '       g   / pV f   \        V4      # VP                  V 4      p\        V\        4      '       d   \	        V4      # . # )z<Return the persisted credential pool, or one provider slice.r-  )r6  r4  r   r+   list)r   r8  poolprovider_entriess   &   r.   read_credential_poolrc  y  sh    !#J>>+,DdD!!Dzxx,%/0@$%G%G4 !OROr-   c               $    V ^8  d   QhRRRRRR/# )rW   r   r   entriesList[Dict[str, Any]]rZ   r   r$   )r[   s   "r.   r\   r\     s"     	, 	,s 	,5I 	,d 	,r-   c                   \        4       ;_uu_ 4        \        4       pVP                  R4      p\        V\        4      '       g   / pW2R&   \        V4      W0&   \        V4      uuRRR4       #   + '       g   i     R# ; i)z7Persist one provider's credential pool under auth.json.r-  N)r'  r6  r4  r   r+   r`  rT  )r   re  r8  ra  s   &&  r.   write_credential_poolrh    s`    			%'
~~/0$%%D,0() M
+ 
			s   AA--A>	c                    V ^8  d   QhRRRR/# )rW   r   r   rZ   rV  r$   )r[   s   "r.   r\   r\     s     9 9 91I 9r-   c                ,    \        4       p\        W4      # )z4Return persisted auth state for a provider, or None.)r6  rY  )r   r8  s   & r.   get_provider_auth_staterk    s    !#J
88r-   c                   V ^8  d   QhRR/# rs   r$   )r[   s   "r.   r\   r\     s     - -] -r-   c                 8    \        4       p V P                  R4      # )z8Return the currently active provider ID from auth store.r0  )r6  r4  r8  s    r.   get_active_providerro    s    !#J>>+,,r-   c                    V ^8  d   QhRRRR/# )rW   r   rt   rZ   r   r$   )r[   s   "r.   r\   r\     s     # #] #d #r-   c                (   \        4       ;_uu_ 4        \        4       pT ;'       g    VP                  R4      pV'       g    RRR4       R# VP                  R/ 4      p\        V\        4      '       g   / pW1R&   VP                  R4      p\        V\        4      '       g   / pWAR&   RpW#9   d   W2 RpW$9   d   WB RpV'       g    RRR4       R# VP                  R4      V8X  d   RVR&   \        V4       RRR4       R#   + '       g   i     R# ; i)z
Clear auth state for a provider. Used by `hermes logout`.
If provider_id is None, clears the active provider.
Returns True if something was cleared.
r0  NFr,  r-  T)r'  r6  r4  r   r+   rT  )r   r8  targetr,  ra  cleareds   &     r.   clear_provider_authrt    s    
		%'
AA
/@ A	 
	 NN;3	)T**I&/{#~~/0$%%D,0()!G>G3 
	4 >>+,6,0J()$9 
: ; 
	: s$   -D D A8D D &D  D	c                   V ^8  d   QhRR/# rW   rZ   r   r$   )r[   s   "r.   r\   r\     s     	% 	%T 	%r-   c                     \        4       ;_uu_ 4        \        4       p RV R&   \        V 4       RRR4       R#   + '       g   i     R# ; i)z
Clear active_provider in auth.json without deleting credentials.
Used when the user switches to a non-OAuth provider (OpenRouter, custom)
so auto-resolution doesn't keep picking the OAuth provider.
Nr0  )r'  r6  rT  rn  s    r.   deactivate_providerrx    s7     
		%'
(,
$%$ 
			s	   8A		c                    V ^8  d   QhRRRR/# )rW   provider_namer   rZ   r$   )r[   s   "r.   r\   r\     s        r-   c                    ^ RI Hp V! 4       pV'       g   R# R.pV F  pVP                  R8X  d   RMRpVP                  RV RVP                   24       VP
                  '       d"   VP
                  P                  4       ^ ,          MRpV'       g   Kx  VP                  R	V 24       K  	  R
P                  V4      #   \         d     R# i ; i)zReturn a helpful hint string when provider resolution fails.

Checks for common config.yaml mistakes (malformed custom_providers, etc.)
and returns a human-readable diagnostic, or empty string if nothing found.
)validate_config_structurer   uC   Config issue detected — run 'hermes doctor' for full diagnostics:r   ERRORWARNINGz  [z] u       → r<  )	hermes_cli.configr|  severityrg   r   hint
splitlinesjoinr   )rz  r|  issueslinesciprefix
first_hints   &      r.   %_get_config_hint_for_unknown_providerr    s    ?*,VWB "w 6WIFLL3vhb5646GGG++-a0Jzx
|45  yy s#   B? AB? )(B? (B? ?CCexplicit_api_keyexplicit_base_urlc               (    V ^8  d   QhRRRRRRRR/# )rW   	requestedrt   r  r  rZ   r   r$   )r[   s   "r.   r\   r\     s8     \ \\ $\ %	\
 	\r-   c                  T ;'       g    RP                  4       P                  4       p/ RRbRRbRRbRRbRRbR	RbR
RbRRbRRbRRbRRbRRbRRbRRbRRbRRbRRb/ RRbRRbRRbRRbRRbR R!bR"R!bR#R$bR%R$bR&R$bR'R(bR)R(bR*R+bR,R+bR-R+bR.R/bR0R/bCR1R/R2R/R3R/R4R/R5R/R6R//CpVP                  W34      pVR78X  d   R7# VR/8X  d   R/# V\        9   d   V# VR8w  d=   \	        V4      pR8V R92pV'       d   VR:V 2,          pM	VR;,          p\        VR<R=7      hV'       g	   V'       d   R7#  \        4       pVP                  R>4      pV'       d0   V\        9   d%   \        V4      p	V	P                  R?4      '       d   V# \        \        P                  ! RB4      4      '       g&   \        \        P                  ! RC4      4      '       d   R7# \        P                  4        F`  w  rTP                  RD8w  d   K  TR8X  d   K!  TP                    F/  p\        \        P                  ! TRE4      4      '       g   K+  Tu u # 	  Kb  	  \        RFRGR=7      h  \         d!   p
\        P                  R@T
4        RAp
?
LRAp
?
ii ; i)Ha^  
Determine which inference provider to use.

Priority (when requested="auto" or None):
1. active_provider in auth.json with valid credentials
2. Explicit CLI api_key/base_url -> "openrouter"
3. OPENAI_API_KEY or OPENROUTER_API_KEY env vars -> "openrouter"
4. Provider-specific API keys (GLM, Kimi, MiniMax) -> that provider
5. Fallback: "openrouter"
autoglmr:   zz-aizz.aizhipugoogler8   zgoogle-geminizgoogle-ai-studiokimir=   moonshotzminimax-chinarF   
minimax_cnclauderB   zclaude-codegithubr3   zgithub-copilotzgithub-modelszgithub-modelzgithub-copilot-acpr5   zcopilot-acp-agent	aigatewayrK   vercelzvercel-ai-gatewayopencoderM   zenhfrS   zhugging-facezhuggingface-hubgorO   zopencode-go-subkilorQ   z	kilo-codezkilo-gatewaylmstudiocustomz	lm-studio	lm_studioollamavllmllamacppz	llama.cppz	llama-cpp
openrouterzUnknown provider 'z'.z

z` Check 'hermes model' for available providers, or run 'hermes doctor' to diagnose config issues.invalid_provider)r   r0  	logged_inz)Could not detect active auth provider: %sNOPENAI_API_KEYOPENROUTER_API_KEYr4   r   zNo inference provider configured. Run 'hermes model' to choose a provider and model, or set an API key (OPENROUTER_API_KEY, OPENAI_API_KEY, etc.) in ~/.hermes/.env.no_provider_configured)r   r   r4  rU   r  r   r6  get_auth_statusr   r   r   r   ri   r   itemsr   r"   )r  r  r  
normalized_PROVIDER_ALIASES_config_hintmsgr8  activestatusepidr   r   s   &$$           r.   resolve_providerr    s     %%v,,.446Jue%+U4;U(+X7I8 	  *= 		 (4\	
 	+
  -k 	) .y 	 %3I 	m .A- 	\ $,\ <OP\ 	N %*> 	m ,] =N} 	m / 	
 ( 6DZ 	H *8 6A((FHj(X{H#& #&&z>J\!X&&V<ZH":,b1T,((CuuC"455 ,E%'
 12f 11$V,Fzz+&& #34559J299UiKj9k9k *//1	) )//G 7B!788
 0 2 	3 &	 '  E@!DDEs   'AI
 
I5I00I5c                    V ^8  d   QhRRRR/# )rW   r   r	   rZ   zOptional[float]r$   )r[   s   "r.   r\   r\   P  s        r-   c                   \        V \        4      '       d	   V '       g   R # V P                  4       pV'       g   R # VP                  R4      '       d   VR R R,           p \        P
                  ! V4      pTP                  f!   TP                  \        P                  R7      pTP                  4       #   \         d     R # i ; i)NZ+00:00)tzinfo)r   r   r   endswithr   fromisoformatr   r  rJ  r   r@  	timestamp)r   ry   parseds   &  r.   _parse_iso_timestampr  P  s    eS!!;;=D}}SCRy8#''- }}x||4	  s   B3 3CCc               $    V ^8  d   QhRRRRRR/# )rW   expires_at_isor	   skew_secondsr   rZ   r   r$   )r[   s   "r.   r\   r\   a  s!     9 9 9C 9D 9r-   c                b    \        V 4      pVf   R# V\        P                  ! 4       V,           8*  # )NT)r  r  )r  r  expires_epochs   && r.   _is_expiringr  a  s+    (8MTYY[<788r-   c                    V ^8  d   QhRRRR/# )rW   
expires_inr	   rZ   r   r$   )r[   s   "r.   r\   r\   h  s      C C r-   c                X     \        V 4      p\        ^ V4      #   \         d    ^ p Li ; i)    )r   r   r  )r  ttls   & r.   _coerce_ttl_secondsr  h  s4    *o q#;  s    ))c                    V ^8  d   QhRRRR/# )rW   r   r	   rZ   rt   r$   )r[   s   "r.   r\   r\   p  s     ( (c (m (r-   c                    \        V \        4      '       g   R # V P                  4       P                  R4      pV'       d   V# R # )N/)r   r   r   rstrip)r   r   s   & r.   _optional_base_urlr  p  s5    eS!!kkm""3'G7'4'r-   c                    V ^8  d   QhRRRR/# )rW   rw   r	   rZ   r   r$   )r[   s   "r.   r\   r\   w  s     
6 
6c 
6n 
6r-   c                   \        V \        4      '       d   V P                  R 4      ^8w  d   / # V P                  R 4      ^,          pVR^\	        V4      ^,          ,
          ^,          ,          ,          p \
        P                  ! VP                  R4      4      p\        P                  ! VP                  R4      4      p\        T\        4      '       d   T# / #   \         d    / u # i ; i)r=  =r   )r   r   countsplitr   base64urlsafe_b64decoder   r   r2  decoder   r+   )rw   r   r   claimss   &   r.   _decode_jwt_claimsr  w  s    eS!!U[[%5%:	kk#q!Gsq3w<!++q011G&&w~~g'>?CJJw/0  --6525  	s   6A
C C*)C*c               $    V ^8  d   QhRRRRRR/# )rW   access_tokenr	   r  r   rZ   r   r$   )r[   s   "r.   r\   r\     s&     C C# CS CT Cr-   c                    \        V 4      pVP                  R 4      p\        V\        \        34      '       g   R# \	        V4      \
        P
                  ! 4       \        ^ \        V4      4      ,           8*  # )expF)r  r4  r   r   r   r  r  )r  r  r  r  s   &&  r.   _codex_access_token_is_expiringr    sT    -F
**U
CcC<((:$))+As</@(AABBr-   c                   V ^8  d   QhRR/# r   r$   )r[   s   "r.   r\   r\     s     A AD Ar-   c                 |    \        \        P                  ! R4      ;'       g    \        P                  ! R4      4      # )zGDetect if running in an SSH session where webbrowser.open() won't work.
SSH_CLIENTSSH_TTY)r   ri   r   r$   r-   r.   _is_remote_sessionr    s'    		,'??299Y+?@@r-   _lockTc                    V ^8  d   QhRRRR/# )rW   r  r   rZ   r   r$   )r[   s   "r.   r\   r\     s     . . . .r-   c                   V '       d'   \        4       ;_uu_ 4        \        4       pRRR4       M
\        4       p\        XR4      pV'       g   \        RRRRR7      hVP	                  R4      p\        V\        4      '       g   \        RRR	RR7      hVP	                  R
4      pVP	                  R4      p\        V\        4      '       d   VP                  4       '       g   \        RRRRR7      h\        V\        4      '       d   VP                  4       '       g   \        RRRRR7      hRVRVP	                  R4      /#   + '       g   i     EL; i)zRead Codex OAuth tokens from Hermes auth store (~/.hermes/auth.json).

Returns dict with 'tokens' (access_token, refresh_token) and 'last_refresh'.
Raises AuthError if no Codex tokens are stored.
Nr1   z?No Codex credentials stored. Run `hermes auth` to authenticate.codex_auth_missingTr   r   r   tokenszICodex auth state is missing tokens. Run `hermes auth` to re-authenticate.codex_auth_invalid_shaper  refresh_tokenzICodex auth is missing access_token. Run `hermes auth` to re-authenticate.codex_auth_missing_access_tokenJCodex auth is missing refresh_token. Run `hermes auth` to re-authenticate. codex_auth_missing_refresh_tokenlast_refresh)	r'  r6  rY  r   r4  r   r+   r   r   )r  r8  rX  r  r  r  s   $     r.   _read_codex_tokensr    s<    )+J   &'
 ^<EM#%!	
 	
 YYx Ffd##W#+!	
 	
 ::n-LJJ/MlC((0B0B0D0DW#2!	
 	
 mS))1D1D1F1FX#3!	
 	
 	&		.1 I  s   D??E	c               $    V ^8  d   QhRRRRRR/# )rW   r  Dict[str, str]r  r   rZ   r   r$   )r[   s   "r.   r\   r\     s!     % %~ %S %D %r-   c                z   VfC   \         P                  ! \        P                  4      P	                  4       P                  RR4      p\        4       ;_uu_ 4        \        4       p\        VR4      ;'       g    / pWR&   WR&   RVR&   \        VRV4       \        V4       RRR4       R#   + '       g   i     R# ; i)	zCSave Codex OAuth tokens to Hermes auth store (~/.hermes/auth.json).Nr  r  r1   r  r  chatgpt	auth_mode)r   r?  r   r@  rA  rJ  r'  r6  rY  r\  rT  )r  r  r8  rX  s   &&  r.   _save_codex_tokensr    s    ||HLL1;;=EEhPST			%'
$Z@FFB h ,n&kZ?$ 
			s   AB))B:	r   g      4@c               (    V ^8  d   QhRRRRRRRR/# )rW   r  r   r  r   r   rZ   r   r$   )r[   s   "r.   r\   r\     s6     W WWW 	W
 Wr-   c               n   ? \        V\        4      '       d   VP                  4       '       g   \        RRRRR7      h\        P
                  ! \        R\        V4      4      4      p\        P                  ! VRR/R	7      ;_uu_ 4       pVP                  \        R
R/RRRVR\        /R7      pRRR4       XP                  ^8w  Ed   RpRVP                   R2pRp VP                  4       p	\        V	\        4      '       d   V	P                  R4      p
\        V
\        4      '       d'   V
P                  4       '       d   V
P                  4       pV	P                  R4      ;'       g    V	P                  R4      p\        V\        4      '       d*   VP                  4       '       d   RVP                  4        2pTR#9   d   RpTR8X  d   RpRp\        TRTTR7      h VP                  4       pTP                  R4      p\        T\        4      '       d   TP                  4       '       g   \        RRRRR7      hRTP                  4       RTP                  4       R \"        P$                  ! \&        P(                  4      P+                  4       P-                  R!R"4      /pTP                  R4      p\        T\        4      '       d*   TP                  4       '       d   TP                  4       TR&   T#   + '       g   i     ELJ; i  \          d     ELXi ; i  \          d   p\        RRRRR7      ThRp?ii ; i)$z>Refresh Codex OAuth tokens without mutating Hermes auth state.r  r1   r  Tr        @Acceptr   )rz   r   r   !application/x-www-form-urlencoded
grant_typer  r   )r   dataNcodex_refresh_failedz'Codex token refresh failed with status r=  Fr   error_descriptionr   zCodex token refresh failed: refresh_token_reusedzCodex refresh token was already consumed by another client (e.g. Codex CLI or VS Code extension). Run `codex` in your terminal to generate fresh tokens, then run `hermes auth` to re-authenticate.z*Codex token refresh returned invalid JSON.codex_refresh_invalid_jsonr  z6Codex token refresh response was missing access_token."codex_refresh_missing_access_tokenr  r  r  >   invalid_grantinvalid_tokeninvalid_request)r   r   r   r   r   Timeoutr  r   Clientr   CODEX_OAUTH_TOKEN_URLCODEX_OAUTH_CLIENT_IDr   r   r+   r4  r   r   r?  r   r@  rA  rJ  )r  r  r   rz   clientresponser   r   r   errerr_codeerr_descrefresh_payloadr   refreshed_accessupdatednext_refreshs   &&$              r.   refresh_codex_oauth_purer    s    	mS))1D1D1F1FX#3!	
 	
 mmCU?%;<=G	g:L/M	N	NRX;;!#%HIo2  
 
O s"%;H<P<P;QQRS 
	--/C#t$$777+h,,1A1A#>>+D77#67MM3779;Mh,,1A1A <X^^=M<NOG HH#))=   $#-	
 	
"--/ '**>:&,,4D4J4J4L4LD#5!	
 	
 	(..0,,.X\\2<<>FFxQTUG
 #&&7L,$$););)=)=#/#5#5#7 NM 
O	N	N0  		*  8#-!	

 	sI   %K.A"L ?'L '=L %L L .K?	LLL4L//L4c               $    V ^8  d   QhRRRRRR/# )rW   r  r  r   r   rZ   r$   )r[   s   "r.   r\   r\   6  s&       r-   c           	     
   \        \        V P                  RR4      ;'       g    R4      \        V P                  RR4      ;'       g    R4      VR7      p\        V 4      pVR,          VR&   VR,          VR&   \	        V4       V# )znRefresh Codex access token using the refresh token.

Saves the new tokens to Hermes auth store automatically.
r  r   r  r   )r  r   r4  r+   r  )r  r   	refreshedupdated_tokenss   &&  r.   _refresh_codex_auth_tokensr  6  s~     )FJJ~r*00b1FJJ+11r2'I
 &\N%.~%>N>"&/&@N?#~&r-   c                   V ^8  d   QhRR/# )rW   rZ   r   r$   )r[   s   "r.   r\   r\   K  s      ": r-   c                    \         P                  ! RR4      P                  4       p V '       g&   \        \        P
                  ! 4       R,          4      p \	        V 4      P                  4       R,          pVP                  4       '       g   R#  \        P                  ! VP                  4       4      pVP                  R4      p\        V\        4      '       g   R# VP                  R4      pVP                  R4      pV'       d	   V'       g   R# \        V^ 4      '       d   \        P!                  R	V4       R# \        V4      #   \"         d     R# i ; i)
zTry to read tokens from ~/.codex/auth.json (Codex CLI shared file).

Returns tokens dict if valid and not expired, None otherwise.
Does NOT write to the shared file.

CODEX_HOMEr   .codexr   Nr  r  r  u7   Codex CLI tokens at %s are expired — skipping import.)ri   r   r   r   r   rh   
expanduseris_filer   r2  r3  r4  r   r+   r  r   r   r   )
codex_home	auth_pathr   r  r  r  s         r.   _import_codex_cli_tokensr$  K  s     <,224Jx/0
Z ++-;I**Y0023X&&$''zz.1

?3= +<;;LLI9 F| s+   AE )E E (E 7
E EEforce_refreshFrefresh_if_expiringrefresh_skew_secondsc               (    V ^8  d   QhRRRRRRRR/# )rW   r%  r   r&  r'  r   rZ   r   r$   )r[   s   "r.   r\   r\   m  s2     < << < 	<
 <r-   c                $    \        4       p\        TR,          4      p\        TP                  RR	4      ;'       g    R	4      P                  4       p\        \        P                  ! R
R4      4      p\        T 4      p	T	'       g   T'       d   \!        Yr4      p	T	'       d   \#        \%        \        \&        4      TR,           4      R7      ;_uu_ 4        \        RR7      p\        TR,          4      p\        TP                  RR	4      ;'       g    R	4      P                  4       p\        T 4      p	T	'       g   T'       d   \!        Yr4      p	T	'       d?   \)        Yh4      p\        TP                  RR	4      ;'       g    R	4      P                  4       pRRR4       \        P                  ! RR	4      P                  4       P+                  R4      ;'       g    \,        p
RRRT
RTRRRTP                  R4      RR/#   \         d|   pTP                  R8w  d   h \        4       pT'       dR   \        P                  R4       \        R4       \        R4       \        R4       \        T4       \        4       p Rp?ELjh Rp?ii ; i  + '       g   i     L; i)z@Resolve runtime credentials from Hermes's own Codex token store.r  z?Migrating Codex credentials from ~/.codex/ to Hermes auth storeu?   ⚠️  Migrating Codex credentials to Hermes's own auth store.z4   This avoids conflicts with Codex CLI and VS Code.z<   Run `hermes auth` to create a fully independent session.
Nr  r  r   $HERMES_CODEX_REFRESH_TIMEOUT_SECONDS20r  r  F)r  HERMES_CODEX_BASE_URLr  r   r1   r   r4   r   zhermes-auth-storer  r  r  )r  r   r   r$  r   r   printr  r+   r   r4  r   r   ri   r   r   r  r'  r  AUTH_LOCK_TIMEOUT_SECONDSr  r  DEFAULT_CODEX_BASE_URL)r%  r&  r'  r  orig_err
cli_tokensr  r  refresh_timeout_secondsshould_refreshr   s   $$$        r.   !resolve_codex_runtime_credentialsr4  m  s   !#$ $x.!Fvzz."5;;<BBDL#BII.TVZ$[\-(N 38\c%8Q2RTknqTq.rss%E2D$x.)Fvzz."=CCDJJLL!-0N"(;!@!d3FT"6::nb#A#G#GRHNNP t 			)2.446==cB 	" 	"!  	NH<%0Y Y   ==00 ./
KKYZSTHIQRz*%'D!4 tss7   
G6 A,I?>I?>I?6I<A/I76I77I<?J	insecure	ca_bundle
auth_statec               (    V ^8  d   QhRRRRRRRR/# )	rW   r5  Optional[bool]r6  rt   r7  rV  rZ   
bool | strr$   )r[   s   "r.   r\   r\     s2        )	
 r-   c                   \        V\        4      '       d   VP                  R 4      M/ p\        V\        4      '       d   TM/ pV e   \        V 4      M\        VP                  RR4      4      pT;'       gN    VP                  R4      ;'       g5    \        P
                  ! R4      ;'       g    \        P
                  ! R4      pV'       d   R# V'       d   \        V4      # R# )tlsr5  Fr6  HERMES_CA_BUNDLESSL_CERT_FILET)r   r+   r4  r   ri   r   r   )r5  r6  r7  	tls_stateeffective_insecureeffective_cas   $$$   r.   _resolve_verifyrB    s     *4J)E)E
u%2I'	488	bI #.X)--
E23 
 	 	& 	&==%	& 	&99'(	& 	& 99_%	  <  r-   c          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
rW   r  httpx.Clientr   r   r   r   rt   rZ   r   r$   )r[   s   "r.   r\   r\     s:        	
 r-   c                    T P                  V R2RV/V'       d   RV/M/ CR7      pVP                  4        VP                  4       p. ROpV Uu. uF  qwV9  g   K  VNK  	  ppV'       d   \        RRP	                  V4       24      hV# u upi )zFPOST to the device code endpoint. Returns device_code, user_code, etc.z/api/oauth/device/coder   r   r  z%Device code response missing fields: z, )device_code	user_codeverification_uriverification_uri_completer  interval)r   raise_for_statusr   r   r  )	r  r   r   r   r  r  required_fieldsfmissings	   &&&&     r.   _request_device_coderP    s     {{
12
#(b
  H ==?DO *;/Qd]qq/G;@7AS@TUVVK <s   BBc               4    V ^8  d   QhRRRRRRRRRRR	RR
R/# )rW   r  rD  r   r   r   rG  r  r   poll_intervalrZ   r   r$   )r[   s   "r.   r\   r\     sW     .E .E.E.E .E 	.E
 .E .E .Er-   c           	         \         P                   ! 4       \        ^V4      ,           p\        ^\        V\        4      4      p\         P                   ! 4       V8  d   V P	                  V R2RRRVRV/R7      pVP
                  ^8X  d%   VP                  4       p	RV	9  d   \        R4      hV	#  VP                  4       p
T
P                  R
R4      pTR8X  d   \         P                  ! T4       K  TR8X  d,   \        T^,           ^4      p\         P                  ! T4       K  T
P                  R4      ;'       g    Rp\        T RT 24      h\        R4      h  \         d    TP                  4        \        R	4      hi ; i)zDPoll the token endpoint until the user approves or the code expires./api/oauth/tokenr  z,urn:ietf:params:oauth:grant-type:device_coder   rG  rF  r  z+Token response did not include access_tokenz1Token endpoint returned a non-JSON error responser   r   authorization_pending	slow_downr  zUnknown authentication errorz: z*Timed out waiting for device authorization)r  r  min%DEVICE_AUTH_POLL_INTERVAL_CAP_SECONDSr   r   r   r   r   rL  RuntimeErrorr4  r   r  )r  r   r   rG  r  rR  r&  current_intervalr  r   error_payload
error_codedescriptions   &&&&&&       r.   _poll_for_tokenr^    sv    yy{SJ//H1c-1VWX
))+
 ;;/0LY{  
 3&mmoGW, !NOON	T$MMOM
 #&&w3
00JJ'($"#3a#7<JJ'(#''(;<^^@^j\K=9::
C
DD!  	T%%'RSS	Ts   -E 'E=c          
     ,    V ^8  d   QhRRRRRRRRRR/# )	rW   r  rD  r   r   r   r  rZ   r   r$   )r[   s   "r.   r\   r\     sC      W  W W  W 	 W
  W  Wr-   c           	        V P                  V R 2RRRVRV/R7      pVP                  ^8X  d)   VP                  4       pRV9  d   \        RRRR	R
7      hV#  VP                  4       p\        TP                  RR4      4      p\        TP                  R4      ;'       g    R4      p	TR9   p
\        T	RYR
7      h  \         d   p\        RRR	R7      ThRp?ii ; i)rT  r  r  r   rF  r  z%Refresh response missing access_tokenr/   r  Tr  zRefresh token exchange failedr   r   Nr   r  r     r  r  )r   r   r   r   r   r   r4  )r  r   r   r  r  r   r[  r   r   r]  relogins   $$$$       r.   _refresh_access_tokenrd    s
    {{
+,/]
  H s"--/(C%+/TXZ ZI 
 }  /:;Dm''(;<__@_`K88G
K&t
VV  I7!'$@EH	IIs   B9 9CCCc          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
rW   r  rD  r   r   r  min_ttl_secondsr   rZ   r   r$   )r[   s   "r.   r\   r\   B  sC     W WW W 	W
 W Wr-   c                   V P                  V R2RRV 2/R\        ^<\        V4      4      /R7      pVP                  ^8X  d(   VP	                  4       pRV9  d   \        RRR	R
7      hV#  VP	                  4       p\        TP                  RR	4      4      p\        TP                  R4      ;'       g    R4      p	TR9   p
\        T	RYR7      h  \         d   p\        RRR	R
7      ThRp?ii ; i)z0Mint (or reuse) a short-lived inference API key.z/api/oauth/agent-keyr   r   rf  )r   r   r4   zMint response missing api_keyr/   server_errorr   r   zAgent key mint request failedNr   r  r  rb  )	r   r  r   r   r   r   r   r   r4  )r  r   r  rf  r  r   r[  r   r   r]  rc  s   $$$$       r.   _mint_agent_keyrj  B  s    {{
/0 GL>":;R_)=!>?  H s"--/G#;%+.B BG 
 }  .9:Dm''(;<__@_`K88G
K&t
VV  G7!'n>CF	GGs   +C C,C''C,verifyc          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
rW   r   r   r4   r   r   rk  r:  rZ   	List[str]r$   )r[   s   "r.   r\   r\   c  s<     6* 6*6* 6* 	6*
 6* 6*r-   c                n   \         P                  ! V4      p\         P                  ! VRR/VR7      ;_uu_ 4       pVP                  V P	                  R4       R2RRV 2/R7      pR	R	R	4       XP
                  ^8w  dl   R
VP
                   2p VP                  4       p\        VP                  R4      ;'       g    VP                  R4      ;'       g    T4      p\        VRRR7      hVP                  4       p
V
P                  R4      p\        V\        4      '       g   . # . pV F  p\        V\        4      '       g   K  VP                  R4      p\        V\        4      '       g   KD  VP                  4       '       g   K\  VP                  4       pRVP!                  4       9   d   K  VP#                  V4       K  	  R R lpVP%                  VR7       \        \        P'                  V4      4      #   + '       g   i     EL; i  \         d"   p	\        P                  RT	4        R	p	?	ELTR	p	?	ii ; i)z6Fetch available model IDs from the Nous inference API.r  r   rz   r   rk  r  z/modelsr   r   )r   Nz#/models request failed with status r  r   z'Could not parse error response JSON: %sr/   models_fetch_failedri  r  r   hermesc                    V ^8  d   QhRRRR/# )rW   midr   rZ   r!   r$   )r[   s   "r.   r\   'fetch_nous_models.<locals>.__annotate__  s      S U r-   c                z    V P                  4       pR V9   d   ^ V 3# RV9   d   RV9  d   ^V 3# RV9   d   ^V 3# ^V 3# )opusprosonnet)r   )rs  lows   & r.   _model_priority*fetch_nous_models.<locals>._model_priority  sM    iikS=s8OC<HC/s8Os?s8O3xr-   )key)r   r  r	  r4  r  r   r   r   r   r   r   r   r   r`  r+   r   r   rg   sortfromkeys)r   r4   r   rk  rz   r  r  r]  r  r  r   r  	model_idsitemmodel_idrs  rz  s   $$$$             r.   fetch_nous_modelsr  c  s    mmO,G	g:L/MV\	]	]ag::!((-.g6$y&9:  
 
^ s";H<P<P;QR	G--/Ccgg&9:]]cggg>N]]R]^K f;PQQmmoG;;vDdD!!	I$%%88D>h$$)9)9.."C399;&S!  NNN'i())[ 
^	]	]  	GLLBAFF	Gs/   +G4,H ;H H 4H	H4H//H4c               $    V ^8  d   QhRRRRRR/# )rW   rX  r   rf  r   rZ   r   r$   )r[   s   "r.   r\   r\     s&     P P P P Pr-   c                    V P                  R 4      p\        V\        4      '       d   VP                  4       '       g   R# \	        V P                  R4      V4      '       * # )	agent_keyFagent_key_expires_at)r4  r   r   r   r  )rX  rf  r|  s   && r.   _agent_key_is_usabler    sD    
))K
 Cc3syy{{EII&<=OOOr-   c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rW   r   r   r5  r9  r6  rt   r'  r   rZ   r   r$   )r[   s   "r.   r\   r\     sC     P% P%P% P% 	P%
 P% 	P%r-   c                .   \        4       ;_uu_ 4        \        4       p\        VR4      pV'       g   \        RRRR7      h\	        VP                  R4      4      ;'       gC    \        P                  ! R4      ;'       g%    \        P                  ! R4      ;'       g    \        P                  R4      p\        VP                  R	4      ;'       g    \        4      p\        WVR
7      pVP                  R4      p	VP                  R4      p
\        V	\        4      '       d	   V	'       g   \        RRRR7      h\        VP                  R4      V4      '       g   V	uuRRR4       # \        V
\        4      '       d	   V
'       g   \        RRRR7      h\        P                   ! V '       d   T MR4      p\        P"                  ! VRR/VR7      ;_uu_ 4       p\%        VVVV
R7      pRRR4       \&        P(                  ! \*        P,                  4      p\/        XP                  R4      4      pVR,          VR&   VP                  R4      ;'       g    T
VR&   VP                  R4      ;'       g    VP                  R4      ;'       g    RVR&   VP                  R4      ;'       g    VP                  R4      VR&   VP1                  4       VR&   WR&   \&        P2                  ! VP5                  4       V,           \*        P,                  R7      P1                  4       VR&   WeR&   WuR	&   RVRJ R\        V\        4      '       d   TMR/VR&   \7        VRV4       \9        V4       VR,          uuRRR4       #   + '       g   i     EL; i  + '       g   i     R# ; i) zKResolve a refresh-aware Nous Portal access token for managed tool gateways.r/   &Hermes is not logged into Nous Portal.Tra  r   HERMES_PORTAL_BASE_URLNOUS_PORTAL_BASE_URLr  r   r5  r6  r7  r  r  ,No access token found for Nous Portal login.
expires_atN2Session expired and no refresh token is available.r   r  r   ro  r  r   r   r  r  
token_typeBearerr   obtained_attzr5  Fr6  r<  )r'  r6  rY  r   r  r4  ri   r   DEFAULT_NOUS_PORTAL_URLr  r   DEFAULT_NOUS_CLIENT_IDrB  r   r  r   r  r	  rd  r   r?  r   r@  r  rA  fromtimestampr  r\  rT  )r   r5  r6  r'  r8  rX  r   r   rk  r  r  rz   r  r  r?  
access_ttls   $$$$            r.   resolve_nous_access_tokenr    s    
		%'
$Z88!%  uyy):;< ' 'yy12' 'yy/0' ' '
&+ 	 		+.HH2HI	 (TYZyy0		/2,,,L>!%  EIIl35IJJ= 
	@ ---]D!%  --?M\\12
 
 - /#+	I
 ll8<<((|)DE
 ). 9n!*!?!P!P=o'mmL9``UYY|=T``X`l"w/EE599W3Eg"}}m(l&44MMOj(||
 )+ 	l $3 &k%:fc#:#:
e 	Z7$^$Q 
	P
 
 
Q 
		so   AN!N?N2NAN(0N#N%N'+NM/	"A)NN*NN!CN/N :	NN	r  r  r   r  r  r  r  min_key_ttl_seconds
force_mintc          $     `    V ^8  d   Qh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RRRR/# )rW   r  r   r  r   r   r   r  r   r  rt   r  r  r  r  r   r   r   r5  r9  r6  r%  r   r  rZ   r   r$   )r[   s   "r.   r\   r\     s     R RRR R 	R
 R R R R R R (R R R R  !R" #R$ %R& 'Rr-   c               z   RT RTRT;'       g    \         RT;'       g    \        P                  R4      RT;'       g    \        P                  R4      RT;'       g    RR	T;'       g    \        R
VRVRV	RV
RR\        V4      RV//p\        WVR7      p\        P                  ! V'       d   TMR4      p\        P                  ! VRR/VR7      ;_uu_ 4       pV'       g'   \        VP                  R4      \        4      '       Ed   \        VVR,          VR,          VR,          R7      p\        P                  ! \         P"                  4      p\%        VP                  R4      4      pVR,          VR&   VP                  R4      ;'       g
    VR,          VR&   VP                  R4      ;'       g    VP                  R4      ;'       g    RVR&   VP                  R	4      ;'       g    VP                  R	4      VR	&   \'        VP                  R4      4      pV'       d   VVR&   VP)                  4       VR
&   VVR&   \        P*                  ! VP-                  4       V,           \         P"                  R7      P)                  4       VR&   V'       g&   \/        V\1        ^<\3        V4      4      4      '       g   \5        VVR,          VR,          VR7      p\        P                  ! \         P"                  4      pVP                  R4      VR&   VP                  R4      VR&   VP                  R4      VR&   VP                  R4      VR&   \        VP                  RR4      4      VR &   VP)                  4       VR!&   \'        VP                  R4      4      pV'       d   VVR&   R"R"R"4       V#   + '       g   i     T# ; i)#z4Refresh Nous OAuth state without mutating auth.json.r  r  r   r   r  r   r  r  r   r  r  r  r  r<  r5  r6  r  r   r  r   ro  r  r  r  r  r   r  rf  r4   key_idagent_key_idagent_key_expires_inreusedFagent_key_reusedagent_key_obtained_atN)r  r  r  DEFAULT_NOUS_INFERENCE_URLDEFAULT_NOUS_SCOPEr   rB  r   r  r	  r  r4  !ACCESS_TOKEN_REFRESH_SKEW_SECONDSrd  r   r?  r   r@  r  r  rA  r  r  r  r  r   rj  )r  r  r   r   r   r  r   r  r  r  r  r  r   r5  r6  r%  r  rX  rk  rz   r  r  r?  r  refreshed_urlmint_payload
minted_urls   &&&&&$$$$$$$$$$$$          r.   refresh_nous_oauth_purer    sM   , 	Y88"8OFF/FNNsS1OO5OWWX[\j,,H,,,{jY 4X
E" hPUVFmmODIG	g:L/MV\	]	]agL<)@Bcdd- %&7 8,#O4	I ,,x||,C,Y]]<-HIJ$-n$=E.!%.]]?%C%]%]u_G]E/""+--"="d"d<AX"d"d\dE,&]]73IIuyy7IE'N.y}}=Q/RSM.;*+#&==?E- ",E,"*"8"8*,#ik , 1%REXAY9Z[[* %&7 8">2 3	L ,,x||,C!-!1!1)!<E+$0$4$4X$>E.!,8,<,<\,JE(),8,<,<\,JE()(,\-=-=h-N(OE$%-0]]_E)*+L,<,<=Q,RSJ.8*+O 
^R LS 
^	]R Ls-   B4N)$N)2N)N))B'N)DN))N:	c               0    V ^8  d   QhRRRRRRRRR	RR
R/# )rW   rX  r   r  r   r   r   r%  r   r  rZ   r$   )r[   s   "r.   r\   r\   K  sF        	
   r-   c                  V P                  R4      ;'       g    / p\        V P                  RR4      V P                  RR4      V P                  RR4      V P                  R\        4      V P                  R\        4      V P                  R	R
4      V P                  R\        4      V P                  R4      V P                  R4      V P                  R4      V P                  R4      VVVP                  R4      VP                  R4      VVR7      # )zRRefresh Nous OAuth from a state dict. Thin wrapper around refresh_nous_oauth_pure.r<  r  r   r  r   r   r   r   r  r  r   r  r  r  r  r5  r6  )r  r   r  r  r  r  r  r   r5  r6  r%  r  )r4  r  r  r  r  )rX  r  r   r%  r  r<  s   &$$$$ r.   refresh_nous_oauth_from_stater  K  s     ))E

 
 bC"		."%		/2&		+|,		#%<=		&(BC99\84ii!34IIm,99\*))K("YY'=>/'$''+&## r-   c               0    V ^8  d   QhRRRRRRRRR	R
RR/# )rW   r  r   r   r   r5  r9  r6  rt   r  r   rZ   r   r$   )r[   s   "r.   r\   r\   j  sN     v vv v 	v
 v v vr-   c                (  aaa \        ^<\        V 4      4      p \        P                  ! 4       P                  R,          o\        4       ;_uu_ 4        \        4       o\        SR4      oS'       g   \        RRRR7      h\        SP                  R4      4      ;'       gC    \        P                  ! R4      ;'       g%    \        P                  ! R4      ;'       g    \        P                  R	4      p\        SP                  R
4      4      ;'       g%    \        P                  ! R4      ;'       g    \        P                  R	4      p\!        SP                  R4      ;'       g    \"        4      pR VVV3R llp\%        W#SR7      p	\&        P(                  ! V'       d   TMR4      p
\+        RS\-        V4      V \/        SP                  R4      4      R7       \&        P0                  ! V
RR/V	R7      ;_uu_ 4       pSP                  R4      pSP                  R4      p\3        V\         4      '       d	   V'       g   \        RRRR7      h\5        SP                  R4      \6        4      '       Ed   \3        V\         4      '       d	   V'       g   \        RRRR7      h\+        RSR\/        V4      R7       \9        WW}R7      p\:        P<                  ! \>        P@                  4      p\C        VP                  R4      4      pTpVR,          SR&   VP                  R4      ;'       g    TSR&   VP                  R 4      ;'       g    SP                  R 4      ;'       g    R!SR &   VP                  R"4      ;'       g    SP                  R"4      SR"&   \        VP                  R
4      4      pV'       d   TpVPE                  4       SR#&   VSR&   \:        PF                  ! VPI                  4       V,           \>        P@                  R$7      PE                  4       SR&   SR,          pSR,          p\+        R%SR\/        V4      \/        V4      R&7       V! R'4       R(pR)pV'       g#   \K        SV 4      '       d   Rp\+        R*SR+7       M% \+        R,S\/        V4      R-7       \M        WWR.7      pVe   \:        P<                  ! \>        P@                  4      pVP                  R34      SR4&   VP                  R54      SR6&   VP                  R4      SR7&   VP                  R4      SR8&   \-        VP                  R9R(4      4      SR:&   VPE                  4       SR;&   \        VP                  R
4      4      pV'       d   Tp\+        R<S\-        VP                  R9R(4      4      R=7       VSR&   VSR
&   VSR&   R>V	R(J R?\3        V	\         4      '       d   T	MR)/SR@&   R)R)R)4       V! RA4       R)R)R)4       SP                  R44      p\3        V\         4      '       d	   V'       g   \        RBRRCRD7      hSP                  R74      p\Q        V4      pVe0   \        ^ \        V\R        PR                  ! 4       ,
          4      4      M\C        SP                  R84      4      pRERRFXR3TR5SP                  R64      RTRTRGX'       d   RH/# RI/#   \         Ed+   p\+        R/STPN                  R07       SP                  R4      pTPN                  RJ9   Ed   \3        T\         4      '       Ed   T'       Ed   \+        RSR1\/        T4      R7       \9        YTTR7      p\:        P<                  ! \>        P@                  4      p\C        TP                  R4      4      pTR,          SR&   TP                  R4      ;'       g    TSR&   TP                  R 4      ;'       g    SP                  R 4      ;'       g    R!SR &   TP                  R"4      ;'       g    SP                  R"4      SR"&   \        TP                  R
4      4      pT'       d   TpTPE                  4       SR#&   TSR&   \:        PF                  ! TPI                  4       T,           \>        P@                  R$7      PE                  4       SR&   SR,          pSR,          p\+        R%SR1\/        T4      \/        T4      R&7       T! R24       \M        YYR.7      p R)p?EL>h R)p?ii ; i  + '       g   i     EL*; i  + '       g   i     EL.; i)Kaq  
Resolve Nous inference credentials for runtime use.

Ensures access_token is valid (refreshes if needed) and a short-lived
inference key is present with minimum TTL (mints/reuses as needed).
Concurrent processes coordinate through the auth store file lock.

Returns dict with: provider, base_url, api_key, key_id, expires_at,
expires_in, source ("cache" or "portal").
r   r/   r  Tra  r   r  r  r  r   NOUS_INFERENCE_BASE_URLr   c                    V ^8  d   QhRRRR/# )rW   reasonr   rZ   r   r$   )r[   s   "r.   r\   6resolve_nous_runtime_credentials.<locals>.__annotate__  s     	 	3 	4 	r-   c                &  <  \        SR S4       \        S4       \        RST \        SP                  R4      4      \        SP                  R4      4      R7       R#   \         d)   p\        RST \	        T4      P
                  R7       h Rp?ii ; i)r/   nous_state_persist_failed)r   r  
error_typeNnous_state_persistedr  r  )r   r  refresh_token_fpaccess_token_fp)r\  rT  r   r   typer%   r   r4  )r  r   r8  r   rX  s   & r.   _persist_state8resolve_nous_runtime_credentials.<locals>._persist_state  s    
$Z? , &'!3EIIo4N!O 2599^3L M  / +!#Cy11	 s   A B(#BBr  r   nous_runtime_credentials_startr  )r   r  r  r  r  r   ro  r  r  r  r  refresh_startaccess_expiring)r   r  r  r  r  r  r  r   r  r  refresh_success)r   r  previous_refresh_token_fpnew_refresh_token_fppost_refresh_access_expiringFNagent_key_reuse)r   
mint_start)r   r  r  
mint_error)r   r   mint_retry_after_invalid_tokenpost_refresh_mint_retryr4   r  r  r  r  r  r  r  r  mint_success)r   r  r5  r6  r<  &resolve_nous_runtime_credentials_finalz*Failed to resolve a Nous inference API keyrh  ri  r   r   r   cacheportalrb  )*r  r   rD  rE  rF  r'  r6  rY  r   r  r4  ri   r   r  r  r  r   r  rB  r   r  r   r   r   r	  r   r  r  rd  r   r?  r   r@  r  rA  r  r  r  rj  r   r  r  )r  r   r5  r6  r  r   r   r   r  rk  rz   r  r  r  r  r?  r  previous_refresh_tokenr  used_cached_keyr  r   latest_refresh_tokenr  r4   r  r  r  r8  r   rX  s   $$$$$                       @@@r.    resolve_nous_runtime_credentialsr  j  s   $ b#&9":;**,""3'K			%'
$Z8D%+dD D uyy):;< ' 'yy12' 'yy/0' ' '
&+ 	 uyy)=>? * *yy23* *)
&+	 	
 		+.HH2HI		 	( !(TYZ--?M,#J' 3/		/0JK	
 \\'H>P3QZ`aaek 99^4L!IIo6MlC00 N)/$H H EIIl35VWW!-55]#$X-3dL L # +,%7%F	 2!'	 ll8<<00|1LM
)6&(1.(An%)2)G)X)X=o&&/mmL&A&h&hUYY|E\&h&h`hl#!*w!7!M!M599W;Mg 29==AU3V W )6&'*}}m$&0l#&.&<&<MMOj0X\\')+ l#  %^4 %o 6% +,.@AW.X);M)J => $O59L"6u>Q"R"R"&.KH@ $$/(:<(H
 $3%%1$Lx 'll8<<0%1%5%5i%@k"(4(8(8(Bn%0<0@0@0N,-0<0@0@0N,-,01A1A(E1R,S()14-./0@0@AU0VW
)3&" + 0 05 AB (7E#$*<E&'!*E+FeOz&#'>'>VDE%Le bn 	?@U 
X ii$Ggs##7D!'n> 	> 12J(4M $ 	As=499;./0 +A!BC  	F&7%))N+jj_'  3; C ! 6 $$/ XX ,199_+E($FF&';SAA00$+(3#C-?@T-U	 %:#)&/?S%	 'll8<<8%8|9T%U
09.0In-1:1O1g1gSgo..7mmL.I.p.pUYYWcMd.p.phpl+)2w)?)U)U599WCUg(:9==I];^(_(1>./2}}m,.8l+.6.D.DMMOj8X\\/#)+ l+ (-^'<(-o(>$-(3#C6HI]6^1CM1R ''@A'6#))5(
 m6K baag 
		s   Ad d =d 6d d 02d #Bd :A c,	;Ac,	B4c,	c,	c,	9C$c,	"c,	$Z3%D&c,	d 3c)?Ac$B%c$ c$c$7C&c$c,	#c$$c))c,	,c=7	d  d	c                   V ^8  d   QhRR/# rW   rZ   r   r$   )r[   s   "r.   r\   r\   g  s      n r-   c                 8   \        R4      p V '       g   RRRRRRRRRRR	R/# R\        V P                  R
4      4      RV P                  R4      RV P                  R4      RV P                  R4      RV P                  R4      R	\        V P                  R4      4      /# )z+Status snapshot for `hermes status` output.r/   r  Fr   Nr   access_expires_atr  has_refresh_tokenr  r  r  )rk  r   r4  )rX  s    r.   get_nous_auth_statusr  g  s    #F+Et $"D
 	
 	T%))N34599%67eii(<=UYY|4		*@ AT%))O"<= r-   c                   V ^8  d   QhRR/# r  r$   )r[   s   "r.   r\   r\   }  s     .
 .
~ .
r-   c                     ^ RI Hp  V ! R4      pV'       d   VP                  4       '       d   VP                  4       pVeu   \	        VRR4      ;'       g    \	        VRR4      pV'       dK   \        V^ 4      '       g9   RRR	\        \        4       4      R
\	        VR
R4      RRRR\	        VRR4       2RV/#  \        4       pRRR	\        \        4       4      R
TP                  R
4      RTP                  R4      RTP                  R4      RTP                  R4      /#   \         d     Lsi ; i  \         d-   pRRR	\        \        4       4      R\        T4      /u Rp?# Rp?ii ; i)zStatus snapshot for Codex auth.

Checks the credential pool first (where `hermes auth` stores credentials),
then falls back to the legacy provider state.
)	load_poolr1   Nruntime_api_keyr  r   r  Tr8  r  r  r  r   zpool:r   unknownr4   Fr   )agent.credential_poolr  has_credentialsselectr  r  r   r   r   r4  r4  r   )r  ra  entryr4   credsr   s         r.   get_codex_auth_statusr  }  se   3(D((**KKME E#4d; : :unb9  #B7A#N#N#T$c/*;&<&~t(L#Y E'%)*L)M"N!7 
13#o/0EIIn5;/eii)uyy+
 	
    
#o/0SX
 	

sG   D D 'D D ,A	D 7A$D- D*)D*-E$8!EE$E$c                    V ^8  d   QhRRRR/# rW   r   r   rZ   r   r$   )r[   s   "r.   r\   r\     s      S ^ r-   c                   \         P                  V 4      pV'       d   VP                  R8w  d   RR/# RpRp\        W4      w  r#RpVP                  '       d0   \
        P                  ! VP                  R4      P                  4       pV R8X  d   \        W!P                  V4      pMV'       d   TpMVP                  pR\        V4      RV RVP                  RVR	VR
\        V4      /# )z<Status snapshot for API-key providers (z.ai, Kimi, MiniMax).r4   
configuredFr   r=   r   r   
key_sourcer   r  )rU   r4  r   r   r#   ri   r   r   r`   r   r   r   r   r   r4   r  env_urlr   s   &     r.   get_api_key_provider_statusr    s    ##K0Gg''94e$$GJ:;PGG))G44b9??Am#)'3M3MwW	-- 	d7mKjHT'] r-   c                    V ^8  d   QhRRRR/# r  r$   )r[   s   "r.   r\   r\     s      c n r-   c                Z   \         P                  V 4      pV'       d   VP                  R8w  d   RR/# \        P                  ! RR4      P                  4       ;'       g0    \        P                  ! RR4      P                  4       ;'       g    Rp\        P                  ! RR4      P                  4       pV'       d   \        P                  ! V4      MR	R
.pVP                  '       d0   \        P                  ! VP                  R4      P                  4       MRpV'       g   VP                  pV'       d   \        P                  ! V4      MRpR\        T;'       g    VP                  R4      4      RT RVP                  RTRTRTRTR\        T;'       g    VP                  R4      4      /# )z:Status snapshot for providers that run a local subprocess.r6   r  FHERMES_COPILOT_ACP_COMMANDr   COPILOT_CLI_PATHr3   HERMES_COPILOT_ACP_ARGS--acp--stdioN
acp+tcp://r   r   commandargsresolved_commandr   r  )rU   r4  r   ri   r   r   shlexr  r#   r   re   rf   r   r^   r   )r   r   r  raw_argsr  r   r  s   &      r.   $get_external_process_provider_statusr    sf   ##K0Gg''+==e$$ 			.399; 	 	99',224	 	 
 yy2B7==?H$,5;;x 7I2FDBIBZBZBZryy1126<<>`bH--07v||G,Td+PPx/B/B</PQK7,HT*OOh.A.A,.OP	 	r-   c                    V ^8  d   QhRRRR/# r^  r$   )r[   s   "r.   r\   r\     s          .  r-   c                   T ;'       g    \        4       pVR8X  d   \        4       # VR8X  d   \        4       # VR8X  d   \        V4      # \        P                  V4      pV'       d   VP                  R8X  d   \        V4      # RR/# )zGeneric auth status dispatcher.r/   r1   r5   r4   r  F)ro  r  r  r  rU   r4  r   r  )r   rr  r   s   &  r.   r  r    s~    11/1F#%%$&&3F;;##F+G7$$	1*622r-   c                    V ^8  d   QhRRRR/# r  r$   )r[   s   "r.   r\   r\     s     ! !c !n !r-   c           	        \         P                  V 4      pV'       d   VP                  R8w  d   \        RV  R2V RR7      hRpRp\	        W4      w  r#RpVP
                  '       d0   \        P                  ! VP
                  R4      P                  4       pV R8X  d   \        W!P                  V4      pM&V'       d   VP                  R4      pMVP                  pR	T RTR
VP                  R4      RT;'       g    R/# )zoResolve API key and base URL for an API-key provider.

Returns dict with: provider, api_key, base_url, source.
r4   
Provider 'z' is not an API-key provider.r  ri  r   r=   r  r   r   r   default)rU   r4  r   r   r   r#   ri   r   r   r`   r   r  r  s   &     r.   $resolve_api_key_provider_credentialsr    s    
  ##K0Gg''94%BC #
 	
 GJ:;PGG))G44b9??Am#)'3M3MwW	>>#&-- 	K7HOOC(*))		 r-   c                    V ^8  d   QhRRRR/# r  r$   )r[   s   "r.   r\   r\     s     % %s %~ %r-   c                f   \         P                  V 4      pV'       d   VP                  R8w  d   \        RV  R2V RR7      hVP                  '       d0   \
        P                  ! VP                  R4      P                  4       MRpV'       g   VP                  p\
        P                  ! RR4      P                  4       ;'       g0    \
        P                  ! RR4      P                  4       ;'       g    R	p\
        P                  ! R
R4      P                  4       pV'       d   \        P                  ! V4      MRR.pV'       d   \        P                  ! V4      MRpV'       g*   VP                  R4      '       g   \        RV R2V RR7      hRT RRRVP                  R4      RT;'       g    TRVRR/# )z>Resolve runtime details for local subprocess-backed providers.r6   r  z&' is not an external-process provider.r  ri  r   r  r  r3   r  r  r  Nr  z(Could not find the Copilot CLI command 'zQ'. Install GitHub Copilot CLI or set HERMES_COPILOT_ACP_COMMAND/COPILOT_CLI_PATH.missing_copilot_clir   r4   r5   r   r  r  r  r   process)rU   r4  r   r   r#   ri   r   r   r   r  r  re   rf   r^   r  )r   r   r   r  r  r  r  s   &      r.   -resolve_external_process_provider_credentialsr    s   ##K0Gg''+==%KL #
 	
 CJBZBZBZryy1126<<>`bH-- 			.399; 	 	99',224	 	 
 yy2B7==?H$,5;;x 7I2FD07v||G,TH$7$7$E$E6wi @] ] &	
 	
 	K=HOOC(#..w) r-   c                   V ^8  d   QhRR/# )rW   rZ   rf  r$   )r[   s   "r.   r\   r\   K  s      %9 r-   c            
         . p \        4       pV'       dH   \        P                  ! 4       R,          R,          pV P                  RRR\	        V4      RRV R2/4       V # )	a'  Scan for credentials from other CLI tools that Hermes can reuse.

Returns a list of dicts, each with:
  - provider: str   -- Hermes provider id (e.g. "openai-codex")
  - path: str       -- filesystem path where creds were found
  - label: str      -- human-friendly description for the setup UI
r  r   r   r1   rj   r   zCodex CLI credentials found (u4   ) — run `hermes auth` to create a separate session)r$  r   rh   rg   r   )foundr1  
codex_paths      r.   detect_external_credentialsr  K  sa     #%E *+JYY[8+k9
C
O4ZL@tu
 	 Lr-   c               (    V ^8  d   QhRRRRRRRR/# )rW   r   r   r   default_modelrt   rZ   r   r$   )r[   s   "r.   r\   r\   f  s0     ; ;;; !; 
	;r-   c                   \        4       ;_uu_ 4        \        4       pWR&   \        V4       RRR4       \        4       pVP                  P                  RRR7       / pVP                  4       '       dH    \        P                  ! VP                  4       4      ;'       g    / p\        V\        4      '       d   TpVP                  R4      p\        V\        4      '       d   \        V4      pMA\        V\        4      '       d*   VP                  4       '       d   RVP                  4       /pM/ pWR&   V'       d,   VP                  4       '       d   VP!                  R4      VR	&   MVP#                  R	R4       V'       d&   VP                  RR
4      p	V	'       d   RV	9   d   W(R&   WR&   VP%                  \        P&                  ! VRR7      4       V#   + '       g   i     EL; i  \         d    / p EL;i ; i)a  Update config.yaml and auth.json to reflect the active provider.

When *default_model* is provided the function also writes it as the
``model.default`` value.  This prevents a race condition where the
gateway (which re-reads config per-message) picks up the new provider
before the caller has finished model selection, resulting in a
mismatched model/provider (e.g. ``anthropic/claude-opus-4.6`` sent to
MiniMax's API).
r0  NTr  r   r   r   r  r   r   Fr   )r'  r6  rT  r   r
  r  r  yaml	safe_loadr3  r   r+   r   r4  r   r   r  popr  	safe_dump)
r   r   r  r8  config_pathconfigloadedcurrent_model	model_cfgcur_defaults
   &&&       r.   _update_config_for_providerr  f  s    
		%'
(3$%$ 
 "#KTD9F	^^K$9$9$;<BBF&$'' JJw'M-&&'		M3	'	'M,?,?,A,A 3 3 56		'j06688 2 9 9# >	* 	j$'
 mmIr2c[0#0i 7O4>>&EBCY 
		  	F	s#   G5*G&  G& G#	&G76G7c                   V ^8  d   QhRR/# r   r$   )r[   s   "r.   r\   r\     s       r-   c                    \        4       p V P                  4       '       g   V #  \        P                  ! V P	                  4       4      ;'       g    / p\        T\        4      '       g   T # TP                  R4      p\        T\        4      '       d   RTR&   RT9   d
   \        TR&   T P                  \        P                  ! TRR7      4       T #   \
         d    T u # i ; i)z5Reset config.yaml provider back to auto after logout.r   r  r   r   Fr  )r   r  r  r  r3  r   r   r+   r4  r   r  r  )r  r  r   s      r.   _reset_config_providerr    s    !#K 5 5 78>>B fd##JJwE%"j 3E*4>>&EBC  s   *C C CCc               (    V ^8  d   QhRRRRRRRR/# )	rW   r  rm  r  r   pricingz#Optional[Dict[str, Dict[str, str]]]rZ   rt   r$   )r[   s   "r.   r\   r\     s6     C CCC 1C 	Cr-   c                  aaaaaaaa ^ RI Hp . pS'       d   SV 9   d   VP                  S4       V  F  pWT9  g   K  VP                  V4       K  	  \        S;'       d;    \        ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      4      oS'       d   \        R V 4       ^ R7      ^,           M^ o/ o^o^ oRoS'       d   V F  pSP                  V4      pV'       d`   V! VP                  RR4      4      pV! VP                  R	R4      4      pVP                  R
R4      p	V	'       d	   V! V	4      MRp
V
'       d   RoMRRRrpWxV
3SV&   \        S\        V4      \        V4      4      o\        S\        V
4      4      oK  	  S'       d   \        S^4      oVVVVVVV3R lp^ pRpS'       dC   R#pRV RRS 2 RRRS 2 RRRS 2 2pS'       d   VRRRS 2 2,          pWR,           ,          p ^ RIH	p V Uu. uF  pRV! V4       2NK  	  ppVP                  R4       VP                  R4       V! VVRR$R%RRVR7      pVP                  4       pVf   R# \        4        V\        V4      8  d
   VV,          # V\        V4      8X  d&   \        R4      P                  4       pV'       d   V# R# R# u upi   \        \        3 d     Mi ; i\        T4       \        \!        \        T4      ^,           4      4      p\#        T^4       F!  w  pp\        RTRT 2 RT! T4       24       K#  	  \        T4      p\        RT^,           RT 2 R24       \        RT^,           RT 2 R24       \        4          \        RT^,            R 24      P                  4       pT'       g   R# \%        T4      p^Tu;8:  d   T8:  d   M MTT^,
          ,          # TT^,           8X  d&   \        R4      P                  4       pT'       d   T# R# TT^,           8X  d   R# \        R!T^,            24       K    \&         d    \        R"4        K  \(        \*        3 d     R# i ; i)&zInteractive model selection. Puts current_model first with a marker. Returns chosen model ID or None.

If *pricing* is provided (``{model_id: {prompt, completion}}``), a compact
price indicator is shown next to each model in aligned columns.
)_format_price_per_mtokc              3  F   <"   T F  pSP                  V4      x  K  	  R # 5ir   r4  ).0mr  s   & r.   	<genexpr>*_prompt_model_selection.<locals>.<genexpr>  s     &Gw!w{{1~~ws   !TFc              3  8   "   T F  p\        V4      x  K  	  R # 5ir   )r   )r$  r%  s   & r.   r&  r'    s     ,GqCFFGs   )r   promptr   
completioninput_cache_readc                   < S
'       dI   SP                  V R4      w  rpRVRS 2 RVRS 2 2pS	'       d   VRVRS 2 2,          pV RS 2 V 2pMT pV S8X  d
   VR,          pV# )r   r  >  <u     ← currently in use)r   r   r   r#  )rs  inpoutr  
price_partbase_price_cache	cache_colr  	has_cachehas_pricingname_col	price_cols   &     r.   _label'_prompt_model_selection.<locals>._label  s    *..sLAOCeS9+.bQykM0BCJ59+"677
!H:&zl3DD-,,Dr-   zSelect default model:r  r<  r-  Inr.  OutCachez  /Mtok)TerminalMenuz  Enter custom model namez  Skip (keep current)z-> )cursor_indexmenu_cursormenu_cursor_stylemenu_highlight_stylecycle_cursorclear_screentitleNzEnter model name: z. z. Enter custom model namez. Skip (keep current)z
Choice [1-z] (default: skip): zPlease enter 1-zPlease enter a numberz     )fg_greenbold)rG  )hermes_cli.modelsr!  rg   r   anyr  r4  r   simple_term_menur?  showr-  inputr   ImportErrorNotImplementedErrorr   	enumerater   r   KeyboardInterruptEOFError)r  r  r  r!  orderedrs  pr0  r1  
cache_readr  r:  default_idx
menu_titlepadheaderr?  choicesmenuidxr  	num_widthinchoicer4  r5  r6  r7  r8  r9  s   &ff                      @@@@@@r.   _prompt_model_selectionra    s5    9 G)3}%NN3 
 wGG33&Gw&G333&Gw&G#GHK@Ks,G,a81<QRH 57LIIICC A,QUU8R-@A,QUU<-DEUU#5r:
>H.z:b $I"$b"%!$5 1LIs3xS:IIs5z2I  Iq)I  K )J cU2az\*!D9++>bqm@TU71YK-011Fy((
1189#Rs}%923./$2!.	
 iik;W3<CL /0668F#6--- :. ,-  
*CGq()*IGQ'31QykM""VC[M23 (GA	Bq1uQykM"";
<=	Bq1uQykM""7
89	G
	ZAw.ABCIIKFf+CC}1}sQw''A34::<!'v1T1AOAE7+, 	+)*!8, 		ss   
K K#AK -"K 2K K K K K ,Q <,Q )0Q Q Q ,Q Q0Q0+Q0/Q0c                    V ^8  d   QhRRRR/# )rW   r  r   rZ   r   r$   )r[   s   "r.   r\   r\   A	  s        r-   c                    ^ RI HpHp V! 4       p\        VP	                  R4      \
        4      '       d   WR,          R&   MRV /VR&   V! V4       R# )u   Save the selected model to config.yaml (single source of truth).

The model is stored in config.yaml only — NOT in .env.  This avoids
conflicts in multi-agent setups where env vars would stomp each other.
)save_configload_configr   r   N)r  rd  re  r   r4  r+   )r  rd  re  r  s   &   r.   _save_model_choicerf  A	  sF     ;]F&**W%t,,%-w	"$h/wr-   c                   V ^8  d   QhRR/# rv  r$   )r[   s   "r.   r\   r\   R	  s      4 r-   c                Z    \        R4       \        R4       \        R4       \        ^ 4      h)z9Deprecated: use 'hermes model' or 'hermes setup' instead.z,The 'hermes login' command has been removed.z(Use 'hermes auth' to manage credentials,zF'hermes model' to select a provider, or 'hermes setup' for full setup.)r-  
SystemExit)r  s   &r.   login_commandrj  R	  s'    	
89	
45	
RS
Q-r-   c                    V ^8  d   QhRRRR/# rW   r   r   rZ   r   r$   )r[   s   "r.   r\   r\   Z	  s     >L >L~ >L$ >Lr-   c                p    \        4       pVP                  RR4      p\        V\        4      '       d   V'       d   \	        V^<4      '       g   \        R4        \        R4      P                  4       P                  4       pVR9   dG   \        RVP                  R\        4      4      p\        4        \        R4       \        R	V R
24       R# M\        R4        \        4       pV'       d   \        R4       \        R4        \        R4      P                  4       P                  4       pVR9   d   \        V4       \         P"                  ! RR4      P                  4       P%                  R4      ;'       g    \        p\        RV4      p\        4        \        R4       \        R4       \        R	V R
24       R# \        4        \        R4       \        R4       \        4        \'        4       p	\        V	R,          V	P                  R4      4       \        RV	P                  R\        4      4      p\        4        \        R4       ^ RIHp
 \        RV
! 4        R24       \        R	V R
24       R#   \        \        3 d    Rp ELi ; i  \         d     ELi ; i  \        \        3 d    Rp ELi ; i)zNOpenAI Codex login via device code flow. Tokens stored in ~/.hermes/auth.json.r4   r   z6Existing Codex credentials found in Hermes auth store.z!Use existing credentials? [Y/n]: yr1   r   Login successful!  Config updated: z (model.provider=openai-codex)Nz?Existing Codex credentials are expired. Starting fresh login...z:Found existing Codex CLI credentials at ~/.codex/auth.jsonzOHermes will create its own session to avoid conflicts with Codex CLI / VS Code.zCImport these credentials? (a separate login is recommended) [y/N]: r_  r,  r  z=Credentials imported. Note: if Codex CLI refreshes its token,z<Hermes will keep working independently with its own session.zSigning in to OpenAI Codex...uF   (Hermes creates its own session — won't affect Codex CLI or VS Code)r  r  )display_hermes_home  Auth state: z
/auth.json)r   rn  r   )rn  r   )r4  r4  r   r   r  r-  rM  r   r   rR  rQ  r  r/  r   r$  r  ri   r   r  _codex_device_code_loginhermes_constantsrq  )r  r   existing_resolved_keyreuser  r1  	do_importr   r  _dhhs   &&         r.   _login_openai_codexrz  Z	  sU   46
 !Y3mS))mDcdqsuDvDvJKABHHJPPR ((9.(,,WacyJz{)**;-7UVW ) ST
 *+JJK_`	cdjjlrrtI $z*yy!8"=CCELLSQkkUkH5nhOKGQRPQ&{m3QRS 
G	
)*	
RS	G$&E uX		.(AB-neii
Tj>klK	G	
<	N46(*
-.	{m+I
JK_ /0    +, 	I	sS   9J J 'I2 AJ J 'J 2J	J J		J JJJ54J5c                   V ^8  d   QhRR/# r  r$   )r[   s   "r.   r\   r\   	  s     N N. Nr-   c                 V	   ^ RI p Rp\        p \        P                  ! \        P                  ! R4      R7      ;_uu_ 4       pVP                  V R2RV/RR/R	7      pRRR4       XP                  ^8w  d   \        RTP                   R2RRR7      hTP                  4       pTP                  RR4      pTP                  RR4      p\        ^\        TP                  RR4      4      4      p	T'       d	   T'       g   \        RRRR7      h\        R4       \        R4       \        RT R24       \        R4       \        RT R24       \        R4       RBp
T P                  4       pRp \        P                  ! \        P                  ! R4      R7      ;_uu_ 4       pT P                  4       T,
          T
8  d   T P                  T	4       TP                  T R2RTRT/RR/R	7      pTP                  ^8X  d   TP                  4       pM/TP                  RC9   d   K  \        R TP                   R2RR!R7      hRRR4       Tf   \        R#RR$R7      hTP                  R%R4      pTP                  R&R4      pT R'2pT'       d	   T'       g   \        R(RR)R7      h \        P                  ! \        P                  ! R4      R7      ;_uu_ 4       pTP                  \$        R*R%R+TR,TRTR&T/RR-/R.7      pRRR4       XP                  ^8w  d   \        R1TP                   R2RR2R7      hTP                  4       pTP                  R3R4      pTP                  R4R4      pT'       g   \        R5RR6R7      h\&        P(                  ! R7R4      P+                  4       P-                  R84      ;'       g    \.        pR9R3TR4T/R:TR;\0        P2                  ! \4        P6                  4      P9                  4       P;                  R<R=4      R>R?R@RA/#   + '       g   i     EL; i  \         d   p\        R
T 2RRR7      hRp?ii ; i  + '       g   i     EL; i  \          d    \        R"4       \#        ^4      hi ; i  + '       g   i     EL; i  \         d   p\        R/T 2RR0R7      hRp?ii ; i)DzBRun the OpenAI device code login flow and return credentials dict.Nzhttps://auth.openai.comr   )rz   z!/api/accounts/deviceauth/usercoder   r   r   )r   r   zFailed to request device code: r1   device_code_request_failedri  z$Device code request returned status r=  device_code_request_errorrH  r   device_auth_idrK  5z-Device code response missing required fields.device_code_incompletez!To continue, follow these steps:
z#  1. Open this URL in your browser:z
     [94mz/codex/device[0m
z  2. Enter this code:z[0m
z/Waiting for sign-in... (press Ctrl+C to cancel)z/api/accounts/deviceauth/tokenz$Device auth polling returned status device_code_poll_error
Login cancelled.z!Login timed out after 15 minutes.device_code_timeoutauthorization_codecode_verifierz/deviceauth/callbackzADevice auth response missing authorization_code or code_verifier.device_code_incomplete_exchanger  r   redirect_urir  )r  r   zToken exchange failed: token_exchange_failedzToken exchange returned status token_exchange_errorr  r  z.Token exchange did not return an access_token.token_exchange_no_access_tokenr,  r  r  r   r  r  r  r  r  r   zdevice-codei  )i  i  )r  r  r   r	  r  r   r   r   r   r   r4  r  r   r-  	monotonicr   rQ  ri  r
  ri   r   r   r  r/  r   r?  r   r@  rA  rJ  )_timeissuerr   r  r   r   device_datarH  r  rR  max_waitstart	code_resp	poll_respr  r  r  
token_respr  r  r  r   s                         r.   rs  rs  	  s   &F%I
\\%--"566&;;(;<!9-');<  D 7 3243C3C2DAF#*E
 	

 ))+KR0I __%5r:N3{z3?@AMN;#*B
 	
 

./	
/0	M&!7
89	
!"	M)I
./	
;< HOOEI\\%--"566&//#e+h6M*"KKh<=*NKS+-?@ ( 	 ((C/ ) 0I**j8#>y?T?T>UUVW!/6N  7. /#*?
 	
 #';R@MM/26MX12L]O#*K
 	


\\%--"566&% "6."L#] ()LM % 
J 7$ $-j.D.D-EQG#*@
 	

 __F::nb1LJJ3M<#*J
 	
 			)2.446==cB 	" 	"!  	L]
 	HX\\2<<>FFxQTUY-	 	y 766  
-cU3#*F
 	

J 766&  "#o, 766  
%cU+#*A
 	

s   3P PP (3Q BP:7Q 3R %Q31R P	P P P7!P22P7:Q	Q Q "Q03R	>R R R(R##R(r   r   r   open_browserc               @    V ^8  d   QhRRRRRRRRRRRR	R
RRRRRRR/
# )rW   r   rt   r   r   r   r  r   r   r   r5  r6  r  r   rZ   r   r$   )r[   s   "r.   r\   r\   ,
  sz     @ @"@ &@ 	@
 @ @ @ @ @ @ @r-   c        	        z	   \         R,          p	T ;'       gI    \        P                  ! R4      ;'       g+    \        P                  ! R4      ;'       g    V	P                  P	                  R4      p T;'       g+    \        P                  ! R4      ;'       g    V	P
                  P	                  R4      p
T;'       g    V	P                  pT;'       g    V	P                  p\        P                  ! V4      pV'       d   RMV'       d   TMRp\        4       '       d   Rp\        RV	P                   R	24       \        R
V  24       V'       d   \        R4       MV'       d   \        RV R24       \        P                  ! VRR/VR7      ;_uu_ 4       p\        VV VVR7      p\        VR,          4      p\        VR,          4      p\!        VR,          4      p\!        VR,          4      p\        4        \        R4       \        RV 24       \        RV 24       V'       d6   \"        P$                  ! V4      pV'       d   \        R4       M\        R4       \'        ^\)        V\*        4      4      p\        RV R24       \-        VV V\        VR,          4      VVR7      pRRR4       \.        P0                  ! \2        P4                  4      p\7        XP9                  R^ 4      4      pVP;                  4       V,           p\=        VP9                  R 4      4      ;'       g    T
pVV
8w  d   \        R!V 24       / R"V bR VbR#VbR$VP9                  R$4      ;'       g    TbR%VP9                  R%R&4      bR'VR',          bR(VP9                  R(4      bR)VP?                  4       bR*\.        P@                  ! V\2        P4                  R+7      P?                  4       bRVbR,R-VRJ R.\C        V\        4      '       d   TMR/bR/RbR0RbR1RbR2RbR3RbR4Rbp \E        VVVRRR57      #   + '       g   i     EL; i  \F         d   pTPH                  R68X  dj   TP9                  R"\J        4      P	                  R4      p\        4        \        R74       \        R8T R924       \        4        \        R:4       \M        ^4      hh Rp?ii ; i);zMRun the Nous device-code flow and return full OAuth state without persisting.r/   r  r  r  r  FTzStarting Hermes login via z...zPortal: z'TLS verification: disabled (--insecure)z$TLS verification: custom CA bundle ()r  r   ro  )r  r   r   r   rJ  rH  r  rK  zTo continue:z  1. Open: z  2. If prompted, enter code: z#  (Opened browser for verification)u=     Could not open browser automatically — use the URL above.z$Waiting for approval (polling every zs)...rG  )r  r   r   rG  r  rR  Nr   z%Using portal-provided inference URL: r   r   r   r  r  r  r  r  r  r  r<  r5  r6  r  r  r  r  r  r  )r  r   r%  r  r   z>Your Nous Portal account does not have an active subscription.z  Subscribe here: z/billingz<After subscribing, run `hermes model` again to finish setup.)'rU   ri   r   r   r  r   r   r   r   r  r  r-  r   r	  rP  r   r   
webbrowserr  r  rW  rX  r^  r   r?  r   r@  r  r4  r  r  rA  r  r   r  r   r   r  ri  )r   r   r   r   r  r   r5  r6  r  r   requested_inference_urlrz   rk  r  r  verification_urlrH  r  rK  openedeffective_interval
token_datar?  token_expires_inr  resolved_inference_urlr7  r   
portal_urls   $$$$$$$$$                    r.   _nous_device_code_loginr  ,
  s     'G 	# 	#99-.	# 	#99+,	# 	# ""fSk  	 	& 	&99./	& 	&%%fSk	 
 ..W..I""W]]EmmO,G"*iTF	&w||nC
89	H_%
&'78	4YKqAB	g:L/MV\	]	]ag*+	
 {+FGHK01	\23
{:./n,-./.yk:;__%56F;<UV C2W$XY45G4HNO$+K67!"

9 
^J ,,x||
$C*:>>,+JK#33J:>>*>?@ 	# 	#"  !8856L5MNO?4 	Y 	(11E	
 	jnn\8< 	
>2 	8 	s}} 	h,,ZHLLISSU 	& 	%:fc#:#:
 	T  	!" 	#$ 	%& 	D'( 	 )J,, 3+
 	
M 
^	]	]Z  88..#!#:fSk  GRS&zl(;<GPQQ-s-   B.P A!PP/ P,	/R::A;R55R:c                    V ^8  d   QhRRRR/# rl  r$   )r[   s   "r.   r\   r\   
  s     D D~ D$ Dr-   c                :   \        V RR4      ;'       g    Rp\        \        V RR4      4      p\        V RR4      ;'       g5    \        P                  ! R4      ;'       g    \        P                  ! R4      p \	        \        V R	R4      \        V R
R4      \        V RR4      ;'       g    VP
                  \        V RR4      ;'       g    VP                  \        V RR4      '       * VVVR#R7	      pVR,          pV'       d   RMV'       d   TMRp\        4       ;_uu_ 4        \        4       p\        VRV4       \        V4      p	RRR4       \        RV4      p
\        4        \        R4       \        RX	 24       \        RV
 R24        VP                  R4      ;'       g    VP                  R4      p\        V\        4      '       d	   V'       g   \!        RRRR7      h^ RIHp VP                  R. 4      p\        4        V'       dI   \        R\'        V4       R24       \)        V4      pV'       d   \+        V4       \        RV 24       R# R# \        R4       R#   + '       g   i     EL%; i  \,         dP   p\        T\         4      '       d   \/        T4      M
\        T4      p\        4        \        R T 24        Rp?R# Rp?ii ; i  \0         d    \        R!4       \3        ^4      h\,         d   p\        R"T 24       \3        ^4      hRp?ii ; i)$z&Nous Portal device authorization flow.rz   Nr   r5  Fr6  r=  r>  r  inference_urlr   r   
no_browser)	r   r   r   r   r  r   r5  r6  r  r   Tr/   ro  rr  rp  z (model.provider=nous)r  r  z,No runtime API key available to fetch modelsr  ri  )_PROVIDER_MODELSzShowing u=    curated models — use "Enter custom model name" for others.zDefault model set to: z,No curated models available for Nous Portal.z?Login succeeded, but could not fetch available models. Reason: r  zLogin failed: ,  )r  r   ri   r   r  r   r   r'  r6  r\  rT  r  r-  r4  r   r   r   rI  r  r   ra  rf  r   r   rQ  ri  )r  r   r   r5  r6  r7  r   rk  r8  saved_tor  runtime_keyr  r  selected_modelr   r   s   &&               r.   _login_nousr  
  s   dIt4<<OGD*e45Hk4( 	& 	&99'(	& 	&99_% :,#D,=&t_dCdK6KK':K:K$.??'--$T<??+ &


 ((<=&.U)YQU)+J VZ@'
3H  
 2&:LM!"xj)*";-/EFG	_$..5WW9WKk3//{B#(  ;(,,VR8IGY 00opq!8!C!&~62>2BCD " DE?  @  	_0:3	0J0J',PSTWPXGGST[S\]^^	_
  "#o se$%msx   8AK 	AK K !#I AK AI4 A<I4 I4  I1	+	K 4K?AK	K 	KK )L;L<LLc                   V ^8  d   QhRR/# rv  r$   )r[   s   "r.   r\   r\   
  s     ; ;D ;r-   c                   \        V RR4      pV'       d%   V\        9  d   \        RV 24       \        ^4      h\	        4       pT;'       g    TpV'       g   \        R4       R# V\        9   d   \        V,          P
                  MTp\        V4      '       dP   \        4        \        RV R24       \        P                  ! R4      '       d   \        R4       R# \        R	4       R# \        R
V R24       R# )z Clear auth state for a provider.r   NzUnknown provider: z#No provider is currently logged in.zLogged out of r=  r  z)Hermes will use OpenRouter for inference.z9Run `hermes model` or configure an API key to use Hermes.zNo auth state found for )
r  rU   r-  ri  ro  r   rt  r  ri   r   )r  r   r  rr  rz  s   &    r.   logout_commandr  
  s    $
D1K{*;;";-01m "F""FF346<@Q6Q%f-22W]M6"" }oQ/099)**=>MN(q9:r-   i  )COPILOT_GITHUB_TOKENGH_TOKENGITHUB_TOKEN)GOOGLE_API_KEYGEMINI_API_KEY)GLM_API_KEYZAI_API_KEYZ_AI_API_KEY)KIMI_API_KEY)MINIMAX_API_KEY)ANTHROPIC_API_KEYANTHROPIC_TOKENCLAUDE_CODE_OAUTH_TOKEN)DASHSCOPE_API_KEY)MINIMAX_CN_API_KEY)DEEPSEEK_API_KEY)AI_GATEWAY_API_KEY)OPENCODE_ZEN_API_KEY)OPENCODE_GO_API_KEY)KILOCODE_API_KEY)HF_TOKEN>   *nonenulldummyexamplechangemeplaceholderyour_api_key*****your-api-key))globalr;   glm-5Global)cnz$https://open.bigmodel.cn/api/paas/v4r  China)zcoding-globalz#https://api.z.ai/api/coding/paas/v4glm-4.7zGlobal (Coding Plan))z	coding-cnz+https://open.bigmodel.cn/api/coding/paas/v4r  zChina (Coding Plan))g       @r   )r   Nr  )__conditional_annotations__r)   
__future__r   r   loggingri   re   r  r  r  r   r{   	threadingr  rD  r  
contextlibr   dataclassesr   r   r   r   pathlibr   typingr	   r
   r   r   r   r  r  r   r   rt  r   	getLoggerr%   r   r  r   r  r1  r.  r  r  r  r  !DEFAULT_AGENT_KEY_MIN_TTL_SECONDSr  rX  r/  DEFAULT_GITHUB_MODELS_BASE_URLDEFAULT_COPILOT_ACP_BASE_URLDEFAULT_GEMINI_BASE_URLr  r
  'CODEX_ACCESS_TOKEN_REFRESH_SKEW_SECONDSr   rU   r*   r_   r`   rq   r   r   r   r   r   r   rY  r   r   r   r   r   r   r   localr	  r'  r6  rT  rY  r\  rc  rh  rk  ro  rt  rx  r  r  r  r  r  r  r  r  r  r  r  r  r  r$  r4  rB  rP  r^  rd  rj  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  ra  rf  rj  rz  rs  r  r  r  )r  s   @r.   <module>r     s   #   	           % ( '  , ,   > 0			8	$     < H % / $+ !$' !() %@ !@ . S 6 = *- '    I0
N%/5( I0 N"1	I0  ~9M!I0. >!$7//I0< nT=*=I0L 
>9G'MI0\ >7*(]I0l ~=-+mI0| 6\}I0J ~(S/-KI0Z .?0.[I0j 8.,kI0z .<0.{I0J N720KI0Z >
 ;1/[I0r <.,sI0B >=&&CI0 , Ih 6 
*$ 	q 	B! !P1 1"4D-
[T [+2 OO% .G 6 6r< <:!H<0	P 	P	,9-# #L	%"2\ '+\ (,	\ \F"9(
6CA. .b% %W "	Wt*D<< !%< !H	<F#  $ ,0	>6.Ej WFWB6* "	6*
 6*rPP%!P%  $P%  $	P%
 !BP%fR R $R "&R !%R  $R +/R  AR "R  $R   $!R"  #R$ %Rj  A "	
   >v@v "v  $	v
  $v vz,.
b><    !H%X6; ;|.C CL">LBNb@%)@ )-@  $	@
  @ @ "@ @  $@  &@FDN; ;OV  E  Fs$   P8 Q 8	QQ	QQ