Ë
    âß²j )  ã                  óª  — d Z ddlmZ ddlZddlmZmZmZmZm	Z	m
Z
 ddlZddlmZ 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/d„Zd0d„Zd1d„Zd2d„Zd3d„Zd4d„Zdddœd5d„Zd6d„Zdddœ	 	 	 	 	 	 	 	 	 	 	 	 	 d7d„Zdddœ	 	 	 	 	 	 	 	 	 	 	 	 	 d8d„Z d9d„Z!ddœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d:d„Z"d;d „Z#d<d!„Z$d=d"„Z% G d#„ d$e«      Z&d>d?d%„Z'd@d&„Z(y)Aa%  Shared plumbing for the bundled web-search provider plugins.

Every helper resolves patched-in-tests collaborators (``get_provider_env``,
``tools.interrupt``, ``plugins.web.keyless_mcp``, ``tools.web_tools`` client
slots) lazily at call time so monkeypatching the source module keeps working.
é    )ÚannotationsN)ÚAnyÚ	AwaitableÚCallableÚDictÚListÚOptional)ÚWebSearchProvideré   c                ó   — ddl m}  || «      S )z:Config-aware env lookup (os.environ, then ~/.hermes/.env).r   )Úget_provider_env)Úagent.web_search_providerr   )Únamer   s     ú8/home/ubuntu/.hermes/hermes-agent/plugins/web/_common.pyÚprovider_envr      s   € å:Ù˜DÓ!Ð!ó    c                ó    — ddl m}  || |«      S )Nr   )Úuse_keyless)Úplugins.web.keyless_mcpr   )r   Úapi_keyÚ_use_keylesss      r   r   r      s   € ÝCÙ˜˜gÓ&Ð&r   c                 ó   — ddl m}   | «       S )Nr   ©Úis_interrupted)Útools.interruptr   r   s    r   Ú_interruptedr      s   € Ý.ÙÓÐr   c                ó   — dd| idœS )NTÚweb)ÚsuccessÚdata© )Úweb_resultss    r   Ú	search_okr#   %   s   € Ø e¨[Ð%9Ñ:Ð:r   c                ó   — d| dœS )NF)r   Úerrorr!   )r%   s    r   Úsearch_failr&   )   s   € Ø uÑ-Ð-r   c                ó   — | |||dœS )N©ÚurlÚtitleÚdescriptionÚpositionr!   r(   s       r   Úweb_hitr-   -   s   € Ø °{ÐPXÑYÐYr   c                ó   — | |||dœS )uO   Title-first row â€” the historical wire shape of brave/searxng/ddgs/tavily/xai.©r*   r)   r+   r,   r!   r/   s       r   Ú	title_hitr0   1   s   € à 3°{ÐPXÑYÐYr   )Ú
source_urlc               ó    — | ||||€| n||dœdœS )zVSuccessful extract entry; ``raw_content`` mirrors ``content`` for the legacy pipeline.)Ú	sourceURLr*   )r)   r*   ÚcontentÚraw_contentÚmetadatar!   )r)   r*   r4   r1   s       r   Údocumentr7   6   s'   € ð ˜U¨wÀwØ)3Ð);¡#ÀÐV[Ñ\ñð r   c                ó   — | dd|dœS )NÚ )r)   r*   r4   r%   r!   )r)   r%   s     r   Ú
page_errorr:   >   s   € Ø °¸UÑCÐCr   c                ó@   — | D �cg c]  }t        ||«      ‘Œ c}S c c}w ©N)r:   )Úurlsr%   Úus      r   Úextract_failr?   B   s   € Ø*.Ö/ QŒJ�q˜%Õ Ò/Ð/ùÒ/s   …c                óJ   — ddl m} |j                  d| ||«        ||||«      S )Nr   )Úsearch_with_failoverz"%s keyless search: '%s' (limit=%d))r   rA   Úinfo)Údisplayr   ÚqueryÚlimitÚloggerrA   s         r   Úkeyless_searchrG   G   s'   € Ý<Ø
‡K�KÐ4°g¸uÀeÔLÙ  e¨UÓ3Ð3r   c                ój   — ddl m} |j                  d| t        |«      «        ||t	        |«      «      S )Nr   )Úextract_with_failoverz%s keyless extract: %d URL(s))r   rI   rB   ÚlenÚlist)rC   r   r=   rF   rI   s        r   Úkeyless_extractrL   M   s+   € Ý=Ø
‡K�KÐ/°¼#¸d»)ÔDÙ  ¤t¨D£zÓ2Ð2r   c               óª   — |rt        |t        «      rt        |«      S |rt        |t        «      r| › d|› �S |j	                  d| ||«       | › d|› d|› �S )zè``verbatim_value_error``: ValueError carries a pre-formatted message (missing key,
    HTTP body) and is returned as-is. ``sdk``: ImportError means the lazily installed
    vendor SDK is missing. Anything else is logged and wrapped.z SDK not installed: z%s %s error: %sÚ z	 failed: )Ú
