+
    jHàjlZ ã                  ó€  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIHtHt ^ RIHtHtHt ^ RIHt ^ RIHtHtHtHtHtHtHt ^ RIHt ^ RIHt ^ R	IH t H!t!H"t"H#t#H$t$H%t%H&t&H't'H(t(H)t)H*t*H+t+H,t,H-t-H.t.H/t/H0t0 ^ R
I1H2t2H3t3H4t4H5t5 ]'       d   ^ RI6H7t7 ]Pp                  ! R4      t9Rt:RR/R R llt;R R lt<RR/R R llt=R R lt>RRRRRRRRRRRR/t?R]@R &   ]A! R!04      tBR"]@R#&   R$ R% ltCR& R' ltDR( R) ltE]A! R*R+04      tFR"]@R,&   R- R. ltGR/ R0 ltHR1 R2 ltIR3 R4 ltJR5 R6 ltKR7 R8 ltLR9 R: ltMR;RR<RR=]-/R> R? lltNR;RR<RR=]-/R@ RA lltORB RC ltPRDR/RE RF lltQRG RH ltRRÃRI RJ lltSRKR/RL RM lltTRDRRR/RN RO lltU]A! RPR04      tVRQ RR ltWRStX]P²                  ! 4       tZRT RU lt[RV RW lt\]]!3RX RY ll4       t]RZ R[ lt^RÄt_R` Ra lt`Rb Rc ltaRd Re ltbRf Rg ltcRh Ri ltdRj Rk lteRl Rm ltfRn Ro ltgRpRq/Rr Rs llthRt Ru ltiRv Rw ltjR_R/Rx Ry lltkRz R{ ltlR| R} ltmR~ R ltnRpRqR€R�/R‚ Rƒ lltoR„ R… ltpR\R†R;]&RKRR<RRRRRRpRqR‡RRˆRR‰RRŠR/R‹ RŒ lltqRpRqR‰RRŠR/R� RŽ lltrR�R/R� R‘ lltsR’ R“ lttR” R• ltu ! R– R—4      tvRpRqR‡RRˆRR‰RR˜R/R™ Rš lltwRpRqR‡RRˆRR‰RR˜R/R› Rœ lltxR� Rž ltyRŸ R  ltzR¡ R¢ lt{R£ R¤ lt|R¥ R¦ lt}R§ R¨ lt~R©tRªt€R«t�R¬ R­ lt‚R®R/R¯ R° lltƒR^RR_RR]RR;RR±R�RpRqR‡RRˆRR²R/	R³ R´ llt„Rµ R¶ lt…R±R�RpRqR²R/R· R¸ llt†R¹ Rº lt‡R» R¼ ltˆR½ R¾ lt‰R¿ RÀ ltŠRÁ RÂ lt‹R# )Åa	  Nous Portal OAuth: device-code login, refresh, shared-store mirroring, JWT selection, status.

Split out of ``hermes_cli/auth.py``; origin helpers are imported lazily inside each function
so ``hermes_cli.auth.<name>`` patches still intercept (and no import cycle).
)ÚannotationsN)ÚcontextmanagerÚsuppress)ÚdatetimeÚtimezoneÚUTC)ÚPath)ÚTYPE_CHECKINGÚAnyÚCallableÚDictÚ	FrozenSetÚListÚOptional)Úurlparse)Ú_pool_entries)Ú_decode_jwt_claimsÚAUTH_LOCK_TIMEOUT_SECONDSÚ	AuthErrorÚDEFAULT_NOUS_CLIENT_IDÚDEFAULT_NOUS_INFERENCE_URLÚDEFAULT_NOUS_PORTAL_URLÚDEFAULT_NOUS_SCOPEÚDEFAULT_NOUS_WELCOME_URLÚ%DEVICE_AUTH_POLL_INTERVAL_CAP_SECONDSÚNOUS_AUTH_PATH_INVOKE_JWTÚNOUS_BILLING_MANAGE_SCOPEÚNOUS_DEVICE_CODE_SOURCEÚNOUS_INFERENCE_INVOKE_SCOPEÚNOUS_INVOKE_JWT_MIN_TTL_SECONDSÚWELCOME_CLAIM_FLAGÚ	_nous_errÚhttpx)ÚdeferredÚdrainÚnote_replacementÚresult_lines)ÚProviderConfigzhermes_cli.authz*Re-authenticate with: hermes auth add nousÚno_refresh_tokenFc               ó$   € V ^8„  d   QhRRRRRR/# )é   ÚreasonÚstrr(   ÚboolÚreturnr   © )Úformats   "Ú9/home/ubuntu/.hermes/hermes-agent/hermes_cli/auth_nous.pyÚ__annotate__r2   '   s'   € ÷ Yñ Y sð YÀð YÐR[ñ Yó    c               óp   € V'       d   RMRp\        RV  RV R\         2V'       d	   RRR7      # T RR7      # )	aU  Shared ``relogin=True`` error for an access token that is not a usable inference JWT.

With no refresh token the failure is a state-shape one (nothing to redeem), so it carries the
terminal ``nous_auth_missing_refresh_token`` code the pool recognises instead of the JWT
``reason``, which would bench the row as a transient outage (#113718).
z" and no refresh token is availableÚ z8Nous Portal access token is not a usable inference JWT (Ú)z. Únous_auth_missing_refresh_tokenT©Úrelogin)r!   Ú_UNUSABLE_JWT_RELOGIN)r+   r(   Údetails   &$ r1   Ú_unusable_invoke_jwt_errorr<   '   sX   € ÷ 6FÑ1È2€FÜØ
BÀ6À(È!ÈFÈ8ÐSUÜ Ð
!ð	#ç-=Ð)ÐSWôYð Yð DJÐSWôYð Yr3   c               ó    € V ^8„  d   QhRRRR/# )r*   Útokenr
   r.   úOptional[str]r/   )r0   s   "r1   r2   r2   5   s   € ÷ Yñ Y˜cð Y mñ Yr3   c                óÚ   € \        V \        4      '       d   V P                  4       MRpV'       d;   \        P                  ! VP                  R4      4      P                  4       R,          # R# )zJReturn a short hash fingerprint for telemetry without leaking token bytes.r5   zutf-8ºNé   NN)Ú
isinstancer,   ÚstripÚhashlibÚsha256ÚencodeÚ	hexdigest)r>   Úcleaneds   & r1   Ú_token_fingerprintrJ   5   sI   € ä)¨%´×5Ò5ˆe�k‰kŒm¸2€GßGNŒ7�>Š>˜'Ÿ.™.¨Ó1Ó2×<Ñ<Ó>¸sÕCÐXÐTXÐXr3   Úsequence_idc               ó(   € V ^8„  d   QhRRRRRRRR/# )	r*   Úeventr,   rK   r?   Úfieldsr
   r.   ÚNoner/   )r0   s   "r1   r2   r2   ;   s/   € ÷ [ñ [˜ð [¨]ð [ÈSð [ÐUYñ [r3   c          	     ó  € \         P                  ! R R4      P                  4       P                  4       R	9  d   R# RV /pV'       d   WR&   VP	                  V4       \
        P                  R\        P                  ! VRRR7      4       R# )
ÚHERMES_OAUTH_TRACEr5   NrM   rK   zoauth_trace %sTF©Ú	sort_keysÚensure_ascii>   Ú1ÚonÚyesÚtrue)	ÚosÚgetenvrD   ÚlowerÚupdateÚloggerÚinfoÚjsonÚdumps)rM   rK   rN   Úpayloads   &$, r1   Ú_oauth_tracerb   ;   sj   € Ü	‡y‚yÐ% rÓ*×0Ñ0Ó2×8Ñ8Ó:ÐB\Ô\ÙØ&¨Ð.€GßØ!,�ÑØ‡N�N�6ÔÜ
‡K�KÐ ¤$§*¢*¨WÀÐSXÔ"YÖZr3   c               ó$   € V ^8„  d   QhRRRRRR/# )r*   Únowr   Úttl_secondsÚintr.   r,   r/   )r0   s   "r1   r2   r2   E   s&   € ÷ Uñ U�Hð U¨3ð U°3ñ Ur3   c                ó€   € \         P                  ! V P                  4       V,           \        R7      P	                  4       # )z.ISO timestamp *ttl_seconds* after *now* (UTC).©Útz)r   ÚfromtimestampÚ	timestampr   Ú	isoformat)rd   re   s   &&r1   Ú
_iso_afterrm   E   s)   € ä×!Ò! #§-¡-£/°KÕ"?ÄCÔH×RÑRÓTÐTr3   Ú	agent_keyÚagent_key_idÚagent_key_expires_atÚagent_key_expires_inÚagent_key_reusedÚagent_key_obtained_atúdict[str, Any]Ú_NOUS_EMPTY_AGENT_KEY_FIELDSzapi.nousresearch.comzfrozenset[str]Ú_NOUS_STALE_PORTAL_HOSTSc               ó    € V ^8„  d   QhRRRR/# )r*   Ú
capabilityr,   r.   r/   )r0   s   "r1   r2   r2   R   s   € ÷ ]ñ ]¨Cð ]°Cñ ]r3   c                óJ   € ^ RI HpHp V! RR7      pV! W0R7      ;'       g    R# )zUPortal entitlement notice for *capability* (fresh account data), "" when unavailable.)Ú&format_nous_portal_entitlement_messageÚget_nous_portal_account_infoT©Úforce_fresh)rx   r5   )Úhermes_cli.nous_accountrz   r{   )rx   rz   r{   Úaccount_infos   &   r1   Ú_portal_entitlement_messager€   R   s&   € ÷Ná/¸DÔA€LÙ1°,ÔV×\Ð\ÐZ\Ð\r3   c               ó    € V ^8„  d   QhRRRR/# )r*   Úerrorr   r.   r,   r/   )r0   s   "r1   r2   r2   Z   s   € ÷ Kñ K¨yð K¸Sñ Kr3   c                ó²   € \        \        4      ;_uu_ 4        \        R 4      ;p'       d   VuuRRR4       #  RRR4       V  R2#   + '       g   i     L; i)zNous model accessNz5 Check credits or billing in Nous Portal, then retry.)r   Ú	Exceptionr€   )r‚   Úmessages   & r1   Ú#_format_nous_entitlement_auth_errorr†   Z   sJ   € Ü	”)×	Õ	Ü1Ð2EÓFÐFˆ7ÖFØ÷ 
Ò	ØF÷ 
ð ˆWÐIÐJÐJ÷ 
×	ús   ˜AÁA	c               ó    € V ^8„  d   QhRRRR/# )r*   Ú	providersrt   r.   rO   r/   )r0   s   "r1   r2   r2   a   s   € ÷ :ñ :¨nð :Àñ :r3   c                óF  € V P                  R 4      p\        V\        4      '       g   R# VP                  R4      ;'       g    RP                  4       pV'       dG   \	        V4      P
                  \        9   d'   \        P                  RV\        4       \        VR&   R# R# R# )ÚnousNÚportal_base_urlr5   z3auth: migrating stale nous portal_base_url %s -> %s)
ÚgetrC   ÚdictrD   r   Úhostnamerv   r]   Úwarningr   )rˆ   rŠ   Ústoreds   &  r1   Ú_migrate_stale_nous_portal_urlr‘   a   s~   € Ø�=‰=˜Ó €DÜ�dœD×!Ò!ÙØ�h‰hÐ(Ó)×/Ð/¨R×6Ñ6Ó8€Fß”(˜6Ó"×+Ñ+Ô/GÔGÜ�‰ØAÀ6ÔKbô	dä"9ˆÐÓñ H�vr3   zinference-api.nousresearch.comzwelcome-api.nousresearch.comÚ_ALLOWED_NOUS_INFERENCE_HOSTSc               ó    € V ^8„  d   QhRRRR/# )r*   rŽ   r?   r.   r-   r/   )r0   s   "r1   r2   r2   u   s   € ÷ Lñ L¨=ð L¸Tñ Lr3   c                óŒ   € V \         9   d   R# V '       g   R# \        4       pVRJ;'       d    \        V4      P                  V 8H  # )ug  Production hosts always; otherwise only the host the operator named in
``NOUS_INFERENCE_BASE_URL``.

A non-production Portal's refresh response names that environment's inference gateway. The
Portal-returned value is network provenance, so it does not get bearer-receive authority on
its own â€” not even for a Nous-owned host: the operator's explicit override is the authority,
and the network value is accepted exactly when it agrees with it. Then the persisted endpoint,
the pricing scope and the proxy all follow the environment the operator chose, and the
per-turn "refusing inference URL host" warning stops.
TFN)r’   Ú_nous_inference_env_overrider   rŽ   )rŽ   Úoverrides   & r1   Ú_nous_inference_host_allowedr—   u   sA   € ð Ô0Ô0ÙßÙÜ+Ó-€HØ˜4Ð×KÐK¤H¨XÓ$6×$?Ñ$?À8Ñ$KÐKr3   c               ó    € V ^8„  d   QhRRRR/# )r*   Úurlr?   r.   r/   )r0   s   "r1   r2   r2   ˆ   s   € ÷ ñ °=ð À]ñ r3   c                ó¤  € \        V \        4      '       d   V P                  4       MRpV'       g   R#  \        V4      pTP
                  R8w  d#   \        P                  RTP
                  4       R# \        TP                  4      '       g#   \        P                  RTP                  4       R# TP                  R4      #   \         d     R# i ; i)u  Validate a Portal-returned inference URL against the host allowlist.

Defense-in-depth: a compromised refresh response (MITM, response injection) could otherwise
redirect every proxy request â€” bearing the user's inference JWT â€” to an attacker endpoint.
r5   NÚhttpszEnous: refusing non-https inference URL scheme %r from Portal responsezenous: refusing inference URL host %r from Portal response (not in allowlist); falling back to defaultÚ/)rC   r,   rD   r   r„   Úschemer]   r�   r—   rŽ   Úrstrip)r™   rI   Úparseds   &  r1   Ú)_validate_nous_inference_url_from_networkr    ˆ   s«   € ô (¨¬S×1Ò1ˆc�i‰iŒk°r€GßÙðÜ˜'Ó"ˆð ‡}�}˜ÔÜ�‰ØSÐU[×UbÑUbô	dáÜ'¨¯©×8Ò8Ü�‰ð:à�O‰Oô	ñ Ø�>‰>˜#ÓÐøô ô Úðús   ´C  Ã CÃCc               ó    € V ^8„  d   QhRRRR/# )r*   Únamesr,   r.   r?   r/   )r0   s   "r1   r2   r2   ¢   s   € ÷ ñ  cð ¨mñ r3   c                 ó¸   € ^ RI HpHp  V  F  pV! V4      pV'       g   K  Vu # 	  R#   T d*    \        P	                  RRP                  T 4      4        R# i ; i)u\  The first set operator routing override among ``names`` (``NOUS_INFERENCE_BASE_URL``,
``HERMES_PORTAL_BASE_URL`` / its ``NOUS_PORTAL_BASE_URL`` alias), resolved through the profile
secret scope, or None.

``get_secret`` already reads ``os.environ`` for a single-profile process, so the only time it
raises is a multi-profile call that has lost its profile scope. That call has no authority to
route on the launch profile's value â€” returning the ambient env there would send a secondary's
tokens to the launch profile's Portal or inference host â€” so the override is simply absent.
Absent is not free: default routing then applies, so a non-production deployment's token is
spent against the production hosts. One WARNING per lost-scope event names the override; the
downstream "ignoring invalid portal_base_url" line never says which caller lost its scope.
)ÚUnscopedSecretErrorÚ
get_secretNu«   nous: %s unreadable â€” no profile secret scope on a multiplexed call; treating the override as absent (default routing applies). The caller needs a profile scope binding.rœ   )Úagent.secret_scoper¤   r¥   r]   r�   Újoin)r¢   r¤   r¥   ÚnameÚvalues   *    r1   Ú_scoped_operator_overriderª   ¢   sa   € ÷ CðÛˆDÙ˜tÓ$ˆEß‰uØ’ñ ñ øØô Ü�‰ðfà�H‰H�U‹Oô	ò ðús   Š) ¡) ¥) ©,AÁAc               ó   € V ^8„  d   QhRR/# ©r*   r.   r?   r/   )r0   s   "r1   r2   r2   ¾   s   € ÷ 	Tñ 	T mñ 	Tr3   c                 ó0   € ^ RI Hp  V ! \        R4      4      # )a‹  User-set ``NOUS_INFERENCE_BASE_URL`` override (trailing slash stripped) or None.

Documented dev/staging escape hatch; the env source is trusted, so unlike Portal-returned URLs
it is intentionally NOT gated by the network host allowlist. Read through the profile-aware
resolver so a multiplexed profile uses its own override and never inherits the default
profile's process-wide value (#65941).
©Ú_optional_base_urlÚNOUS_INFERENCE_BASE_URL©Úhermes_cli.authr¯   rª   r®   s    r1   r•   r•   ¾   s   € õ 3ÙÔ7Ð8QÓRÓSÐSr3   c               ó   € V ^8„  d   QhRR/# r¬   r/   )r0   s   "r1   r2   r2   Ê   s   € ÷ kñ k =ñ kr3   c                 ó2   € ^ RI Hp  V ! \        RR4      4      # )a9  ``HERMES_PORTAL_BASE_URL`` / ``NOUS_PORTAL_BASE_URL`` override or None.

