Ë
    âß²j�ß  ã                  óÎ  — U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
 ddlmZ ddlmZmZmZmZmZmZmZ ddlmZmZmZmZmZmZmZmZmZmZm Z  ddl!m"Z" erdd	l#m$Z$  ejJ                  d
«      Z&dZ'dZ(dZ)dLd„Z*dMd„Z+dNd„Z,dOd„Z-dPd„Z.dLd„Z/	 	 	 	 	 	 	 	 dQd„Z0dRd„Z1ddœdSd„Z2	 dT	 	 	 	 	 	 	 	 	 dUd„Z3	 dVdddœ	 	 	 	 	 	 	 	 	 	 	 dWd„Z4	 dT	 	 	 	 	 dXd„Z5ddddœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dYd„Z6d Z7dZd!„Z8d[d"„Z9d\d#„Z:d$Z; G d%„ d&e jx                  «      Z=d]d'„Z>d^d(„Z?d_d)„Z@d`d*„ZAd+d,œ	 	 	 	 	 	 	 dad-„ZBdbd.„ZCdcd/„ZDddedd0œ	 	 	 	 	 	 	 	 	 ddd1„ZEded2„ZFdfd3„ZGd4ZHi ZId5eJd6<    ej–                  «       ZLdgd7„ZMdhd8„ZNdeHd9œ	 	 	 	 	 	 	 did:„ZOeHd;œ	 	 	 	 	 	 	 djd<„ZPdkd=„ZQdTdld>„ZRdmd?„ZSdnd@„ZTdodA„ZUdLdB„ZVddCœdpdD„ZWdEdFœdqdG„ZXdrdH„ZY	 	 	 	 	 	 	 	 	 	 dsdI„ZZ	 	 	 	 	 	 	 	 dtdJ„Z[dudK„Z\y)vaÍ  OpenAI Codex OAuth: token store, refresh, quota probe, device-code login.

Tokens live in ~/.hermes/auth.json, NOT ~/.codex/: Hermes keeps its own Codex OAuth session
separate from the Codex CLI / VS Code extension so one app's refresh-token rotation cannot
invalidate the other's session.

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)Úsuppress)ÚPath)ÚTYPE_CHECKINGÚAnyÚDictÚIteratorÚListÚOptionalÚTuple)Ú_decode_jwt_claimsÚAUTH_LOCK_TIMEOUT_SECONDSÚ	AuthErrorÚ'CODEX_ACCESS_TOKEN_REFRESH_SKEW_SECONDSÚCODEX_OAUTH_CLIENT_IDÚCODEX_OAUTH_TOKEN_URLÚCODEX_OAUTH_USER_AGENTÚCODEX_RATE_LIMITED_CODEÚDEFAULT_CODEX_BASE_URLÚ
_codex_errÚhttpx)Ú	env_float)ÚProviderConfigzhermes_cli.authzGCodex auth is missing access_token. Run `{relogin}` to re-authenticate.zHCodex auth is missing refresh_token. Run `{relogin}` to re-authenticate.z=No Codex credentials stored. Run `{relogin}` to authenticate.c                 ó   — ddl m}   | d«      S )Nr   ©Úoauth_relogin_commandúopenai-codex)Úagent.turn_failure_copyr   r   s    ú:/home/ubuntu/.hermes/hermes-agent/hermes_cli/auth_codex.pyÚ_codex_relogin_commandr    )   s   € Ý=á  Ó0Ð0ó    c                ó<   — ddl m}  || «      }|€dS t        |«      S )zABest-effort parse of a ``Retry-After`` header into whole seconds.r   )Úparse_retry_after_secondsN)Úagent.retry_utilsr#   Úint)Úheadersr#   Úsecondss      r   Ú_parse_retry_after_secondsr(   /   s"   € å;Ù'¨Ó0€GØ�?ˆ4Ð4¬¨G«Ð4r!   c                ó<   — t        | xs d«      j                  «       S )NÚ )ÚstrÚstrip)Úvalues    r   Ú	_strippedr.   6   s   € ÜˆuŠ{˜Ó×!Ñ!Ó#Ð#r!   c                ó(   — ddl m} |D ]  }d| |<   Œ	 y)z?Reset a pool entry's cooldown / last-error metadata to healthy.r   )Ú_POOL_STATUS_FIELDSN)Úhermes_cli.authr0   )Úentryr0   Ústatus_fields      r   Ú_clear_pool_entry_statusr4   :   s   € å3Ø+ò #ˆØ"ˆˆlÒñ#r!   c                óÒ   — t        | «      j                  d«      }t        |t        t        f«      xr6 t	        |«      t        j
                  «       t        dt        |«      «      z   k  S )NÚexpr   )r   ÚgetÚ
isinstancer%   ÚfloatÚtimeÚmax)Úaccess_tokenÚskew_secondsr6   s      r   Ú_codex_access_token_is_expiringr>   A   sO   € Ü
˜\Ó
*×
.Ñ
.¨uÓ
5€CÜ�cœC¤˜<Ó(Òd¬U°3«Z¼D¿I¹I»KÌ#ÈaÔQTÐUaÓQbÓJcÑ<cÑ-dÐdr!   c                 óx   — t        j                  dd«      j                  «       j                  d«      xs t        S )NÚHERMES_CODEX_BASE_URLr*   ú/)ÚosÚgetenvr,   Úrstripr   © r!   r   Ú_codex_base_urlrF   F   s.   € Ü�9‰9Ð,¨bÓ1×7Ñ7Ó9×@Ñ@ÀÓEÒ_ÔI_Ð_r!   c               ó$   — dt        «       | ||ddœS )Nr   Úchatgpt)ÚproviderÚbase_urlÚapi_keyÚsourceÚlast_refreshÚ	auth_mode)rF   )rK   rL   rM   s      r   Ú_codex_runtime_resultrO   J   s!   € ð #´Ó0AÈgØ¨,ÀYñPð Pr!   c                óx   — ddl m}m} | r |«       5   |«       cddd«       S  |«       S # 1 sw Y    |«       S xY w)zVLoad the auth store, taking the cross-process lock unless the caller already holds it.r   )Ú_auth_store_lockÚ_load_auth_storeN)r1   rQ   rR   )ÚlockrQ   rR   s      r   Ú_load_auth_store_maybe_lockedrT   Q   s;   € çBÙÙÓñ 	&Ù#Ó%÷	&ñ 	&áÓÐ÷	&áÓÐús   ’*ª9T©Ú_lockc                ó4  — ddl m}m} t        | «      } ||d«      }|s*t	        t
        j                  t        «       ¬«      dd¬«      ‚|j                  d«      }t        |t        «      st	        dt        «       › d	�d
d¬«      ‚ ||j                  d«      «      s*t	        t        j                  t        «       ¬«      dd¬«      ‚ ||j                  d«      «      s*t	        t        j                  t        «       ¬«      dd¬«      ‚||j                  d«      dœS )zERead Codex OAuth tokens from Hermes auth store (~/.hermes/auth.json).r   )Ú_load_provider_stateÚ_nonempty_strr   ©ÚreloginÚcodex_auth_missingTÚtokensz)Codex auth state is missing tokens. Run `ú` to re-authenticate.Úcodex_auth_invalid_shaper<   Úcodex_auth_missing_access_tokenÚrefresh_tokenÚ codex_auth_missing_refresh_tokenrM   ©r]   rM   )r1   rX   rY   rT   r   Ú_NO_CREDENTIALS_MSGÚformatr    r7   r8   ÚdictÚ_MISSING_ACCESS_TOKEN_MSGÚ_MISSING_REFRESH_TOKEN_MSG)rV   rX   rY   Ú
auth_storeÚstater]   s         r   Ú_read_codex_tokensrk   Z   s  € çCÜ.¨uÓ5€JÙ  ¨^Ó<€EÙÜÔ,×3Ñ3Ô<RÓ<TÐ3ÓUØ-°tô=ð 	=à�Y‰Y�xÓ €FÜ�fœdÔ#ÜØ7Ô8NÓ8PÐ7QÐQfÐgØ&°ô6ð 	6ñ ˜Ÿ™ NÓ3Ô4ÜÔ2×9Ñ9ÔBXÓBZÐ9Ó[Ø:ÀDôJð 	Já˜Ÿ™ OÓ4Ô5ÜÔ3×:Ñ:ÔCYÓC[Ð:Ó\Ø;ÀTôKð 	Kà¨e¯i©i¸Ó.GÑHÐHr!   c                ó|  — |j                  d«      }|sy|j                  d«      }t        | d«      }|€y|xs i j                  d«      xs d}t        |«      D ]a  }|j                  d«      }	|	dk(  xr! t        |xr |j                  d«      |k(  «      }
|	dk(  s|
sŒD||d<   |r||d<   |r||d<   t	        |«       Œc y)	u"  Mirror a fresh Codex re-auth into the credential_pool OAuth entries.

    ``device_code`` (the singleton-seeded entry from ``hermes setup`` / the model picker) is always
    synced. ``manual:device_code`` (``hermes auth add openai-codex``) is synced only when its
    access_token equals the PREVIOUS singleton token â€” a legacy alias of the singleton; an entry
    with its own token material is an independent account and must be left alone. ``manual:api_key``
    and any other source are independent credentials and are never overwritten by a re-auth.

    See #33000, #39236.
    The original #33538 fix refreshed every ``manual:device_code`` entry unconditionally. That worked when
    ``manual:device_code`` only meant "legacy alias of the singleton", but the same source string is now
    also produced by independent-account additions, and the broad sync silently clobbered distinct accounts
    with the latest-authenticated token pair. The access_token-match check distinguishes the two cases
    without changing the source-string contract.
    r<   Nra   r   rL   zmanual:device_codeÚdevice_coderM   )r7   Ú_pool_entriesÚ_codex_pool_dictsÚboolr4   )ri   r]   rM   Úprevious_singleton_tokensr<   ra   ÚentriesÚprev_atr2   rL   Úis_aliass              r   Ú_sync_codex_pool_entriesru   p   sÜ   € ð$ —:‘:˜nÓ-€LÙØØ—J‘J˜Ó/€MÜ˜J¨Ó7€GØ€Øà(Ò.¨B×3Ñ3°NÓCÒKÀt€GÜ" 7Ó+ò (ˆØ—‘˜8Ó$ˆØÐ1Ñ1ò >´dØÒ<˜Ÿ	™	 .Ó1°WÑ<ó7>ˆà˜-Ò'©8ØØ ,ˆˆnÑÙØ%2ˆE�/Ñ"ÙØ$0ˆE�.Ñ!Ü  Õ'ñ(r!   F)Ú
set_activeÚwrite_throughc               ó"  — ddl m}m}m}m}m}	m}
m} |€ |«       } |d«      5 \  }}}|rt        |«      ni }t        |j                  d«      t        «      r|j                  d«      nd}|j                  | |d¬«       |r5t        |«      j                  «       rt        |«      j                  «       |d<   |d}}|r|� || |«       «      s ||«      |d	}}} |
|d||¬
«       t        || ||¬«        |	||¬«       ddd«       y# 1 sw Y   yxY w)u½  Save Codex OAuth tokens to the auth store the grant was resolved FROM.

    Codex refresh tokens are single-use with rotation-family reuse detection. A profile without its
    own ``providers.openai-codex`` block reads root's grant via the fallback, so a refresh under that
    profile must rotate ROOT's chain â€” singleton AND ``credential_pool`` entries â€” or root keeps the
    consumed refresh token, the next process replays it and OpenAI revokes the whole family
    (#87503). Root-only write-back: a profile copy would shadow root and disable the write-through
    on the next refresh (#74339). Mirrors the xAI source-aware save.

    Only a token REFRESH passes ``write_through=True``: a fresh login or import under a profile
    is the profile's own grant and must not overwrite the root account it was borrowing.
    ``set_active=False`` stores credentials for a side tool (image gen) without making Codex the
    active inference provider.
    r   )Ú_auth_file_pathrR   Ú_provider_state_transactionÚ
_same_pathÚ_save_auth_storeÚ_store_provider_stateÚ
_utc_now_zNr   r]   rH   )r]   rM   rN   ÚlabelF)rv   )rq   ©Útarget_path)r1   ry   rR   rz   r{   r|   r}   r~   rf   r8   r7   Úupdater+   r,   ru   )r]   rM   r   rv   rw   ry   rR   rz   r{   r|   r}   r~   ri   rj   Úsource_pathrq   Útarget_storer�   s                     r   Ú_save_codex_tokensr…   ™   s  € ÷$=÷ =ñ =ð ÐÙ!“|ˆÙ	$ ^Ó	4ð @Ñ8X¸ÀUÈKÙ$”�U”¨"ˆô $.¨e¯i©i¸Ó.AÄ4Ô#HˆE�I‰I�hÔÈdð 	"à�‰˜F°ÈˆÔSÙ”S˜“Z×%Ñ%Ô'Ü  ›Z×-Ñ-Ó/ˆE�'‰NØ$.°�kˆÙ˜[Ð4¹ZÈÑUdÓUfÔ=gñ 5EÀ[Ó4QÐS^Ð`e z˜+ˆLÙ˜l¨N¸EÈjÕYÜ Ø˜& ,ÐJcõ	eá˜°;Õ?÷#@÷ @ñ @ús   ¤CDÄDc                óØ  — ddl m} ddlm} ddlm}m}m}  |«       sy |«       }|r4t        |j                  d«      «      rt        |j                  d«      «      syt        |«      xs d} |d«      5 \  }	}
}|
xs i j                  d	«      }t        |t        «      r|ni }t        |j                  d«      «      xs d|k7  r t        j                  d
| «       	 ddd«       y ||«      }|r8 ||d   «      d|fvr)t        j                  d| t        «       «       	 ddd«       yt        j                  d| «        ||«       ddd«       t        |«      S # 1 sw Y   t        |«      S xY w)aw  Adopt a valid Codex CLI token pair into Hermes auth, if available.

    Automatic adoption only; the interactive import offer in ``_login_openai_codex`` asks first and is
    not subject to ``auth.adopt_external_logins``.

    ``observed_access_token`` is the singleton access_token (or None) the caller saw when it decided
    the credential needs repair. Recovery repairs THAT credential and nothing else (#73667): a Codex
    Desktop/CLI login into another ChatGPT workspace must not replace it silently, and a concurrent
    explicit re-auth must not be overwritten, so the save is a compare-and-swap under the store lock.
    r   )Ú_codex_principal_identity)Úadopt_external_logins_enabled)Ú_import_codex_cli_tokensrz   r…   Nr<   ra   r   r]   zOCodex CLI recovery skipped (%s): the credential was re-authenticated meanwhile.z™Codex CLI recovery refused (%s): the Codex CLI login belongs to a different ChatGPT workspace than the Hermes credential. Run `%s` to re-authenticate it.z3Codex auth recovered from Codex CLI auth.json (%s).)Úagent.credential_poolr‡   Úagent.credential_sourcesrˆ   r1   r‰   rz   r…   r.   r7   r8   rf   ÚloggerÚinfoÚwarningr    )ÚreasonÚobserved_access_tokenr‡   rˆ   r‰   rz   r…   ÚimportedÚobservedÚ_storerj   Ú_sourceÚstoredÚknowns                 r   Ú_recover_codex_tokens_from_clir—   Ä   s[  € õ @ÝFßiÑiÙ(Ô*ØÙ'Ó)€Hñ œ 8§<¡<°Ó#?Ô@Ü˜(Ÿ,™, Ó7Ô8ØÜÐ.Ó/Ò7°4€HÙ	$ ^Ó	4ð %Ñ8P¸ÀÈØ’+˜2×"Ñ" 8Ó,ˆÜ% f¬dÔ3‘¸ˆÜ�f—j‘j Ó0Ó1Ò9°T¸hÒFÜ�K‰KÐiÐkqÔrØ÷%ð %ñ *¨(Ó3ˆÙÑ.¨x¸Ñ/GÓHÐQUÐW\ÐP]Ñ]Ü�N‰NðXàÔ.Ó0ô2ð ÷%ð %ô 	�‰ÐIÈ6ÔRÙ˜8Ô$÷%ô �‹>Ð÷%ô �‹>Ðús   Á4A&EÃ#9EÄ%EÅE))Úrelogin_requiredÚinvalid_json_reloginÚ
strict_strc               óp  ‡— |fdˆfd„}	 | j                  «       }	t        |	t        «      s	|� ||Ž ‚i }	|	j                  d«      }|r#t        |t        «      r|j                  «       nd}nt        |«      }|s ||Ž ‚|	|fS # t        $ r,}
|€|n|} ||d   j                  |
¬«      |d   |«      |
‚d}
~
ww xY w)	aF  Parse a 200 token-refresh response; return ``(payload, stripped access_token)``.

    Each ``(message, code)`` pair keeps the provider's historical wording; ``{exc}`` in
    *invalid_json*'s message is formatted with the JSON error. *strict_str* rejects non-string
    access tokens; otherwise they are ``str()``-coerced.
    c                ó"   •— t        | ‰||¬«      S )N)rI   Úcoder˜   )r   )Úmessager�   r[   rI   s      €r   Ú_errz+_refresh_payload_access_token.<locals>._errù   s   ø€ Ü˜¨8¸$ÐQXÔYÐYr!   Nr   )Úexcé   r<   r*   )rž   r+   r�   r+   r[   rp   Úreturnr   )	ÚjsonÚ	Exceptionre   r8   rf   r7   r+   r,   r.   )ÚresponserI   Úinvalid_jsonÚinvalid_responseÚmissing_accessr˜   r™   rš   rŸ   Úpayloadr    r[   Úaccesss    `           r   Ú_refresh_payload_access_tokenr«   î   sÖ   ø€ ð 7Gö ZðWØ—-‘-“/ˆô �gœtÔ$ØÐ'ÙÐ(Ð)Ð)ØˆØ�[‰[˜Ó(€FÙÜ#-¨f´cÔ#:�—‘”À‰ä˜6Ó"ˆÙÙ�NÐ#Ð#Ø�Fˆ?Ðøô ò WØ&:Ð&BÑ"ÐH\ˆÙ�< ‘?×)Ñ)¨cÐ)Ó2°LÀ±OÀWÓMÐSVÐVûðWús   ‹B  Â 	B5Â	'B0Â0B5)z[SSL:z_ssl.cÚUNEXPECTED_EOFc                ól   ‡— ddl Š| | j                  | j                  f}t        ˆfd„|D «       «      sy	 y)u<  Actionable hint for device-login transport errors that look like TLS middlebox interference.

    OpenSSL 3.5+ advertises post-quantum hybrid groups (e.g. X25519MLKEM768) by default, and some
    intercepting middleboxes reject the resulting larger TLS 1.3 ClientHello â€” while curl, using a
    different TLS stack, still works, so the failure masquerades as a Codex outage (#106384).
    httpx wraps the ``ssl.SSLError`` in a ``ConnectError``/``ConnectTimeout`` whose text usually
    repeats the OpenSSL message; the cause chain is checked too in case it doesn't.
    r   Nc              3  ó„   •‡K  — | ]6  Š‰�2t        ‰‰j                  «      xs t        ˆfd„t        D «       «      –— Œ8 y ­w)Nc              3  ó8   •K  — | ]  }|t        ‰«      v –— Œ y ­w©N)r+   )Ú.0ÚmarkerÚerrs     €r   ú	<genexpr>z._ssl_interop_hint.<locals>.<genexpr>.<genexpr>  s   øè ø€ Ò,cÀF¨V´s¸3³xÔ-?Ñ,cùs   ƒ)r8   ÚSSLErrorÚanyÚ_SSL_TROUBLE_MARKERS)r±   r³   Ússls    @€r   r´   z$_ssl_interop_hint.<locals>.<genexpr>  s<   ùè ø€ ò à˜C˜Oô 	�3˜Ÿ™Ó%Òc¬Ó,cÔNbÔ,cÓ)cÓcñùs   „<A r*   u�   This looks like a TLS handshake failure rather than a Codex outage: some networks reject the larger TLS 1.3 ClientHello that OpenSSL 3.5+ sends by default (post-quantum hybrid groups). Workaround: point OPENSSL_CONF at a config restricting Groups to classic curves (x25519:secp256r1:secp384r1:x448), or test with TLS 1.2 â€” see the Codex note in https://hermes-agent.nousresearch.com/docs/integrations/providers)r¸   Ú	__cause__Ú__context__r¶   )r    Úchainr¸   s     @r   Ú_ssl_interop_hintr¼     sA   ø€ ó à�#—-‘- §¡Ð1€EÜó àôô ð ð	Mðr!   c                óè   — | }t        «       }|�dt        |«      |vrWt        |t        j                  t
        f«      ry|j                  t        |«      «       |j                  }|�t        |«      |vrŒWy)aB  True when *exc* is transport-level (connection/TLS/socket) and safe to retry.

    httpx raises ``httpx.TransportError`` subclasses wrapping the original ``ssl``/``socket``
    error as ``__cause__``, so both spellings count. Anything else (decode errors, bugs) is
    not a network blip and must surface immediately.
    TF)ÚsetÚidr8   r   ÚTransportErrorÚOSErrorÚaddr¹   )r    r³   Úseens      r   Ú_is_transient_transport_errorrÄ   ,  sh   € ð $'€CÜ“U€DØ
