+
    kHàjm+  ã                  óR  a € 0 t $ R t^ RIHt ^ RIHt ^ RIt^ RIt^ RI	t	^ RI
t
^ RIt^ RIt^ RIHtHtHt ^ RIHtHtHtHtHt ]P.                  ! ]4      t^tRtRtRtR]R&   RsR	]R
&    ! R R] 4      t!R R lt"R R lt#R]/R R llt$R R lt%R R lt&R R lt' ! R R]4      t(R# )uØ  DuckDuckGo search via the optional ``ddgs`` package (search only, no key). ``is_available()``
reflects package importability; the plugin registers either way so ``hermes tools`` can offer to
install it. Isolation: ``ddgs``/``primp`` can block inside native code while holding the GIL, so a
thread-pool ``future.result(timeout=â€¦)`` cap can never fire and Ctrl+C/SIGTERM freeze the process â€”
each search runs in a disposable child process the parent can terminate/kill.
)ÚannotationsN)ÚAnyÚDictÚOptional)ÚBaseWebSearchProviderÚsearch_failÚ	search_okÚsetup_schemaÚ	title_hitgš™™™™™¹?g      ð?zOptional[str]Ú
_test_hookúOptional[subprocess.Popen]Ú_last_worker_procc                  ó   € ] tR t^"tRtRtR# )Ú_SearchInterruptedzHRaised when tools.interrupt.is_interrupted() trips during a search wait.© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__static_attributes__r   ó    Ú>/home/ubuntu/.hermes/hermes-agent/plugins/web/ddgs/provider.pyr   r   "   s   † ÝRr   r   c               ó$   € V ^8„  d   QhRRRRRR/# ©é   ÚqueryÚstrÚ
safe_limitÚintÚreturnúlist[dict[str, Any]]r   )Úformats   "r   Ú__annotate__r#   &   s"   € ÷ ñ ˜Cð ¨Sð Ð5Iñ r   c                óì  € ^ RI Hp . pV! ^
R7      ;_uu_ 4       p\        VP                  WR7      4       Fž  w  rVWQ8¼  d    M•TP	                  \        \        VP                  RR4      4      \        VP                  R4      ;'       g    VP                  R4      ;'       g    R4      \        VP                  RR4      4      V^,           4      4       K   	  R	R	R	4       V#   + '       g   i     T# ; i)
u  Blocking ddgs query â†’ normalized hits (module-level: the child worker imports it,
tests patch it for in-process runs).

``DDGS(timeout=â€¦)`` bounds each individual HTTP request; the overall wall-clock cap is enforced by the
parent via process timeout (#68096).
)ÚDDGS©Útimeout)Úmax_resultsÚtitleÚ ÚhrefÚurlÚbodyN)Úddgsr%   Ú	enumerateÚtextÚappendr
   r   Úget)r   r   r%   ÚresultsÚclientÚiÚhits   &&     r   Ú_run_ddgs_searchr7   &   së   € õ Ø$&€GÙ	�b×	Õ	˜VÜ §¡¨E Ó JÖK‰FˆAØŒÙØ�N‰Nœ9¤S¨¯©°¸"Ó)=Ó%>ÄÀCÇGÁGÈFÃO×DkÐDkÐWZ×W^ÑW^Ð_dÓWe×DkÐDkÐikÓ@lÔnqÐru×ryÑryð  {Að  CEó  sFó  oGð  IJð  MNõ  INó  Oö  Pñ L÷ 
ð
 €N÷ 
Ö	ð
 €Nús   šBC"Â#5C"Ã"C3	c               ó   € V ^8„  d   QhRR/# )r   r    r   r   )r"   s   "r   r#   r#   7   s   € ÷ 	Gñ 	G˜Sñ 	Gr   c                 ó¾  €  ^ RI p \        V RR4      ;p'       dZ   \        P                  P	                  \        P                  P	                  \        P                  P                  V4      4      4      #  \        P                  P                  \        P                  P                  ! \        .\        P                  .^,          O5!  4      #   \         d     Lfi ; i)z‘``sys.path`` entry that makes ``import plugins`` work in the child (live package
