
    Ji                      U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlZddlmZ ddlmZmZ ddlmZmZ ddlmZ ddlmZmZmZmZ ddlZddlZdd	l m!Z!m"Z" dd
l#m$Z$  ej%        e&          Z'	 ddl(Z(n# e)$ r dZ(Y nw xY w	 ddl*Z*n# e)$ r dZ*Y nw xY wdZ+dZ,dZ-dZ.dZ/dZ0dZ1dZ2dZ3dZ4dZ5dZ6dZ7dZ8dZ9e G d d                      Z:i d e:ddde-e.e/e0          d e:ddd e4!          d" e:d"d#d$e5d%&          d' e:d'd(d)e6d*+          d, e:d,d-d$d.d/d01          d2 e:d2d3d$d4d5d61          d7 e:d7d8d$d9d:d;1          d< e:d<d=d$d>d?&          d@ e:d@dAd$dBdCdD1          dE e:dEdFd$dGdHdI1          dJ e:dJdKd$dLdMdN1          dO e:dOdPd$dQdRdS1          dT e:dTdUd$dVdWdX1          dY e:dYdZd$d[d\d]1          d^ e:d^d_d$d`dadb1          dc e:dcddd$dedfdg1          Z;dhe<di<   djZ=ddoZ>ddqZ?ddsZ@h dtZAdudvdd|ZBddZCg dZDdddZE G d deF          ZGddZHddZIddZJddddZKddZLddZM ejN                    ZOee,fd d            ZPd!d"dZQd#dZRd$dZSd%dZTd!d&dZUd'dZVd(dZWddZXd!d)dZYd*dZZ	 d!dddd+dZ[d,dZ\d-dZ]d.dZ^d/dZ_d0dZ`d1dZaddZbddd2dZcd!d3dĄZdddƜd4dȄZed5dɄZfd6dʄZgdde9d̜d7dЄZhddddќd8dׄZid9d݄Zjd:dZkd;dZld<dZmdddd=dZnd>dZoddde2dd?dZpde0dddde1ddddddd@dZqe1dddddAdZre1ddddddBdZsdCdZtdCdZudDdZvdDdZwd!d&dZxdDdZydDd ZzdEdZ{	 d!dFdZ|ddZ}dGdHdZ~dId
Zd*dZdJdZdCdZdddddddddd	dKdZdJdZd*dZdS (L  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_keyi  x   z%https://chatgpt.com/backend-api/codexzhttps://api.githubcopilot.comzacp://copilotapp_EMoamEEZ73f0CkXaXp7hrannz#https://auth.openai.com/oauth/tokenc                      e Zd ZU dZded<   ded<   ded<   dZded<   dZded<   dZded	<   dZded
<    e	e
          Zded<   dZded<   dZded<   dS )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_varN)__name__
__module____qualname____doc____annotations__r   r   r   r    r   dictr#   r&   r'   r$       ,/home/ubuntu/hermes-agent/hermes_cli/auth.pyr   r   Q   s         //GGGIIINNNO     IEOOOO!E$777E7777     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)COPILOT_GITHUB_TOKENGH_TOKENGITHUB_TOKEN)r   r   r   r   r&   copilot-acpzGitHub Copilot ACPexternal_processCOPILOT_ACP_BASE_URL)r   r   r   r   r'   zaiz
Z.AI / GLMhttps://api.z.ai/api/paas/v4)GLM_API_KEYZAI_API_KEYZ_AI_API_KEYGLM_BASE_URL)r   r   r   r   r&   r'   kimi-codingzKimi / Moonshotzhttps://api.moonshot.ai/v1)KIMI_API_KEYKIMI_BASE_URLminimaxMiniMaxz https://api.minimax.io/anthropic)MINIMAX_API_KEYMINIMAX_BASE_URL	anthropic	Anthropiczhttps://api.anthropic.com)ANTHROPIC_API_KEYANTHROPIC_TOKENCLAUDE_CODE_OAUTH_TOKENalibabazAlibaba Cloud (DashScope)z6https://dashscope-intl.aliyuncs.com/compatible-mode/v1)DASHSCOPE_API_KEYDASHSCOPE_BASE_URL
minimax-cnzMiniMax (China)z"https://api.minimaxi.com/anthropic)MINIMAX_CN_API_KEYMINIMAX_CN_BASE_URLdeepseekDeepSeekzhttps://api.deepseek.com/v1)DEEPSEEK_API_KEYDEEPSEEK_BASE_URL
ai-gatewayz
AI Gatewayzhttps://ai-gateway.vercel.sh/v1)AI_GATEWAY_API_KEYAI_GATEWAY_BASE_URLopencode-zenzOpenCode Zenzhttps://opencode.ai/zen/v1)OPENCODE_ZEN_API_KEYOPENCODE_ZEN_BASE_URLopencode-gozOpenCode Gozhttps://opencode.ai/zen/go/v1)OPENCODE_GO_API_KEYOPENCODE_GO_BASE_URLkilocodez	Kilo Codezhttps://api.kilo.ai/api/gateway)KILOCODE_API_KEYKILOCODE_BASE_URLhuggingfacezHugging Facez https://router.huggingface.co/v1)HF_TOKENHF_BASE_URLzDict[str, ProviderConfig]PROVIDER_REGISTRYzhttps://api.kimi.com/coding/v1r   default_urlenv_overridereturnc                F    |r|S |                      d          rt          S |S )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)r5   rh   ri   s      r/   _resolve_kimi_base_urlrn      s4      *%% "!!r.   	list[str]c                 n   g } t          j        d          }|r|                     |           ddt          t	          j                    dz  dz  dz            fD ]Z}|| v rt          j                            |          r4t          j	        |t          j
                  r|                     |           [| S )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_candidatesr      s    J|D!!H $(### 	DIKK("U*T122 ) )	
 
""7>>)$$ 	)9bg)F)F 	)i(((r.   Optional[str]c                 ^   t                      D ]} 	 t          j        | ddgddd          }n?# t          t          j        f$ r&}t
                              d| |           Y d}~Vd}~ww xY w|j        dk    r4|j        	                                r|j        	                                c S dS )	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): %sNr   )
r   
subprocessrunFileNotFoundErrorTimeoutExpiredloggerdebug
returncodestdoutstrip)gh_pathresultexcs      r/   _try_gh_cli_tokenr     s    %'' ) )		^&'*#	  FF ":#<= 	 	 	LL>MMMHHHH	 !!fm&9&9&;&;!=&&(((((4s   .A*A%%A*>   *****your-api-key*nonenulldummyexamplechangemeplaceholderyour_api_key   )
min_lengthvaluer
   r   intboolc                   t          | t                    sdS |                                 }t          |          |k     rdS |                                t
          v rdS dS )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   4  sZ    eS!! ukkmmG
7||j  u}}444u4r.   provider_idpconfigtuple[str, str]c                R   | dk    rZ	 ddl m}  |            \  }}|r||fS n=# t          $ r%}t                              d|           Y d}~nd}~wt
          $ r Y nw xY wdS |j        D ]>}t          j        |d          	                                }t          |          r||fc S ?dS )zDResolve an API-key provider's token and indicate where it came from.r4   r   )resolve_copilot_tokenz#Copilot token validation failed: %sN)r   r   r   )hermes_cli.copilot_authr   
ValueErrorr   warning	Exceptionr&   rw   getenvr   r   )r   r   r   r   sourcer   env_varvals           r/    _resolve_api_key_provider_secretr   @  s    i	EEEEEE1133ME6 %f}$% 	G 	G 	GNN@#FFFFFFFF 	 	 	D	v+    i$$**,,S!! 	 <	  6s   " 
AAAA))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)       @r   floatOptional[Dict[str, str]]c                   t           D ]\  }}}}	 t          j        | dd|  dd|ddddd	gd
|          }|j        dk    r%t                              d||           ||||dc S t                              d||j                   # t          $ r&}t                              d||           Y d}~d}~ww xY wdS )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Bearer application/json)AuthorizationContent-TypeFr   userping)rolecontent)modelstream
max_tokensmessages)headersjsonr      zZ.AI endpoint probe: %s (%s) OK)r   base_urlr   labelz#Z.AI endpoint probe: %s returned %sz"Z.AI endpoint probe: %s failed: %sN)ZAI_ENDPOINTShttpxpoststatus_coder   r   r   )r5   r   ep_idr   r   r   respr   s           r/   detect_zai_endpointr   j  s?    *7 K K%x	K:...%8w%8%8$6 
 ##"#*0V!D!D E	     D 3&&>xPPP (""	     LL>tGWXXXX 	K 	K 	KLL=ucJJJJJJJJ	K4s   AB*!B
