+
    iHàjˆ"  ã                  ó2  a € 0 t $ R t^ RIHt ^ RIt^ RIHt ^ RIHtH	t	 ^ RI
Ht ]P                  ! ]4      t]! R]]R7      tR]R	&   ]P#                  ]! 4       4       R
 R ltR R ltRtRtR R ltR R ltR R ltRRR/R R llltR R ltR R ltR# )u‚  Web Search Provider Registry.

Populated by plugins via :meth:`PluginContext.register_web_search_provider`;
consumed by the ``web_search`` / ``web_extract`` wrappers in :mod:`tools.web_tools`.

Active selection, in precedence order (the ``supports_search`` /
``supports_extract`` capability filter applies at every step, so a search-only
provider configured as ``web.extract_backend`` falls through):

1. ``web.search_backend`` / ``web.extract_backend``, then ``web.backend``.
2. The single capability-eligible provider that is registered AND available.
3. Legacy preference walk (``_LEGACY_PREFERENCE``) filtered by availability â€”
   the historic ``tools.web_tools._get_backend()`` order, so installs that never
   set a config key keep landing on the same provider.
4. Keyless free-tier walk (``_KEYLESS_PREFERENCE``), last resort.
5. ``None`` â€” the tool points the user at ``hermes tools``.
)ÚannotationsN)ÚOptional)ÚProviderRegistryÚis_available_safe)ÚWebSearchProviderÚWeb)ÚlabelÚprovider_clsÚloggerz#ProviderRegistry[WebSearchProvider]Ú	_registryc               ó    € V ^8„  d   QhRRRR/# )é   ÚpathÚstrÚreturnúOptional[str]© )Úformats   "Ú>/home/ubuntu/.hermes/hermes-agent/agent/web_search_registry.pyÚ__annotate__r   #   s   € ÷ ñ ˜Cð  Mñ ó    c                 ó~  €  ^ RI Hp V! 4       pV  F-  p\        V\        4      '       g    R# VP	                  V4      pK/  	  \        V\
        4      '       d'   VP                  4       '       d   VP                  4       # R#   \         d2   p\        P                  RRP                  T 4      T4        Rp?R# Rp?ii ; i)zGResolve a dotted config key from ``config.yaml``. Returns None on miss.)Úload_config_readonlyNzCould not read config %s: %sÚ.)Úhermes_cli.configr   Ú
isinstanceÚdictÚgetr   ÚstripÚ	Exceptionr
   ÚdebugÚjoin)r   r   ÚcurÚsegmentÚexcs   *    r   Ú_read_config_keyr%   #   s˜   € ðJÝ:á"Ó$ˆÛˆGÜ˜c¤4×(Ò(ÚØ—'‘'˜'Ó"ŠCñ ô �cœ3×Ò C§I¡I§K¢KØ—9‘9“;Ðñ øô ô JÜ�‰Ð3°S·X±X¸d³^ÀS×IÐIÙûðJús#   ‚)B  ­A B  Á.B  Â B<Â&B7Â7B<c               ó    € V ^8„  d   QhRRRR/# )r   Ú
capabilityr   r   r   r   )r   s   "r   r   r   4   s   € ÷ ñ  Cð ¨Mñ r   c                óœ   € \        RV  R24      ;'       g    \        RR4      pV'       d!   VP                  4       R8X  d   V R8X  d   R# R# V# )z½``web.<capability>_backend`` (preferred) or ``web.backend`` (shared fallback). The managed ``nous``
selection names no provider: it is served by Perplexity (search) and Firecrawl (extract).ÚwebÚ_backendÚbackendÚnousÚsearchÚ
perplexityÚ	firecrawl)r%   Úlower)r'   Ú
configureds   & r   Ú_configured_backendr2   4   sT   € ô " %¨J¨<°xÐ)@ÓA×gÐgÔEUÐV[Ð]fÓEg€Jß�j×&Ñ&Ó(¨FÔ2Ø)¨XÔ5ˆ|ÐF¸;ÐFØÐr   c               ó   € V ^8„  d   QhRR/# )r   r   Útupler   )r   s   "r   r   r   H   s   € ÷ ñ ˜Uñ r   c                 óÌ   €  ^ RI Hp Hp V\        V 4      ,          p\	        WR V RV ,           4      #   \
         d&   p\        P                  RT4        Rp?\        # Rp?ii ; i)z¼Keyless walk order, starting at the ring cursor in
