Ë
    ãß²j-)  ã                  óô   — 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mZm	Z	m
Z
 dZdZdZdd„Zdd	„Zdd
„Zdd„Zh d£Zh d£Zdd„Zdd„Zdd„Z	 	 	 	 	 	 	 	 d d„Zd!d„Zd"d„Zdd„Zdd„Zddddœ	 	 	 	 	 	 	 d#d„Zy)$z0Shared helpers for direct xAI HTTP integrations.é    )ÚannotationsN)ÚAnyÚDictÚOptionalzhttps://api.x.ai/v1i �' i £ c                óH   — t        | t        «      r| j                  |«      S d S ©N)Ú
isinstanceÚdictÚget)ÚobjÚkeys     ú3/home/ubuntu/.hermes/hermes-agent/tools/xai_http.pyÚ	_dict_getr      s   € Ü% c¬4Ô0ˆ3�7‰7�3‹<Ð:°dÐ:ó    c                 óö  — ddl m}   | dd«      xs dj                  «       ry	 ddlm}  |«       dz  }|j                  «       syt        j                  |j                  d	¬
«      «      }t        t        t        |d«      d«      d«      }t        t        |d«      xs d«      j                  «       ryt        t        |d«      d«      }t        |t        «      xr t        d„ |D «       «      S # t        $ r Y yw xY w)uY  Cheap probe: True when xAI credentials are *likely* usable.

    Deliberately avoids :func:`resolve_xai_http_credentials` (disk locks, OAuth network
    refresh) â€” hot-paint callers and ``WebSearchProvider.is_available()`` must not do network
    I/O. Checks, fast-to-slow: ``XAI_API_KEY``; ``providers.xai-oauth.tokens.access_token`` in
    ``auth.json``; any ``credential_pool.xai-oauth`` entry with an ``access_token`` (pool-only
    multi-account grants never write the providers singleton). Returns False on any exception
    so a corrupted auth store can't block other availability scans.
    r   )Ú
get_secretÚXAI_API_KEYÚ T©Úget_hermes_homez	auth.jsonFz	utf-8-sig©ÚencodingÚ	providersú	xai-oauthÚtokensÚaccess_tokenÚcredential_poolc              3  óš   K  — | ]C  }t        |t        «      xr- t        |j                  d d«      xs d«      j	                  «       –— ŒE y­w)r   r   N)r	   r
   Ústrr   Ústrip)Ú.0Úes     r   ú	<genexpr>z&has_xai_credentials.<locals>.<genexpr>-   sB   è ø€ ò 1
ØUVŒJ�qœ$ÓÒP¤C¨¯©¨n¸bÓ(AÒ(GÀRÓ$H×$NÑ$NÓ$PÓPñ1
ùs   ‚A	A)Úagent.secret_scoper   r    Úhermes_constantsr   ÚexistsÚjsonÚloadsÚ	read_textr   r   r	   ÚlistÚanyÚ	Exception)r   r   Ú	auth_pathÚstorer   Úentriess         r   Úhas_xai_credentialsr0      sí   € õ .á�= "Ó%Ò+¨×2Ñ2Ô4ØðÝ4Ù#Ó%¨Ñ3ˆ	Ø×ÑÔ!ØÜ—
‘
˜9×.Ñ.¸Ð.ÓDÓEˆÜœ9¤Y¨u°kÓ%BÀKÓPÐRZÓ[ˆÜŒy˜ Ó0Ò6°BÓ7×=Ñ=Ô?ØÜœI eÐ->Ó?ÀÓMˆÜ˜'¤4Ó(ò 
¬Sñ 1
ØZaô1
ó .
ð 	
øô ò Ùðús   ¤ C, ÁA,C, Â29C, Ã,	C8Ã7C8c                 ó<   — 	 ddl m}  d| › �S # t        $ r d} Y Œw xY w)z>Return a stable Hermes-specific User-Agent for xAI HTTP calls.r   ©Ú__version__ÚunknownzHermes-Agent/)Ú
hermes_clir3   r,   r2   s    r   Úhermes_xai_user_agentr6   4   s/   € ð Ý*ð ˜;˜-Ð(Ð(øô ò  ØŠð ús   ‚ �šc                 ó   — dt        «       iS )zaDefault headers for OpenAI-SDK and raw HTTP clients talking to xAI (replaces the SDK User-Agent).z
User-Agent)r6   © r   r   Úhermes_xai_default_headersr9   =   s   € àÔ/Ó1Ð2Ð2r   >   Ú1ÚonÚyesÚtrueÚenabled>   Ú0ÚnoÚoffÚfalseÚdisabledc                ó´   — t        | t        «      r| S t        | t        «      r5| j                  «       j	                  «       x}t
        t        z  v r|t
        v S |S r   )r	   Úboolr   r    ÚlowerÚ_TRUE_WORDSÚ_FALSE_WORDS)ÚvalueÚdefaultÚ