Documented dev/staging escape hatch (e.g. hosted agents on the staging Portal). Trusted env
source: must NOT be gated by ``_NOUS_PORTAL_ALLOWED_HOSTS``, which rejects untrusted
NETWORK-provided values persisted to auth.json, not operator config. Read through the
profile secret scope like ``_nous_inference_env_override``: it is reached on every routed
turn (``_nous_effective_routing``), and a raw environ read would POST a multiplexed
secondary's refresh token to the DEFAULT profile's Portal.
r®   ÚHERMES_PORTAL_BASE_URLÚNOUS_PORTAL_BASE_URLr±   r®   s    r1   Ú_nous_portal_env_overrider·   Ê   s   € õ 3ÙÔ7Ð8PÐRhÓiÓjÐjr3   c               ó    € V ^8„  d   QhRRRR/# )r*   Ústatert   r.   r,   r/   )r0   s   "r1   r2   r2   Ø   s   € ÷ ñ  ð °Cñ r3   c                óF  € \        4       pV'       d   VP                  R4      # ^ RIHpHp V! V P                  R4      4      ;'       g    \        pVP                  R4      p\        V4      P                  pV'       d#   WR9  d   \        P                  RWE4       \        # V# )a  HERMES_PORTAL_BASE_URL / NOUS_PORTAL_BASE_URL is the trusted operator override and wins
OUTRIGHT, bypassing the host allowlist (which exists to reject an untrusted network-provided
value, not one the operator configured). Otherwise the stored/default value, allowlist-gated.rœ   ©Ú_NOUS_PORTAL_ALLOWED_HOSTSr¯   r‹   zSauth: ignoring invalid portal_base_url %r (host %r not in allowlist), using default)r·   rž   r²   r¼   r¯   rŒ   r   r   rŽ   r]   r�   )r¹   Úenv_portal_overrider¼   r¯   r‹   Úhosts   &     r1   Ú_nous_portal_base_urlr¿   Ø   s‰   € ô 4Ó5ÐßØ"×)Ñ)¨#Ó.Ð.ßNÙ(¨¯©Ð3DÓ)EÓF×aÐaÔJa€OØ%×,Ñ,¨SÓ1€OÜ�OÓ$×-Ñ-€Dß�Ô6Ü�‰ØaØô	#ô 'Ð&ØÐr3   c               ó    € V ^8„  d   QhRRRR/# )r*   Ú	raw_scoper
   r.   zset[str]r/   )r0   s   "r1   r2   r2   ë   s   € ÷ ñ ˜Sð  Xñ r3   c                ó0  € \        4       p\        V \        4      '       d9   VP                  R  V P	                  RR4      P                  4        4       4       V# \        V \        \        \         \        34      '       d   VP                  ! R V  4       !   V# )c              3  óT   "  € T F  qP                  4       '       g   K  Vx € K   	  R # 5i©N)rD   )Ú.0Úparts   & r1   Ú	<genexpr>Ú _scope_values.<locals>.<genexpr>ð   s   é € Ð[Ñ'J˜tÏjÉjÏl—d’dÓ'Jùs   ‚(ž
(Ú,Ú c              3  óh   "  € T F(  p\        V\        4      '       g   K  \        V4      x € K*  	  R # 5irÄ   )rC   r,   Ú_scope_values)rÅ   Úitems   & r1   rÇ   rÈ   ò   s&   é € Ð[¹	°ÄZÐPTÔVY×EZÔ+œ d×+Ð+»	ùs   ‚2Ÿ2)	ÚsetrC   r,   r\   ÚreplaceÚsplitÚlistÚtupleÚ	frozenset)rÁ   Úscopess   & r1   rÌ   rÌ   ë   sv   € ô “u€FÜ�)œS×!Ò!Ø�‰Ñ[ y×'8Ñ'8¸¸cÓ'B×'HÑ'HÔ'JÓ[Ô[ð €Mô 
�I¤¤e¬S´)Ð<×	=Ò	=Ø�ŠÑ[¹	Ó[Ò\Ø€Mr3   ÚscopeÚ
expires_atÚmin_ttl_secondsc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r*   r>   r
   rÕ   rÖ   r×   rf   r.   r?   r/   )r0   s   "r1   r2   r2   ö   s;   € ÷ _ñ _Øð_Øð_Ø25ð_àð_à?Lñ_r3   c               óè  € ^ RI Hp \        V 4      pV'       g   R# \        V4      \        VP	                  R4      4      ,          \        VP	                  R4      4      ,          p\
        V9  d   R# VP	                  R4      p\        ^ \        V4      4      p\        V\        \        34      '       d/   \        V4      \        P                  ! 4       V,           8:  d   R# R# V! W(4      '       d   R	# R# )
zDReturn None when the token can be used for inference, else a reason.)Ú_is_expiringÚaccess_token_not_jwtrÕ   ÚscpÚmissing_inference_invoke_scopeÚexpÚinvoke_jwt_expiringNÚ%invoke_jwt_expiry_unknown_or_expiring)r²   rÚ   r   rÌ   rŒ   r   Úmaxrf   rC   ÚfloatÚtime)	r>   rÕ   rÖ   r×   rÚ   ÚclaimsrÔ   rÞ   Úskews	   &$$$     r1   Ú_nous_invoke_jwt_statusræ   ö   s¿   € õ -Ü Ó&€FßÙ%Ü˜EÓ"¤]°6·:±:¸gÓ3FÓ%GÕGÜ˜fŸj™j¨Ó/Ó0õ1€Fä"¨&Ô0Ù/Ø
�*‰*�UÓ
€CÜˆq”#�oÓ&Ó'€DÜ�#œœU�|×$Ò$Ü(-¨c«
´t·y²y³{ÀTÕ7IÔ(JÐ$ÐTÐPTÐTÙ6BÀ:×6TÒ6TÐ2Ð^ÐZ^Ð^r3   c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r*   r>   r
   rÕ   rÖ   r×   rf   r.   r-   r/   )r0   s   "r1   r2   r2   	  s;   € ÷ \ñ \Øð\Øð\Ø25ð\àð\à?Cñ\r3   c               ó&   € ^ RI Hp V! WW#R7      RJ # )é    ©ræ   ©rÕ   rÖ   r×   N)r²   ræ   )r>   rÕ   rÖ   r×   ræ   s   &$$$ r1   Ú_nous_invoke_jwt_is_usablerì   	  s$   € õ 8Ù"Ø zôTØW[ð\ð \r3   c               ó$   € V ^8„  d   QhRRRRRR/# )r*   r¹   rt   r>   r
   r.   r?   r/   )r0   s   "r1   r2   r2     s&   € ÷ Mñ M Nð M¸3ð MÀ=ñ Mr3   c                ó^   € ^ RI Hp V! WP                  R4      V P                  R4      R7      # )zW``_nous_invoke_jwt_status`` for *token* using *state*'s scope / expires_at (patchable).rê   rÕ   rÖ   )rÕ   rÖ   )r²   ræ   rŒ   )r¹   r>   ræ   s   && r1   Ú_state_invoke_jwt_statusrï     s+   € å7Ù"Ø—Y‘Y˜wÓ'°E·I±I¸lÓ4KôMð Mr3   Úaccess_tokenc               ó$   € V ^8„  d   QhRRRRRR/# )r*   r¹   rt   rð   r
   r.   rO   r/   )r0   s   "r1   r2   r2     s"   € ÷ 1ñ 1¨^ð 1Ècð 1Ð]añ 1r3   c               óh   € Vf   V P                  R4      MTp\        W4      pVe   \        V4      hR # )Nrð   )rŒ   rï   r<   )r¹   rð   r>   r+   s   &$  r1   Ú!_assert_nous_inference_jwt_usableró     s7   € Ø)5Ò)=ˆE�I‰I�nÔ%À<€EÜ% eÓ3€FØÒÜ(¨Ó0Ð0ñ r3   c               ó$   € V ^8„  d   QhRRRRRR/# )r*   rÖ   r
   Úfallback_expires_inr.   rf   r/   )r0   s   "r1   r2   r2     s!   € ÷ 4ñ 4˜sð 4¸ð 4Àñ 4r3   c                ó˜   € ^ RI HpHp V! V 4      pVe0   \        ^ \	        V\
        P
                  ! 4       ,
          4      4      # V! V4      # )zNSeconds until *expires_at* (ISO), else *fallback_expires_in* coerced to a TTL.)Ú_coerce_ttl_secondsÚ_parse_iso_timestamp)r²   r÷   rø   rá   rf   rã   )rÖ   rõ   r÷   rø   Úexpires_epochs   &&   r1   Ú_remaining_ttlrú     s>   € çIÙ(¨Ó4€MØÒ Ü�1”c˜-¬$¯)ª)«+Õ5Ó6Ó7Ð7ÙÐ2Ó3Ð3r3   c               ó$   € V ^8„  d   QhRRRRRR/# )r*   r>   r
   Úfallback_expires_atr.   r?   r/   )r0   s   "r1   r2   r2   (  s&   € ÷ Qñ Q ð Q¸#ð QÈñ Qr3   c                óv  € \        V 4      pVP                  R 4      p\        V\        \        34      '       dV   \        \        4      ;_uu_ 4        \        P                  ! \	        V4      \        R7      P                  4       uuRRR4       # \        V\        4      '       d   V# R#   + '       g   i     L*; i)rÞ   rh   N)r   rŒ   rC   rf   râ   r   r„   r   rj   r   rl   r,   )r>   rü   rä   rÞ   s   &&  r1   Ú_nous_jwt_expires_atrþ   (  s}   € Ü Ó&€FØ
�*‰*�UÓ
€CÜ�#œœU�|×$Ò$Ü”i× Õ Ü×)Ò)¬%°«*¼Ô=×GÑGÓI÷ !Ò ä",Ð-@Ä#×"FÒ"FÐÐPÈDÐP÷ !× ús   Á3B(Â(B8	Úobtained_atc               ó$   € V ^8„  d   QhRRRRRR/# )r*   r¹   rt   rÿ   r?   r.   rO   r/   )r0   s   "r1   r2   r2   1  s)   € ÷ dñ dØðdØ+8ðdØDHñdr3   c          	     óè  € ^ RI Hp V P                  R4      pV! V4      '       g   R# V P                  R4      pV'       gW   V P                  R4      V8H  ;'       d	    V! V4      pV'       d   TM'\        P                  ! \
        4      P                  4       p\        W0P                  R4      4      p\        W`P                  R4      4      pV'       d	   W`R&   WpR&   V P                  VRVVRVR	7       R# )
ré   ©Ú_nonempty_strrð   Nrs   rn   rÖ   Ú
expires_inF)rn   ro   rp   rq   rr   rs   )
r²   r  rŒ   r   rd   r   rl   rþ   rú   r\   )r¹   rÿ   r  rð   Úexisting_obtained_atÚreuserÖ   r  s   &$      r1   Ú#_set_nous_agent_key_from_invoke_jwtr  1  sË   € å-Ø—9‘9˜^Ó,€LÙ˜×&Ò&ÙØ Ÿ9™9Ð%<Ó=ÐßØ—	‘	˜+Ó&¨,Ñ6×^Ð^¹=ÐI]Ó;^ˆß.3Ñ*¼¿ºÄcÓ9J×9TÑ9TÓ9VˆÜ% l·I±I¸lÓ4KÓL€JÜ 
¯I©I°lÓ,CÓD€JßØ(ˆlÑØ(ˆlÑØ	‡L�LØ¨TÈ
Ø'¸%ÐWbð ö dr3   c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r*   r¹   rt   rð   r
   rK   r?   r.   rO   r/   )r0   s   "r1   r2   r2   E  s2   € ÷ 	Gñ 	GØð	GØ,/ð	GØERð	GØ^bñ	Gr3   c          	     óÂ   € ^ RI Hp V! V4      '       d   WR&   \        V 4       \        P	                  R4       \        RV\        V P                  R4      4      R7       R# )ré   r  rð   z)Nous inference auth: using NAS invoke JWTÚnous_invoke_jwt_selected©rK   Úaccess_token_fpN)r²   r  r  r]   Údebugrb   rJ   rŒ   )r¹   rð   rK   r  s   &$$ r1   Ú_select_nous_invoke_jwtr  E  sL   € å-Ù�\×"Ò"Ø ,ˆnÑÜ'¨Ô.Ü
‡L�LÐ<Ô=ÜØ"°Ü*¨5¯9©9°^Ó+DÓE÷Gr3   r  c               ó    € V ^8„  d   QhRRRR/# )r*   r¹   rt   r.   r/   )r0   s   "r1   r2   r2   V  s   € ÷ [ñ [¨.ð [¸^ñ [r3   c                óp   € V P                  4        UUu/ uF  w  rV\        9  g   K  WbK  	  upp# u uppi rÄ   )ÚitemsÚ"_NOUS_EFFECTIVE_STATE_IGNORED_KEYS)r¹   ÚkÚvs   &  r1   Ú_nous_effective_provider_stater  V  s.   € Ø"Ÿ[™[œ]ÔZ™]‘T�Q¨aÔ7YÑ.YŒDˆAŠD™]ÒZÐZùÓZs   ”2¨2znous_auth.jsonc               ó   € V ^8„  d   QhRR/# ©r*   r.   r   r/   )r0   s   "r1   r2   r2   ^  s   € ÷ 0ñ 0˜tñ 0r3   c                 ó¶   € \         P                  ! RR4      P                  4       p V '       d   \        V 4      P	                  4       # ^ RIHp V! 4       R,          # )ae  Directory of the shared Nous token store: ``HERMES_SHARED_AUTH_DIR`` or ``<root>/shared/``.

Outside any named profile so all profiles share it (``hermes --profile X auth add nous --type
oauth`` one-tap imports it). Written on login AND every runtime refresh so the refresh_token
stays current across profiles; a stale token just falls back to device-code.
ÚHERMES_SHARED_AUTH_DIRr5   ©Úget_default_hermes_rootÚshared)rY   rZ   rD   r   Ú
expanduserÚhermes_constantsr  )r–   r  s     r1   Ú_nous_shared_auth_dirr  ^  sE   € ô �yŠyÐ1°2Ó6×<Ñ<Ó>€HßÜ�H‹~×(Ñ(Ó*Ð*Ý8Ù"Ó$ xÕ/Ð/r3   c               ó   € V ^8„  d   QhRR/# r  r/   )r0   s   "r1   r2   r2   l  s   € ÷ ñ  ñ r3   c                 óN  € \        4       \        ,          p \        P                  P	                  R 4      '       dX   ^ RIHp V! 4       R,          \        ,          P                  RR7      p V P                  RR7      pW28X  d   \        RV  R24      hV #   \         d    T p L&i ; i)ÚPYTEST_CURRENT_TESTr  r  F)ÚstrictzDRefusing to touch real user shared Nous auth store during test run: z@. Set HERMES_SHARED_AUTH_DIR to a tmp_path in your test fixture.)
r  ÚNOUS_SHARED_STORE_FILENAMErY   ÚenvironrŒ   r  r  Úresolver„   ÚRuntimeError)Úpathr  Úreal_home_sharedÚresolveds       r1   Ú_nous_shared_store_pathr+  l  s¥   € Ü Ó"Ô%?Õ?€Dô 
‡z�z‡~�~Ð+×,Ò,Ý<á#Ó%¨Õ0Ô3MÕMÏwÉwÐ^cÈwÓOdð 	ð	Ø—|‘|¨5�|Ó1ˆHð Ô'ÜØVØ�&ÐXðZó[ð [ð €Køô ô 	ØŠHð	ús   Á+B ÂB$Â#B$c               ó   € V ^8„  d   QhRR/# )r*   Útimeout_secondsrâ   r/   )r0   s   "r1   r2   r2   �  s   € ÷ ñ ¨Uñ r3   c              #  óò   "  € ^ RI Hp  \        4       P                  R4      pT! T\
        T RT R24      ;_uu_ 4        Rx € RRR4       R#   \         d	    Rx €  R# i ; i  + '       g   i     R# ; i5i)zÖCross-profile lock for the shared Nous OAuth store.

Lock ordering invariant: if both this and ``_auth_store_lock`` need to be held, acquire
``_auth_store_lock`` FIRST. All runtime refresh paths follow this order.
)Ú
_file_lockz.lockNz-Timed out waiting for shared Nous auth lock (r6   )r²   r/  r+  Úwith_suffixr'  Ú_nous_shared_lock_holder)r-  r/  Ú	lock_paths   &  r1   Ú_nous_shared_store_lockr3  €  s�   é € õ +ðÜ+Ó-×9Ñ9¸'ÓBˆ	ñ 
ØÔ+¨_Ø
7¸	°{À!ÐD÷
Fõ 
Fó 	÷
Fñ 
Føô ô ÛÚðú÷
F÷ 
Fð 
Füs>   ‚A7ŠA £A7¾A#Á
A7ÁA ÁA7ÁA Á A7Á#A4	Á.	A7c               ó    € V ^8„  d   QhRRRR/# )r*   r-  râ   r.   r/   )r0   s   "r1   r2   r2   “  s   € ÷ Añ A¨%ð A°Eñ Ar3   c                ó0   € \        V R ,           \        4      # )g      @)rá   r   ©r-  s   &r1   Ú_shared_lock_timeoutr7  “  s   € Üˆ Õ$Ô&?Ó@Ð@r3   Ú
token_typeÚ	client_idr‹   Úinference_base_urlc               ó    € V ^8„  d   QhRRRR/# )r*   r¹   rt   r.   r-   r/   )r0   s   "r1   r2   r2   Ÿ  s   € ÷ ñ ¨.ð ¸Tñ r3   c                óþ  € ^ RI HpHpHp V! 4       ;'       g    / pVP	                  R4      pV! V4      '       g   R# V! VP	                  R4      4      ;'       g    RpV! V P	                  R4      4      ;'       g    RpVP                  4       \        V P	                  R4      ;'       g    R4      P                  4       8g  pV'       g	   Wg8”  g   R# \         F!  p	VP	                  V	4      p
V
R9  g   K  W V	&   K#  	  R# )	zACopy fresher shared OAuth tokens into a profile-local Nous state.)r  rø   Ú_read_shared_nous_stateÚrefresh_tokenFrÖ   ç        r5   T>   Nr5   )r²   r  rø   r=  rŒ   rD   r,   Ú_NOUS_SHARED_STATE_KEYS)r¹   r  rø   r=  r  Úshared_refreshÚshared_access_expÚlocal_access_expÚrefresh_changedÚkeyr©   s   &          r1   Ú_merge_shared_nous_oauth_staterF  Ÿ  sÖ   € ç\Ñ\Ù$Ó&×,Ð,¨"€FØ—Z‘Z Ó0€NÙ˜×(Ò(ÙÙ,¨V¯Z©Z¸Ó-EÓF×MÐMÈ#ÐÙ+¨E¯I©I°lÓ,CÓD×KÐKÈÐØ$×*Ñ*Ó,´°E·I±I¸oÓ4N×4TÐ4TÐRTÓ0U×0[Ñ0[Ó0]Ñ]€OßÐ#4Ô#GÙß&ˆØ—
‘
˜3“ˆØ˜
Ö"Ø�#‹Jñ 'ñ r3   c               ó    € V ^8„  d   QhRRRR/# )r*   Úsrcrt   r.   r/   )r0   s   "r1   r2   r2   ²  s   € ÷ -ñ -˜Nð -¨~ñ -r3   c                óv  € RV P                  R4      RV P                  R4      RV P                  R4      ;'       g    RRV P                  R4      ;'       g    \        RV P                  R4      ;'       g    \        RV P                  R4      ;'       g    \        RV P                  R4      ;'       g#    V P                  R	4      R
8X  d   \        M\
        RV P                  R4      RV P                  R4      /	R	RRRRR\        3 Uu/ uF$  pV P                  V4      R9  g   K  WV,          bK&  	  upC# u upi )zLThe defaulted OAuth core (tokens + routing + expiry) shared across profiles.rð   r>  r8  ÚBearerrÕ   r9  r‹   r:  Úauth_methodÚ	anonymousrÿ   rÖ   Úaccount_tierÚ
anon_tokenÚuser_idÚorg_idÚconnectors_token)Nr5   )rŒ   r   r   r   r   r   r    )rH  r  s   & r1   Ú_nous_shared_shaperR  ²  s)  € ð 	˜Ÿ™ Ó/°À#Ç'Á'È/ÓBZØ�c—g‘g˜lÓ+×7Ð7¨xØ�—‘˜Ó!×7Ð7Ô%7Ø�S—W‘W˜[Ó)×CÐCÔ-CØ˜3Ÿ7™7Ð#4Ó5×PÐPÔ9Pà˜cŸg™gÐ&:Ó;÷ oð oØ(+¯©°Ó(>À+Ô(MÕ$ÔSmØ�s—w‘w˜}Ó-¨|¸S¿W¹WÀ\Ó=Rð-ð  -¨n¸lÈIÐW_ÐasÜ1ñ3ó ,ñ 3˜à�g‰g�a‹j 
Ñ*ô ˆ1�!�fŠ9ñ 3ñ ,ð-ð -ùò,s   ÄD6Ä%D6c               ó    € V ^8„  d   QhRRRR/# )r*   r¹   rt   r.   rO   r/   )r0   s   "r1   r2   r2   Ä  s   € ÷ ñ  Nð °tñ r3   c                ó   € ^ RI HpHp V P                  R4      pV! V P                  R4      4      pV'       g.   V! V4      '       d   V! V P                  R4      4      '       g   R# R^/\	        V 4      CR\
        P                  ! \        4      P                  4       /Cp \        4       ;_uu_ 4        \        4       p\        \        4       V 4       V! WeRR	7       RRR4       \        R
