§
    øžyjyP  ã                  óÔ  — d Z ddlmZ ddlZddlZddlZddlmZmZmZ ddl	m
Z
mZmZmZmZ ddlZddlmZmZ ddlmZmZ  ej        e¦  «        ZdZd	Zd
ZdZdZdZdPd„ZdQd„Z dRd„Z!dSd„Z"dSd„Z#dTd„Z$dUd„Z%dVd „Z&dWd#„Z'dXd'„Z(dYd)„Z)dZd+„Z*d[d.„Z+	 	 	 	 	 	 d\d]d6„Z,d7d8d9d:d;d<œd=d>d:id?d@œd=d>d:idAd@œd:dBd<œd:dCd<œdDdEd0dFœdDdGd0dFœdHœd1gdIœdJœZ-dK„ Z. ej/        d7d7e-e.e%dLgdMdN¬O¦  «         dS )^u…  X Search tool backed by xAI's built-in ``x_search`` Responses API tool.

Authentication
--------------
The tool registers when **either** xAI credential path is available:

* ``XAI_API_KEY`` is set in ``~/.hermes/.env`` or the process environment
  (paid xAI API key), OR
* The user is signed in via xAI Grok OAuth â€” SuperGrok subscription â€”
  i.e. ``hermes auth add xai-oauth`` has been run and the stored refresh
  token still works.

Credential preference at call time matches
:func:`tools.xai_http.resolve_xai_http_credentials`: SuperGrok OAuth first,
direct OAuth resolver second, ``XAI_API_KEY`` last. That helper also
auto-refreshes the OAuth access token when it's within the refresh skew
window, so a ``True`` from :func:`check_x_search_requirements` means the
bearer is fetchable AND non-empty.

Defensive output
----------------
The tool surfaces two additional signals beyond xAI's raw response so callers
can tell a real citation-backed answer from an unsourced one:

* ``from_date`` / ``to_date`` are validated client-side before the HTTP call.
  Malformed (non ``YYYY-MM-DD``), inverted (``from_date > to_date``), and
  pure-future ranges (``from_date`` later than today UTC) fail fast with a
  clear error instead of burning an API call. ``to_date`` in the future is
  still allowed so callers can legitimately request "from yesterday to
  tomorrow".
* Successful responses carry ``degraded`` and ``degraded_reason`` fields.
  ``degraded`` is ``True`` when any narrowing filter (handles or dates) was
  active AND xAI returned no citations in either the top-level ``citations``
  array or the inline ``url_citation`` annotations. In that case the
  ``answer`` came from the model's own knowledge rather than the X index,
  and the caller should treat the result as unsourced.

Salvaged from PR #10786 (originally by @Jaaneek); credential resolution
reworked to honor both auth modes per Teknium's design.
é    )ÚannotationsN)ÚdateÚdatetimeÚtimezone)ÚAnyÚDictÚListÚOptionalÚTuple)ÚregistryÚ
tool_error)Úhermes_xai_user_agentÚresolve_xai_http_credentialszhttps://api.x.ai/v1zgrok-4.5é´   é   )ÚlowÚmediumÚhighÚxhighé
   ÚreturnúDict[str, Any]c                 ót   — 	 ddl m}   | ¦   «                              di ¦  «        pi S # t          $ r i cY S w xY w)Nr   ©Úload_configÚx_search)Úhermes_cli.configr   ÚgetÚ	Exceptionr   s    ú9/home/ragecks/.hermes/hermes-agent/tools/x_search_tool.pyÚ_load_x_search_configr!   F   s^   € ðØ1Ð1Ð1Ð1Ð1Ð1àˆ{‰}Œ}× Ò  ¨RÑ0Ô0Ð6°BÐ6øÝð ð ð Øˆ	ˆ	ˆ	ðøøøs   ‚%( ¨7¶7Ústrc                 ó˜   — t          ¦   «         } t          |                      d¦  «        pd¦  «                             ¦   «         pt          S )NÚmodelÚ )r!   r"   r   ÚstripÚDEFAULT_X_SEARCH_MODEL)Úcfgs    r    Ú_get_x_search_modelr)   O   s>   € Ý