normalizeds      r   Ú_coerce_boolrL   F   sL   € Ü�%œÔØˆÜ�%œÔ°·±³×1DÑ1DÓ1FÐ#F :Ì;ÔYeÑKeÑ"eØœ[Ð(Ð(Ø€Nr   c                ó:  — | €yt        | t        «      r/| j                  «       j                  «       } | dv ry	 t	        | «      } t        | t        t        f«      st        S t	        | «      dk  rdS t        t	        | «      t        «      S # t
        $ r	 t        cY S w xY w)z\Normalize an xAI storage TTL: int seconds, or None for permanent storage (omit on the wire).N>   r   r?   ÚnoneÚnullÚneverrJ   ÚforeverÚ	permanentr   )
r	   r   r    rF   ÚintÚ
ValueErrorÚ&SAFE_XAI_STORAGE_EXPIRES_AFTER_SECONDSÚfloatÚminÚ%MAX_XAI_STORAGE_EXPIRES_AFTER_SECONDS)rI   s    r   Ú_coerce_expires_afterrY   N   s�   € à€}ØÜ�%œÔØ—‘“×#Ñ#Ó%ˆØÐYÑYØð	:Ü˜“JˆEô �eœc¤5˜\Ô*Ü5Ð5Ü�u“: ’?ˆ4Ð^¬¬C°«JÔ8]Ó(^Ð^øô	 ò 	:Ü9Ò9ð	:ús   ¸B ÂBÂBc                óD  — 	 ddl m} t        t        t         |«       | «      d«      d«      }t	        |t
        «      r|ni }t        |j                  d«      d«      t        |j                  d«      d«      t        |j                  d	«      «      d
œS # t        $ r d}Y Œqw xY w)zÒRead ``<section_name>.xai.storage`` (``image_gen``/``video_gen``) -> {enabled, public_url, expires_after}.
    On by default so xAI returns permanent public URLs, not short-lived CDN ones; null TTL = permanent.r   )Úload_configÚxaiÚstorageNr>   TÚ
