+
    lHàj]  ã                   óž   € R t ^ RIt]P                  ! R4      tRRRRRRR	R
/tR R ltR R ltR R ltR R ltR R lt	R R lt
R R ltR# )a�  One-shot keyless-ring rescue for failed keyed/configured web calls.

Stateless by design: a rescue routes THIS call through the free-tier ring (plugins/web/keyless_mcp.py);
the next web_search/web_extract call attempts the chosen backend again. Callers must never cache a
rescue-served response, or the one-shot rescue becomes sticky for a whole TTL. Logs under the origin
(tools.web_tools) logger.
Nztools.web_toolsÚexaÚEXA_API_KEYÚparallelÚPARALLEL_API_KEYÚ	firecrawlÚFIRECRAWL_API_KEYÚkeenableÚKEENABLE_API_KEYc                ó$   € V ^8„  d   QhR\         /# ©é   Úreturn©Úbool)Úformats   "Ú;/home/ubuntu/.hermes/hermes-agent/tools/web_tools_rescue.pyÚ__annotate__r      s   € ÷ 
ñ 
¤ñ 
ó    c                 óÆ   € ^ RI Hp  V ! 4       P                  RR4      '       g   R#  ^ RIHp V! 4       #   \
         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)zV``web.keyless_rescue`` (default on), implicitly off when the keyless tier is disabled.)Ú_load_web_configÚkeyless_rescueTF)Ú_keyless_tier_enabledz$keyless rescue tier check failed: %sN)Útools.web_toolsr   ÚgetÚagent.web_search_registryr   Ú	ExceptionÚloggerÚdebug)r   r   Úexcs      r   Ú_keyless_rescue_enabledr      sR   € å0ÙÓ×!Ñ!Ð"2°D×9Ò9ÙðÝCÙ$Ó&Ð&øÜô Ü�‰Ð;¸SÔAÝûðús   §4 ´A ¿AÁA c                ó0   € V ^8„  d   QhR\         R\        /# )r   Únamer   )Ústrr   )r   s   "r   r   r   !   s   € ÷ Kñ Kœsð K¤tñ Kr   c                ó¦   € V R8X  d   ^ RI Hp V! 4       # ^ RIHp ^ RIHp \        P                  V R4      pT! Y'       d   V! V4      4      # R4      # )uÊ  Did *name*'s own provider route this call through the anonymous keyless ring?

Mirrors the predicate each ring provider evaluates before calling, so eligibility reflects what
actually happened. Firecrawl owns extra routes that bypass the ring without a key â€” the managed
Nous Tool Gateway (persisted ``nous`` selection, or the legacy never-configured fallback when the
gateway is ready) and a self-hosted ``FIRECRAWL_API_URL`` â€” so it is asked directly.
r   )Ú_use_keyless_ring©Úget_provider_env)Úuse_keylessÚ )Úplugins.web.firecrawl.providerr$   Úagent.web_search_providerr&   Úplugins.web.keyless_mcpr'   Ú_RING_KEY_VARSr   )r!   r$   r&   r'   Úkey_vars   &    r   Ú_ring_vendor_keylessr.   !   sM   € ð ˆ{ÔÝDÙ Ó"Ð"Ý:Ý3Ü× Ñ   rÓ*€GÙ�t¾'Ñ-¨gÓ6ÓJÐJÀrÓJÐJr   c                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   Úoriginal_errorÚqueryÚlimit)r"   Úint)r   s   "r   r   r   2   s!   € ÷ ñ ´sð Ä3ð Ìsñ r   c           	     ó   € ^ RI Hp ^ RIHp \	        V RR4      R8w  g;   V! R4      '       g-   VP                  4       '       d   VP                  4       '       g   R# \        P                  RT;'       g    RR	,          4        ^ R
I	H
p V! R4      P                  W#4      pVP                  R4      '       g9   \        P                  R\        VP                  RR4      4      R	,          4       R# VP                  R/ 4      P!                  RRT;'       g    RR,           R2R7       V#   \         d   pRRR\        T4      /p Rp?L¨Rp?ii ; i)z±Try managed Firecrawl for this call only; None leaves the original error for keyless rescue.
Managed Firecrawl is billed, so a caller on free fast search alone never reaches it.r%   )Ú	web_toolsr!   r(   Ú
perplexityÚPERPLEXITY_API_KEYNzSweb_search managed Perplexity failed (%s); serving this call from managed FirecrawlºNéÈ   N)Úget_providerr   ÚsuccessFÚerrorz)managed Firecrawl fallback failed too: %sÚdataÚmanaged_primaryz)Primary managed search failed this call (úunknown errorºNi,  NzS); result served by the managed fallback. The next call will use the primary again.)Úfallback_fromÚbackend_error)r*   r&   Útoolsr5   ÚgetattrÚ_managed_web_searchÚ_is_tool_gateway_readyr   Úwarningr   r:   Úsearchr   r"   r   Ú
setdefaultÚupdate)	Úproviderr0   r1   r2   r&   Ú_wtr:   Úrespr   s	   &&&&     r   Ú_managed_search_fallbackrN   2   s9  € õ ;Ý&Ü�˜& "Ó%¨Ô5ÙÐ 4×5Ò5¸S×=TÑ=T×=VÒ=VÐ^a×^xÑ^x×^zÒ^zÙÜ
‡N�NÐhÐky×kÐkÐ}ð  BFõ  kGô  Hð5Ý:Ù˜KÓ(×/Ñ/°Ó=ˆð �8‰8�I×ÒÜ�‰ÐBÄCÈÏÉÐQXÐZ\ÓH]ÓD^Ð_cÕDdÔeÙØ‡O�O�F˜BÓ×&Ñ&Ø'ØAÀ>×CdÐCdÐUdÐfjÕBkÐAlð mið ið 'ô ð
 €Køô ô 5Ø˜5 '¬3¨s«8Ð4�ûð5ús   ÂD) Ä)EÄ4EÅEc                ó$   € V ^8„  d   QhR\         /# r   r   )r   s   "r   r   r   K   s   € ÷ ñ ¤$ñ r   c                óì   € \        4       '       d   V f   R#  ^ RIHp \        V RR4      pW!9  ;'       g    \	        V4      '       * #   \
         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)uc  True when a failed call on *provider* should get a one-shot rescue.