isinstanceÚ
ValueErrorÚstrÚImportErrorÚwarning)ÚvendorÚkindÚexcrF   ÚsdkÚverbatim_value_errors         r   Ú_failure_messagerY   T   sa   € ñ ¤
¨3´
Ô ;Ü�3‹xˆÙ
Œz˜#œ{Ô+Ø�Ð-¨c¨UÐ3Ð3Ø
‡N�NÐ$ f¨d°CÔ8ØˆX�Q�t�f˜I c UÐ+Ð+r   c                ó„   — 	 t        «       r|S  |«       S # t        $ r!} |t        | |||||¬«      «      cY d }~S d }~ww xY w)N©rW   rX   )r   Ú	ExceptionrY   )	rT   rU   rF   ÚbodyÚinterruptedÚfailrW   ÚvverV   s	            r   Ú_guardedra   `   sH   € ðdÜŒ>ØÐÙ‹vˆøÜò dÙÔ$ V¨T°3¸ÀCÐ^aÔbÓcÕcûðdús   ‚ Ž •	?ž:´?º?FTr[   c          
     ó@   — t        | d||t        d«      t        ||«      S )NÚsearchÚInterrupted)ra   r&   )rT   rF   r]   rW   rX   s        r   Ú
run_searchre   i   s#   € Ü�F˜H f¨d´KÀÓ4NÔP[Ð]`ÐbvÓwÐwr   c                ó4   — | D �cg c]  }|dddœ‘Œ
 c}S c c}w )Nrd   r9   )r)   r%   r*   r!   )r=   r>   s     r   Ú_extract_interruptedrg   m   s   € ØEIÖJÀ�A ¸Ó;ÒJÐJùÒJs   …c          
     ó@   ‡— t        | d||t        ‰«      ˆfd„||«      S )uI   Per-URL failures are returned as entries with ``error`` â€” never raised.Úextractc                ó   •— t        ‰| «      S r<   )r?   )Úmr=   s    €r   ú<lambda>zrun_extract.<locals>.<lambda>v   s   ø€ Ô[gÐhlÐnoÓ[p€ r   )ra   rg   )rT   rF   r=   r]   rW   rX   s     `   r   Úrun_extractrm   q   s1   ø€ ô
 �F˜I v¨tÔ5IÈ$Ó5OÓQpÐruð  xLó  Mð  Mr   c             ƒ  óº   K  — 	 t        «       rt        |«      S  |«       ƒ d{  –—† S 7 Œ# t        $ r%}t        |t	        | d||||¬«      «      cY d}~S d}~ww xY w­w)zIAsync twin of :func:`run_extract` (``body`` is awaited inside the guard).Nri   r[   )r   rg   r\   r?   rY   )rT   rF   r=   r]   rW   rX   rV   s          r   Úrun_extract_asyncro   y   se   è ø€ ð
HÜŒ>Ü'¨Ó-Ð-Ù“V�|Ðˆ|ùÜò HÜ˜DÔ"2°6¸9ÀcÈ6ÐWZð  rFô  #Gó  Hõ  	HûðHüsE   ‚A„* ˜A™
* £(¤* §A¨* ª	A³AÁAÁAÁAÁAc                ó`   — | j                   xs dj                  «       xs d| j                  › �S )zPResponse body text for a >=400 reply, or ``HTTP <code>`` when the body is empty.r9   zHTTP )ÚtextÚstripÚstatus_code)Úresponses    r   Úhttp_status_detailru   ‡   s-   € à�M‰MÒ˜R×&Ñ&Ó(ÒJ¨e°H×4HÑ4HÐ3IÐ,JÐJr   )Úreach_targetc               ó,  — 	 t        j                  ||||¬«      }|j                  «        	 |j                  «       dfS # t         j                  $ rC}|j	                  d| |«       dt        | › d|j                  j                  › �«      fcY d}~S d}~wt         j                  $ r4}|j	                  d| |«       dt        d|xs | › d|› �«      fcY d}~S d}~ww xY w# t        $ r.}|j	                  d| |«       dt        d	| › d
�«      fcY d}~S d}~ww xY w)u©   GET ``url`` and parse JSON â†’ ``(data, None)`` or ``(None, failure_dict)``.
    ``reach_target`` overrides the "Could not reach ..." subject (SearXNG includes its URL).)ÚparamsÚheadersÚtimeoutz%s HTTP error: %sNz returned HTTP z%s request error: %szCould not reach z: z%s response parse error: %szCould not parse z response as JSON)ÚhttpxÚgetÚraise_for_statusÚHTTPStatusErrorrS   r&   rt   rs   ÚRequestErrorÚjsonr\   )	Úlabelr)   rx   ry   rz   rF   rv   ÚresprV   s	            r   Úhttp_get_jsonrƒ   Œ   s  € ðTÜ�y‰y˜ V°WÀgÔNˆØ×ÑÔðNØ�y‰y‹{˜DÐ Ð øô × Ñ ò VØ�‰Ð*¨E°3Ô7Ø”[ E 7¨/¸#¿,¹,×:RÑ:RÐ9SÐ!TÓUÐUÕUûÜ×Ñò TØ�‰Ð-¨u°cÔ:Ø”[Ð#3°LÒ4IÀEÐ3JÈ"ÈSÈEÐ!RÓSÐSÕSûðTûô
 ò NØ�‰Ð4°e¸SÔAØ”[Ð#3°E°7Ð:KÐ!LÓMÐMÕMûðNúsJ   ‚)> ¬C ¾CÁ8BÂ	CÂCÂ%)CÃCÃCÃ	DÃ%#DÄDÄDc                óþ   — t        | «      D ��cg c]a  \  }}t        t        |j                  dd«      «      t        |j                  dd«      «      t        |j                  |d«      «      |dz   «      ‘Œc c}}S c c}}w )zGBrave/SearXNG row normalizer: ``str()`` every field, 1-based positions.r*   r9   r)   é   )Ú	enumerater0   rQ   r|   )Úraw_resultsÚdescription_keyÚiÚrs       r   Útitled_rowsr‹   ¢   sp   € ô ˜kÓ*÷áˆAˆqô 	”#�a—e‘e˜G RÓ(Ó)¬3¨q¯u©u°U¸BÓ/?Ó+@Ä#ÀaÇeÁeÈOÐ]_ÓF`ÓBaÐcdÐghÑchÕióð ùó s   �A&A9c                ó„   — 	 ddl m}  || d¬«       y# t        $ r Y yt        $ r}t        t	        |«      «      ‚d}~ww xY w)z—Best-effort ``tools.lazy_deps.ensure``: its own ImportError is benign and swallowed;
    an install hint (any other error) is re-raised as ImportError.r   )ÚensureF)ÚpromptN)Útools.lazy_depsr�   rR   r\   rQ   )ÚfeatureÚ_lazy_ensurerV   s      r   Úlazy_ensurer’   ª   s>   € ð$Ý:Ù�W UÖ+øÜò ÙÜò $Üœ#˜c›(Ó#Ð#ûð$ús   ‚ “	?ž?¦:º?c                ó¤   — ddl m} t        || d«      }|�|S t        |«      }|st	        |«      ‚t        |«        ||«      }t        || |«       |S )zÈLazy-build + cache a vendor SDK client on ``tools.web_tools.<slot>`` (so tests that
    reset ``tools.web_tools._<vendor>_client = None`` see fresh state). Raises ValueError
    when the key is unset.r   N)Útools.web_toolsÚ	web_toolsÚgetattrr   rP   r’   Úsetattr)	ÚslotÚenv_varÚmissing_key_errorr�   ÚfactoryÚ_wtÚcachedr   Úclients	            r   Úcached_sdk_clientrŸ   ¶   s\   € õ "Ü�S˜$ Ó%€FØÐØˆÜ˜7Ó#€GÙÜÐ*Ó+Ð+Ü�ÔÙ�WÓ€FÜˆC��vÔØ€Mr   c                  óœ   — e Zd ZU dZdZded<   dZded<   dZded<   dZded	<   dZ	ded