ˆ/œb ›g¨TÑ1Ü�cœE×0Ñ0´'Ð:Ô;ØØ�‰”�C“ÔØ�m‰mˆð	 ˆ/œb ›g¨TÒ1ð
 r!   c          	     ój  — d\  }}	 	 t        t        j                  d«      ¬«      5 } |j                  | fi |¤Žcddd«       S # 1 sw Y   nxY wnc# t        $ rW}||k(  st        |«      s#t        |d   › d|› t        |«      › �|d   «      |‚t        j                  |«       |dz  }Y d}~nd}~ww xY wŒ®)ad  One 15s POST for the device-login flow; transport errors become ``_codex_err(*failure)``.

    A transient transport blip (a dropped connection mid-flow) is retried twice with a small
    linear backoff before failing: losing the token exchange to a single SSL EOF wastes a
    device-code approval the user already completed in the browser (#114610).
    )r¡   é   ç      .@©ÚtimeoutNr   z: r¡   )
Ú_codex_http_clientr   ÚTimeoutÚpostr¤   rÄ   r   r¼   r:   Úsleep)ÚurlÚfailureÚkwargsÚattemptÚattemptsÚclientr    s          r   Ú_codex_login_postrÔ   =  sÅ   € ð Ñ€GˆXØ
ð	Ü#¬E¯M©M¸$Ó,?Ô@ð 2ÀFØ"�v—{‘{ 3Ñ1¨&Ñ1÷2÷ 2ò 2úð 2øäò 	Ø˜(Ò"Ô*GÈÔ*LÜ Ø˜q‘z�l " S EÔ*;¸CÓ*@Ð)AÐBÀGÈAÁJóPØUXðYä�J‰J�wÔØ�q‰L�Gûð	úð	 s.   ˆA §Aº	A ÁAÁ	A Á	B1ÁAB,Â,B1i   c                  ó(   — e Zd ZdZdd„Zdd„Zdd„Zy)	Ú_CappedByteStreamzíBody stream that raises once more than ``_CODEX_AUTH_BODY_MAX_BYTES`` came off the wire.

    httpx type-checks ``response.stream`` against ``SyncByteStream``, so the cap has to be a
    stream subclass rather than a bare generator.
    c                ó6   — ||j                   c| _        | _        y r°   )ÚstreamÚ	_responseÚ_raw)Úselfr¥   s     r   Ú__init__z_CappedByteStream.__init__[  s   € Ø$,¨h¯o©oÐ!ˆŒ˜�	r!   c              #  óü   K  — d}| j                   D ]g  }|t        |«      z  }|t        kD  rJ| j                  «        t	        d| j
                  j                  j                  › dt        dz  › d�dd¬«      ‚|–— Œi y ­w)	Nr   zCodex auth response from z
 exceeded i   z KiB; refusing to parse it.Úcodex_auth_response_too_largeFrZ   )rÚ   ÚlenÚ_CODEX_AUTH_BODY_MAX_BYTESÚcloser   rÙ   rÎ   Úhost)rÛ   ÚtotalÚchunks      r   Ú__iter__z_CappedByteStream.__iter__^  s‡   è ø€ ØˆØ—Y‘Yò 	ˆEØ”S˜“ZÑˆEØÔ1Ò1Ø—
