§
    øžyjøX  ã                  óê   — 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	m
Z
 ddlmZ ddlmZmZmZ  ej        e¦  «        ZdZdZd	Z ej        d
ej        ¦  «        Zdd„Zdd„Z G d„ de¦  «        ZdS )uÛ  xAI Web Search â€” plugin form.

Routes ``web_search`` tool calls through xAI's agentic Web Search tool
(server-side ``web_search`` on the Responses API). Grok runs the actual
searching and page-browsing server-side; we ask it to return the top
results as structured JSON so we can hand back the same
``{title, url, description, position}`` rows every other Hermes web
provider produces.

Reference: https://docs.x.ai/developers/tools/web-search

Config keys this provider responds to::

    web:
      search_backend: "xai"           # explicit per-capability
      backend: "xai"                  # shared fallback

Optional knobs (under ``web.xai`` in ``config.yaml``)::

    web:
      xai:
        model: "grok-build-0.1"       # reasoning model required by web_search
        allowed_domains: ["x.ai"]     # max 5 â€” mutually exclusive with excluded_domains
        excluded_domains: ["bad.com"] # max 5 â€” mutually exclusive with allowed_domains
        timeout: 90                   # seconds (default 90)

Auth: reuses :func:`tools.xai_http.resolve_xai_http_credentials`, which
prefers Hermes-managed xAI Grok OAuth (via ``hermes auth``) and falls back
to ``XAI_API_KEY`` (resolved through ``~/.hermes/.env``, then
``os.environ``).
é    )ÚannotationsN)ÚAnyÚDictÚListÚOptional)ÚWebSearchProvider)Úhas_xai_credentialsÚhermes_xai_user_agentÚresolve_xai_http_credentialszgrok-build-0.1éZ   é   z\{[\s\S]*\}ÚreturnúDict[str, Any]c                 ón  — 	 ddl m}   | ¦   «         }t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        r|ni S # t
          $ r'}t                               d|¦  «         i cY d}~S d}~ww xY w)z7Read ``web.xai`` from config.yaml (returns {} on miss).r   )Úload_configÚwebNÚxaiz!Could not load web.xai config: %s)Úhermes_cli.configr   Ú