Ñ
!Ô
!€CÝ�—’˜Ñ Ô Ð& BÑ'Ô'×-Ò-Ñ/Ô/ÐIÕ3IÐJó    úOptional[str]c                 ón  — t          ¦   «         } |                      d¦  «        }|�!t          |¦  «                             ¦   «         sd S t          |¦  «                             ¦   «                              ¦   «         }|t
          vr0d                     t
          ¦  «        }t          d|› d|›d�¦  «        ‚|S )NÚreasoning_effortú, z*x_search.reasoning_effort must be one of: z (got ú))r!   r   r"   r&   ÚlowerÚX_SEARCH_REASONING_EFFORTSÚjoinÚ
ValueError)r(   Ú	raw_valueÚeffortÚalloweds       r    Ú_get_x_search_reasoning_effortr7   T   s¾   € Ý
Ñ
!Ô
!€CØ—’Ð*Ñ+Ô+€IØÐ¥ I¡¤× 4Ò 4Ñ 6Ô 6ÐØˆtå�‰^Œ^×!Ò!Ñ#Ô#×)Ò)Ñ+Ô+€FØÕ/Ð/Ð/Ø—)’)Õ6Ñ7Ô7ˆÝð#¸ð #ð #Øð#ð #ð #ñ
ô 
ð 	
ð €Mr*   Úintc                 ó¾   — t          ¦   «         } |                      dt          ¦  «        }	 t          dt	          |¦  «        ¦  «        S # t
          $ r
 t          cY S w xY w)NÚtimeout_secondsé   )r!   r   Ú DEFAULT_X_SEARCH_TIMEOUT_SECONDSÚmaxr8   r   ©r(   r4   s     r    Ú_get_x_search_timeout_secondsr?   d   sd   € Ý
Ñ
!Ô
!€CØ—’Ð)Õ+KÑLÔL€Ið0Ý�2•s˜9‘~”~Ñ&Ô&Ð&øÝð 0ð 0ð 0Ý/Ð/Ð/Ð/ð0øøøó   «A ÁAÁAc                 ó¾   — t          ¦   «         } |                      dt          ¦  «        }	 t          dt	          |¦  «        ¦  «        S # t
          $ r
 t          cY S w xY w)NÚretriesr   )r!   r   ÚDEFAULT_X_SEARCH_RETRIESr=   r8   r   r>   s     r    Ú_get_x_search_retriesrD   m   sc   € Ý
Ñ
!Ô
!€CØ—’˜	Õ#;Ñ<Ô<€Ið(Ý�1•c˜)‘n”nÑ%Ô%Ð%øÝð (ð (ð (Ý'Ð'Ð'Ð'ð(øøør@   úTuple[str, str, str]c                 óš  — t          ¦   «         } t          |                      d¦  «        pd¦  «                             ¦   «         }|st	          d¦  «        ‚t          |                      d¦  «        pt
          ¦  «                             ¦   «                              d¦  «        }t          |                      d¦  «        pd¦  «        }|||fS )uè  Return ``(api_key, base_url, source)``.

    ``source`` is one of ``"xai-oauth"`` or ``"xai"`` so callers (and tests)
    can tell which credential path won. Raises ``RuntimeError`` if no usable
    credential is available â€” the registered :func:`check_x_search_requirements`
    gate makes that case unreachable in normal operation, but the runtime
    check exists so a credential that expires between registration and
    invocation produces a clean tool error instead of a 401.
    Úapi_keyr%   z~No xAI credentials available. Run `hermes auth add xai-oauth` to sign in with your SuperGrok subscription, or set XAI_API_KEY.Úbase_urlú/ÚproviderÚxai)r   r"   r   r&   ÚRuntimeErrorÚDEFAULT_XAI_BASE_URLÚrstrip)ÚcredsrG   rH   Úsources       r    Ú_resolve_xai_bearerrQ   z   sÀ   € õ )Ñ*Ô*€EÝ�%—)’)˜IÑ&Ô&Ð,¨"Ñ-Ô-×3Ò3Ñ5Ô5€GØð 
