
    (Gj(                        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dd d.d#ZdS )/z0Shared helpers for direct xAI HTTP integrations.    )annotationsN)AnyDictOptionali ' i  returnboolc                    t           j                            dd                                          rdS 	 ddlm}   |             dz  }|                                sdS t          j        |	                                          }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          t          |pd                                                    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).

    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).
    XAI_API_KEY Tr   get_hermes_homez	auth.jsonF	providersN	xai-oauthtokensaccess_token)osenvirongetstriphermes_constantsr   existsjsonloads	read_text
isinstancedictr   str	Exception)r   	auth_pathstorer   	xai_stater   r   s          4/home/rurouni/.hermes/hermes-agent/tools/xai_http.pyhas_xai_credentialsr#      si   ( 
z~~mR((..00 t444444#O%%3	!! 	5
9..0011.8.E.EOEIIk***4	2<Y2M2MWIMM+...SW	,6y$,G,GQx(((T5?5M5MWvzz.111SWC*++1133444   uus   'E% DE% %
E32E3namer   c                    	 ddl m}  ||           }||S n# t          $ r Y nw xY wt          j                            | |          S )zRead ``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&   6   so    LLLLLL%%d++L    :>>$(((s    
%%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_clir-   r   r,   s    r"   hermes_xai_user_agentr0   H   sN     *******       (;(((s   	 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)r'   r4   r   r   r   r   )r1   r4   cfgsections       r"   _load_config_sectionr7   Q   s    111111kmm+5c4+@+@J#'','''d$Wd33;ww;   			s   AA A&%A&r*   r   r(   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)r*   r(   
normalizeds      r"   _coerce_boolrE   ]   sk    % % [[]]((**
>>>4@@@5N    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 )zNormalize an xAI storage TTL.

    Returns:
        int seconds for an expiring file,
        None for permanent storage (omit expires_after on the wire).
    N>   r   r(   >   r>   nonenullneverforever	permanentr   )
r   r   r   rC   int
ValueError&SAFE_XAI_STORAGE_EXPIRES_AFTER_SECONDSfloatmin%MAX_XAI_STORAGE_EXPIRES_AFTER_SECONDS)r*   rD   secondss      r"   _coerce_expires_afterrU   i   s     }t% 	:[[]]((**
((4OOO4	:
OOEE 	: 	: 	: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storager=   T
public_urlexpires_after)r=   rY   rZ   )r7   r   r   r   rE   rU   )r1   r6   xai_sectionrX   r=   rY   rZ   s          r"   read_xai_imagine_storage_configr\      s     #<00G(27D(A(AK'++e$$$tK,6{D,I,ISkooi(((tG#GT22:ggG7;;y11488Ggkk,77>>J)'++o*F*FGGM  &  rF   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.r=   Nz%Y%m%d-%H%M%S   .bin-rY   )filenamerY   rZ   )
r\   datetimenowUTCstrftimeuuiduuid4hexlstripr   )	r1   r]   r^   r5   rg   tsshortextpayloads	            r"   build_xai_storage_optionsrr      s     *,
7
7Cy> t




-
-C	o	&	&BJLLRaR E


3


(5C&;;;;e;;c;;3|,-- G ?'#&#7 NrF   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.r=   r   rZ   Nzwithout an automatic expiryiQ 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.)r\   )r1   r5   	retentiondayss       r"   xai_storage_notice_textry      s    
),
7
7Cy> r
?#1		?#|4GGGGDAIISS2GG		:	: 	:'3	: 	: 	:rF   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              |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
)ry   r   r   mkdirr   
write_textrf   rg   rh   	isoformatr   )r1   noticer   
marker_dirmarkers        r"   "maybe_mark_xai_storage_notice_seenr      s    $\22F t444444$_&&0
555GGGG==?? 	4(+//==GGIIDPQQQ   s   AB0 AB0 0B?>B?Fforce_refreshr   Dict[str, str]c                   	 ddl m}  ||           }t          |                    d          pd                                          }t          |                    d          pd                                                              d          }|rd||pd	d
S n# t          $ r Y nw xY w| s	 ddlm}  |d          }t          |                    d          pd                                          }t          |                    d          pd                                                              d          }|rd||pd	d
S n# t          $ r Y nw xY wt          t          d          pd                                          }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 bypass the resolver's JWT-exp shortcut and
    perform an unconditional OAuth refresh. Callers should use this only as a
    reactive remediation after a server 401 (mid-window revocation, opaque
    tokens where the proactive JWT check is a no-op, etc.), not as a default —
    the auth-store lock is held for the duration of the refresh.
    r   )%resolve_xai_oauth_runtime_credentialsr   api_keyr   base_url/r   zhttps://api.x.ai/v1)providerr   r   )resolve_runtime_provider)	requestedr
   XAI_BASE_URLrW   )
hermes_cli.authr   r   r   r   rstripr   hermes_cli.runtime_providerr   r&   )r   r   credsr   r   r   runtimer   s           r"   resolve_xai_http_credentialsr      s4    IIIIII55MRRR599Y//5266<<>>uyy,,23399;;BB3GG 	''$=(=  	      	LLLLLL..EEEGw{{955;<<BBDDL7;;z228b99??AAHHMMH  ++ ( A,A    	 	 	D	 -..4"55;;==G=00I4IJJPPRRYYZ]^^H  s%   BB 
B+*B+1BE 
EE)r   r   )N)r$   r   )r   r   )r1   r   r   r2   )r*   r   r(   r   r   r   )r*   r   r   rG   )r1   r   r]   r   r^   r   r   r_   )r1   r   r   r   )r1   r   r   rz   )r   r   r   r   )__doc__
__future__r   rf   r   r   rj   typingr   r   r   rS   rP   r#   r&   r0   r7   rE   rU   r\   rr   ry   r   r    rF   r"   <module>r      si   6 6 " " " " " "   				  & & & & & & & & & & ): %)9 &# # # #L) ) ) ) )$) ) ) )	 	 	 		 	 	 	2 2 2 26   >   0   $   & ;@ 5 5 5 5 5 5 5 5rF   