B<B77B<c                  .     e Zd ZdZddddd fdZ xZS )	AuthErrorz,Structured auth error with UX mapping hints.r   NFprovidercoderelogin_requiredmessager   r   r   r   r   r   rj   Nonec               t    t                                          |           || _        || _        || _        d S N)super__init__r   r   r   )selfr   r   r   r   	__class__s        r/   r   zAuthError.__init__  s9     	!!! 	 0r.   )
r   r   r   r   r   r   r   r   rj   r   )r(   r)   r*   r+   r   __classcell__)r   s   @r/   r   r     sX        66 "!&1 1 1 1 1 1 1 1 1 1 1 1r.   r   errorr   c                    t          | t                    st          |           S | j        r|  dS | j        dk    r	 dS | j        dk    r	 dS | j        dk    r|  dS t          |           S )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'' 5zz A@@@@z,,,C	
 	

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

 z...8888u::r.   r   c                    t          | t                    sdS |                                 }|sdS t          j        |                    d                                                    dd         S )zJReturn a short hash fingerprint for telemetry without leaking token bytes.Nutf-8   )r   r   r   hashlibsha256encode	hexdigest)r   r   s     r/   _token_fingerprintr     sd    eS!! tkkmmG t>'..1122<<>>ssCCr.   c                 |    t          j        dd                                                                          } | dv S )NHERMES_OAUTH_TRACEr   >   1onyestrue)rw   r   r   r   )raws    r/   _oauth_trace_enabledr     s8    
)("
-
-
3
3
5
5
;
;
=
=C,,,r.   sequence_ideventr  fieldsr   c                   t                      sd S d| i}|r||d<   |                    |           t                              dt	          j        |dd                     d S )Nr  r  zoauth_trace %sTF)	sort_keysensure_ascii)r   updater   infor   dumps)r  r  r  payloads       r/   _oauth_tracer    sp    !! &.G -!,NN6
KK $*WSX"Y"Y"YZZZZZr.   r	   c                 $    t                      dz  S )N	auth.json)r   r$   r.   r/   _auth_file_pathr    s    {**r.   c                 D    t                                          d          S )Nz.lock)r  with_suffixr$   r.   r/   _auth_lock_pathr    s    ((111r.   timeout_secondsc              #    K   t          t          dd          dk    rLt          xj        dz  c_        	 dV  t          xj        dz  c_        n# t          xj        dz  c_        w xY wdS t                      }|j                            dd           t          8t          1dt          _        	 dV  dt          _        n# dt          _        w xY wdS t          rH|                                r|	                                j
        dk    r|                    dd	           |                    t          rd
nd          5 }t          j                    t          d|           z   }	 	 t          r?t          j        |                                t          j        t          j        z             nG|                    d           t          j        |                                t          j        d           nX# t,          t.          t0          f$ r= t          j                    |k    rt3          d          t          j        d           Y nw xY wdt          _        	 dV  dt          _        t          r3t          j        |                                t          j                   nt          r`	 |                    d           t          j        |                                t          j        d           n# t.          t:          f$ r Y nw xY wn# dt          _        t          r2t          j        |                                t          j                   w t          r`	 |                    d           t          j        |                                t          j        d           w # t.          t:          f$ r Y w w xY ww xY wddd           dS # 1 swxY w Y   dS )zCCross-process advisory lock for auth.json reads+writes.  Reentrant.depthr   r   NT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1$	)EEE##q(#####q(######!!I4$777}"#	(EEE&'##a#''''  4y'')) 4Y^^-=-=-E-J-JS7333	0D	1	1 Y9;;S/!:!::	!
! KK	 0 0 2 2EMEM4QRRRRNN1%%%N9#3#3#5#5vJJJ#Wo> ! ! !9;;(**&'NOOO
4     !	! #$	EEE&'# I,,..>>>> NN1%%%N9#3#3#5#5vJJJJ)   D	 '(# I,,..>>>> NN1%%%N9#3#3#5#5vJJJJ)   D	-                 s   A A$.B? ?C?&O	&BG43O	4AIO	IO	LAO	+AK32O	3LO	LO	AN9AN! N9!N5	2N94N5	5N99O		OO	auth_fileOptional[Path]r"   c                   | pt                      } |                                 s
t          i dS 	 t          j        |                                           }n# t          $ r t          i dcY S w xY wt          |t                    rht          |	                    d          t                    s(t          |	                    d          t                    r|
                    di            |S t          |t                    rPt          |	                    d          t                    r(|d         }i }d|v r|d         |d<   t          ||rdnd dS t          i dS )N)version	providersr@  credential_poolsystemsnous_portalr0   )r?  r@  active_provider)r  r"  AUTH_STORE_VERSIONr   loads	read_textr   r   r-   get
setdefault)r<  r   rB  r@  s       r/   _load_auth_storerJ    s   ._..I @-B???@j,,..// @ @ @-B?????@ #t 377;''..cgg/00$77 	{B'''
 #t BCGGI,>,>!E!E Bi.	G## ' 6If-I-6#@66DB B 	B *;;;s   &A A.-A.
auth_storec                B   t                      }|j                            dd           t          | d<   t	          j        t          j                                                  | d<   t          j
        | d          dz   }|                    |j         dt          j                     d	t          j                    j                   }	 |                    d
d          5 }|                    |           |                                 t          j        |                                           d d d            n# 1 swxY w Y   t          j        ||           	 t          j        t1          |j                  t          j                  }n# t4          $ r d }Y nw xY w|C	 t          j        |           t          j        |           n# t          j        |           w xY w	 |                                r|                                 nO# t4          $ r Y nCw xY w# 	 |                                r|                                 w w # t4          $ r Y w w xY wxY w	 |                    t>          j         t>          j!        z             n# t4          $ r Y nw xY w|S )NTr  r?  
updated_at   )indent
z.tmp..wr   r  )"r  r  r  rE  r   nowr   utc	isoformatr   r
  	with_namer   rw   getpiduuiduuid4hexr&  writeflushfsyncr*  replacer   O_RDONLYr1  closer"  unlinkchmodr#  S_IRUSRS_IWUSR)rK  r<  r  tmp_pathhandledir_fds         r/   _save_auth_storerh  ;  s   !!I4$777.Jy'|HL99CCEEJ|jA...5G""in#[#[29;;#[#[IY#[#[\\H]]3]11 	&VLL!!!LLNNNHV]]__%%%	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	