\        X4      \        V4      R7       \'        4        R#   + '       g   i     L<; i  \          d!   p\"        P%                  RT4        Rp?LERp?ii ; i)z¦Persist a minimal copy of the Nous OAuth state to the shared store.

Best-effort: failures are logged and swallowed; per-profile auth.json stays the source of truth.
)r  Ú_save_private_jsonr>  rN  rð   NÚ_schemaÚ
updated_atT)rS   Únous_shared_store_written)r(  Úrefresh_token_fpz*Failed to write shared Nous auth store: %s)r²   r  rU  rŒ   rR  r   rd   r   rl   r3  r+  r%   r=  rb   r,   rJ   r„   r]   r  r$   )r¹   r  rU  r>  Úis_guestr  r(  Úexcs   &       r1   Ú_write_shared_nous_stater\  Ä  s	  € ÷
 BØ—I‘I˜oÓ.€Mñ ˜UŸY™Y |Ó4Ó5€Hß™]¨=×9Ò9¹mÈEÏIÉIÐVdÓLe×>fÒ>fÙà�1ð5Ü*¨5Ó1ð5à”h—l’l¤3Ó'×1Ñ1Ó3ñ5€Fð	HÜ$×&Õ&Ü*Ó,ˆDÜÔ4Ó6¸Ô>Ù˜t°tÕ<÷ 'ô 	Ø'¬c°$«iÜ/°Ó>õ	@ô 
†G÷ '×&ûô ô HÜ�‰ÐAÀ3×GÑGûðHús0   Â D" Â2)DÃ(D" ÄD	ÄD" Ä"EÄ-EÅEc               ó   € V ^8„  d   QhRR/# )r*   r.   úOptional[dict[str, Any]]r/   )r0   s   "r1   r2   r2   á  s   € ÷ +ñ +Ð!9ñ +r3   c                 ó"  € ^ RI Hp   \        4       pTP	                  4       '       g   R#  \
        P                  ! TP                  RR7      4      p\        T\        4      '       g   R# T ! TP                  R4      4      ;'       g7    T ! TP                  R4      4      ;'       d    T ! TP                  R4      4      pT'       d   T# R#   \         d     R# i ; i  \        \        3 d"   p\        P                  RY4        Rp?R# Rp?ii ; i)	z Shared Nous OAuth state when present and well-formed, else None.

None (missing / unreadable / malformed / lacking tokens) means "fall through to device-code".
r  Nz	utf-8-sig)Úencodingz.Shared Nous auth store at %s is unreadable: %srN  rð   r>  )r²   r  r+  r'  Úis_filer_   ÚloadsÚ	read_textÚOSErrorÚ
ValueErrorr]   r  rC   r�   rŒ   )r  r(  ra   r[  Ú
has_tokenss        r1   r=  r=  á  sç   € õ
 .ðÜ&Ó(ˆð �<‰<�>Š>ÙðÜ—*’*˜TŸ^™^°[˜^ÓAÓBˆô �gœt×$Ò$ÙÙ˜wŸ{™{¨<Ó8Ó9÷ dð dÙ�g—k‘k .Ó1Ó2×bÐb±}ÀWÇ[Á[ÐQ`ÓEaÓ7bð ç ˆ7Ð* dÐ*øô ô Úðûô ”ZÐ ô Ü�‰ÐEÀtÔQÝûðús(   ˆ
C
 «&C Ã
CÃCÃDÃ-D	Ä	Dc               ó    € V ^8„  d   QhRRRR/# ©r*   r+   r,   r.   rO   r/   )r0   s   "r1   r2   r2   ù  s   € ÷ Hñ H Sð H¨Tñ Hr3   c                ó  €  \        4       ;_uu_ 4        \        4       P                  RR7       RRR4       \        RV R7       R#   + '       g   i     L; i  \         d"   p\
        P                  RT4        Rp?R# Rp?ii ; i)zBRemove the shared Nous OAuth store after a terminal token failure.T)Ú
missing_okNÚnous_shared_store_cleared©r+   z*Failed to clear shared Nous auth store: %s)r3  r+  Úunlinkrb   r„   r]   r  )r+   r[  s   & r1   Ú_clear_shared_nous_statern  ù  sc   € ðHÜ$×&Õ&Ü#Ó%×,Ñ,¸Ð,Ô=÷ 'äÐ0¸×@÷ '×&ûô ô HÜ�‰ÐAÀ3×GÒGûðHús-   ‚A ”A¯A ÁA	ÁA ÁBÁ$B Â Bc               ó(   € V ^8„  d   QhRRRRRRRR/# )r*   r¹   rt   r‚   r   r+   r,   r.   r/   )r0   s   "r1   r2   r2     s)   € ÷ #ñ # ð #¸	ð #È3ð #ÐSañ #r3   c                ó  € ^ RI Hp RVRVP                  RV P                  R4      RV P                  R4      R\	        V P                  R4      4      /p V! 4       p\        V4      VR&    \        P                  ! V4      pVP                  VP                  VP                  R	R
7       RpT P                  R4      p	\        T	\
        4      '       de   T	'       d]    \        P                   ! T	4      p
T
P#                  T
P$                  ;'       g    \&        R7      \        P(                  ! \&        4      8  pY„R&   T#   \         d	    RTR&    L¥i ; i  \         d   p\        T4      TR&    Rp?LÇRp?ii ; i  \*         d    Rp LQi ; i)aT  Redaction-safe forensic record for a quarantine: fingerprints, sizes and booleans only.

NEVER include a raw token/agent_key (credential-shaped literals get corrupted in logs). The
12-char SHA-256 prefix correlates to NAS's refreshTokenHash without leaking the secret;
provenance is client_id + agent_key_id (Nous state has no session_id).
©Ú_auth_file_pathr+   Ú
error_coder9  ro   rY  r>  Úauth_json_pathT)Úauth_json_sizeÚauth_json_mtimeÚauth_json_existsFrw  Úauth_json_stat_errorNrÖ   )ÚtzinfoÚtoken_already_expired)r²   rr  ÚcoderŒ   rJ   r,   rY   Ústatr\   Úst_sizeÚst_mtimeÚFileNotFoundErrorr„   ÚreprrC   r   ÚfromisoformatrÏ   ry  r   rd   re  )r¹   r‚   r+   rr  ÚforensicÚ	auth_pathÚstr[  Úalready_expiredÚexpires_at_rawrŸ   s   &&&        r1   Ú_quarantine_forensicsr‡    sa  € õ 0à�&˜,¨¯
©
°KÀÇÁÈ;ÓAWØ˜Ÿ	™	 .Ó1ØÔ.¨u¯y©y¸Ó/IÓJð L€Hð

5Ù#Ó%ˆ	Ü%(¨£^ˆÐ!Ñ"ð	1Ü—’˜Ó#ˆBØ�O‰OØ!Ÿz™z¸2¿;¹;ÐY]ð ô _ð '+€OØ—Y‘Y˜|Ó,€NÜ�.¤#×&Ò&¯>ð	#Ü×+Ò+¨NÓ;ˆFØ%Ÿ~™~°V·]±]×5IÐ5IÄc˜~ÓJÜ!)§¢¬cÓ!2ñ 3ˆOð )8Ð$Ñ%Ø€Oøô !ô 	1Ø+0ˆHÐ'Ó(ð	1ûäô 5Ü+/°«9ˆÐ'Ö(ûð5ûô ô 	#Ø"ŠOð	#úsN   ÁE Á*>D; Ã3E7 Ä'E7 Ä;EÅE ÅEÅE ÅE4ÅE/Å/E4Å7FÆFc               ó(   € V ^8„  d   QhRRRRRRRR/# )	r*   r¹   rt   r‚   r   r+   r,   r.   rO   r/   )r0   s   "r1   r2   r2   )  s*   € ÷ (ñ (¨ð (¸yð (ÐUXð (Ð]añ (r3   c          
     ó  € ^ RI HpHpHp \        P                  R\        P                  ! \        WV4      RRR7      4       . VO\        O F  pV P                  VR4       K  	  V! RWR7      V R	&   \        V4       V! 4        R# )
u(  Keep routing metadata but remove dead OAuth material so it is not replayed.

Only for terminal errors (``*_refresh_failed`` = HTTP 400/401/403 invalid_grant / revoked /
refresh_token_reused; ``*_auth_missing_refresh_token``), all ``relogin_required=True`` â€”
transient 429/5xx never quarantine.
)Ú_FLAT_OAUTH_TOKEN_KEYSÚ_last_auth_error_markerÚ!invalidate_nous_auth_status_cachez6Nous OAuth state quarantined (terminal auth death): %sTFrR   NrŠ   rl  Úlast_auth_error)r²   rŠ  r‹  rŒ  r]   r�   r_   r`   r‡  ru   Úpoprn  )r¹   r‚   r+   rŠ  r‹  rŒ  rE  s   &&$    r1   Ú_quarantine_nous_oauth_stater�  )  s�   € ÷\ñ \ô
 ‡N�NØ@Ü�
Š
Ô(¨°vÓ>È$Ð]bÔcôeð HÐ'ÐGÔ*FÓGˆØ�	‰	�#�tÖñ Há6°v¸uÔT€EÐ
ÑÜ˜VÔ$Ù%Ö'r3   c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r*   Ú
auth_storert   r‚   r   r+   r,   r.   r-   r/   )r0   s   "r1   r2   r2   ?  s,   € ÷ ñ ØðØ'0ðØ=@ðØEIñr3   c               óR  € \        V R4      pVf   R# \        R\         20pV Uu. uF3  p\        V\        4      '       d   VP	                  R4      V9   d   K1  VNK5  	  pp\        V4      \        V4      8g  pV'       d#   W`R,          R&   \        RW!P                  R7       V# u upi )zHRemove singleton-seeded Nous pool entries that contain dead OAuth state.rŠ   Fzmanual:ÚsourceÚcredential_poolÚ!nous_pool_device_code_quarantined)r+   rs  )r   r   rC   r�   rŒ   Úlenrb   r{  )r‘  r‚   r+   ÚentriesÚsingleton_sourcesÚeÚretainedÚremoveds   &&$     r1   Ú_quarantine_nous_pool_entriesrœ  ?  s§   € ô ˜J¨Ó/€GØ‚ÙÜ0°GÔ<SÐ;TÐ2UÐVÐáóbÙˆa¤:¨a´×#6Ò#6¸1¿5¹5À»?ÐN_Ñ;_�ˆ‘7ð ð bä�(‹mœs 7›|Ñ+€GßØ08Ð$Õ% fÑ-ÜÐ8À×T^ÑT^Õ_Ø€Nùòbs   ¦.B$ÁB$r-  ç      .@c               ó    € V ^8„  d   QhRRRR/# ©r*   r-  râ   r.   r^  r/   )r0   s   "r1   r2   r2   O  s   € ÷ ñ °eð ÐG_ñ r3   c                óX  a	€ ^ RI HpHo	HpHp  \        \        V 4      R7      ;_uu_ 4        V! 4       pV'       g    RRR4       R# / \        V4      CRRRRRRRR	R//CpV! WPR
V	3R lR7      pS	! V4       RRR4       V#   + '       g   i     X# ; i  \         dŠ   p\        T\        4      p\        RR\        T4      P                  /T'       d   R\        TRR4      /M/ B  T'       d   T! T4      '       d   \        R4       \         P#                  RT4        Rp?R# Rp?ii ; i)zéRehydrate Nous OAuth state from the shared store via a forced refresh.

Returns auth_state ready for ``persist_nous_credentials()``; None on any failure (expired
token, portal unreachable) so the caller falls through to device-code.
)r=  r\  Úrefresh_nous_oauth_from_stateÚ_is_terminal_nous_refresh_errorr6  Nrn   rp   ÚtlsÚinsecureFÚ	ca_bundleTc                ó   <€ S! V 4      # rÄ   r/   )ÚupdatedÚ_reasonr\  s   &&€r1   Ú<lambda>Ú/_try_import_shared_nous_state.<locals>.<lambda>c  s   ø€ Ñ9QÐRYÔ9Zr3   ©r-  Úforce_refreshÚon_state_updateÚ
error_typers  r{  Ú&shared_import_terminal_refresh_failurezShared Nous import failed: %s)Únous_shared_import_failed)r²   r=  r\  r¡  r¢  r3  r7  rR  r„   rC   r   rb   ÚtypeÚ__name__Úgetattrrn  r]   r  )
r-  r=  r¡  r¢  r  r¹   Ú	refreshedr[  Úis_authr\  s
   $        @r1   Ú_try_import_shared_nous_stater¶  O  s*  ø€ ÷)ó )ðÜ$Ô5IÈ/Ó5Z×[Ö[Ù,Ó.ˆFßØ÷ \Ñ[ð
%?Ü$ VÓ,ð%?Ø.9¸4ÐAWÐY]Ø˜
 E¨;¸Ð=ñ%?ˆEñ 6ØÀdÜ Zô\ˆIñ % YÔ/÷ \ð* Ð÷+ \Ö[ð* Ðûô ô Ü˜S¤)Ó,ˆÜñ 	OÜ48¸³I×4FÑ4Fð	Oç=D�œg c¨6°4Ó8Ñ9È"ò	O÷ Ñ6°s×;Ò;Ü$Ð%MÔNÜ�‰Ð4°cÔ:ÝûðúsL   �B ¬B½B Á0BÁ7B ÂB	ÂB ÂB ÂD)Â AD$Ã/D$Ã=!D$Ä$D)c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r*   Úclientúhttpx.Clientr‹   r,   r9  r>  r.   rt   r/   )r0   s   "r1   r2   r2   q  s4   € ÷ <8ñ <8Øð<8Ø.1ð<8Ø>Að<8ØRUð<8àñ<8r3   c           	     ó˜  € V P                  V R 2RV/RRRV/R7      pVP                  ^È8X  d(   VP                  4       pRV9  d   \        RRR	R
7      hV# RVP                  u;8:  d   R8:  d!   M M\	        RVP                   R2RRR	R7      hVP                  R"9   d   VP
                  P                  R4      MRpV'       d8   ^ RIHp \	        RVP                   RV R2RRR	V! VP
                  4      R7      h^ RI	H
p  VP                  4       p	\        V	\        4      '       g   / p	V	P                  R4      p
V
f   VP                  R#9   d   Rp
V
f   RM
\        V
4      p\        V	P                  R4      ;'       g    R4      pW¸9   pVR8X  g   R VP                  4       9   d   R!pR	p\        WËVR
7      h  \         d    / p	 Lµi ; i)$z/api/oauth/tokenzx-nous-refresh-tokenÚ
grant_typer>  r9  )ÚheadersÚdatarð   z%Refresh response missing access_tokenÚinvalid_tokenTr8   iô  iW  z-Nous Portal is temporarily unavailable (HTTP z).rŠ   Útemporarily_unavailable)Úproviderr{  Ú	retryablezx-vercel-mitigatedN)Úparse_retry_after_secondsz?Nous Portal's edge firewall challenged the token refresh (HTTP z, x-vercel-mitigated=z'). Credentials kept; try again shortly.Úupstream_blocked)rÀ  r{  rÁ  Úretry_after)Ú_OAUTH_GRANT_DEAD_CODESr‚   Úinvalid_grantÚerror_descriptionzRefresh token exchange failedÚrefresh_token_reusedr  uá  Nous Portal detected refresh-token reuse and revoked this session.
This usually means an external process (monitoring script, custom self-heal hook, or another Hermes install sharing ~/.hermes/auth.json) called POST /api/oauth/token with Hermes's refresh token without persisting the rotated token back.
Nous refresh tokens are single-use â€” only Hermes may call the refresh endpoint. For health checks, use `hermes auth status` instead.
Re-authenticate with: hermes auth add nous>   é“  é­  >   é‘  rÉ  )ÚpostÚstatus_coder_   r!   r   r¼  rŒ   Úagent.retry_utilsrÂ  r²   rÅ  r„   rC   r�   r,   r[   )r¸  r‹   r9  r>  Úresponsera   Ú	mitigatedrÂ  rÅ  Úerror_payloadÚraw_coder{  Údescriptionr9   s   $$$$          r1   Ú_refresh_access_tokenrÔ  q  s   € ð �{‰{ØÐ
Ð+Ð,Ø'¨Ð7Ø˜O¨[¸)ÐDð ó F€Hð ×Ñ˜sÔ"Ø—-‘-“/ˆØ Ô(ÜÐCÀ_Ð^bÔcÐcØˆØ
ˆh×"Ñ"Ö) c×)ÜØ;¸H×<PÑ<PÐ;QÐQSÐTØÐ";ÀtôMð 	Mð ?G×>RÑ>RÐV`Ô>`�× Ñ ×$Ñ$Ð%9Ô:Ðfj€IßÝ?ÜØMÈh×NbÑNbÐMcð d"Ø"+ Ð,SðUàÐ"4ÀÙ1°(×2BÑ2BÓCô	Eð 	Eõ
 8ðØ Ÿ™›ˆô �m¤T×*Ò*Øˆð
 × Ñ  Ó)€HØÒ˜H×0Ñ0°JÔ>Ø"ˆØÒ#‰4¬¨X«€DÜ�m×'Ñ'Ð(;Ó<×_Ð_Ð@_Ó`€KØÑ-€Gð Ð%Ô%¨°K×4EÑ4EÓ4GÔ)Gð9ð 	ð ˆÜ
�K¨wÔ
7Ð7øô; ô ØŠðús   ÄF9 Æ9G	ÇG	c               ó<   € V ^8„  d   QhRRRRRRRRRRR	RR
RRRRR/	# )r*   r¸  r¹  r‘  rt   r¹   r‹   r,   r9  r>  r+   ÚpersistzCallable[[], None]r.   r/   )r0   s   "r1   r2   r2   °  sX   € ÷ ñ ØðØ)7ðØ@Nðàðà%(ðà9<ðàFIðð  ðð %3ñr3   c                ó°   € ^ RI HpHp	  V! WVVR7      #   \         d6   p
T	! T
4      '       d"   \	        Y*TR7       \        YTR7       T! 4        h Rp
?
ii ; i)zYRedeem the refresh token; on terminal failure quarantine state + pool, persist, re-raise.)rÔ  r¢  ©r¸  r‹   r9  r>  rl  N)r²   rÔ  r¢  r   r�  rœ  )r¸  r‘  r¹   r‹   r9  r>  r+   rÖ  rÔ  r¢  r[  s   $$$$$$$$   r1   Ú_refresh_nous_or_quarantinerÙ  °  s[   € ÷
 Wð	Ù$ØÀiØ'ô)ð 	)øô ô Ù*¨3×/Ò/Ü(¨¸FÕCÜ)¨*À&ÕIÙŒIØûðús   Š
 •A 0AÁAc          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r*   r¹   rt   r´  r>  r,   r:  r?   r.   rO   r/   )r0   s   "r1   r2   r2   Â  s4   € ÷ 6ñ 6Øð6Ø&4ð6ØEHð6à%ð6à15ñ6r3   c               óê  € ^ RI Hp \        P                  ! \        4      pV! VP                  R4      4      pVR,          V R&   VP                  R4      ;'       g    TV R&   VP                  R4      ;'       g    V P                  R4      ;'       g    RV R&   VP                  R4      ;'       g    V P                  R4      V R&   Ve   W0R	&   VP                  4       V R
&   W`R&   \        WV4      V R&   R# )a
  Write a successful Nous token-refresh payload into *state* (tokens + expiry fields).

*inference_base_url*, when given, is the healed network-provenance URL to persist alongside
the rotated tokens (key order in auth.json is preserved from the original login shape).
)r÷   r  rð   r>  r8  rJ  rÕ   Nr:  rÿ   rÖ   )r²   r÷   r   rd   r   rŒ   rl   rm   )r¹   r´  r>  r:  r÷   rd   Ú
access_ttls   &&&$   r1   Ú_apply_nous_refreshed_tokensrÝ  Â  sØ   € õ 4Ü
�,Š,”sÓ
€CÙ$ Y§]¡]°<Ó%@ÓA€JØ% nÕ5€Eˆ.ÑØ&Ÿ]™]¨?Ó;×LÐL¸}€Eˆ/ÑØ#Ÿ-™-¨Ó5×\Ð\¸¿¹À<Ó9P×\Ð\ÐT\€Eˆ,ÑØ—]‘] 7Ó+×AÐA¨u¯y©y¸Ó/A€Eˆ'�NØÒ%Ø&8Ð"Ñ#ØŸ=™=›?€Eˆ-ÑØ$ˆ,ÑÜ$ SÓ5€Eˆ,Ór3   c               ó    € V ^8„  d   QhRRRR/# )r*   r´  rt   r.   r,   r/   )r0   s   "r1   r2   r2   Ø  s   € ÷ -ñ -¨.ð -¸Sñ -r3   c                óV   € \        V P                  R4      4      pT;'       g    \        # )uk  Validated network-provenance inference URL from a refresh payload, healed to the default.

A Portal URL rejected by the allowlist resets to the production default instead of leaving a
previously-persisted bad host (e.g. a stale staging URL) in place â€” otherwise a poisoned
auth.json re-validates to None on every refresh and silently re-uses the dead endpoint.
r:  )r    rŒ   r   )r´  r™   s   & r1   Ú_healed_nous_inference_urlrà  Ø  s'   € ô 4°I·M±MÐBVÓ4WÓ
X€CØ×,Ð,Ô,Ð,r3   c               ó$   € V ^8„  d   QhRRRRRR/# )r*   r-  râ   Úverifyr
   r.   r¹  r/   )r0   s   "r1   r2   r2   ã  s!   € ÷ ñ  uð °cð ¸lñ r3   c                ó`   € \         P                  ! \         P                  ! V 4      R R/VR7      # )ÚAcceptzapplication/json)Útimeoutr¼  râ  )r"   ÚClientÚTimeout)r-  râ  s   &&r1   Ú_nous_http_clientrè  ã  s*   € Ü�<Š<Ü—’˜oÓ.¸ÐCUÐ8VØôð r3   c               ó    € V ^8„  d   QhRRRR/# )r*   Úmidr,   r.   rÒ   r/   )r0   s   "r1   r2   r2   é  s   € ÷ ñ ˜ð  ñ r3   c                óp   € V P                  4       pRV9   d   ^ MRV9   d
   RV9  d   ^M
RV9   d   ^M^pW 3# )zUSort key: opus > pro > haiku/flash > sonnet (sonnet is cheap/fast; best model first).ÚopusÚproÚsonnet)r[   )rê  ÚlowÚranks   &  r1   Ú_model_priorityrñ  é  s=   € à
�)‰)‹+€CØ˜3”‰A¨°#¬¸(È#Ô:M¡AØ #”o‘¨1ð 	àˆ;Ðr3   râ  Tc          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r*   r:  r,   Úapi_keyr-  râ   râ  z
bool | strr.   z	list[str]r/   )r0   s   "r1   r2   r2   ñ  s4   € ÷ *ñ *Øð*Ø),ð*Ø?Dð*àð*à"+ñ*r3   c                óÞ  € ^ RI Hp \        W#4      ;_uu_ 4       pVP                  V P	                  R4       R2RRV 2/R7      pRRR4       XP
                  ^È8w  dj   RVP
                   2p VP                  4       p\        VP                  R	4      ;'       g    VP                  R
