Ë
    âß²jº  ã                  ó  — d Z ddlmZ ddlZddlmZmZmZmZ ddl	Z	ddl
mZmZmZmZmZmZmZmZmZmZmZmZmZ  ej0                  e«      ZdZdddœZdd	„Zdd
œdd„Zdd„Zdd„Z dd„Z!dd„Z"dd„Z# G d„ de«      Z$ddiZ%d„ Z&y)u“  Tavily web search + content extraction (``/search``, ``/extract``; sync httpx).

Env: ``TAVILY_API_KEY`` (https://app.tavily.com/home, optional), ``TAVILY_BASE_URL``.
Keyed requests use ``Authorization: Bearer``; without a key the request is
keyless (``X-Tavily-Access-Mode: keyless``). Tavily is NOT in the zero-config
keyless ring â€” keyless access is opt-in by selecting Tavily in ``hermes tools``.
é    )ÚannotationsN)ÚAnyÚDictÚListÚOptional)ÚSEARCH_LIMIT_CAPÚBaseWebSearchProviderÚdocumentÚextract_failÚhttp_status_detailÚprovider_envÚrun_extractÚ
run_searchÚsearch_failÚ	search_okÚsetup_schemaÚ	title_hitÚuse_keylesszhermes-agentF)Úinclude_raw_contentÚinclude_imagesc                ó8   — dt         i}| r
d| › �|d<   |S d|d<   |S )NzX-Client-NamezBearer ÚAuthorizationÚkeylesszX-Tavily-Access-Mode)Ú_CLIENT_NAME)Úapi_keyÚheaderss     ú@/home/ubuntu/.hermes/hermes-agent/plugins/web/tavily/provider.pyÚ_tavily_headersr      s9   € Ø¤Ð-€GÙØ%,¨W¨IÐ#6ˆ�Ñ ð €Nð +4ˆÐ&Ñ'Ø€Nó    ©r   c               ó>  — |€t        d«      }t        d«      xs d}|› d| j                  d«      › �}t        j                  d| |«       t	        j
                  ||dt        |«      ¬«      }|j                  dk\  rt        t        |«      «      ‚|j                  «       S )	a!  POST to Tavily and return parsed JSON. ``api_key=None`` reads ``TAVILY_API_KEY``;
    pass ``""`` to force the keyless header even when a key exists
    (``web.provider_tier.tavily: free``). Non-2xx raises ValueError with the body so
    Tavily's rate-limit/upgrade text reaches the model.ÚTAVILY_API_KEYÚTAVILY_BASE_URLzhttps://api.tavily.comú/zTavily %s request to %sé<   )ÚjsonÚtimeoutr   i�  )r   ÚlstripÚloggerÚinfoÚhttpxÚpostr   Ústatus_codeÚ
ValueErrorr   r&   )ÚendpointÚpayloadr   Úbase_urlÚurlÚresponses         r   Ú_tavily_requestr4   %   s•   € ð
 €ÜÐ/Ó0ˆÜÐ-Ó.ÒJÐ2J€HØˆJ�a˜Ÿ™¨Ó,Ð-Ð
