Ë
    âß²jBE  ã                  óâ  — U d Z ddlmZ ddl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 ddlmZ ddlmZ ddlmZ dd	lmZ  ej8                  e«      Zd
Zda de!d<   d.d„Z" G d„ d«      Z# e#«       Z$d„ Z%d/d„Z&d0d„Z'd1d„Z(d1d„Z) G d„ d«      Z*d2d„Z+d1d„Z,d1d„Z-d2d„Z.d3d„Z/d4d„Z0d5d„Z1d6d„Z2d7d„Z3d d!dd"œd8d#„Z4d$Z5d%Z6d9d&„Z7 G d'„ d(e«      Z8dd)lm9Z9 dd*lm:Z: ddl;Z;d+d,iZ<d-„ Z=y):a  Firecrawl web search + extract provider (direct SDK, keyless cloud, or Nous tool-gateway).

Config: ``web.backend`` / ``web.search_backend`` / ``web.extract_backend: firecrawl``.
Env: FIRECRAWL_API_KEY, FIRECRAWL_API_URL (self-hosted), FIRECRAWL_GATEWAY_URL / TOOL_GATEWAY_*.
é    )ÚannotationsN)ÚAnyÚDictÚListÚOptional)ÚBaseWebSearchProviderÚkeyless_extractÚkeyless_searchÚlazy_ensureÚsearch_failÚ	search_okÚsetup_schema)Úmanaged_tool_gateway)Útool_backend_helpers)Úis_safe_url)Úcheck_website_accesszhttps://api.firecrawl.devzOptional[type]Ú_FIRECRAWL_CLS_CACHEc                 ó@   — t         €t        d«       ddlm}  | a t         S )uR   Import and cache ``firecrawl.Firecrawl`` (lazy_deps install hint â†’ ImportError).zsearch.firecrawlr   )Ú	Firecrawl)r   r   Ú	firecrawlr   )Ú_clss    úC/home/ubuntu/.hermes/hermes-agent/plugins/web/firecrawl/provider.pyÚ_load_firecrawl_clsr      s"   € ô Ð#ÜÐ&Ô'Ý/Ø#ÐÜÐó    c                  ó,   — e Zd ZdZdZdd„Zdd„Zd	d„Zy)
Ú_FirecrawlProxyzJCallable proxy that looks like ``firecrawl.Firecrawl`` but imports lazily.© c                ó"   —  t        «       |i |¤ŽS ©N)r   )ÚselfÚargsÚkwargss      r   Ú__call__z_FirecrawlProxy.__call__-   s   € Ø$Ô"Ó$ dÐ5¨fÑ5Ð5r   c                ó*   — t        |t        «       «      S r   )Ú
isinstancer   )r    Úobjs     r   Ú__instancecheck__z!_FirecrawlProxy.__instancecheck__0   s   € Ü˜#Ô2Ó4Ó5Ð5r   c                 ó   — y)Nz <lazy firecrawl.Firecrawl proxy>r   ©r    s    r   Ú__repr__z_FirecrawlProxy.__repr__3   s   € Ø1r   N)r!   r   r"   r   Úreturnr   )r&   r   r+   Úbool©r+   Ústr)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú	__slots__r#   r'   r*   r   r   r   r   r   (   s   „ ÙTà€Ió6ó6ô2r   r   c                 ó   — ddl m}  | S )zbClient cache slots live on tools.web_tools so tests that reset ``_firecrawl_client`` there see it.r   N)Útools.web_toolsÚ	web_tools)Ú_mods    r   Ú_wtr8   :   s
   € å"Ø€Kr   c                óB   — ddl m}  || «      xs dj                  «       S )Nr   )Úget_env_valueÚ )Úhermes_cli.configr:   Ústrip)Únamer:   s     r   Ú_envr?   @   s   € Ý/Ù˜$ÓÒ% 2×,Ñ,Ó.Ð.r   c                 óô   — t        d«      } t        d«      j                  d«      }| s|r-dd| fd|ffD ��ci c]  \  }}|sŒ	||“Œ c}}d|xs d| xs dffS t        «       rd	dt        id