<    e
d„ «      Z e
d„ «      Zdd„Zdd„Zdd„Zdd„Zy)ÚBaseWebSearchProvidera‡  Subclasses set ``NAME`` / ``DISPLAY_NAME`` / ``KEY_ENV`` and flip ``EXTRACT`` / ``KEYLESS``.
    ``is_available`` deliberately ignores the keyless tier: otherwise the legacy preference walk
    would route users holding a key for a lower-priority backend onto this vendor's free tier.
    ``is_keyless_available`` is True for keyless vendors unless pinned ``web.provider_tier.<name>: paid``.r9   rQ   ÚNAMEÚDISPLAY_NAMEÚKEY_ENVFÚboolÚEXTRACTÚKEYLESSc                ó   — | j                   S r<   )r¢   ©Úselfs    r   rl   zBaseWebSearchProvider.<lambda>Ô   s
   €  §¡€ r   c                ó   — | j                   S r<   )r£   r©   s    r   rl   zBaseWebSearchProvider.<lambda>Õ   s   € ¨×):Ñ):€ r   c                ó>   — t        t        | j                  «      «      S r<   )r¥   r   r¤   r©   s    r   Úis_availablez"BaseWebSearchProvider.is_available×   s   € Ü”L §¡Ó.Ó/Ð/r   c                ój   — ddl m}m} | j                  xr  |«       xr  || j                  «      dk7  S )Nr   )Úkeyless_enabledÚprovider_tierÚpaid)r   r¯   r°   r§   r¢   )rª   r¯   r°   s      r   Úis_keyless_availablez*BaseWebSearchProvider.is_keyless_availableÚ   s+   € ßJØ�|‰|ÒX¡Ó 1ÒX±mÀDÇIÁIÓ6NÐRXÑ6XÐXr   c                 ó   — y)NTr!   r©   s    r   Úsupports_searchz%BaseWebSearchProvider.supports_searchÞ   s   € Ør   c                ó   — | j                   S r<   )r¦   r©   s    r   Úsupports_extractz&BaseWebSearchProvider.supports_extractá   s   € Ø�|‰|Ðr   N©Úreturnr¥   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r¢   Ú__annotations__r£   r¤   r¦   r§   Úpropertyr   Údisplay_namer­   r²   r´   r¶   r!   r   r   r¡   r¡   È   sf   … ñnð
 €Dˆ#ƒNØ€L�#ÓØ€GˆSÓØ€GˆTÓØ€GˆTÓáÑ*Ó+€DÙÑ:Ó;€Ló0óYóôr   r¡   c                ó*   — |r|||dœgng }| |||dœ|¥S )zO``hermes tools`` picker entry; ``env_vars`` is empty when ``key_env`` is blank.)ÚkeyrŽ   r)   )r   ÚbadgeÚtagÚenv_varsr!   )r   rÂ   rÃ   Úkey_envrŽ   r)   ÚextrarÄ   s           r   Úsetup_schemarÇ   å   s*   € áCJ˜¨6¸#Ñ>Ñ?ÐPR€HØ 5°À(ÑTÈeÐTÐTr   c          	     óZ   — t        | › d�d||| › d�|d¬«      }t        | › d�d|d|g¬«      S )	z;Picker entry for a keyless-ring vendor with a paid variant.u    Â· Paid (API key)r±   z API key)Úweb_tieru    Â· Free (keyless)u   free Â· no keyÚfree)rÉ   Úvariants)rÇ   )rC   rÅ   Úkey_urlÚfree_tagÚpaid_tagr±   s         r   Úkeyless_variant_schemarÏ   ë   sT   € ä˜7˜)Ð#5Ð6¸ÀÈ'ÐV]ÐU^Ð^fÐSgÐipð  |Bô  C€DÜ˜7˜)Ð#5Ð6Ð8HÈ(Ð]cÐosÐntÔuÐur   )r   rQ   r¸   rQ   )r   rQ   r   rQ   r¸   r¥   r·   )r"   úList[Dict[str, Any]]r¸   úDict[str, Any])r%   rQ   r¸   rÑ   )
