§
    øžyj;0  ã                  ó¼   — 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&d	„Zd'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„Zd0d „Zd!dd"œd1d%„ZdS )2z0Shared helpers for direct xAI HTTP integrations.é    )ÚannotationsN)ÚAnyÚDictÚOptionali �' i £ ÚreturnÚboolc                 óØ  — 	 ddl m}   | dd¦  «        pd                     ¦   «         rdS nE# t          $ r8 t          j                             dd¦  «                             ¦   «         rY dS Y nw xY w	 ddlm}  |¦   «         dz  }| 	                    ¦   «         sdS t          j        |                     d	¬
¦  «        ¦  «        }t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        r|                     d¦  «        nd}t          |pd¦  «                             ¦   «         rdS t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        r|                     d¦  «        nd}	t          |	t           ¦  «        rU|	D ]R}
t          |
t          ¦  «        sŒt          |
                     dd¦  «        pd¦  «                             ¦   «         r dS ŒSdS # t"          $ r Y dS w xY w)u”  Cheap probe â€” return True when xAI credentials are *likely* usable.

    Deliberately avoids :func:`resolve_xai_http_credentials` so callers in
    hot-paint paths (``hermes tools`` repaint, tool-registration scans,
    ``WebSearchProvider.is_available()``) don't incur disk locks or â€” in
    the OAuth path â€” a network token refresh. The ABC contract on
    :meth:`agent.web_search_provider.WebSearchProvider.is_available`
    explicitly forbids network calls for exactly this reason.

    Resolution order, fast-to-slow:

    1. ``XAI_API_KEY`` env var (cheapest; covers explicit-key users).
    2. ``~/.hermes/auth.json`` has a non-empty ``providers.xai-oauth.tokens.access_token``
       (single file read, no expiry check, no refresh).
    3. ``credential_pool.xai-oauth`` has any entry with a non-empty
       ``access_token`` (covers multi-account ``hermes auth add xai-oauth``
       grants that are pool-only / ``manual:device_code``).

    Returns False on any exception so a corrupted auth store can't block
    other availability scans. Truthful refresh + expiry handling happens
    in ``search()`` (or whichever caller actually makes the request).
    r   )Ú
get_secretÚXAI_API_KEYÚ T©Úget_hermes_homez	auth.jsonFz	utf-8-sig©ÚencodingÚ	providersNú	xai-oauthÚtokensÚaccess_tokenÚcredential_pool)Úagent.secret_scoper
   ÚstripÚImportErrorÚosÚenvironÚgetÚhermes_constantsr   ÚexistsÚjsonÚloadsÚ	read_textÚ
isinstanceÚdictÚstrÚlistÚ	Exception)r
   r   Ú	auth_pathÚstorer   Ú	xai_stater   r   r   ÚentriesÚentrys              ú4/home/ragecks/.hermes/hermes-agent/tools/xai_http.pyÚhas_xai_credentialsr,      s­  € ð.Ø1Ð1Ð1Ð1Ð1Ð1ð
 ˆJ�} bÑ)Ô)Ð/¨R×6Ò6Ñ8Ô8ð 	Ø�4ð	øõ	 ð ð ð ÝŒ:�>Š>˜-¨Ñ,Ô,×2Ò2Ñ4Ô4ð 	Ø�4�4ð	ð 	ðøøøðØ4Ð4Ð4Ð4Ð4Ð4à#�OÑ%Ô%¨Ñ3ˆ	Ø×ÒÑ!Ô!ð 	Ø�5Ý”