t        dffS yc c}}w )u  Direct Firecrawl ``(mode, kwargs, cache_key)`` or None. ``mode`` is ``"sdk"`` (keyed / self-hosted) or
    ``"keyless"`` (explicit selection + no credentials â†’ anonymous public cloud; the explicit selection is
    required so an unconfigured install never silently routes to it).ÚFIRECRAWL_API_KEYÚFIRECRAWL_API_URLú/ÚsdkÚapi_keyÚapi_urlÚdirectNÚkeylesszdirect-keyless)r?   ÚrstripÚ _is_explicit_firecrawl_selectionÚ_FIRECRAWL_CLOUD_API_URL)rE   rF   ÚkÚvs       r   Ú_get_direct_firecrawl_configrN   E   s°   € ô Ð&Ó'€GÜÐ&Ó'×.Ñ.¨sÓ3€GÙ‘'Ø¨)°WÐ)=À	È7Ð?SÐ(T×Z¡  1ÒXY�q˜!‘tÓZÐ]eÐgnÒgvÐrvÐxò  yHð  DHð  ]Ið  Ið  	IÜ'Ô)Ø˜9Ô&>Ð?ÐBRÔTlÐnrÐAsÐsÐsØùó [s   ¶
A4ÁA4c                 ó   — ddl m}   | d«      S )Nr   ©Ú_web_config_selectsr   )Úplugins.web.keyless_mcprQ   rP   s    r   rJ   rJ   R   s   € Ý;Ù˜{Ó+Ð+r   c                 ó°   ‡‡— t        d«      st        d«      ryddlmŠmŠ ddlm}  ˆˆfd„d„ fD ]  }	  |«       r yŒ  | d	d
«      S # t        $ r Y Œ#w xY w)zªRoute via the keyless ring only with no direct credentials, when the managed Nous
    gateway isn't the selected path, and the keyless tier isn't disabled or pinned paid.rA   rB   Fr   ©ÚNOUS_MANAGED_PROVIDERÚread_selection)Úuse_keylessc                 ó   •—  ‰d«      ‰ k(  S )NÚwebr   rT   s   €€r   ú<lambda>z#_use_keyless_ring.<locals>.<lambda>_   s   ø€ ™.¨Ó/Ð3HÑH€ r   c                 ó0   — t        «       xr t        «        S r   )Ú_is_tool_gateway_readyrJ   r   r   r   rZ   z#_use_keyless_ring.<locals>.<lambda>_   s&   € ÔRhÓRjò  SVô  tTó  tVð  pV€ r   r   r;   )r?   Útools.tool_backend_helpersrU   rV   rR   rW   Ú	Exception)rW   ÚproberU   rV   s     @@r   Ú_use_keyless_ringr`   W   sp   ù€ ô ÐÔ ¤DÐ)<Ô$=ØßPÝ3äHñ  KVð  Wò ˆð	ÙŒwÙð ðñ �{ BÓ'Ð'øô ò 	Ùð	ús   µA	Á		AÁAc                  ó6   — e Zd ZdZefd	d„Zd