‘
”Ü Ø/°·±×0BÑ0B×0GÑ0GÐ/HÈ
Ü1°TÑ9Ð:Ð:UðWà3¸UôDð Dð ‹Kñ	ùs   ‚A:A<c                ó8   — | j                   j                  «        y r°   )rÚ   rá   )rÛ   s    r   rá   z_CappedByteStream.closej  s   € Ø�	‰	�‰Õr!   N©r¥   ú'httpx.Response'r¢   ÚNone)r¢   zIterator[bytes])r¢   ré   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rÜ   rå   rá   rE   r!   r   rÖ   rÖ   T  s   „ ñó>ó
ôr!   rÖ   c                ó$   — t        | «      | _        y)as  httpx response hook: refuse to buffer an auth body above ``_CODEX_AUTH_BODY_MAX_BYTES``.

    Runs before ``client.post()`` reads the body, so a hostile or broken endpoint/proxy answering
    200 with megabytes of "JSON" is cut off at the cap instead of being fully buffered and parsed
    (#55253). Same cap for every status: error bodies are small diagnostics too.
    N)rÖ   rØ   )r¥   s    r   Ú_cap_codex_response_bodyrï   n  s   € ô (¨Ó1€H…Or!   c                 ó¨   — t        j                  dddt        gii| ¤Ž}t        t        «      5  ddlm}  ||«       ddd«       |S # 1 sw Y   |S xY w)a  Build an ``httpx.Client`` for Codex OAuth/probe endpoints with Happy-Eyeballs racing and a
    1 MiB response-body cap (``_cap_codex_response_body``).

    A host advertising AAAA records but blackholing IPv6 makes each serial connect eat the full
    timeout before IPv4 is tried (same failure mode as the chat transport). Best-effort: if the
    racing backend can't be installed (mocked client in tests), serial connect behavior remains.

    Same broken-IPv6 failure mode as the chat transport (#13834): a host that advertises AAAA records but
    blackholes IPv6 makes each serial connect attempt eat the full connect timeout before IPv4 is tried, so
    token refresh / device login / usage probes time out where the official Codex CLI (which races families
    per RFC 8305) works.
    Úevent_hooksr¥   r   )Úenable_happy_eyeballs_on_clientNrE   )r   ÚClientrï   r   r¤   Úagent.process_bootstraprò   )rÐ   rÓ   rò   s      r   rÊ   rÊ   x  sU   € ô �\‰\ÑY zÔ4LÐ3MÐ&NÐYÐRXÑY€FÜ	”)Ó	ñ 0ÝKÙ'¨Ô/÷0ð €M÷0ð €Mús   ®AÁAc                ó:   — | �d| › d�nd}t        |t        d¬«      S )Nz2Codex provider quota exhausted (429); retry after zs. Credentials are still valid.zfCodex provider quota exhausted (429). Credentials are still valid; retry after the usage limit resets.FrZ   )r   r   )Úretry_afterrž   s     r   Ú_codex_quota_exhausted_errorr÷   Œ  s:   € ð Ð"ð =¸[¸Mð J'ñ 	'ð	.ð	 ô �gÔ6ÀÔFÐFr!   c                ó¾  — ddl m} d}d| j                  › d�}	 | j                  «       }t	        |t
        «      rá|j                  d«      }t	        |t
        «      ri|j                  d«      xs |j                  d«      } ||«      r|j                  «       }|j                  d	«      } ||«      rkd
|j                  «       › �}nW ||«      rO|j                  «       }|j                  d«      xs |j                  d	«      } ||«      rd
|j                  «       › �}|dk(  rdt        «       › d�}|dv xs | j                  dv }	t        |||	¬«      S # t        $ r Y Œ@w xY w)zFDecode a non-200 Codex token-refresh response into a shaped AuthError.r   )rY   Úcodex_refresh_failedz'Codex token refresh failed with status ú.Úerrorr�   Útyperž   zCodex token refresh failed: Úerror_descriptionÚrefresh_token_reusedz£Codex refresh token was already consumed by another client (e.g. Codex CLI or VS Code extension). Run `codex` in your terminal to generate fresh tokens, then run `r^   >   Úinvalid_grantÚinvalid_tokenÚinvalid_requestrþ   >   é‘  é“  rZ   )r1   rY   Ústatus_coder£   r8   rf   r7   r,   r¤   r    r   )
r¥   rY   r�   rž   r³   Úerr_objÚnested_codeÚ
nested_msgÚerr_descr˜   s
             r   Ú_codex_refresh_failure_errorr	  –  sm  € å-Ø!€DØ7¸×8LÑ8LÐ7MÈQÐO€GðØ�m‰m‹oˆÜ�cœ4Ô Ø—g‘g˜gÓ&ˆGä˜'¤4Ô(Ø%Ÿk™k¨&Ó1ÒH°W·[±[ÀÓ5H�Ù  Ô-Ø&×,Ñ,Ó.�DØ$Ÿ[™[¨Ó3�
Ù  Ô,Ø <¸Z×=MÑ=MÓ=OÐ<PÐQ‘Gá˜wÔ'Ø—}‘}“�ØŸ7™7Ð#6Ó7ÒM¸3¿7¹7À9Ó;M�Ù  Ô*Ø <¸X¿^¹^Ó=MÐ<NÐO�Gð Ð%Ò%ðô 0Ó1Ð2Ð2GðIð 	ð 	Ð]Ð]ò 	.Ø×Ñ :Ð-ð ô �g˜tÐ-=Ô>Ð>øô ò Ùðús   šDE Å	EÅEg      4@©Útimeout_secondsc          
     óž  — ddl m}m} ~  ||«      s*t        t        j                  t        «       ¬«      dd¬«      ‚t        t        j                  t        dt        |«      «      «      dt        dœ¬	«      5 }|j                  t        d
did|t        dœ¬«      }ddd«       j                   dk(  rt#        t%        t'        |dd«      «      «      ‚|j                   dk7  rt)        |«      ‚t+        |dddd¬«      \  }}||j-                  «        |«       dœ}	|j/                  d«      }
 ||
«      r|
j-                  «       |	d<   |	S # 1 sw Y   Œ«xY w)z>Refresh Codex OAuth tokens without mutating Hermes auth state.r   )rY   r~   rZ   rb   Tç      @úapplication/json)ÚAcceptú
User-Agent)rÉ   r&   úContent-Typeú!application/x-www-form-urlencodedra   )Ú
grant_typera   Ú	client_id)r&   ÚdataNé­  r&   éÈ   r   )z*Codex token refresh returned invalid JSON.Úcodex_refresh_invalid_json)z6Codex token refresh response was missing access_token.Ú"codex_refresh_missing_access_token)rI   r§   r¦   r¨   )r<   ra   rM   )r1   rY   r~   r   rh   re   r    rÊ   r   rË   r;   r9   r   rÌ   r   r   r  r÷   r(   Úgetattrr	  r«   r,   r7   )r<   ra   r  rY   r~   rÓ   r¥   Úrefresh_payloadÚrefreshed_accessÚupdatedÚnext_refreshs              r   Úrefresh_codex_oauth_purer  ½  s`  € ÷ :ØÙ˜Ô'ÜÔ3×:Ñ:ÔCYÓC[Ð:Ó\Ø;ÀTôKð 	Kä	Ü—‘œc #¤u¨_Ó'=Ó>Ó?Ø-Ô=SÑTô
Vð 5àY_Ø—;‘;Ü!¨NÐ<_Ð+`à-ÀÜ2ñ4ð ó 5ˆ÷5ð ×Ñ˜sÒ"ô +Ü&¤w¨x¸ÀDÓ'IÓJóLð 	Là×Ñ˜sÒ"Ü*¨8Ó4Ð4Ü(EØ˜>¸DØað2ô)3Ñ%€OÐ%ð )¸=×;NÑ;NÓ;PÙ"›ñ&€Gð #×&Ñ& Ó7€LÙ�\Ô"Ø#/×#5Ñ#5Ó#7ˆ�Ñ Ø€N÷75ð 5ús   Á6#EÅEc           
     ó\  — ddl m}m}m} t	        t        t        «      t        |«      dz   «      } |d|«      5 \  }}}|xs i j                  d«      }	t        |	t        «      r|	ni }	t        |	j                  d«      «      t        |	j                  d«      «      }}
|
rF|rD|t        | j                  d«      «      k7  r't        j                  d«       i | ¥|
|d	œ¥cd
d
d
«       S 	  |t        | j                  dd«      xs d«      t        | j                  dd«      xs d«      |¬«      }i | ¥|d   |d   d	œ¥} ||d¬«       d
d
d
«       |S # t        $ rI}t        |dd«      s‚ t!        dt        |dd
«      xs d› �|
xs d
¬«      }|s‚ |cY d
}~cd
d
d
«       S d
}~ww xY w# 1 sw Y   S xY w)a  Refresh Codex access token using the refresh token.

    The whole re-read -> endpoint POST -> write-back runs inside the SOURCE store's transaction:
    two profiles borrowing the same root grant otherwise both submit the same single-use refresh
    token (each holds only its own profile lock) and OpenAI revokes the family. A waiter that
    finds root already rotated by its peer adopts the stored pair instead of replaying the
    consumed token. Both locks wait out a full endpoint timeout so the waiter adopts, not times out.
    r   )rz   r…   r  r  r   r]   r<   ra   uK   Codex refresh token already rotated by a peer â€” adopting the stored pair.©r<   ra   Nr*   r
  r˜   Fzrefresh_token rejected: r�   Ú
auth_error©r�   T)rw   )r1   rz   r…   r  r;   r9   r   r7   r8   rf   r.   rŒ   r�   r+   r   r  r—   )r]   r  rz   r…   r  Úlock_timeoutr“   rj   r”   r•   Ú	stored_atÚ	stored_rtÚ	refreshedr    r‘   Úupdated_tokenss                   r   Ú_refresh_codex_auth_tokensr)  ã  sÂ  € ÷ jÑiÜ”uÔ6Ó7¼¸Ó9OÐRUÑ9UÓV€LÙ	$ ^°\Ó	Bð ?ÑF^ÀvÈuÐV]Ø’+˜2×"Ñ" 8Ó,ˆÜ% f¬dÔ3‘¸ˆÜ(¨¯©°NÓ)CÓDÄiÐPV×PZÑPZÐ[jÓPkÓFl�9ˆ	Ù™ y´I¸f¿j¹jÈÓ>YÓ4ZÒ'ZÜ�K‰KÐeÔfØT�fÐT¨iÈ)ÒT÷?ñ ?ð	Ù0Ü�F—J‘J˜~¨rÓ2Ò8°bÓ9¼3¸v¿z¹zÈ/Ð[]Ó?^Ò?dÐbdÓ;eØ /ô1ˆIð$9Øð9Ø&/°Ñ&?Ø& Ñ7ò9ˆñ 	˜>¸Õ>÷=?ð> Ðøô) ò 	ô ˜3Ð 2°EÔ:ØÜ5Ø*¬7°3¸ÀÓ+EÒ+UÈÐ*VÐWØ&/Ò&7°4ô9ˆHñ ØØŒO÷3?ñ ?ûð	ú÷?ð> Ðús=   ¹B F!Ã$AEÄ)F!Å	FÅ5FÆ
FÆF!ÆFÆF!Æ!F+c                 ó>  — ddl m}  t        j                  dd«      j	                  «       xs  t        t        j                  «       dz  «      }t        |«      j                  «       dz  }|j                  «       sy	 t        j                  |j                  d¬	«      «      j                  d
«      }t        |t        «      r"|j                  d«      r|j                  d«      sy | |d   d«      rt         j#                  d|«       yt        |«      S # t$        $ r Y yw xY w)zWRead ~/.codex/auth.json (Codex CLI file) tokens if valid and not expired; never writes.r   )r>   Ú
CODEX_HOMEr*   z.codexz	auth.jsonNz	utf-8-sig)Úencodingr]   r<   ra   u7   Codex CLI tokens at %s are expired â€” skipping import.)r1   r>   rB   rC   r,   r+   r   ÚhomeÚ
expanduserÚis_filer£   ÚloadsÚ	read_textr7   r8   rf   rŒ   Údebugr¤   )r>   Ú
codex_homeÚ	auth_pathr]   s       r   r‰   r‰     sê   € å?Ü—‘˜<¨Ó,×2Ñ2Ó4ÒS¼¼D¿I¹I»KÈ(Ñ<RÓ8S€JÜ�ZÓ ×+Ñ+Ó-°Ñ;€IØ×ÑÔØðÜ—‘˜I×/Ñ/¸Ð/ÓEÓF×JÑJÈ8ÓTˆÜ˜6¤4Ô(¨V¯Z©Z¸Ô-GØ—J‘J˜Ô/Øñ +¨6°.Ñ+AÀ1ÔEÜ�L‰LÐRÐT]Ô^ØÜ�F‹|ÐøÜò Ùðús   Á;A&D Ã""D Ä
D Ä	DÄD)Úforce_refreshÚrefresh_if_expiringÚrefresh_skew_secondsÚ	read_onlyc                ó„  ‡ ‡‡‡‡— ddl m}mŠm}m} d}d}d}		 ‰r
 |d¬«      }ne |«       5  ddl m}
m}  | |
«       d«      xs i j                  d«      }t        |t        «      r|j                  d	«      nd}	 |d¬«      }ddd«       |�€?t        «       }|r2‰ r0‰s.ddlm}  |d«      j%                  |¬«      }|�|j&                  nd}|rt)        |dd¬«      S t+        «       }|r·‰sDt-        |«      r9t.        j1                  d«       t3        «        t        «       }|rt)        |dd¬«      S |j                  d«      }t        |t4        t6        f«      xr |t9        j8                  «       kD  }t;        |r$t5        |t9        j8                  «       z
  «      «      ‚d«      ‚|�|‚t=        t>        jA                  tC        «       ¬«      dd¬«      ‚t        |d   «      }tE        |j                  d	«      «      }tG        dd«      }dˆˆ ˆˆˆfd„} ||«      r‹tI        t7        tJ        «      |dz   «      } ||¬«      5   |d¬«      }t        |d   «      } |tE        |j                  d	«      «      «      rtM        ||«      }tE        |j                  d	«      «      }ddd«       t)        |d|j                  d«      ¬«      S # 1 sw Y   �Œ:xY w# t        $ rc}|}‰sT|j                  rH|j                  d
v r:t        t        |j                  xs d«      |	¬«      }|r||j                  d«      dœ}Y d}~�Œ¤d}~ww xY w# 1 sw Y   Œ¢xY w) u  Resolve runtime credentials from Hermes's own Codex token store.

    ``read_only=True`` (status / doctor / pickers) reports the stored state as-is: no Codex CLI
    adoption, no token refresh, no auth-store write â€” and it wins over ``force_refresh``. A
    diagnostic that silently imports another program's rotating refresh token or spends one is a
    mutation the user never asked for (#68004).

    Falls back to the credential pool when the singleton (``providers.openai-codex.tokens``) has no
    usable access_token but the pool (``credential_pool.openai-codex``) does.

    This closes the divergence between the chat path (singleton-only via this function) and the auxiliary
    path (pool-first via ``_read_codex_access_token``). Without this fallback, a user whose tokens live only
    in the pool â€” for example after a manual pool seed, a partial re-auth, or pool-only restoration from a
    backup â€” gets a bare HTTP 401 ``Missing Authentication header`` from the wire instead of a usable
    credential. See issue #32992.
    r   )rQ   r>   Ú_probe_codex_quota_restoredrk   NFrU   )rR   rX   r   r]   r<   >   r_   r`   rb   r"  r#  rM   rc   )Ú	load_pool)Úapi_key_hintr*   Úcredential_pool)rL   rM   uB   Codex quota restored upstream â€” clearing stale pool cooldown(s).Úreset_atrZ   r\   TÚ$HERMES_CODEX_REFRESH_TIMEOUT_SECONDSé   c                ó>   •— ‰ryt        ‰«      xs ‰xr	  ‰| ‰«      S )NF)rp   )Útokenr>   r5  r8  r6  r7  s    €€€€€r   Ú_should_refreshz:resolve_codex_runtime_credentials.<locals>._should_refreshx  s.   ø€ ÙØÜ�MÓ"ò bØÒ`Ñ$CÀEÐK_Ó$`ð	br!   r  r
  zhermes-auth-store)rB  r+   r¢   rp   )'r1   rQ   r>   r:  rk   rR   rX   r7   r8   rf   r   r˜   r�   r—   r+   Ú_pool_codex_access_tokenrŠ   r;  Útry_refresh_matchingÚruntime_api_keyrO   Ú_codex_pool_rate_limit_statusÚ&_probe_codex_pool_entry_quota_restoredrŒ   r�   Ú clear_codex_pool_quota_cooldownsr%   r9   r:   r÷   r   rd   re   r    r.   r   r;   r   r)  )r5  r6  r7  r8  rQ   r:  rk   Ú