8Y'''	WS!122BK@@FF 	 	 	FFF	!           	   "!!! 	 	 	D		   "!!!!" 	 	 	D	t|34444   s   H" "AD>2H" >EH" EH" 1F H" F H" F  H" &G :H" G%%H" )(H 
HH"I$(II
IIII",J 
JJOptional[Dict[str, Any]]c                    |                      d          }t          |t                    sd S |                     |          }t          |t                    rt          |          nd S )Nr@  )rH  r   r-   )rK  r   r@  states       r/   _load_provider_staterl  _  sZ    {++Ii&& tMM+&&E$UD11;4;;;t;r.   rk  c                    |                      di           }t          |t                    si | d<   | d         }|||<   || d<   d S )Nr@  rD  )rI  r   r-   )rK  r   rk  r@  s       r/   _save_provider_statern  g  sX    %%k266Ii&& ,"$
;{+	"Ik$/J !!!r.   c                   t                      }|                    d          }t          |t                    si }| t          |          S |                    |           }t          |t                    rt	          |          ng S )z<Return the persisted credential pool, or one provider slice.rA  )rJ  rH  r   r-   list)r   rK  poolprovider_entriess       r/   read_credential_poolrs  p  s~    !##J>>+,,DdD!! Dzzxx,,%/0@$%G%GO4 !!!ROr.   entriesList[Dict[str, Any]]c                   t                      5  t                      }|                    d          }t          |t                    si }||d<   t          |          || <   t          |          cddd           S # 1 swxY w Y   dS )z7Persist one provider's credential pool under auth.json.rA  N)r;  rJ  rH  r   r-   rp  rh  )r   rt  rK  rq  s       r/   write_credential_poolrw  |  s    			 , ,%''
~~/00$%% 	1D,0J() MM[
++, , , , , , , , , , , , , , , , , ,s   A A<<B B c                >    t                      }t          ||           S )z4Return persisted auth state for a provider, or None.)rJ  rl  )r   rK  s     r/   get_provider_auth_statery    s    !##J
K888r.   c                 H    t                      } |                     d          S )z8Return the currently active provider ID from auth store.rD  )rJ  rH  rK  s    r/   get_active_providerr|    s     !##J>>+,,,r.   c                $   t                      5  t                      }| p|                    d          }|s	 ddd           dS |                    di           }t          |t                    si }||d<   |                    d          }t          |t                    si }||d<   d}||v r||= d}||v r||= d}|s	 ddd           dS |                    d          |k    rd|d<   t          |           ddd           n# 1 swxY w Y   dS )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.
    rD  NFr@  rA  T)r;  rJ  rH  r   r-   rh  )r   rK  targetr@  rq  cleareds         r/   clear_provider_authr    s    
		 % %%''
A
/@ A A 		% % % % % % % % NN;33	)T** 	0I&/J{#~~/00$%% 	1D,0J()Y&!GT>>VG 	3% % % % % % % %4 >>+,,66,0J()$$$9% % % % % % % % % % % % % % %: 4s   )DA:D-DD	D	c                     t                      5  t                      } d| d<   t          |            ddd           dS # 1 swxY w Y   dS )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.
    NrD  )r;  rJ  rh  r{  s    r/   deactivate_providerr    s     
		 % %%''
(,
$%$$$% % % % % % % % % % % % % % % % % %s   #?AA)explicit_api_keyexplicit_base_url	requestedr  r  c               X   | pd                                                                 }i ddddddddddd	dd
dddddddddddddddddddddi dddddddddd d!d d"d d#d$d%d$d&d'd(d'd)d'd*d+d,d+d-d+d.d+d/d+d+d+d+d0}|                    ||          }|d1k    rd1S |d+k    rd+S |t          v r|S |dk    rt	          d2| d3d45          |s|rd1S 	 t                      }|                    d6          }|r/|t          v r&t          |          }|                    d7          r|S n2# t          $ r%}t          	                    d8|           Y d9}~nd9}~ww xY wt          t          j        d:                    s!t          t          j        d;                    rd1S t                                          D ]J\  }	}
|
j        d<k    r|	dk    r|
j        D ]*}t          t          j        |d=                    r|	c c S +Kt	          d>d?5          )@a~  
    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kimirB   moonshotzminimax-chinarQ   
minimax_cnclauderI   zclaude-codegithubr4   zgithub-copilotzgithub-modelszgithub-modelzgithub-copilot-acpr9   zcopilot-acp-agent	aigatewayrX   vercelzvercel-ai-gatewayopencoder[   zenhfrd   zhugging-facezhuggingface-hubgor^   zopencode-go-subkilora   z	kilo-codezkilo-gatewaylmstudiocustomz	lm-studio	lm_studioollamavllm)llamacppz	llama.cppz	llama-cpp
openrouterzUnknown provider 'z'.invalid_provider)r   rD  	logged_inz)Could not detect active auth provider: %sNOPENAI_API_KEYOPENROUTER_API_KEYr5   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   rH  rg   r   rJ  get_auth_statusr   r   r   r   rw   r   itemsr   r&   )r  r  r  
normalized_PROVIDER_ALIASESrK  activestatusepidr   r   s               r/   resolve_providerr    s     %v,,..4466Jue%+U4;U)= 	 (4\ 	+	  -k	
 	)
 .y 	 %3I 	m .A- 	\  $,\ <OP\ 	N %*> 	m ,] =N} 	m / 	
 ( 6DZ 	H *8 6A( 	( #H  ;CH!  $ #&&z:>>J\!!|Xx&&&V////#
 
 
 	
  , |E%''
 122 	f 111$V,,Fzz+&&  E E E@!DDDDDDDDE #34455 9J29UiKjKj9k9k | *//11 
 
W	)) )/ 	 	G 7B!7!788 




	 	3 &	   s   ,AE 
E0E++E0Optional[float]c                l   t          | t                    r| sd S |                                 }|sd S |                    d          r|d d         dz   }	 t	          j        |          }n# t          $ r Y d S w xY w|j         |                    t          j
                  }|                                S )NZ+00:00)tzinfo)r   r   r   endswithr   fromisoformatr   r  r^  r   rT  	timestamp)r   r   parseds      r/   _parse_iso_timestampr  (  s    eS!!  t;;==D t}}S $CRCy8#'--   tt}x|44s   A* *
A87A8expires_at_isoskew_secondsc                \    t          |           }|dS |t          j                    |z   k    S )NT)r  r'  )r  r  expires_epochs      r/   _is_expiringr  9  s0    (88MtTY[[<788r.   
expires_inc                h    	 t          |           }n# t          $ r d}Y nw xY wt          d|          S )Nr   )r   r   r(  )r  ttls     r/   _coerce_ttl_secondsr  @  sF    *oo   q#;;s    !!c                    t          | t                    sd S |                                                     d          }|r|nd S )N/)r   r   r   rstrip)r   r   s     r/   _optional_base_urlr  H  sC    eS!! tkkmm""3''G'774'r.   c                   t          | t                    r|                     d          dk    ri S |                     d          d         }|ddt	          |          dz  z
  dz  z  z  }	 t          j        |                    d                    }t          j	        |
                    d                    }n# t          $ r i cY S w xY wt          |t                    r|ni S )NrQ  rN  r   =r   r   )r   r   countsplitr   base64urlsafe_b64decoder   r   rF  decoder   r-   )r   r  r   claimss       r/   _decode_jwt_claimsr  O  s    eS!! U[[%5%5%:%:	kk#q!Gsq3w<<!++q011G&w~~g'>'>??CJJw//00   			--56625s   +AB: :C	C	access_tokenc                
   t          |           }|                    d          }t          |t          t          f          sdS t	          |          t          j                    t          dt          |                    z   k    S )NexpFr   )r  rH  r   r   r   r'  r(  )r  r  r  r  s       r/   _codex_access_token_is_expiringr  \  si    --F
**U

CcC<(( u::$)++As</@/@(A(AABBr.   c                 l    t          t          j        d          pt          j        d                    S )zGDetect if running in an SSH session where webbrowser.open() won't work.
SSH_CLIENTSSH_TTY)r   rw   r   r$   r.   r/   _is_remote_sessionr  h  s)    	,''?29Y+?+?@@@r.   T_lockr  c                   | r5t                      5  t                      }ddd           n# 1 swxY w Y   nt                      }t          |d          }|st          dddd          |                    d          }t          |t                    st          ddd	d          |                    d
          }|                    d          }t          |t                    r|                                st          dddd          t          |t                    r|                                st          dddd          ||                    d          dS )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.
    Nr2   z@No Codex credentials stored. Run `hermes login` to authenticate.codex_auth_missingTr   tokenszJCodex auth state is missing tokens. Run `hermes login` to re-authenticate.codex_auth_invalid_shaper  refresh_tokenzJCodex auth is missing access_token. Run `hermes login` to re-authenticate.codex_auth_missing_access_tokenKCodex auth is missing refresh_token. Run `hermes login` to re-authenticate. codex_auth_missing_refresh_tokenlast_refresh)r  r  )	r;  rJ  rl  r   rH  r   r-   r   r   )r  rK  rk  r  r  r  s         r/   _read_codex_tokensr  u  s     ( 	, 	,)++J	, 	, 	, 	, 	, 	, 	, 	, 	, 	, 	, 	, 	, 	, 	, &''
 ^<<E 
N#%!	
 
 
 	
 YYx  Ffd## 
X#+!	
 
 
 	
 ::n--LJJ//MlC(( 
0B0B0D0D 
X#2!	
 
 
 	
 mS)) 
1D1D1F1F 
Y#3!	
 
 
 	
 		.11  s   ,00r  Dict[str, str]r  c                ~   |Dt          j        t          j                                                                      dd          }t                      5  t                      }t          |d          pi }| |d<   ||d<   d|d<   t          |d|           t          |           ddd           dS # 1 swxY w Y   dS )	zCSave Codex OAuth tokens to Hermes auth store (~/.hermes/auth.json).Nr  r  r2   r  r  chatgpt	auth_mode)r   rS  r   rT  rU  r^  r;  rJ  rl  rn  rh  )r  r  rK  rk  s       r/   _save_codex_tokensr    s   |HL11;;==EEhPSTT			 % %%''
$Z@@FB h ,n&kZ???$$$% % % % % % % % % % % % % % % % % %s   AB22B69B6g      4@r  r  c          	        ~ t          |t                    r|                                st          dddd          t	          j        t          dt          |                              }t	          j        |ddi	          5 }|	                    t          d
did|t          d          }ddd           n# 1 swxY w Y   |j        dk    rd}d|j         d}d}	 |                                }	t          |	t                    r|	                    d          }
t          |
t                    r(|
                                r|
                                }|	                    d          p|	                    d          }t          |t                    r+|                                rd|                                 }n# t           $ r Y nw xY w|dv rd}t          |d||          	 |                                }n&# t           $ r}t          dddd          |d}~ww xY w|                    d          }t          |t                    r|                                st          dddd          |                                |                                t#          j        t&          j                                                                      dd           d!}|                    d          }t          |t                    r+|                                r|                                |d<   |S )"z>Refresh Codex OAuth tokens without mutating Hermes auth state.r  r2   r  Tr         @Acceptr   )r   r   r   !application/x-www-form-urlencodedr  )
grant_typer  r   )r   dataNr   codex_refresh_failedz'Codex token refresh failed with status rQ  Fr   error_descriptionr   zCodex token refresh failed: >   invalid_grantinvalid_tokeninvalid_requestz*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  r  r  )r   r   r   r   r   Timeoutr(  r   Clientr   CODEX_OAUTH_TOKEN_URLCODEX_OAUTH_CLIENT_IDr   r   r-   rH  r   r   rS  r   rT  rU  r^  )r  r  r  r   clientresponser   r   r   errerr_codeerr_descrefresh_payloadr   refreshed_accessupdatednext_refreshs                    r/   refresh_codex_oauth_purer     s    	mS)) 
1D1D1F1F 
Y#3!	
 
 
 	
 mCU?%;%;<<==G	g:L/M	N	N	N 	
RX;;!#%HI-!.2   
 
	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 s""%SH<PSSS 
	--//C#t$$ P777++h,, ,1A1A ,#>>++D77#677M3779;M;Mh,, P1A1A POX^^=M=MOOG 	 	 	D	HHH##-	
 
 
 	
"--//   8#-!	
 
 

 	 '**>::&,, 
4D4J4J4L4L 
D#5!	
 
 
 	
 )..00&,,.. X\22<<>>FFxQTUU G
 #&&77L,$$ 8););)=)= 8#/#5#5#7#7 Ns=   )B::B>B>!C%G 
GG1H 
H)H$$H)c           	        t          t          |                     dd          pd          t          |                     dd          pd          |          }t          |           }|d         |d<   |d         |d<   t	          |           |S )zzRefresh Codex access token using the refresh token.
    
    Saves the new tokens to Hermes auth store automatically.
    r  r   r  r  )r   r   rH  r-   r  )r  r  	refreshedupdated_tokenss       r/   _refresh_codex_auth_tokensr    s     )FJJ~r**0b11FJJ++1r22'  I
 &\\N%.~%>N>"&/&@N?#~&&&r.   c                 L   t          j        dd                                          } | s#t          t	          j                    dz            } t	          |                                           dz  }|                                sdS 	 t          j	        |
                                          }|                    d          }t          |t                    sdS |                    d          r|                    d          sdS t          |          S # t          $ r Y dS w xY w)	zTry to read tokens from ~/.codex/auth.json (Codex CLI shared file).
    
    Returns tokens dict if valid, None otherwise. Does NOT write to the shared file.
    
CODEX_HOMEr   .codexr  Nr  r  r  )rw   r   r   r   r	   rv   
expanduseris_filer   rF  rG  rH  r   r-   r   )
codex_home	auth_pathr  r  s       r/   _import_codex_cli_tokensr    s   
 <,,2244J 1x/00
Z  ++--;I t	*Y002233X&&&$'' 	4zz.)) 	O1L1L 	4F||   tts   AD *D D 
D#"D#F)force_refreshrefresh_if_expiringrefresh_skew_secondsr  r  r  c                \   	 t                      }n# t          $ r}|j        dk    r t                      }|ret                              d           t          d           t          d           t          d           t          |           t                      }n Y d}~nd}~ww xY wt          |d                   }t          |
                    dd	          pd	                                          }t          t          j        d
d                    }t          |           }	|	s|rt!          ||          }	|	rt#          t%          t          t&                    |dz                       5  t          d          }t          |d                   }t          |
                    dd	          pd	                                          }t          |           }	|	s|rt!          ||          }	|	rGt)          ||          }t          |
                    dd	          pd	                                          }ddd           n# 1 swxY w Y   t          j        dd	                                                              d          pt,          }
d|
|d|
                    d          ddS )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 login` to create a fully independent session.
Nr  r  r   $HERMES_CODEX_REFRESH_TIMEOUT_SECONDS20r  r  Fr  HERMES_CODEX_BASE_URLr  r2   zhermes-auth-storer  r  )r   r   r5   r   r  r  )r  r   r   r  r   r	  printr  r-   r   rH  r   r   rw   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_credentialsr  2  s   !##    =000 .//
 	KKYZZZSTTTHIIIRSSSz***%''DD DDDD" $x.!!Fvzz."55;<<BBDDL#BI.TVZ$[$[\\-((N ] 3 ]8G[\\ Qc%8Q2R2RTknqTq.r.rsss 	Q 	Q%E222D$x.))Fvzz."==CDDJJLLL!-00N" e(; e!@Oc!d!d Q3F<STT"6::nb#A#A#GRHHNNPP	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 	Q 		)2..4466==cBB 	"!  #%00  s(    
B'BB""B'1C	II
I
insecure	ca_bundle
auth_stater  Optional[bool]r  r  
bool | strc                   t          |t                    r|                    d          ni }t          |t                    r|ni }| t          |           n"t          |                    dd                    }|p<|                    d          p't	          j        d          pt	          j        d          }|rdS |rt          |          S dS )Ntlsr  Fr  HERMES_CA_BUNDLESSL_CERT_FILET)r   r-   rH  r   rw   r   r   )r  r  r  	tls_stateeffective_insecureeffective_cas         r/   _resolve_verifyr)  u  s     *4J)E)EM
u%%%2I'	488@		bI #.X)--
E2233 
 	 	&==%%	&9'((	& 9_%%	   u !<   4r.   r  httpx.Clientr   r   r    c                   |                      | dd|i|rd|ini           }|                                 |                                g d}fd|D             }|r%t          dd                    |                     S )	zFPOST to the device code endpoint. Returns device_code, user_code, etc.z/api/oauth/device/coder   r    r  )device_code	user_codeverification_uriverification_uri_completer  intervalc                    g | ]}|v|	S r$   r$   ).0fr  s     r/   
<listcomp>z(_request_device_code.<locals>.<listcomp>  s    ;;;QQd]]q]]]r.   z%Device code response missing fields: z, )r   raise_for_statusr   r   join)r  r   r   r    r  required_fieldsmissingr  s          @r/   _request_device_coder:    s     {{222
#(0b
   H ==??D  O <;;;/;;;G WU7ASASUUVVVKr.   r-  poll_intervalc                &   t          j                     t          d|          z   }t          dt          |t                              }t          j                     |k     r$|                     | dd||d          }|j        dk    r)|                                }	d|	vrt          d          |	S 	 |                                }
n1# t          $ r$ |	                                 t          d	          w xY w|
                    d
d          }|dk    rt          j        |           |dk    r)t          |dz   d          }t          j        |           |
                    d          pd}t          | d|           t          d          )zDPoll the token endpoint until the user approves or the code expires.r   /api/oauth/tokenz,urn:ietf:params:oauth:grant-type:device_code)r  r   r-  r,  r   r  z+Token response did not include access_tokenz1Token endpoint returned a non-JSON error responser   r   authorization_pending	slow_down   r  zUnknown authentication errorz: z*Timed out waiting for device authorization)r'  r(  min%DEVICE_AUTH_POLL_INTERVAL_CAP_SECONDSr   r   r   r   r   r6  RuntimeErrorrH  r4  r3  )r  r   r   r-  r  r;  r:  current_intervalr  r  error_payload
error_codedescriptions                r/   _poll_for_tokenrH    s    y{{SJ///H1c-1VWWXX
)++
 
 ;;000L&*   
 
 3&&mmooGW,, !NOOON	T$MMOOMM 	T 	T 	T%%'''RSSS	T #&&w33