4      ;'       g    T4      p\        VR4      hVP                  4       P                  R4      p
\        V
\        4      '       g   . # . pV
 Fr  p\        V\        4      '       d   VP                  R4      MRpV! V4      '       g   K<  RVP                  4       9  g   KS  VP!                  VP#                  4       4       Kt  	  VP%                  \&        R7       \        \        P)                  V4      4      #   + '       g   i     ELp; i  \         d"   p	\        P                  RT	4        Rp	?	EL,Rp	?	ii ; i)z6Fetch available model IDs from the Nous inference API.r  rœ   z/modelsÚAuthorizationzBearer )r¼  Nz#/models request failed with status rÇ  r‚   z'Could not parse error response JSON: %sÚmodels_fetch_failedr½  ÚidÚhermes©rE  )r²   r  rè  rŒ   rž   rÍ  r_   r,   r„   r]   r  r!   rC   rÑ   r�   r[   ÚappendrD   Úsortrñ  Úfromkeys)r:  ró  r-  râ  r  r¸  rÏ  rÓ  Úerrr™  r½  Ú	model_idsrÍ   Úmodel_ids   $$$$          r1   Úfetch_nous_modelsr   ñ  s˜  € õ .Ü	˜?×	3Ô	3°vØ—:‘:Ø!×(Ñ(¨Ó-Ð.¨gÐ6Ø$¨°¨yÐ&9Ð:ð ó <ˆ÷ 
4ð ×Ñ˜sÔ"Ø;¸H×<PÑ<PÐ;QÐRˆð	GØ—-‘-“/ˆCÜ˜cŸg™gÐ&9Ó:×]Ð]¸c¿g¹gÀgÓ>N×]Ð]ÐR]Ó^ˆKô ˜Ð%:Ó;Ð;Ø�=‰=‹?×Ñ˜vÓ&€DÜ�dœD×!Ò!Øˆ	Ø€IÛˆÜ%/°´d×%;Ò%;�4—8‘8˜D”>Àˆá˜×"Ô" x°x·~±~Ó7GÖ'GØ×Ñ˜XŸ^™^Ó-Ö.ñ	 ð
 ‡N�N”€NÔ'Ü”—‘˜iÓ(Ó)Ð)÷- 
4×	3Ð	3ûô ô 	GÜ�L‰LÐBÀA×FÒFûð	Gús/   š+F,Á.,G  ÂG  Â4G  Æ,F=	Ç G,ÇG'Ç'G,c               ó$   € V ^8„  d   QhRRRRRR/# )r*   r¹   rt   r×   rf   r.   r-   r/   )r0   s   "r1   r2   r2     s!   € ÷ 6ñ 6 ð 6Àð 6Èñ 6r3   c                óÎ   € ^ RI Hp V P                  R4      pV! V4      ;'       d@    \        W0P                  R4      V P                  R4      \	        ^ \        V4      4      R7      # )ré   r  rn   rÕ   rp   rë   )r²   r  rŒ   rì   rá   rf   )r¹   r×   r  rE  s   &&  r1   Ú_agent_key_is_usabler    sY   € Ý-Ø
�)‰)�KÓ
 €CÙ˜Ó÷ 6ð 6Ô"<Ø—9‘9˜WÓ%°%·)±)Ð<RÓ2SÜ˜Aœs ?Ó3Ó4ô#6ð 6r3   rJ  r¤  r¥  r¬  r­  c          "     ó\   € V ^8„  d   QhRRRRRRRRRRRRRRR	R
RR
RR
RR
RRRRRR
RRRRRR/# )r*   rð   r,   r>  r9  r‹   r:  r8  rÕ   rÿ   r?   rÖ   rn   rp   r-  râ   r¤  úOptional[bool]r¥  r¬  r-   r­  ú/Optional[Callable[[dict[str, Any], str], None]]r.   rt   r/   )r0   s   "r1   r2   r2     s¯   € ÷ )ñ )Øð)Ø&)ð)Ø69ð)ØLOð)àð)à,/ð)àCFð)ð ð)ð 4Að)ð ð	)ð <Ið	)ð
 ð)ð
 .<ð)ð
 P]ð)ð ð)ð Eð)ð Q_ñ)r3   c               óV   € \        RV RVRVRVRVRVRVRVR	VR
V	RV
RRVRV//W¾VR7      # )zéRefresh Nous OAuth state without mutating auth.json directly.