isinstanceÚdictÚgetÚ	ExceptionÚloggerÚdebug)r   ÚcfgÚweb_sectionÚxai_sectionÚexcs        ú>/home/ragecks/.hermes/hermes-agent/plugins/web/xai/provider.pyÚ_load_xai_web_configr    @   sÈ   € ð	Ø1Ð1Ð1Ð1Ð1Ð1àˆk‰mŒmˆÝ(2°3½Ñ(=Ô(=ÐG�c—g’g˜e‘n”n�nÀ4ˆÝ0:¸;ÍÑ0MÔ0MÐW�k—o’o eÑ,Ô,Ð,ÐSWˆÝ(¨µdÑ;Ô;ÐCˆ{ˆ{ÀÐCøÝð ð ð Ý�ŠÐ8¸#Ñ>Ô>Ð>Øˆ	ˆ	ˆ	ˆ	ˆ	ˆ	øøøøðøøøs   ‚B B Â
B4ÂB/Â)B4Â/B4Úvaluer   ú	List[str]c                ó  — t          | t          ¦  «        sg S g }| D ]l}t          |t          ¦  «        r;|                     ¦   «         r'|                     |                     ¦   «         ¦  «         t          |¦  «        t          k    r nŒm|S )z<Coerce a config value to a clean list of <=5 domain strings.)r   ÚlistÚstrÚstripÚappendÚlenÚ_MAX_DOMAIN_FILTERS)r!   ÚcleanedÚitems      r   Ú_coerce_domain_listr,   N   s‰   € å�e�TÑ"Ô"ð Øˆ	Ø€GØð ð ˆÝ�d�CÑ Ô ð 	) T§Z¢Z¡\¤\ð 	)Ø�NŠN˜4Ÿ:š:™<œ<Ñ(Ô(Ð(Ýˆw‰<Œ<Õ.Ò.Ð.ØˆEð /à€Nó    c                  óä   — e Zd ZdZedd„¦   «         Zedd„¦   «         Zdd„Zdd„Zdd	„Z	d d!d„Z
ed"d„¦   «         Zed#d„¦   «         Zed$d„¦   «         Zed%d„¦   «         Zed&d„¦   «         Zd'd„ZdS )(ÚXAIWebSearchProvideruv  Search-only provider backed by xAI's agentic Web Search tool.

    Sends a structured prompt to Grok with ``tools=[{"type": "web_search"}]``
    enabled and asks it to return the top *limit* results as JSON. Falls
    back to the Responses API ``citations`` list if Grok ignores the JSON
    schema instruction (rare for grok-4.3 but cheap insurance).

    No extract capability â€” pair with Firecrawl / Tavily / Exa for
    ``web_extract`` if you need page content.

    Trust model
    -----------
    Unlike index-backed providers (Brave / Tavily / Exa) which return
    verbatim search-engine results, this backend is an LLM in a trench
    coat: Grok decides which URLs to surface, generates the titles and
    descriptions itself, and is influenced by the *content of the query*.
    A maliciously crafted query (e.g. injected via untrusted upstream
    input the agent picked up) can in principle steer Grok into emitting
    attacker-chosen URLs. Callers that pipe untrusted text directly into
    ``web_search`` should treat returned URLs the same way they would
    treat any model-generated link â€” validate before fetching.
    r   r%   c                ó   — dS )Nr   © ©Úselfs    r   ÚnamezXAIWebSearchProvider.namex   s   € àˆur-   c                ó   — dS )NúxAI Web Search (Grok)r1   r2   s    r   Údisplay_namez!XAIWebSearchProvider.display_name|   s   € à&Ð&r-   Úboolc                ó   — t          ¦   «         S )u  Cheap availability probe â€” env var OR auth-store has OAuth tokens.

        Delegates to :func:`tools.xai_http.has_xai_credentials`, which is
        deliberately *not* the same as :func:`resolve_xai_http_credentials`:
        it never triggers OAuth token refresh or acquires the auth-store
        lock. The ABC contract requires this method to be safe to call on
        every ``hermes tools`` repaint and at tool-registration time.
        Token freshness / refresh is handled inside :meth:`search`.
        )r	   r2   s    r   Úis_availablez!XAIWebSearchProvider.is_available€   s   € õ #Ñ$Ô$Ð$r-   c                ó   — dS )NTr1   r2   s    r   Úsupports_searchz$XAIWebSearchProvider.supports_searchŒ   s   € Øˆtr-   c                ó   — dS )NFr1   r2   s    r   Úsupports_extractz%XAIWebSearchProvider.supports_extract�   s   € Øˆur-   r   ÚqueryÚlimitÚintr   c                ó  — 	 ddl m}  |¦   «         rdddœS n# t          $ r Y nw xY wt          ¦   «         }t	          |                     d¦  «        pd¦  «                             ¦   «         }t	          |                     d¦  «        pd	¦  «                             ¦   «                              d
¦  «        }|sdddœS 	 t          |¦  «        }n# t          t          f$ r d}Y nw xY wt          dt          |d¦  «        ¦  «        }t          ¦   «         }t          |                     d¦  «        t          ¦  «        r|                     d¦  «        nt          }|                     ¦   «         pt          }	 t!          |                     dt"          ¦  «        ¦  «        }	n# t          t          f$ r
 t"          }	Y nw xY wt%          |                     d¦  «        ¦  «        }
t%          |                     d¦  «        ¦  «        }|
r|rdddœS ddi}|
rd|
i|d<   n	|rd|i|d<   |                      ||¦  «        }|d|dœg|gdgdœ}d|› �dt)          ¦   «         dœ}	 ddl}n# t,          $ r dddœcY S w xY wt.                               d ||||¦  «         |                     d!¦  «        d"k    }d}t3          d#¦  «        D �]Á}	 |                     |› d$�|||	¬%¦  «        }|                     ¦   «           �nŒ# |j        $ �rG}|j        �|j        j        nd}|d&k    r´|dk    r®|r¬t.                               d'¦  «         	 t          d(|¬)¦  «        }t	          |                     d¦  «        pd¦  «                             ¦   «         }|r||k    r|}d|› �|d*<   Y d}~ŒÞn2# t          $ r%}t.                               d+|¦  «         Y d}~nd}~ww xY wd}	 |j        �|j        j         dd,…         nd}n# t          $ r d}Y nw xY wt.                               d-||¦  «         dd.|› d/|› �                     ¦   «         dœcY d}~c S d}~w|j!        $ r/}t.                               d0|¦  «         dd1|› �dœcY d}~c S d}~ww xY w|€dd2dœS 	 | "                    ¦   «         }n7# t          $ r*}t.                               d3|¦  «         dd4dœcY d}~S d}~ww xY wt          |tF          ¦  «        r|                     d5¦  «        nd}t          |tF          ¦  «        rO|                     d6¦  «        p|                     d7¦  «        pd8}t.                               d9|¦  «         dd:|› �dœS |  $                    ||¬;¦  «        }|sd(d<g id=œS d(d<|id=œS )>zÓExecute a Grok-backed web search.

        Returns ``{"success": True, "data": {"web": [{title, url, description, position}, ...]}}``
        on success, ``{"success": False, "error": str}`` on failure.
        r   )Úis_interruptedFÚInterrupted)ÚsuccessÚerrorÚapi_keyÚ Úbase_urlzhttps://api.x.ai/v1ú/z_No xAI credentials found. Run `hermes auth` to sign in with xAI Grok OAuth, or set XAI_API_KEY.r   é   éd   ÚmodelÚtimeoutÚallowed_domainsÚexcluded_domainszZweb.xai.allowed_domains and web.xai.excluded_domains cannot both be set (xAI restriction).ÚtypeÚ