location first; correct for source checkouts and site-packages).NÚ__file__)
ÚpluginsÚgetattrÚosÚpathÚdirnameÚabspathÚ	ExceptionÚjoinr:   Úpardir)Úplugins_pkgÚpkg_files     r   Ú_plugins_path_entryrF   7   s•   € ðÛ%Ü˜{¨J¸Ó=Ð=ˆ8Ö=Ü—7‘7—?‘?¤2§7¡7§?¡?´2·7±7·?±?À8Ó3LÓ#MÓNÐNð >ô �7‰7�?‰?œ2Ÿ7™7Ÿ<š<¬ÐE´R·Y±Y°KÀ!µOÓEÓFÐFøô ô Ùðús   ‚A1C ÃCÃCÚgracec               ó$   € V ^8„  d   QhRRRRRR/# )r   Úprocr   rG   Úfloatr    ÚNoner   )r"   s   "r   r#   r#   C   s#   € ÷ 8ñ 8Ð8ð 8ÀEð 8Ðfjñ 8r   c               ón  a a€ S f   R# RpR VV 3R llp S P                   S P                  3 F*  pS P                  4       e   K  V! 4        V! 4       '       * pK,  	  V'       d#   \        P	                  RS P
                  4       R# R#   \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)uá   Terminate a worker, escalate to kill, and wait so no orphan remains. Does not close
the parent's pipe ends â€” closing stdout while another thread is blocked in ``read()``
deadlocks on some platforms; the caller drains first.NFc               ó   € V ^8„  d   QhRR/# ©r   r    Úboolr   )r"   s   "r   r#   Ú)_terminate_and_reap.<locals>.__annotate__K   s   € ÷ 'ñ '˜dñ 'r   c                 óè   <€ \         P                  ! 4       S,           p SP                  4       f3   \         P                  ! 4       V 8  d   \         P                  ! R4       KD  SP                  4       R J# )Ngš™™™™™©?)ÚtimeÚ	monotonicÚpollÚsleep)ÚdeadlinerG   rI   s    €€r   Ú_wait_until_deadÚ-_terminate_and_reap.<locals>._wait_until_deadK   sK   ø€ Ü—>’>Ó# eÕ+ˆØ�i‰i‹kÒ!¤d§n¢nÓ&6¸Ô&AÜ�JŠJ�tÖØ�y‰y‹{ $Ð&Ð&r   z*DDGS worker pid=%s did not exit after killzDDGS worker reap error: %s)Ú	terminateÚkillrT   ÚloggerÚwarningÚpidrA   Údebug)rI   rG   ÚaliverW   ÚescalateÚexcs   fd    r   Ú_terminate_and_reaprb   C   s“   ù€ ð ‚|ÙØ€E÷'ñ 'ð8ØŸ™¨¯©Ó3ˆHØ�y‰y‹{Ô"Ù”
Ù,Ó.Ô.’ñ 4÷ Ü�N‰NÐGÈÏÉÖRñ øäô 8Ü�‰Ð1°3×7Ò7ûð8ús#   –*B ÁB Á$ B ÂB4ÂB/Â/B4c               ó    € V ^8„  d   QhRRRR/# )r   Úenvzdict[str, str]r    úsubprocess.Popenr   )r"   s   "r   r#   r#   \   s   € ÷ ñ �~ð Ð*:ñ r   c                ó~  € \         P                  P                  R4      pV'       d>   V P                  RR4      pV'       d   V\         P                  ,           V,           MTV R&   V P                  RR4      p\	        4       pV'       dO   WCP                  \         P                  4      9  d,   V'       d   V\         P                  ,           V,           MTV R&   \         P                  P                  \         P                  P                  \         P                  P                  \        4      4      R4      p\        P                  R8X  d   R\        P                  /MRR/p\        P                  ! \        P                   V.3R\        P"                  R	\        P"                  R
\        P$                  RV RRRRRR/VB # )zàStart ``_search_worker.py`` as a script with ``plugins`` importable. Running as a
script puts ``plugins/web/ddgs/`` on ``sys.path[0]``, breaking ``import plugins...``,
so the real package location is prepended to PYTHONPATH.Ú
PYTHONPATHr*   z_search_worker.pyÚwin32ÚcreationflagsÚstart_new_sessionTÚstdinÚstdoutÚstderrrd   r0   Úencodingzutf-8ÚerrorsÚreplace)r=   Úenvironr2   ÚpathseprF   Úsplitr>   rB   r?   r@   r:   ÚsysÚplatformÚ
subprocessÚCREATE_NEW_PROCESS_GROUPÚPopenÚ
executableÚPIPEÚDEVNULL)rd   Ú_ambient_ppÚ_currentÚchild_pythonpathÚ
path_entryÚworker_pathÚextra_kwargss   &      r   Ú_spawn_workerr‚   \   si  € ô —*‘*—.‘. Ó.€KßØ—7‘7˜<¨Ó,ˆç3;ˆKœ"Ÿ*™*Õ$ xÖ/Àð 	ˆLÑð —w‘w˜|¨RÓ0ÐÜ$Ó&€Jß�j×(>Ñ(>¼r¿z¹zÓ(JÔJßJZ˜J¬¯©Õ3Ð6FÖFÐ`jˆˆLÑÜ—'‘'—,‘,œrŸw™wŸ™¬r¯w©w¯©¼xÓ/HÓIÐK^Ó_€Kä]`×]iÑ]iÐmtÔ]t O´Z×5XÑ5XÑ#Yð  |Oð  QUð  {V€Lô ×ÒÜ	�‰˜Ð%ñÜ-7¯_©_ðÜEOÇ_Á_ðÜ]g×]oÑ]oðàðàðà%,ðà5>ðàBNñð r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úrawr   rI   re   r    r!   r   )r"   s   "r   r#   r#   z   s#   € ÷ ñ ˜ð Ð$4ð Ð9Mñ r   c                óP  € V P                  4       p V '       g   \        RVP                  4        R24      h \        P                  ! V 4      p\        T\        4      '       g   \        RT: 24      hTP                  R4      '       g.   \        \        TP                  R4      ;'       g    R	4      4      hTP                  R
4      ;'       g    . p\        T\        4      '       g   \        R4      hT#   \        P
                   d   p\        RT R,          : 24      ThRp?ii ; i)zSDecode the worker's stdout envelope; raise ``RuntimeError`` on any malformed shape.z*DDGS worker exited without a result (code=Ú)z#DDGS worker returned invalid JSON: :NéÈ   NNz*DDGS worker returned an invalid envelope: ÚokÚerrorzDDGS worker failedr3   z%DDGS worker returned non-list results)ÚstripÚRuntimeErrorrT   ÚjsonÚloadsÚJSONDecodeErrorÚ