``on_state_update`` fires after a successful access-token refresh so callers owning persistent
state can save the rotated refresh token before later validation can fail.
rð   r>  r9  r‹   r:  r8  rÕ   rÿ   rÖ   rn   rp   r£  r¤  r¥  r«  )r¡  )rð   r>  r9  r‹   r:  r8  rÕ   rÿ   rÖ   rn   rp   r-  r¤  r¥  r¬  r­  s   &&&&&$$$$$$$$$$$r1   Úrefresh_nous_oauth_purer    sb   € ô )à˜L¨/¸=È+ÐW`Ø˜Ð0DÐFXØ˜* g¨u°mÀ[Ø˜* k°9Ø"Ð$8Ø�J ¨+°yÐAð	Cð (Ø'ô	)ð 	)r3   c          
     ó,   € V ^8„  d   QhRRRRRRRRR	R/# )
r*   rH  rt   r-  râ   r¬  r-   r­  r  r.   r/   )r0   s   "r1   r2   r2   0  s4   € ÷ *ñ *Ø	ð*Ø-2ð*ØJNð*àDð*àP^ñ*r3   c               ó  € ^ RI HpHpHpHp V P                  R4      ;'       g    / pVP                  R4      VP                  R4      r©RV P                  RR4      RV P                  RR4      RV P                  R4      ;'       g    \        R	V P                  R	4      ;'       g    \        P                  R
4      RV P                  R4      ;'       g    \        P                  R
4      RV P                  R4      ;'       g    RRV P                  R4      ;'       g    \        RV P                  R4      RV P                  R4      RV P                  R4      RV P                  R4      RR\        V	4      RV
//pV! WšVR7      p\        T;'       g    RV4      ;_uu_ 4       p\        W»P                  R4      4      pV'       g   Ve–   VP                  R4      p\        V\        4      '       d	   V'       g    Ve   \!        VRR7      h\#        RRRR7      hV! WÛR	,          VR,          VR7      p\%        VVV\'        V4      R7       Ve   V! \)        V4      R4       V! V4       V! V4       RRR4       V#   + '       g   i     T# ; i)zURefresh Nous OAuth from a state dict (defaults filled in) without mutating auth.json.)ró   rÔ  Ú_resolve_verifyr  r£  r¤  r¥  rð   r5   r>  r9  r‹   rœ   r:  r8  rJ  rÕ   rÿ   rÖ   rn   rp   ©r¤  r¥  Ú
auth_stater�  NT©r(   z.No refresh token is available for Nous Portal.r7   r8   rØ  ©r:  Úpost_refresh_access_token)r²   ró   rÔ  r  r  rŒ   r   r   rž   r   r   r-   rè  rï   rC   r,   r<   r!   rÝ  rà  r�   )rH  r-  r¬  r­  ró   rÔ  r  r  r£  r¤  r¥  r¹   râ  r¸  Úcurrent_invoke_jwt_statusÚrefresh_token_valuer´  s   &$$$             r1   r¡  r¡  0  sJ  € ÷!ó !ð �'‰'�%‹.×
Ð
˜B€CØŸ'™' *Ó-¨s¯w©w°{Ó/Cˆià˜Ÿ™ °Ó3°_ÀcÇgÁgÈoÐ_aÓFbØ�S—W‘W˜[Ó)×CÐCÔ-CØ˜CŸG™GÐ$5Ó6×QÐQÔ:Q×YÑYÐZ]Ó^ØØ�G‰GÐ(Ó)×GÐGÔ-GÏÉÐPSËØ�c—g‘g˜lÓ+×7Ð7¨xØ�—‘˜Ó!×7Ð7Ô%7Ø�s—w‘w˜}Ó-¨|¸S¿W¹WÀ\Ó=RØ�S—W‘W˜[Ó)Ð+AÀ3Ç7Á7ÐKaÓCbØ�
œD ›N¨K¸ÐCð
E€Eñ  hÐPUÔV€FÜ	˜?×2Ð2¨d°F×	;Ô	;¸vÜ$<¸UÇIÁIÈnÓD]Ó$^Ð!ßÐ5ÒAØ"'§)¡)¨OÓ"<ÐÜÐ1´3×7Ò7×?RØ,Ò8Ü4Ø1ÀDôJð JäØDÐFgØ ô"ð "ñ .ØÐ5FÕ/GØ Õ,Ð<OôQˆIô )Ø�yÐ"5Ü#=¸iÓ#HõJð Ò*Ù¤ U£Ð-HÔIÙ)¨%Ô0Ù Ô&÷) 
<ð* €L÷+ 
<Ö	;ð* €Lús   ÆAI5Ç5A6I5É5J	Úlabelc               ó    € V ^8„  d   QhRRRR/# )r*   Úcredsrt   r  r?   r/   )r0   s   "r1   r2   r2   ]  s   € ÷ Zñ Z Nð Z¸mñ Zr3   c               ó.  € ^ RI HpHp ^ RIHp \        V 4      pV'       d<   \        V4      P                  4       '       d   \        V4      P                  4       VR&   V! RV4       V! V4       V! R4      p\        R VP                  4        4       R4      # )a²  Persist Nous OAuth credentials as the singleton provider state.

Nous credentials are read from ``providers.nous`` (401 recovery, pool seeding) AND
``credential_pool.nous`` (runtime ``pool.select()``); a pool-only write broke expiry recovery.
So: write the singleton, mirror to the shared store, then ``load_pool("nous")`` upserts the
canonical ``device_code`` entry in place. ``label`` rides in the singleton so re-seeding keeps
it.
)Ú_save_active_provider_stater\  ©Ú	load_poolr  rŠ   c              3  óR   "  € T F  qP                   \        8X  g   K  Vx € K  	  R # 5irÄ   )r“  r   )rÅ   r™  s   & r1   rÇ   Ú+persist_nous_credentials.<locals>.<genexpr>n  s   é € ÐR™N�q¯h©hÔ:QÑ.Q—’›Nùs   ‚'�
'N)
r²   r  r\  Úagent.credential_poolr  r�   r,   rD   Únextr—  )r  r  r  r\  r  r¹   Úpools   &$     r1   Úpersist_nous_credentialsr  ]  su   € ÷ VÝ/Ü�‹K€Eß”�U“×!Ñ!×#Ò#Ü˜U›×)Ñ)Ó+ˆˆg‰Ù ¨Ô.Ù˜UÔ#Ù�VÓ€DÜÑR˜DŸL™LœNÓRÐTXÓYÐYr3   c               ó   € V ^8„  d   QhRR/# ©r*   r.   rO   r/   )r0   s   "r1   r2   r2   q  s   € ÷ Uñ U¨ñ Ur3   c                 ó‚   €  ^ RI Hp  V ! R4       R#   \         d"   p\        P	                  RT4        Rp?R# Rp?ii ; i)zGBest-effort pool reseed after providers.nous changes; never fail login.r  rŠ   z7Failed to sync Nous credential pool from auth store: %sN)r  r  r„   r]   r  )r  r[  s     r1   Ú_sync_nous_pool_from_auth_storer#  q  s8   € ðUÝ3Ù�&ÖøÜô UÜ�‰ÐNÐPS×TÒTûðUús   ‚ ’>�9¹>c               ó    € V ^8„  d   QhRRRR/# )r*   r¹   rt   r.   ztuple[str, str, str, str]r/   )r0   s   "r1   r2   r2   z  s   € ÷ "?ñ "? >ð "?Ð6Oñ "?r3   c                ó²  € ^ RI HpHp V! V P                  R4      4      ;'       g    \        P                  R4      p\        4       pV'       d   VP                  R4      pMs\        V4      pVP                  VP                  rvVR8H  ;'       g    VR8H  ;'       d    VR
9   pV'       d   Wa9  g	   V'       g   \        P                  RW64       \        p^ RIHp	 \        V! V P                  R4      4      4      ;'       g    V	! V 4      '       d   \        M\         p
Y:\#        4       ;'       g    T
\%        V P                  R	4      ;'       g    \&        4      3# )a  ``(portal_url, stored_inference_url, effective_inference_url, client_id)`` from *state*.

The stored inference URL is re-validated network-provenance (persisted); the effective one
layers the runtime-only ``NOUS_INFERENCE_BASE_URL`` override on top and is never persisted.
r»   r‹   rœ   r›   ÚhttpzXauth: ignoring invalid portal_base_url %r (host %r or scheme not allowed), using default©Úis_guest_stater:  r9  >   Ú	localhostú	127.0.0.1)r²   r¼   r¯   rŒ   r   rž   r·   r   rŽ   r�   r]   r�   Úhermes_cli.anon_authr(  r    r   r   r•   r,   r   )r¹   r¼   r¯   Ú
portal_urlr½   Úparsed_portal_urlÚportal_hostr�   Útrusted_schemer(  Ústored_inference_urls   &          r1   Ú_nous_effective_routingr1  z  s>  € ÷ OÙ$ U§Y¡YÐ/@Ó%AÓB×]Ð]ÔF]×eÑeÐfiÓj€Jô 4Ó5ÐßØ(×/Ñ/°Ó4‰
ä$ ZÓ0ÐØ/×8Ñ8Ð:K×:RÑ:R�VØ 7Ñ*÷ Lð LØ�fÑ×JÐJ Ð0JÑ!Jð 	ç˜kÔK×SaÜ�N‰NðAàô)ô 1ˆJõ 4ä1Ù˜uŸy™yÐ)=Ó>Ó?ó	A÷ 	_ð 	_á(6°u×(=Ò(=Õ$ÔC]ð ð
 	Ô*FÓ*H×*`Ð*`ÐL`ÜˆE�I‰I�kÓ"×<Ð<Ô&<Ó=ð?ð ?r3   c                  óŒ   € ] tR tRtRtR R ltR R ltR R ltR	 tR
 R lt	R R lt
R R ltR R ltR R ltR R ltRtR# )Ú_NousRuntimeResolveiŸ  aP  Working set for one ``resolve_nous_runtime_credentials`` call.

Holds the token pair + routing tuple that shared-store merges / refreshes replace mid-flight.
``persist`` skips writes where only derived TTL countdowns changed (keeps the mtime-keyed
auth-status cache warm) and mirrors every real write to the shared store (best-effort).
c               ó4   € V ^8„  d   QhRRRRRRRRRR	R
RRR/# )r*   r‘  rt   r¹   Ústate_source_pathzOptional[Path]r¬  r-   Ústale_access_tokenr?   r-  râ   r.   rO   r/   )r0   s   "r1   r2   Ú _NousRuntimeResolve.__annotate__§  sD   € ÷ ñ Ø(ðØ1?ðØTbðàðà4AðàTYðà^bñr3   c               	óT  € WVuV n         V n        V n        WEuV n        V n        W`n        \        P                  ! 4       P                  R ,          V n	        \        V4      V n        RV n        VP                  R4      V n        VP                  R4      V n        V P!                  4        R# )rA   Frð   r>  N)r‘  r¹   Ú_source_pathr¬  r6  r-  ÚuuidÚuuid4ÚhexrK   r�   Ú_persisted_stateÚpersisted_anyrŒ   rð   r>  Ú_reload_routing)Úselfr‘  r¹   r5  r¬  r6  r-  s   &&&&$$$r1   Ú__init__Ú_NousRuntimeResolve.__init__§  sŒ   € ð :DÐL]Ð6ˆŒ˜œ TÔ%6Ø6CÐ3ˆÔ˜DÔ3Ø.ÔÜŸ:š:›<×+Ñ+¨CÕ0ˆÔÜ $ U£ˆÔØ"ˆÔØ!ŸI™I nÓ5ˆÔØ"ŸY™Y Ó7ˆÔØ×ÑÖr3   c               ó   € V ^8„  d   QhRR/# r!  r/   )r0   s   "r1   r2   r7  ´  s   € ÷ ?ñ ? ñ ?r3   c                	ób   € \        V P                  4      w  V n        V n        V n        V n        R # rÄ   )r1  r¹   r‹   Ústored_inference_base_urlr:  r9  ©r@  s   &r1   r?  Ú#_NousRuntimeResolve._reload_routing´  s'   € ä2°4·:±:Ó>ñ	ˆÔ	˜tÔ=¸tÔ?VØ	Žr3   c               ó    € V ^8„  d   QhRRRR/# rh  r/   )r0   s   "r1   r2   r7  ¸  s   € ÷ (ñ (˜cð ( dñ (r3   c                	ó<  € ^ RI HpHp V P                  p\	        V P
                  4      p\	        V4      V8X  d   \        RV P                  VR7       R#  V! V P                  RW@P                  4       \        RT P                  T\        TP                  R	4      4      \        TP                  R
4      4      R7       \        T4      T n        RT n        T! T4       R#   \         d3   p\        RT P                  T\        T4      P                  R7       h Rp?ii ; i)ré   )Ú_save_provider_state_to_sourcer\  Únous_state_persist_skipped)rK   r+   NrŠ   Únous_state_persist_failed)rK   r+   r®  Únous_state_persistedr>  rð   )rK   r+   rY  r  T)r²   rJ  r\  r¹   r  r=  rb   rK   r‘  r9  r„   r±  r²  rJ   rŒ   r�   r>  )r@  r+   rJ  r\  r¹   Ú	persistedr[  s   &&     r1   rÖ  Ú_NousRuntimeResolve.persist¸  sï   € ß\Ø—
‘
ˆÜ2°4×3HÑ3HÓIˆ	Ü)¨%Ó0°IÔ=ÜÐ5À4×CSÑCSÐ\bÕcÙð	Ù*¨4¯?©?¸FÀE×K\ÑK\Ô]ô 	Ø"°×0@Ñ0@ÈÜ/°·	±	¸/Ó0JÓKÜ.¨u¯y©y¸Ó/HÓIõ	Kô !% U£ˆÔØ!ˆÔÙ  Ö'øô ô 	ÜØ+¸×9IÑ9IÐRXÜ ›9×-Ñ-õ/ð ûð		ús   ÁC ÃDÃ)-DÄDc                	ó@   € \        \        V P                  4      R 7      # )r6  )r3  r7  r-  rF  s   &r1   Úshared_lockÚ_NousRuntimeResolve.shared_lockÎ  s   € Ü&Ô7KÈD×L`ÑL`Ó7aÔbÐbr3   c               ó   € V ^8„  d   QhRR/# ©r*   r.   r-   r/   )r0   s   "r1   r2   r7  Ñ  s   € ÷ Nñ N $ñ Nr3   c                	óp   € \        V P                  \        4      ;'       d    \        V P                  4      # rÄ   )rC   rð   r,   r-   rF  s   &r1   Úhas_access_tokenÚ$_NousRuntimeResolve.has_access_tokenÑ  s(   € Ü˜$×+Ñ+¬SÓ1×MÐM´d¸4×;LÑ;LÓ6MÐMr3   c               ó   € V ^8„  d   QhRR/# r¬   r/   )r0   s   "r1   r2   r7  Ô  s   € ÷ Gñ G =ñ Gr3   c                	óB   € \        V P                  V P                  4      # rÄ   )rï   r¹   rð   rF  s   &r1   Úinvoke_jwt_statusÚ%_NousRuntimeResolve.invoke_jwt_statusÔ  s   € Ü'¨¯
©
°D×4EÑ4EÓFÐFr3   c               ó   € V ^8„  d   QhRR/# rT  r/   )r0   s   "r1   r2   r7  ×  s   € ÷ ñ ˜dñ r3   c                óà   € \        V P                  4      '       g   R# V P                  P                  R4      V n        V P                  P                  R4      V n        V P                  4        R# )zSAdopt fresher shared-store tokens (caller holds the shared lock). True when merged.Frð   r>  T)rF  r¹   rŒ   rð   r>  r?  rF  s   &r1   Úmerge_sharedÚ _NousRuntimeResolve.merge_shared×  sM   € ä-¨d¯j©j×9Ò9ÙØ ŸJ™JŸN™N¨>Ó:ˆÔØ!ŸZ™ZŸ^™^¨OÓ<ˆÔØ×ÑÔÙr3   c               ó   € V ^8„  d   QhRR/# r!  r/   )r0   s   "r1   r2   r7  à  s   € ÷ 'ñ '¨dñ 'r3   c                óN  € V P                   pV P                  '       d‡   V P                  '       ds   \        V\        4      '       d[   V'       dQ   WP                  8w  d?   V P                  4       f+   \        RV P                  \        V4      R7       RV n        R# R# R# R# R# R# R# )uÛ   Skip the refresh when a peer already rotated the grant.

Under the store lock: if the bearer that failed upstream is no longer the one on disk and
the on-disk one is usable, adopt it â€” never re-POST the shared grant.
NÚrefresh_skipped_peer_rotatedr  F)	rð   r¬  r6  rC   r,   rZ  rb   rK   rJ   )r@  r>   s   & r1   Úskip_refresh_if_peer_rotatedÚ0_NousRuntimeResolve.skip_refresh_if_peer_rotatedà  sŽ   € ð ×!Ñ!ˆØ××Ð 4×#:×#:Ð#:¼zÈ%ÔQT×?UÒ?U×Z_Ø×4Ñ4Ô4¸×9OÑ9OÓ9QÒ9YÜØ.¸D×<LÑ<LÜ 2°5Ó 9õ;ð "'ˆDÖñ	 :ZÑ4ñ [`Ñ?UÑ#:Ñr3   c               ó$   € V ^8„  d   QhRRRRRR/# )r*   r¸  r¹  rZ  r?   r.   rO   r/   )r0   s   "r1   r2   r7  î  s"   € ÷ 2ñ 2˜lð 2¸}ð 2ÐQUñ 2r3   c                óŠ  a € \        S P                  \        4      '       d   S P                  '       g   \        T;'       g    RRR7      hS P                  '       d   RMT;'       g    Rp\        RS P                  V\        S P                  4      R7       \        VS P                  S P                  S P                  S P                  S P                  RV 3R lR	7      pS P                  p\        V4      S n        \        4       ;'       g    S P                  S n        \#        S P                  VS P                  S P                  R
7       S P                  R,          S n        S P                  R,          S n        \        RS P                  V\        V4      \        S P                  4      R7       S P'                  R4       R# )zURedeem the refresh token, apply + persist the rotated pair (caller holds both locks).r¬  Tr  Úaccess_unusableÚrefresh_start)rK   r+   rY  Úruntime_access_refresh_failurec                 ó&   <€ S P                  R 4      # )Ú'terminal_runtime_access_refresh_failure)rÖ  rF  s   €r1   r©  Ú-_NousRuntimeResolve.refresh.<locals>.<lambda>ü  s   ø€ ˜DŸL™LÐ)RÔSr3   )r¸  r‘  r¹   r‹   r9  r>  r+   rÖ  r  rð   r>  Úrefresh_success)rK   r+   Úprevious_refresh_token_fpÚnew_refresh_token_fpr  N)rC   r>  r,   r<   r¬  rb   rK   rJ   rÙ  r‘  r¹   r‹   r9  rà  rE  r•   r:  rÝ  rð   rÖ  )r@  r¸  rZ  Úrefresh_reasonr´  Úprevious_refresh_tokens   f&&   r1   ÚrefreshÚ_NousRuntimeResolve.refreshî  su  ø€ ä˜$×,Ñ,¬c×2Ò2¸$×:L×:LÐ:LÜ,Ø!×4Ð4 _ÀtôMð Mð  $×1×1Ð1‰OÐ8I×8^Ð8^ÐM^ð 	äØ¨×)9Ñ)9À.Ü/°×0BÑ0BÓCõ	Eô 0Ø d§o¡o¸T¿Z¹ZØ ×0Ñ0¸D¿N¹NØ×,Ñ,Ð5UÜSô	Uˆ	ð
 "&×!3Ñ!3Ðô *DÀIÓ)NˆÔ&Ü">Ó"@×"bÐ"bÀD×DbÑDbˆÔÜ$Ø�J‰J˜	 4×#5Ñ#5Ø#×=Ñ=õ	?ð !ŸJ™J ~Õ6ˆÔØ!ŸZ™Z¨Õ8ˆÔÜØ¨4×+;Ñ+;ÀNÜ&8Ð9OÓ&PÜ!3°D×4FÑ4FÓ!Gõ	Ið
 	�‰Ð0Ö1r3   c               ó    € V ^8„  d   QhRRRR/# )r*   r¸  r¹  r.   rO   r/   )r0   s   "r1   r2   r7    s   € ÷ 8ñ 8°ð 8À$ñ 8r3   c                óœ  € ^ RI HpHp V! V P                  4      '       d¼   V P                  '       g   V P                  4       e–   V! V P                  VRR7       V P                  R,          V n        V P                  P                  R4      ;'       g    V P                  V n        \        4       ;'       g    V P                  V n
        V P                  R4       R# V P                  4       '       gI   V P                  4       ;_uu_ 4        V P                  4       '       d   V P                  R4       RRR4       V P                  4       '       g   \        R	R