web_searchÚfiltersÚuser)ÚroleÚcontentÚno_inline_citations)rM   ÚinputÚtoolsÚincludezBearer zapplication/json)ÚAuthorizationzContent-Typez
User-AgentNz4httpx is not installed (required for xAI web search)z0xAI web search via %s: '%s' (limit=%d, model=%s)Úproviderz	xai-oauthé   z
/responses)ÚheadersÚjsonrN   i‘  zQxAI web search got 401 on first attempt; forcing OAuth refresh and retrying once.T)Úforce_refreshÚapi_key_hintr[   z1xAI web search OAuth refresh after 401 failed: %si,  zxAI web search HTTP %d: %szxAI web search returned HTTP z: z xAI web search request error: %szCould not reach xAI: z#xAI web search produced no responsezxAI web search bad JSON: %sz/Could not parse xAI Responses API reply as JSONrF   ÚmessageÚcodezunknown errorz*xAI web search returned error envelope: %szxAI returned an error: ©r@   r   )rE   Údata)%Útools.interruptrC   r   r   r%   r   r&   ÚrstriprA   Ú	TypeErrorÚ
ValueErrorÚmaxÚminr    r   ÚDEFAULT_MODELÚfloatÚDEFAULT_TIMEOUTr,   Ú_build_promptr
   ÚhttpxÚImportErrorr   ÚinfoÚrangeÚpostÚraise_for_statusÚHTTPStatusErrorÚresponseÚstatus_codeÚwarningÚtextÚRequestErrorr_   r   Ú_extract_results)r3   r?   r@   rC   ÚcredsrG   rI   r   rM   rN   ÚallowedÚexcludedÚweb_search_toolÚpromptÚpayloadr^   rp   Úis_oauth_pathÚrespÚattemptr   ÚstatusÚ	refreshedÚrefreshed_keyÚrefresh_excÚbodyre   Ú	api_errorÚerr_msgÚweb_resultss                                 r   ÚsearchzXAIWebSearchProvider.search”   s’  € ð	Ø6Ð6Ð6Ð6Ð6Ð6àˆ~ÑÔð BØ#(°=ÐAÐAÐAðBøåð 	ð 	ð 	ØˆDð	øøøõ -Ñ.Ô.ˆÝ�e—i’i 	Ñ*Ô*Ð0¨bÑ1Ô1×7Ò7Ñ9Ô9ˆÝ�u—y’y Ñ,Ô,ÐEÐ0EÑFÔF×LÒLÑNÔN×UÒUÐVYÑZÔZˆØð 	à ð:ðð ð ð	Ý˜‘J”JˆEˆEøÝ�:Ð&ð 	ð 	ð 	ØˆEˆEˆEð	øøøå�A•s˜5 #‘”Ñ'Ô'ˆå"Ñ$Ô$ˆÝ$.¨s¯wªw°wÑ/?Ô/?ÅÑ$EÔ$EÐX�—’˜Ñ Ô Ð Í=ˆØ—’‘”Ð.¥ˆð	&Ý˜CŸGšG I­Ñ?Ô?Ñ@Ô@ˆGˆGøÝ�:Ð&ð 	&ð 	&ð 	&Ý%ˆGˆGˆGð	&øøøõ & c§g¢gÐ.?Ñ&@Ô&@ÑAÔAˆÝ& s§w¢wÐ/AÑ'BÔ'BÑCÔCˆØð 		�xð 		ð !ð<ðð ð ð ,2°<Ð*@ˆØð 	HØ*;¸WÐ)EˆO˜IÑ&Ð&Øð 	HØ*<¸hÐ)GˆO˜IÑ&à×#Ò# E¨5Ñ1Ô1ˆð Ø%°&Ð9Ð9Ð:Ø%Ð&ð .Ð.ð#