000J'((($$"#3a#7<<J'(((#''(;<<^@^j99K99:::
C
D
DDs   3C .C6c                   |                      | dd||d          }|j        dk    r-|                                }d|vrt          ddd	d
          |S 	 |                                }n%# t          $ r}t          ddd
          |d }~ww xY wt          |                    dd                    }t          |                    d          pd          }	|dv }
t          |	d||
          )Nr=  r  )r  r   r  r,  r   r  z%Refresh response missing access_tokenr0   r  Tr   zRefresh token exchange failedr   r   r   r  r     r  r  )r   r   r   r   r   r   rH  )r  r   r   r  r  r  rE  r   r   rG  relogins              r/   _refresh_access_tokenrM    sO    {{,,,)"*
 
   H s""--//((C%+/TXZ Z Z ZI  I I I7!'$@ @ @EH	II }  /::;;Dm''(;<<_@_``K88G
K&tg
V
V
VVs   A- -
B7B

Bmin_ttl_secondsc                   |                      | ddd| idt          dt          |                    i          }|j        dk    r,|                                }d|vrt          d	d
d          |S 	 |                                }n%# t          $ r}t          dd
d          |d}~ww xY wt          |                    dd                    }t          |                    d          pd          }	|dv }
t          |	d
||
          )z0Mint (or reuse) a short-lived inference API key.z/api/oauth/agent-keyr   r   rN  <   )r   r   r   r5   zMint response missing api_keyr0   server_errorr   r   zAgent key mint request failedNr   r  rK  r   )	r   r(  r   r   r   r   r   r   rH  )r  r   r  rN  r  r  rE  r   r   rG  rL  s              r/   _mint_agent_keyrS    sa    {{000 ":L":":;R_)=)=!>!>?   H s""--//G##;%+.B B B BG  G G G7!'n> > >CF	GG }  .99::Dm''(;<<_@_``K88G
K&tg
V
V
VVs   6B 
B-B((B-)r  verifyr   rT  	List[str]c                x   t          j        |          }t          j        |ddi|          5 }|                    |                     d           ddd| i          }d	d	d	           n# 1 swxY w Y   |j        d
k    rd|j         }	 |                                }t          |                    d          p|                    d          p|          }n2# t          $ r%}	t          
                    d|	           Y d	}	~	nd	}	~	ww xY wt          |dd          |                                }
|
                    d          }t          |t                    sg S g }|D ]}t          |t                    s|                    d          }t          |t                    rT|                                r@|                                }d|                                v r|                    |           dd}|                    |           t          t                              |                    S )z6Fetch available model IDs from the Nous inference API.r  r   r   r   rT  r  z/modelsr   r   )r   Nr   z#/models request failed with status r  r   z'Could not parse error response JSON: %sr0   models_fetch_failedrR  r  r   hermesmidr   rj   r%   c                j    |                                  }d|v rd| fS d|v rd|vrd| fS d|v rd| fS d| fS )Nopusr   prosonnetr      rN  )r   )rZ  lows     r/   _model_priorityz*fetch_nous_models.<locals>._model_priorityS  sX    iikkS==s8OC<<HC//s8Os??s8O3xr.   )key)rZ  r   rj   r%   )r   r  r  rH  r  r   r   r   r   r   r   r   r   rp  r-   r   r   ru   sortfromkeys)r   r5   r  rT  r   r  r  rG  r  r  r  r  	model_idsitemmodel_idrZ  ra  s                    r/   fetch_nous_modelsrh  (  s    mO,,G	g:L/MV\	]	]	] 
ag::!((--666$&9&9&9:  
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 s""RH<PRR	G--//Ccgg&9::]cggg>N>N]R]^^KK 	G 	G 	GLLBAFFFFFFFF	Gf;PQQQQmmooG;;vDdD!! 	I 	" 	"$%% 	88D>>h$$ 	")9)9 	"..""C399;;&&S!!!    NNN'''i(()))s*   3A--A14A1AC 
D&DDc                    |                      d          }t          |t                    r|                                sdS t	          |                      d          |           S )N	agent_keyFagent_key_expires_at)rH  r   r   r   r  )rk  rN  rb  s      r/   _agent_key_is_usablerl  a  sY    
))K
 
 Cc3 syy{{ uEII&<==OOOOr.   )r  r  r  r  c                   t                      5  t                      }t          |d          }|st          ddd          t	          |                    d                    p.t          j        d          pt          j        d          pt          	                    d          }t          |                    d	          pt                    }t          |||
          }|                    d          }	|                    d          }
t          |	t                    r|	st          ddd          t          |                    d          |          s|	cddd           S t          |
t                    r|
st          ddd          t          j        | r| nd          }t          j        |ddi|          5 }t%          ||||
          }ddd           n# 1 swxY w Y   t'          j        t*          j                  }t/          |                    d                    }|d         |d<   |                    d          p|
|d<   |                    d          p|                    d          pd|d<   |                    d          p|                    d          |d<   |                                |d<   ||d<   t'          j        |                                |z   t*          j                                                  |d<   ||d<   ||d	<   |du t          |t                    r|ndd|d<   t7          |d|           t9          |           |d         cddd           S # 1 swxY w Y   dS )zKResolve a refresh-aware Nous Portal access token for managed tool gateways.r0   &Hermes is not logged into Nous Portal.TrJ  r   HERMES_PORTAL_BASE_URLNOUS_PORTAL_BASE_URLr  r   r  r  r  ,No access token found for Nous Portal login.
expires_atN2Session expired and no refresh token is available.r   r  r   rW  r  r   r   r  r  
token_typeBearerr    obtained_attzFr  r  r#  )r;  rJ  rl  r   r  rH  rw   r   DEFAULT_NOUS_PORTAL_URLr  r   DEFAULT_NOUS_CLIENT_IDr)  r   r  r   r  r  rM  r   rS  r   rT  r  rU  fromtimestampr  rn  rh  )r  r  r  r  rK  rk  r   r   rT  r  r  r   r  r  rS  
access_ttls                   r/   resolve_nous_access_tokenr  h  sm    
		 H% H%%''