r)   rQ   r*   rQ   r+   rQ   r,   Úintr¸   rÑ   )
r*   rQ   r)   rQ   r+   rQ   r,   rÒ   r¸   rÑ   )
r)   rQ   r*   rQ   r4   rQ   r1   úOptional[str]r¸   rÑ   )r)   rQ   r%   rQ   r¸   rÑ   )r=   ú	List[str]r%   rQ   r¸   rÐ   )rC   rQ   r   rQ   rD   rQ   rE   rÒ   rF   úlogging.Loggerr¸   rÑ   )
rC   rQ   r   rQ   r=   rÔ   rF   rÕ   r¸   rÐ   )rT   rQ   rU   rQ   rV   r\   rF   rÕ   rW   r¥   rX   r¥   r¸   rQ   )rT   rQ   rU   rQ   rF   rÕ   r]   zCallable[[], Any]r^   r   r_   úCallable[[str], Any]rW   r¥   r`   r¥   r¸   r   )rT   rQ   rF   rÕ   r]   zCallable[[], Dict[str, Any]]rW   r¥   rX   r¥   r¸   rÑ   )r=   rÔ   r¸   rÐ   )rT   rQ   rF   rÕ   r=   rÔ   r]   z"Callable[[], List[Dict[str, Any]]]rW   r¥   rX   r¥   r¸   rÐ   )rT   rQ   rF   rÕ   r=   rÔ   r]   z-Callable[[], Awaitable[List[Dict[str, Any]]]]rW   r¥   rX   r¥   r¸   rÐ   )rt   r   r¸   rQ   )r�   rQ   r)   rQ   rx   rÑ   ry   zDict[str, str]rz   rÒ   rF   rÕ   rv   rÓ   r¸   z$tuple[Any, Optional[Dict[str, Any]]])r‡   rÐ   rˆ   rQ   r¸   rÐ   )r�   rQ   r¸   ÚNone)r˜   rQ   r™   rQ   rš   rQ   r�   rQ   r›   rÖ   r¸   r   )r9   r9   r9   )r   rQ   rÂ   rQ   rÃ   rQ   rÅ   rQ   rŽ   rQ   r)   rQ   rÆ   r   r¸   rÑ   )rC   rQ   rÅ   rQ   rÌ   rQ   rÍ   rQ   rÎ   rQ   r¸   rÑ   ))r¼   Ú
__future__r   ÚloggingÚtypingr   r   r   r   r   r	   r{   r   r
   ÚSEARCH_LIMIT_CAPr   r   r   r#   r&   r-   r0   r7   r:   r?   rG   rL   rY   ra   re   rg   rm   ro   ru   rƒ   r‹   r’   rŸ   r¡   rÇ   rÏ   r!   r   r   ú<module>rÜ      s®  ðñõ #ã ß A× Aã å 7àÐ ó"ó'ó
ó;ó.óZóZð
 QUõ óDó0ó
4ó3ó	,ódð hmð  LPõ xóKð °tñMØðMØ'ðMØ/8ðMØ@bðMàðMà04ðMð óMð °tñ
HØð
HØ'ð
HØ/8ð
HØ@mð
Hàð
Hà04ð
Hð ó
HóKð ;?ñNØðNØðNØ%3ðNØ>LðNØWZðNàðNà*7ðNð *óNó,ó	$óô$Ð-ô ô:Uôvr   