ÝðOñ
ô 
ð 	
õ �5—9’9˜ZÑ(Ô(Ð@Õ,@ÑAÔA×GÒGÑIÔI×PÒPÐQTÑUÔU€HÝ�—’˜:Ñ&Ô&Ð/¨%Ñ0Ô0€FØ�H˜fÐ$Ð$r*   Úboolc                 óÈ   — 	 t          ¦   «         } t          t          |                      d¦  «        pd¦  «                             ¦   «         ¦  «        S # t
          $ r Y dS w xY w)a)  Return True when xAI credentials are available AND valid.

    ``resolve_xai_http_credentials`` calls
    :func:`hermes_cli.auth.resolve_xai_oauth_runtime_credentials` which
    auto-refreshes the OAuth access token if it's expiring; a successful
    return therefore implies a usable bearer.
    rG   r%   F)r   rR   r"   r   r&   r   )rO   s    r    Úcheck_x_search_requirementsrT   �   sg   € ðÝ,Ñ.Ô.ˆÝ•C˜Ÿ	š	 )Ñ,Ô,Ð2°Ñ3Ô3×9Ò9Ñ;Ô;Ñ<Ô<Ð<øÝð ð ð Øˆuˆuðøøøs   ‚AA Á
A!Á A!ÚhandlesúOptional[List[str]]Ú
field_nameú	List[str]c                ó  — g }| pg D ]O}t          |pd¦  «                             ¦   «                              d¦  «        }|r|                     |¦  «         ŒPt	          |¦  «        t
          k    rt          |› dt
          › d�¦  «        ‚|S )Nr%   ú@z supports at most z handles)r"   r&   ÚlstripÚappendÚlenÚMAX_HANDLESr3   )rU   rW   ÚcleanedÚhandleÚ
normalizeds        r    Ú_normalize_handlesrb   £   s•   € Ø€GØ�-˜Rð 'ð 'ˆÝ˜˜ 2Ñ&Ô&×,Ò,Ñ.Ô.×5Ò5°cÑ:Ô:ˆ
Øð 	'Ø�NŠN˜:Ñ&Ô&Ð&øÝ
ˆ7�|„|•kÒ!Ð!Ý˜JÐOÐO½+ÐOÐOÐOÑPÔPÐPØ€Nr*   Úvaluer   c                óÊ   — |                       ¦   «         }	 t          j        |d¦  «                             ¦   «         S # t          $ r}t	          |› d|›d�¦  «        |‚d}~ww xY w)aë  Parse a strict YYYY-MM-DD string into a ``date``.

    xAI accepts any string in the ``from_date``/``to_date`` slots and silently
    returns an answer with no citations when the value is malformed or refers
    to a window where no posts can exist. That behavior burns a billable API
    call and produces a confident-sounding fluff answer that's hard for callers
    to distinguish from a real result. Validating client-side fails fast and
    gives the agent a clear error to act on.
    z%Y-%m-%dz must be YYYY-MM-DD (got r/   N)r&   r   Ústrptimer   r3   )rc   rW   ÚrawÚexcs       r    Ú_parse_iso_daterh   ®   s}   € ð �+Š+‰-Œ-€CðÝÔ   jÑ1Ô1×6Ò6Ñ8Ô8Ð8øÝð ð ð ÝØÐ<Ð<°CÐ<Ð<Ð<ñ
ô 
àð	øøøøðøøøs   –&= ½
A"ÁAÁA"Ú	from_dateÚto_dateÚNonec                ó  — d}d}|                       ¦   «         rt          | d¦  «        }|                      ¦   «         rt          |d¦  «        }|rB|r@||k    r:t          d|                     ¦   «         › d|                     ¦   «         › d�¦  «        ‚|�pt	          j        t          j        ¦  «                             ¦   «         }||k    r<t          d|                     ¦   «         › d|                     ¦   «         › d�¦  «        ‚dS dS )uê  Validate ``from_date`` / ``to_date`` before they reach xAI.

    Rules:
      * Either field, if non-empty, must parse as ``YYYY-MM-DD``.
      * When both are set, ``from_date <= to_date``.
      * ``from_date`` must not be later than today UTC â€” no posts can exist
        in a window that hasn't started yet, so the call would be guaranteed
        to return zero citations. ``to_date`` in the future is allowed
        (callers may legitimately set "from yesterday to tomorrow").
    Nri   rj   zfrom_date (z ) must be on or before to_date (r/   zC) is in the future; X Search only indexes past posts (today UTC is )	r&   rh   r3   Ú	isoformatr   Únowr   Úutcr   )ri   rj   Úparsed_fromÚ	parsed_toÚ	today_utcs        r    Ú_validate_date_rangers   Á   s?  € ð #'€KØ $€IØ‡‚ÑÔð >Ý% i°Ñ=Ô=ˆØ‡}‚}�„ð 8Ý# G¨YÑ7Ô7ˆ	Øð 