$Z88 	8!%    uyy):;;<< 'y122'y/00' '
&++ 	 		+..H2HII	 (iTYZZZyy00		/22,,, 	L 	>!%    EIIl335IJJ 	 =H% H% H% H% H% H% H% H%@ --- 	] 	D!%    -? LMM\12
 
 
 
	 - /#+	  I
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 l8<(((|)D)DEE
 ). 9n!*!?!?!P=o'mmL99`UYY|=T=T`X`l"w//E599W3E3Eg"}}m(l&4MMOOj(|
 
 
 )++ 	l $3 &k%#-fc#:#:D
 
e 	Z777$$$^$QH% H% H% H% H% H% H% H% H% H% H% H% H% H% H% H% H% H%s>   E	M0%AM0?GM0G#	#M0&G#	'E<M00M47M4rv  ru  r    rw  rr  rj  rk  min_key_ttl_secondsr  r  r  r  
force_mintru  rw  rr  rj  rk  r  r  c               0   | ||pt           |pt                              d          |pt                              d          |pd|pt          |||	|
t          |          |dd}t          |||          }t          j        |r|nd          }t          j	        |ddi|	          5 }|s)t          |                    d
          t                    r{t          ||d         |d         |d                   }t          j        t           j                  }t%          |                    d                    }|d         |d<   |                    d          p|d         |d<   |                    d          p|                    d          pd|d<   |                    d          p|                    d          |d<   t'          |                    d                    }|r||d<   |                                |d<   ||d<   t          j        |                                |z   t           j                                                  |d
<   |s,t/          |t1          dt3          |                              st5          ||d         |d         |          }t          j        t           j                  }|                    d          |d<   |                    d          |d<   |                    d
          |d<   |                    d          |d<   t          |                    dd                    |d <   |                                |d!<   t'          |                    d                    }|r||d<   d"d"d"           n# 1 swxY w Y   |S )#z4Refresh Nous OAuth state without mutating auth.json.r  rv  rz  )r  r  r   r   r   ru  r    rw  rr  rj  rk  r#  r  r   r  r   rW  rr  r   r   r  rt  r  r  ru  r    r   rw  rx  rP  r  r   r  rN  r5   rj  key_idagent_key_idrk  agent_key_expires_inreusedFagent_key_reusedagent_key_obtained_atN)r|  r{  r  DEFAULT_NOUS_INFERENCE_URLDEFAULT_NOUS_SCOPEr   r)  r   r  r  r  rH  !ACCESS_TOKEN_REFRESH_SKEW_SECONDSrM  r   rS  r   rT  r  r  rU  r}  r  rl  r(  r   rS  )r  r  r   r   r   ru  r    rw  rr  rj  rk  r  r  r  r  r  r  rk  rT  r   r  r  rS  r~  refreshed_urlmint_payload
minted_urls                              r/   refresh_nous_oauth_purer    s   , %&8"8+F/FNNsSS1O5OWWX[\\ ,H,,"  4X"
 
 E" h)PUVVVFmHOODIIG	g:L/MV\	]	]	] '9ag 	L<)@)@Bcdd 	- %&7 8,#O4	  I ,x|,,C,Y]]<-H-HIIJ$-n$=E.!%.]]?%C%C%]u_G]E/""+--"="="d<AXAX"d\dE,&]]733Iuyy7I7IE'N.y}}=Q/R/RSSM <.;*+#&==??E- ",E,"*"8*,# # #ikk ,  	91%REXAYAY9Z9Z[[ 	9* %&7 8">2 3	  L ,x|,,C!-!1!1)!<!<E+$0$4$4X$>$>E.!,8,<,<\,J,JE(),8,<,<\,J,JE()(,\-=-=h-N-N(O(OE$%-0]]__E)*+L,<,<=Q,R,RSSJ 9.8*+O'9 '9 '9 '9 '9 '9 '9 '9 '9 '9 '9 '9 '9 '9 '9R Ls   'KNNNr  r  r  r  c                  |                      d          pi }t          |                      dd          |                      dd          |                      dd          |                      dt                    |                      dt                    |                      d	d
          |                      dt                    |                      d          |                      d          |                      d          |                      d          |||                     d          |                     d          ||          S )zRRefresh Nous OAuth from a state dict. Thin wrapper around refresh_nous_oauth_pure.r#  r  r   r  r   r   r   r   ru  rv  r    rw  rr  rj  rk  r  r  r  )rH  r  r{  r  r  )rk  r  r  r  r  r#  s         r/   refresh_nous_oauth_from_stater    s    ))E


 bC"		."%%		/2&&		+|,,		#%<==		&(BCC99\844ii!344IIm,,99\**))K(("YY'=>>/'$$''+&&##   r.   )r  r  r  r  r  c                   t          dt          |                     } t          j                    j        dd         t                      5  t                      t          d          st          ddd          t          
                    d                    p.t          j        d	          pt          j        d
          pt                              d          }t          
                    d                    pt          j        d          pt                              d          }t!          
                    d          pt"                    }dMfd}t%          ||          }	t'          j        |r|nd          }
t+          dt-          |          | t/          
                    d                               t'          j        |
ddi|	          5 }
                    d          }
                    d          }t3          |t                     r|st          ddd          t5          
                    d          t6                    rt3          |t                     r|st          ddd          t+          d d!t/          |          "           t9          ||||#          }t;          j        t>          j                   }tC          |
                    d$                    }|}|d         d<   |
                    d          p|d<   |
                    d%          p
                    d%          pd&d%<   |
                    d'          p
                    d'          d'<   t          |
                    d                    }|r|}|"                                d(<   |d$<   t;          j#        |$                                |z   t>          j         )          "                                d<   d         }d         }t+          d*d!t/          |          t/          |          +            |d,           d-}d}|s%tK          |           rd}t+          d./           nz	 t+          d0t/          |          1           tM          |||| 2          }nE# t          $ r7}t+          d3|j'        4           
                    d          }|j'        d5v rt3          |t                     r|rt+          d d6t/          |          "           t9          ||||#          }t;          j        t>          j                   }tC          |
                    d$                    }|d         d<   |
                    d          p|d<   |
                    d%          p
                    d%          pd&d%<   |
                    d'          p
                    d'          d'<   t          |
                    d                    }|r|}|"                                d(<   |d$<   t;          j#        |$                                |z   t>          j         )          "                                d<   d         }d         }t+          d*d6t/          |          t/          |          +            |d7           tM          |||| 2          }n Y d}~nd}~ww xY w|t;          j        t>          j                   }|
                    d8          d9<   |
                    d:          d;<   |
                    d          d<<   |
                    d$          d=<   t-          |
                    d>d-                    d?<   |"                                d@<   t          |
                    d                    }|r|}t+          dAt-          |
                    d>d-                    B           |d<   |d<   |d<   |	d-u t3          |	t                     r|	nddCdD<   ddd           n# 1 swxY w Y    |dE           ddd           n# 1 swxY w Y   
                    d9          }t3          |t                     r|st          dFddGH          
                    d<          }tQ          |          }|1t          dIt          |tS          j)                    z
                      n!tC          
                    d=                    }d||
                    d;          |||rdJndKdLS )Na  
    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").
    rP  Nr   r0   rn  TrJ  r   ro  rp  r  r   NOUS_INFERENCE_BASE_URLr   reasonr   rj   r   c                d   	 t          d           t                     n8# t          $ r+}t          d| t	          |          j                    d }~ww xY wt          d| t                              d                    t                              d                               d S )Nr0   nous_state_persist_failed)r  r  