˜9×.Ò.¸Ð.ÑDÔDÑEÔEˆÝ.8¸ÅÑ.EÔ.EÐO�E—I’I˜kÑ*Ô*Ð*È4ˆ	Ý2<¸YÍÑ2MÔ2MÐW�I—M’M +Ñ.Ô.Ð.ÐSWˆ	Ý,6°yÅ$Ñ,GÔ,GÐQ�—’˜xÑ(Ô(Ð(ÈTˆÝ5?ÀÍÑ5MÔ5MÐW�v—z’z .Ñ1Ô1Ð1ÐSWˆÝˆ|Ð!˜rÑ"Ô"×(Ò(Ñ*Ô*ð 	Ø�4õ ;EÀUÍDÑ:QÔ:QÐ[˜%Ÿ)š)Ð$5Ñ6Ô6Ð6ÐW[ˆõ ˜/­4Ñ0Ô0ðˆO×Ò Ñ,Ô,Ð,àð 	õ
 �g�tÑ$Ô$ð 	 Ø ð  ð  �Ý! %­Ñ.Ô.ð ØÝ�u—y’y °Ñ4Ô4Ð:¸Ñ;Ô;×AÒAÑCÔCð  Ø˜4˜4ð àˆuøÝð ð ð Øˆuˆuðøøøs5   ‚+ «<A-Á,A-Á1'I ÂC;I ÆB?I ÉI É
I)É(I)Únamer#   c                ó”   — 	 ddl m} n0# t          $ r# t          j                             | |¦  «        cY S w xY w || ¦  «        }|�|n|S )zõRead ``name`` from ``~/.hermes/.env`` first, then ``os.environ``.

    Wraps :func:`hermes_cli.config.get_env_value` so tests can patch
    ``tools.xai_http.get_env_value`` to inject dotenv-only secrets into the
    xAI credential resolver.
    r   )Úget_env_value)Úhermes_cli.configr/   r   r   r   r   )r-   ÚdefaultÚ_hermes_get_env_valueÚvalues       r+   r/   r/   O   st   € ð-ØLÐLÐLÐLÐLÐLÐLøÝð -ð -ð -ÝŒz�~Š~˜d GÑ,Ô,Ð,Ð,Ð,ð-øøøð "Ð! $Ñ'Ô'€EØÐ%ˆ5ˆ5¨7Ð2s   ‚	 ‰*6µ6c                 ó@   — 	 ddl m}  n# t          $ r d} Y nw xY wd| › �S )z>Return a stable Hermes-specific User-Agent for xAI HTTP calls.r   ©Ú__version__ÚunknownzHermes-Agent/)Ú
hermes_clir6   r%   r5   s    r+   Úhermes_xai_user_agentr9   _   sN   € ð Ø*Ð*Ð*Ð*Ð*Ð*Ð*øÝð  ð  ð  Øˆˆˆð øøøà(˜;Ð(Ð(Ð(s   ‚	 ‰—úDict[str, str]c                 ó"   — dt          ¦   «         iS )u5  Default headers for OpenAI-SDK and raw HTTP clients talking to xAI.

    Replaces the OpenAI Python SDK's identifying ``User-Agent: OpenAI/Python â€¦``
    so chat/completions and Responses traffic is attributed as Hermes Agent,
    matching the direct HTTP integrations (search, TTS, STT, image, video).
    z
User-Agent)r9   © ó    r+   Úhermes_xai_default_headersr>   h   s   € ð Õ/Ñ1Ô1Ð2Ð2r=   Úsection_nameúDict[str, Any]c                óÒ   — 	 ddl m}  |¦   «         }t          |t          ¦  «        r|                     | ¦  «        nd}t          |t          ¦  «        r|ni S # t
          $ r i cY S w xY w)z=Return a top-level Hermes config section as a dict, or empty.r   )Úload_configN)r0   rB   r!   r"   r   r%   )r?   rB   ÚcfgÚsections       r+   Ú_load_config_sectionrE   r   s†   € ðØ1Ð1Ð1Ð1Ð1Ð1àˆk‰mŒmˆÝ+5°c½4Ñ+@Ô+@ÐJ�#—'’'˜,Ñ'Ô'Ð'ÀdˆÝ$ W­dÑ3Ô3Ð;ˆwˆw¸Ð;øÝð ð ð Øˆ	ˆ	ˆ	ðøøøs   ‚AA ÁA&Á%A&r3   r   r1   c                óÂ   — t          | t          ¦  «        r| S t          | t          ¦  «        r2|                      ¦   «                              ¦   «         }|dv rdS |dv rdS |S )N>   Ú1ÚonÚyesÚtrueÚenabledT>   Ú0ÚnoÚoffÚfalseÚdisabledF)r!   r   r#   r   Úlower)r3   r1   Ú