isinstanceÚdictr2   r   Úlist)r„   rI   Úenvelopera   r3   s   &&   r   Ú_parse_enveloper“   z   sú   € à
�)‰)‹+€CßÜÐGÈÏ	É	ËÀ}ÐTUÐVÓWÐWðYÜ—:’:˜c“?ˆô �h¤×%Ò%ÜÐGÈÁ|ÐTÓUÐUØ�<‰<˜×ÒÜœ3˜xŸ|™|¨GÓ4×LÐLÐ8LÓMÓNÐNØ�l‰l˜9Ó%×+Ð+¨€GÜ�gœt×$Ò$ÜÐBÓCÐCØ€Nøô ×Ñô YÜÐ@ÀÀTÅÁÐNÓOÐUXÐXûðYús   ·C4 Ã4D%Ä	D Ä D%c               ó$   € V ^8„  d   QhRRRRRR/# r   r   )r"   s   "r   r#   r#   �   s"   € ÷ '&ñ '& Cð '&°Sð '&Ð=Qñ '&r   c                óþ  € ^ RI Hp ^ RIHp RV RV/pV! \	        \
        P                  4      4      p\        '       d   \        VR&   RVR&   \        V4      ;ps	\        P                  ! ^R7      pVP                  VP                  \        P                  ! V4      4      pR	R	R
rºp	 \         P"                  ! 4       \$        ,           pV
'       gh   V! 4       ;p	'       gY   V\         P"                  ! 4       ,
          ;p^ 8”  d6    VP'                  \)        \*        V4      R7      ^ ,          ;'       g    R