.€CÜ
‡K�KÐ)¨8°SÔ9Ü�z‰z˜# G°RÄÐQXÓAYÔZ€HØ×Ñ˜sÒ"ÜÔ+¨HÓ5Ó6Ð6Ø�=‰=‹?Ðr   c                óú   — t        t        | j                  dg «      «      D ��cg c]F  \  }}t        |j                  dd«      |j                  dd«      |j                  dd«      |dz   «      ‘ŒH c}}«      S c c}}w )NÚresultsÚtitleÚ r2   Úcontenté   )r   Ú	enumerateÚgetr   )r3   ÚiÚrs      r   Ú _normalize_tavily_search_resultsr?   5   so   € Üä˜hŸl™l¨9°bÓ9Ó:÷áˆAˆqô 	�!—%‘%˜ Ó$ a§e¡e¨E°2Ó&6¸¿¹¸iÈÓ8LÈaÐRSÉeÕTóó ð ùó s   ¤AA7
c                ó  — | j                  dg «      D �cg c]S  }t        |j                  dd«      |j                  dd«      |j                  dd«      xs |j                  dd«      «      ‘ŒU }}|| j                  dg «      D �cg c].  }t        |j                  dd«      |j                  dd	«      «      ‘Œ0 c}z  }|| j                  d
g «      D �cg c]  }t        t        |«      d	«      ‘Œ c}z  }|S c c}w c c}w c c}w )zLMap ``/extract`` to documents without attributing missing URLs to a request.r6   r2   r8   r7   Úraw_contentr9   Úfailed_resultsÚerrorzextraction failedÚfailed_urls)r<   r
   Ú_failed_documentÚstr)r3   r>   Ú	documentsÚfÚus        r   Ú_normalize_tavily_documentsrJ   <   s
  € ð —‘˜i¨Ó,öàô 	�—‘�u˜bÓ! 1§5¡5¨°"Ó#5°q·u±u¸]ÈBÓ7OÒ7gÐST×SXÑSXÐYbÐdfÓSgÕhð€Ið ð Ðck×coÑcoð  qAð  CEó  dFö  GÐ^_Ô" 1§5¡5¨°Ó#3°Q·U±U¸7ÐDWÓ5XÕYò  Gñ  G€IØÈÏÉÐVcÐegÓIhÖiÀAÔ"¤3 q£6Ð+>Õ?ÒiÑi€IØÐùòùò GùÚis   •AC4Â3C9ÃC>c                ó   — | ddd|d| idœS )Nr8   Ú	sourceURL)r2   r7   r9   rA   rC   Úmetadata© )r2   rC   s     r   rE   rE   G   s   € Ø °À2ÐPUÐdoÐqtÐcuÑvÐvr   c                ó   — d| › d�S )NzzTAVILY_API_KEY is not set. Get a key at https://app.tavily.com/home or select Tavily in `hermes tools` for opt-in keyless ú.rN   )Úactions    r   Ú_missing_key_errorrR   K   s)   € ð Hð  IOð  HPð  PQð  Rð  Rr   c                óp   — t        d«      }t        d|«      }|s|sdt        | «      dfS |rdn|d|rdfS dfS )z¬``(request_key, missing_key_error, log_prefix)``: request key is ``""`` when forcing
    keyless, ``None`` when neither key nor keyless applies (``missing_key_error`` set).r"   ÚtavilyNr8   zkeyless )r   r   rR   )rQ   r   Úforce_keylesss      r   Ú_authrV   O   sO   € ô Ð+Ó,€GÜ ¨'Ó2€MÙ¡ØÔ'¨Ó/°Ð3Ð3Ù‰2 G¨TÁ°:ÐVÐVÐTVÐVÐVr   c                  ó>   — e Zd ZdZdZdZdZdZdZd