d„Zddœd„Zd„ Zy)Ú_KeylessFirecrawlClientz‘Minimal REST client for Firecrawl's keyless cloud mode; duck-types the SDK's
    ``search`` / ``scrape`` and never sends an Authorization header.c                ó0   — |j                  d«      | _        y )NrC   )rI   rF   )r    rF   s     r   Ú__init__z _KeylessFirecrawlClient.__init__l   s   € Ø—~‘~ cÓ*ˆ�r   c                ó”   — t        j                  | j                  › |› �|ddid¬«      }|j                  «        |j	                  «       S )NzContent-Typezapplication/jsong      N@)ÚjsonÚheadersÚtimeout)ÚhttpxÚpostrF   Úraise_for_statusrf   )r    ÚpathÚpayloadÚresponses       r   Ú_postz_KeylessFirecrawlClient._posto   sE   € Ü—:‘: §¡ ¨t¨fÐ5¸GÈnÐ^pÐMqÐ{ô  AˆØ×!Ñ!Ô#Ø�}‰}‹Ðr   é   )Úlimitc               ó,   — | j                  d||dœ«      S )Nz
/v2/search©Úqueryrq   ©ro   )r    rt   rq   s      r   rZ   z _KeylessFirecrawlClient.<lambda>t   s   € ¨T¯Z©Z¸ÐPUÐ`eÑFfÓ-g€ r   c               ó,   — | j                  d||dœ«      S )Nz
/v2/scrape©ÚurlÚformatsru   )r    rx   ry   s      r   rZ   z _KeylessFirecrawlClient.<lambda>u   s   € ¨4¯:©:°lÈCÐ\cÑDdÓ+e€ r   N)rF   r.   )rl   r.   rm   úDict[str, Any]r+   rz   )	r/   r0   r1   r2   rK   rd   ro   ÚsearchÚscraper   r   r   rb   rb   h   s&   „ ñHð '?ô +óð
 +,Óg€FÙe�Fr   rb   c                 ó,   — t        j                  d«      S )Nr   )Ú_gatewayÚbuild_vendor_gateway_urlr   r   r   Ú_get_firecrawl_gateway_urlr€   x   s   € Ü×,Ñ,¨[Ó9Ð9r   c                 óP   — t        j                  dt         j                  ¬«      duS )z<True when gateway URL + Nous Subscriber token are available.r   ©Útoken_readerN)r~   Úresolve_managed_tool_gatewayÚpeek_nous_access_tokenr   r   r   r\   r\   |   s!   € ä×0Ñ0°Ì8×KjÑKjÔkÐswÐwÐwr   c                 ó|   — ddl m} m}  |d«      }|| k(  r
t        «       S t	        «       duxs |du xr
 t        «       S )zrTrue when the route selected via ``hermes tools`` (or, on a never-configured
    install, either route) is usable.r   rT   rY   N)r]   rU   rV   r\   rN   )rU   rV   Úselecteds      r   Úcheck_firecrawl_api_keyrˆ   �   sE   € ÷ QÙ˜eÓ$€HØÐ(Ò(Ü%Ó'Ð'Ü'Ó)°Ð5Òh¸(ÀdÐ:JÒ:gÔOeÓOgÐhr   c                 ó2   — t        j                  «       rdS dS )Nzc, or use the Nous Tool Gateway via your subscription (FIRECRAWL_GATEWAY_URL or TOOL_GATEWAY_DOMAIN)r;   )Ú_backend_helpersÚmanaged_nous_tools_enabledr   r   r   Ú_firecrawl_backend_help_suffixrŒ   ‹   s4   € ô uE÷  u`ñ  u`ô  ubÐpð  jð  hjð  jr   c                 óæ  ‡‡‡— t        «       } ddlmŠm}mŠ  |d«      Št        «       }d„ }dd„}‰‰k(  r |«       dˆˆfd„}}}n'‰€
t        «       r|d	ˆˆfd
„}}}n|�|}n |«       d|}}}|€&t        j                  d«       t         «       «      ‚|\  }}	}
t        | dd«      }|�t        | dd«      |
k(  r|S |dk(  rt        |	d   ¬«      n
t        di |	¤Ž| _        |
| _        | j                  S )uo  Get or create the cached Firecrawl client. Strict selection semantics on the stored ``web`` selection:
    ``"nous"`` â†’ managed Tool Gateway ONLY; any other stored backend â†’ direct Firecrawl ONLY (never a silent
    managed fallback billed to Nous); never-configured â†’ direct when present, else managed. Raises ValueError
    when the resolved path is unusable.r   )rU   rV   Úselection_errorrY   c                 ó¸   — t        j                  dt         j                  ¬«      } | €y d| j                  | j                  dœd| j                  | j                  ffS )Nr   r‚   rD   )rE   rF   ztool-gateway)r~   r„   Úread_nous_access_tokenÚnous_user_tokenÚgateway_origin)Úgws    r   Ú_managedz'_get_firecrawl_client.<locals>._managed™   sh   € Ü×2Ñ2°;ÌX×MlÑMlÔmˆØˆ:ØØ "×"4Ñ"4À×ARÑARÑSÐVdÐfh×fwÑfwÐy{÷  zLñ  zLð  VMð  Mð  	Mr   c                 ón   — d} t        j                  «       r| dz   S | dz   t        j                  d«      z   S )Nz†Web tools are not configured. Set FIRECRAWL_API_KEY for cloud Firecrawl or set FIRECRAWL_API_URL for a self-hosted Firecrawl instance.z„ With your Nous subscription you can also use the Tool Gateway. run `hermes tools` and select Nous Subscription as the web provider.Ú zmanaged Firecrawl web tools)rŠ   r‹   Ú%nous_tool_gateway_unavailable_message)Úmessages    r   Ú_unconfigured_messagez4_get_firecrawl_client.<locals>._unconfigured_messageŸ   sG   € ð [ˆÜ×6Ñ6Ô8Øð  dñ  dð  dØ˜‰}Ô/×UÑUÐVsÓtÑtÐtr   zRthe Nous Subscription web selection is stored but the tool gateway is unavailable.c                 ó   •—  ‰d‰ d«      S )NrY   zDthe Nous Tool Gateway is not available (not entitled or unreachable)r   )rU   rŽ   s   €€r   rZ   z'_get_firecrawl_client.<locals>.<lambda>§   s   ø€ ñ  L[ØÐ(Ð*póLr€ r   NzMdirect Firecrawl selected but FIRECRAWL_API_KEY/FIRECRAWL_API_URL is not set.c                 ó    •—  ‰d‰ xs dd«      S )NrY   r   z6neither FIRECRAWL_API_KEY nor FIRECRAWL_API_URL is setr   )r‡   rŽ   s   €€r   rZ   z'_get_firecrawl_client.<locals>.<lambda>®   s    ø€ ñ  JYØ�8Ò*˜{Ð,dóJf€ r   z,missing direct config and tool-gateway auth.z*Firecrawl client initialization failed: %sÚ_firecrawl_clientÚ_firecrawl_client_configrH   rF   )rF   r-   r   )r8   r]   rU   rV   rŽ   rN   rJ   ÚloggerÚerrorÚ
ValueErrorÚgetattrrb   r   rœ   r�   )ÚwtrV   Údirect_configr”   r™   ÚresolvedÚlogr˜   Úclient_moder"   Úclient_configÚcachedrU   r‡   rŽ   s               @@@r   Ú_get_firecrawl_clientr©   �   s0  ú€ ô
 
‹€BßaÑaÙ˜eÓ$€HÜ0Ó2€MòMóuð Ð(Ò(Ù!)£ð  .Bô Dr�w�#‰à	Ð	Ô!AÔ!Cð
 "/Ð0ô Bf�w�#‰à	Ð	"Ø ‰á!)£Ð-[Ð]r�w�#ˆØÐÜ�‰ÐAÀ3ÔGÜ™›Ó#Ð#Ø)1Ñ&€K�˜Ü�RÐ,¨dÓ3€FØÐœg bÐ*DÀdÓKÈ}Ò\ØˆØQ\Ð`iÒQiÔ2¸6À)Ñ;LÕMÔoxñ  pCð  |Bñ  pC€BÔØ"/€BÔØ×ÑÐr   c           	     óÒ   — | �*t        | t        t        t        t        t
        t        f«      r| S dd„ fdd„ ffD ]  \  }}t        | |«      sŒ	  || «      c S  | S # t        $ r Y Œ,w xY w)uR   SDK objects (pydantic ``model_dump`` / ``__dict__``) â†’ plain data when possible.Ú