read_errorr  r’   rR   rX   Úrawr    r‘   Ú
pool_tokenr;  r'  Úpool_rate_limitr>  Ú	in_futurer]   r<   Úrefresh_timeout_secondsrC  r$  r>   s   ````                      @r   Ú!resolve_codex_runtime_credentialsrP  &  s&  ü€ ÷(ó ð '+€JØ€DØ"€HðZÙñ &¨EÔ2‰Dá!Ó#ñ 7÷ SÙ+Ñ,<Ó,>ÀÓOÒUÐSU×ZÑZÐ[cÓd�Ü6@ÀÄdÔ6K˜3Ÿ7™7 >Ô2ÐQU�Ù)°Ô6�÷7ð  �|Ü-Ó/ˆ
Ù™-±	å7Ù! .Ó1×FÑFÐT^ÐFÓ_ˆIØ6?Ð6K˜×2Ò2ÐQSˆJÙÜ(¨Ð<MÐ\`ÔaÐaÜ7Ó9ˆÙñ
 Ô!GÈÔ!XÜ—‘Ð`ÔaÜ0Ô2Ü5Ó7�
ÙÜ0Ø"Ð+<È4ôQð Qà&×*Ñ*¨:Ó6ˆHÜ" 8¬c´5¨\Ó:ÒU¸xÌ$Ï)É)Ë+Ñ?UˆIÜ.Éi¬s°8¼d¿i¹i»kÑ3IÓ/JÓbÐbÐ]aÓbÐbØÐ!ØÐÜÔ,×3Ñ3Ô<RÓ<TÐ3ÓUØ-°tô=ð 	=ä�$�x‘.Ó!€FÜ˜VŸZ™Z¨Ó7Ó8€LÜ'Ð(NÐPRÓSÐ÷bñ bñ �|Ô$äœ5Ô!:Ó;Ð=TÐWZÑ=ZÓ[ˆÙ¨lÔ;ñ 	AÙ%¨EÔ2ˆDÜ˜$˜x™.Ó)ˆFÙœy¨¯©°NÓ)CÓDÔEÜ3°FÐ<SÓT�Ü$ V§Z¡Z°Ó%?Ó@ˆL÷	Aô !ØÐ0¸t¿x¹xÈÓ?WôYð Y÷A7ñ 7ûô ò ZØˆ
Ù˜S×1Ò1°c·h±hð C(ñ 7(ô 6Ü�C—H‘HÒ, Ó-ÀXôOˆHáØ"*¸H¿L¹LÈÓ<XÑY�ÿùðZú÷f	Að 	Aús=   ™K ¬AJ:ÂK È7AL6Ê:KÊ?K Ë	L3ËAL.Ì.L3Ì6L?c                óÞ   ‡‡— t        |xs d«      j                  «       t        |xs d«      j                  «       cŠŠ| dk(  xs* t        ˆfd„dD «       «      xs t        ˆfd„dD «       «      S )zITrue when persisted pool-entry error metadata describes a 429/quota stop.r*   r  c              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wr°   rE   )r±   ÚkÚreason_ls     €r   r´   z._is_codex_rate_limit_shaped.<locals>.<genexpr>�  s   øè ø€ ÒM ˆq�HŒ}ÑMùó   ƒ)Ú
rate_limitÚusage_limitÚquotac              3  ó&   •K  — | ]  }|‰v –— Œ
 y ­wr°   rE   )r±   rS  Ú	message_ls     €r   r´   z._is_codex_rate_limit_shaped.<locals>.<genexpr>‘  s   øè ø€ ÒN !ˆq�IŒ~ÑNùrU  )z
rate limitzusage limitrX  )r+   Úlowerr¶   )r�   r�   rž   rZ  rT  s      @@r   Ú_is_codex_rate_limit_shapedr\  ‹  sj   ù€ ä˜fšl¨Ó+×1Ñ1Ó3´S¸ºÀBÓ5G×5MÑ5MÓ5OÐ€Hˆià�‰ò 	OÜÓMÐ&LÔMÓMò	OäÓNÐ'MÔNÓNðPr!   c                ó¢   — | j                  d«      dk(  xr: t        | j                  d«      | j                  d«      | j                  d«      «      S )zFPool entry frozen by a 429/quota stop (as opposed to an auth failure).Úlast_statusÚ	exhaustedÚlast_error_codeÚlast_error_reasonÚlast_error_message)r7   r\  )r2   s    r   Ú_entry_is_rate_limit_exhaustedrc  ”  sK   € à�9‰9�]Ó# {Ñ2ò )Ô7RØ�	‰	Ð#Ó$ e§i¡iÐ0CÓ&DØ�	‰	Ð&Ó'ó8)ð )r!   i,  z'Dict[str, Tuple[float, Optional[bool]]]Ú_codex_quota_probe_cachec                ól   — t        j                  | j                  d«      «      j                  «       d d S )Nzutf-8é   )ÚhashlibÚsha256ÚencodeÚ	hexdigest)rB  s    r   Ú_codex_quota_probe_cache_keyrk  ¢  s*   € Ü�>‰>˜%Ÿ,™, wÓ/Ó0×:Ñ:Ó<¸S¸bÐAÐAr!   c                ó®   — t        | «      j                  d«      xs
 t        «       }|j                  d«      r|dt	        d«        }|d|v rdndz   }|dz   S )a7  Resolve the Codex usage endpoint for a probe.

    Mirrors the Codex CLI's PathStyle split: base URLs containing ``/backend-api`` use the ChatGPT
    ``/wham/usage`` path, everything else ``/api/codex/usage``. Kept local so this low-level auth
    module does not import the auxiliary account-usage module.
    rA   z/codexNz/backend-apiz/whamz