normalizeds      r+   Ú_coerce_boolrS   ~   sk   € Ý�%�ÑÔð ØˆÝ�%�ÑÔð Ø—[’[‘]”]×(Ò(Ñ*Ô*ˆ
ØÐ>Ð>Ð>Ø�4ØÐ@Ð@Ð@Ø�5Ø€Nr=   úOptional[int]c                ó†  — | €dS t          | t          ¦  «        rZ|                      ¦   «                              ¦   «         }|dv rdS |dv rdS 	 t	          |¦  «        } n# t
          $ r
 t          cY S w xY wt          | t          t          f¦  «        r,t	          | ¦  «        }|dk    rdS t          |t          ¦  «        S t          S )zŸNormalize an xAI storage TTL.

    Returns:
        int seconds for an expiring file,
        None for permanent storage (omit expires_after on the wire).
    N>   r   r1   >   rL   ÚnoneÚnullÚneverÚforeverÚ	permanentr   )
r!   r#   r   rQ   ÚintÚ
ValueErrorÚ&SAFE_XAI_STORAGE_EXPIRES_AFTER_SECONDSÚfloatÚminÚ%MAX_XAI_STORAGE_EXPIRES_AFTER_SECONDS)r3   rR   Úsecondss      r+   Ú_coerce_expires_afterrb   Š   sÚ   € ð €}ØˆtÝ�%�ÑÔð 	:Ø—[’[‘]”]×(Ò(Ñ*Ô*ˆ
Ø˜Ð(Ð(Ø�4ØÐOÐOÐOØ�4ð	:Ý˜
‘O”OˆEˆEøÝð 	:ð 	:ð 	:Ý9Ð9Ð9Ð9ð	:øøøå�%�#�u˜Ñ&Ô&ð CÝ�e‘*”*ˆØ�aŠ<ˆ<Ø�4Ý�7ÕAÑBÔBÐBÝ1Ð1s   ÁA ÁA1Á0A1c                óÞ  — t          | ¦  «        }t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        r|ni }t	          |                     d¦  «        d¦  «        }t	          |                     d¦  «        d¦  «        }t          |                     d¦  «        ¦  «        }|||dœS )	aÇ  Read storage settings for xAI Imagine under image_gen/video_gen config.

    Supported config shape:

        image_gen:
          xai:
            storage:
              enabled: true
              public_url: true
              expires_after: null     # omit for permanent public URLs

    The same shape is accepted under ``video_gen.xai.storage``. Storage is on
    by default so xAI returns permanent public URLs instead of short-lived CDN URLs.
    ÚxaiNÚstoragerK   TÚ
public_urlÚexpires_after)rK   rf   rg   )rE   r!   r"   r   rS   rb   )r?   rD   Úxai_sectionre   rK   rf   rg   s          r+   Úread_xai_imagine_storage_configri   ¥   sÜ   € õ # <Ñ0Ô0€GÝ(2°7½DÑ(AÔ(AÐK�'—+’+˜eÑ$Ô$Ð$Àt€KÝ,6°{ÅDÑ,IÔ,IÐSˆk�oŠo˜iÑ(Ô(Ð(Èt€GÝ# G­TÑ2Ô2Ð:ˆgˆg¸€Gå˜7Ÿ;š; yÑ1Ô1°4Ñ8Ô8€GÝ˜gŸkšk¨,Ñ7Ô7¸Ñ>Ô>€JÝ)¨'¯+ª+°oÑ*FÔ*FÑGÔG€Mð Ø Ø&ðð ð r=   Úfilename_prefixÚ	extensionúOptional[Dict[str, Any]]c               óŽ  — t          | ¦  «        }|d         sdS t          j                             t          j        ¦  «        }|                     d¦  «        }t          j        ¦   «         j        dd…         }|                     d¦  «        pd}|› d|› d|› d|› �t          |d         ¦  «        d	œ}|d
         �|d
         |d
<   |S )zAReturn an xAI ``storage_options`` payload, or None when disabled.rK   Nz%Y%m%d-%H%M%Sé   ú.ÚbinÚ-rf   )Úfilenamerf   rg   )
ri   ÚdatetimeÚnowÚUTCÚstrftimeÚuuidÚuuid4ÚhexÚlstripr   )	r?   rj   rk   rC   rt   ÚtsÚshortÚextÚpayloads	            r+   Úbuild_xai_storage_optionsr   Ä   sØ   € õ *¨,Ñ
7Ô
7€CØˆyŒ>ð Øˆtå
Ô
×
Ò
¥¤Ñ
-Ô
-€CØ	�Š�oÑ	&Ô	&€BÝŒJ‰LŒLÔ˜R˜a˜RÔ €EØ
×
Ò
˜3Ñ
Ô
Ð
( 5€Cà&Ð;Ð;¨Ð;Ð;¨eÐ;Ð;°cÐ;Ð;Ý˜3˜|Ô,Ñ-Ô-ðð €Gð ˆ?ÔÐ'Ø#& Ô#7ˆ�Ñ Ø€Nr=   c                ó”   — t          | ¦  «        }|d         sdS |d         €d}n|d         dz  }d|d›d	|d
k    rdnd› �}d|› d| › d�S )z5User-facing notice for first xAI Imagine storage use.rK   r   rg   Nzwithout an automatic expiryi€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.)ri   )r?   rC   Ú	retentionÚdayss       r+   Úxai_storage_notice_textr†   Ü   sŽ   € å
)¨,Ñ
7Ô
7€CØˆyŒ>ð ØˆrØ
ˆ?ÔÐ#Ø1ˆ	ˆ	à�?Ô# |Ñ4ˆØG ÐGÐGÐG°D¸A²I°I¨S¨SÀ2ÐGÐGˆ	ð	:Øð	:ð 	:à'3ð	:ð 	:ð 	:ðr=   úOptional[str]c                óˆ  — t          | ¦  «        }|sdS 	 ddlm}  |¦   «         dz  }|                     dd¬¦  «         || › d�z  }|                     ¦   «         rdS |                     t          j                             t          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_textrs   rt   ru   Ú	isoformatr%   )r?   Únoticer   Ú
marker_dirÚmarkers        r+   Ú"maybe_mark_xai_storage_notice_seenr”   î   sí   € å$ \Ñ2Ô2€FØð ØˆtðØ4Ð4Ð4Ð4Ð4Ð4à$�_Ñ&Ô&¨Ñ0ˆ
Ø×Ò °ÐÑ5Ô5Ð5Ø ÐGÐGÐGÑGˆØ�=Š=‰?Œ?ð 	Ø�4Ø×Ò�(Ô+×/Ò/µ´Ñ=Ô=×GÒGÑIÔIÈDÑPÐ[bÐÑcÔcÐcØˆøÝð ð ð Øˆˆˆðøøøs   •AB2 ÁAB2 Â2CÃ CF)Úforce_refreshÚapi_key_hintr•   r–   c                ó<  — 	 ddl m} ddlm}  |d¦  «        }| r|                     |¦  «        n|                     ¦   «         }| r|€|                     ¦   «         }t          t          |dd¦  «        pt          |dd¦  «        ¦  «                             ¦   «         }t          t          |dd¦  «        pt          |d	d¦  «        p|j	        ¦  «                             ¦   «          
                    d