model_dumpc                ó"   — | j                  «       S r   )r«   )rM   s    r   rZ   z"_to_plain_object.<locals>.<lambda>Å   s   € °1·<±<³>€ r   Ú__dict__c                óŽ   — | j                   j                  «       D ��ci c]  \  }}|j                  d«      rŒ||“Œ c}}S c c}}w )NÚ_)r­   ÚitemsÚ
startswith)rM   rL   Úxs      r   rZ   z"_to_plain_object.<locals>.<lambda>Å   sa   € Ðmn×mwÑmw×m}Ñm}Óm÷  \ZÑeiÐefÐhið  HI÷  HTñ  HTð  UXõ  HYÐ\]Ð_`Ñ\`ó  \Z€ ùó  \Zs
   žA¸A)	r%   ÚdictÚlistr.   ÚintÚfloatr,   Úhasattrr^   )ÚvalueÚattrÚconverts      r   Ú_to_plain_objectr»   Á   s…   € à€}œ
 5¬4´´s¼CÄÌÐ*MÔNØˆØ'Ñ)AÐBÀZñ  RZð  E[ð  \ò ‰ˆˆgÜ�5˜$ÕðÙ˜u“~Ò%ðð €Løô ò Ùðús   ÁAÁ	A&Á%A&c                óŽ   — t        | t        «      r/t        t        | «      D �cg c]  }t        |t        «      sŒ|‘Œ c}S g S c c}w r   )r%   r´   Úmapr»   r³   )ÚvaluesÚps     r   Ú_normalize_result_listrÀ   Î   s8   € ÜPZÐ[aÔcgÔPh”sÔ+¨VÓ4ÖL�!¼