ð #
ˆð 1 wÐ0Ð0Ø.Ý/Ñ1Ô1ð
ð 
ˆð	ØˆLˆLˆLˆLøÝð 	ð 	ð 	à ØOðð ð ð ð ð	øøøõ 	�ŠØ>Ø�e˜U Eñ	
ô 	
ð 	
ð  Ÿš :Ñ.Ô.°+Ò=ˆØˆÝ˜Q‘x”xð .	Rñ .	RˆGð-RØ—z’zØÐ+Ð+Ð+Ø#Ø Ø#ð	 "ñ ô �ð ×%Ò%Ñ'Ô'Ð'Ø‘øØÔ(ð !ñ !ð !Ø58´\Ð5M˜œÔ1Ð1ÐST�Ø˜S’=�= W°¢\ \°m \Ý—K’Kð5ñô ð ðÝ$@Ø*.Ø)0ð%ñ %ô %˜	õ ),¨I¯MªM¸)Ñ,DÔ,DÐ,JÈÑ(KÔ(K×(QÒ(QÑ(SÔ(S˜Ø(ð %¨]¸gÒ-EÐ-EØ&3˜GØ7JÀÐ7JÐ7J˜G OÑ4Ø$˜H˜H˜H˜Høøõ %ð ð ð ÝŸšØOØ'ñô ð ð ð ð ð ð øøøøðøøøð
 �ðØ69´lÐ6N˜3œ<Ô,¨T¨c¨TÔ2Ð2ÐTV�D�DøÝ ð ð ð Ø�D�D�Dðøøøå—’Ð;¸VÀTÑJÔJÐJà$ØM¸VÐMÐMÀtÐMÐM×TÒTÑVÔVðð ð ð ð ð ð ð ð ð øøøøð Ô%ð Rð Rð RÝ—’ÐAÀ3ÑGÔGÐGØ#(Ð3PÈ3Ð3PÐ3PÐQÐQÐQÐQÐQÐQÐQÐQÐQÐQøøøøðRøøøð ˆ<à$Ð/TÐUÐUÐUð	Ø—9’9‘;”;ˆDˆDøÝð 	ð 	ð 	Ý�NŠNÐ8¸#Ñ>Ô>Ð>à ØJðð ð ð ð ð ð ð øøøøð	øøøõ *4°D½$Ñ)?Ô)?ÐI�D—H’H˜WÑ%Ô%Ð%ÀTˆ	Ý�i¥Ñ&Ô&ð 	Tà—’˜iÑ(Ô(ð #Ø—=’= Ñ(Ô(ð#à"ð õ
 �NŠNÐGÈÑQÔQÐQØ$Ð/RÈÐ/RÐ/RÐSÐSÐSà×+Ò+¨D¸Ð+Ñ>Ô>ˆØð 	:ð  $¨e°R¨[Ð9Ð9Ð9à¨%°Ð)=Ð>Ð>Ð>sß   ‚ ˜
%¤%Â=C ÃC#Ã"C#Å2(F ÆF6Æ5F6ÉI ÉI-É,I-Ê<0K/Ë/Q8Ë:=P<Ì8ANÎP<Î
OÎ!OÎ<P<ÏOÏP<ÏO*Ï)P<Ï*O9Ï6P<Ï8O9Ï9;P<Ð4Q8Ð<Q8Ñ	"Q3Ñ+Q8Ñ3Q8ÒR Ò
SÒ"SÓSÓSc                ó   — d|› d| › �S )a7  Compose the prompt that asks Grok to act as a search engine.

        We deliberately ask for a JSON object (not bare array) so we can
        match it cheaply with ``_JSON_BLOCK_RE``; we explicitly forbid
        prose, markdown fences, and inline-citation links to keep the
        payload parseable.
        u<  Use the web_search tool to find current information for the query below, then respond with ONLY a single JSON object â€” no prose, no markdown fences, no inline citation links â€” matching this exact schema:

{"results": [{"title": "string", "url": "string", "description": "1-2 sentence summary"}]}

Return at most zy results, ordered by relevance, with absolute https:// URLs. If no usable results exist, return {"results": []}.

Query: r1   )r?   r@   s     r   ro   z"XAIWebSearchProvider._build_promptV  s*   € ðð
 $ðð ð ðð ð
	
r-   Úresponse_dataúList[Dict[str, Any]]c               óz  — |                       |¦  «        \  }}|D ]}|                      ||¬¦  «        }|r|c S Œ |r1d                     |¦  «        }|                      |||¬¦  «        }|r|S |                     d¦  «        pg }	t          |	t          ¦  «        r!d„ t          |	d|…         ¦  «        D ¦   «         S g S )u<  Pull a ``[{title, url, description, position}, ...]`` list out of a
        Responses-API reply.

        Strategy:

        1. Walk ``output[*].content[*].text`` for ``output_text`` blocks and
           try to parse the first JSON object that has a ``results`` list.
        2. If the JSON path fails, fall back to the message annotations
           (``url_citation`` entries) â€” every annotation carries a URL and
           a ``title`` (citation number); we pair those URLs with surrounding
           text from the message body as a best-effort description.
        rd   Ú
Ú	citationsc                ó”   — g | ]E\  }}t          |t          ¦  «        ¯|                     ¦   «         ¯.d t          |¦  «        d |dz   dœ‘ŒFS )rH   rK   ©ÚtitleÚurlÚdescriptionÚposition)r   r%   r&   )Ú.0ÚiÚus      r   ú
<listcomp>z9XAIWebSearchProvider._extract_results.<locals>.<listcomp>—  sm   € ð 	ð 	ð 	ñ �A�qÝ˜a¥Ñ%Ô%ð	ð +,¯'ª'©)¬)ð	àÝ˜q™6œ6Ø#%Ø ! A¡ð	ð ð	ð 	ð 	r-   N)Ú_collect_output_textÚ_try_parse_json_resultsÚjoinÚ_results_from_annotationsr   r   r$   Ú	enumerate)
Úclsr�   r@   Útext_blocksr   ÚblockÚparsedÚjoined_textÚannotation_resultsr”   s
             r   r|   z%XAIWebSearchProvider._extract_resultsk  s  € ð& $'×#;Ò#;¸MÑ#JÔ#JÑ ˆ�[ð !ð 	ð 	ˆEØ×0Ò0°¸eÐ0ÑDÔDˆFØð Ø���ðð ð 	*ØŸ)š) KÑ0Ô0ˆKØ!$×!>Ò!>Ø˜[°ð "?ñ "ô "Ðð "ð *Ø)Ð)ð "×%Ò% kÑ2Ô2Ð8°bˆ	Ý�i¥Ñ&Ô&ð 
	ð	ð 	õ & i°°°Ô&7Ñ8Ô8ð	ñ 	ô 	ð 	ð ˆ	r-   ú&tuple[List[str], List[Dict[str, Any]]]c                óæ  — g }g }|                       d¦  «        }t          |t          ¦  «        s||fS |D �]8}t          |t          ¦  «        r|                      d¦  «        dk    rŒ2|                      d¦  «        }t          |t          ¦  «        sŒ]|D ]Ø}t          |t          ¦  «        r|                      d¦  «        dk    rŒ1|                      d¦  «        }t          |t          ¦  «        r)|                     ¦   «         r|                     |¦  «         |                      d¦  «        }t          |t          ¦  «        r*|D ]'}	t          |	t          ¦  «        r |j        |	¦  «         Œ(ŒÙ�Œ:||fS )zEReturn (text_blocks, annotations) extracted from ``response.output``.ÚoutputrQ   rb   rV   Úoutput_textrz   r   )r   r   r$   r   r%   r&   r'   )
r�   r¥   r   r¬   r+   rV   Úchunkrz   Úchunk_annotationsÚanns
             r   rŸ   z)XAIWebSearchProvider._collect_output_text¤  s‹  € ð
 "$ˆØ,.ˆØ×"Ò" 8Ñ,Ô,ˆÝ˜&¥$Ñ'Ô'ð 	,Ø Ð+Ð+àð 	4ñ 	4ˆDÝ˜d¥DÑ)Ô)ð ¨T¯XªX°fÑ-=Ô-=ÀÒ-JÐ-JØØ—h’h˜yÑ)Ô)ˆGÝ˜g¥tÑ,Ô,ð ØØ ð 