/api/codexz/usage)r.   rD   rF   Úendswithrß   )rJ   Ú
normalizedÚprefixs      r   Ú_codex_usage_probe_urlrp  ¦  s`   € ô ˜8Ó$×+Ñ+¨CÓ0ÒE´OÓ4E€JØ×Ñ˜8Ô$ØÐ 0¤3 x£= .Ð1ˆ
Ø n¸
Ñ&B™7ÈÑU€FØ�HÑÐr!   )rJ   Úmin_interval_secondsc               ón  — ddl m}m} t        | «      }|rt	        |«      syt        |«      }t        j                  «       }t        5  |j                  |«      }|�||d   z
  |k  r|d   cddd«       S |df||<   ddd«       d}		 ddl
m}
 d|› �ddd	œ |
|«      ¥}t        d
¬«      5 }|j                  t        |«      |¬«      }ddd«       j                  dk(  rÝ|j                  «       xs i }|j                  d«      xs i g|j                  d«      xs g D �cg c]'  }t!        |t"        «      r|j                  d«      xs i ‘Œ) c}z   }d}|D ]]  }dD ]V  }|j                  |«      xs i j                  d«      }t!        |t$        t&        f«      sŒ>t)        |xs dt'        |«      «      }ŒX Œ_ |�|dk  }	n|j                  dk(  rd}	t        5  ||	f||<   ddd«       |	S # 1 sw Y   �ŒjxY w# 1 sw Y   �Œ,xY wc c}w # t*        $ r t,        j/                  dd¬«       d}	Y Œ[w xY w# 1 sw Y   |	S xY w)zÃAsk the Codex usage endpoint whether this account's quota is usable again.

    Probes are throttled per access token (module-local cache) so the hot selection path can fire
    this freely.
    r   )rd  rY   Nr¡   )Úcodex_account_headerszBearer r  z	codex-cli)ÚAuthorizationr  r  g      $@rÈ   )r&   r  rV  Úadditional_rate_limits)Úprimary_windowÚsecondary_windowÚused_percentg        g      Y@r  FzCodex quota probe failedT©Úexc_info)r1   rd  rY   r.   r   rk  r:   Ú	monotonicÚ_codex_quota_probe_lockr7   Úagent.codex_headersrs  rÊ   rp  r  r£   r8   rf   r%   r9   r;   r¤   rŒ   r2  )r<   rJ   rq  rd  rY   rB  Ú	cache_keyÚnowÚcachedÚresultrs  r&   rÓ   r¥   r©   ÚextraÚwindowsÚ
worst_usedrV  ÚkeyÚuseds                        r   r:  r:  ´  sn  € ÷ HÜ�lÓ#€Eñ Ô*¨5Ô1ØÜ,¨UÓ3€IÜ
�.‰.Ó
€CÜ	 ñ :Ø)×-Ñ-¨iÓ8ˆØÐ 3¨°©¡?Ð6JÒ"JØ˜!‘9÷:ñ :ð
 03°D¨kÐ  Ñ+÷:ð "€Fðå=à& u gÐ.Ð:LØ%ñGá)>¸uÓ)EðGˆô  ¨Ô-ð 	U°Ø—z‘zÔ"8¸Ó"BÈG�zÓTˆH÷	Uà×Ñ 3Ò&Ø—m‘m“oÒ+¨ˆGð —{‘{ <Ó0Ò6°BÐ7à%Ÿk™kÐ*BÓCÒIÀrö;,àÜ˜e¤TÔ*ð —	‘	˜,Ó'Ò-¨2Ñ-ò;,ñ ,ˆGð +/ˆJØ%ò I�
ØAò I�CØ&ŸN™N¨3Ó/Ò5°2×:Ñ:¸>ÓJ�DÜ! $¬¬e¨Õ5Ü%(¨Ò):°s¼EÀ$»KÓ%H™
ñIðIð
 Ð%Ø# eÑ+‘Ø×!Ñ! SÒ(ØˆFô 
!ñ <Ø/2°F¨mÐ  Ñ+÷<à€M÷M:ñ :ú÷	Uñ 	Uüò;,øô ò Ü�‰Ð/¸$ˆÔ?ØŠðú÷<à€Mús\   Á#G#Á4G#Â#H Â)G0ÃAH Ä,G=Å	AH Æ6H ÇH*Ç#G-Ç0G:Ç5H È"H'È&H'È*H4)rq  c               óÌ  — ddl m} t        | «      t        |«      }}|r|rt        |d«      syt	        |«      }t        j                  «       }t        5  |j                  |«      }|�||d   z
  |k  r
	 ddd«       yddd«       	 t        ||«      S # 1 sw Y   ŒxY w# t        $ r= t        j                  dd¬«       t        5  |df||<   ddd«       Y y# 1 sw Y   Y yxY ww xY w)u  Refresh an EXPIRED stored access token so the quota probe can get a real answer.

    Exhausted pool entries are skipped by the proactive refresh chain (#44799), so by the time
    anything probes with the stored token it has expired; the usage endpoint answers
    ``401 token_expired``, the probe returns None, and the cooldown is kept until
    ``last_error_reset_at`` no matter what happened upstream (top-up, plan upgrade) â€” #89415.
    Returns the rotated token pair (callers MUST persist it: refresh tokens are single-use) or
    None when no refresh was needed/possible. The cooldown itself is left untouched.

    Shares the probe's per-token throttle: a refresh that keeps failing (revoked grant, network
    down) would otherwise POST to the token endpoint on every credential selection, while the
    probe itself is capped at one call per ``min_interval_seconds``. A failed attempt reserves
    the stale token's probe slot, so neither the refresh nor the doomed 401 probe fire again
    until the interval has elapsed.
    r   )rd  Nz$Codex pre-probe token refresh failedTry  )r1   rd  r.   r>   rk  r:   r{  r|  r7   r  r¤   rŒ   r2  )	r<   ra   rq  rd  rB  Úrefreshr~  r  r€  s	            r   Ú"_refresh_expired_codex_probe_tokenr‰  í  sè   € õ$ 9Ü˜|Ó,¬i¸Ó.Fˆ7€EÙ™Ô'FÀuÈaÔ'PØÜ,¨UÓ3€IÜ
�.‰.Ó
€CÜ	 ñ Ø)×-Ñ-¨iÓ8ˆØÐ 3¨°©¡?Ð6JÒ"JØ÷÷ ð ðÜ'¨¨wÓ7Ð7÷ð ûô ò Ü�‰Ð;ÀdˆÔKÜ$ñ 	>Ø36¸°+Ð$ YÑ/÷	>á÷	>áúð	ús6   Á BÂB ÂBÂ&C#ÃCÃC#ÃC	ÃC#ÃC#c                ó  — ddl m}m}m} t	        | j                  d«      «      }t        || j                  d«      «      }|ru|d   }	  |«       5   |«       }t        t        |d«      «      D ]@  }|j                  d«      | j                  d«      k(  sŒ'|j                  |«        ||«        n ddd«       |syt        || j                  d«      ¬«      S # 1 sw Y   Œ(xY w# t        $ r t        j                  dd	¬
«       Y ŒMw xY w)z^``_probe_codex_quota_restored`` for a persisted pool entry, refreshing an expired token first.r   ©rQ   rR   r|   r<   ra   r   r¿   Nz-Failed to persist refreshed Codex pool tokensTry  rJ   )rJ   )r1   rQ   rR   r|   r.   r7   r‰  ro   rn   r‚   r¤   rŒ   r2  r:  )r2   rQ   rR   r|   rB  Úfreshri   Ú
disk_entrys           r   rH  rH    sõ   € çTÑTÜ�e—i‘i Ó/Ó0€EÜ.¨u°e·i±iÀÓ6PÓQ€EÙØ�nÑ%ˆð		YÙ!Ó#ñ Ù-Ó/�
Ü"3´MÀ*ÈnÓ4]Ó"^ò �JØ!—~‘~ dÓ+¨u¯y©y¸«Ó>Ø"×)Ñ)¨%Ô0Ù(¨Ô4Ùð	÷ñ ØÜ& u°u·y±yÀÓ7LÔMÐM÷ð ûô ò 	YÜ�L‰LÐHÐSWˆLÖXð	Yús1   ÁC" ÁACÂCÂ/C" ÃCÃC" Ã" DÄDc                óº  — ddl m}m} ddlm}m}m} d}	  |d«      rdn |«       } ||¬«      5   ||«      }t        t        |d«      «      D ]B  }	| r"t        |	j                  d«      xs d«      | k7  rŒ't        |	«      sŒ3t        |	«       |d	z  }ŒD |r
 |||¬«       ddd«       |S # 1 sw Y   |S xY w# t        $ r t        j                  d
d¬«       Y |S w xY w)aü  Clear rate-limit cooldowns on persisted openai-codex pool entries.

    Called after the upstream quota is KNOWN to be restored (a ``/usage reset`` redemption or a
    positive live probe) so auth.json stops freezing credentials behind a stale
    ``last_error_reset_at``. With *access_token* only the matching entry clears; otherwise every
    rate-limited entry does (a redeemed banked reset restores the whole account; a still-exhausted
    entry just re-freezes with fresh metadata on its next 429).
    r   )Ú_borrowed_single_use_pool_rootÚ_profile_owns_pool_providerr‹  r   Nr€   r<   r*   r¡   z*Failed to clear Codex pool quota cooldownsTry  )rŠ   r�  r�  r1   rQ   rR   r|   ro   rn   r+   r7   rc  r4   r¤   rŒ   r2  )
r<   r�  r�  rQ   rR   r|   ÚclearedÚtargetri   r2   s
             r   rI  rI  (  së   € ÷ bßTÑTØ€GðRñ 5°^ÔD‘ÑJhÓJjˆÙ¨&Ô1ñ 		AÙ)¨&Ó1ˆJÜ*¬=¸À^Ó+TÓUò !�Ù¤C¨¯	©	°.Ó(AÒ(GÀRÓ$HÈLÒ$XØÜ1°%Õ8Ü,¨UÔ3Ø˜q‘L‘Gð!ñ Ù  ¸Õ@÷		Að €N÷		Að €Nûô ò RÜ�‰ÐAÈDˆÕQØ€NðRús5   –B6 °AB)ÂB)ÂB6 Â)B3Â.B6 Â3B6 Â6 CÃCc              #  óL   K  — | xs dD ]  }t        |t        «      sŒ|–— Œ y ­w)NrE   )r8   rf   )rr   r2   s     r   ro   ro   G  s(   è ø€ Ø’˜Bò ˆÜ�eœTÕ"Ø‹Kñùs   ‚$�$c                 óT  — ddl m} m} ddlm} 	 t        j
                  «       }t         |d«      «      D ]Ê  }|j                  d«      } | |«      rt        |«      sŒ( ||j                  d«      «      }|�||kD  sŒG|j                  d«      |j                  d	«      ||j                  d
«      |j                  d«      |j                  «       |j                  d«      |j                  d«      |j                  d«      dœ	c S  	 y# t        $ r t        j                  dd¬«       Y yw xY w)zöReturn metadata for a pool-only Codex credential in quota cooldown.

    Reads through ``read_credential_pool`` so a named profile with no Codex rows of its own sees
    the global-root pool (the per-provider fallback every other pool read uses).r   ©rY   Úread_credential_pool©Ú_parse_absolute_timestampr   r<   Úlast_error_reset_atNr   rM   ra  rb  ra   r¿   rJ   )	r   rM   r>  r�   rž   r<   ra   r¿   rJ   z#Codex pool rate-limit lookup failedTry  )r1   rY   r–  rŠ   r˜  r:   ro   r7   rc  r,   r¤   rŒ   r2  )rY   r–  r˜  r  r2   rB  r>  s          r   rG  rG  M  s  € ÷
 DÝ?ðKÜ�i‰i‹kˆÜ&Ñ';¸NÓ'KÓLò 	7ˆEØ—I‘I˜nÓ-ˆEÙ  Ô'Ô/MÈeÔ/TØÙ0°·±Ð;PÓ1QÓRˆHØÐ 8¨c£>à"ŸY™Y wÓ/ÀÇÁÈ>ÓAZØ (°E·I±IÐ>QÓ4RØ$Ÿy™yÐ)=Ó>ÐPU×P[ÑP[ÓP]Ø%*§Y¡Y¨Ó%?ÀuÇyÁyÐQUÃØ %§	¡	¨*Ó 5ñ7ò 7ñ	7ð øô ò KÜ�‰Ð:ÀTˆÕJØðKús   �A+D Á<BD ÄD Ä D'Ä&D'c                ó’   — | j                  d«      }t        |t        «      r|j                  |«      nd}t        |t        «      r|S dS )zL``auth_store["credential_pool"][provider_id]`` when it is a list, else None.r=  N)r7   r8   rf   Úlist)ri   Úprovider_idÚpoolrr   s       r   rn   rn   g  s>   € à�>‰>Ð+Ó,€DÜ'1°$¼Ô'=ˆd�h‰h�{Ô#À4€GÜ  ¬$Ô/ˆ7Ð9°TÐ9r!   c                 ó`  — ddl m}  ddlm}m} 	 t         |d«      «      D ]d  }|j                  d«      } | |j                  d«      «      }|duxr |t        j                  «       kD  } ||«      sŒQ|rŒT|j                  «       c S  	 y# t        $ r t        j                  dd	¬