Rr«Ko  \/        V4       VP1                  4       '       g3    T;'       g(    VP'                  \2        R7      ^ ,          ;'       g    R
pVP7                  R	RR7       V	'       d   \9        R4      hV
'       g   \-        R\$         R24      h\;        W¶4      #   \        P,                   d     EK'  i ; i  \4         d     Lvi ; i  \/        T4       TP1                  4       '       gE    T;'       g(    TP'                  \2        R7      ^ ,          ;'       g    R
pM  \4         d     Mi ; iTP7                  R	RR7       i ; i)u,  Run ``_run_ddgs_search`` in a disposable process with a hard deadline. The parent
never joins a child that may be in native code holding *its* GIL â€” it polls a
communicator thread and, on timeout/interrupt, kills the OS process.
Raises ``TimeoutError``, ``_SearchInterrupted``, or ``RuntimeError``.)Úis_interrupted)Ú_sanitize_subprocess_envr   r   Ú	test_hookÚ1ÚHERMES_DDGS_ALLOW_TEST_HOOKS)Úmax_workersFr*   r&   T)ÚwaitÚcancel_futuresúDuckDuckGo search interruptedú"DuckDuckGo search timed out after Ús)Útools.interruptr–   Útools.environments.localr—   r�   r=   rq   r   r‚   r   ÚcfÚThreadPoolExecutorÚsubmitÚcommunicaterŒ   ÚdumpsrR   rS   Ú_SEARCH_TIMEOUT_SECSÚresultÚminÚ_POLL_INTERVAL_SECSÚTimeoutErrorrb   ÚdoneÚ_TERMINATE_GRACE_SECSrA   Úshutdownr   r“   )r   r   r–   r—   Úrequestrd   rI   ÚpoolÚfutÚinterruptedr­   r„   rV   Ú	remainings   &&            r   Ú_run_ddgs_search_boundedrµ   �   s  € õ
 /ÝAà&¨¨|¸ZÐH€GÙ
"¤4¬¯
©
Ó#3Ó
4€CßƒzÜ)ˆ�ÑØ.1ˆÐ*Ñ+Ü,¨SÓ1Ð1€DÐô × Ò ¨QÔ/€DØ
�+‰+�d×&Ñ&¬¯
ª
°7Ó(;Ó
<€CØ" E¨2�s€Kð7Ü—>’>Ó#Ô&:Õ:ˆß©~Ó/?Ð ? Ö ?ÐS[Ô^b×^lÒ^lÓ^nÕSnÐFnÀiÐrsÔEsðØŸJ™J¬sÔ3FÈ	Ó/R˜JÓSÐTUÕV×\Ð\ÐZ\Ð^b’Tô 	˜DÔ!à�x‰x�zŠzðØ×OÐO˜SŸZ™ZÔ0E˜ZÓFÀqÕI×OÐOÈR�ð 	�‰˜5°ˆÔ6ßÜ Ð!@ÓAÐAßÜÐ?Ô@TÐ?UÐUVÐWÓXÐXÜ˜3Ó%Ð%øô —?‘?ô Ûðûô ô Ùðûô 	˜DÔ!à�x‰x�zŠzðØ×OÐO˜SŸZ™ZÔ0E˜ZÓFÀqÕI×OÐOÈR‘øÜô Ùðúà�‰˜5°ˆÕ6ús�   Â&'H ÃH Ã#H Ä-G Ä/G Ä3H ÅG1 Å $G1 ÆG1 ÇG.Ç)H Ç-G.Ç.H Ç1G?Ç>G?È"I<È%IÈ.$IÉIÉI<ÉI%É"I<É$I%É%I<c                  óJ   € ] tR t^·tRtRtRtR R ltRR R lltR R	 lt	R
t
R# )ÚDDGSWebSearchProviderz¢DuckDuckGo HTML-scrape search provider (no API key; DDG rate-limits server-side).
ddgs errors surface as ``{"success": False, "error": ...}`` rather than raising.r.   úDuckDuckGo (ddgs)c               ó   € V ^8„  d   QhRR/# rN   r   )r"   s   "r   r#   Ú"DDGSWebSearchProvider.__annotate__¾   s   € ÷ ñ ˜dñ r   c                ó4   €  ^ RI pR#   \         d     R# i ; i)u�   True when ``ddgs`` is importable. Must NOT do network I/O â€” runs at
tool-registration time and on every ``hermes tools`` paint.NTF)r.   ÚImportError)Úselfr.   s   & r   Úis_availableÚ"DDGSWebSearchProvider.is_available¾   s   € ð	ÛÙøÜô 	Úð	ús   ‚ ˆ–c               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r   Úlimitr   r    údict[str, Any]r   )r"   s   "r   r#   rº   Ç   s!   € ÷ &ñ &˜Cð &¨ð &°Nñ &r   c           	     ó"  € V P                  4       '       g   \        R4      #  \        V\        ^\	        V4      4      4      p\        P                  R
T\        T4      T4       \        T4      #   \
         d2    \        P                  R\        T4       \        R\         R24      u # \         d%    \        P                  RT4       \        R4      u # \         d/   p\        P                  RT4       \        RT 24      u R	p?# R	p?ii ; i)z›Run the search in a disposable child with a hard wall-clock timeout so a
