
    @=j                        d Z ddlmZ ddlmZ ddlZddlmZm	Z	 ddl
mZ  ej        e          ZdZddZ G d de          ZdS )u  DuckDuckGo search — plugin form (via the ``ddgs`` package).

Subclasses the plugin-facing :class:`agent.web_search_provider.WebSearchProvider`.
The legacy in-tree module ``tools.web_providers.ddgs`` was removed in the
same commit that moved this code under ``plugins/``; this file is now the
canonical implementation.

The ``ddgs`` package is an optional dependency. ``is_available()`` reflects
whether the package is importable; the plugin still registers either way so
``hermes tools`` can prompt the user to install it.
    )annotationsN)AnyDict)WebSearchProvider   querystr
safe_limitintreturnlist[dict[str, Any]]c                   ddl m} g } |d          5 }t          |                    | |                    D ]\  }}||k    r nt	          |                    d          p|                    d          pd          }|                    t	          |                    d	d                    |t	          |                    d
d                    |dz   d           ddd           n# 1 swxY w Y   |S )aC  Run the blocking ddgs query and return normalized hits.

    Module-level (not a closure) so tests can patch it directly without
    spawning a real multi-second worker thread. ``DDGS(timeout=...)`` bounds
    each individual HTTP request; the overall wall-clock cap is enforced by
    the caller via a future timeout.
    r   )DDGS
   timeout)max_resultshrefurl titlebody   )r   r   descriptionpositionN)ddgsr   	enumeratetextr	   getappend)r   r
   r   resultsclientihitr   s           ?/home/rurouni/.hermes/hermes-agent/plugins/web/ddgs/provider.py_run_ddgs_searchr&      sL    $&G	b			 VEz J JKK 	 	FAsJcggfoo==2>>CNN "!5!566#&swwvr':':#;#; !A	                   Ns   CC,,C03C0c                  l    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
ddZdS )DDGSWebSearchProvidera  DuckDuckGo HTML-scrape search provider.

    No API key needed. Rate limits are enforced server-side by DuckDuckGo;
    the provider surfaces ``DuckDuckGoSearchException`` and other ddgs errors
    as ``{"success": False, "error": ...}`` rather than raising.
    r   r	   c                    dS )Nr    selfs    r%   namezDDGSWebSearchProvider.nameB   s    v    c                    dS )NDuckDuckGo (ddgs)r*   r+   s    r%   display_namez"DDGSWebSearchProvider.display_nameF   s    ""r.   boolc                2    	 ddl }dS # t          $ r Y dS w xY w)u   Return True when the ``ddgs`` package is importable.

        Probes the import once; cheap because Python caches the import. Must
        NOT perform network I/O — runs at tool-registration time and on every
        ``hermes tools`` paint.
        r   NTF)r   ImportError)r,   r   s     r%   is_availablez"DDGSWebSearchProvider.is_availableJ   s7    	KKK4 	 	 	55	s    
c                    dS )NTr*   r+   s    r%   supports_searchz%DDGSWebSearchProvider.supports_searchX   s    tr.   c                    dS )NFr*   r+   s    r%   supports_extractz&DDGSWebSearchProvider.supports_extract[   s    ur.      r   limitr   Dict[str, Any]c                6   	 ddl }n# t          $ r dddcY S w xY wt          dt          |                    }t	          j        d          }	 |                    t          ||          }	 |                    t                    }n[# t          j
        $ rI t                              d	t          |           dd
t           ddcY |                    dd           S w xY wnQ# t          $ rD}t                              d|           dd| dcY d}~|                    dd           S d}~ww xY w	 |                    dd           n# |                    dd           w xY wt                              d|t!          |          |           dd|idS )a  Execute a DuckDuckGo search and return normalized results.

        The synchronous ``ddgs`` call is run in a worker thread with a hard
        wall-clock timeout (``_SEARCH_TIMEOUT_SECS``) so a hung search cannot
        block the shared agent loop indefinitely (#36776).
        r   NFu8   ddgs package is not installed — run `pip install ddgs`)successerrorr   )max_workersr   z-DDGS search timed out after %ds for query: %rz"DuckDuckGo search timed out after uh   s — DuckDuckGo may be rate-limiting or slow. Try again later or switch to a different search provider.T)waitcancel_futureszDDGS search error: %szDuckDuckGo search failed: z'DDGS search '%s': %d results (limit %d)web)r>   data)r   r4   maxr   _cfThreadPoolExecutorsubmitr&   result_SEARCH_TIMEOUT_SECSTimeoutErrorloggerwarningshutdown	Exceptioninfolen)	r,   r   r;   r   r
   poolfutureweb_resultsexcs	            r%   searchzDDGSWebSearchProvider.search^   s'   	KKKK 	 	 	 S    	 CJJ''
 %!444	;[[!15*EEF$mm4HmII#   C(%  
  %D=Q D D D     MMuTM::::+   	S 	S 	SNN2C888$/QC/Q/QRRRRRRR MMuTM::::	S , MMuTM::::DMMuTM::::=uc+FVFVX]^^^%)=>>>sf    C$ ,B C$ >C C$ C  C$ #E $
D2."D-D2E -D22E E'c                    dddg ddS )Nr0   u   free · no key · search onlyuR   Search via the ddgs Python package — no API key (pair with any extract provider)r   )r-   badgetagenv_vars
post_setupr*   r+   s    r%   get_setup_schemaz&DDGSWebSearchProvider.get_setup_schema   s"    '4g !
 
 	
r.   N)r   r	   )r   r2   )r:   )r   r	   r;   r   r   r<   )r   r<   )__name__
__module____qualname____doc__propertyr-   r1   r5   r7   r9   rV   r\   r*   r.   r%   r(   r(   :   s             X # # # X#         5? 5? 5? 5? 5?n	
 	
 	
 	
 	
 	
r.   r(   )r   r	   r
   r   r   r   )r`   
__future__r   concurrent.futuresfuturesrF   loggingtypingr   r   agent.web_search_providerr   	getLoggerr]   rL   rJ   r&   r(   r*   r.   r%   <module>ri      s   
 
 # " " " " "                      7 7 7 7 7 7		8	$	$     6d
 d
 d
 d
 d
- d
 d
 d
 d
 d
r.   