«       Y yw xY w)a  First non-empty pool access_token not in an exhaustion cooldown window, else "".

    Fallback for ``resolve_codex_runtime_credentials`` when the singleton has no creds; reads
    through ``read_credential_pool`` so a profile inherits the global-root pool (#34143).
    r   r—  r•  r   r<   r™  Nz!Codex pool fallback lookup failedTry  r*   )rŠ   r˜  r1   rY   r–  ro   r7   r:   r,   r¤   rŒ   r2  )r˜  rY   r–  r2   rB  r>  Úin_cooldowns          r   rD  rD  n  s«   € õ @ßCð
IÜ&Ñ';¸NÓ'KÓLò 	%ˆEØ—I‘I˜nÓ-ˆEñ 1°·±Ð;PÓ1QÓRˆHØ"¨$Ð.ÒI°8¼d¿i¹i»kÑ3IˆKÙ˜UÕ#ªKØ—{‘{“}Ò$ñ	%ð øô ò IÜ�‰Ð8À4ˆÕHØðIús$   �A!B
 Á2B
 Á5B
 ÂB
 Â
 B-Â,B-)Úforce_new_loginc               óò  — ddl m}m}m}m}m}m}m}	m}
 ddl	m
} ~|s… |d|
|dt        d¬«      ry |«       }|rit        d	«       t        d
«        |dd¬«      rI ||«        |	dt        «       «      }t        «        t        d«       t        d«       t        d|› d�«       yt        «         || «      } ||d   |j                  d«      «        |	d|j                  dt        «      «      } |d|d¬«       y)z�OpenAI Codex login: device code by default, browser PKCE when opted in (``--browser`` /
    ``auth.codex_login_flow``). Tokens stored in ~/.hermes/auth.json.r   )r>   r‰   Ú!_offer_existing_oauth_credentialsÚ_print_login_successÚ_prompt_yes_nor…   Ú_update_config_for_providerrP  )Úcodex_oauth_loginr   ÚCodexz?Existing Codex credentials are expired. Starting fresh login...)ÚresolveÚis_expiringÚdisplay_nameÚdefault_base_urlÚexpired_noticeNz:Found existing Codex CLI credentials at ~/.codex/auth.jsonzOHermes will create its own session to avoid conflicts with Codex CLI / VS Code.zCImport these credentials? (a separate login is recommended) [y/N]: Ún)Údefaultz=Credentials imported. Note: if Codex CLI refreshes its token,z<Hermes will keep working independently with its own session.z  Config updated: z (model.provider=openai-codex)r]   rM   rJ   T)Úshow_auth_state)r1   r>   r‰   r¢  r£  r¤  r…   r¥  rP  Úhermes_cli.auth_codex_browserr¦  r   ÚprintrF   r7   )ÚargsÚpconfigr   r>   r‰   r¢  r£  r¤  r…   r¥  rP  r¦  Ú
cli_tokensÚconfig_pathÚcredss                  r   Ú_login_openai_codexr·  „  sÿ   € ÷H÷ Hó Hõ @ØÙÙ,ØÐ$EØ7ÀgÜ3Ø\õ	^ð
 Ù-Ó/ˆ
ÙÜÐNÔOÜÐcÔdÙØUÐ_bõdá" :Ô.Ù9¸.Ì/ÓJ[Ó\�Ü”ÜÐUÔVÜÐTÔUÜÐ*¨;¨-Ð7UÐVÔWØô 
„GÙ˜dÓ#€EÙ�u˜X‘¨¯	©	°.Ó(AÔBÙ-Ø˜Ÿ	™	 *Ô.DÓEóG€Ká˜¨ÀdÖKr!   r*   ©Úduringc               ón   — t        t        | dd«      «      }|�d|› d�nd}t        d|› d|› �t        «      S )zYAuthError for a 429 from OpenAI's device-auth endpoints (throttle, not credential fault).r&   Nz Try again in about zs.z' Wait a minute and run the login again.z7OpenAI is rate-limiting Codex login requests (HTTP 429)zJ. This is a temporary throttle on OpenAI's side, not a credential problem.)r(   r  r   r   )r¥   r¹  rö   Ú	wait_hints       r   Ú_codex_login_rate_limited_errorr¼  ¬  s]   € ô -¬W°X¸yÈ$Ó-OÓP€Kà2=Ð2IÐ
˜{˜m¨2Ñ.Ø6ð ô Ø
AÀ&Àð JSØS\ÐR]ð	_äó!ð !r!   c           
     ó¢  — d}t        d|dz   «      D ]�  }t        | › d�d|iddid¬«      }|j                  d	k7  r nh||k  sŒ0t        t	        |d
d«      «      }t        dt        t        |�|nd|z  «      d«      «      }t        d|› d�«       t        j                  |«       Œ‘ j                  d	k(  rt        |«      ‚|j                  dk7  rt        d|j                  › d�d«      ‚|j                  «       }t        dt        |j                  dd«      «      «      |d<   |j                  dd«      r|j                  dd«      st        dd«      ‚|S )u  Step 1 of the Codex device flow: request a user code, retrying capped on HTTP 429.

    OpenAI rate-limits this request when login is attempted too often from one IP/account â€” retry
    with capped backoff (honoring ``Retry-After``) before surfacing an actionable message.
    é   r¡   z!/api/accounts/deviceauth/usercoder  r  r  )zFailed to request device codeÚdevice_code_request_failed)r£   r&   rÏ   r  r&   Né   é<   z:OpenAI is rate-limiting login requests (429); retrying in zs...r  z$Device code request returned status rú   Údevice_code_request_errorrÆ   ÚintervalÚ5Ú	user_coder*   Údevice_auth_idz-Device code response missing required fields.Údevice_code_incomplete)ÚrangerÔ   r  r(   r  r;   Úminr%   r±  r:   rÍ   r¼  r   r£   r7   )Úissuerr  Úmax_attemptsrÑ   Úresprö   ÚdelayÚdevice_datas           r   Ú_codex_request_device_coderÏ  ¼  sk  € ð €LÜ˜˜L¨1Ñ,Ó-ò ˆÜ ØˆhÐ7Ð8ÀÈYÐ?WØ#Ð%7Ð8ØSôUˆð ×Ñ˜sÒ"ÙØ�\Ó!ä4´W¸TÀ9ÈdÓ5SÓTˆKÜ˜œ3œs°+Ð2I¡;ÈqÐT[É|Ó\Ð^`ÓaÓbˆEÜÐNÈuÈgÐUYÐZÔ[Ü�J‰J�uÕðð ×Ñ˜3ÒÜ-¨dÓ3Ð3Ø×Ñ˜3ÒÜØ2°4×3CÑ3CÐ2DÀAÐFÐHcóeð 	eà—)‘)“+€KÜ! !¤S¨¯©¸ÀSÓ)IÓ%JÓK€K�
ÑØ�?‰?˜;¨Ô+°;·?±?ÐCSÐUWÔ3XÜÐHÐJbÓcÐcØÐr!   c               óL  — d}d}t        j                  «       }d}	 t        t        j                  d«      ¬«      5 }d}	t        j                  «       |z
  |k  r—t        j
                  |«       	 |j                  | › d�||dœd	d
i¬«      }
d}	|
j                  dk(  r|
j                  «       }nC|
j                  dvrt        d|
j                  › d�d«      ‚t        j                  «       |z
  |k  rŒ—ddd«       |€t        dd«      ‚|S # t        $ rd}t        |«      st        d|› t        |«      › �d«      |‚|	dz  }	|	|k\  rt        d|	› d|› t        |«      › �d«      |‚t        d«       Y d}~�Œ1d}~ww xY w# 1 sw Y   Œ‰xY w# t        $ r t        d«       t        d«      ‚w xY w)zXStep 3 of the Codex device flow: poll until sign-in completes (403/404 = still pending).i„  é   NrÇ   rÈ   r   z/api/accounts/deviceauth/token)rÆ  rÅ  r  r  )r£   r&   z$Device auth polling request failed: Údevice_code_poll_errorr¡   z)Device auth polling request failed after z consecutive transport errors: z>Transient network error while waiting for sign-in; retrying...r  >   é”  r  z$Device auth polling returned status rú   z