hung native ``primp`` call cannot freeze the Hermes process.

See #36776, #68096.
u8   ddgs package is not installed â€” run `pip install ddgs`z-DDGS search timed out after %ds for query: %rrŸ   uh   s â€” DuckDuckGo may be rate-limiting or slow. Try again later or switch to a different search provider.z%DDGS search interrupted for query: %rrž   zDDGS search error: %szDuckDuckGo search failed: Nz'DDGS search '%s': %d results (limit %d))r¾   r   rµ   Úmaxr   r¬   r[   r\   r¨   r   ÚinforA   Úlenr   )r½   r   rÁ   Úweb_resultsra   s   &&&  r   ÚsearchÚDDGSWebSearchProvider.searchÇ   sü   € ð × Ñ ×"Ò"ÜÐYÓZÐZð	Cä2°5¼#¸aÄÀUÃÓ:LÓMˆKô 	�‰Ð=¸uÄcÈ+ÓFVÐX]Ô^Ü˜Ó%Ð%øô ô 	Ü�N‰NÐJÔL`ÐbgÔhÜØ4Ô5IÐ4Jð Kuð uóò ô "ô 	@Ü�K‰KÐ?ÀÔGÜÐ>Ó?Ò?Üô 	CÜ�N‰NÐ2°CÔ8ÜÐ!;¸C¸5ÐAÓBÕBûð	Cús5   £A. Á.9DÂ)DÂ2"DÃDÃDÃ #D	ÄDÄ	Dc               ó   € V ^8„  d   QhRR/# )r   r    rÂ   r   )r"   s   "r   r#   rº   á   s   € ÷ 
ñ 
 .ñ 
r   c                	ó    € \        R RRRR7      # )r¸   u   free Â· no key Â· search onlyuR   Search via the ddgs Python package â€” no API key (pair with any extract provider)r.   )Ú
post_setup)r	   )r½   s   &r   Úget_setup_schemaÚ&DDGSWebSearchProvider.get_setup_schemaá   s   € äØÐ!@Ø`Ðmsô
ð 	
r   r   N)é   )r   r   r   r   r   ÚNAMEÚDISPLAY_NAMEr¾   rÈ   rÍ   r   r   r   r   r·   r·   ·   s(   † ñXð €DØ&€Lõ÷&÷4
ñ 
r   r·   ))Ú__conditional_annotations__r   Ú
__future__r   Úconcurrent.futuresÚfuturesr£   rŒ   Úloggingr=   rv   rt   rR   Útypingr   r   r   Úplugins.web._commonr   r   r   r	   r
   Ú	getLoggerr   r[   r¨   r«   r®   r   Ú__annotations__r   rA   r   r7   rF   rb   r‚   r“   rµ   r·   )rÒ   s   @r   Ú<module>rÛ      s®   øðôõ #å Û Û Û 	Û Û 
Û ß &Ñ &ç fÕ fà	×	Ò	˜8Ó	$€ð Ð ØÐ ØÐ Ø €
ˆMÓ  Ø04Ð Ð-Ó 4ôS˜ô Sõõ"	Gð8ÐLa÷ 8õ2õ<õ&'&ôT/
Ð1ö /
r   