¦  «        }t          t          d¦  «        pt          d¦  «        pd¦  «                             ¦   «          
                    d
¦  «        }|                     ||¬¦  «        }	|rd||	dœS n# t          $ r Y nw xY w	 ddlm}
  |
ddt          ¬¦  «        }n@# t           $ r3 t          t          d¦  «        pd¦  «                             ¦   «         }Y nw xY wt          t          d¦  «        pd¦  «                             ¦   «          
                    d
¦  «        }	d||	dœS )u;  Resolve bearer credentials for direct xAI HTTP endpoints.

    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.

    Set ``force_refresh=True`` to perform an unconditional OAuth refresh.
    Reactive callers should also pass the rejected bearer as ``api_key_hint``
    so a freshly loaded multi-account pool refreshes the exact issuing entry,
    not whichever entry its strategy would otherwise select first.
    r   )Ú	load_poolNr   Úruntime_api_keyr   r   Úruntime_base_urlÚbase_urlú/ÚHERMES_XAI_BASE_URLÚXAI_BASE_URL)Úfallback)ÚproviderÚapi_keyr›   )Úresolve_provider_secretr   rd   )Ú
env_getterzhttps://api.x.ai/v1)Úagent.credential_poolr˜   Úhermes_cli.authÚauthÚtry_refresh_matchingÚselectr#   Úgetattrr   ÚDEFAULT_XAI_OAUTH_BASE_URLÚrstripr/   Ú _xai_validate_inference_base_urlr%   Útools.tool_backend_helpersr¢   r   )r•   r–   r˜   Úauth_modÚpoolr*   r   Úfallback_base_urlÚoverride_base_urlr›   r¢   r¡   s               r+   Úresolve_xai_http_credentialsr²     s�  € ð&(Ø3Ð3Ð3Ð3Ð3Ð3Ø*Ð*Ð*Ð*Ð*Ð*àˆy˜Ñ%Ô%ˆð ðˆD×%Ò% lÑ3Ô3Ð3à—’‘”ð 	ð
 ð 	"˜U˜]ð —K’K‘M”MˆEÝÝ�EÐ,¨dÑ3Ô3ð 2Ý�u˜n¨bÑ1Ô1ñ