À1ÄdÕ8KŠAÒLÐpÐnpÐpùÒLs
   £A¹Ac                ó¶  — t        | «      }t        |t        «      r›|j                  d«      }t        |t        «      rt        |«      S t        |t        «      r"|j                  d«      |j                  d«      gng }||j                  d«      |j                  d«      gz   D ]  }t        |«      }|sŒ|c S  t        | d«      rt        t        | dg «      «      S g S )z9Search results across SDK/direct/gateway response shapes.ÚdatarY   Úresults)r»   r%   r³   Úgetr´   rÀ   r·   r¡   )rn   ÚplainrÂ   Ú
candidatesÚ	candidateÚ
normalizeds         r   Ú_extract_web_search_resultsrÉ   Ò   sÄ   € ä˜XÓ&€EÜ�%œÔØ�y‰y˜Ó ˆÜ�dœDÔ!Ü)¨$Ó/Ð/Ü?IÈ$ÔPTÔ?U�d—h‘h˜u“o t§x¡x°	Ó':Ñ;Ð[]ˆ
Ø# u§y¡y°Ó'7¸¿¹À9Ó9MÐ&NÑNò 	"ˆIÜ/°	Ó:ˆJÚØ!Ò!ð	"ô ˆx˜ÔÜ%¤g¨h¸¸rÓ&BÓCÐCØ€Ir   c                óˆ   — t        | «      }t        |t        «      si S t        |j                  d«      t        «      r|d   S |S )NrÂ   )r»   r%   r³   rÄ   )Úscrape_resultrÅ   s     r   Ú_extract_scrape_payloadrÌ   ã   s<   € Ü˜]Ó+€EÜ�eœTÔ"Øˆ	Ü& u§y¡y°Ó'8¼$Ô?ˆ5�‰=ÐJÀUÐJr   r;   F©ÚtitleÚrawÚblockedc               óh   — |rddD �ci c]  }|||   “Œ
 c}ini }| |ddœ|rddini ¥d|i¥|¥S c c}w )z™Per-URL extract failure. ``raw`` adds ``raw_content`` (post-scrape failures carry
    it, pre-scrape ones don't); ``blocked`` adds ``blocked_by_policy``.Úblocked_by_policy)ÚhostÚruleÚsourcer;   )rx   rÎ   ÚcontentÚraw_contentrŸ   r   )rx   rŸ   rÎ   rÏ   rÐ   rL   Úpolicys          r   Ú_error_entryrÙ   ê   s\   € ñ \cÐ!Ð;UÖ#V°a A w¨q¡z¡MÒ#VÑWÐhj€FØ °2ÑxÑQT¸=È"Ñ:MÐZ\ÐxÐ_fÐhmÑxÐqwÐxÐxùò $Ws   ˆ/uc   Scrape timed out after 60s â€” page may be too large or unresponsive. Try browser_navigate instead.z:Blocked: URL targets a private or internal network addressc              ƒ  óž  K  — t        | «      x}r.t        j                  d|d   |d   «       t        | |d   |¬«      S 	 t        j                  d| «       	 t	        j
                  t	        j                  t        «       j                  | |¬«      d¬	«      ƒ d
{  –—† }t        |«      }|j                  di «      }t        |t        «      s)t!        |d«      r|j#                  «       nt%        |di «      }|j                  dd«      |j                  d| «      }}t'        |«      s)t        j                  d|«       t        |t(        |d¬«      S t        |«      x}	r0t        j                  d|	d   |	d   «       t        ||	d   |d|	¬«      S |j                  d«      |j                  d«      }}
|dk(  s|€|
r|
n	|xs |
xs d}|||||dœS 7 �Œ/# t        j                  $ r) t        j                  d| «       t        | t        «      cY S w xY w# t*        $ r8}t        j-                  d| |«       t        | t/        |«      d¬«      cY d
}~S d
}~ww xY w­w)z¢Scrape one URL (60s timeout) and re-check SSRF + website policy against the
    post-redirect URL. Never raises for scrape errors; returns an error entry instead.z%Blocked web_extract for %s by rule %srÓ   rÔ   r˜   )rÐ   zFirecrawl scraping: %srw   é<   )rh   Nz!Firecrawl scrape timed out for %sÚmetadatar«   r­   rÎ   r;   Ú	sourceURLz7Blocked redirected web_extract for unsafe final URL: %sT)rÎ   rÏ   z0Blocked redirected web_extract for %s by rule %srÍ   ÚmarkdownÚhtml)rx   rÎ   rÖ   r×   rÜ   z"Firecrawl scrape failed for %s: %s)rÏ   )r   rž   ÚinforÙ   ÚasyncioÚwait_forÚ	to_threadr©   r|   ÚTimeoutErrorÚwarningÚ_SCRAPE_TIMEOUT_MSGrÌ   rÄ   r%   r³   r·   r«   r¡   r   Ú_UNSAFE_REDIRECT_MSGr^   Údebugr.   )rx   ry   ÚformatrÐ   rË   rm   rÜ   rÎ   Ú	final_urlÚfinal_blockedrÞ   rß   rÖ   Ú