Login cancelled.é‚   z!Login timed out after 15 minutes.Údevice_code_timeout)r:   r{  rÊ   r   rË   rÍ   rÌ   r¤   rÄ   r   r¼   r±  r  r£   ÚKeyboardInterruptÚ
SystemExit)rÊ  rÆ  rÅ  Úpoll_intervalÚmax_waitÚmax_consecutive_blipsÚstartÚ	code_resprÓ   Úconsecutive_blipsÚ	poll_respr    s               r   Ú_codex_poll_authorization_coderß  Ü  s÷  € ð €HØÐÜ�N‰NÓ€EØ€Ið!Ü¬¯©°dÓ(;Ô<ð 	2ÀØ !ÐÜ—.‘.Ó" UÑ*¨XÒ5Ü—
‘
˜=Ô)ðØ &§¡Ø!˜(Ð"@ÐAØ0>ÈYÑWØ!/Ð1CÐ Dð !,ó !F�Ið" %&Ð!Ø×(Ñ(¨CÒ/Ø )§¡Ó 0�IØØ×(Ñ(°
Ñ:Ü$Ø>¸y×?TÑ?TÐ>UÐUVÐWØ0ó2ð 2ô3 —.‘.Ó" UÑ*¨XÓ5÷	2ðB ÐÜÐ<Ð>SÓTÐTØÐøô5 !ò Ü8¸Ô=Ü(ØBÀ3À%ÔHYÐZ]ÓH^ÐG_Ð`Ø4ó6à;>ð?ð &¨Ñ*Ð%Ø(Ð,AÒAÜ(ØGÐHYÐGZð [2Ø25°Ô7HÈÓ7MÐ6NðPà4ó6ð <?ð?ô ÐZÔ[Ýûðú÷	2ð 	2ûô< ò ÜÐ"Ô#Ü˜‹oÐðúsN   œF »2E7Á.DÂ
A$E7Ã/F Ä	E4ÄAE/Å)E7Å/E4Å4E7Å7F Å<F Æ F#c           	     ó�  — |j                  dd«      }|j                  dd«      }|r|st        dd«      ‚t        t        d|| › d�||dœdd	id
¬«      }|j                  dk(  rt        |d¬«      ‚|j                  dk7  rt        d|j                  › d�d«      ‚|j                  «       }|j                  dd«      st        dd«      ‚|S )zHStep 4 of the Codex device flow: swap the authorization code for tokens.Úauthorization_coder*   Úcode_verifierzADevice auth response missing authorization_code or code_verifier.Údevice_code_incomplete_exchangez/deviceauth/callback)r  r�   Úredirect_urir  râ  r  r  )zToken exchange failedÚtoken_exchange_failed)r  r&   rÏ   r  z during token exchanger¸  r  zToken exchange returned status rú   Útoken_exchange_errorr<   z.Token exchange did not return an access_token.Útoken_exchange_no_access_token)r7   r   rÔ   r   r  r¼  r£   )rÊ  r  rÜ  rá  râ  Ú
token_respr]   s          r   Ú"_codex_exchange_authorization_coderé  
  sü   € ð #Ÿ™Ð';¸RÓ@ÐØ—M‘M /°2Ó6€MÙ¡]ÜØOØ-ó/ð 	/ô #Üà.Ð8JØ%˜hÐ&:Ð;È)Ø*ñ,ð  Ð!DÐEØBôD€Jð ×Ñ Ò$Ü-¨jÐAYÔZÐZØ×Ñ Ò$ÜØ-¨j×.DÑ.DÐ-EÀQÐGÐI_óað 	aà�_‰_Ó€FØ�:‰:�n bÔ)ÜØ<Ð>^ó`ð 	`à€Mr!   c                 óˆ  — ddl m}  dt        }}t        ||«      }|d   }t	        d«       t	        d«       t	        d|› d�«       t	        d	«       t	        d|› d
�«       t	        d«       t        ||d   ||d   ¬«      }t        |||«      }|j                  dd«      |j                  dd«      dœt        «        | «       dddœS )zBRun the OpenAI device code login flow and return credentials dict.r   )r~   zhttps://auth.openai.comrÅ  z!To continue, follow these steps:
z#  1. Open this URL in your browser:z
     [94mz/codex/device[0m
z  2. Enter this code:z[0m
z/Waiting for sign-in... (press Ctrl+C to cancel)rÆ  rÃ  )rÆ  rÅ  rØ  r<   r*   ra   r!  rH   zdevice-code)r]   rJ   rM   rN   rL   )	r1   r~   r   rÏ  r±  rß  ré  r7   rF   )r~   rÊ  r  rÎ  rÅ  rÜ  r]   s          r   Ú_codex_device_code_loginrë  '  sÜ   € å*Ø1Ô3HˆI€FÜ,¨V°YÓ?€KØ˜KÑ(€Iô 
Ð
.Ô/Ü	Ð
/Ô0Ü	ˆM˜&˜Ð!7Ð
8Ô9Ü	Ð
!Ô"Ü	ˆM˜)˜ IÐ
.Ô/Ü	Ð
;Ô<Ü.Ø˜{Ð+;Ñ<È	Ø! *Ñ-ô/€Iô 0°¸	À9ÓM€Fð #ŸJ™J ~°rÓ:Ø#ŸZ™Z¨¸Ó<ñ>ô $Ó%±z³|ÐR[Øñ!ð !r!   )r¢   r+   )r&   r   r¢   úOptional[int])r-   r   r¢   r+   )r2   úDict[str, Any]r¢   ré   )r<   r   r=   r%   r¢   rp   )rK   r+   rL   r+   rM   úOptional[str]r¢   rí  )rS   rp   r¢   rí  )rV   rp   r¢   rí  r°   )
ri   rí  r]   úDict[str, str]rM   rî  rq   úOptional[Dict[str, str]]r¢   ré   )NN)r]   rï  rM   r+   r   r+   rv   rp   rw   rp   r¢   ré   )r�   r+   r�   rî  r¢   rð  )r¥   rè   rI   r+   r¦   úTuple[str, str]r§   zOptional[Tuple[str, str]]r¨   rñ  r˜   rp   r™   úOptional[bool]rš   rp   r¢   zTuple[Dict[str, Any], str])r    ÚBaseExceptionr¢   r+   )r    ró  r¢   rp   )rÎ   r+   rÏ   rñ  rÐ   r   r¢   rè   rç   )rÐ   r   r¢   z'httpx.Client')rö   rì  r¢   r   )r¥   rè   r¢   r   )r<   r+   ra   r+   r  r9   r¢   rí  )r]   rï  r  r9   r¢   rï  )r¢   rð  )
r5  rp   r6  rp   r7  r%   r8  rp   r¢   rí  )r�   r   r�   r   rž   r   r¢   rp   )r2   rí  r¢   rp   )rB  r+   r¢   r+   )rJ   rî  r¢   r+   )r<   r   rJ   rî  rq  r9   r¢   rò  )r<   r   ra   r   rq  r9   r¢   úOptional[Dict[str, Any]])r2   rí  r¢   rò  )r<   rî  r¢   r%   )rr   úOptional[List[Any]]r¢   zIterator[Dict[str, Any]])r¢   rô  )ri   rí  rœ  r+   r¢   rõ  )r³  r   r   rp   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í   Ú
__future__r   Úloggingrg  r£   rB   Ú	threadingr:   Ú
contextlibr   Úpathlibr   Útypingr   r   r   r	   r
   r   r   Úhermes_cli.auth_constantsr   r   r   r   r   r   r   r   r   r   r   Úutilsr   r1   r   Ú	getLoggerrŒ   rg   rh   rd   r    r(   r.   r4   r>   rF   rO   rT   rk   ru   r…   r—   r«   r·   r¼   rÄ   rÔ   rà   ÚSyncByteStreamrÖ   rï   rÊ   r÷   r	  r  r)  r‰   rP  r\  rc  Ú&CODEX_QUOTA_PROBE_MIN_INTERVAL_SECONDSrd  Ú__annotations__ÚLockr|  rk  rp  r:  r‰  rH  rI  ro   rG  rn   rD  r·  r¼  rÏ  rß  ré  rë  rE   r!   r   ú<module>r     sÔ  ðòõ #ã Û Û Û 	Û Û Ý Ý ß L× LÑ L÷`÷ `÷ `ñ `õ áÝ.ð 
ˆ×	Ñ	Ð,Ó	-€ð fÐ ØgÐ ØUÐ ó1ó5ó$ó#óeó
`ðPØðPØ ðPØ0=ðPØBPóPóð )-õ Ið0 ;?ð&(Øð&(Ø(6ð&(ØFSð&(à7ð&(àCGó&(ðT DHð(@à°5ñ(@Øð(@Ø*-ð(@Ø=@ð(@àð(@à,0ð(@ð 
ó(@ðX =Að'Øð'Ø,9ð'ØE]ó'ðZ "È$Øñ	ØðØ-0ðØ@Oðà/ðàAPðð ðð :Hðð ð	ð !;ó	ðB =Ð óó4ó"ð( )Ð ô˜×,Ñ,ô ó42óó(Gó$?ðP HLñ#Øð#Ø&)ð#Ø?Dð#ØP^ó#óL*óZð. #ÀØ GØñbYØðbYØ9=ðbYàðbYð ðbYð !/óbYóJPó)ð *-Ð &ØDFÐ ÐAÓ FØ(˜)Ÿ.™.Ó*Ð óBóð 59Ø"Hñ6Øð6Ø$1ð6àð6àM[ó6ðv #Iñ"Øð"Ø&)ð"àð"àMeó"óJNô,ó>óó4:óð, SXõ %LðP RTõ !ó ð@+Øð+Ø$'ð+Ø47ð+ØHKð+ØP^ó+ð\ØðØðØ,:ðØ?Móô:!r!   