error_typenous_state_persistedr  r  )r  r  refresh_token_fpaccess_token_fp)rn  rh  r   r  typer(   r   rH  )r  r   rK  r  rk  s     r/   _persist_statez8resolve_nous_runtime_credentials.<locals>._persist_stateY  s    
$Z??? ,,,,   / +!#Cyy1	     &'!3EIIo4N4N!O!O 2599^3L3L M M     s    $ 
A&AAr  r   nous_runtime_credentials_startr  )r  r  r  r  r  r   rW  r  rq  rr  rs  refresh_startaccess_expiring)r  r  r  rt  r  ru  rv  r    rw  rx  refresh_success)r  r  previous_refresh_token_fpnew_refresh_token_fppost_refresh_access_expiringFagent_key_reuser  
mint_start)r  r  r  
mint_error)r  r   rK  mint_retry_after_invalid_tokenpost_refresh_mint_retryr5   rj  r  r  rk  r  r  r  r  mint_success)r  r  rz  r#  &resolve_nous_runtime_credentials_finalz*Failed to resolve a Nous inference API keyrQ  rR  r   cacheportal)r   r   r5   r  rr  r  r   )r  r   rj   r   )*r(  r   rX  rY  rZ  r;  rJ  rl  r   r  rH  rw   r   r{  r  r  r   r|  r)  r   r  r  r   r   r  r   r  r  rM  r   rS  r   rT  r  rU  r}  r  rl  rS  r   r  r'  )r  r  r  r  r  r   r   r   r  rT  r   r  r  r  r  rS  r~  previous_refresh_tokenr  used_cached_keyr  r   latest_refresh_tokenr  r5   rr  r  r  rK  r  rk  s                               @@@r/    resolve_nous_runtime_credentialsr  /  s   $ b#&9":":;;*,,"3B3'K			 JA JA%''
$Z88 	DD%+dD D D D uyy):;;<< 'y122'y/00' '
&++ 	 uyy)=>>?? *y233*)
&++	 	
 		+..H2HII		 	 	 	 	 	 	 	( !(iTYZZZ-? LMM,#J'' 3/		/0J0JKK	
 	
 	
 	
 \'H>P3QZ`aaa U	ek 99^44L!IIo66MlC00 H H N)/$H H H H EIIl335VWW (?!-55 L] L#$X-3dL L L L # +,%7%F%F	    2!?'}  	 l8<000|1L1LMM
)6&(1.(An%)2)G)G)X=o&&/mmL&A&A&hUYY|E\E\&h`hl#!*w!7!7!M599W;M;Mg 29==AU3V3V W W  7)6&'*}}m$&0l#&.&<MMOOj0X\' ' ')++ l#  %^4 %o 6% +,.@AW.X.X);M)J)J    =>>> $O59L D"6u>Q"R"R D"&.KHHHHH@ $$/(:<(H(H   
 $3%%1CV$ $ $LL ! 6 6 6 $$/ X    ,199_+E+E($FFF&';SAA G0 G %+(3#C-?@T-U-U	    %:#)?&/?S% % %	 'l8<88%8|9T9T%U%U
09.0In-1:1O1O1gSgo..7mmL.I.I.pUYYWcMdMd.phpl+)2w)?)?)U599WCUCUg(:9==I];^;^(_(_( ?1>./2}}m,.8l+.6.DMMOOj8X\/ / /#)++ l+ (-^'<(-o(>$-(3#C6HI]6^6^1CM1R1R    ''@AAA'6#)?)5GZ( ( (
  %c6p 'l8<00%1%5%5i%@%@k"(4(8(8(B(Bn%0<0@0@0N0N,-0<0@0@0N0N,-,01A1A(E1R1R,S,S()14-./0@0@AU0V0VWW
 4)3&" + 0 05 A ABB    (7E#$*<E&'!*E+"eO'1&#'>'>HVVD E%LeU	 U	 U	 U	 U	 U	 U	 U	 U	 U	 U	 U	 U	 U	 U	n 	?@@@UJA JA JA JA JA JA JA JA JA JA JA JA JA JA JAX ii$$Ggs## >7 >D!'n> > > 	> 122J(44M $ 	As=49;;.//000 +A!B!BCC  &))N++  ,:''(  sd   Fa6+Ja2R<:a<[>H-[94a9[>>E
aa6a	a6a	a66a:=a:c            
     `   t          d          } | s	dddddddS t          |                     d                    |                     d          |                     d          |                     d          |                     d	          t          |                     d
                    dS )z+Status snapshot for `hermes status` output.r0   FN)r  r   r   access_expires_atrk  has_refresh_tokenr  r   r   rr  rk  r  )ry  r   rH  )rk  s    r/   get_nous_auth_statusr  ,  s    #F++E 
#"&!%$(!&
 
 	
 %))N3344 99%677#ii(<=="YY|44 %		*@ A A!%))O"<"<==  r.   c                 Z   	 t                      } dt          t                                |                     d          |                     d          |                     d          dS # t          $ r6}dt          t                                t          |          dcY d}~S d}~ww xY w)	zStatus snapshot for Codex auth.Tr  r  r   )r  rK  r  r  r   F)r  rK  r   N)r  r   r  rH  r   )credsr   s     r/   get_codex_auth_statusr  B  s    
133o//00!IIn55;//ii))
 
 	
  
 
 
o//00XX
 
 	
 	
 	
 	
 	
 	

s   A'A* *
B*4+B%B*%B*c                   t                               |           }|r|j        dk    rddiS d}d}t          | |          \  }}d}|j        r,t          j        |j        d                                          }| dk    rt          ||j	        |          }n|r|}n|j	        }t          |          | |j        ||t          |          dS )z<Status snapshot for API-key providers (z.ai, Kimi, MiniMax).r5   
configuredFr   rB   )r  r   r   
key_sourcer   r  )rg   rH  r   r   r'   rw   r   r   rn   r   r   r   r   r   r5   r  env_urlr   s         r/   get_api_key_provider_statusr  U  s    ##K00G %g'944e$$GJ:;PPGZG B)G4b99??AAm##)'73MwWW	 .- 7mm ']]  r.   c                   t                               |           }|r|j        dk    rddiS t          j        dd                                          p(t          j        dd                                          pd}t          j        dd                                          }|rt          j        |          nd	d
g}|j        r,t          j        |j        d                                          nd}|s|j	        }|rt          j        |          nd}t          |p|                    d                    | |j        ||||t          |p|                    d                    dS )z:Status snapshot for providers that run a local subprocess.r:   r  FHERMES_COPILOT_ACP_COMMANDr   COPILOT_CLI_PATHr4   HERMES_COPILOT_ACP_ARGS--acp--stdioN
acp+tcp://)r  r   r   commandargsresolved_commandr   r  )rg   rH  r   rw   r   r   shlexr  r'   r   rs   rt   r   rl   r   )r   r   r  raw_argsr  r   r  s          r/   $get_external_process_provider_statusr  t  sy   ##K00G %g'+===e$$ 		.3399;; 	9',,2244	 
 y2B77==??H$,F5;x   7I2FDBIBZbry1266<<>>>`bH .-07Av|G,,,T+Px/B/B</P/PQQ,*Oh.A.A,.O.OPP	 	 	r.   c                   | pt                      }|dk    rt                      S |dk    rt                      S |dk    rt          |          S t                              |          }|r|j        dk    rt          |          S ddiS )zGeneric auth status dispatcher.r0   r2   r9   r5   r  F)r|  r  r  r  rg   rH  r   r  )r   r~  r   s      r/   r  r    s    1/11F#%%%$&&&3F;;;##F++G 37$	11*6222r.   c                   t                               |           }|r|j        dk    rt          d|  d| d          d}d}t	          | |          \  }}d}|j        r,t          j        |j        d                                          }| dk    rt          ||j
        |          }n|r|                    d          }n|j
        }| ||                    d          |pd	d
S )zwResolve API key and base URL for an API-key provider.

    Returns dict with: provider, api_key, base_url, source.
    r5   
Provider 'z' is not an API-key provider.r  rR  r   rB   r  default)r   r5   r   r   )rg   rH  r   r   r   r'   rw   r   r   rn   r   r  r  s         r/   $resolve_api_key_provider_credentialsr    s   
  ##K00G 
g'944CCCC #
 
 
 	
 GJ:;PPGZG B)G4b99??AAm##)'73MwWW	 .>>#&&-  OOC(()		  r.   c                   t                               |           }|r|j        dk    rt          d|  d| d          |j        r,t          j        |j        d                                          nd}|s|j        }t          j        dd                                          p(t          j        dd                                          pd	}t          j        d
d                                          }|rt          j
        |          nddg}|rt          j        |          nd}|s+|                    d          st          d| d| d          | d|                    d          |p||ddS )z>Resolve runtime details for local subprocess-backed providers.r:   r  z&' is not an external-process provider.r  rR  r   r  r  r4   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_clir9   r  process)r   r5   r   r  r  r   )rg   rH  r   r   r'   rw   r   r   r   r  r  rs   rt   rl   r  )r   r   r   r  r  r  r  s          r/   -resolve_external_process_provider_credentialsr    s   ##K00G 
g'+===LLLL #
 
 
 	
 CJBZbry1266<<>>>`bH .- 		.3399;; 	9',,2244	 
 y2B77==??H$,F5;x   7I2FD07Av|G,,,T 
H$7$7$E$E 
]w ] ] ] &	
 
 
 	
   OOC((#.w  r.   c                     g } t                      }|rCt          j                    dz  dz  }|                     dt	          |          d| dd           | S )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  r2   zCodex CLI credentials found (u5   ) — run `hermes login` to create a separate session)r   rx   r   )r  r	   rv   ru   r   )foundr  
codex_paths      r/   detect_external_credentialsr    st     #%E *++J Y[[8+k9
&
OOvZvvv
 
 	 	 	 Lr.   default_modelc                   t                      5  t                      }| |d<   t          |           ddd           n# 1 swxY w Y   t                      }|j                            dd           i }|                                rS	 t          j        |	                                          pi }t          |t                    r|}n# t          $ r i }Y nw xY w|                    d          }t          |t                    rt          |          }nBt          |t                    r+|                                rd|                                i}ni }| |d<   |r-|                                r|                    d          |d	<   n|                    d	d           |r!|                    dd
          }	|	rd|	v r||d<   ||d<   |                    t          j        |d                     |S )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).
    rD  NTr  r   r  r   r  r   r   Fr  )r;  rJ  rh  r   r  r  r"  yaml	safe_loadrG  r   r-   r   rH  r   r   r  popr%  	safe_dump)
r   r   r  rK  config_pathconfigloadedcurrent_model	model_cfgcur_defaults
             r/   _update_config_for_providerr    sd    
		 % %%''
(3
$%$$$% % % % % % % % % % % % % % % "##KTD999F 	^K$9$9$;$;<<BF&$''   	 	 	FFF	 JJw''M-&& ''			M3	'	' M,?,?,A,A  3 3 5 56			'Ij (06688 ( 2 9 9# > >	* 	j$'''
  1mmIr22 	1c[00#0Ii F7O4>&EBBBCCCs!   #>AA
?C
 
CCc                    t                      } |                                 s| S 	 t          j        |                                           pi }n# t
          $ r | cY S w xY wt          |t                    s| S |                    d          }t          |t                    rd|d<   d|v r
t          |d<   | 
                    t          j        |d                     | S )z5Reset config.yaml provider back to auto after logout.r   r  r   r   Fr  )r   r"  r  r  rG  r   r   r-   rH  r   r%  r  )r  r  r   s      r/   _reset_config_providerr  K  s    !##K  5 5 7 788>B    fd## JJwE% 4"j 3E*4>&EBBBCCCs   (A AAr   re  r  c           
     &   g }r| v r|                                | D ]}||vr|                     |           fdd}	 ddlm} fd|D             }|                     d           |                     d            |||ddd	d