4ð 
4�Ý! %­Ñ.Ô.ð °%·)²)¸FÑ2CÔ2CÀ}Ò2TÐ2TØØ—y’y Ñ(Ô(�Ý˜d¥CÑ(Ô(ð -¨T¯ZªZ©\¬\ð -Ø×&Ò& tÑ,Ô,Ð,Ø$)§I¢I¨mÑ$<Ô$<Ð!ÝÐ/µÑ6Ô6ð 4Ø0ð 4ð 4˜Ý% c­4Ñ0Ô0ð 4Ø.˜KÔ.¨sÑ3Ô3Ð3øøñ
4ð ˜KÐ'Ð'r-   rz   úOptional[List[Dict[str, Any]]]c               ó   — | g}t                                | ¦  «        }|rA|                     d¦  «        | k    r(|                     |                     d¦  «        ¦  «         |D �]i}	 t	          j        |¦  «        }n# t          j        t          f$ r Y Œ1w xY wt          |t          ¦  «        sŒK| 
                    d¦  «        }t          |t          ¦  «        sŒvg }|d|…         D ]à}t          |t          ¦  «        sŒt          | 
                    dd¦  «        ¦  «                             ¦   «         }	|	sŒP|                     t          | 
                    dd¦  «        ¦  «                             ¦   «         |	t          | 
                    dd¦  «        ¦  «                             ¦   «         t          |¦  «        dz   d	œ¦  «         Œá|r|c S �ŒkdS )
aR  Parse a JSON object with a ``results`` array out of ``text``.

        Returns the normalized result list on success, ``None`` when the
        block has no valid JSON object or no ``results`` key. Tolerates
        leading/trailing prose because reasoning models sometimes prefix a
        short narration even when told not to.
        r   ÚresultsNr˜   rH   r—   r™   rK   r–   )Ú_JSON_BLOCK_RErŽ   Úgroupr'   r_   ÚloadsÚJSONDecodeErrorri   r   r   r   r$   r%   r&   r(   )
rz   r@   Ú
candidatesÚmatchÚ	candidater§   r³   Ú
normalizedÚrowr˜   s
             r   r    z,XAIWebSearchProvider._try_parse_json_resultsÂ  sç  € ð �Vˆ
Ý×%Ò% dÑ+Ô+ˆØð 	.�U—[’[ ‘^”^ tÒ+Ð+Ø×Ò˜eŸkšk¨!™nœnÑ-Ô-Ð-à#ð 	"ñ 	"ˆIðÝœ IÑ.Ô.��øÝÔ(­*Ð5ð ð ð Ø�ðøøøå˜f¥dÑ+Ô+ð ØØ—j’j Ñ+Ô+ˆGÝ˜g¥tÑ,Ô,ð ØØ/1ˆJØ˜v ˜v”ð ð �Ý! #¥tÑ,Ô,ð ØÝ˜#Ÿ'š' %¨Ñ,Ô,Ñ-Ô-×3Ò3Ñ5Ô5�Øð ØØ×!Ò!å!$ S§W¢W¨W°bÑ%9Ô%9Ñ!:Ô!:×!@Ò!@Ñ!BÔ!BØ"Ý'*¨3¯7ª7°=À"Ñ+EÔ+EÑ'FÔ'F×'LÒ'LÑ'NÔ'Nõ %(¨
¡O¤O°aÑ$7ðð ñ
ô 
ð 
ð 
ð ð "Ø!Ð!Ð!Ð!ñ"àˆts   Á'A<Á<BÂBr   r¨   c          	     ó8  — t          ¦   «         }g }| D �]…}|                     d¦  «        dk    rŒt          |                     dd¦  «        ¦  «                             ¦   «         }|r||v rŒY|                     |¦  «         d}|                     d¦  «        }|                     d¦  «        }	t          |t          ¦  «        r—t          |	t          ¦  «        r‚d|cxk    r|	cxk     rt          |¦  «        k    ran n^t          d|dz
  ¦  «        }
||
|…                              ¦   «         }t          |¦  «        dk    r|d	d
…                              ¦   «         }| 	                    d||t          |¦  «        dz   dœ¦  «         t          |¦  «        |k    r n�Œ‡|S )a	  Best-effort fallback when JSON parsing fails.

        Uses each ``url_citation`` annotation's ``url`` (the citation
        title is just the integer label, so we don't surface it) and
        slices ~200 characters of surrounding text as the description.
        rQ   Úurl_citationr˜   rH   Ústart_indexÚ	end_indexr   éÈ   i8ÿÿÿNrK   r–   )
