
    [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%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/d$ZdS )0z0Shared 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          |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).
    XAI_API_KEY Tr   get_hermes_homez	auth.jsonF	providersN	xai-oauthtokensaccess_tokencredential_pool)osenvirongetstriphermes_constantsr   existsjsonloads	read_text
isinstancedictstrlist	Exception)
r   	auth_pathstorer   	xai_stater   r   r   entriesentrys
             0/home/ice/.hermes/hermes-agent/tools/xai_http.pyhas_xai_credentialsr'      s9   . 
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|!r""((** 	4 ;EUD:Q:Q[%))$5666W[ /400O,,, 	
 gt$$ 	      !%.. uyy44:;;AACC  44 u   uus%   'H C9H B?H H 
H,+H,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*   I   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_clir1   r    r0   s    r&   hermes_xai_user_agentr4   [   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+   r8   r   r   r   r    )r5   r8   cfgsections       r&   _load_config_sectionr;   d   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_boolrI   p   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,   >   rB   nonenullneverforever	permanentr   )
r   r   r   rG   int
ValueError&SAFE_XAI_STORAGE_EXPIRES_AFTER_SECONDSfloatmin%MAX_XAI_STORAGE_EXPIRES_AFTER_SECONDS)r.   rH   secondss      r&   _coerce_expires_afterrY   |   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storagerA   T
public_urlexpires_after)rA   r]   r^   )r;   r   r   r   rI   rY   )r5   r:   xai_sectionr\   rA   r]   r^   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  &  rJ   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.rA   Nz%Y%m%d-%H%M%S   .bin-r]   )filenamer]   r^   )
r`   datetimenowUTCstrftimeuuiduuid4hexlstripr   )	r5   ra   rb   r9   rk   tsshortextpayloads	            r&   build_xai_storage_optionsrv      s     *,
7
7Cy> t




-
-C	o	&	&BJLLRaR E


3


(5C&;;;;e;;c;;3|,-- G ?'#&#7 NrJ   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.rA   r   r^   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`   )r5   r9   	retentiondayss       r&   xai_storage_notice_textr}      s    
),
7
7Cy> r
?#1		?#|4GGGGDAIISS2GG		:	: 	:'3	: 	: 	:rJ   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
)r}   r   r   mkdirr   
write_textrj   rk   rl   	isoformatr    )r5   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_refreshapi_key_hintr   r   Dict[str, str]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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 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   r
   zhttps://api.x.ai/v1r[   )agent.credential_poolr   hermes_cli.authauthtry_refresh_matchingselectr   getattrr   DEFAULT_XAI_OAUTH_BASE_URLrstripr*    _xai_validate_inference_base_urlr    )r   r   r   auth_modpoolr%   r   fallback_base_urloverride_base_urlr   r   s              r&   resolve_xai_http_credentialsr      sK   &(333333******y%% D%%l333 	
  	"U] KKMMEE,d33 2unb11
 
 %'' 	  E-t44 3uj"--32
 
 %''&&++	 	
  /00 ^,,
 
 %''&&++	 	
 <<& = 
 
  	''$  	     -..4"55;;==G=00I4IJJPPRRYYZ]^^H  s   E&E* *
E76E7)r   r   )N)r(   r   )r   r   )r5   r   r   r6   )r.   r   r,   r   r   r   )r.   r   r   rK   )r5   r   ra   r   rb   r   r   rc   )r5   r   r   r   )r5   r   r   r~   )r   r   r   r~   r   r   )__doc__
__future__r   rj   r   r   rn   typingr   r   r   rW   rT   r'   r*   r4   r;   rI   rY   r`   rv   r}   r   r    rJ   r&   <module>r      ss   6 6 " " " " " "   				  & & & & & & & & & & ): %)9 &6 6 6 6r) ) ) ) )$) ) ) )	 	 	 		 	 	 	2 2 2 26   >   0   $   *  "&C C C C C C C CrJ   