scrape_errs                 r   Ú_scrape_onerí   õ   s4  è ø€ ô ' sÓ+Ð+€wÐ+Ü�‰Ð;¸WÀV¹_ÈgÐV\ÉoÔ^Ü˜C ¨Ñ!3¸WÔEÐEð<Ü�‰Ð,¨cÔ2ð	:Ü")×"2Ñ"2´7×3DÑ3DÔEZÓE\×EcÑEcÐilÐv}Ô3~ð  IKô  #L÷  LˆMô *¨-Ó8ˆØ—;‘;˜z¨2Ó.ˆä˜(¤DÔ)Ü07¸À,Ô0O�x×*Ñ*Ô,ÔU\Ð]eÐgqÐsuÓUvˆHØ#Ÿ<™<¨°Ó4°h·l±lÀ;ÐPSÓ6TˆyˆÜ˜9Ô%Ü�K‰KÐQÐS\Ô]Ü 	Ô+?ÀuÐRVÔWÐWÜ0°Ó;Ð;ˆ=Ð;Ü�K‰KÐJÈMÐZ`ÑLaÐcpÐqwÑcxÔyÜ 	¨=¸Ñ+CÈ5ÐVZÐdqÔrÐrØ Ÿ™ ZÓ0°'·+±+¸fÓ2E�$ˆØ$¨
Ò2°v°~É(‘(ÐY]ÒYoÐaiÒYoÐmoˆØ ¨5¸WÐU\ÐjrÑsÐsð% LúÜ×#Ñ#ò 	:Ü�N‰NÐ>ÀÔDÜ Ô%8Ó9Ò9ð	:ûô$ ò <Ü�‰Ð9¸3À
ÔKÜ˜C¤ Z£°dÔ;Õ;ûð<üsŠ   ‚<I¿H	 ÁAG
 ÂGÂG
 ÂB-H	 Å
IÅ<H	 ÆIÆ>H	 ÇIÇG
 Ç
9HÈH	 ÈIÈHÈH	 È		I
È-IÈ?I
É IÉI
É
Ic                  óB   — e Zd ZdZdZdZdZdZd
d„Zddd„Z	dd„Z
dd„Zy	)ÚFirecrawlWebSearchProviderz9Firecrawl search + extract provider with dual auth paths.r   r   Tc                ó   — t        «       S r   )rˆ   r)   s    r   Úis_availablez'FirecrawlWebSearchProvider.is_available  s   € Ü&Ó(Ð(r   c                ó°  — ddl m}  |«       rt        d«      S t        «       rt	        dd||t
        «      S t
        j                  d||«       t        «       }	 t        |j                  ||¬«      «      }t
        j                  dt        |«      «       t        |«      S # t        $ r.}t
        j                  d	|«       t        d