Úsetr   r%   r&   Úaddr   rA   r(   rj   r'   )r   r¨   r@   Úseenr³   r°   r˜   r™   ÚstartÚendÚwindow_starts              r   r¢   z.XAIWebSearchProvider._results_from_annotationsõ  sº  € õ ™œˆØ(*ˆØð 	ñ 	ˆCØ�wŠw�v‰Œ .Ò0Ð0ØÝ�c—g’g˜e RÑ(Ô(Ñ)Ô)×/Ò/Ñ1Ô1ˆCØð ˜# ˜+˜+ØØ�HŠH�S‰MŒMˆMàˆKØ—G’G˜MÑ*Ô*ˆEØ—'’'˜+Ñ&Ô&ˆCÝ˜%¥Ñ%Ô%ð =­*°S½#Ñ*>Ô*>ð =À1ÈÐCgÐCgÒCgÐCgÐPSÐCgÐCgÒCgÐCgÕWZÐ[fÑWgÔWgÒCgÐCgÐCgÐCgÐCgÝ" 1 e¨c¡kÑ2Ô2�Ø)¨,°uÐ*<Ô=×CÒCÑEÔE�Ý�{Ñ#Ô# cÒ)Ð)Ø"-¨d¨e¨eÔ"4×":Ò":Ñ"<Ô"<�Kà�NŠNàØØ#.Ý # G¡¤¨qÑ 0ð	ð ñô ð õ �7‰|Œ|˜uÒ$Ð$Ø�ñ %àˆr-   c                ó   — dddg ddœS )Nr6   ÚpaiduU   Agentic web search via Grok's web_search tool â€” uses xAI Grok OAuth or XAI_API_KEY.Úxai_grok)r4   ÚbadgeÚtagÚenv_varsÚ
post_setupr1   r2   s    r   Úget_setup_schemaz%XAIWebSearchProvider.get_setup_schema#  s&   € ð
 ,Øð-ð Ø$ð	
ð 	
ð 		
r-   N)r   r%   )r   r8   )r   )r?   r%   r@   rA   r   r   )r?   r%   r@   rA   r   r%   )r�   r   r@   rA   r   r‘   )r�   r   r   rª   )rz   r%   r@   rA   r   r±   )r   r‘   r¨   r%   r@   rA   r   r‘   ©r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úpropertyr4   r7   r:   r<   r>   rŽ   Ústaticmethodro   Úclassmethodr|   rŸ   r    r¢   rÏ   r1   r-   r   r/   r/   `   sp  € € € € € ðð ð. ðð ð ñ „Xðð ð'ð 'ð 'ñ „Xð'ð
%ð 
%ð 
%ð 
%ðð ð ð ðð ð ð ð
~?ð ~?ð ~?ð ~?ð ~?ðD ð
ð 
ð 
ñ „\ð
ð( ð6ð 6ð 6ñ „[ð6ðp ð(ð (ð (ñ „\ð(ð: ð0ð 0ð 0ñ „\ð0ðd ð)ð )ð )ñ „\ð)ðZ
ð 
ð 
ð 
ð 
ð 
r-   r/   rÐ   )r!   r   r   r"   )rÔ   Ú
__future__r   r_   ÚloggingÚreÚtypingr   r   r   r   Úagent.web_search_providerr   Útools.xai_httpr	   r
   r   Ú	getLoggerrÑ   r   rl   rn   r)   ÚcompileÚ	MULTILINEr´   r    r,   r/   r1   r-   r   ú<module>rá      sI  ððð ð@ #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,à 7Ð 7Ð 7Ð 7Ð 7Ð 7ðð ð ð ð ð ð ð ð ð ð 
ˆÔ	˜8Ñ	$Ô	$€à €Ø€ØÐ ð
 �”˜N¨B¬LÑ9Ô9€ðð ð ð ð
ð 
ð 
ð 
ð$P
ð P
ð P
ð P
ð P
Ð,ñ P
ô P
ð P
ð P
ð P
r-   