:mod:`plugins.web.keyless_mcp` so resolution and dispatch agree on which
vendor a fresh install starts at; the rest follow in ring order.)Ú_KEYLESS_RINGÚ_ring_cursorNz"keyless ring order unavailable: %s)	Úplugins.web.keyless_mcpr6   r7   Úlenr4   r   r
   r    Ú_KEYLESS_PREFERENCE)r6   r7   Ústartr$   s       r   Ú_keyless_preferencer<   H   s`   € ð@ßGàœs =Ó1Õ1ˆÜ�] 6Ð*¨]¸6¸EÐ-BÕBÓCÐCøÜô @Ü�‰Ð9¸3×?Ð?ÜÐûð@ús   ‚03 ³A#¾AÁA#c               ó$   € V ^8„  d   QhRRRRRR/# )r   r1   r   r'   r   r   úOptional[WebSearchProvider]r   )r   s   "r   r   r   V   s"   € ÷ 8ñ 8˜ð 8°sð 8Ð?Zñ 8r   c               ó@  a€ \         P                  4       pR V3R llpR R lpV '       dX   VP                  V 4      pVe   V! V4      '       d   V# Vf   \        P	                  RV 4       M\        P	                  RV S4       VP                  4        Uu. uF$  qc! V4      '       g   K  V! V4      '       g   K"  VNK&  	  pp\        V4      ^8X  d
   V^ ,          # \         F$  pVP                  V4      pVf   K  WW9   g   K"  Vu # 	  \        4       '       dR   \        4        FC  p	VP                  V	4      pVe   V! V4      '       g   K(   VP                  4       '       d   Vu # KE  	  R# u upi   \         d"   p
\        P	                  RYš4        Rp
?
Ku  Rp
?
ii ; i)	aŠ  Resolve the active provider for a capability ("search" | "extract").

Rules, in order (see module docstring): explicit config wins even when
``is_available()`` is False (the dispatcher surfaces a precise
"X_API_KEY is not set" error instead of a silent switch); then the single
available capable provider; then the availability-filtered legacy walk;
then the keyless free-tier walk; else None.
c               ó    € V ^8„  d   QhRRRR/# ©r   Úpr   r   Úboolr   )r   s   "r   r   Ú_resolve.<locals>.__annotate__a   s   € ÷ 
ñ 
Ð%ð 
¨$ñ 
r   c                ó†   <€ \        SR 8X  d   V P                  4       4      # SR8X  d   V P                  4       4      # R4      # )r-   ÚextractF)rC   Úsupports_searchÚsupports_extract)rB   r'   s   &€r   Ú_capableÚ_resolve.<locals>._capablea   sM   ø€ ÜØ#-°Ô#9ˆA×ÑÓó
ð 	
à)3°yÔ)@�×#Ñ#Ó%ó
ð 	
àFKó
ð 	
r   c               ó    € V ^8„  d   QhRRRR/# rA   r   )r   s   "r   r   rD   g   s   € ÷ Tñ TÐ'ð T¨Dñ Tr   c                ó$   € \        V \        R 4      # )z$provider %s.is_available() raised %s)r   r
   )rB   s   &r   Ú
_availableÚ_resolve.<locals>._availableg   s   € Ü  ¤FÐ,RÓSÐSr   Nz<web backend '%s' configured but not registered; falling backzCweb backend '%s' configured but does not support '%s'; falling backz,provider %s.is_keyless_available() raised %s)r   Úmergedr   r
   r    Úvaluesr9   Ú_LEGACY_PREFERENCEÚ_keyless_tier_enabledr<   Úis_keyless_availabler   )r1   r'   ÚsnapshotrI   rM   ÚproviderrB   ÚeligibleÚlegacyÚnamer$   s   &d         r   Ú_resolverY   V   sl  ø€ ô ×ÑÓ!€H÷
ð 
õT÷ Ø—<‘< 
Ó+ˆØÒ¡H¨X×$6Ò$6ØˆOØÒÜ�L‰LÐWÐYcÕdä�L‰LØUÐWaÐcmôð $Ÿ?™?Ô,ÓNÑ,�a°¸·”Á
È1Ç—�Ñ,€HÐNÜ
ˆ8ƒ}˜ÔØ˜�{Ðç$ˆØ—<‘< Ó'ˆØÔ HÖ$8ØŠOñ %ô ×ÒÜ'Ö)ˆDØ—|‘| DÓ)ˆHØÒ¡x°×'9Ò'9ÙðXØ×0Ñ0×2Ò2Ø#’Oñ 3ñ *ñ ùò/ Oøô( ô XÜ—‘ÐKÈT×WÒWûðXús0   ÂE,Â*E,Â:E,ÅE1Å"E1Å1FÅ<FÆFc               ó   € V ^8„  d   QhRR/# )r   r   rC   r   )r   s   "r   r   r   ‘   s   € ÷ 	ñ 	˜tñ 	r   c                 óä   €  ^ RI Hp  V ! 4       P                  R4      ;'       g    / p\        VP                  RR4      4      #   \         d"   p\
        P                  RT4        Rp?R# Rp?ii ; i)zBRead ``web.keyless_fallback`` from config.yaml (default: enabled).)Úload_configr)   Úkeyless_fallbackTz'keyless_fallback config read failed: %sN)r   r\   r   rC   r   r
   r    )r\   Úweb_cfgr$   s      r   rR   rR   ‘   s]   € ðÝ1á“-×#Ñ# EÓ*×0Ð0¨bˆÜ�G—K‘KÐ 2°DÓ9Ó:Ð:øÜô Ü�‰Ð>ÀÔDÝûðús   ‚"A ¥A ÁA/ÁA*Á*A/r'   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r1   r   r'   r   r   )r   s   "r   r   r   �   s"   € ÷ %ñ %¨ð %Èmð %Ðgtñ %r   c               ó*  € R R lpV '       g   VR	9   d   \        V4      p V '       g   R# T! V 4      p ^ RIHp V! 4       pVP                  P	                  4        F…  w  rg\        V\        4      '       g   K  VP                  R4      '       g   K6  VP                  '       d   KJ  VP                  R8X  g   K]  V! VP                  R^4      ^,          4      V8X  g   Kƒ  Vu # 	  R#   \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)
u  Plugin key of a *disabled* bundled web plugin that would have provided
the configured backend (``web.<capability>_backend`` â†’ ``web.backend``), or None.

Lets the dispatcher say "re-enable web-firecrawl" instead of "No web extract
provider configured". Resolved from config.yaml rather than the resolved
backend because a disabled provider fails the availability gate and silently
drops to the default. Bundled web plugins live under ``web/<vendor>`` with
the provider name differing only by hyphen/underscore, so both are normalized.

When a user sets ``web.extract_backend: firecrawl`` (or the search equivalent) but also lists
``web-firecrawl`` in ``plugins.disabled``, the provider never registers and the dispatcher would
otherwise emit a misleading "No web extract provider configured. Set web.extract_backend to ..." error â€”
even though the backend IS configured correctly. This helper detects that case so the dispatcher can
point the user at the actual cause (issue #40190 follow-up: pi314's disabled-plugin symptom).
c               ó    € V ^8„  d   QhRRRR/# )r   Úsr   r   r   )r   s   "r   r   Ú._disabled_web_plugin_for.<locals>.__annotate__­   s   € ÷ 3ñ 3�ð 3˜ñ 3r   c                ó^   € V P                  4       P                  4       P                  R R4      # )Ú-Ú_)r   r0   Úreplace)rb   s   &r   Ú_normÚ'_disabled_web_plugin_for.<locals>._norm­   s"   € Ø�w‰w‹y�‰Ó ×(Ñ(¨¨cÓ2Ð2r   N)Úget_plugin_managerzweb/zdisabled via configÚ/z%disabled-web-plugin lookup failed: %s)r-   rF   )r2   Úhermes_cli.pluginsrj   Ú_pluginsÚitemsr   r   Ú
startswithÚenabledÚerrorÚsplitr   r
   r    )	r1   r'   rh   Úwantrj   ÚpmÚkeyÚloadedr$   s	   &$       r   Ú_disabled_web_plugin_forrw   �   sÚ   € õ 3÷ ˜*Ð(=Ô=Ü(¨Ó4ˆ
ßÙá�Ó€DðCÝ9áÓ!ˆØŸ;™;×,Ñ,Ö.‰KˆCä˜3¤×$Ô$¨¯©¸×)?Ô)?ÈÏÏÊØ—L‘LÐ$9Ö9¹eÀCÇIÁIÈcÐSTÓDUÐVWÕDXÓ>YÐ]aÖ>aà’
ñ /ñ øô ô CÜ�‰Ð<¸c×BÐBÙûðCús;   ´?C& Á8C& ÂC& Â%C& Â8!C& ÃC& Ã"C& Ã&DÃ1DÄDc               ó   € V ^8„  d   QhRR/# ©r   r   r>   r   )r   s   "r   r   r   Å   s   € ÷ Hñ HÐ$?ñ Hr   c                 ó.   € \        \        R4      RR7      # )z1Resolve the currently-active web search provider.r-   ©r'   ©rY   r2   r   r   r   Úget_active_search_providerr}   Å   s   € äÔ'¨Ó1¸hÔGÐGr   c               ó   € V ^8„  d   QhRR/# ry   r   )r   s   "r   r   r   Ê   s   € ÷ Jñ JÐ%@ñ Jr   c                 ó.   € \        \        R4      RR7      # )z2Resolve the currently-active web extract provider.rF   r{   r|   r   r   r   Úget_active_extract_providerr€   Ê   s   € äÔ'¨	Ó2¸yÔIÐIr   )r/   ÚparallelÚtavilyr.   ÚexaÚsearxngz
brave-freeÚddgs)rƒ   r�   r/   Úkeenable)N)Ú__conditional_annotations__Ú__doc__Ú
__future__r   ÚloggingÚtypingr   Úagent.provider_registryr   r   Úagent.web_search_providerr   Ú	getLoggerÚ__name__r
   r   Ú__annotations__ÚexportÚglobalsr%   r2   rQ   r:   r<   rY   rR   rw   r}   r€   )r‡   s   @r   Ú<module>r“      s¦   øðôõ$ #ã Ý ç GÝ 7à	×	Ò	˜8Ó	$€ñ 2BØ
Ð/¸ô2€	Ð.ó ð 
× Ñ ‘“Ô õõ"ð oÐ ð CÐ õõ8õv	ñ%Ð^b÷ %ð %õPH÷
Jr   