|› �«      cY d}~S d}~ww xY w)z¡Pre-flight errors (ValueError / ImportError) propagate so the dispatcher emits
        the legacy ``tool_error`` envelope; in-flight errors become failure dicts.r   ©Úis_interruptedÚInterruptedr   r   z!Firecrawl search: '%s' (limit=%d)rs   z"Firecrawl: found %d search resultszFirecrawl search error: %szFirecrawl search failed: N)Útools.interruptrô   r   r`   r
   rž   rà   r©   rÉ   r{   Úlenr   r^   rå   )r    rt   rq   rô   ÚclientÚweb_resultsÚexcs          r   r{   z!FirecrawlWebSearchProvider.search!  s»   € õ 	3ÙÔÜ˜}Ó-Ð-ÜÔÜ! +¨{¸EÀ5Ì&ÓQÐQÜ�‰Ð7¸ÀÔFÜ&Ó(ˆð	BÜ5°f·m±mÈ%ÐW\°mÓ6]Ó^ˆKÜ�K‰KÐ<¼cÀ+Ó>NÔOÜ˜[Ó)Ð)øÜò 	BÜ�N‰NÐ7¸Ô=ÜÐ!:¸3¸%Ð@ÓAÕAûð	Bús   ÁAB Â	CÂ'#CÃ
CÃCc              ‹  óf  K  — ddl m}  |«       r|D �cg c]  }|dddœ‘Œ
 c}S t        «       r)t        j                  t
        dd|t        «      ƒ d{  –—† S |j                  d	«      }|d