ô 
÷ Š%‰'Œ'ð 	õ  Ý�EÐ-¨tÑ4Ô4ð 3Ý�u˜j¨"Ñ-Ô-ð3àÔ2ñ
ô 
÷ Š%‰'Œ'—&’&˜‘+”+ð	 	õ
  ÝÐ/Ñ0Ô0ð Ý˜^Ñ,Ô,ðàñ
ô 
÷ Š%‰'Œ'—&’&˜‘+”+ð	 	ð
 ×<Ò<ØØ&ð =ñ 
ô 
ˆð ð 	à'Ø'Ø$ðð ð ð	øõ ð ð ð ØˆðøøøðBØFÐFÐFÐFÐFÐFà)Ð)¨-¸Í=ÐYÑYÔYˆˆøÝð Bð Bð BÝ•m MÑ2Ô2Ð8°bÑ9Ô9×?Ò?ÑAÔAˆˆˆðBøøøå•= Ñ0Ô0ÐIÐ4IÑJÔJ×PÒPÑRÔR×YÒYÐZ]Ñ^Ô^€HàØØðð ð s$   ‚E&E* Å*
E7Å6E7Å;F Æ:GÇG)r   r   )N)r-   r#   )r   r#   )r   r:   )r?   r#   r   r@   )r3   r   r1   r   r   r   )r3   r   r   rT   )r?   r#   rj   r#   rk   r#   r   rl   )r?   r#   r   r#   )r?   r#   r   r‡   )r•   r   r–   r‡   r   r:   )Ú__doc__Ú
__future__r   rs   r   r   rw   Útypingr   r   r   r`   r]   r,   r/   r9   r>   rE   rS   rb   ri   r   r†   r”   r²   r<   r=   r+   ú<module>r¶      s‡  ðØ 6Ð 6à "Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø €€€Ø &Ð &Ð &Ð &Ð &Ð &Ð &Ð &Ð &Ð &ð ):Ð %Ø)9Ð &ð<ð <ð <ð <ð~3ð 3ð 3ð 3ð 3ð )ð )ð )ð )ð3ð 3ð 3ð 3ð	ð 	ð 	ð 	ð	ð 	ð 	ð 	ð2ð 2ð 2ð 2ð6ð ð ð ð>ð ð ð ð0ð ð ð ð$ð ð ð ð*  Ø"&ðHð Hð Hð Hð Hð Hð Hð Hr=   