RR7      hV P                  4       pV P!                  4        V P                  '       g   Vf   R# V P                  4       ;_uu_ 4        V P                  4       '       d2   V P                  4       pV P                  R4       V P!                  4        V P                  '       g   Ve   V P#                  W4       RRR4       R#   + '       g   i     Lý; i  + '       g   i     R# ; i)zTMerge from the shared store / refresh until the access token is a usable invoke JWT.)r(  Úrefresh_guest_stateNÚ	inference)Úpurposerð   r:  Úguest_exchangeÚ)runtime_shared_merge_missing_access_tokenz,No access token found for Nous Portal login.Únous_auth_missing_access_tokenTr8   Ú!post_shared_merge_access_unusable)r+  r(  rv  r¹   r¬  rZ  rð   rŒ   rE  r•   r:  rÖ  rV  rQ  r^  r!   rc  rr  )r@  r¸  r(  rv  rZ  s   &&   r1   Úensure_usable_access_tokenÚ._NousRuntimeResolve.ensure_usable_access_token  s¸  € çLÙ˜$Ÿ*™*×%Ò%ð ×!×!Ð! T×%;Ñ%;Ó%=Ò%IÙ# D§J¡J°ÀÕLØ$(§J¡J¨~Õ$>�Ô!Ø15·±·±Ð@TÓ1U×1wÐ1wÐY]×YwÑYw�Ô.Ü*FÓ*H×*jÐ*jÈD×LjÑLj�Ô'Ø—‘Ð-Ô.ÙØ×$Ñ$×&Ò&Ø×!Ñ!×#Õ#Ø×$Ñ$×&Ò&Ø—L‘LÐ!LÔM÷ $ð ×$Ñ$×&Ò&ÜØ>Ð@`Ðjnôpð pà ×2Ñ2Ó4ÐØ×)Ñ)Ô+Ø×"×"Ð"Ð&7Ò&CÙØ×Ñ×ÕØ× Ñ ×"Ò"Ø$(×$:Ñ$:Ó$<Ð!Ø—‘Ð@ÔAØ×1Ñ1Ô3Ø×!×!Ð!Ð%6Ò%BØ—‘˜VÔ7÷  Ñ÷ $×#ú÷  ×Ðús   Ä
(H'Æ.AH:ÈH:È'H7	È:I	)r=  r9  rð   r‘  r9  r¬  r:  r>  r‹   r>  rK   r6  r¹   rE  r-  N)r²  Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__rA  r?  rÖ  rQ  rV  rZ  r^  rc  rr  r}  Ú__static_attributes__r/   r3   r1   r3  r3  Ÿ  sB   † ñõõ?õ(ò,cõNõGõõ'õ2÷B8ñ 8r3   r3  r6  c               ó0   € V ^8„  d   QhRRRRRRRRR	RR
R/# ©r*   r-  râ   r¤  r  r¥  r?   r¬  r-   r6  r.   rt   r/   )r0   s   "r1   r2   r2   0  sA   € ÷ ñ ØðØ0>ðàðà48ðð &ðð 2@ñr3   c                ó  a aaaa€ ^ RI HpHp ^ RIHp  V! VVVVV 3R l4      #   T dU   p^ RIHp	 T	! R4      ;'       g    / p
T! \        TP                  ;'       g    R4      T
P                  R4      R7       h R	p?ii ; i)
a-  Resolve Nous inference credentials for runtime use (refreshing under the auth-store lock).

A guest whose ``anon_`` credential NAS no longer knows (reaped or claimed) is retired and never
replaced here: the welcome trial is claimed once per OS user, so that user goes on to sign-in or
provider setup.
)ÚAnonCredentialDeadÚclear_dead_guest)Úrun_with_challengec                 ó$   <€ \        SSS SSR 7      # ))r-  r¤  r¥  r¬  r6  )Ú!_resolve_nous_runtime_credentials)r¥  r¬  r¤  r6  r-  s   €€€€€r1   r©  Ú2resolve_nous_runtime_credentials.<locals>.<lambda>?  s   ø€ Ô*KØ+°hÈ)Ø'Ð<Nõ+Pr3   ©Úget_provider_auth_staterŠ   Úanon_credential_deadrN  )Ú
dead_tokenN)
r+  r‡  rˆ  Úhermes_cli.anon_challenger‰  r²   rŽ  r,   r{  rŒ   )r-  r¤  r¥  r¬  r6  r‡  rˆ  r‰  Údead_excrŽ  Údeads   ddddd      r1   Ú resolve_nous_runtime_credentialsr”  0  s�   ü€ ÷ JÝ<ð
ñ "÷ #Pð #Pó Qð 	Qøð ô Ý;Ù& vÓ.×4Ð4°"ˆÙœ˜XŸ]™]×DÐDÐ.DÓEÐRV×RZÑRZÐ[gÓRhÕiØûð	ús   •% ¥B ¬1A;ÁA;Á;B c               ó0   € V ^8„  d   QhRRRRRRRRR	RR
R/# r…  r/   )r0   s   "r1   r2   r2   I  sI   € ÷ 7Cñ 7CØð7CØ0>ð7Càð7Cà48ð7Cð &ð7Cð 2@ñ7Cr3   c                ó¦  € ^ RI HpHpHpHpHp	Hp
Hp V! R4      ;_uu_ 4       w  rÍpV'       g   \        RRRR7      h^ RI	H
p V! V4      '       d   \        RR4      h\        WÍWãW@R7      pV! WVR	7      p\        R
VP                  \        VP                  R4      4      R7       \!        T ;'       g    RV4      ;_uu_ 4       pVP#                  V4       V! VVP$                  R7       V	! VVP$                  VP                  R7       VP'                  VP(                  VP*                  VP,                  V! V4      R7       RRR4       VP/                  R4       RRR4       XP0                  '       d   V
! 4        XP                  R4      p\3        V\4        4      '       d	   V'       g   \        RR4      hVP                  R4      pRRRVP6                  RTRVP                  R4      RTR\9        VVP                  R4      4      R\:        R \:        R!\5        X;'       g    V! 4       4      /	#   + '       g   i     Lô; i  + '       g   i     Lî; i)"uu  Resolve Nous inference credentials for runtime use (refreshing under the auth-store lock).

``stale_access_token`` is the bearer that just failed upstream (401): with ``force_refresh``,
the refresh POST is skipped if the store (re-read under the lock) already holds a *different*
usable token â€” a peer won the rotation; adopt it rather than invalidate a sibling's token.
)ró   rr  Ú_provider_state_transactionr  r  r#  Ú_tls_state_from_verifyrŠ   z&Hermes is not logged into Nous Portal.Únous_auth_missingTr8   ©Úguest_without_free_tier)r¬  r6  r-  r  Únous_runtime_credentials_startr>  )rK   rY  r�  )rð   )rð   rK   )r‹   r9  r:  r£  NÚ&resolve_nous_runtime_credentials_finalrn   z*Failed to resolve a Nous inference API keyÚserver_errorrp   rÀ  Úbase_urlró  Úkey_idro   rÖ   r  rq   r“  rƒ  Ú
state_path)r²   ró   rr  r—  r  r  r#  r˜  r!   r+  r›  r3  rb   rK   rJ   rŒ   rè  r}  rð   r\   r‹   r9  rE  rÖ  r>  rC   r,   r:  rú   r   )r-  r¤  r¥  r¬  r6  ró   rr  r—  r  r  r#  r˜  r‘  r¹   r5  r›  Úrunrâ  r¸  ró  rÖ   s   $$$$$                r1   r‹  r‹  I  s  € ÷ ÷  ñ  ñ 
% V×	,Ô	,Ñ0V°ÐDUßÜÐDÐFYÐcgÔhÐhÝ@Ù" 5×)Ò)äÐDÐFYÓZÐZÜ!ØÐ0Ø1ôTˆñ !¨(ÐTYÔZˆÜØ,¸#¿/¹/Ü/°·	±	¸/Ó0JÓKõ	Mô ˜×6Ð6°$¸×?Ô?À6Ø×*Ñ*¨6Ô2Ù-¨eÀ#×BRÑBRÕSÙ#Ø C×$4Ñ$4À#Ç/Á/õSð
 �L‰LØ #× 3Ñ 3¸s¿}¹}Ø#&×#@Ñ#@Ù*¨6Ó2ð ô 4÷ @ð 	�‰Ð<Ô=÷5 
-ð6 ××ÐÙ'Ô)Ø�i‰i˜Ó$€GÜ�gœs×#Ò#¯7ÜÐDÀnÓUÐUØ—‘Ð1Ó2€Jà�F˜J¨×(>Ñ(>À	È7Ø�%—)‘)˜NÓ+¨\¸:Ø”n Z°·±Ð;QÓ1RÓSØÔ+ð 	Ô.Ø”cÐ+×@Ð@©Ó/@ÓAðCð C÷' @×?ú÷ 
-×	,ús+   £-I ÁA2I ÃA>H-	ÅI È-H=È8I É I	c               ó   € V ^8„  d   QhRR/# ©r*   r.   rt   r/   )r0   s   "r1   r2   r2   ƒ  s   € ÷ Jñ J ñ Jr3   c                 ó&   € R RRRRRRRRRRRRRR	R/# )
Ú	logged_inFr‹   Nr:  Úaccess_expires_atrp   Úhas_refresh_tokenÚinference_credential_presentÚcredential_sourcer/   r/   r3   r1   Ú_empty_nous_auth_statusr«  ƒ  s7   € à�UÐ-¨tÐ5IÈ4Ø˜TÐ#9¸4ÐATÐV[Ø&¨Ð/BÀDðJð Jr3   c               ó   € V ^8„  d   QhRR/# r¤  r/   )r0   s   "r1   r2   r2   Š  s   € ÷ ')ñ ') Nñ ')r3   c                 óª  a
a€ ^ RI Ho
  ^ RIHp  V ! R4      pV'       dK   VP	                  4       '       d5   VP                  4        Uu. uF  p\        VRR4      R8w  g   K  VNK  	  upM. pV'       g   \        4       # \        VV
3R lR7      oR V3R	 llpV! R
4      '       g   \        4       # V! R4      V! R4      re\        V! RR4      ;'       g    R4      P                  4       P                  4       p\        V4      ;'       d%    VP                  R4      ;'       g    \        V4      pV! RR4      p	RTRV'       d   V! R4      ;'       g    \        MRRV! R4      ;'       g    V! R4      ;'       g	    V! R4      RV'       d   TMRRV! R4      RV! R4      R\        V4      RRRRV	 2RRV	 2/
# u upi   \         d    \        4       u # i ; i)!z¿Best-effort status from the credential pool.

Fallback only: the auth-store provider state is the runtime source of truth because it is what
``resolve_nous_runtime_credentials()`` refreshes.
)rø   r  rŠ   rK  NrL  c           	     ó¸   <€ S! \        V R R4      4      ;'       g    RS! \        V RR4      4      ;'       g    R\        \        V R^ 4      ;'       g    ^ 4      ) 3# )rp   Nr?  rÖ   Úpriority)r³  rf   )r™  rø   s   &€r1   r©  Ú,_snapshot_nous_pool_status.<locals>.<lambda>™  sW   ø€ Ù ¤¨Ð,BÀDÓ!IÓJ×QÐQÈcÙ ¤¨¨L¸$Ó!?Ó@×GÐGÀCÜ”˜˜J¨Ó*×/Ð/¨aÓ0Ð0ñ,2r3   rù  c                ó   <€ \        SW4      # rÄ   )r³  )r¨   ÚdefaultÚentrys   &&€r1   r©  r°  �  s   ø€ ¬'°%¸Ô*Gr3   Úruntime_api_keyrð   r>  Ú	auth_typer5   Úoauthr  Úunknownr¦  r‹   r:  Úruntime_base_urlrŸ  r§  rÖ   rp   r¨  r©  Trª  úpool:r“  rÄ   )r²   rø   r  r  Úhas_credentialsr—  r³  r«  rá   r,   rD   r[   r-   Ú
startswithr   r„   )r  r  r™  r—  Úattrrð   r>  rµ  Úis_portal_oauthr  rø   r³  s             @@r1   Ú_snapshot_nous_pool_statusr¾  Š  sÎ  ù€ õ 5ð )Ý3Ù˜Ó ˆ÷ �T×)Ñ)×+Ò+ð #Ÿl™lœnÓ_™n˜´¸¸=È$Ó0OÐS^Ñ0^—1�1™nÒ_Ø24ð 	çÜ*Ó,Ð,Ü�Gô "2ô 3ˆö HˆÙÐ%×&Ò&Ü*Ó,Ð,Ù&*¨>Ó&:¹DÀÓ<Q�mÜ™˜[¨"Ó-×3Ð3°Ó4×:Ñ:Ó<×BÑBÓDˆ	Ü˜|Ó,÷ Bð BØ× Ñ  Ó)×@Ð@¬T°-Ó-@ð 	á�W˜iÓ(ˆà˜ØßHW‘Ð'Ó(×CÐCÔ,CøÐ]aØ ÙÐ)Ó*×ZÐZ©dÐ3EÓ.F×ZÐZÉ$ÈzÓJZØ¯O™LÀØ¡ lÓ!3Ø"¡DÐ)?Ó$@Ø¤ mÓ!4Ð6TÐVZØ 5¨¨ °(¸eÀEÀ7¸Oð
Mð 
	Mùò! `øô6 ô )Ü&Ó(Ò(ð)úsp   ŠF:  F: ¶F: ÁF5Á!F5Á'F: Á4	F: Á>0F: Â/AF: ÄF: Ä!F: ÅF: ÅF: Å(F: Å8F: Æ	+F: Æ5F: Æ:GÇGc               ó(   € V ^8„  d   QhRRRRRRRR/# )r*   r¹   rt   r¦  r-   r“  r,   r.   r/   )r0   s   "r1   r2   r2   ´  s,   € ÷ ,ñ ,Øð,Ø)-ð,Ø7:ð,Ø?Mñ,r3   c               ó®  € ^ RI Hp V P                  R4      pV P                  R4      pRTRV P                  R4      RV P                  R4      RV P                  R4      R	V P                  R	4      R
\        V P                  R4      4      RTR\        T;'       g    V P                  R4      4      RRRTR\	        V\
        4      '       d   TMRRV! V 4      /# )zVAuth-store-backed Nous status snapshot (shared by the live and refresh-free variants).r'  rð   rM  r¦  r‹   r:  r§  rÖ   rp   r¨  r>  r©  rn   rª  r‘  r“  NÚ	free_tier)r+  r(  rŒ   r-   rC   r,   )r¹   r¦  r“  r(  rð   rM  s   &$$   r1   Ú_nous_status_from_staterÂ  ´  sÅ   € õ 4Ø—9‘9˜^Ó,€LØ—9‘9˜^Ó,€Là�YÐ 1°5·9±9Ð=NÓ3OØ˜eŸi™iÐ(<Ó=Ø˜UŸY™Y |Ó4Ø §	¡	Ð*@Ó AØœT %§)¡)¨OÓ"<Ó=¸~È|Ø&¬¨\×-SÐ-S¸U¿Y¹YÀ{Ó=SÓ(TØ˜\¨8°Và¬
°<Ä×(EÒ(E™È4Ø‘^ EÓ*ð
,ð 
,r3   c               ó   € V ^8„  d   QhRR/# r¤  r/   )r0   s   "r1   r2   r2   Ç  s   € ÷ #ñ # >ñ #r3   c                 ól  € ^ RI Hp  ^ RIHpHp V! R4      pV'       d   V ! V4      '       d   \        4       # \        V\        VP                  R4      4      RR7      p ^ RI	H
p V! 4       ;_uu_ 4        V! 4       pRRR4       V! R4      ;'       g    TpTP                  R	R
RVP                  R4      ;'       g    VP                  R4      RXP                  R4      ;'       g+    VP                  R4      ;'       g    VP                  R4      RVP                  R4      ;'       g    VP                  R4      RVP                  R4      ;'       g+    VP                  R4      ;'       g    VP                  R4      R\        VP                  R4      4      RR
RRRRVP                  RR4       2RVP                  R4      /
4       V#   + '       g   i     ELV; i  \         dM   pTP                  R	RR\        T4      R\        \        TRR4      4      R\        TRR4      /4        Rp?T# Rp?ii ; i)zEUncached implementation of get_nous_auth_status(). See that function.rš  )rŽ  r”  rŠ   rð   r‘  ©r¦  r“  )Úbackground_callerNr¦  Tr‹   r:  rŸ  r§  rÖ   rp   r¨  r>  r©  rª  r“  zruntime:Úportalr   Fr‚   Úrelogin_requiredrs  r{  )r+  r›  r²   rŽ  r”  r¾  rÂ  r-   rŒ   r‘  rÆ  r\   r   r,   r³  )	r›  rŽ  r”  r¹   Úbase_statusrÆ  r  Úrefreshed_stater[  s	            r1   Ú_compute_nous_auth_statusrË  Ç  s  € å<ßYÙ# FÓ+€EßÑ+¨E×2Ò2Ü)Ó+Ð+Ü)Øœ˜eŸi™i¨Ó7Ó8ÀôO€Kð7å?Ù× Õ Ù4Ó6ˆE÷ !á1°&Ó9×BÐB¸UˆØ×ÑØ˜ØØ×#Ñ#Ð$5Ó6×\Ð\¸+¿/¹/ÐJ[Ó:\Ø Ø—	‘	˜*Ó%÷ 9ð 9¨×)<Ñ)<Ð=QÓ)R÷ 9ð 9Ø—?‘?Ð#7Ó8ØØ×#Ñ# LÓ1×YÐY°[·_±_ÐEXÓ5YØ"Ø—	‘	˜,Ó'÷ ;ð ;¨?×+>Ñ+>Ð?UÓ+V÷ ;ð ;Ø—?‘?Ð#9Ó:Ø¤ o×&9Ñ&9¸/Ó&JÓ!KØ*¨DÐ2EÀ|Ø˜ §¡¨8°XÓ!>Ð ?Ð@À(ÈEÏIÉIÐV^ÓL_ðaô 	bð( Ð÷/ !× Ð ûô$ ô 7Ø×ÑØ˜ ¬¨S«Ø¤¤W¨SÐ2DÀeÓ%LÓ MØœ' # v¨tÓ4ð6÷ 	7ð 	7ð Ðûð7ús\   ÁG Á3GÁ;G Â(G Â;)G Ã%G Ã>)G Ä()G ÅG Å+AG ÇG	Ç	G ÇH3Ç'AH.È.H3c               ó    € V ^8„  d   QhRRRR/# )r*   r¹   rt   r.   r^  r/   )r0   s   "r1   r2   r2   í  s   € ÷ 
ñ 
 ~ð 
Ð:Rñ 
r3   c                óâ   € V P                  R4      p\        V\        4      '       dH   VP                  R4      '       d1   V P                  R4      '       g   V P                  R4      '       g   V# R# )zçThe persisted ``last_auth_error`` when it is a terminal quarantine with no credential left.

Only terminal while there is no usable credential: if a later login repopulated tokens the stale
marker must not keep reporting terminal.
r�  rÈ  rð   r>  N)rŒ   rC   r�   )r¹   Úlast_errs   & r1   Ú_terminal_quarantine_markerrÏ  í  sT   € ð �y‰yÐ*Ó+€HÜ�8œT×"Ò" x§|¡|Ð4F×'GÒ'GØ—Y‘Y˜~×.Ò.°%·)±)¸O×2LÒ2LØˆÙr3   c               ó   € V ^8„  d   QhRR/# r¤  r/   )r0   s   "r1   r2   r2   ú  s   € ÷ ñ  Nñ r3   c                 óÞ  € ^ RI Hp  ^ RIHp  V! R4      pV'       d   V ! V4      '       d   \        4       # \        W"P                  R4      4      p\        V4      pVRJ ;'       g'    \        VP                  R4      4      ;'       d    VRJ p\        W%RR7      pVe=   TP                  R	VP                  R
4      VP                  R4      ;'       g    RR7       V#   \         d    Rp LÕi ; i)u  Refresh-free Nous auth snapshot for read-only display surfaces.

NEVER calls ``resolve_nous_runtime_credentials()`` (no refresh POST / single-use token spent);
``logged_in`` = usable invoke JWT, or a refresh token not terminally quarantined â€” not proof
the server still accepts it.
rš  r�  rŠ   Nrð   r>  Úauth_store_localrÅ  Tr{  r…   zre-login required)rÈ  rs  r‚   )r+  r›  r²   rŽ  r„   r¾  rï   rŒ   rÏ  r-   rÂ  r\   )r›  rŽ  r¹   Ú
jwt_reasonrÎ  r¦  Ústatuss          r1   Úget_nous_auth_status_localrÕ  ú  sâ   € õ =Ý7ðÙ'¨Ó/ˆ÷ Ñ+¨E×2Ò2Ü)Ó+Ð+Ü)¨%·±¸>Ó1JÓK€JÜ*¨5Ó1€HØ˜tÐ#×_Ð_¬¨e¯i©i¸Ó.HÓ)I×)^Ð)^ÈhÐZ^ÐN^€IÜ$ UÐHZÔ[€FØÒØ�‰Ø!¨h¯l©l¸6Ó.BØ—,‘,˜yÓ)×@Ð@Ð-@ð 	ô 	Bð €Møô ô ØŠðús   ŽC ÃC,Ã+C,ÚvalidÚterminalr·  c               ó   € V ^8„  d   QhRR/# )r*   r.   r,   r/   )r0   s   "r1   r2   r2     s   € ÷  ñ   3ñ  r3   c                 óØ   € ^ RI Hp   V ! R4      pV'       g   \        # \	        V4      e   \
        # \        WP                  R4      4      f   \        # \        #   \         d    Rp LXi ; i)uR  Classify the Nous bootstrap session for the dashboard /api/status probe.

Local auth-store state only; polled frequently, so it never resolves or refreshes. ANTI-FLAP:
only a *terminal* failure maps to "terminal" â€” a rotation blip, network error, or expiring
token must NOT (that would trigger a spurious NAS re-mint on a healthy box).
r�  rŠ   Nrð   )	r²   rŽ  r„   ÚNOUS_SESSION_UNKNOWNrÏ  ÚNOUS_SESSION_TERMINALrï   rŒ   ÚNOUS_SESSION_VALID)rŽ  r¹   s     r1   Úget_nous_session_validityrÝ    sl   € õ 8ðÙ'¨Ó/ˆ÷ Ü#Ð#ô # 5Ó)Ò5Ü$Ð$Ü §y¡y°Ó'@ÓAÒIÜ!Ð!ô  Ðøô ô ØŠðús   ˆA ÁA)Á(A)Úon_pool_missc               ó0   € V ^8„  d   QhRRRRRRRRRR	R
R/# )r*   Úprovider_idr,   Úis_expiringzCallable[[str, int], bool]Ú	auth_moder&  zCallable[[], dict[str, Any]]rÞ  z0Optional[Callable[[], Optional[dict[str, Any]]]]r.   rt   r/   )r0   s   "r1   r2   r2   6  sK   € ÷ .]ñ .]Øð.]Ø&@ð.]ØMPð.]à)ð.]ð Cð.]ð O]ñ.]r3   c               ó¤  € ^ RI Hp  ^ RIHp V! V 4      pV'       dò   VP	                  4       '       dÜ   VP                  4       pVe³   \        VRR4      ;'       g    \        VRR4      p	V	'       d‰   V! V	^ 4      '       gz   RRR	\        V! 4       4      R
\        VR
R4      RTRR\        VRR4       2RT	R\        \        VRR4      ;'       g    \        VRR4      ;'       g    R4      P                  R4      /# Ve   V! 4       ;p
'       d   V
#  T! 4       pRRR	\        T! 4       4      R
TP                  R
4      RTP                  R4      RTP                  R4      RTP                  R4      RTP                  R4      ;'       g    R/#   \         d     Lˆi ; i  \         d*   pRRR	\        T! 4       4      R\        T4      /u Rp?# Rp?ii ; i)u°  Status snapshot for a store-backed OAuth provider (Codex, xAI).

Pool first (where `hermes auth` / `hermes model` store device_code tokens), then
*on_pool_miss* for a pool-derived degraded status, then the legacy state via *resolve*.

The pool read is an observation (``peek``), not a lease: ``select()`` refreshes an expiring
single-use token and, when that speculative POST fails transiently, benches the entry with a
persisted cooldown â€” every credential-gated listing (``/model`` picker, doctor) then shows the
provider as unconfigured while the runtime resolver still serves it. Refreshing stays with the
runtime resolver reached through *resolve*, whose failures persist nothing.
rq  r  Nr´  rð   r5   r¦  Tr‘  Úlast_refreshrâ  r“  r¹  r  r·  ró  rŸ  r¸  rœ   Fr‚   )r²   rr  r  r  rº  Úpeekr³  r,   rž   r„   rŒ   r   )rà  rá  râ  r&  rÞ  rr  r  r  r³  ró  Údegradedr  r[  s   &$$$$        r1   Ú_pool_first_oauth_statusrç  6  sß  € õ 0ðÝ3Ù˜Ó%ˆß�D×(Ñ(×*Ò*Ø—I‘I“KˆEØÒ ä˜EÐ#4°dÓ;×aÐa¼wÀuÈnÐ^`Ó?að ç¡;¨w¸×#:Ò#:à# T¨<¼¹_Ó=NÓ9OØ&¬°°~ÀtÓ(LØ# YØ  E¬'°%¸À)Ó*LÐ)MÐ"NÐPYÐ[bð #¤C¬°Ð7IÈ4Ó(P÷ )Rð )RÜ+2°5¸*ÀdÓ+K÷)Rð )RØOQó%SßSYÑSYÐZ]ÓS^ð`ð `ð Ò'¹»Ð-G¨XÖ-GØ�ð]Ù“	ˆà˜˜|¬S±Ó1BÓ-CØ˜EŸI™I nÓ5Ø˜Ÿ™ ;Ó/°¸5¿9¹9ÀXÓ;NØ�u—y‘y Ó+¨Z¸¿¹À:Ó9N×9TÐ9TÐRTð	Vð 	Vøô	 ô Ùðûô ô ]Ø˜U L´#±oÓ6GÓ2HÈ'ÔSVÐWZÓS[Ð\Õ\ûð]úse   ˆF
 žF
 ´'F
 ÁF
 Á2F
 ÂA!F
 Ã#F
 Ã:F
 ÄF
 ÄA5F ÆF Æ