�yð 
 [°9Ò%<Ð%<Ýð1˜+×/Ò/Ñ1Ô1ð 1ð 1Ø!×+Ò+Ñ-Ô-ð1ð 1ð 1ñ
ô 
ð 	
ð ÐÝ”L¥¤Ñ.Ô.×3Ò3Ñ5Ô5ˆ	Ø˜Ò"Ð"Ýð,˜k×3Ò3Ñ5Ô5ð ,ð ,à×&Ò&Ñ(Ô(ð,ð ,ð ,ñô ð ð Ðà"Ð"r*   Úpayloadc                ó4  — t          |                      d¦  «        pd¦  «                             ¦   «         }|r|S g }|                      dg ¦  «        pg D ]�}|                     d¦  «        dk    rŒ|                     dg ¦  «        pg D ]h}|                     d¦  «        }|dv rMt          |                     d¦  «        pd¦  «                             ¦   «         }|r|                     |¦  «         ŒiŒžd	                     |¦  «                             ¦   «         S )
NÚoutput_textr%   ÚoutputÚtypeÚmessageÚcontent>   Útextrv   r{   z

)r"   r   r&   r\   r2   )rt   rv   ÚpartsÚitemrz   Úctyper{   s          r    Ú_extract_response_textr   á   s$  € Ý�g—k’k -Ñ0Ô0Ð6°BÑ7Ô7×=Ò=Ñ?Ô?€KØð ØÐà€EØ—’˜H bÑ)Ô)Ð/¨Rð 'ð 'ˆØ�8Š8�FÑÔ˜yÒ(Ð(ØØ—x’x 	¨2Ñ.Ô.Ð4°"ð 	'ð 	'ˆGØ—K’K Ñ'Ô'ˆEØÐ/Ð/Ð/Ý˜7Ÿ;š; vÑ.Ô.Ð4°"Ñ5Ô5×;Ò;Ñ=Ô=�Øð 'Ø—L’L Ñ&Ô&Ð&øð	'ð �;Š;�uÑÔ×#Ò#Ñ%Ô%Ð%r*   úList[Dict[str, Any]]c                óä  — g }|                       dg ¦  «        pg D ]Ô}|                      d¦  «        dk    rŒ|                      dg ¦  «        pg D ]Ÿ}|                      dg ¦  «        pg D ]„}|                      d¦  «        dk    rŒ|                     |                      dd¦  «        |                      d	d¦  «        |                      d
¦  «        |                      d¦  «        dœ¦  «         Œ…Œ ŒÕ|S )Nrw   rx   ry   rz   r   Úurl_citationÚurlr%   ÚtitleÚstart_indexÚ	end_index)rƒ   r„   r…   r†   )r   r\   )rt   Ú	citationsr}   rz   Ú
annotations        r    Ú_extract_inline_citationsr‰   ó   s  € Ø&(€IØ—’˜H bÑ)Ô)Ð/¨Rð ð ˆØ�8Š8�FÑÔ˜yÒ(Ð(ØØ—x’x 	¨2Ñ.Ô.Ð4°"ð 	ð 	ˆGØ%Ÿkšk¨-¸Ñ<Ô<ÐBÀð 
ð 
�
Ø—>’> &Ñ)Ô)¨^Ò;Ð;ØØ× Ò à)Ÿ~š~¨e°RÑ8Ô8Ø!+§¢°¸Ñ!<Ô!<Ø'1§~¢~°mÑ'DÔ'DØ%/§^¢^°KÑ%@Ô%@ð	ð ñô ð ð ð
ð	ð Ðr*   rg   úrequests.HTTPErrorc                ó�  — t          | dd ¦  «        }|€t          | ¦  «        S 	 |                     ¦   «         }n# t          $ r d }Y nw xY wt	          |t
          ¦  «        r›t          |                     d¦  «        pd¦  «                             ¦   «         }t          |                     d¦  «        pd¦  «                             ¦   «         }|pt          |¦  «        }|r||vr|› d|› �}|pt          | ¦  «        S t          t          |dd¦  «        pd¦  «                             ¦   «         }|r