public_urlÚexpires_after)r>   r^   r_   )	Úhermes_cli.configr[   r   r,   r	   r
   rL   r   rY   )Úsection_namer[   r]   s      r   Úread_xai_imagine_storage_configrb   _   s�   € ðÝ1ÜœI¤i±³¸|Ó&LÈeÓTÐV_Ó`ˆô $ G¬TÔ2‰g¸€Gä §¡¨IÓ 6¸Ó=Ü" 7§;¡;¨|Ó#<¸dÓCÜ.¨w¯{©{¸?Ó/KÓLñð øô ò ØŠðús   ‚+B ÂBÂBc          	     óZ  — t        | «      }|d   syt        j                  j                  t        j                  «      j	                  d«      }|› d|› dt        j                  «       j                  dd › d|j                  d«      xs d› �}|t        |d   «      d	œ}|d
   �|d
   |d
<   |S )zAReturn an xAI ``storage_options`` payload, or None when disabled.r>   Nz%Y%m%d-%H%M%SÚ-é   ú.Úbinr^   )Úfilenamer^   r_   )
rb   ÚdatetimeÚnowÚUTCÚstrftimeÚuuidÚuuid4ÚhexÚlstriprE   )ra   Úfilename_prefixÚ	extensionÚcfgÚtsrh   Úpayloads          r   Úbuild_xai_storage_optionsrv   o   s´   € ô *¨,Ó
7€CØˆyŠ>ØÜ	×	Ñ	×	Ñ	œxŸ|™|Ó	,×	5Ñ	5°oÓ	F€BØ!Ð" ! B 4 q¬¯©«×)9Ñ)9¸"¸1Ð)=Ð(>¸aÀ	×@PÑ@PÐQTÓ@UÒ@^ÐY^Ð?_Ð`€HØ+3Ä4ÈÈLÑHYÓCZÑ[€GØ
ˆ?ÑÐ'Ø#& Ñ#7ˆ�Ñ Ø€Nr   c                ót   — t        | «      }|d   syd}|d   �|d   dz  }d|d›d|d	k7  rd
nd› �}d|› d| › d�S )z5User-facing notice for first xAI Imagine storage use.r>   r   zwithout an automatic expiryr_   i€Q z
for about Úgz dayé   ÚszMxAI Imagine storage is enabled so generated media gets a reusable public URL zK. xAI may bill for stored files and public URL hosting. Disable this with `zL.xai.storage.enabled: false` or set `expires_after` to change the retention.)rb   )ra   rs   Ú	retentionÚdayss       r   Úxai_storage_notice_textr}   ~   su   € ä
)¨,Ó
7€CØˆyŠ>ØØ-€IØ
ˆ?ÑÐ'Ø�?Ñ# |Ñ4ˆØ   a ¨°D¸A²I©SÀ2Ð,FÐGˆ	ð	Ø�[ð !'Ø'3 nð 5:ð	:ðr   c                ó\  — t        | «      }|sy	 ddlm}  |«       dz  }|j                  dd¬«       || › d�z  }|j	                  «       ry|j                  t        j                  j                  t        j                  «      j                  «       dz   d	¬
«       |S # t        $ r |cY S w xY w)zBReturn the storage notice once per Hermes home, then mark it seen.Nr   r   ÚstateT)ÚparentsÚexist_okÚ_xai_storage_notice_seenÚ
zutf-8r   )r}   r%   r   Úmkdirr&   Ú
write_textri   rj   rk   Ú	isoformatr,   )ra   Únoticer   Ú
marker_dirÚmarkers        r   Ú"maybe_mark_xai_storage_notice_seenrŠ   �   s¨   € ä$ \Ó2€FÙØð
Ý4Ù$Ó&¨Ñ0ˆ
Ø×Ñ °ÐÔ5Ø  Ð.FÐGÑGˆØ�=‰=Œ?ØØ×Ñœ(×+Ñ+×/Ñ/´·±Ó=×GÑGÓIÈDÑPÐ[bÐÔcØˆøÜò ØŠðús   �;B ÁAB ÂB+Â*B+c                 ó    — ddl m}   | dd«      S )u$  Read ``XAI_API_KEY`` via ``resolve_provider_secret`` (config â†’ profile scope â†’ env/.env â†’ pool).

    Both the preferred-key and the no-OAuth fallback paths go through here so scope policy
    (incl. failing closed in a multiplexed gateway turn) is never re-implemented per caller.
    r   ©Úresolve_provider_secretr   r\   )Útools.tool_backend_helpersr�   rŒ   s    r   Ú_resolve_explicit_xai_api_keyr�   ¡   s   € õ CÙ" =°%Ó8Ð8r   c                 ó†   — ddl m}  t         | d«      xs  | d«      xs d«      j                  «       j	                  d«      S )zG``HERMES_XAI_BASE_URL`` then ``XAI_BASE_URL``, stripped; '' when unset.r   ©Úget_env_valueÚHERMES_XAI_BASE_URLÚXAI_BASE_URLr   ú/)r`   r’   r   r    Úrstripr‘   s    r   Ú_xai_base_url_overrider—   «   s;   € å/Ü‰}Ð2Ó3ÒZ±}À^Ó7TÒZÐXZÓ[×aÑaÓc×jÑjÐknÓoÐor   F)Úforce_refreshÚapi_key_hintÚprefer_api_keyc                ól  — ddl m} |rNt        t        «       xs d«      j	                  «       x}r't        «       }|j                  |t        ¬«      }d||dœS 	 ddlm	}  |d«      }| r|j                  |«      n|j                  «       }	| r|	€|j                  «       }	t        |	d	d«      xs t        |	d