dd„Z	dd„Z
dd„Zy	)ÚTavilyWebSearchProviderz<Tavily search + extract provider (keyed, or opt-in keyless).rT   ÚTavilyr"   Tc                ó6   ‡‡— dˆˆfd„}t        dt        |«      S )Nc                 óÌ   •— t        d«      \  } }}|rt        |«      S t        j                  d|‰‰«       ‰t	        ‰t
        «      dœt        ¥}t        t        d|| ¬«      «      S )NÚsearchz Tavily %ssearch: '%s' (limit=%d))ÚqueryÚmax_resultsr    )	rV   r   r)   r*   Úminr   Ú_SEARCH_PAYLOADr?   r4   )ÚkeyÚmissingÚprefixr0   Úlimitr]   s       €€r   Ú_bodyz-TavilyWebSearchProvider.search.<locals>._bodyc   sa   ø€ Ü#(¨£?Ñ ˆC�˜&ÙÜ" 7Ó+Ð+Ü�K‰KÐ:¸FÀEÈ5ÔQØ %´c¸%ÔAQÓ6RÑfÔVeÐfˆGÜ3´OÀHÈgÐ_bÔ4cÓdÐdr   rY   ©ÚreturnúDict[str, Any])r   r)   )Úselfr]   rd   re   s    `` r   r\   zTavilyWebSearchProvider.searchb   s   ù€ ö	eô ˜(¤F¨EÓ2Ð2r   c                ó4   ‡— dˆfd„}t        dt        ‰|«      S )Nc                 ó¶   •— t        d«      \  } }}|rt        ‰|«      S t        j                  d|t	        ‰«      «       t        d‰ddœ| ¬«      }t        |«      S )NÚextractzTavily %sextract: %d URL(s)F)Úurlsr   r    )rV   r   r)   r*   Úlenr4   rJ   )ra   rb   rc   Úrawrm   s       €r   re   z.TavilyWebSearchProvider.extract.<locals>._bodyn   sX   ø€ Ü#(¨Ó#3Ñ ˆC�˜&ÙÜ# D¨'Ó2Ð2Ü�K‰KÐ5°v¼sÀ4»yÔIÜ! )°dÈeÑ-TÐ^aÔbˆCÜ.¨sÓ3Ð3r   rY   )rg   úList[Dict[str, Any]])r   r)   )ri   rm   Úkwargsre   s    `  r   rl   zTavilyWebSearchProvider.extractm   s   ø€ õ	4ô ˜8¤V¨T°5Ó9Ð9r   c                ó"   — t        dddddd«      S )NrY   u   free Â· key optionalzGSearch + extract. Opt-in keyless; set TAVILY_API_KEY for higher limits.r"   uC   Tavily API key (optional â€” keyless works when Tavily is selected)zhttps://app.tavily.com/home)r   )ri   s    r   Úget_setup_schemaz(TavilyWebSearchProvider.get_setup_schemax   s%   € ÜØÐ,Ð.wØÐcð  fCó
ð 	
r   N)é   )r]   rF   rd   Úintrg   rh   )rm   z	List[str]rq   r   rg   rp   rf   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚNAMEÚDISPLAY_NAMEÚKEY_ENVÚEXTRACTÚKEYLESSr\   rl   rs   rN   r   r   rX   rX   Y   s-   „ ÙFà€DØ€LØ€GØ€GØ€Gô	3ó	:ô
r   rX   ÚWebSearchProvider)zagent.web_search_providerr   c                óÌ   — t         j                  | «      }|€t        dt        ›d| ›�«      ‚dd l}ddlm}  |t        | g|¢­Ž  t        |j                  |d   «      |d   «      S )Nzmodule z has no attribute r   )Ú	warn_oncer:   )	Ú_PLUGIN_COMPAT_LAZYr<   ÚAttributeErrorrv   Ú	importlibÚhermes_cli.plugin_compatr�   ÚgetattrÚimport_module)ÚnameÚtargetr„   r�   s       r   Ú__getattr__rŠ   Š   se   € Ü ×$Ñ$ TÓ*€FØ€~Ü˜w¤x lÐ2DÀTÀHÐMÓNÐNÛÝ2ÙŒh˜Ð&˜vÓ&Ü�9×*Ñ*¨6°!©9Ó5°v¸a±yÓAÐAr   )r   rF   rg   zDict[str, str])r/   rF   r0   rh   r   zOptional[str]rg   rh   )r3   rh   rg   rh   )r3   rh   rg   rp   )r2   rF   rC   rF   rg   rh   )rQ   rF   rg   rF   )rQ   rF   rg   z(tuple[Optional[str], Optional[str], str])'ry   Ú
__future__r   ÚloggingÚtypingr   r   r   r   r+   Úplugins.web._commonr   r	   r
   r   r   r   r   r   r   r   r   r   r   Ú	getLoggerrv   r)   r   r`   r   r4   r?   rJ   rE   rR   rV   rX   r‚   rŠ   rN   r   r   ú<module>r�      s£   ðñõ #ã ß ,Ó ,ã ÷÷ ÷ õ ð
 
ˆ×	Ñ	˜8Ó	$€à€à*/À5ÑI€óð Y]õ ó óówóRóWô#
Ð3ô #
ðZ ÐKðÐ ó
Br   