|d d…         S t          | ¦  «        S )NÚresponseÚcoder%   Úerrorz: r{   éô  )Úgetattrr"   Újsonr   Ú
isinstanceÚdictr   r&   )rg   rŒ   rt   r�   rŽ   ry   r{   s          r    Ú_http_error_messager”     sU  € Ý�s˜J¨Ñ-Ô-€HØÐÝ�3‰xŒxˆðØ—-’-‘/”/ˆˆøÝð ð ð Øˆˆˆðøøøõ �'�4Ñ Ô ð #Ý�7—;’;˜vÑ&Ô&Ð,¨"Ñ-Ô-×3Ò3Ñ5Ô5ˆÝ�G—K’K Ñ(Ô(Ð.¨BÑ/Ô/×5Ò5Ñ7Ô7ˆØÐ'�3˜w™<œ<ˆØð 	+�D Ð'Ð'ØÐ*Ð* Ð*Ð*ˆGØÐ"�#˜c™(œ(Ð"å�w�x ¨Ñ,Ô,Ð2°Ñ3Ô3×9Ò9Ñ;Ô;€DØð Ø�D�S�DŒzÐÝˆs‰8Œ8€Os   ¤9 ¹AÁAr%   FÚqueryÚallowed_x_handlesÚexcluded_x_handlesÚenable_image_understandingÚenable_video_understandingc                ó  — | r|                       ¦   «         st          d¦  «        S 	 t          ¦   «         \  }}}	n3# t          $ r&}
t          t	          |
¦  «        ¦  «        cY d }
~
S d }
~
ww xY w	 t          |d¦  «        }t          |d¦  «        }|r|rt          d¦  «        S 	 t          ||¦  «         n3# t          $ r&}
t          t	          |
¦  «        ¦  «        cY d }
~
S d }
~
ww xY w	 t          ¦   «         }n3# t          $ r&}
t          t	          |
¦  «        ¦  «        cY d }
~
S d }
~
ww xY wddi}|r||d<   |r||d<   |                      ¦   «         r|                      ¦   «         |d<   |                      ¦   «         r|                      ¦   «         |d<   |rd	|d
<   |rd	|d<   t          ¦   «         d|                       ¦   «         dœg|gddœ}|rd|i|d<   t          ¦   «         }t          ¦   «         }d }t          |dz   ¦  «        D �]`}	 t          j        |› d�d|› �dt          ¦   «         dœ||¬¦  «        }|                     ¦   «           �n# t          j        $ r‘}t%          t%          |dd ¦  «        dd ¦  «        }|�|dk     s||k    r‚ t&                               d|dz   |dz   t+          |¦  «        ¦  «         t-          j        t1          dd|dz   z  ¦  «        ¦  «         Y d }~Œäd }~wt          j        t          j        f$ r]}||k    r‚ t&                               d|dz   |dz   |¦  «         t-          j        t1          dd|dz   z  ¦  «        ¦  «         Y d }~�ŒZd }~ww xY w|€t          d¦  «        ‚|                     ¦   «         }t9          |¦  «        }t;          |                     d ¦  «        pg ¦  «        }t?          |¦  «        }g }|r|                      d¦  «         |r|                      d¦  «         |                      ¦   «         r|                      d¦  «         |                      ¦   «         r|                      d¦  «         tC          |¦  «        o| o| }|rd!d" "                    |¦  «        › �nd }t7          j#        d	d#|	d|d$         |                       ¦   «         |||||d%œd¬&¦  «        S # t          j        $ rb}t&           $                    d'|d	¬(¦  «         t7          j#        dd#dt+          |¦  «        tK          |¦  «        j&        d)œd¬&¦  «        cY d }~S d }~wt          j        $ re}t&           $                    d*|d	¬(¦  «         t7          j#        dd#dd+t          ¦   «         › d,�tK          |¦  «        j&        d)œd¬&¦  «        cY d }~S d }~wtN          $ rb}t&           $                    d'|d	¬(¦  «         t7          j#        dd#dt	          |¦  «        tK          |¦  «        j&        d)œd¬&¦  «        cY d }~S d }~ww xY w)-Nzquery is required for x_searchr–   r—   z@allowed_x_handles and excluded_x_handles cannot be used togetherrx   r   ri   rj   Tr˜   r™   Úuser)Úrolerz   F)r$   ÚinputÚtoolsÚstorer5   Ú	reasoningé   z
/responseszBearer zapplication/json)ÚAuthorizationzContent-Typez
User-Agent)Úheadersr‘   ÚtimeoutrŒ   Ústatus_coder�   z.x_search upstream failure on attempt %s/%s: %sg      @g      ø?z/x_search transient failure on attempt %s/%s: %sz*x_search request did not return a responser‡   z'no citations returned despite filters: r.   rK   r$   )ÚsuccessrJ   Úcredential_sourceÚtoolr$   r•   Úanswerr‡   Úinline_citationsÚdegradedÚdegraded_reason)Úensure_asciizx_search failed: %s)Úexc_info)r¦   rJ   r¨   rŽ   Ú
error_typezx_search timed out: %szxAI x_search timed out after z seconds)(r&   r   rQ   rL   r"   rb   rs   r3   r7   r)   r?   rD   ÚrangeÚrequestsÚpostr   Úraise_for_statusÚ	HTTPErrorr�   ÚloggerÚwarningr”   ÚtimeÚsleepÚminÚReadTimeoutÚConnectionErrorr‘   r   Úlistr   r‰   r\   rR   r2   ÚdumpsrŽ   rx   Ú__name__r   )r•   r–   r—   ri   rj   r˜   r™   rG   rH   rP   rg   r6   Úexcludedr-   Útool_defrt   r:   Úmax_retriesrŒ   ÚattemptÚer¥   Údatar©   r‡   rª   Úactive_filtersr«   r¬   s                                r    Úx_search_toolrÆ   #  s½  € ð ð <˜Ÿš™œð <ÝÐ:Ñ;Ô;Ð;ð$Ý$7Ñ$9Ô$9Ñ!ˆ�˜6˜6øÝð $ð $ð $Ý�#˜c™(œ(Ñ#Ô#Ð#Ð#Ð#Ð#Ð#Ð#øøøøð$øøøðh
Ý$Ð%6Ð8KÑLÔLˆÝ%Ð&8Ð:NÑOÔOˆØð 	b�xð 	bÝÐ`ÑaÔaÐað	(Ý  ¨GÑ4Ô4Ð4Ð4øÝð 	(ð 	(ð 	(Ý�c #™hœhÑ'Ô'Ð'Ð'Ð'Ð'Ð'Ð'øøøøð	(øøøð	(Ý=Ñ?Ô?ÐÐøÝð 	(ð 	(ð 	(Ý�c #™hœhÑ'Ô'Ð'Ð'Ð'Ð'Ð'Ð'øøøøð	(øøøð %+¨JÐ#7ˆØð 	4Ø,3ˆHÐ(Ñ)Øð 	6Ø-5ˆHÐ)Ñ*Ø�?Š?ÑÔð 	6Ø$-§O¢OÑ$5Ô$5ˆH�[Ñ!Ø�=Š=‰?Œ?ð 	2Ø")§-¢-¡/¤/ˆH�YÑØ%ð 	:Ø59ˆHÐ1Ñ2Ø%ð 	:Ø59ˆHÐ1Ñ2õ )Ñ*Ô*ð #Ø$Ÿ{š{™}œ}ðð ðð �ZØð

ð 

ˆð ð 	@Ø$,Ð.>Ð#?ˆG�KÑ å7Ñ9Ô9ˆÝ+Ñ-Ô-ˆØ04ˆÝ˜[¨1™_Ñ-Ô-ð "	:ñ "	:ˆGð!:Ý#œ=ØÐ+Ð+Ð+à)<°7Ð)<Ð)<Ø(:Ý&;Ñ&=Ô&=ðð ð
 !Ø+ð	ñ 	ô 	�ð ×)Ò)Ñ+Ô+Ð+Ø‘øÝÔ%ð 
:ð 
:ð 
:Ý%¥g¨a°¸TÑ&BÔ&BÀMÐSWÑXÔX�ØÐ&¨+¸Ò*;Ð*;¸wÈ+Ò?UÐ?UØÝ—’ØDØ˜a‘KØ !‘OÝ'¨Ñ*Ô*ñ	ô ð õ ”
�3˜s C¨7°Q©;Ñ$7Ñ8Ô8Ñ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9øøøøÝÔ(­(Ô*BÐCð 	:ð 	:ð 	:Ø˜kÒ)Ð)ØÝ—’ØEØ˜a‘KØ !‘OØñ	ô ð õ ”
�3˜s C¨7°Q©;Ñ$7Ñ8Ô8Ñ9Ô9Ð9Ð9Ð9Ð9Ð9Ñ9øøøøð	:øøøð ÐÝÐKÑLÔLÐLà�}Š}‰Œˆå'¨Ñ-Ô-ˆÝ˜Ÿš +Ñ.Ô.Ð4°"Ñ5Ô5ˆ	Ý4°TÑ:Ô:Ðð %'ˆØð 	7Ø×!Ò!Ð"5Ñ6Ô6Ð6Øð 	8Ø×!Ò!Ð"6Ñ7Ô7Ð7Ø�?Š?ÑÔð 	/Ø×!Ò! +Ñ.Ô.Ð.Ø�=Š=‰?Œ?ð 	-Ø×!Ò! )Ñ,Ô,Ð,Ý˜Ñ'Ô'ÐR°	¨MÐRÐBRÐ>Rˆð ðÐQ°d·i²iÀÑ6OÔ6OÐQÐQÐQàð 	õ ŒzàØ!Ø%+Ø"Ø  Ô)ØŸš™œØ Ø&Ø$4Ø$Ø#2ðð ð ð
ñ 
ô 
ð 	
øõ  Ôð 
ð 
ð 
Ý�ŠÐ*¨A¸ˆÑ=Ô=Ð=ÝŒzà Ø!Ø"Ý,¨QÑ/Ô/Ý" 1™gœgÔ.ðð ð ð	
ñ 	
ô 	
ð 		
ð 		
ð 		
ð 		
ð 		
ð 		
øøøøõ Ôð 
ð 
ð 
Ý�ŠÐ-¨q¸4ˆÑ@Ô@Ð@ÝŒzà Ø!Ø"ØbÕ9VÑ9XÔ9XÐbÐbÐbÝ" 1™gœgÔ.ðð ð ð	
ñ 	
ô 	
ð 		
ð 		
ð 		
ð 		
ð 		
ð 		
øøøøõ ð 
ð 
ð 
Ý�ŠÐ*¨A¸ˆÑ=Ô=Ð=ÝŒzà Ø!Ø"Ý˜Q™œÝ" 1™gœgÔ.ðð ð ð	
ñ 	
ô 	
ð 		
ð 		
ð 		
ð 		
ð 		
ð 		
øøøøð
øøøs  §: º
A*ÁA%ÁA*Á%A*Á.2R8 Â"B3 Â2R8 Â3
C#Â=CÃC#ÃR8 ÃC#Ã#R8 Ã'C6 Ã5R8 Ã6
D&Ä D!ÄD&ÄR8 Ä!D&Ä&CR8 ÈAIÉR8 ÉM!ÉBK&Ë!R8 Ë&M!ÌAMÍR8 ÍM!Í!ER8 Ò8XÓAT$ÔXÔ$XÔ6AVÖXÖXÖ#AX ×:XØ Xr   uÖ  Search X (Twitter) posts, profiles, and threads using xAI's built-in X Search tool. Read-only discovery only: use this for current discussion, reactions, or claims on public X rather than general web pages. Do not use it to post, reply, like, DM, upload media, delete, or inspect the user's authenticated X account â€” those require a separate authenticated X API surface outside this tool. Available when xAI credentials are configured (SuperGrok OAuth or XAI_API_KEY).ÚobjectÚstringzWhat to look up on X.)rx   ÚdescriptionÚarrayrx   z;Optional list of X handles to include exclusively (max 10).)rx   ÚitemsrÉ   z/Optional list of X handles to exclude (max 10).z)Optional start date in YYYY-MM-DD format.z'Optional end date in YYYY-MM-DD format.Úbooleanz?Whether xAI should analyze images attached to matching X posts.)rx   rÉ   Údefaultz?Whether xAI should analyze videos attached to matching X posts.©r•   r–   r—   ri   rj   r˜   r™   )rx   Ú
propertiesÚrequired)ÚnamerÉ   Ú
parametersc                óv  — t          |                      dd¦  «        |                      d¦  «        |                      d¦  «        |                      dd¦  «        |                      dd¦  «        t          |                      dd¦  «        ¦  «        t          |                      d	d¦  «        ¦  «        ¬
¦  «        S )Nr•   r%   r–   r—   ri   rj   r˜   Fr™   rÎ   )rÆ   r   rR   )ÚargsÚkws     r    Ú_handle_x_searchrÖ     s    € ÝØ�hŠh�w Ñ#Ô#ØŸ(š(Ð#6Ñ7Ô7ØŸ8š8Ð$8Ñ9Ô9Ø—(’(˜;¨Ñ+Ô+Ø—’˜ BÑ'Ô'Ý#'¨¯ªÐ1MÈuÑ(UÔ(UÑ#VÔ#VÝ#'¨¯ªÐ1MÈuÑ(UÔ(UÑ#VÔ#Vðñ ô ð r*   ÚXAI_API_KEYu   ðŸ�¦i † )rÑ   ÚtoolsetÚschemaÚhandlerÚcheck_fnÚrequires_envÚemojiÚmax_result_size_chars)r   r   )r   r"   )r   r+   )r   r8   )r   rE   )r   rR   )rU   rV   rW   r"   r   rX   )rc   r"   rW   r"   r   r   )ri   r"   rj   r"   r   rk   )rt   r   r   r"   )rt   r   r   r€   )rg   rŠ   r   r"   )NNr%   r%   FF)r•   r"   r–   rV   r—   rV   ri   r"   rj   r"   r˜   rR   r™   rR   r   r"   )0Ú__doc__Ú
__future__r   r‘   Úloggingr·   r   r   r   Útypingr   r   r	   r
   r   r±   Útools.registryr   r   Útools.xai_httpr   r   Ú	getLoggerr¾   rµ   rM   r'   r<   rC   r1   r^   r!   r)   r7   r?   rD   rQ   rT   rb   rh   rs   r   r‰   r”   rÆ   ÚX_SEARCH_SCHEMArÖ   Úregister© r*   r    ú<module>ré      sP  ðð'ð 'ðR #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø €€€Ø -Ð -Ð -Ð -Ð -Ð -Ð -Ð -Ð -Ð -Ø 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3à €€€à /Ð /Ð /Ð /Ð /Ð /Ð /Ð /Ø NÐ NÐ NÐ NÐ NÐ NÐ NÐ Nà	ˆÔ	˜8Ñ	$Ô	$€à,Ð Ø#Ð Ø#&Ð  ØÐ Ø?Ð Ø€ðð ð ð ðKð Kð Kð Kð
ð ð ð ð 0ð 0ð 0ð 0ð(ð (ð (ð (ð%ð %ð %ð %ð,ð ð ð ð&ð ð ð ðð ð ð ð&ð ð ð ð@&ð &ð &ð &ð$ð ð ð ð(ð ð ð ð< .2Ø.2ØØØ',Ø',ðy
ð y
ð y
ð y
ð y
ðz ð	Pð ð !Ø6ðð ð
  Ø  (Ð+Ø\ð"ð "ð  Ø  (Ð+ØPð#ð #ð !ØJðð ð
 !ØHðð ð
 "Ø`Ø ð+ð +ð "Ø`Ø ð+ð +ð9!
ð !
ðD �IðI%ð %ð1ð 1€ðh	ð 	ð 	ð €Ô Ø	ØØØØ(Ø�Ø
Ø!ð	ñ 	ô 	ð 	ð 	ð 	r*   