FÆFÆGÆ&G
ÇGÇ
GÚopen_browserÚon_verificationc               ó@   € V ^8„  d   QhRRRRRRRRRRRR	R
RRRRRRR/
# )r*   r‹   r?   r:  r9  rÕ   rè  r-   r-  râ   r¤  r¥  ré  ú$Optional[Callable[[str, str], None]]r.   rt   r/   )r0   s   "r1   r2   r2   g  sv   € ÷ Kñ KØ%ðKØBOðKàðKà,9ðKàPTðKð ðKð .2ðKð GTðKð :ð	Kð FTñ	Kr3   c        	        ó  € ^ RI Hp	Hp
HpHpHpHpHpHpH	pH
p V	R,          pT ;'       gI    \        P                  ! R4      ;'       g+    \        P                  ! R4      ;'       g    VP                  P                  R4      p T;'       g+    \        P                  ! R4      ;'       g    VP                  P                  R4      pT;'       g    VP                   pT;'       g    VP"                  pV'       d   RMV'       d   TMRpV! 4       '       d   Rp\%        R	VP&                   R
24       \%        RV  24       V'       d   \%        R4       MV'       d   \%        RV R24       \)        VV4      ;_uu_ 4       pV! VWVR7      p\+        VR,          4      p\+        VR,          4      p\-        VR,          4      p\-        VR,          4      pV! VVVRR7       Ve*   \/        \0        4      ;_uu_ 4        V! VV4       RRR4       \3        ^\5        V\6        4      4      p\%        RV R24       V! VW\+        VR,          4      VVR7      pRRR4       \8        P:                  ! \<        4      pV
! XP?                  R^ 4      4      pV! VP?                  R4      4      ;'       g    Tp V V8w  d   \%        RV  24       RT RT RTRVP?                  R4      ;'       g    TR VP?                  R R!4      R"VR",          R#VP?                  R#4      R$VPA                  4       R%\C        VV4      RVR&V! V4      /\D        Cp! V! V!VRR'7      #   + '       g   i     ELN; i  + '       g   i     EL; i  \F         d‡   p"T"PH                  R(8X  dp   T!P?                  R\J        4      P                  R4      p#\%        4        \%        T! T"4      4       \%        R)T# R*24       \%        4        \%        R+4       \M        ^4      hh Rp"?"ii ; i),zMRun the Nous device-code flow and return full OAuth state without persisting.)
ÚPROVIDER_REGISTRYr÷   Ú_is_remote_sessionr¯   Ú_poll_for_tokenÚ_print_device_code_instructionsÚ_request_device_coder˜  Úformat_auth_errorr¡  rŠ   rµ   r¶   rœ   r°   FTzStarting Hermes login via z...zPortal: z'TLS verification: disabled (--insecure)z$TLS verification: custom CA bundle (r6   )r¸  r‹   r9  rÕ   Úverification_uri_completeÚ	user_coder  Úintervalu   â€”)rè  Úfailure_dashNz$Waiting for approval (polling every zs)...Údevice_code)r¸  r‹   r9  r÷  r  Úpoll_intervalr:  z%Using portal-provided inference URL: r‹   r9  rÕ   r8  rJ  rð   r>  rÿ   rÖ   r£  )r-  r¬  Úsubscription_requiredz  Subscribe here: z/billingz<After subscribing, run `hermes model` again to finish setup.)'r²   rí  r÷   rî  r¯   rï  rð  rñ  r˜  rò  r¡  rY   rZ   r‹   rž   r:  r9  rÕ   Úprintr¨   rè  r,   rf   r   r„   rá   Úminr   r   rd   r   rŒ   rl   rm   ru   r   r{  r   Ú
SystemExit)$r‹   r:  r9  rÕ   rè  r-  r¤  r¥  ré  rí  r÷   rî  r¯   rï  rð  rñ  r˜  rò  r¡  ÚpconfigÚrequested_inference_urlrâ  r¸  Údevice_dataÚverification_urlrô  r  rõ  Úeffective_intervalÚ
token_datard   Útoken_expires_inÚresolved_inference_urlr  r[  r,  s$   $$$$$$$$$                           r1   Ú_nous_device_code_loginr  g  s­  € ÷R÷ R÷ Rð   Õ'€Gà÷ 	#ð 	#œ2Ÿ9š9Ð%=Ó>÷ 	#ð 	#Ä"Ç)Â)ÐLbÓBc÷ 	#ð 	#Ø×"Ñ"§F¡F¨3£Kð ð 	÷ 	&ð 	&œbŸišiÐ(AÓB÷ 	&ð 	&Ø×%Ñ%§v¡v¨c£{ð ð ×.Ð.˜W×.Ñ.€IØ×"Ð"�W—]‘]€Eß"*™¿i±ÈT€FÙ×ÒØˆÜ	Ð& w§|¡| n°CÐ
8Ô9Ü	ˆH�_Ð%Ð
&Ô'ßÜÐ7Õ8ß	ÜÐ4°Y°K¸qÐAÔBÜ	˜?¨F×	3Ô	3°vÙ*Ø¨?ÐW\ô^ˆä˜{Ð+FÕGÓHÐÜ˜ KÕ0Ó1ˆ	Ü˜ \Õ2Ó3ˆ
Ü�{ :Õ.Ó/ˆÙ'Ø˜i°lÐQVõ	Xð Ò&Üœ)×$Õ$ÙÐ 0°)Ô<÷ %ä  ¤C¨Ô2WÓ$XÓYÐÜÐ4Ð5GÐ4HÈÐNÔOÙ$Ø¨?Ü˜K¨Õ6Ó7ÀJØ"ô$ˆ
÷! 
4ô( �,Š,”sÓ
€CÙ*¨:¯>©>¸,ÈÓ+JÓKÐá˜:Ÿ>™>Ð*>Ó?Ó@×[Ð[ÐD[ð àÐ!8Ô8ÜÐ5Ð6LÐ5MÐNÔOà˜?Ð,@ÐBXØ�Y ¨¯©¸Ó)@×)IÐ)IÀEØ�j—n‘n \°8Ó<Ø˜
 >Õ2Ø˜Ÿ™¨Ó8Ø�s—}‘}“¨´jÀÐFVÓ6WØÐ&¨Ñ/EÀfÓ/Mð(ô 'ð(€JðÙ,Ø¨ÀuôNð 	N÷1 %×$Ð$ú÷ 
4×	3Ð	3ûôL ô 	Ø�8‰8Ð.Ô.Ø#Ÿ™Ð(9Ô;RÓS×ZÑZÐ[^Ó_ˆJÜŒGÜÑ# CÓ(Ô)ÜÐ& z l°(Ð;Ô<ÜŒGÜÐPÔQÜ˜Q“-ÐØûð	ús?   Å=A;MÇ8
M	ÈAMÌ<
M/ ÍMÍ	MÍM,	Í/P Í:BO;Ï;P c               ó    € V ^8„  d   QhRRRR/# )r*   r  rt   r.   rO   r/   )r0   s   "r1   r2   r2   µ  s   € ÷ *ñ *¨~ð *À$ñ *r3   c                ó  € ^ RI HpHp \        \        4      ;_uu_ 4        V! V 4       RRR4       \        \        4      ;_uu_ 4        V! 4        RRR4       R#   + '       g   i     L9; i  + '       g   i     R# ; i)zZMirror to the shared store + reseed the pool, swallowing all errors (same as _login_nous).)r#  r\  N)r²   r#  r\  r   r„   )r  r#  r\  s   &  r1   Ú_mirror_nous_state_best_effortr  µ  sI   € çYÜ	”)×	Õ	Ù  Ô,÷ 
ä	”)×	Õ	Ù'Ô)÷ 
Ñ	÷ 
×	úç	×	Ð	ús    	AÁA-ÁA*	Á-A>	c               ó(   € V ^8„  d   QhRRRRRRRR/# )r*   rè  r-   r-  râ   ré  rë  r.   r/   )r0   s   "r1   r2   r2   ¾  s2   € ÷ %Uñ %UØð%UØ38ð%Uà9ð%UàEIñ%Ur3   c           
     ó@  € ^ RI HpHpHpHp V! R4      ;'       g    / pVR,          pVP                  R4      p	\        V	\        4      '       d   V	P                  4       M. p
\        \        P                  . T
;'       g    \        .O\        N4      4      pT! VP                  R4      ;'       g    RVP                  R4      ;'       g    RVP                  R4      ;'       g    VP                  RP                  V4      WVR	7      pV! RV4       \!        V4        ^ R
IHp V! 4        ^ RIHp V! V4       VP                  R4      p\        V\        4      ;'       d    \        VP                  4       9   #   \&         d    \(        P+                  RRR7        Lri ; i)a  Re-run the device flow requesting ``billing:manage`` (step-up on 403 insufficient_scope).

The user must be ADMIN/OWNER and select "Allow Remote Spending" in the portal, else the
server silently downscopes and this returns False. Persists like ``_login_nous`` minus the
model picker.
)rí  r  r  rŽ  rŠ   rÕ   r‹   Nr:  r9  rÊ   )r‹   r:  r9  rÕ   rè  r-  ré  )Úinvalidate_cached_tokenz'Billing token cache invalidation failedT)Úexc_info©Úsettle_after_upgrade)r²   rí  r  r  rŽ  rŒ   rC   r,   rÐ   rÑ   r�   rü  r   r   r9  r§   r  Úhermes_cli.nous_billingr  r„   r]   r  r+  r  )rè  r-  ré  rí  r  r  rŽ  Úpriorrý  Ú
_raw_scopeÚprior_scopeÚ	requestedr  r  r  Úgranteds   $$$             r1   Ústep_up_nous_billing_scoper  ¾  st  € ÷!ó !ñ $ FÓ+×1Ð1¨r€EØ Õ'€Gð —‘˜7Ó#€JÜ(2°:¼s×(CÒ(C�*×"Ñ"Ô$È€KÜ”T—]‘]ð $TØ
×
6Ð
6Ô5Ð6ð$TÜ9Rð$Tó Uó V€Iá(ØŸ	™	Ð"3Ó4×<Ð<¸Ø Ÿ9™9Ð%9Ó:×BÐB¸dØ—)‘)˜KÓ(×=Ð=¨G×,=Ñ,=ÀSÇXÁXÈiÓEXØ!ÐTcô	e€Jñ
   ¨
Ô3Ü" :Ô.ðOÝCÙÔ!õ :Ù˜Ô$Ø�n‰n˜WÓ%€GÜ�gœsÓ#×TÐTÔ(AÀWÇ]Á]Ã_Ñ(TÐTøô ô OÜ�‰Ð>ÈˆÖNðOús   ÄE8 Å8"FÆFc               ó$   € V ^8„  d   QhRRRRRR/# )r*   r  rt   r:  r,   r.   r?   r/   )r0   s   "r1   r2   r2   æ  s)   € ÷ Nñ NØðNØ47ðNØ<IñNr3   c                óR  € ^ RI Hp V P                  R4      ;'       g    V P                  R4      p\        V\        4      '       d	   V'       g   \        RR4      h^ RIHpHpH	pH
pHpHp	 ^ RIHp
HpHp V! 4       pV P                  RR	4      p\#        4        . pR	pR
pV'       d�   V
! R4      pV! RR7      pV! 4       pV'       d,   \%        \&        4      ;_uu_ 4        \)        R4      pRRR4       V'       d   TMT	pV! VVV4      w  ppV'       g
   V! VV4      pTpV! VVRR7      pVV8g  pV'       d   V! VVRR7      w  rßV'       dr   ^ RIHp V! VR7      pV'       d   \#        V4       ^ RIHpHp V! RR7      pVe   V! VVP4                  4      p\#        R\7        V4       R24       V! VXWþVRWVR7	      # V'       dF   T;'       g    \8        P;                  R4      p\#        R4       \#        T;'       g    RV R24       R# \#        R4       R#   + '       g   i     EL5; i)a  Fetch the curated Nous model list (tier/policy-filtered) and run the interactive picker.

Returns the selected model id, or None when the user skipped / nothing was selectable.
Raises on any fetch failure so the caller can print the "Login succeeded, but..." notice.
)Ú_prompt_model_selectionrn   rð   z,No runtime API key available to fetch modelsr¾  )Úget_curated_nous_model_idsÚcheck_nous_free_tierÚpartition_nous_models_by_tierÚunion_with_nous_on_sale_modelsÚ&union_with_portal_free_recommendationsÚ&union_with_portal_paid_recommendations)Úget_pricing_for_providerÚnous_policy_allowed_idsÚrestrict_to_nous_policyr‹   r5   FrŠ   Tr|   zpaid Nous modelsN)Úrescue_empty)rÁ  )Únous_policy_notice)r›  )Úfeatured_firstÚnous_picker_usage)ÚwarmzShowing u=    curated models â€” use "Enter custom model name" for others.)ÚpricingÚunavailable_modelsr,  Úunavailable_messageÚconfirm_providerÚconfirm_base_urlÚconfirm_api_keyÚusagerœ   z#No free models currently available.zUpgrade at z to access paid models.z,No curated models available for Nous Portal.)r²   r  rŒ   rC   r,   r!   Úhermes_cli.modelsr  r  r  r  r  r  Úhermes_cli.models_pricingr  r   r!  rú  r   r„   r€   r~   r#  Úhermes_cli.model_picker_usager$  r%  Úfeatured_model_idsr–  r   rž   )r  r:  r  Úruntime_keyr  r  r  r  r  r  r  r   r!  rþ  Ú_portalr(  r)  Ú_policy_narrowedr'  rÁ  Ú_policy_allowedÚunionÚ_before_policyr#  Ú_policy_noticer$  r%  Ú_usageÚ_urls   &&                           r1   Ú_pick_nous_model_after_loginr;  æ  s  € õ 8Ø—.‘. Ó-×OÐO°·±ÀÓ1O€KÜ�k¤3×'Ò'¯{ÜÐFÈÓXÐX÷÷ ÷ñ ñ
 +Ó,€IØ�n‰nÐ.°Ó3€GÜ	„GØ!ÐØÐØÐßÙ*¨6Ó2ˆá(°TÔ:ˆ	á1Ó3ˆßÜœ)×$Õ$Ü&AÐBTÓ&UÐ#÷ %÷
 7@Ñ2Ø7ð 	ñ # 9¨g°wÓ?Ñˆ	�7ßá6°yÀ'ÓJˆIØ"ˆÙ+¨I°ÐUYÔZˆ	Ø$¨Ñ6ÐßÙ,IØ˜7¨dô-4Ñ)ˆIçÝ>Ù+Ð4DÔEˆßÜ�.Ô!ßSÙ"¨Ô-ˆàÒÙ& y°&×2KÑ2KÓLˆIÜØ”s˜9“~Ð&ð ':ð :ô	;ñ 'Ø˜wÐ;MØ 3ÀfØ/Øô	ð 	÷
 Ø×2Ð2Ô2×:Ñ:¸3Ó?ˆÜÐ3Ô4ÜÐ!×PÐP {°4°&Ð8OÐ%PÔQñ ô 	Ð<Ô=Ù÷S %×$Ð$ús   ÃHÈH&	c               ó    € V ^8„  d   QhRRRR/# rŸ  r/   )r0   s   "r1   r2   r2   7  s   € ÷ ñ ¨uð Ð9Qñ r3   c                óP  € ^ RI HpHp ^ RIHp V! 4       pV'       d   V! V4      '       d   R#  \        4       p\        4        \        V'       d   RV 2MR4       V! RRR7      '       g   R# \        R	4       \        V R
7      pVf   \        R4       V#   \         d    Rp Lki ; i)zõCodex-style auto-import: offer to rehydrate a Nous credential from another profile.

Checks the shared store before launching a fresh device-code flow. Returns the refreshed
auth state when the user accepted and the import succeeded, else None.
)Ú_prompt_yes_nor=  r'  Nz)Found existing Nous OAuth credentials at z,Found existing shared Nous OAuth credentialsz!Import these credentials? [Y/n]: Úy)r²  z3Rehydrating Nous session from shared credentials...r6  uK   Could not refresh shared credentials â€” falling back to device-code login.)	r²   r>  r=  r+  r(  r+  r'  rú  r¶  )r-  r>  r=  r(  r  Úshared_pathr  s   &      r1   Ú_offer_shared_nous_importrA  7  sŸ   € ÷ HÝ3Ù$Ó&€Fß‘^ F×+Ò+ñ ðÜ-Ó/ˆô 
„GÜ	Ç{Ð5°k°]Ñ
CØ=ô?áÐ=Às×KÓKÙÜ	Ð
?Ô@Ü.¸ÔO€JØÒÜÐ[Ô\ØÐøô ô ØŠðús   ¯
B ÂB%Â$B%c               ó    € V ^8„  d   QhRRRR/# )r*   Úprior_active_providerr
   r.   rO   r/   )r0   s   "r1   r2   r2   T  s   € ÷ 	%ñ 	%°Cð 	%¸Dñ 	%r3   c                óÎ   € ^ RI HpHpHp V! 4       ;_uu_ 4        V! 4       pV '       d   WR&   MVP	                  RR4       V! V4       RRR4       R#   + '       g   i     R# ; i)zUUndo the ``active_provider="nous"`` that ``_save_provider_state`` wrote during login.)Ú_auth_store_lockÚ_load_auth_storeÚ_save_auth_storeÚactive_providerN)r²   rE  rF  rG  rŽ  )rC  rE  rF  rG  r‘  s   &    r1   Ú_restore_active_providerrI  T  sK   € çTÑTÙ	×	Õ	Ù%Ó'ˆ
ß Ø,AÐ(Ò)à�N‰NÐ,¨dÔ3Ù˜Ô$÷ 
×	×	Ò	ús   š/AÁA$	c               ó    € V ^8„  d   QhRRRR/# )r*   rý  r'   r.   rO   r/   )r0   s   "r1   r2   r2   `  s   € ÷ Gñ G˜~ð G°$ñ Gr3   c                óÜ  € ^ RI HpHpHpHpHpHpHpHp	H	p
 \        V RR4      ;'       g    Rp\        V RR4      ;'       g5    \        P                  ! R4      ;'       g    \        P                  ! R4      p \        V4      pVfu   T! \        V RR4      \        V R	R4      \        V R
R4      ;'       g    VP                  \        V RR4      \        V RR4      '       * V\        \        V RR4      4      VR7      pVR,          pV! 4       ;_uu_ 4        V! 4       P!                  R4      pRRR4       \#        4       ;_uu_ 4       pV! RV4      pV	! V4       RRR4       T! 4        ^ RIHp V! V4       \)        4        \)        R4       \)        RX 24       R XP*                   4        F  p\)        RV 24       K  	  Rp \-        WÞ4      pV'       g.   \7        X4       \)        4        \)        R4       \)        R4       R# T! RVVR7      pV! V4       \)        RV 24       ^ RIHp V! VR4      ;p'       d   \)        RV 24       \)        RV R 24       R#   + '       g   i     EL7; i  + '       g   i     EL; i  \.         dM   p\1        T\2        4      '       d	   T
! T4      M
\5        T4      p\)        4        \)        RT 24        Rp?ELRp?ii ; i  \<         d    \)        R!4       \?        ^‚4      h\.         dg   p^ R"I H!p \D        PG                  R#T4       \)        4        T! T\I        \        T RR4      4      R$7       F  p\)        T4       K  	  \?        ^4      hRp?ii ; i)%z&Nous Portal device authorization flow.)	rE  rF  r  r  Ú_save_model_choicer#  Ú_update_config_for_providerr\  rò  rå  Nr�  r¥  ÚHERMES_CA_BUNDLEÚSSL_CERT_FILEr,  Úinference_urlr9  rÕ   Ú
no_browserFr¤  )r‹   r:  r9  rÕ   rè  r-  r¤  r¥  r:  rH  rŠ   r  zLogin successful!z  Auth state: c              3  óH   "  € T F  p\        V4       F  q"x € K  	  K  	  R # 5irÄ   )r&   )rÅ   ÚviewÚlines   &  r1   rÇ   Ú_login_nous.<locals>.<genexpr>„  s   é € ÐU¡o˜dÄ,ÈtÖBT¸$”TÑBT‘T£oùs   ‚ "z  z?Login succeeded, but could not fetch available models. Reason: z:No provider change. Nous credentials saved for future use.z4  Run `hermes model` again to switch to Nous Portal.)Údefault_modelzDefault model set to: )Úlarge_model_noticeu     âš  z  Config updated: z (model.provider=nous)z
Login cancelled.)Úsign_in_failure_linesznous login failed: %r)Úservice_host)%r²   rE  rF  r  r  rL  r#  rM  r\  rò  r³  rY   rZ   rA  r9  r-   rŒ   r#   r+  r  rú  Úresultsr;  r„   rC   r   r,   rI  r0  rW  ÚKeyboardInterruptrü  Úhermes_cli.auth_error_copyrX  r]   r  Ú_portal_host)Úargsrý  rE  rF  r  r  rL  r#  rM  r\  rò  r-  r¥  r  r:  rC  ÚhandoffÚsaved_tor  rT  Úselected_modelr[  r…   Úconfig_pathrW  Ú_noticerX  s   &&                         r1   Ú_login_nousrd  `  s  € ÷5÷ 5õ 5ô ˜d I¨tÓ4×<Ð<¸€Oä��k 4Ó(÷ 	&ð 	&¬B¯IªIÐ6HÓ,I÷ 	&ð 	&Ü�9Š9�_Ó%ð ð=Ü.¨Ó?ˆ
ØÒÙ0Ü '¨¨l¸DÓ AÜ#*¨4°À$Ó#GÜ! $¨°TÓ:×OÐO¸g×>OÑ>OÜ˜d G¨TÓ2Ü!(¨¨|¸UÓ!CÔCØ /¼$¼wÀtÈZÐY^Ó?_Ó:`Ø#ô%ˆJð (Ð(<Õ=Ðñ ×ÕÙ$4Ó$6×$:Ñ$:Ð;LÓ$MÐ!÷  ä�ZŒZ˜7Ù2°6¸:ÓFˆHá$ ZÔ0÷ ñ 	(Ô)Ý=Ù˜ZÔ(ÜŒÜÐ!Ô"Ü�˜x˜jÐ)Ô*ÙU g§o¢oÖUˆDÜ�B�t�f�+Öñ Vð ˆð	_Ü9¸*ÓYˆN÷ Ü$Ð%:Ô;ÜŒGÜÐNÔOÜÐHÔIÙÙ1ØÐ&°nôFˆá˜>Ô*ÜÐ& ~Ð&6Ð7Ô8ÝDÙ(¨¸Ó@Ð@ˆ7Ö@Ü�F˜7˜)Ð$Ô%ÜÐ" ; -Ð/EÐFÖG÷K  ×Ðúç�ZˆZûô  ô 	_Ü0:¸3Ä	×0JÒ0JÑ'¨Ô,ÔPSÐTWÓPXˆGÜŒGÜÐSÐT[ÐS\Ð]×^Ò^ûð	_ûô( ô ÜÐ"Ô#Ü˜‹oÐÜô ÝDÜ�‰Ð,¨cÔ2ÜŒÙ)¨#¼LÌÐQUÐWcÐeiÓIjÓ<k×lˆDÜ�$ŽKñ mä˜‹mÐûðús‰   Á8BK ÄIÄ*K ÅI,ÅA*K ÇJ  ÇK Ç+K ÈAK ÉI)	É#	K É,I=	É7	K Ê KÊAKËK ËKËK Ë)M+ÌM+ÌA!M&Í&M+c               ó    € V ^8„  d   QhRRRR/# )r*   r,  r?   r.   r,   r/   )r0   s   "r1   r2   r2   ª  s   € ÷ añ a˜]ð a¨sñ ar3   c                ó\   € \        T ;'       g    \        4      P                  ;'       g    R # )zportal.nousresearch.com)r   r   rŽ   )r,  s   &r1   r]  r]  ª  s%   € Ü�J×9Ð9Ô"9Ó:×CÑC×`Ð`ÐG`Ð`r3   rÄ   )rð   r>  r8  rÕ   r9  r‹   r:  rÿ   rÖ   rK  rM  rN  rO  rP  )ŒÚ__conditional_annotations__r‚  Ú
__future__r   ÚloggingrE   r_   rY   Ú	threadingrã   r:  Ú
contextlibr   r   r   r   r   Úpathlibr   Útypingr	   r
   r   r   r   r   r   Úurllib.parser   Úhermes_cli.auth_codexr   Úhermes_cli.auth_constantsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   Úhermes_cli.guest_handoffr#   r$   r%   r&   r²   r'   Ú	getLoggerr]   r:   r<   rJ   rb   rm   ru   Ú__annotations__rÓ   rv   r€   r†   r‘   r’   r—   r    rª   r•   r·   r¿   rÌ   ræ   rì   rï   ró   rú   rþ   r  r  r  r  r$  Úlocalr1  r  r+  r3  r7  r@  rF  rR  r\  r=  rn  r‡  r�  rœ  r¶  rÔ  rÙ  rÝ  rà  rè  rñ  r   r  r  r¡  r  r#  r1  r3  r”  r‹  r«  r¾  rÂ  rË  rÏ  rÕ  rÜ  rÛ  rÚ  rÝ  rç  r  r  r  r;  rA  rI  rd  r]  )rg  s   @r1   Ú<module>ru     s»  øðôõ #ã Û Û Û 	Û Û Û ß /ß ,Ñ ,Ý ß P× PÑ PÝ !Ý /÷*÷ *÷ *÷ *õ *÷ UÓ TçÝ.ð 