dd          }|                                }|dS t	                       |t          |          k     r||         S |t          |          k    r't          d                                          }	|	r|	ndS dS # t          t          f$ r Y nw xY wt	          d           t          |d          D ]#\  }
}t	          d|
 d |                      $t          |          }t	          d|dz    d           t	          d|dz    d           t	                       	 	 t          d|dz    d                                          }|sdS t          |          }d|cxk    r|k    rn n||dz
           S ||dz   k    r't          d                                          }	|	r|	ndS ||dz   k    rdS t	          d|dz               n2# t          $ r t	          d           Y nt          t          f$ r Y dS w xY w)zeInteractive model selection. Puts current_model first with a marker. Returns chosen model ID or None.c                    | k    r|  dS | S )Nu     ← currently in user$   )rZ  r  s    r/   _labelz'_prompt_model_selection.<locals>._labelm  s"    -1111
r.   r   )TerminalMenuc                ,    g | ]}d  |           S )  r$   )r3  rZ  r  s     r/   r5  z+_prompt_model_selection.<locals>.<listcomp>x  s*    999#%s%%999r.   z  Enter custom model namez  Skip (keep current)z-> )fg_greenbold)r  TFzSelect default model:)cursor_indexmenu_cursormenu_cursor_stylemenu_highlight_stylecycle_cursorclear_screentitleNzEnter model name: r   r  z. z. Enter custom model namerN  z. Skip (keep current)z
Choice [1-z] (default: skip): zPlease enter 1-zPlease enter a number)ru   simple_term_menur  showr  r   inputr   ImportErrorNotImplementedError	enumerater   r   KeyboardInterruptEOFError)re  r  orderedrZ  default_idxr  choicesmenuidxr  inchoicer  s    `           @r/   _prompt_model_selectionr
  b  sv    G &)33}%%%    gNN3     K11111199999992333.///|$2!.)	
 	
 	
 iikk;4W3<CLL  /006688F#-66-t,-    

!"""GQ'' ' '3%1%%s%%&&&&GA	
/q1u
/
/
/000	
+q1u
+
+
+,,,	GGG	BABBBCCIIKKF tf++CC}}}}1}}}}}sQw''A344::<<!'1vvT1At+AE++,,,, 	+ 	+ 	+)*****!8, 	 	 	44	!sO   A'D /(D 9D D('D(9*I  %)I  /I  ?	I  
I   J;JJrg  c                    ddl m}m}  |            }t          |                    d          t
                    r| |d         d<   nd| i|d<    ||           dS )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.
    r   )save_configload_configr   r  N)hermes_cli.configr  r  r   rH  r-   )rg  r  r  r  s       r/   _save_model_choicer    sz     ;:::::::[]]F&**W%%t,, 0%-w	""$h/wKr.   c                z    t          d           t          d           t          d           t          d          )z9Deprecated: use 'hermes model' or 'hermes setup' instead.z,The 'hermes login' command has been removed.z2Use 'hermes model' to select a provider and model,z-or 'hermes setup' for full interactive setup.r   )r  
SystemExit)r  s    r/   login_commandr    s;    	
8999	
>???	
9:::
Q--r.   c                   	 t                      }t          d           	 t          d                                                                          }n# t
          t          f$ r d}Y nw xY w|dv r[t          d|                    dt                              }t                       t          d           t          d| d	           d
S n# t          $ r Y nw xY wt                      }|rt          d           t          d           	 t          d                                                                          }n# t
          t          f$ r d}Y nw xY w|dv rt          |           t          j        dd                                                              d          pt          }t          d|          }t                       t          d           t          d           t          d| d	           d
S t                       t          d           t          d           t                       t!                      }t          |d         |                    d                     t          d|                    dt                              }t                       t          d           ddlm}	 t          d |	             d           t          d| d	           d
S )zNOpenAI Codex login via device code flow. Tokens stored in ~/.hermes/auth.json.z6Existing Codex credentials found in Hermes auth store.z!Use existing credentials? [Y/n]: y)r   r  r   r2   r   Login successful!  Config updated: z (model.provider=openai-codex)Nz: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   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  r   )display_hermes_home  Auth state: z
/auth.json)r  r  r  r   r   r  r   r  rH  r  r   r  r  rw   r   r  _codex_device_code_loginhermes_constantsr  )
r  r   existingreuser  r  	do_importr   r  _dhhs
             r/   _login_openai_codexr    s   466FGGG	=>>DDFFLLNNEE+, 	 	 	EEE	$$$5nhllS]_uFvFvwwKGGG%&&&R{RRRSSSF %     *++J JKKK_```	cddjjllrrttII+, 	 	 	III	$$z***y!8"==CCEELLSQQkUkH5nhOOKGGGQRRRPQQQR{RRRSSSF 
GGG	
)***	
RSSS	GGG$&&E uX		.(A(ABBB-neii
Tj>k>kllK	GGG	
<<<<<<	
-4466
-
-
-...	
J{
J
J
JKKKKKsG   C 3A C A*'C )A**A C 
CC3E EEc            
     \	   ddl } d}t          }	 t          j        t          j        d                    5 }|                    | dd|idd	i
          }ddd           n# 1 swxY w Y   n'# t          $ r}t          d| dd          d}~ww xY w|j        dk    rt          d|j         ddd          |	                                }|
                    dd          }|
                    dd          }t          dt          |
                    dd                              }	|r|st          ddd          t          d           t          d           t          d| d           t          d           t          d| d            t          d!           d"}
|                                 }d}	 t          j        t          j        d                    5 }|                                 |z
  |
k     rz|                     |	           |                    | d#||d$dd	i
          }|j        dk    r|	                                }n%|j        d%v rzt          d&|j         ddd'          ddd           n# 1 swxY w Y   n,# t           $ r t          d(           t#          d)          w xY w|t          d*dd+          |
                    d,d          }|
                    d-d          }| d.}|r|st          d/dd0          	 t          j        t          j        d                    5 }|                    t$          d,||||d1dd2i3          }ddd           n# 1 swxY w Y   n'# t          $ r}t          d4| dd5          d}~ww xY w|j        dk    rt          d6|j         ddd7          |	                                }|
                    d8d          }|
                    d9d          }|st          d:dd;          t'          j        d<d                                                              d=          pt.          }||d>|t1          j        t4          j                                                                      d?d@          dAdBdCS )DzBRun the OpenAI device code login flow and return credentials dict.r   Nzhttps://auth.openai.comr   )r   z!/api/accounts/deviceauth/usercoder   r   r   )r   r   zFailed to request device code: r2   device_code_request_failedrR  r   z$Device code request returned status rQ  device_code_request_errorr.  r   device_auth_idr_  r1  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)i  z/api/accounts/deviceauth/token)r#  r.  )i  i  z$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_exchange)r  r   redirect_urir   r+  r  )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  zdevice-code)r  r   r  r  r   )r'  r  r   r  r  r   r   r   r   r   rH  r(  r   r  	monotonicr4  r   r  r  rw   r   r   r  r  r   rS  r   rT  rU  r^  )_timeissuerr   r  r   r   device_datar.  r#  r;  max_waitstart	code_resp	poll_respr*  r+  r-  
token_respr  r  r  r   s                         r/   r  r  	  s   &F%I
\%-"5"5666 	&;;<<<!9-');<   D	 	 	 	 	 	 	 	 	 	 	 	 	 	 	  
 
 
3c33#*F
 
 
 	

 3F43CFFF#*E
 
 
 	

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

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


\%-"5"5666 	&%"6.$0!*%2  ()LM % 
 
J	 	 	 	 	 	 	 	 	 	 	 	 	 	 	  
 
 
+c++#*A
 
 
 	

 $$Gj.DGGG#*@
 
 
 	

 __F::nb11LJJ33M 
<#*J
 
 
 	
 		)2..4466==cBB 	"!  )*
 
  X\22<<>>FFxQTUU	 	 	s   'A.  A"A. "A&&A. )A&*A. .
B8BB='J $BJ:J J

J J
J )J;'M? &M3'M? 3M77M? :M7;M? ?
N#	NN#,  	r   r   r   r    open_browserr  r  r  r  r<  c        	   
        t           d         }	| p.t          j        d          pt          j        d          p|	j                            d          } |pt          j        d          p|	j                            d          }
|p|	j        }|p|	j        }t          j	        |          }|rdn|r|nd}t                      rd}t          d|	j         d	           t          d
|             |rt          d           n|rt          d| d           t          j        |ddi|          5 }t          || ||          }t          |d                   }t          |d                   }t!          |d                   }t!          |d                   }t                       t          d           t          d|            t          d|            |r5t#          j        |          }|rt          d           nt          d           t'          dt)          |t*                              }t          d| d           t-          || |t          |d                   ||          }d d d            n# 1 swxY w Y   t/          j        t2          j                  }t7          |                    dd!                    }|                                |z   }t=          |                    d"                    p|
}||
k    rt          d#|            i d$| d"|d%|d&|                    d&          p|d'|                    d'd(          d)|d)         d*|                    d*          d+|                                d,t/          j         |t2          j        -                                          d|d.|du tC          |t                    r|nd d/d0d d1d d2d d3d d4d d5d }tE          |||dd6          S )7zMRun the Nous device-code flow and return full OAuth state without persisting.r0   ro  rp  r  r  FTzStarting Hermes login via z...zPortal: z'TLS verification: disabled (--insecure)z$TLS verification: custom CA bundle ()r  r   rW  )r  r   r   r    r0  r.  r  r1  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.r   z$Waiting for approval (polling every zs)...r-  )r  r   r   r-  r  r;  Nr   r   z%Using portal-provided inference URL: r   r   r    ru  rv  r  r  rw  rr  rx  r#  rz  rj  r  rk  r  r  r  r  )#rg   rw   r   r   r  r   r   r    r   r  r  r  r   r  r:  r   r   
webbrowserr&  r(  rA  rB  rH  r   rS  r   rT  r  rH  r  r  rU  r}  r   r  )r   r   r   r    r<  r  r  r  r  r   requested_inference_urlr   rT  r  r4  verification_urlr.  r  r1  openedeffective_interval
token_datarS  token_expires_inrr  resolved_inference_urlr  s                              r/   _nous_device_code_loginrG  	  s     'G 	#9-..	#9+,,	# "fSkk  	 	&9.//	&%fSkk	 
 .W.I"W]EmO,,G"*Ri1QTF 	