Eligible: any call that did NOT go through the keyless ring â€” a non-ring backend, a ring vendor
in keyed mode, or a ring vendor routed through the managed gateway / a self-hosted instance. A
ring vendor that walked the ring is NOT eligible: its failure means the ring already failed.
NF)Ú_KEYLESS_RINGr!   r(   z#rescue eligibility check failed: %s)r   r+   rQ   rD   r.   r   r   r   )rK   rQ   r!   r   s   &   r   Ú_rescue_eligiblerR   K   sg   € ô #×$Ò$¨Ò(8ÙðÝ9Ü�x ¨Ó,ˆØÑ(×JÐJÔ0DÀTÓ0JÔ,JÐJøÜô Ü�‰Ð:¸CÔ@Ýûðús   ˜A ¶A ÁA3ÁA.Á.A3c          
      óT   € V ^8„  d   QhR\         R\         R\         R\        R\        /# )r   Úprovider_namer0   r1   r2   r   )r"   r3   Údict)r   s   "r   r   r   ]   s0   € ÷ ñ ¤#ð ´sð Ä3ð Ìsð ÔW[ñ r   c           
     óh  € ^ RI Hp \        P                  RY;'       g    RR,          4       V! WV4      pVP	                  R4      '       dA   VP                  R/ 4      P                  T RT  RT;'       g    R	R
,           RV  R2R7       V# RRRT;'       g    R RVP	                  RR4       R2/# )zSRescue a failed search via the ring; annotate the result with the original failure.)Úsearch_with_failoverz<web_search backend '%s' failed (%s); one-shot keyless rescuer(   r8   r;   r=   zConfigured backend 'z' failed this call (r?   r@   zC); result served by the keyless free tier. The next call will use 'z' again.)Úrescued_fromrB   Fr<   zsearch failedz (keyless rescue also failed: ÚunknownÚ))r+   rW   r   rG   r   rI   rJ   )rT   r0   r1   r2   rW   Úrescueds   &&&&  r   Ú_rescue_searchr\   ]   sÜ   € å<Ü
‡N�NØFØ×,Ð,¨"¨dÕ3ôñ # =¸Ó?€GØ‡{�{�9×ÒØ×Ñ˜6 2Ó&×-Ñ-Ø&à& } oð 6Ø#×6Ð6 ¸Õ=Ð>ð ?+Ø+8¨/¸ðCð 	.ô 	
ð ˆð 	�5ØØ×0Ð0 Ð1ð 2,Ø,3¯K©K¸ÀÓ,KÐ+LÈAðOðð r   c                ó0   € V ^8„  d   QhR\         R\        /# )r   Úresultr   )rU   r   )r   s   "r   r   r   y   s   € ÷ Yñ Y¤4ð Y¬Dñ Yr   c                ó´   € \        V P                  R4      ;'       g    R4      P                  4       p\        V P                  R4      4      ;'       g    RV9   # )ub   True for a website-policy refusal â€” intentional, never rescued (it would fetch blocked content).r<   r(   Úblocked_by_policyzblocked by website policy)r"   r   Úlowerr   )r^   r<   s   & r   Ú_policy_blocked_resultrb   y   sJ   € ä�—
‘
˜7Ó#×)Ð) rÓ*×0Ñ0Ó2€EÜ�—
‘
Ð.Ó/Ó0×XÐXÐ4OÐSXÑ4XÐXr   c                óH   € V ^8„  d   QhR\         R\        R\        R\        /# )r   rT   ÚurlsÚresultsr   )r"   Úlist)r   s   "r   r   r      s(   € ÷  ñ  ¤3ð  ¬dð  ¼Tð  Ädñ  r   c                ó  a€ ^ RI Hp \        S4      \        V4      8H  p\        S4       UUu. uF"  w  rVV'       d   \	        V4      '       d   K   VNK$  	  pppV'       g   S# V'       d   V Uu. uF  qQV,          NK  	  upM
\        V4      pV3R lV 4       p	\        V	R4      p
\        P                  RT \        V4      T
;'       g    RR,          4       V! V \        V4      4      pV'       d=   \        ;QJ d    R V 4       F  '       d   K   RM	  R	M! R V 4       4      '       d   S# V F`  pVP                  R
4      '       d   RMVP                  R/ 4      p\        V\        4      '       g   KF  WR&   T
;'       g    RR,          VR&   Kb  	  V'       d\   \        V4      \        V4      8X  dC   \        \        W{4      4      p\        S4       UUu. uF  w  rVVP                  WV4      NK  	  upp# V# u uppi u upi u uppi )a  Rescue a whole-batch extract failure via the ring.

Only genuine failures are re-fetched; policy-blocked entries are preserved verbatim. If the provider
broke url/result order parity, every entry is treated as rescueable and the ring's list replaces the
batch wholesale.
)Úextract_with_failoverc              3   ó”   <"  € T F=  pSV,          P                  R 4      '       g   K#  SV,          P                  R 4      x € K?  	  R# 5i)r<   N©r   )Ú.0Úire   s   & €r   Ú	<genexpr>Ú"_rescue_extract.<locals>.<genexpr>Ž   s3   øé € ÐU©z¨!¸WÀQ½Z¿^¹^ÈG×=TÔ%ˆg�a�j�n‰n˜W×%Ð%«zùs
   ƒ A¨ Azextract failedzKweb_extract backend '%s' failed all %d URL(s) (%s); one-shot keyless rescuer(   r8   c              3   óD   "  € T F  qP                  R R4      x € K  	  R# 5i)r<   r(   Nrj   )rk   Úrs   & r   rm   rn   •   s   é € Ð;±7¨a—u‘u˜W b×)Ð)³7ùs   ‚ FTr<   NÚmetadatarX   r@   rB   )r+   rh   ÚlenÚ	enumeraterb   rf   Únextr   rG   Úallr   rI   Ú
isinstancerU   Úzip)rT   rd   re   rh   Úparityrl   rp   Ú
rescue_idxÚrescue_urlsÚerrorsr0   r[   ÚmetaÚreplacementss   &&f           r   Ú_rescue_extractr~      sœ  ø€ õ >ä�‹\œS ›YÑ&€FÜ )¨'Ô 2ÔbÑ 2™˜¿&ÔH^Ð_`×Ha—!�!Ñ 2€JÑbßØˆç39¡JÓ/¡J˜q˜—7�7¡JÒ/¼tÀD»z€KÜU©zÓU€FÜ˜&Ð"2Ó3€NÜ
‡N�NØUØ”s˜;Ó'¨.×*>Ð*>¸BÀÕ)Eôñ $ M´4¸Ó3DÓE€Gß—3“3Ñ;±7Ó;—3—3’3Ñ;±7Ó;×;Ò;ØˆÛˆØ—u‘u˜W—~’~‰t¨1¯<©<¸
ÀBÓ+GˆÜ�dœD×!Ô!Ø#0�Ñ Ø%3×%9Ð%9°r¸4Õ$@ˆD�Ó!ñ	 ÷
 ”#�g“,¤# j£/Ô1ÜœC 
Ó4Ó5ˆÜ3<¸WÔ3EÔFÑ3E©4¨1�× Ñ  Ö&Ñ3EÒFÐFØ€Nùó- cùò 0ùó" Gs   ­G8ÁG8Á.G>ÇH)Ú__doc__ÚloggingÚ	getLoggerr   r,   r   r.   rN   rR   r\   rb   r~   © r   r   Ú<module>rƒ      sc   ðñó à	×	Ò	Ð,Ó	-€ð 
ˆ=˜*Ð&8ØÐ$ jÐ2Dð€õ
õKõ"õ2õ$õ8Y÷ r   