v r|gnddg}|D �cg c]$  } |«       r|dddœnt        |||«      ƒ d{  –—† ‘Œ& c}S c c}w 7 ŒU7 Œc c}w ­w)zƒPer-URL scrape; failures become items with an ``error`` field.
        ``format``: "markdown" | "html" | both (markdown preferred).r   ró   rõ   r;   )rx   rŸ   rÎ   r   r   Nré   )rÞ   rß   rÞ   rß   )	rö   rô   r`   rá   rã   r	   rž   rÄ   rí   )r    Úurlsr"   Ú_is_interruptedÚuré   ry   rx   s           r   Úextractz"FirecrawlWebSearchProvider.extract3  sÈ   è ø€ õ 	FÙÔØMQÖRÈ˜A¨ÀÓCÒRÐRÜÔÜ ×*Ñ*¬?¸KÈÐVZÔ\bÓc×cÐcØ—‘˜HÓ%ˆØ$Ð(<Ñ<�6‘(À:ÈvÐBVˆð ö
àñ BQÔAR�C -¸"Ò=Ô^iÐjmÐovÐx~Ó^×XÑò
ð 	
ùò Sàcøð Y@úò
ùs?   ‚B1”B#¡1B1ÁB(Á$B1Á7"B,ÂB*
ÂB,Â 	B1Â*B,Â,B1c                ó"   — t        dddddd«      S )Nr   u    keyless/paid Â· optional gatewayzYFull search + extract; supports keyless cloud, direct API, and Nous tool-gateway routing.rA   zBFirecrawl API key (optional; blank = keyless cloud or self-hosted)z'https://docs.firecrawl.dev/introduction)r   r)   s    r   Úget_setup_schemaz+FirecrawlWebSearchProvider.get_setup_schemaB  s%   € ÜØÐ;ØgØÐ!eð  hQó
ð 	
r   N©r+   r,   )rp   )rt   r.   rq   rµ   r+   rz   )rü   ú	List[str]r"   r   r+   úList[Dict[str, Any]])r+   rz   )r/   r0   r1   r2   ÚNAMEÚDISPLAY_NAMEÚEXTRACTÚKEYLESSrñ   r{   rÿ   r  r   r   r   rï   rï     s.   „ ÙCà€DØ€LØ€GØ€Gó)ôBó$
ô
r   rï   )ÚNoReturn)ÚTYPE_CHECKINGÚ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_onceé   )	Ú_PLUGIN_COMPAT_LAZYrÄ   ÚAttributeErrorr/   Ú	importlibÚhermes_cli.plugin_compatr  r¡   Úimport_module)r>   Útargetr  r  s       r   Ú__getattr__r  X  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+   Útype)r>   r.   r+   r.   )r+   zOptional[tuple]r  r-   )r+   r   )r¸   r   r+   r   )r¾   r   r+   r  )rn   r   r+   r  )rË   r   r+   rz   )rx   r.   rŸ   r.   rÎ   r.   rÏ   r,   rÐ   zOptional[Dict[str, Any]]r+   rz   )rx   r.   ry   r  ré   zOptional[str]r+   rz   )>r2   Ú
__future__r   rá   ÚloggingÚtypingr   r   r   r   ri   Úplugins.web._commonr   r	   r
   r   r   r   r   Útoolsr   r~   r   rŠ   Útools.url_safetyr   Útools.website_policyr   Ú	getLoggerr/   rž   rK   r   Ú__annotations__r   r   r   r8   r?   rN   rJ   r`   rb   r€   r\   rˆ   rŒ   r©   r»   rÀ   rÉ   rÌ   rÙ   ræ   rç   rí   rï   r	  r
  Úosr  r  r   r   r   ú<module>r!     s&  ðòõ #ã Û ß ,Ó ,ã ÷ J÷  Jñ  JÝ 2Ý :Ý (å 5à	ˆ×	Ñ	˜8Ó	$€à6Ð ð (,Ð �nÓ +ó ÷2ñ 2ñ Ó€	òó/ó

ó,ó
(÷"fñ fó :óxó
iójó. ód
óqóó"Kð 8:ÀuÐrvõ yð |Ð ØSÐ ó<ôB1
Ð!6ô 1
õp Ý  Û 	ð ÐKðÐ ó
Br   