8w|
8
8
8999	
&_
&
&''' C78888	 CAYAAABBB	g:L/MV\	]	]	] #
ag*+	
 
 
 {+FGHHK011	\233
{:.//n.,..///:y::;;; 	W_%566F W;<<<<UVVV C2W$X$XYYN5GNNNOOO$+K677!"
 
 

9#
 #
 #
 #
 #
 #
 #
 #
 #
 #
 #
 #
 #
 #
 #
J ,x|
$
$C*:>>,+J+JKK#33J:>>*>??@@ 	#"  !888N6LNNOOO?4 	Y 	((1E	
 	jnn\8<< 	
>2 	88 	s}} 	h,ZHLIIISSUU 	& 	%#-fc#:#:D
 
 	T  	!" 	#$ 	%& 	D'( 	 )J, )/'   s   ,D>I66I:=I:c                   t          | dd          pd}t          t          | dd                    }t          | dd          p't          j        d          pt          j        d          }	 t	          t          | d	d          p|j        t          | d
d          p|j        t          | dd          p|j        t          | dd          p|j        t          | dd           |||d	  	        }|d         }|rdn|r|nd}t                      5  t                      }t          |d|           t          |          }	ddd           n# 1 swxY w Y   t          d|          }
t                       t          d           t          d|	            t          d|
 d           	 |                    d          p|                    d          }t!          |t"                    r|st%          ddd          ddlm} |                    dg           }t                       |rSt          dt+          |           d           t-          |          }|r!t/          |           t          d |            nt          d!           dS dS # t0          $ r^}t!          |t$                    rt3          |          nt#          |          }t                       t          d"|            Y d}~dS d}~ww xY w# t4          $ r t          d#           t7          d$          t0          $ r&}t          d%|            t7          d&          d}~ww xY w)'z&Nous Portal device authorization flow.r   Nr   r  Fr  r$  r%  
portal_urlinference_urlr   r    
no_browserr:  r;  r   Tr0   r  r  r  z (model.provider=nous)rj  r  z,No runtime API key available to fetch modelsr  rR  r   )_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'  r(  zLogin failed: r   )r  r   rw   r   rG  r   r   r   r    r;  rJ  rn  rh  r  r  rH  r   r   r   hermes_cli.modelsrL  r   r
  r  r   r   r   r  )r  r   r  r  r  r  r   rT  rK  saved_tor  runtime_keyrL  re  selected_modelr   r   s                    r/   _login_nousrQ  
  s   dIt44<OGD*e4455Hk4(( 	&9'((	&9_%% ;,#D,==XAX&t_dCCawGadK66K':K$..?'-$T<???+ &

 

 


 ((<=&.VUU)5UYYQU 	4 	4)++J VZ@@@'
33H	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4
 2&:LMM!""")x))***F;FFFGGG	_$..55W9W9WKk3// { B#(    ;:::::(,,VR88IGGG FpYpppqqq!8!C!C! E&~666C>CCDDDDEEEEE   	_ 	_ 	_0:3	0J0JX',,,PSTWPXPXGGGG]T[]]^^^^^^^^^	_
    "###oo   $s$$%%%mmsd   ,B K5 /E;K5 EK5 EAK5 %C!J
 

K2AK-'K5 -K22K5 51M&!MMc                   t          | dd          }|r*|t          vr!t          d|            t          d          t	                      }|p|}|st          d           dS |t          v rt          |         j        n|}t          |          rWt                       t          d| d           t          j	        d          rt          d	           dS t          d
           dS t          d| d           dS )z Clear auth state for a provider.r   NzUnknown provider: r   z#No provider is currently logged in.zLogged out of rQ  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  rg   r  r  r|  r   r  r  rw   r   )r  r   r  r~  provider_names        r/   logout_commandrT  P
  s-   $
D11K {*;;;0;00111mm ""F"FF 34446<@Q6Q6Q%f-22W]M6"" ;   /}///0009)** 	O=>>>>>MNNNNN9999:::::r.   )r5   r   rh   r   ri   r   rj   r   )rj   ro   )rj   r   )r   r
   r   r   rj   r   )r   r   r   r   rj   r   )r   )r5   r   r   r   rj   r   )r   r   rj   r   )r   r
   rj   r   )rj   r   )r  r   r  r   r  r
   rj   r   )rj   r	   )r  r   r   )r<  r=  rj   r"   )rK  r"   rj   r	   )rK  r"   r   r   rj   ri  )rK  r"   r   r   rk  r"   rj   r   )r   r   rj   r"   )r   r   rt  ru  rj   r	   )r   r   rj   ri  )r   r   rj   r   )rj   r   )r  r   r  r   r  r   rj   r   )r   r
   rj   r  )r  r
   r  r   rj   r   )r  r
   rj   r   )r   r
   rj   r   )r   r
   rj   r"   )r  r
   r  r   rj   r   )r  r   rj   r"   )r  r  r  r   rj   r   )r  r   r  r   r  r   rj   r"   )r  r  r  r   rj   r  )rj   r   )r  r   r  r   r  r   rj   r"   )r  r   r  r   r  ri  rj   r!  )
r  r*  r   r   r   r   r    r   rj   r"   )r  r*  r   r   r   r   r-  r   r  r   r;  r   rj   r"   )
r  r*  r   r   r   r   r  r   rj   r"   )
r  r*  r   r   r  r   rN  r   rj   r"   )
r   r   r5   r   r  r   rT  r!  rj   rU  )rk  r"   rN  r   rj   r   )
r  r   r  r   r  r   r  r   rj   r   )$r  r   r  r   r   r   r   r   r   r   ru  r   r    r   rw  r   rr  r   rj  r   rk  r   r  r   r  r   r  r   r  r   r  r   r  r   rj   r"   )rk  r"   r  r   r  r   r  r   r  r   rj   r"   )r  r   r  r   r  r   r  r   r  r   rj   r"   )rj   r"   )r   r   rj   r"   )rj   ru  )r   r   r   r   r  r   rj   r	   )r   )re  rU  r  r   rj   r   )rg  r   rj   r   )r   r   rj   r   )r   r   r   r   r   r   r    r   r<  r   r  r   r  r   r  r   r  r   rj   r"   )r+   
__future__r   r   loggingrw   rs   r  r#  r  r   r   	threadingr'  rX  r?  
contextlibr   dataclassesr   r   r   r   pathlibr	   typingr
   r   r   r   r   r  r  r   r   r  r   	getLoggerr(   r   r   r   r!  rE  r  r{  r  r|  r  !DEFAULT_AGENT_KEY_MIN_TTL_SECONDSr  rB  r  DEFAULT_GITHUB_MODELS_BASE_URLDEFAULT_COPILOT_ACP_BASE_URLr  r  'CODEX_ACCESS_TOKEN_REFRESH_SKEW_SECONDSr   rg   r,   rm   rn   r   r   r   r   r   r   r   rC  r   r   r   r   r  r  r  localr  r;  rJ  rh  rl  rn  rs  rw  ry  r|  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  r)  r:  rH  rM  rS  rh  rl  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r
  r  r  r  r  rG  rQ  rT  r$   r.   r/   <module>rb     s     # " " " " "   				                    % % % % % % ( ( ( ( ( ( ( ( ' ' ' ' ' ' ' '       , , , , , , , , , , , ,   > > > > > > > > 0 0 0 0 0 0		8	$	$LLLL   EEEMMMM   FFF     < H % / $+ !$' !() %@ !@ . 6 = *- '         A0
NN%/5(   A0 NN"1	  A0  ~~9M  !A0. >>!$7/  /A0< 
>>9G'  =A0L >>7*(  MA0\ ~~=-+  ]A0l 6\  mA0z ~~(S/-  {A0J ..?0.  KA0Z 8.,  [A0j ..<0.  kA0z NN720  {A0J >>
 ;1/  KA0b <.,  cA0r >>=&&  sA0  A A A AX 6 
 
 
 
   *   $    89 	 	 	 	 	 	   B  ! ! ! ! !P1 1 1 1 1 1 1 1"   4D D D D- - - -
 >B [ [ [ [ [ [+ + + +2 2 2 2 $IO%% .G 6 6 6 6 6r< < < < <:! ! ! !H< < < <0 0 0 0	P 	P 	P 	P 	P	, 	, 	, 	,9 9 9 9- - - -# # # # #L	% 	% 	% 	%"  $W '+'+	W W W W W W|   "9 9 9 9   ( ( ( (
6 
6 
6 
6C C C CA A A A )- . . . . . .b% % % % %$ "	O O O O O Od   *   2   $ G	< < < < < <J  $#+/	     >   6.E .E .E .Ej W  W  W  WFW W W WJ "6* 6* 6* 6* 6* 6*rP P P P "## AP% P% P% P% P% P%t #!% $#*.@!##%R R R R R Rp  A!     B  A!##v v v v v vz   ,
 
 
 
&   >   <          ! ! ! !H% % % %X   < $(; ; ; ; ;|   .J J J J JZ   "   6L 6L 6L 6LrN N N Nf &*(,#!#%s s s s s slE E E EP; ; ; ; ; ;s$   B BB B% %B/.B/