d«      }
t        t        |	dd«      xs t        |	dd«      xs |j                  «      j	                  «       j                  d«      }|j                  t        «       |¬«      }t        |
«      j	                  «       rdt        |
«      j	                  «       |dœS 	 ddlm} t        «       }t         |d«      xs t        «      j	                  «       j                  d«      }d||dœS # t        $ r Y ŒWw xY w)u§  Resolve bearer credentials for direct xAI HTTP endpoints.

    Default order: Hermes-managed xAI OAuth, then ``XAI_API_KEY`` (via ``get_env_value`` so
    ``~/.hermes/.env`` keys count). ``prefer_api_key=True`` inverts that for API-metered
    endpoints where the subscription OAuth bearer authorizes but misbehaves (x_search answers
    without citations, TTS 403s). Both branches honor ``HERMES_XAI_BASE_URL``/``XAI_BASE_URL``
    behind the same origin-pinning validation. ``force_refresh=True`` forces an OAuth refresh;
    pass the rejected bearer as ``api_key_hint`` so a multi-account pool refreshes the issuing
    entry, not whichever its strategy selects first.

    Prefers Hermes-managed xAI OAuth credentials when available, then falls back to ``XAI_API_KEY`` resolved
    via ``hermes_cli.config.get_env_value`` so keys stored in ``~/.hermes/.env`` (the standard Hermes
    location) are honored â€” not just ones already exported into ``os.environ``. This keeps direct xAI
    endpoints (images, TTS, STT, etc.) aligned with the main runtime auth model and preserves the regression
    contract from PR #17140 / #17163.
    The key is read through :func:`tools.tool_backend_helpers.resolve_provider_secret` so profile secret
    scoping is identical to the fallback branch, and the base URL honors ``HERMES_XAI_BASE_URL`` /
    ``XAI_BASE_URL`` behind the same origin-pinning validation as the OAuth branch. See #87045, #88040.
    r   Nr   )Úfallbackr\   )ÚproviderÚapi_keyÚbase_url)Ú	load_poolr   Úruntime_api_keyr   Úruntime_base_urlrŸ   r•   r‘   r”   )Úhermes_cli.authÚauthr   r�   r    r—   Ú _xai_validate_inference_base_urlÚDEFAULT_XAI_BASE_URLÚagent.credential_poolr    Útry_refresh_matchingÚselectÚgetattrÚDEFAULT_XAI_OAUTH_BASE_URLr–   r,   r`   r’   )r˜   r™   rš   Úauth_modÚexplicit_keyÚoverriderŸ   r    ÚpoolÚentryr   Úfallback_base_urlr’   rž   s                 r   Úresolve_xai_http_credentialsr²   ±   s¦  € õ, 'Ù¬3Ô/LÓ/NÒ/TÐRTÓ+U×+[Ñ+[Ó+]Ð]˜<Ð]ä)Ó+ˆØ×<Ñ<¸XÔPdÐ<ÓeˆØ!¨lÈÑQÐQðÝ3Ù˜Ó%ˆÙ;H�×)Ñ)¨,Ô7ÈdÏkÉkËmˆÙ˜U˜]ð —K‘K“MˆEÜ˜uÐ&7¸Ó>ÒdÄ'È%ÐQ_ÐacÓBdˆÜÜ�EÐ-¨tÓ4ò 3Ü�u˜j¨"Ó-ò3à×2Ñ2ó
÷ ‰%‹'—&‘&˜“+ð	 	ð
 ×<Ñ<Ô=SÓ=UÐ`qÐ<ÓrˆÜˆ|Ó×"Ñ"Ô$Ø +¼¸LÓ8I×8OÑ8OÓ8QÐ_gÑhÐhð %õ
 0Ü+Ó-€GÜ‘= Ó0ÒHÔ4HÓI×OÑOÓQ×XÑXÐY\Ó]€HØ¨'¸xÑHÐHøô ò Ùðús   ÁDF' Æ'	F3Æ2F3)r   r   r   r   Úreturnr   )r³   rE   )r³   r   )r³   úDict[str, str])rI   r   rJ   rE   r³   rE   )rI   r   r³   zOptional[int])ra   r   r³   zDict[str, Any])ra   r   rq   r   rr   r   r³   zOptional[Dict[str, Any]])ra   r   r³   r   )ra   r   r³   úOptional[str])r˜   rE   r™   rµ   rš   rE   r³   r´   )Ú__doc__Ú
__future__r   ri   r'   Úosrm   Útypingr   r   r   r¦   rX   rU   r   r0   r6   r9   rG   rH   rL   rY   rb   rv   r}   rŠ   r�   r—   r²   r8   r   r   ú<module>rº      sÏ   ðÙ 6å "ã Û Û 	Û ß &Ñ &ð -Ð Ø(9Ð %Ø)9Ð &ó;óó>)ó3ò
 4€Ú6€óó_ó"ð ØðØ+.ðØ;>ðàóóó"ó$9ópð #À$Ð_dñ4IØð4IØ2?ð4IØX\ð4Iàô4Ir   