×	Ò	Ð,Ó	-€àDÐ ðYÈ÷ YõYð[¸T÷ [õUð ��~ tÐ-CÀTØ˜DÐ"4°dÐ<SÐUYð0[Ð ˜nó [ñ ,5Ð6LÐ5MÓ+NÐ ˜.Ó Nõ]õKõ:ñ 1:Ø$à"ð;$ó 1%Ð ˜~ó %õ
Lõ&õ4õ8	Tõkõõ&ð_Ø $ð_Ø8<ð_à:÷_ð&\Ø $ð\Ø8<ð\à:÷\õMð1ÐTX÷ 1õ4÷QðdØ;?÷dð(	GØ26ð	GØUY÷	Gñ &/°Ð>TÐ/UÓ%VÐ "õ[ð .Ð Ø$Ÿ?š?Ó,Ð õ0õð( Ø5Nö ó ðõ$Að
FÐ õõ&-õ$õ:+õ0Hõ#õL(õ,ð ¸d÷ õD<8õ~ð$6à(,÷6õ,-õõð*ØGKð*à÷*õ<6ð)à2:ð)àI[ð)ð "&ð)ð DHð)ð  $ð	)ð LPð	)ð
 "ð)ð
 ?Cð)ð
 `dð)ð  ð)ð HL÷)ð2*Ø59ð*ØQVð*àGK÷*ðZZÈd÷ Zõ(Uõ"?÷JN8ñ N8ðbØ $ðØAEðà#ðà;@ðð )-÷ð27CØ $ð7CØAEð7Cà#ð7Cà;@ð7Cð )-÷7CõtJõ')õT,õ&#õL
õð: Ð Ø"Ð Ø Ð õ ð4.]ð FJ÷.]ðbKØ(,ðKØRVðKà#ðKà<@ðKàW[ðKð "ðKð 5:ðKð W[ðKð =A÷	Kõ\*ð%UØ ð%UØ;?ð%Uà<@÷%UõPNõbõ:	%õG÷Tar3   