§
    ‰eîiàS ã                   ó  — d Z ddlZddlZddl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 ddlmZmZmZ ddlmZ ddlmZmZmZ ddlmZmZ dd	lmZ dd
lmZ  ej         e!¦  «        Z"de#de$fd„Z%de&fd„Z'de#fd„Z(de#de$fd„Z)da*da+de
e,ee#e#f         e,e#e
e#         e
e#         f         f                  fd„Z-de#fd„Z.de$fd„Z/de$fd„Z0dµd„Z1de#fd„Z2de3e#         fd„Z4d„ Z5da6da7d„ Z8d„ Z9 ej:        dd¦  «        Z;de#de&de&fd „Z<d!e&de&fd"„Z=d¶d!e&d$e#deee#e	f                  fd%„Z>d&e	de	fd'„Z?d(e	deee#e	f                  fd)„Z@d!e	deee#e	f                  fd*„ZAd+e	dee#e	f         fd,„ZBd-ZCd.e	de$fd/„ZDd·d0e
e#         de,e
e	         e
e#         ee#e	f         f         fd1„ZEde
e#         fd2„ZF ed3d4¬5¦  «        ZGd#d#deCfd6e#d7e#d8e#d0e
e#         d9eHde
e#         fd:„ZI	 	 	 d¸d6e#d=e#d0e
e#         d>eHd?e$d@e#de
e#         fdA„ZJd6e#d=e#d0e
e#         dBeHdCeHde
e#         fdD„ZKdEe#de#fdF„ZLdaMdG„ ZNd¹dIe#dJeHde&fdK„ZOdLee#         deee#e	f                  fdM„ZPdºdIe#dJeHde&fdO„ZQdLee#         deee#e	f                  fdP„ZRdºdIe#dJeHde#fdQ„ZSddRdeCfdLee#         dSe#dTe$d0e
e#         d9eHde#fdU„ZTddVdRdeCfd7e#dWe#dXe#dTe$d0e
e#         d9eHde#fdY„ZUde$fdZ„ZVde$fd[„ZWde$fd\„ZXe!d]k    �r¸	  eYd^¦  «          eYd_¦  «          eW¦   «         ZZ e/¦   «         Z[ e$ ej:        d`d#¦  «         \                    ¦   «         ¦  «        Z] e$ ej:        dad#¦  «         \                    ¦   «         ¦  «        Z^ eX¦   «         Z_ eF¦   «         Z`eZrÅ e(¦   «         Za eYdbea› �¦  «         eadck    r eYdd¦  «         n¼eadek    r eYdf¦  «         nªeadgk    r eYdh¦  «         n˜e^rB eYdi ej:        da¦  «         \                    ¦   «          b                    dj¦  «        › �¦  «         nTe]r eYdk¦  «         nFe[r eYdl e.¦   «         › �¦  «         n- eYdm¦  «         n! eYdn¦  «          eYdo e2¦   «         › �¦  «         e_s" eYdp¦  «          eYdq¦  «          eYdr¦  «         n eYdse`› �¦  «         eZs ecdt¦  «          eYdu¦  «         e_r eYdve`› �¦  «          eYdweC› dx�¦  «         eGjd        r0 eYdyeGje        › �¦  «          eYdzeGjf        › d{eGje        › d|�¦  «         n eYd}¦  «          eYd~¦  «          eYd¦  «          eYd€¦  «          eYd#¦  «          eYd�¦  «          eYd‚¦  «          eYd#¦  «          eYdƒ¦  «          eYd„¦  «          eYd…¦  «          eYd†¦  «          eYd‡¦  «         e_rš eYdˆ¦  «          eYd‰¦  «          eYdŠ¦  «          eYd#¦  «          eYd‹¦  «          eYdŒ¦  «          eYd�¦  «          eYdŽ¦  «          eYd�¦  «          eYd�¦  «          eYd‘¦  «          eYd#¦  «          eYd’¦  «          eYd“¦  «          eYd”¦  «          eYd•¦  «          eYd–¦  «          eYd—¦  «          eYd˜¦  «          eYd™¦  «          eYdš¦  «          eYd›¦  «          eYdœ¦  «          eYd�¦  «         ddžlgmhZhmiZi dŸd d¡dId¢d£d¤œidIgd¥œd¦œZjd§d¨d¡dLd©dªd¢id«dNd¬œidLgd¥œd¦œZk ehjl        dŸd­ejd®„ eW e4¦   «         d¯d°¬±¦  «          ehjl        d§d­ekd²„ eW e4¦   «         dRd³d°¬´¦	  «	         dS )»a%  
Standalone Web Tools Module

This module provides generic web tools that work with multiple backend providers.
Backend is selected during ``hermes tools`` setup (web.backend in config.yaml).
When available, Hermes can route Firecrawl calls through a Nous-hosted tool-gateway
for Nous Subscribers only.

Available tools:
- web_search_tool: Search the web for information
- web_extract_tool: Extract content from specific web pages
- web_crawl_tool: Crawl websites with specific instructions

Backend compatibility:
- Exa: https://exa.ai (search, extract)
- Firecrawl: https://docs.firecrawl.dev/introduction (search, extract, crawl; direct or derived firecrawl-gateway.<domain> for Nous Subscribers)
- Parallel: https://docs.parallel.ai (search, extract)
- Tavily: https://tavily.com (search, extract, crawl)

LLM Processing:
- Uses OpenRouter API with Gemini 3 Flash Preview for intelligent content extraction
- Extracts key excerpts and creates markdown summaries to reduce token usage

Debug Mode:
- Set WEB_TOOLS_DEBUG=true to enable detailed logging
- Creates web_tools_debug_UUID.json in ./logs directory
- Captures all tool calls, results, and compression metrics

Usage:
    from web_tools import web_search_tool, web_extract_tool, web_crawl_tool
    
    # Search the web
    results = web_search_tool("Python machine learning libraries", limit=3)
    
    # Extract content from URLs  
    content = web_extract_tool(["https://example.com"], format="markdown")
    
    # Crawl a website
    crawl_data = web_crawl_tool("example.com", "Find contact information")
é    N)ÚListÚDictÚAnyÚOptional)Ú	Firecrawl)Úasync_call_llmÚextract_content_or_reasoningÚget_async_text_auxiliary_client)ÚDebugSession)Úbuild_vendor_gateway_urlÚread_nous_access_tokenÚresolve_managed_tool_gateway)Úmanaged_nous_tools_enabledÚprefers_gateway)Úis_safe_url)Úcheck_website_accessÚnameÚreturnc                 óp   — t          j        | ¦  «        }t          |o|                     ¦   «         ¦  «        S ©N)ÚosÚgetenvÚboolÚstrip)r   Úvals     ú1/home/div/.hermes/hermes-agent/tools/web_tools.pyÚ_has_envr   G   s*   € Ý
Œ)�D‰/Œ/€CÝ�Ð#˜Ÿ	š	™œÑ$Ô$Ð$ó    c                  ó~   — 	 ddl m}   | ¦   «                              di ¦  «        S # t          t          f$ r i cY S w xY w)z5Load the ``web:`` section from ~/.hermes/config.yaml.r   ©Úload_configÚweb)Úhermes_cli.configr!   ÚgetÚImportErrorÚ	Exceptionr    s    r   Ú_load_web_configr'   K   s^   € ðØ1Ð1Ð1Ð1Ð1Ð1Øˆ{‰}Œ}× Ò  ¨Ñ+Ô+Ð+øÝ�Ð#ð ð ð Øˆ	ˆ	ˆ	ðøøøs   ‚#& ¦<»<c                  óz  — t          ¦   «                              d¦  «        pd                     ¦   «                              ¦   «         } | dv r| S dt	          d¦  «        pt	          d¦  «        pt          ¦   «         fdt	          d¦  «        fd	t	          d
¦  «        fdt	          d¦  «        ff}|D ]\  }}|r|c S ŒdS )zàDetermine which web backend to use.

    Reads ``web.backend`` from config.yaml (set by ``hermes tools``).
    Falls back to whichever API key is present for users who configured
    keys manually without running setup.
    ÚbackendÚ )ÚparallelÚ	firecrawlÚtavilyÚexar,   ÚFIRECRAWL_API_KEYÚFIRECRAWL_API_URLr+   ÚPARALLEL_API_KEYr-   ÚTAVILY_API_KEYr.   ÚEXA_API_KEY)r'   r$   Úlowerr   r   Ú_is_tool_gateway_ready)Ú
configuredÚbackend_candidatesr)   Ú	availables       r   Ú_get_backendr9   S   sæ   € õ #Ñ$Ô$×(Ò(¨Ñ3Ô3Ð9°r×@Ò@ÑBÔB×HÒHÑJÔJ€JØÐ?Ð?Ð?ØÐð 
•hÐ2Ñ3Ô3ÐpµxÐ@SÑ7TÔ7TÐpÕXnÑXpÔXpÐqØ	•XÐ0Ñ1Ô1Ð2Ø	•8Ð,Ñ-Ô-Ð.Ø	•˜Ñ'Ô'Ð(ð	Ðð 1ð ð Ñˆ�Øð 	ØˆNˆNˆNð	ð ˆ;r   r)   c                 ó¬   — | dk    rt          d¦  «        S | dk    rt          d¦  «        S | dk    rt          ¦   «         S | dk    rt          d¦  «        S dS )	z:Return True when the selected backend is currently usable.r.   r3   r+   r1   r,   r-   r2   F)r   Úcheck_firecrawl_api_key)r)   s    r   Ú_is_backend_availabler<   n   sk   € à�%ÒÐÝ˜Ñ&Ô&Ð&Ø�*ÒÐÝÐ*Ñ+Ô+Ð+Ø�+ÒÐÝ&Ñ(Ô(Ð(Ø�(ÒÐÝÐ(Ñ)Ô)Ð)Øˆ5r   c                  ó  — t          j        dd¦  «                             ¦   «         } t          j        dd¦  «                             ¦   «                              d¦  «        }| s|sdS i }| r| |d<   |r||d<   |d|pd| pdffS )	zHReturn explicit direct Firecrawl kwargs + cache key, or None when unset.r/   r*   r0   ú/NÚapi_keyÚapi_urlÚdirect)r   r   r   Úrstrip)r?   r@   Úkwargss      r   Ú_get_direct_firecrawl_configrD   €   s£   € åŒiÐ+¨RÑ0Ô0×6Ò6Ñ8Ô8€GÝŒiÐ+¨RÑ0Ô0×6Ò6Ñ8Ô8×?Ò?ÀÑDÔD€Gàð ˜7ð Øˆtà€FØð $Ø#ˆˆyÑØð $Ø#ˆˆyÑà�H˜g˜o¨¨w¨¸$Ð?Ð?Ð?r   c                  ó    — t          d¦  «        S )z(Return configured Firecrawl gateway URL.r,   )r   © r   r   Ú_get_firecrawl_gateway_urlrG   ‘   s   € å# KÑ0Ô0Ð0r   c                  ó2   — t          dt          ¬¦  «        duS )zGReturn True when gateway URL and a Nous Subscriber token are available.r,   ©Útoken_readerN)r   Ú_read_nous_access_tokenrF   r   r   r5   r5   –   s   € å'¨ÕBYÐZÑZÔZÐbfÐfÐfr   c                  ó"   — t          ¦   «         duS )zBReturn True when direct Firecrawl config is explicitly configured.N)rD   rF   r   r   Ú_has_direct_firecrawl_configrM   ›   s   € å'Ñ)Ô)°Ð5Ð5r   c                  óJ   — d} t          ¦   «         r| dz  } t          | ¦  «        ‚)z>Raise a clear error for unsupported web backend configuration.z†Web tools are not configured. Set FIRECRAWL_API_KEY for cloud Firecrawl or set FIRECRAWL_API_URL for a self-hosted Firecrawl instance.u‡    With your Nous subscription you can also use the Tool Gateway â€” run `hermes tools` and select Nous Subscription as the web provider.)r   Ú
ValueError)Úmessages    r   Ú&_raise_web_backend_configuration_errorrQ       s=   € ð	sð õ "Ñ#Ô#ð 
ØðSñ	
ˆõ �WÑ
Ô
Ðr   c                  ó(   — t          ¦   «         sdS 	 dS )zAReturn optional managed-gateway guidance for Firecrawl help text.r*   zc, or use the Nous Tool Gateway via your subscription (FIRECRAWL_GATEWAY_URL or TOOL_GATEWAY_DOMAIN))r   rF   r   r   Ú_firecrawl_backend_help_suffixrS   ®   s$   € å%Ñ'Ô'ð Øˆrð	9ðð r   c                  óX   — g d¢} t          ¦   «         r|                      g d¢¦  «         | S )zEReturn tool metadata env vars for the currently enabled web backends.)r3   r1   r2   r/   r0   )ÚFIRECRAWL_GATEWAY_URLÚTOOL_GATEWAY_DOMAINÚTOOL_GATEWAY_SCHEMEÚTOOL_GATEWAY_USER_TOKEN)r   Úextend)Úrequiress    r   Ú_web_requires_envr[   ¸   sO   € ðð ð €Hõ "Ñ#Ô#ð 
Ø�Šðð ð ñ	
ô 	
ð 	
ð €Or   c                  óf  — t          ¦   «         } | �t          d¦  «        s| \  }}n_t          dt          ¬¦  «        }|€(t                               d¦  «         t          ¦   «          |j        |j        dœ}d|d         |j        f}t          �t          |k    rt          S t          d	i |¤Ža	|a
t          S )
zõGet or create Firecrawl client.

    When ``web.use_gateway`` is set in config, the Tool Gateway is preferred
    even if direct Firecrawl credentials are present.  Otherwise direct
    Firecrawl takes precedence when explicitly configured.
    Nr"   r,   rI   zTFirecrawl client initialization failed: missing direct config and tool-gateway auth.)r?   r@   ztool-gatewayr@   rF   )rD   r   r   rK   ÚloggerÚerrorrQ   Únous_user_tokenÚgateway_originÚ_firecrawl_clientÚ_firecrawl_client_configr   )Údirect_configrC   Úclient_configÚmanaged_gateways       r   Ú_get_firecrawl_clientrf   Í   sÜ   € õ 1Ñ2Ô2€MØÐ ­¸Ñ)?Ô)?Ð Ø -Ñˆ��å6ØÝ0ð
ñ 
ô 
ˆð Ð"Ý�LŠLÐoÑpÔpÐpÝ2Ñ4Ô4Ð4ð 'Ô6Ø&Ô5ð
ð 
ˆð
 Ø�9ÔØÔ+ð
ˆõ Ð$Õ)AÀ]Ò)RÐ)RÝ Ð å!Ð+Ð+ FÐ+Ð+ÐØ,ÐÝÐr   c                  óŒ   — ddl m}  t          €1t          j        d¦  «        }|st          d¦  «        ‚ | |¬¦  «        at          S )zwGet or create the Parallel sync client (lazy initialization).

    Requires PARALLEL_API_KEY environment variable.
    r   )ÚParallelNr1   úVPARALLEL_API_KEY environment variable not set. Get your API key at https://parallel.ai©r?   )r+   rh   Ú_parallel_clientr   r   rO   )rh   r?   s     r   Ú_get_parallel_clientrl   ø   sf   € ð
 "Ð!Ð!Ð!Ð!Ð!åÐÝ”)Ð.Ñ/Ô/ˆØð 	Ýð:ñô ð ð $˜8¨GÐ4Ñ4Ô4ÐÝÐr   c                  óŒ   — ddl m}  t          €1t          j        d¦  «        }|st          d¦  «        ‚ | |¬¦  «        at          S )zxGet or create the Parallel async client (lazy initialization).

    Requires PARALLEL_API_KEY environment variable.
    r   )ÚAsyncParallelNr1   ri   rj   )r+   rn   Ú_async_parallel_clientr   r   rO   )rn   r?   s     r   Ú_get_async_parallel_clientrp   
  sf   € ð
 'Ð&Ð&Ð&Ð&Ð&åÐ%Ý”)Ð.Ñ/Ô/ˆØð 	Ýð:ñô ð ð "/ °wÐ!?Ñ!?Ô!?ÐÝ!Ð!r   ÚTAVILY_BASE_URLzhttps://api.tavily.comÚendpointÚpayloadc                 óJ  — t          j        d¦  «        }|st          d¦  «        ‚||d<   t          › d|                      d¦  «        › �}t
                               d| |¦  «         t          j        ||d¬¦  «        }| 	                    ¦   «          | 
                    ¦   «         S )z¶Send a POST request to the Tavily API.

    Auth is provided via ``api_key`` in the JSON body (no header-based auth).
    Raises ``ValueError`` if ``TAVILY_API_KEY`` is not set.
    r2   z\TAVILY_API_KEY environment variable not set. Get your API key at https://app.tavily.com/homer?   r>   zTavily %s request to %sé<   )ÚjsonÚtimeout)r   r   rO   Ú_TAVILY_BASE_URLÚlstripr]   ÚinfoÚhttpxÚpostÚraise_for_statusrv   )rr   rs   r?   ÚurlÚresponses        r   Ú_tavily_requestr€      s«   € õ ŒiÐ(Ñ)Ô)€GØð 
Ýð>ñ
ô 
ð 	
ð !€GˆIÑÝÐ
6Ð
6 §¢°Ñ 4Ô 4Ð
6Ð
6€CÝ
‡K‚KÐ)¨8°SÑ9Ô9Ð9ÝŒz˜# G°RÐ8Ñ8Ô8€HØ×ÒÑÔÐØ�=Š=‰?Œ?Ðr   r   c           	      ó  — g }t          |                      dg ¦  «        ¦  «        D ]^\  }}|                     |                     dd¦  «        |                     dd¦  «        |                     dd¦  «        |dz   dœ¦  «         Œ_dd	|id
œS )zâNormalize Tavily /search response to the standard web search format.

    Tavily returns ``{results: [{title, url, content, score, ...}]}``.
    We map to ``{success, data: {web: [{title, url, description, position}]}}``.
    ÚresultsÚtitler*   r~   Úcontenté   )rƒ   r~   ÚdescriptionÚpositionTr"   ©ÚsuccessÚdata)Ú	enumerater$   Úappend)r   Úweb_resultsÚiÚresults       r   Ú _normalize_tavily_search_resultsr�   4  s¨   € ð €KÝ˜xŸ|š|¨I°rÑ:Ô:Ñ;Ô;ð ð ‰	ˆˆ6Ø×ÒØ—Z’Z ¨Ñ,Ô,Ø—:’:˜e RÑ(Ô(Ø!Ÿ:š: i°Ñ4Ô4Ø˜A™ð	
ð 
ñ 	ô 	ð 	ð 	ð  e¨[Ð%9Ð:Ð:Ð:r   r*   Úfallback_urlc                 óì  — g }|                       dg ¦  «        D ]Š}|                      d|¦  «        }|                      dd¦  «        p|                      dd¦  «        }|                     ||                      dd¦  «        ||||                      dd¦  «        dœdœ¦  «         Œ‹|                       d	g ¦  «        D ]\}|                     |                      d|¦  «        ddd|                      d
d¦  «        d|                      d|¦  «        idœ¦  «         Œ]|                       dg ¦  «        D ]F}t          |t          ¦  «        r|nt          |¦  «        }|                     |ddddd|idœ¦  «         ŒG|S )zäNormalize Tavily /extract or /crawl response to the standard document format.

    Maps results to ``{url, title, content, raw_content, metadata}`` and
    includes any ``failed_results`` / ``failed_urls`` as error entries.
    r‚   r~   Úraw_contentr*   r„   rƒ   ©Ú	sourceURLrƒ   ©r~   rƒ   r„   r“   ÚmetadataÚfailed_resultsr^   úextraction failedr•   )r~   rƒ   r„   r“   r^   r—   Úfailed_urls)r$   rŒ   Ú
isinstanceÚstr)	r   r‘   Ú	documentsr�   r~   ÚrawÚfailÚfail_urlÚurl_strs	            r   Ú_normalize_tavily_documentsr¢   E  sÅ  € ð ')€IØ—,’,˜y¨"Ñ-Ô-ð 	ð 	ˆØ�jŠj˜ Ñ-Ô-ˆØ�jŠj˜¨Ñ+Ô+ÐH¨v¯zªz¸)ÀRÑ/HÔ/HˆØ×ÒØØ—Z’Z ¨Ñ,Ô,ØØØ&)°F·J²J¸wÈÑ4KÔ4KÐLÐLð
ð 
ñ 	ô 	ð 	ð 	ð —’Ð-¨rÑ2Ô2ð ð ˆØ×ÒØ—8’8˜E <Ñ0Ô0ØØØØ—X’X˜gÐ':Ñ;Ô;Ø$ d§h¢h¨u°lÑ&CÔ&CÐDð
ð 
ñ 	ô 	ð 	ð 	ð —L’L °Ñ3Ô3ð 	ð 	ˆÝ(¨µ3Ñ7Ô7ÐJ�(�(½SÀ¹]¼]ˆØ×ÒØØØØØ(Ø$ gÐ.ð
ð 
ñ 	ô 	ð 	ð 	ð Ðr   Úvaluec           	      ól  — | €dS t          | t          t          t          t          t
          t          f¦  «        r| S t          | d¦  «        r%	 |                      ¦   «         S # t          $ r Y nw xY wt          | d¦  «        r4	 d„ | j
                             ¦   «         D ¦   «         S # t          $ r Y nw xY w| S )zBConvert SDK objects to plain python data structures when possible.NÚ
model_dumpÚ__dict__c                 óD   — i | ]\  }}|                      d ¦  «        °||“ŒS ©Ú_©Ú
startswith)Ú.0ÚkÚvs      r   ú
<dictcomp>z$_to_plain_object.<locals>.<dictcomp>}  s0   € ÐUÐUÐU™T˜Q À1Ç<Â<ÐPSÑCTÔCTÐU�A�qÐUÐUÐUr   )r›   ÚdictÚlistrœ   ÚintÚfloatr   Úhasattrr¥   r&   r¦   Úitems)r£   s    r   Ú_to_plain_objectr¶   m  sÛ   € à€}Øˆtå�%�$¥¥c­3µµtÐ<Ñ=Ô=ð Øˆåˆu�lÑ#Ô#ð ð	Ø×#Ò#Ñ%Ô%Ð%øÝð 	ð 	ð 	ØˆDð	øøøõ ˆu�jÑ!Ô!ð ð	ØUÐU U¤^×%9Ò%9Ñ%;Ô%;ÐUÑUÔUÐUøÝð 	ð 	ð 	ØˆDð	øøøð €Ls$   ÁA  Á 
A-Á,A-Â"B$ Â$
B1Â0B1Úvaluesc                 ó´   — t          | t          ¦  «        sg S g }| D ];}t          |¦  «        }t          |t          ¦  «        r|                     |¦  «         Œ<|S )z7Normalize mixed SDK/list payloads into a list of dicts.)r›   r±   r¶   r°   rŒ   )r·   Ú
normalizedÚitemÚplains       r   Ú_normalize_result_listr¼   „  sg   € å�f�dÑ#Ô#ð Øˆ	à')€JØð %ð %ˆÝ  Ñ&Ô&ˆÝ�e�TÑ"Ô"ð 	%Ø×Ò˜eÑ$Ô$Ð$øØÐr   c                 óv  — t          | ¦  «        }t          |t          ¦  «        ræ|                     d¦  «        }t          |t          ¦  «        rt          |¦  «        S t          |t          ¦  «        rLt          |                     d¦  «        ¦  «        }|r|S t          |                     d¦  «        ¦  «        }|r|S t          |                     d¦  «        ¦  «        }|r|S t          |                     d¦  «        ¦  «        }|r|S t          | d¦  «        rt          t          | dg ¦  «        ¦  «        S g S )zKExtract Firecrawl search results across SDK/direct/gateway response shapes.rŠ   r"   r‚   )r¶   r›   r°   r$   r±   r¼   r´   Úgetattr)r   Úresponse_plainrŠ   Údata_webÚdata_resultsÚtop_webÚtop_resultss          r   Ú_extract_web_search_resultsrÄ   ‘  s4  € å% hÑ/Ô/€Nå�.¥$Ñ'Ô'ð Ø×!Ò! &Ñ)Ô)ˆÝ�d�DÑ!Ô!ð 	0Ý)¨$Ñ/Ô/Ð/å�d�DÑ!Ô!ð 	$Ý-¨d¯hªh°u©o¬oÑ>Ô>ˆHØð  Ø�Ý1°$·(²(¸9Ñ2EÔ2EÑFÔFˆLØð $Ø#Ð#å(¨×);Ò);¸EÑ)BÔ)BÑCÔCˆØð 	ØˆNå,¨^×-?Ò-?À	Ñ-JÔ-JÑKÔKˆØð 	ØÐåˆx˜ÑÔð DÝ%¥g¨h¸¸rÑ&BÔ&BÑCÔCÐCà€Ir   Úscrape_resultc                 óª   — t          | ¦  «        }t          |t          ¦  «        si S |                     d¦  «        }t          |t          ¦  «        r|S |S )zINormalize Firecrawl scrape payload shape across SDK and gateway variants.rŠ   )r¶   r›   r°   r$   )rÅ   Úresult_plainÚnesteds      r   Ú_extract_scrape_payloadrÉ   °  sV   € å# MÑ2Ô2€LÝ�l¥DÑ)Ô)ð Øˆ	à×Ò˜fÑ%Ô%€FÝ�&�$ÑÔð ØˆàÐr   éˆ  Úclientc                 óÌ   — ddl m} t          t          | dd¦  «        pd¦  «        } ||¦  «        j        pd                     ¦   «         }|dk    p|                     d¦  «        S )z?Return True when the resolved auxiliary backend is Nous Portal.r   )ÚurlparseÚbase_urlr*   znousresearch.comz.nousresearch.com)Úurllib.parserÍ   rœ   r¾   Úhostnamer4   Úendswith)rË   rÍ   rÎ   Úhosts       r   Ú_is_nous_auxiliary_clientrÓ   ¿  ss   € à%Ð%Ð%Ð%Ð%Ð%å•7˜6 :¨rÑ2Ô2Ð8°bÑ9Ô9€HØˆH�XÑÔÔ'Ð-¨2×4Ò4Ñ6Ô6€DØÐ%Ò%ÐK¨¯ªÐ7JÑ)KÔ)KÐKr   Úmodelc                 óÚ   — t          d¦  «        \  }}t          j        dd¦  «                             ¦   «         }| p|p|}i }|�$t	          |¦  «        rddlm}  |¦   «         pddgi}|||fS )	zHResolve the current web-extract auxiliary client, model, and extra body.Úweb_extractÚAUXILIARY_WEB_EXTRACT_MODELr*   Nr   )Úget_auxiliary_extra_bodyÚtagszproduct=hermes-agent)r
   r   r   r   rÓ   Úagent.auxiliary_clientrØ   )rÔ   rË   Údefault_modelÚconfigured_modelÚeffective_modelÚ
extra_bodyrØ   s          r   Ú_resolve_web_extract_auxiliaryrß   È  s—   € å;¸MÑJÔJÑ€FˆMÝ”yÐ!>ÀÑCÔC×IÒIÑKÔKÐØÐ@Ð/Ð@°=€Oà!#€JØÐÕ7¸Ñ?Ô?ÐØCÐCÐCÐCÐCÐCØ-Ð-Ñ/Ô/ÐU°FÐ=SÐ<TÐ3Uˆ
à�? JÐ.Ð.r   c                  ó*   — t          ¦   «         \  } }} |S )zBReturn the current default model for web extraction summarization.©rß   )r©   rÔ   s     r   Ú_get_default_summarizer_modelrâ   Ö  s   € å0Ñ2Ô2�K€A€uˆaØ€Lr   Ú	web_toolsÚWEB_TOOLS_DEBUG)Úenv_varr„   r~   rƒ   Ú
min_lengthc              ƒ   ó  K  — d}d}d}d}	 t          | ¦  «        }	|	|k    r'|	dz  }
t                               d|
¦  «         d|
d›d	�S |	|k     rt                               d
|	|¦  «         dS g }|r|                     d|› �¦  «         |r|                     d|› �¦  «         |rd                     |¦  «        dz   nd}|	|k    r4t                               d|	¦  «         t          | ||||¦  «        ƒ d{V —†S t                               d|	¦  «         t          | ||¦  «        ƒ d{V —†}|r\t          |¦  «        |k    r|d|…         dz   }t          |¦  «        }|	dk    r||	z  nd}t                               d|	||dz  ¦  «         |S # t          $ rt}t                               dt          |¦  «        dd…         ¦  «         | d|…         }t          | ¦  «        |k    r|d|d›dt          | ¦  «        d›d�z  }|cY d}~S d}~ww xY w)aÜ  
    Process web content using LLM to create intelligent summaries with key excerpts.
    
    This function uses Gemini 3 Flash Preview (or specified model) via OpenRouter API 
    to intelligently extract key information and create markdown summaries,
    significantly reducing token usage while preserving all important information.
    
    For very large content (>500k chars), uses chunked processing with synthesis.
    For extremely large content (>2M chars), refuses to process entirely.
    
    Args:
        content (str): The raw content to process
        url (str): The source URL (for context, optional)
        title (str): The page title (for context, optional)
        model (str): The model to use for processing (default: google/gemini-3-flash-preview)
        min_length (int): Minimum content length to trigger processing (default: 5000)
        
    Returns:
        Optional[str]: Processed markdown content, or None if content too short or processing fails
    i€„ i ¡ é † rÊ   i@B z<Content too large (%.1fMB > 2MB limit). Refusing to process.z[Content too large to process: z.1fzdMB. Try using web_crawl with specific extraction instructions, or search for a more focused source.]z:Content too short (%d < %d chars), skipping LLM processingNzTitle: zSource: Ú
ú

r*   z5Content large (%d chars). Using chunked processing...z+Processing content with LLM (%d characters)ú4

[... summary truncated for context management ...]r   ç      ð?z*Content processed: %d -> %d chars (%.1f%%)éd   zŒweb_extract LLM summarization failed (%s). Tip: increase auxiliary.web_extract.timeout in config.yaml or switch to a faster auxiliary model.éx   u'   

[Content truncated â€” showing first Ú,ú of z­ chars. LLM summarization timed out. To fix: increase auxiliary.web_extract.timeout in config.yaml, or use a faster auxiliary model. Use browser_navigate for the full page.])Úlenr]   ÚwarningÚdebugrŒ   Újoinrz   Ú_process_large_content_chunkedÚ_call_summarizer_llmr&   rœ   )r„   r~   rƒ   rÔ   ræ   ÚMAX_CONTENT_SIZEÚCHUNK_THRESHOLDÚ
CHUNK_SIZEÚMAX_OUTPUT_SIZEÚcontent_lenÚsize_mbÚcontext_infoÚcontext_strÚprocessed_contentÚprocessed_lengthÚcompression_ratioÚeÚ	truncateds                     r   Úprocess_content_with_llmr  Þ  s  è è € ð8 !ÐØ€OØ€JØ€Oð@Ý˜'‘l”lˆð Ð)Ò)Ð)Ø! IÑ-ˆGÝ�NŠNÐYÐ[bÑcÔcÐcð g°Wð  gð  gð  gð  gð  gð ˜Ò#Ð#Ý�LŠLÐUÐWbÐdnÑoÔoÐoØ�4ð ˆØð 	3Ø×ÒÐ 1¨%Ð 1Ð 1Ñ2Ô2Ð2Øð 	2Ø×ÒÐ 0¨3Ð 0Ð 0Ñ1Ô1Ð1Ø:FÐN�d—i’i Ñ-Ô-°Ñ6Ð6ÈBˆð ˜Ò(Ð(Ý�KŠKÐOÐQ\Ñ]Ô]Ð]Ý7Ø˜ e¨Z¸ñô ð ð ð ð ð ð ð õ
 	�ŠÐAÀ;ÑOÔOÐOå"6°wÀÈUÑ"SÔ"SÐSÐSÐSÐSÐSÐSÐàð 	~åÐ$Ñ%Ô%¨Ò7Ð7Ø$5Ð6F°Ð6FÔ$Gð  KCñ  %CÐ!õ  #Ð#4Ñ5Ô5ÐØBMÐPQÂ/À/Ð 0°;Ñ >Ð >ÐWZÐÝ�KŠKÐDÀkÐScÐevÐy|Ñe|Ñ}Ô}Ð}à Ð øåð ð ð Ý�Šð5õ �‰FŒF�4�C�4ŒLñ		
ô 	
ð 	
ð Ð,˜_Ð,Ô-ˆ	Ýˆw‰<Œ<˜/Ò)Ð)Øð]¸OÐSð ]ð ]Ý�w‘<”<ÐHð]ð ]ð ]ñˆIð ÐÐÐÐÐÐøøøøð%øøøs2   Œ;F
 Á"F
 Á,BF
 Ã8BF
 Æ

HÆA)HÇ=HÈHé N  Frþ   Ú
max_tokensÚis_chunkÚ
chunk_infoc           
   ƒ   óž  K  — |rd}d|› |› d| › d�}nd}d|› d| › d�}d	}d	}	d
}
t          |¦  «        D �]˜}	 t          |¦  «        \  }}}|�|st                               d¦  «          d
S d|d|dœd|dœgd|dœ}|r||d<   t	          di |¤Žƒ d
{V —†}t          |¦  «        } | r| c S t                               d|dz   |¦  «         ||dz
  k     r.t          j        |	¦  «        ƒ d
{V —† t          |	d	z  d¦  «        }	ŒÌ| c S # t          $ r t                               d¦  «         Y  d
S t          $ r–}|}
||dz
  k     r~t                               d|dz   |t          |¦  «        d
d…         ¦  «         t                               d|	¦  «         t          j        |	¦  «        ƒ d
{V —† t          |	d	z  d¦  «        }	n|
‚Y d
}~�Œ’d
}~ww xY wd
S )a·  
    Make a single LLM call to summarize content.
    
    Args:
        content: The content to summarize
        context_str: Context information (title, URL)
        model: Model to use
        max_tokens: Maximum output tokens
        is_chunk: Whether this is a chunk of a larger document
        chunk_info: Information about chunk position (e.g., "Chunk 2/5")
        
    Returns:
        Summarized content or None on failure
    añ  You are an expert content analyst processing a SECTION of a larger document. Your job is to extract and summarize the key information from THIS SECTION ONLY.

Important guidelines for chunk processing:
1. Do NOT write introductions or conclusions - this is a partial document
2. Focus on extracting ALL key facts, figures, data points, and insights from this section
3. Preserve important quotes, code snippets, and specific details verbatim
4. Use bullet points and structured formatting for easy synthesis later
5. Note any references to other sections (e.g., "as mentioned earlier", "see below") without trying to resolve them

Your output will be combined with summaries of other sections, so focus on thorough extraction rather than narrative flow.zAExtract key information from this SECTION of a larger document:

z

SECTION CONTENT:
z§

Extract all important information from this section in a structured format. Focus on facts, data, insights, and key details. Do not add introductions or conclusions.a~  You are an expert content analyst. Your job is to process web content and create a comprehensive yet concise summary that preserves all important information while dramatically reducing bulk.

Create a well-structured markdown summary that includes:
1. Key excerpts (quotes, code snippets, important facts) in their original format
2. Comprehensive summary of all other important information
3. Proper markdown formatting with headers, bullets, and emphasis

Your goal is to preserve ALL important information while reducing length. Never lose key facts, figures, insights, or actionable information. Make it scannable and well-organized.zNPlease process this web content and create a comprehensive markdown summary:

zCONTENT TO PROCESS:
zõ

Create a markdown summary that captures all key information in a well-organized, scannable format. Include important quotes and code snippets in their original formatting. Focus on actionable information, specific details, and unique insights.é   Nz7No auxiliary model available for web content processingrÖ   Úsystem©Úroler„   Úuserçš™™™™™¹?©ÚtaskrÔ   ÚmessagesÚtemperaturer  rÞ   z4LLM returned empty content (attempt %d/%d), retryingr…   ru   z'LLM API call failed (attempt %d/%d): %srí   zRetrying in %ds...rF   )Úrangerß   r]   rò   r   r	   ÚasyncioÚsleepÚminÚRuntimeErrorr&   rœ   )r„   rþ   rÔ   r  r  r  Úsystem_promptÚuser_promptÚmax_retriesÚretry_delayÚ
last_errorÚattemptÚ
aux_clientrÝ   rÞ   Úcall_kwargsr   Ú	api_errors                     r   rö   rö   B  sæ  è è € ð, ð &wð	~ˆðiàðiàðið ið
 	ðið ið iˆˆðwˆðwàðwð wð 	ðwð wð wˆð €KØ€KØ€Jå˜Ñ%Ô%ð +!ñ +!ˆð*	!Ý6TÐUZÑ6[Ô6[Ñ3ˆJ˜¨ØÐ!¨Ð!Ý—’ÐXÑYÔYÐYØ�t�tà%Ø(à%°-Ð@Ð@Ø#°Ð<Ð<ðð  #Ø(ðð ˆKð ð 7Ø,6�˜LÑ)Ý+Ð:Ð:¨kÐ:Ð:Ð:Ð:Ð:Ð:Ð:Ð:ˆHÝ2°8Ñ<Ô<ˆGØð Ø���å�NŠNÐQÐSZÐ]^ÑS^Ð`kÑlÔlÐlØ˜ q™Ò(Ð(Ý”m KÑ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0Ð0Ý! +°¡/°2Ñ6Ô6�ØØˆNˆNˆNøÝð 	ð 	ð 	Ý�NŠNÐTÑUÔUÐUØ�4�4�4Ýð 	!ð 	!ð 	!Ø"ˆJØ˜ q™Ò(Ð(Ý—’ÐHÈ'ÐTUÉ+ÐWbÕdgÐhqÑdrÔdrÐswÐtwÐswÔdxÑyÔyÐyÝ—’Ð3°[ÑAÔAÐAÝ”m KÑ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0Ð0Ý! +°¡/°2Ñ6Ô6��à Ð ð ���‘øøøøð	!øøøð ˆ4s1   ·1DÁ+;DÂ)ADÃ?DÄ$G
Ä+	G
Ä4BGÇG
Ú
chunk_sizeÚmax_output_sizec           	   ƒ   ó  ‡‡‡‡K  — g Št          dt          | ¦  «        |¦  «        D ]$}| |||z   …         }‰                     |¦  «         Œ%t                               dt          ‰¦  «        |¦  «         dt
          dt          dt          t
          t          t                   f         fˆˆˆfd„Šˆfd„t          ‰¦  «        D ¦   «         }t          j        |Ž ƒ d{V —†}g }	t          |d	„ ¬
¦  «        D ]%\  }
}|r|	                     d|
dz   › d|› �¦  «         Œ&|	st                               d¦  «         dS t                               dt          |	¦  «        t          ‰¦  «        ¦  «         t          |	¦  «        dk    r*|	d         }t          |¦  «        |k    r|d|…         dz   }|S t                               dt          |	¦  «        ¦  «         d                     |	¦  «        }d|› d‰› d|› d�}	 t          ‰¦  «        \  }}}|�|sQt                               d¦  «         d                     |	¦  «        }t          |¦  «        |k    r|d|…         dz   }|S d|dddœd|dœgdd d!œ}|r||d"<   t#          d+i |¤Žƒ d{V —†}t%          |¦  «        }|s;t                               d#¦  «         t#          d+i |¤Žƒ d{V —†}t%          |¦  «        }|sQt                               d$¦  «         d                     |	¦  «        }t          |¦  «        |k    r|d|…         dz   }|S t          |¦  «        |k    r|d|…         d%z   }t          | ¦  «        }t          |¦  «        }|dk    r||z  nd&}t                               d'|||d(z  ¦  «         |S # t&          $ rq}t                               d)t          |¦  «        dd(…         ¦  «         d                     |	¦  «        }t          |¦  «        |k    r|d|…         d*z   }|cY d}~S d}~ww xY w),a¤  
    Process large content by chunking, summarizing each chunk in parallel,
    then synthesizing the summaries.
    
    Args:
        content: The large content to process
        context_str: Context information
        model: Model to use
        chunk_size: Size of each chunk in characters
        max_output_size: Maximum final output size
        
    Returns:
        Synthesized summary or None on failure
    r   z&Split into %d chunks of ~%d chars eachÚ	chunk_idxÚchunk_contentr   c           	   “   óÈ  •K  — 	 d| dz   › dt          ‰¦  «        › d�}t          |‰‰dd|¬¦  «        ƒ d{V —†}|rHt                               d	| dz   t          ‰¦  «        t          |¦  «        t          |¦  «        ¦  «         | |fS # t          $ rP}t                               d
| dz   t          ‰¦  «        t          |¦  «        dd…         ¦  «         | dfcY d}~S d}~ww xY w)zSummarize a single chunk.z[Processing chunk r…   rð   Ú]i'  T)r  r  r  Nz&Chunk %d/%d summarized: %d -> %d charszChunk %d/%d failed: %sé2   )rñ   rö   r]   rz   r&   rò   rœ   )r%  r&  r  Úsummaryr  Úchunksrþ   rÔ   s        €€€r   Úsummarize_chunkz7_process_large_content_chunked.<locals>.summarize_chunkÔ  sL  øè è € ð	#ØO¨i¸!©mÐOÐOÅÀVÁÄÐOÐOÐOˆJÝ0ØØØØ ØØ%ðñ ô ð ð ð ð ð ð ˆGð ð DÝ—’ÐDÀiÐRSÁmÕUXÐY_ÑU`ÔU`ÕbeÐfsÑbtÔbtÕvyð  {Bñ  wCô  wCñ  Dô  Dð  DØ˜gÐ%Ð%øÝð 	#ð 	#ð 	#Ý�NŠNÐ3°YÀ±]ÅCÈÁKÄKÕQTÐUVÑQWÔQWÐX[ÐY[ÐX[ÔQ\Ñ]Ô]Ð]Ø˜d�?Ð"Ð"Ð"Ð"Ð"Ð"øøøøð	#øøøs   …BB Â
C!ÂACÃC!ÃC!c                 ó.   •— g | ]\  }} ‰||¦  «        ‘ŒS rF   rF   )r¬   rŽ   Úchunkr,  s      €r   ú
<listcomp>z2_process_large_content_chunked.<locals>.<listcomp>è  s)   ø€ ÐIÐIÐI©8¨1¨eˆ_ˆ_˜Q Ñ&Ô&ÐIÐIÐIr   Nc                 ó   — | d         S )Nr   rF   )Úxs    r   ú<lambda>z0_process_large_content_chunked.<locals>.<lambda>í  s
   € ¸A¸a¼D€ r   )Úkeyz## Section r…   ré   zAll chunk summarizations failedzB[Failed to process large content: all chunk summarizations failed]zGot %d/%d chunk summariesz

[... truncated ...]zSynthesizing %d summaries...z

---

a'  You have been given summaries of different sections of a large document. 
Synthesize these into ONE cohesive, comprehensive summary that:
1. Removes redundancy between sections
2. Preserves all key facts, figures, and actionable information
3. Is well-organized with clear structure
4. Is under z characters

zSECTION SUMMARIES:
z,

Create a single, unified markdown summary.z9No auxiliary model for synthesis, concatenating summariesrê   rÖ   r  zdYou synthesize multiple summaries into one cohesive, comprehensive summary. Be thorough but concise.r  r  r  r  r  rÞ   z3Synthesis LLM returned empty content, retrying onceu>   Synthesis failed after retry â€” concatenating chunk summariesrë   rì   z+Synthesis complete: %d -> %d chars (%.2f%%)rí   zSynthesis failed: %sz.

[... truncated due to synthesis failure ...]rF   )r  rñ   rŒ   r]   rz   r²   rœ   Útupler   r‹   r  ÚgatherÚsortedró   rô   rß   rò   r   r	   r&   )r„   rþ   rÔ   r"  r#  rŽ   r.  Útasksr‚   Ú	summariesr%  r*  r�   Úcombined_summariesÚsynthesis_promptr  rÝ   rÞ   Úfallbackr   r   Úfinal_summaryÚoriginal_lenÚ	final_lenÚcompressionr  r+  r,  s    ``                       @@r   rõ   rõ   ¶  s  øøøøè è € ð, €FÝ�1•c˜'‘l”l JÑ/Ô/ð ð ˆØ˜˜!˜j™.Ð(Ô)ˆØ�Š�eÑÔÐÐå
‡K‚KÐ8½#¸f¹+¼+ÀzÑRÔRÐRð#­ð #½Sð #ÅUÍ3ÕPXÕY\ÔP]ÐK]ÔE^ð #ð #ð #ð #ð #ð #ð #ð #ð( JÐIÐIÐIµyÀÑ7HÔ7HÐIÑIÔI€EÝ”N EÐ*Ð*Ð*Ð*Ð*Ð*Ð*€Gð €IÝ$ W°.°.ÐAÑAÔAð Gð GÑˆ	�7Øð 	GØ×ÒÐE¨9°q©=ÐEÐE¸GÐEÐEÑFÔFÐFøàð TÝ�ŠÐ6Ñ7Ô7Ð7ØSÐSå
‡K‚KÐ+­S°©^¬^½SÀ¹[¼[ÑIÔIÐIõ ˆ9�~„~˜ÒÐØ˜1”ˆÝˆv‰;Œ;˜Ò(Ð(ØÐ,˜_Ð,Ô-Ð0IÑIˆFØˆõ ‡K‚KÐ.µ°I±´Ñ?Ô?Ð?à&×+Ò+¨IÑ6Ô6Ðð
.ð
 ð
.ð 
.ð ð
.ð 
.ð ð
.ð 
.ð 
.Ðð7Ý2PÐQVÑ2WÔ2WÑ/ˆ
�O ZØÐ _ÐÝ�NŠNÐVÑWÔWÐWØ—{’{ 9Ñ-Ô-ˆHÝ�8‰}Œ}˜Ò.Ð.Ø#Ð$4 _Ð$4Ô5Ð8QÑQ�ØˆOð "Ø$à!ð  /Uð  Vð  VØÐ,<Ð=Ð=ðð Øð	
ð 	
ˆð ð 	3Ø(2ˆK˜Ñ%Ý'Ð6Ð6¨+Ð6Ð6Ð6Ð6Ð6Ð6Ð6Ð6ˆÝ4°XÑ>Ô>ˆð ð 	CÝ�NŠNÐPÑQÔQÐQÝ+Ð:Ð:¨kÐ:Ð:Ð:Ð:Ð:Ð:Ð:Ð:ˆHÝ8¸ÑBÔBˆMð ð 	Ý�NŠNÐ[Ñ\Ô\Ð\Ø—{’{ 9Ñ-Ô-ˆHÝ�8‰}Œ}˜Ò.Ð.Ø#Ð$4 _Ð$4Ô5Ð8QÑQ�ØˆOõ ˆ}ÑÔ Ò/Ð/Ø)Ð*:¨?Ð*:Ô;Ð>vÑvˆMå˜7‘|”|ˆÝ˜Ñ&Ô&ˆ	Ø2>ÀÒ2BÐ2B�i ,Ñ.Ð.Èˆå�ŠÐAÀ<ÐQZÐ\gÐjmÑ\mÑnÔnÐnØÐøåð ð ð Ý�ŠÐ-­s°1©v¬v°d°s°d¬|Ñ<Ô<Ð<à—;’;˜yÑ)Ô)ˆÝˆx‰=Œ=˜?Ò*Ð*ØÐ 0 Ð 0Ô1Ð4fÑfˆHØˆˆˆˆˆˆøøøøðøøøs.   Ç3A'N ÉCN Ì#A,N Î
PÎA&PÐ PÐPÚtextc                 óf   — d}d}t          j        |d| ¦  «        }t          j        |d|¦  «        }|S )aÚ  
    Remove base64 encoded images from text to reduce token count and clutter.
    
    This function finds and removes base64 encoded images in various formats:
    - (data:image/png;base64,...)
    - (data:image/jpeg;base64,...)
    - (data:image/svg+xml;base64,...)
    - data:image/[type];base64,... (without parentheses)
    
    Args:
        text: The text content to clean
        
    Returns:
        Cleaned text with base64 images replaced with placeholders
    z+\(data:image/[^;]+;base64,[A-Za-z0-9+/=]+\)z'data:image/[^;]+;base64,[A-Za-z0-9+/=]+z[BASE64_IMAGE_REMOVED])ÚreÚsub)r@  Úbase64_with_parens_patternÚbase64_patternÚcleaned_texts       r   Úclean_base64_imagesrG  I  sG   € ð$ "PÐð @€Nõ ”6Ð4Ð6NÐPTÑUÔU€Lõ ”6˜.Ð*BÀLÑQÔQ€LàÐr   c                  óª   — ddl m}  t          €@t          j        d¦  «        }|st          d¦  «        ‚ | |¬¦  «        adt          j        d<   t          S )	zhGet or create the Exa client (lazy initialization).

    Requires EXA_API_KEY environment variable.
    r   )ÚExaNr3   zLEXA_API_KEY environment variable not set. Get your API key at https://exa.airj   zhermes-agentzx-exa-integration)Úexa_pyrI  Ú_exa_clientr   r   rO   Úheaders)rI  r?   s     r   Ú_get_exa_clientrM  n  sr   € ð
 ÐÐÐÐÐåÐÝ”)˜MÑ*Ô*ˆØð 	Ýð5ñô ð ð �c 'Ð*Ñ*Ô*ˆØ3A�ÔÐ/Ñ0ÝÐr   é
   ÚqueryÚlimitc                 ó�  — ddl m}  |¦   «         rdddœS t                               d| |¦  «         t	          ¦   «                              | |ddi¬	¦  «        }g }t          |j        pg ¦  «        D ]P\  }}|j        pg }| 	                    |j
        pd
|j        pd
|rd                     |¦  «        nd
|dz   dœ¦  «         ŒQdd|idœS )z6Search using the Exa SDK and return results as a dict.r   ©Úis_interruptedÚInterruptedF©r^   r‰   zExa search: '%s' (limit=%d)Ú
highlightsT)Únum_resultsÚcontentsr*   Ú r…   ©r~   rƒ   r†   r‡   r"   rˆ   )Útools.interruptrS  r]   rz   rM  Úsearchr‹   r‚   rV  rŒ   r~   rƒ   rô   )rO  rP  rS  r   r�   rŽ   r�   rV  s           r   Ú_exa_searchr]  ƒ  s   € à.Ð.Ð.Ð.Ð.Ð.Ø€~ÑÔð :Ø&°5Ð9Ð9Ð9å
‡K‚KÐ-¨u°eÑ<Ô<Ð<ÝÑ Ô ×'Ò'ØØà˜$ð
ð (ñ ô €Hð €KÝ˜xÔ/Ð5°2Ñ6Ô6ð ð ‰	ˆˆ6ØÔ&Ð,¨"ˆ
Ø×ÒØ”:Ð# Ø”\Ð' RØ3=ÐE˜3Ÿ8š8 JÑ/Ô/Ð/À2Ø˜A™ð	
ð 
ñ 	ô 	ð 	ð 	ð  e¨[Ð%9Ð:Ð:Ð:r   Úurlsc           
      ób  — ddl m}  |¦   «         rd„ | D ¦   «         S t                               dt	          | ¦  «        ¦  «         t          ¦   «                              | d¬¦  «        }g }|j        pg D ];}|j        pd}|j	        pd}|j
        pd}|                     ||||||dœd	œ¦  «         Œ<|S )
z¾Extract content from URLs using the Exa SDK.

    Returns a list of result dicts matching the structure expected by the
    LLM post-processing pipeline (url, title, content, metadata).
    r   rR  c                 ó   — g | ]}|d ddœ‘Œ	S ©rT  r*   ©r~   r^   rƒ   rF   ©r¬   Úus     r   r/  z _exa_extract.<locals>.<listcomp>§  ó"   € ÐNÐNÐNÀA˜ M¸BÐ?Ð?ÐNÐNÐNr   zExa extract: %d URL(s)T)r@  r*   r”   r–   )r[  rS  r]   rz   rñ   rM  Úget_contentsr‚   r@  r~   rƒ   rŒ   )r^  rS  r   r‚   r�   r„   r~   rƒ   s           r   Ú_exa_extractrg  Ÿ  s  € ð /Ð.Ð.Ð.Ð.Ð.Ø€~ÑÔð OØNÐNÈÐNÑNÔNÐNå
‡K‚KÐ(­#¨d©)¬)Ñ4Ô4Ð4ÝÑ Ô ×-Ò-ØØð .ñ ô €Hð
 €GØÔ"Ð( bð 
ð 
ˆØ”+Ð# ˆØŒjÐ˜BˆØ”Ð" ˆØ�ŠØØØØ"Ø&)°EÐ:Ð:ð
ð 
ñ 	ô 	ð 	ð 	ð €Nr   é   c           	      ó6  — ddl m}  |¦   «         rdddœS t          j        dd¦  «                             ¦   «                              ¦   «         }|dvrd}t                               d	| ||¦  «         t          ¦   «         j	         
                    | g| |t          |d
¦  «        ¬¦  «        }g }t          |j        pg ¦  «        D ]P\  }}|j        pg }|                     |j        pd|j        pd|rd                     |¦  «        nd|dz   dœ¦  «         ŒQdd|idœS )z;Search using the Parallel SDK and return results as a dict.r   rR  rT  FrU  ÚPARALLEL_SEARCH_MODEÚagentic)Úfastzone-shotrk  z)Parallel search: '%s' (mode=%s, limit=%d)é   )Úsearch_queriesÚ	objectiveÚmodeÚmax_resultsr*   rY  r…   rZ  Tr"   rˆ   )r[  rS  r   r   r4   r   r]   rz   rl   Úbetar\  r  r‹   r‚   ÚexcerptsrŒ   r~   rƒ   rô   )	rO  rP  rS  rp  r   r�   rŽ   r�   rs  s	            r   Ú_parallel_searchrt  Á  se  € à.Ð.Ð.Ð.Ð.Ð.Ø€~ÑÔð :Ø&°5Ð9Ð9Ð9åŒ9Ð+¨YÑ7Ô7×=Ò=Ñ?Ô?×EÒEÑGÔG€DØÐ2Ð2Ð2Øˆå
‡K‚KÐ;¸UÀDÈ%ÑPÔPÐPÝ#Ñ%Ô%Ô*×1Ò1Ø�wØØÝ˜˜r‘N”Nð	 2ñ ô €Hð €KÝ˜xÔ/Ð5°2Ñ6Ô6ð ð ‰	ˆˆ6Ø”?Ð( bˆØ×ÒØ”:Ð# Ø”\Ð' RØ19ÐA˜3Ÿ8š8 HÑ-Ô-Ð-¸rØ˜A™ð	
ð 
ñ 	ô 	ð 	ð 	ð  e¨[Ð%9Ð:Ð:Ð:r   c           
   ƒ   óB  K  — ddl m}  |¦   «         rd„ | D ¦   «         S t                               dt	          | ¦  «        ¦  «         t          ¦   «         j                             | d¬¦  «        ƒ d{V —†}g }|j        pg D ]Y}|j	        pd}|sd	 
                    |j        pg ¦  «        }|j        pd}|j        pd}|                     ||||||d
œdœ¦  «         ŒZ|j        pg D ];}|                     |j        pddd|j        p|j        pdd|j        pdidœ¦  «         Œ<|S )zÉExtract content from URLs using the Parallel async SDK.

    Returns a list of result dicts matching the structure expected by the
    LLM post-processing pipeline (url, title, content, metadata).
    r   rR  c                 ó   — g | ]}|d ddœ‘Œ	S ra  rF   rc  s     r   r/  z%_parallel_extract.<locals>.<listcomp>è  re  r   zParallel extract: %d URL(s)T)r^  Úfull_contentNr*   rê   r”   r–   r™   r•   )r~   rƒ   r„   r^   r—   )r[  rS  r]   rz   rñ   rp   rr  Úextractr‚   rw  rô   rs  r~   rƒ   rŒ   Úerrorsr„   Ú
error_type)	r^  rS  r   r‚   r�   r„   r~   rƒ   r^   s	            r   Ú_parallel_extractr{  à  s´  è è € ð /Ð.Ð.Ð.Ð.Ð.Ø€~ÑÔð OØNÐNÈÐNÑNÔNÐNå
‡K‚KÐ-­s°4©y¬yÑ9Ô9Ð9Ý/Ñ1Ô1Ô6×>Ò>ØØð ?ñ ô ð ð ð ð ð ð €Hð
 €GØÔ"Ð( bð ð ˆØÔ%Ð+¨ˆØð 	9Ø—k’k &¤/Ð"7°RÑ8Ô8ˆGØŒjÐ˜BˆØ”Ð" ˆØ�ŠØØØØ"Ø&)°EÐ:Ð:ð
ð 
ñ 	ô 	ð 	ð 	ð ”Ð& Bð ð ˆØ�ŠØ”9�? ØØØ”]ÐM eÔ&6ÐMÐ:MØ$ e¤i o°2Ð6ð
ð 
ñ 	ô 	ð 	ð 	ð €Nr   c                 óì  — | |dœdddddœ}	 ddl m}  |¦   «         rt          dd¬¦  «        S t          ¦   «         }|d	k    r©t	          | |¦  «        }t          |                     d
i ¦  «                             dg ¦  «        ¦  «        |d<   t          j        |dd¬¦  «        }t          |¦  «        |d<   t           
                    d|¦  «         t                               ¦   «          |S |dk    r©t          | |¦  «        }t          |                     d
i ¦  «                             dg ¦  «        ¦  «        |d<   t          j        |dd¬¦  «        }t          |¦  «        |d<   t           
                    d|¦  «         t                               ¦   «          |S |dk    rçt                               d| |¦  «         t          d| t!          |d¦  «        dddœ¦  «        }t#          |¦  «        }t          |                     d
i ¦  «                             dg ¦  «        ¦  «        |d<   t          j        |dd¬¦  «        }t          |¦  «        |d<   t           
                    d|¦  «         t                               ¦   «          |S t                               d| |¦  «         t%          ¦   «                              | |¬¦  «        }t)          |¦  «        }	t          |	¦  «        }
t                               d|
¦  «         dd|	idœ}|
|d<   t          j        |dd¬¦  «        }t          |¦  «        |d<   t           
                    d|¦  «         t                               ¦   «          |S # t*          $ r}dt-          |¦  «        › �}t                               d|¦  «         ||d<   t           
                    d|¦  «         t                               ¦   «          t          |¦  «        cY d}~S d}~ww xY w)aE  
    Search the web for information using available search API backend.

    This function provides a generic interface for web search that can work
    with multiple backends (Parallel or Firecrawl).

    Note: This function returns search result metadata only (URLs, titles, descriptions).
    Use web_extract_tool to get full content from specific URLs.
    
    Args:
        query (str): The search query to look up
        limit (int): Maximum number of results to return (default: 5)
    
    Returns:
        str: JSON string containing search results with the following structure:
             {
                 "success": bool,
                 "data": {
                     "web": [
                         {
                             "title": str,
                             "url": str,
                             "description": str,
                             "position": int
                         },
                         ...
                     ]
                 }
             }
    
    Raises:
        Exception: If search fails or API key is not set
    )rO  rP  Nr   )Ú
parametersr^   Úresults_countÚoriginal_response_sizeÚfinal_response_sizerR  rT  F©r‰   r+   rŠ   r"   r~  r
  ©ÚindentÚensure_asciir€  Úweb_search_toolr.   r-   zTavily search: '%s' (limit: %d)r\  rm  )rO  rq  Úinclude_raw_contentÚinclude_imagesz'Searching the web for: '%s' (limit: %d)zFound %d search resultsTrˆ   zError searching web: ú%sr^   )r[  rS  Ú
tool_errorr9   rt  rñ   r$   rv   ÚdumpsÚ_debugÚlog_callÚsaver]  r]   rz   r€   r  r�   rf   r\  rÄ   r&   rœ   ró   )rO  rP  Údebug_call_datarS  r)   Úresponse_dataÚresult_jsonrž   r   r�   r~  r  Ú	error_msgs                r   r…  r…    s  € ðH Øð
ð 
ð ØØ"#Ø ð	ð 	€OðR%Ø2Ð2Ð2Ð2Ð2Ð2Øˆ>ÑÔð 	<Ý˜m°UÐ;Ñ;Ô;Ð;õ ‘.”.ˆØ�jÒ Ð Ý,¨U°EÑ:Ô:ˆMÝ/2°=×3DÒ3DÀVÈRÑ3PÔ3P×3TÒ3TÐUZÐ\^Ñ3_Ô3_Ñ/`Ô/`ˆO˜OÑ,Ýœ* ]¸1È5ÐQÑQÔQˆKÝ58¸Ñ5EÔ5EˆOÐ1Ñ2Ý�OŠOÐ-¨Ñ?Ô?Ð?Ý�KŠK‰MŒMˆMØÐà�eÒÐÝ'¨¨uÑ5Ô5ˆMÝ/2°=×3DÒ3DÀVÈRÑ3PÔ3P×3TÒ3TÐUZÐ\^Ñ3_Ô3_Ñ/`Ô/`ˆO˜OÑ,Ýœ* ]¸1È5ÐQÑQÔQˆKÝ58¸Ñ5EÔ5EˆOÐ1Ñ2Ý�OŠOÐ-¨Ñ?Ô?Ð?Ý�KŠK‰MŒMˆMØÐà�hÒÐÝ�KŠKÐ9¸5À%ÑHÔHÐHÝ! (ØÝ" 5¨"™~œ~Ø',Ø"'ð	-ð -ñ ô ˆCõ =¸SÑAÔAˆMÝ/2°=×3DÒ3DÀVÈRÑ3PÔ3P×3TÒ3TÐUZÐ\^Ñ3_Ô3_Ñ/`Ô/`ˆO˜OÑ,Ýœ* ]¸1È5ÐQÑQÔQˆKÝ58¸Ñ5EÔ5EˆOÐ1Ñ2Ý�OŠOÐ-¨Ñ?Ô?Ð?Ý�KŠK‰MŒMˆMØÐå�ŠÐ=¸uÀeÑLÔLÐLå(Ñ*Ô*×1Ò1ØØð 2ñ 
ô 
ˆõ
 2°(Ñ;Ô;ˆÝ˜KÑ(Ô(ˆÝ�ŠÐ-¨}Ñ=Ô=Ð=ð à�{ðð
ð 
ˆð ,9ˆ˜Ñ(õ ”j °qÀuÐMÑMÔMˆå14°[Ñ1AÔ1AˆÐ-Ñ.õ 	�ŠÐ)¨?Ñ;Ô;Ð;Ý�Š‰ŒˆàÐøåð %ð %ð %Ø4­C°©F¬FÐ4Ð4ˆ	Ý�Š�T˜9Ñ%Ô%Ð%à#,ˆ˜Ñ Ý�ŠÐ)¨?Ñ;Ô;Ð;Ý�Š‰Œˆå˜)Ñ$Ô$Ð$Ð$Ð$Ð$Ð$Ð$øøøøð%øøøs9   � M* ®B<M* Ã+B.M* ÆC,M* ÊC"M* Í*
O3Í4A4O.Ï(O3Ï.O3TÚformatÚuse_llm_processingc              ƒ   óN  ‡‡,‡-K  — ddl m} ddlm} | D ]N}|                     |¦  «        s|                      ||¦  «        ¦  «        rt          j        dddœ¦  «        c S ŒO| |||‰dœdddddg g d	œ}	 t                               d
t          | ¦  «        ¦  «         g }	g }
| D ]A}t          |¦  «        s|
                     |ddddœ¦  «         Œ,|	                     |¦  «         ŒB|	sg }�nÖt          ¦   «         }|dk    rt          |	¦  «        ƒ d{V —†}�n«|dk    rt          |	¦  «        }�n”|dk    rXt                               dt          |	¦  «        ¦  «         t          d|	ddœ¦  «        }t!          ||	r|	d         nd¬¦  «        }�n6g }|dk    rdg}n|dk    rdg}nddg}g }ddlm} |	D �]} |¦   «         r|                     |dddœ¦  «         Œ't'          |¦  «        }|r`t                               d|d         |d         ¦  «         |                     |dd|d         |d         |d         |d         dœd œ¦  «         Œ˜	 t                               d!|¦  «         	 t)          j        t)          j        t/          ¦   «         j        ||¬"¦  «        d#¬$¦  «        ƒ d{V —†}nK# t(          j        $ r9 t                               d%|¦  «         |                     |ddd&dœ¦  «         Y �Œ?w xY wt7          |¦  «        }|                     d'i ¦  «        }d}|                     d¦  «        }|                     d¦  «        }t;          |t<          ¦  «        s?t?          |d(¦  «        r|                      ¦   «         }nt?          |d)¦  «        r|j!        }ni }|                     d*d¦  «        }|                     d+|¦  «        }t'          |¦  «        }|rbt                               d,|d         |d         ¦  «         |                     ||dd|d         |d         |d         |d         dœd-œ¦  «         �Œ‡|dk    s|€|r|n|p|pd}|                     |||||d.œ¦  «         �Œ¶# tD          $ rO}t           #                    d/||¦  «         |                     |dddtI          |¦  «        d0œ¦  «         Y d}~�Œ
d}~ww xY w|
r|
|z   }d1|i}t          |                     d1g ¦  «        ¦  «        }t                               d2|¦  «         ||d3<   t          t          j        |¦  «        ¦  «        |d4<   |ptK          ¦   «         Š,tM          ¦   «         }|�r;|�r8t                               d5¦  «         |d6                              d7¦  «         ˆ,ˆfd8„Š-|                     d1g ¦  «        }ˆ-fd9„|D ¦   «         } t)          j'        | Ž ƒ d{V —†}!|!D ]Á\  }"}#}$|"                     d:d;¦  «        }|$d<k    rG|d=                              |#¦  «         |d>xx         d?z  cc<   t                               d@|¦  «         Œi|$dAk    r7|d=                              |#¦  «         t                               dB|¦  «         Œ¦t                               dC|¦  «         ŒÂn§|r7|s5t                               dD¦  «         |d6                              dE¦  «         |                     d1g ¦  «        D ]W}"|"                     d:d;¦  «        }t          |"                     dFd¦  «        ¦  «        }%t                               dG||%¦  «         ŒXdH„ |                     d1g ¦  «        D ¦   «         }&d1|&i}'|'                     d1¦  «        g k    rtQ          dI¦  «        }(tS          |(¦  «        })n&t          j        |'dJd¬K¦  «        }(tS          |(¦  «        })t          |)¦  «        |dL<   |d6                              dM¦  «         tT           +                    dN|¦  «         tT           ,                    ¦   «          |)S # tD          $ r}*dOtI          |*¦  «        › �}+t           #                    dP|+¦  «         |+|dQ<   tT           +                    dN|¦  «         tT           ,                    ¦   «          tQ          |+¦  «        cY d}*~*S d}*~*ww xY w)Ra#  
    Extract content from specific web pages using available extraction API backend.

    This function provides a generic interface for web content extraction that
    can work with multiple backends. Currently uses Firecrawl.

    Args:
        urls (List[str]): List of URLs to extract content from
        format (str): Desired output format ("markdown" or "html", optional)
        use_llm_processing (bool): Whether to process content with LLM for summarization (default: True)
        model (Optional[str]): The model to use for LLM processing (defaults to current auxiliary backend model)
        min_length (int): Minimum content length to trigger LLM processing (default: 5000)

    Security: URLs are checked for embedded secrets before fetching.
    
    Returns:
        str: JSON string containing extracted content. If LLM processing is enabled and successful,
             the 'content' field will contain the processed markdown summary instead of raw content.
    
    Raises:
        Exception: If extraction fails or API key is not set
    r   )Ú
_PREFIX_RE)ÚunquoteFz_Blocked: URL contains what appears to be an API key or token. Secrets must not be sent in URLs.)r‰   r^   )r^  r’  r“  rÔ   ræ   N)r}  r^   Úpages_extractedÚpages_processed_with_llmr  r€  Úcompression_metricsÚprocessing_appliedz!Extracting content from %d URL(s)r*   ú:Blocked: URL targets a private or internal network address©r~   rƒ   r„   r^   r+   r.   r-   zTavily extract: %d URL(s)rx  )r^  r‡  ©r‘   ÚmarkdownÚhtmlrR  rT  rb  z%Blocked web_extract for %s by rule %srÒ   ÚrulerP   Úsource©rÒ   r   r¡  ©r~   rƒ   r„   r^   Úblocked_by_policyzScraping: %s)r~   Úformatsru   )rw   z!Firecrawl scrape timed out for %suc   Scrape timed out after 60s â€” page may be too large or unresponsive. Try browser_navigate instead.r—   r¥   r¦   rƒ   r•   z0Blocked redirected web_extract for %s by rule %s©r~   rƒ   r„   r“   r^   r¤  r–   zScrape failed for %s: %s)r~   rƒ   r„   r“   r^   r‚   zExtracted content from %d pagesr—  r  z3Processing extracted content with LLM (parallel)...rš  Úllm_processingc              “   óœ  •K  — |                       dd¦  «        }|                       dd¦  «        }|                       dd¦  «        p|                       dd¦  «        }|s| ddfS t          |¦  «        }t          |||‰	‰
¦  «        ƒ d{V —†}|r3t          |¦  «        }|d	k    r||z  nd
}|| d<   || d<   ||||‰	dœ}| |dfS |||d
dddœ}| |dfS )zHProcess a single result with LLM and return updated result with metrics.r~   úUnknown URLrƒ   r*   r“   r„   NÚ
no_contentr   rì   ©r~   Úoriginal_sizeÚprocessed_sizer  Ú
model_usedÚ	processedÚcontent_too_short©r~   r¬  r­  r  r®  ÚreasonÚ	too_short©r$   rñ   r  )r�   r~   rƒ   r“   r¬  r¯  r­  r  ÚmetricsrÝ   ræ   s            €€r   Úprocess_single_resultz/web_extract_tool.<locals>.process_single_resultd  sR  øè è € à—j’j ¨Ñ6Ô6�ØŸ
š
 7¨BÑ/Ô/�Ø$Ÿjšj¨¸Ñ;Ô;ÐX¸v¿zºzÈ)ÐUWÑ?XÔ?X�à"ð 6Ø! 4¨Ð5Ð5å # KÑ 0Ô 0�õ #;Ø  e¨_¸jñ#ô #ð ð ð ð ð ð �	ð ð 8Ý%(¨¡^¤^�NØJWÐZ[ÒJ[ÐJ[¨¸Ñ(FÐ(FÐadÐ%ð )2�F˜9Ñ%Ø,7�F˜=Ñ)ð  #Ø)6Ø*8Ø->Ø&5ðð �Gð " 7¨KÐ7Ð7ð  #Ø)6Ø*7Ø-0Ø&*Ø"5ðð �Gð " 7¨KÐ7Ð7r   c                 ó&   •— g | ]} ‰|¦  «        ‘ŒS rF   rF   )r¬   r�   r¶  s     €r   r/  z$web_extract_tool.<locals>.<listcomp>‘  s%   ø€ ÐNÐNÐN°vÐ*Ð*¨6Ñ2Ô2ÐNÐNÐNr   r~   r©  r¯  r™  r˜  r…   ú%s (processed)r³  ú&%s (no processing - content too short)ú%s (no content to process)úPLLM processing requested but no auxiliary model available, returning raw contentÚllm_processing_unavailabler“   ú%s (%d characters)c                 óÚ   — g | ]h}|                      d d¦  «        |                      dd¦  «        |                      dd¦  «        |                      d¦  «        dœd|v r
d|d         ini ¥‘ŒiS ©r~   r*   rƒ   r„   r^   rœ  r¤  ©r$   ©r¬   Úrs     r   r/  z$web_extract_tool.<locals>.<listcomp>«  óš   € ð 	
ð 	
ð 	
ð ð —u’u˜U BÑ'Ô'ØŸš˜w¨Ñ+Ô+ØŸ5š5 ¨BÑ/Ô/ØŸš˜w™œð	ð ð
 GZÐ]^ÐF^ÐF^Ð)¨1Ð-@Ô+AÐBÐBÐdfðð	
ð 	
ð 	
r   z%Content was inaccessible or not foundr
  r‚  r€  Úbase64_image_removalÚweb_extract_toolzError extracting content: rˆ  r^   )-Úagent.redactr•  rÏ   r–  r\  rv   rŠ  r]   rz   rñ   r   rŒ   r9   r{  rg  r€   r¢   r[  rS  r   r  Úwait_forÚ	to_threadrf   ÚscrapeÚTimeoutErrorrò   rÉ   r$   r›   r°   r´   r¥   r¦   r&   ró   rœ   râ   Úcheck_auxiliary_modelr5  r‰  rG  r‹  rŒ  r�  ).r^  r’  r“  rÔ   ræ   r•  r–  Ú_urlrŽ  Ú	safe_urlsÚssrf_blockedr~   r‚   r)   rž   r¥  Ú_is_interruptedÚblockedrÅ   Úscrape_payloadr—   rƒ   Úcontent_markdownÚcontent_htmlÚ	final_urlÚfinal_blockedÚchosen_contentÚ
scrape_errr   r—  Úauxiliary_availableÚresults_listr7  Úprocessed_resultsr�   rµ  ÚstatusÚcontent_lengthÚtrimmed_resultsÚtrimmed_responser�  Úcleaned_resultr  r‘  rÝ   r¶  s.       `                                       @@r   rÅ  rÅ  �  s4  øøøè è € ð> (Ð'Ð'Ð'Ð'Ð'Ø$Ð$Ð$Ð$Ð$Ð$Øð ð ˆØ×Ò˜TÑ"Ô"ð 	 j×&7Ò&7¸¸À¹¼Ñ&FÔ&Fð 	Ý”:Ø ð=ðð ñ ô ð ð ð ð	ð ØØ"4ØØ$ð
ð 
ð ØØ$%Ø"#Ø Ø!Ø ðð €Oð"K%Ý�ŠÐ7½¸T¹¼ÑCÔCÐCð ˆ	Ø-/ˆØð 	&ð 	&ˆCÝ˜sÑ#Ô#ð &Ø×#Ò#Ø¨¸ØYð%ð %ñ ô ð ð ð
 × Ò  Ñ%Ô%Ð%Ð%ð ð w	ØˆG‰Gå"‘n”nˆGà˜*Ò$Ð$Ý 1°)Ñ <Ô <Ð<Ð<Ð<Ð<Ð<Ð<�‘Ø˜EÒ!Ð!Ý& yÑ1Ô1�‘Ø˜HÒ$Ð$Ý—’Ð7½¸Y¹¼ÑHÔHÐHÝ% iØ%Ø&+ð2ð 2ñ ô �õ 6°cÐXaÐHiÈ	ÐRSÌÈÐgiÐjÑjÔj�‘ð &(�Ø˜ZÒ'Ð'Ø)˜l�G�GØ˜vÒ%Ð%Ø%˜h�G�Gð  *¨6Ð2�Gð 13�àMÐMÐMÐMÐMÐMØ$ð Vñ V�CØ&�Ñ(Ô(ð !ØŸš¨s¸]ÐUWÐ'XÐ'XÑYÔYÐYØ õ 3°3Ñ7Ô7�GØð !ÝŸšÐ$KÈWÐU[Ì_Ð^eÐflÔ^mÑnÔnÐnØŸšØ#&°ÀØ%,¨YÔ%7Ø:AÀ&¼/ÐSZÐ[aÔSbÐnuÐv~Ônð  2Að  2Að(ð (ñ ô ð ð
 !ðFÝŸš N°CÑ8Ô8Ð8ð%Ý29Ô2BÝ 'Ô 1Ý$9Ñ$;Ô$;Ô$BØ(+Ø,3ð!"ñ !"ô !"ð
 )+ð3ñ 3ô 3ð -ð -ð -ð -ð -ð -˜M˜Møõ  'Ô3ð %ð %ð %Ý"ŸNšNÐ+NÐPSÑTÔTÐTØ#ŸNšNØ'*°RÀBð *Oð,ð ,ñ ô ð ð %™Hð%øøøõ *AÀÑ)OÔ)O˜Ø#1×#5Ò#5°jÀ"Ñ#EÔ#E˜Ø "˜Ø+9×+=Ò+=¸jÑ+IÔ+IÐ(Ø'5×'9Ò'9¸&Ñ'AÔ'A˜õ  *¨(µDÑ9Ô9ð .Ý& x°Ñ>Ô>ð .Ø+3×+>Ò+>Ñ+@Ô+@  Ý!(¨°:Ñ!>Ô!>ð .Ø+3Ô+<  à+- ð !)§¢¨W°bÑ 9Ô 9˜ð %-§L¢L°¸cÑ$BÔ$B˜	Ý(<¸YÑ(GÔ(G˜Ø(ð %Ý"ŸKšKÐ(ZÐ\iÐjpÔ\qð  tAð  BHô  tIñ  Jô  Jð  JØ#ŸNšNØ'0¸5ÈRÐ`bØ)6°yÔ)AØ>KÈFÔ>SÐ]jÐkqÔ]rð  Lð  MUô  Vð  6Wð  6Wð,ð ,ñ ô ð ñ
 %ð ?EÈ
Ò>RÐ>RÐW]ÐWeÐjzÐWeÐ)9Ð)9ð  COð  Cið  Scð  Cið  gi˜àŸšØ#,Ø%*Ø'5Ø+9Ø(0ð(ð (ñ ô ð ñ øõ %ð ð ð ÝŸšÐ%?ÀÀjÑQÔQÐQØŸšØ#&Ø%'Ø')Ø+-Ý%(¨¡_¤_ð(ð (ñ ô ð ð ð ð ð ñ øøøøðøøøð ð 	-Ø" WÑ,ˆGà˜wÐ'ˆå˜hŸlšl¨9°bÑ9Ô9Ñ:Ô:ˆÝ�ŠÐ5°ÑGÔGÐGà-<ˆÐ)Ñ*Ý47½¼
À8Ñ8LÔ8LÑ4MÔ4MˆÐ0Ñ1ØÐBÕ#@Ñ#BÔ#BˆÝ3Ñ5Ô5Ðð ñ I	GÐ"5ñ I	GÝ�KŠKÐMÑNÔNÐNØÐ0Ô1×8Ò8Ð9IÑJÔJÐJð)8ð )8ð )8ð )8ð )8ð )8ðX $Ÿ<š<¨	°2Ñ6Ô6ˆLØNÐNÐNÐNÀÐNÑNÔNˆEÝ&-¤n°eÐ&<Ð <Ð <Ð <Ð <Ð <Ð <Ðð ,=ð 
Fð 
FÑ'�˜ Ø—j’j ¨Ñ6Ô6�Ø˜[Ò(Ð(Ø#Ð$9Ô:×AÒAÀ'ÑJÔJÐJØ#Ð$>Ð?Ð?Ô?À1ÑDÐ?Ð?Ñ?Ý—K’KÐ 0°#Ñ6Ô6Ð6Ð6Ø˜{Ò*Ð*Ø#Ð$9Ô:×AÒAÀ'ÑJÔJÐJÝ—K’KÐ HÈ#ÑNÔNÐNÐNå—N’NÐ#?ÀÑEÔEÐEÐEð
Fð "ð [Ð*=ð [Ý—’ÐqÑrÔrÐrØÐ 4Ô5×<Ò<Ð=YÑZÔZÐZà"Ÿ,š, y°"Ñ5Ô5ð Gð G�Ø—j’j ¨Ñ6Ô6�Ý!$ V§Z¢Z°¸rÑ%BÔ%BÑ!CÔ!C�Ý—’Ð0°#°~ÑFÔFÐFÐFð	
ð 	
ð —\’\ )¨RÑ0Ô0ð	
ñ 	
ô 	
ˆð & Ð7Ðà×Ò 	Ñ*Ô*¨bÒ0Ð0Ý$Ð%LÑMÔMˆKå0°Ñ=Ô=ˆNˆNõ œ*Ð%5¸aÈeÐTÑTÔTˆKå0°Ñ=Ô=ˆNå14°^Ñ1DÔ1DˆÐ-Ñ.ØÐ,Ô-×4Ò4Ð5KÑLÔLÐLõ 	�ŠÐ*¨OÑ<Ô<Ð<Ý�Š‰ŒˆàÐøåð %ð %ð %Ø9µ°Q±´Ð9Ð9ˆ	Ý�Š�T˜9Ñ%Ô%Ð%à#,ˆ˜Ñ Ý�ŠÐ*¨OÑ<Ô<Ð<Ý�Š‰Œˆå˜)Ñ$Ô$Ð$Ð$Ð$Ð$Ð$Ð$øøøøð%øøøs…   Á5G` ÉQ%É$AJ'Ê&Q%Ê'AK/Ë+Q%Ë,` Ë.K/Ë/EQ%Ð4` Ð6-Q%Ñ#` Ñ%
R>Ñ/AR9Ò3` Ò9R>Ò>M` à
b$à%A4bâb$âb$ÚbasicÚinstructionsÚdepthc              ƒ   ó4  ‡‡,‡-‡.K  — | ||||‰dœdddddg g dœ}	 |pt          ¦   «         Š-t          ¦   «         }t          ¦   «         }|dk    �r|                      d¦  «        sd| › �} t	          | ¦  «        st          j        d| d	d	d
dœgid¬¦  «        S t          | ¦  «        }	|	rct           	                    d|	d         |	d         ¦  «         t          j        d| d	d	|	d         |	d         |	d         |	d         dœdœgid¬¦  «        S ddl
m}
  |
¦   «         rt          dd¬¦  «        S t           	                    d| ¦  «         | d|dœ}|r||d<   t          d|¦  «        }t          || ¬¦  «        }d|i}t          |                     dg ¦  «        ¦  «        }t           	                    d|¦  «         ||d<   t          t          j        |¦  «        ¦  «        |d <   |r­|r«t           	                    d!¦  «         |d"                              d#¦  «         ˆ-ˆfd$„Š,ˆ,fd%„|                     dg ¦  «        D ¦   «         }t%          j        |Ž ƒ d{V —†}|D ]7\  }}}|d&k    r+|d'                              |¦  «         |d(xx         d)z  cc<   Œ8|r7|s5t                               d*¦  «         |d"                              d+¦  «         d,„ |                     dg ¦  «        D ¦   «         }t          j        d|id-d¬.¦  «        }t+          |¦  «        }t          |¦  «        |d/<   t,                               d0|¦  «         t,                               ¦   «          |S t3          ¦   «         s)t          j        d1t5          ¦   «         › d2�dd3œd¬¦  «        S |                      d¦  «        s d| › �} t           	                    d4| ¦  «         |rd5|› d6�nd	}t           	                    d7| |¦  «         t	          | ¦  «        st          j        d| d	d	d
dœgid¬¦  «        S t          | ¦  «        }	|	rct           	                    d|	d         |	d         ¦  «         t          j        d| d	d	|	d         |	d         |	d         |	d         dœdœgid¬¦  «        S dd8d9gid:œ}|rt           	                    d;¦  «         ddl
m}
  |
¦   «         rt          dd¬¦  «        S 	  t7          ¦   «         j        ddd<| i|¤Ž}n.# t:          $ r!}t                               d=|¦  «         ‚ d}~ww xY wg }g }t?          |d>¦  «        �r|j         r|j         ng }t           	                    d?tC          |d@dA¦  «        ¦  «         t           	                    dBt          |¦  «        ¦  «         |s°t                               dCdD„ tE          |¦  «        D ¦   «         ¦  «         t                               d?tC          |d@dE¦  «        ¦  «         t                               dFtC          |dGdE¦  «        ¦  «         t                               dHtC          |dIdE¦  «        ¦  «         nÁtG          |tH          ¦  «        rd>|v r|                     d>g ¦  «        }n‘t                               dJ¦  «         t                               dKtK          |¦  «        ¦  «         t?          |dL¦  «        r?t                               dMtM          |j'         (                    ¦   «         ¦  «        ¦  «         |D �]Š}dN}d	} d}!d}"i }#t?          |dO¦  «        rU| )                    ¦   «         }$|$                     d9¦  «        }!|$                     dP¦  «        }"|$                     dQi ¦  «        }#nðt?          |dL¦  «        r‹tC          |d9d¦  «        }!tC          |dPd¦  «        }"tC          |dQi ¦  «        }%t?          |%dO¦  «        r|% )                    ¦   «         }#nˆt?          |%dL¦  «        r|%j'        }#nptG          |%tH          ¦  «        r|%}#nXi }#nUtG          |tH          ¦  «        r@|                     d9¦  «        }!|                     dP¦  «        }"|                     dQi ¦  «        }#tG          |#tH          ¦  «        s?t?          |#dO¦  «        r|# )                    ¦   «         }#nt?          |#dL¦  «        r|#j'        }#ni }#|#                     dR|#                     d<dN¦  «        ¦  «        }|#                     dSd	¦  «        } t          |¦  «        }&|&rbt           	                    dT|&d         |&d         ¦  «         |                     || d	d	|&d         |&d         |&d         |&d         dœdUœ¦  «         �Œi|!p|"pd	}'|                     || |'|'|#dVœ¦  «         �ŒŒd|i}t          |                     dg ¦  «        ¦  «        }t           	                    d|¦  «         ||d<   t          t          j        |¦  «        ¦  «        |d <   |�r;|�r8t           	                    d!¦  «         |d"                              d#¦  «         ˆ-ˆfdW„Š.|                     dg ¦  «        }(ˆ.fdX„|(D ¦   «         }t%          j        |Ž ƒ d{V —†}|D ]Á\  }}}|                     d<dN¦  «        }|d&k    rG|d'                              |¦  «         |d(xx         d)z  cc<   t           	                    dY|¦  «         Œi|dZk    r7|d'                              |¦  «         t           	                    d[|¦  «         Œ¦t                               d\|¦  «         ŒÂn§|r7|s5t                               d*¦  «         |d"                              d+¦  «         |                     dg ¦  «        D ]W}|                     d<dN¦  «        }t          |                     d]d	¦  «        ¦  «        })t           	                    d^||)¦  «         ŒXd_„ |                     dg ¦  «        D ¦   «         }d|i}*t          j        |*d-d¬.¦  «        }t+          |¦  «        }t          |¦  «        |d/<   |d"                              d`¦  «         t,                               d0|¦  «         t,                               ¦   «          |S # t:          $ r}datU          |¦  «        › �}+t                               db|+¦  «         |+|dc<   t,                               d0|¦  «         t,                               ¦   «          t          |+¦  «        cY d}~S d}~ww xY w)ea�  
    Crawl a website with specific instructions using available crawling API backend.
    
    This function provides a generic interface for web crawling that can work
    with multiple backends. Currently uses Firecrawl.
    
    Args:
        url (str): The base URL to crawl (can include or exclude https://)
        instructions (str): Instructions for what to crawl/extract using LLM intelligence (optional)
        depth (str): Depth of extraction ("basic" or "advanced", default: "basic")
        use_llm_processing (bool): Whether to process content with LLM for summarization (default: True)
        model (Optional[str]): The model to use for LLM processing (defaults to current auxiliary backend model)
        min_length (int): Minimum content length to trigger LLM processing (default: 5000)
    
    Returns:
        str: JSON string containing crawled content. If LLM processing is enabled and successful,
             the 'content' field will contain the processed markdown summary instead of raw content.
             Each page is processed individually.
    
    Raises:
        Exception: If crawling fails or API key is not set
    )r~   rá  râ  r“  rÔ   ræ   Nr   )r}  r^   Úpages_crawledr˜  r  r€  r™  rš  r-   )zhttp://úhttps://rå  r‚   r*   r›  rœ  F)r„  z#Blocked web_crawl for %s by rule %srÒ   r   rP   r¡  r¢  r£  rR  rT  r�  zTavily crawl: %srm  )r~   rP  Úextract_depthrá  Úcrawlr�  zCrawled %d pagesrä  r  z1Processing crawled content with LLM (parallel)...rš  r§  c              “   óz  •K  — |                       dd¦  «        }|                       dd¦  «        }|                       dd¦  «        }|s| d dfS t          |¦  «        }t          |||‰‰¦  «        ƒ d {V —†}|r8|| d<   || d<   ||t          |¦  «        |rt          |¦  «        |z  nd‰d	œ}| |d
fS |||dd ddœ}| |dfS )Nr~   r©  rƒ   r*   r„   rª  r“   rì   r«  r¯  r°  r±  r³  r´  )	r�   Úpage_urlrƒ   r„   r¬  r¯  rµ  rÝ   ræ   s	          €€r   Ú_process_tavily_crawlz-web_crawl_tool.<locals>._process_tavily_crawl8  s  øè è € Ø%Ÿzšz¨%°Ñ?Ô?�HØ"ŸJšJ w°Ñ3Ô3�EØ$Ÿjšj¨°BÑ7Ô7�GØ"ð :Ø% t¨\Ð9Ð9Ý$'¨¡L¤L�MÝ&>¸wÈÐRWÐYhÐjtÑ&uÔ&uÐ uÐ uÐ uÐ uÐ uÐ u�IØ ð <Ø07˜˜}Ñ-Ø,5˜˜yÑ)Ø*2À]ÕfiÐjsÑftÔftØZgÐ8p½¸I¹¼ÈÑ8VÐ8VÐmpð  APð#Qð #Q˜à% w°Ð;Ð;Ø&.ÀÐboØ47ÀtÐWjðlð l�Gà! 7¨KÐ7Ð7r   c                 ó&   •— g | ]} ‰|¦  «        ‘ŒS rF   rF   )r¬   rÂ  rê  s     €r   r/  z"web_crawl_tool.<locals>.<listcomp>J  s%   ø€ ÐWÐWÐW°aÐ.Ð.¨qÑ1Ô1ÐWÐWÐWr   r¯  r™  r˜  r…   r»  r¼  c                 óÚ   — g | ]h}|                      d d¦  «        |                      dd¦  «        |                      dd¦  «        |                      d¦  «        dœd|v r
d|d         ini ¥‘ŒiS r¿  rÀ  rÁ  s     r   r/  z"web_crawl_tool.<locals>.<listcomp>U  s¾   € ð Oð Oð OØmnð ()§u¢u¨U°BÑ'7Ô'7À!Ç%Â%ÈÐQSÑBTÔBTÐab×afÒafÐgpÐrtÑauÔauð  AB÷  AFò  AFð  GNñ  AOô  AOð  ið  iØFYÐ]^ÐF^ÐF^Ð)¨1Ð-@Ô+AÐBÐBÐdfð ið Oð Oð Or   r
  r‚  r€  Úweb_crawl_toolzFweb_crawl requires Firecrawl. Set FIRECRAWL_API_KEY, FIRECRAWL_API_URLz*, or use web_search + web_extract instead.rU  z Added https:// prefix to URL: %sz with instructions: 'ú'zCrawling %s%sr¥  rž  )rP  Úscrape_optionsz;Instructions parameter ignored (not supported in crawl API)r~   zCrawl API call failed: %srŠ   z
Status: %srÛ  ÚunknownzRetrieved %d pageszCrawlJob attributes: %sc                 ó<   — g | ]}|                      d ¦  «        °|‘ŒS r¨   rª   )r¬   Úattrs     r   r/  z"web_crawl_tool.<locals>.<listcomp>¥  s-   € Ð8xÐ8xÐ8xÀ$Ðcg×crÒcrÐsvÑcwÔcwÐ8x¸Ð8xÐ8xÐ8xr   zN/Az	Total: %sÚtotalzCompleted: %sÚ	completedzUnexpected crawl result typezResult type: %sr¦   zResult attributes: %sr©  r¥   rŸ  r—   r•   rƒ   z"Blocked crawled page %s by rule %sr¦  r–   c              “   óp  •K  — |                       dd¦  «        }|                       dd¦  «        }|                       dd¦  «        }|s| ddfS t          |¦  «        }t          |||‰	‰
¦  «        ƒ d{V —†}|r3t          |¦  «        }|dk    r||z  nd	}|| d
<   || d<   ||||‰	dœ}| |dfS |||d	dddœ}| |dfS )zNProcess a single crawl result with LLM and return updated result with metrics.r~   r©  rƒ   r*   r„   Nrª  r   rì   r“   r«  r¯  r°  r±  r³  r´  )r�   ré  rƒ   r„   r¬  r¯  r­  r  rµ  rÝ   ræ   s            €€r   Úprocess_single_crawl_resultz3web_crawl_tool.<locals>.process_single_crawl_result  s<  øè è € à!Ÿ:š: e¨]Ñ;Ô;�ØŸ
š
 7¨BÑ/Ô/�Ø Ÿ*š* Y°Ñ3Ô3�àð 6Ø! 4¨Ð5Ð5å # G¡¤�õ #;Ø˜X u¨o¸zñ#ô #ð ð ð ð ð ð �	ð ð 8Ý%(¨¡^¤^�NØJWÐZ[ÒJ[ÐJ[¨¸Ñ(FÐ(FÐadÐ%ð -4�F˜=Ñ)Ø(1�F˜9Ñ%ð  (Ø)6Ø*8Ø->Ø&5ðð �Gð " 7¨KÐ7Ð7ð  (Ø)6Ø*7Ø-0Ø&*Ø"5ðð �Gð " 7¨KÐ7Ð7r   c                 ó&   •— g | ]} ‰|¦  «        ‘ŒS rF   rF   )r¬   r�   rö  s     €r   r/  z"web_crawl_tool.<locals>.<listcomp>4  s%   ø€ ÐTÐTÐT¸VÐ0Ð0°Ñ8Ô8ÐTÐTÐTr   r¸  r³  r¹  rº  r„   r½  c                 óÚ   — g | ]h}|                      d d¦  «        |                      dd¦  «        |                      dd¦  «        |                      d¦  «        dœd|v r
d|d         ini ¥‘ŒiS r¿  rÀ  rÁ  s     r   r/  z"web_crawl_tool.<locals>.<listcomp>N  rÃ  r   rÄ  zError crawling website: rˆ  r^   rF   )+râ   rË  r9   r«   r   rv   rŠ  r   r]   rz   r[  rS  r‰  r€   r¢   rñ   r$   rŒ   r  r5  rò   rG  r‹  rŒ  r�  r;   rS   rf   rç  r&   ró   r´   rŠ   r¾   Údirr›   r°   Útyper±   r¦   Úkeysr¥   rœ   )/r~   rá  râ  r“  rÔ   ræ   rŽ  rØ  r)   rÐ  Ú_is_intrs   rž   r‚   r   rä  r7  rÚ  r�   rµ  rÛ  rÝ  r�  rß  Úinstructions_textÚcrawl_paramsÚcrawl_resultr  ÚpagesÚ	data_listrº   ré  rƒ   rÒ  rÓ  r—   Ú	item_dictÚmetadata_objÚpage_blockedr„   rÙ  rÜ  rÞ  r‘  rê  rÝ   rö  s/        `                                      @@@r   rí  rí  Õ  s«  øøøøè è € ð@ Ø(ØØ"4ØØ$ð
ð 
ð ØØ$%Ø"#Ø Ø!Ø ðð €Oð$j%ØÐBÕ#@Ñ#BÔ#BˆÝ3Ñ5Ô5ÐÝ‘.”.ˆð �hÒÑà—>’>Ð"9Ñ:Ô:ð 'Ø& Ð&Ð&�õ ˜sÑ#Ô#ð rÝ”z 9°sÀRÐTVØYð0[ð 0[ð /\ð #]Økpðrñ rô rð rõ +¨3Ñ/Ô/ˆGØð QÝ—’ÐAÀ7È6Ä?ÐT[Ð\bÔTcÑdÔdÐdÝ”z 9°sÀRÐTVÐahÐirÔasØ29¸&´/È7ÐSYÌ?ÐfmÐnvÔfwÐ)xÐ)xð0zð 0zð /{ð #|ð KPðQñ Qô Qð Qð BÐAÐAÐAÐAÐAØˆw‰yŒyð @Ý! -¸Ð?Ñ?Ô?Ð?å�KŠKÐ*¨CÑ0Ô0Ð0àØØ!&ð'ð 'ˆGð
 ð 7Ø*6�˜Ñ'Ý! '¨7Ñ3Ô3ˆCÝ1°#ÀCÐHÑHÔHˆGà! 7Ð+ˆHõ   §¢¨Y¸Ñ ;Ô ;Ñ<Ô<ˆMÝ�KŠKÐ*¨MÑ:Ô:Ð:Ø/<ˆO˜OÑ,Ý8;½D¼JÀxÑ<PÔ<PÑ8QÔ8QˆOÐ4Ñ5ð "ð IÐ&9ð IÝ—’ÐOÑPÔPÐPØÐ 4Ô5×<Ò<Ð=MÑNÔNÐNð8ð 8ð 8ð 8ð 8ð 8ð$ XÐWÐWÐW¸8¿<º<È	ÐSUÑ;VÔ;VÐWÑWÔW�Ý*1¬.¸%Ð*@Ð$@Ð$@Ð$@Ð$@Ð$@Ð$@Ð!Ø/@ð Ið IÑ+�F˜G VØ Ò,Ð,Ø'Ð(=Ô>×EÒEÀgÑNÔNÐNØ'Ð(BÐCÐCÔCÀqÑHÐCÐCÑCøà!ð [Ð*=ð [Ý—’ÐqÑrÔrÐrØÐ 4Ô5×<Ò<Ð=YÑZÔZÐZðOð OØrz×r~Òr~ð  @Ið  KMñ  sNô  sNðOñ Oô OˆOåœ* i°Ð%AÈ!ÐZ_Ð`Ñ`Ô`ˆKÝ0°Ñ=Ô=ˆNÝ58¸Ñ5HÔ5HˆOÐ1Ñ2Ý�OŠOÐ,¨oÑ>Ô>Ð>Ý�KŠK‰MŒMˆMØ!Ð!õ 'Ñ(Ô(ð 	#Ý”:ðiÝ:Ñ<Ô<ðið ið ià ðð ð "ð	#ñ #ô #ð #ð �~Š~Ð5Ñ6Ô6ð 	AØ"˜SÐ"Ð"ˆCÝ�KŠKÐ:¸CÑ@Ô@Ð@àGSÐ[ÐC°LÐCÐCÐCÐCÐY[ÐÝ�Š�O SÐ*;Ñ<Ô<Ð<õ ˜3ÑÔð 	nÝ”:˜y°3ÀÐPRØUð,Wð ,Wð +Xð YØglðnñ nô nð nõ ' sÑ+Ô+ˆØð 	MÝ�KŠKÐ=¸wÀv¼ÐPWÐX^ÔP_Ñ`Ô`Ð`Ý”:˜y°3ÀÐPRÐ]dÐenÔ]oØ.5°f¬oÀwÈvÄÐbiÐjrÔbsÐ%tÐ%tð,vð ,vð +wð xð GLðMñ Mô Mð Mð à˜J˜<ðð
ð 
ˆð ð 	WÝ�KŠKÐUÑVÔVÐVà=Ð=Ð=Ð=Ð=Ð=Øˆ7‰9Œ9ð 	<Ý˜m°UÐ;Ñ;Ô;Ð;ð	Ø8Õ0Ñ2Ô2Ô8ð ð Øðàðð ˆLˆLøõ ð 	ð 	ð 	Ý�LŠLÐ4°aÑ8Ô8Ð8Øøøøøð	øøøð ')ˆð ˆ	õ �< Ñ(Ô(ñ 	ZØ-9Ô->ÐF˜Ô)Ð)ÀBˆIÝ�KŠK˜¥g¨l¸HÀiÑ&PÔ&PÑQÔQÐQÝ�KŠKÐ,­c°)©n¬nÑ=Ô=Ð=ð ð YÝ—’Ð6Ð8xÐ8xÍ#ÈlÑJ[ÔJ[Ð8xÑ8xÔ8xÑyÔyÐyÝ—’˜\­7°<ÀÈ5Ñ+QÔ+QÑRÔRÐRÝ—’˜[­'°,ÀÈÑ*OÔ*OÑPÔPÐPÝ—’˜_­g°lÀKÐQVÑ.WÔ.WÑXÔXÐXøå˜¥dÑ+Ô+ð 	Z°¸,Ð0FÐ0FØ$×(Ò(¨°Ñ4Ô4ˆIˆIå�NŠNÐ9Ñ:Ô:Ð:Ý�LŠLÐ*­D°Ñ,>Ô,>Ñ?Ô?Ð?Ý�| ZÑ0Ô0ð ZÝ—’Ð4µd¸<Ô;P×;UÒ;UÑ;WÔ;WÑ6XÔ6XÑYÔYÐYàð E	ñ E	ˆDà$ˆHØˆEØ#ÐØˆLØˆHõ �t˜\Ñ*Ô*ð 4à ŸOšOÑ-Ô-�	Ø#,§=¢=°Ñ#<Ô#<Ð Ø(Ÿ}š}¨VÑ4Ô4�Ø$Ÿ=š=¨°RÑ8Ô8��Ý˜˜zÑ*Ô*ð 4å#*¨4°¸TÑ#BÔ#BÐ Ý& t¨V°TÑ:Ô:�õ  ' t¨Z¸Ñ<Ô<�Ý˜<¨Ñ6Ô6ð "Ø+×6Ò6Ñ8Ô8�H�HÝ˜\¨:Ñ6Ô6ð "Ø+Ô4�H�HÝ ­dÑ3Ô3ð "Ø+�H�Hà!�H�HÝ˜D¥$Ñ'Ô'ð 4à#'§8¢8¨JÑ#7Ô#7Ð Ø#Ÿxšx¨Ñ/Ô/�ØŸ8š8 J°Ñ3Ô3�õ ˜h­Ñ-Ô-ð "Ý˜8 \Ñ2Ô2ð "Ø'×2Ò2Ñ4Ô4�H�HÝ˜X zÑ2Ô2ð "Ø'Ô0�H�Hà!�Hð  —|’| K°·²¸eÀ]Ñ1SÔ1SÑTÔTˆHØ—L’L ¨"Ñ-Ô-ˆEõ 0°Ñ9Ô9ˆLØð Ý—’Ð@À,ÈvÔBVÐXdÐekÔXlÑmÔmÐmØ—’Ø#¨eÀÐSUØ)¨)Ô4Ø2>¸vÔ2FÐP\Ð]cÔPdÐp|ð  ~Fô  qGð  *Hð  *Hðð ñ ô ð ñ
 ð 'Ð<¨,Ð<¸"ˆGà�LŠLØØØ"Ø&Ø$ðð ñ ô ð ñ ð ˜uÐ%ˆå˜HŸLšL¨°BÑ7Ô7Ñ8Ô8ˆÝ�ŠÐ&¨Ñ6Ô6Ð6à+8ˆ˜Ñ(Ý47½¼
À8Ñ8LÔ8LÑ4MÔ4MˆÐ0Ñ1ð ñ I	LÐ"5ñ I	LÝ�KŠKÐKÑLÔLÐLØÐ0Ô1×8Ò8Ð9IÑJÔJÐJð)8ð )8ð )8ð )8ð )8ð )8ðX $Ÿ<š<¨	°2Ñ6Ô6ˆLØTÐTÐTÐTÀ|ÐTÑTÔTˆEÝ&-¤n°eÐ&<Ð <Ð <Ð <Ð <Ð <Ð <Ðð ,=ð 
Kð 
KÑ'�˜ Ø!Ÿ:š: e¨]Ñ;Ô;�Ø˜[Ò(Ð(Ø#Ð$9Ô:×AÒAÀ'ÑJÔJÐJØ#Ð$>Ð?Ð?Ô?À1ÑDÐ?Ð?Ñ?Ý—K’KÐ 0°(Ñ;Ô;Ð;Ð;Ø˜{Ò*Ð*Ø#Ð$9Ô:×AÒAÀ'ÑJÔJÐJÝ—K’KÐ HÈ(ÑSÔSÐSÐSå—N’NÐ#?ÀÑJÔJÐJÐJð
Kð "ð [Ð*=ð [Ý—’ÐqÑrÔrÐrØÐ 4Ô5×<Ò<Ð=YÑZÔZÐZà"Ÿ,š, y°"Ñ5Ô5ð Lð L�Ø!Ÿ:š: e¨]Ñ;Ô;�Ý!$ V§Z¢Z°	¸2Ñ%>Ô%>Ñ!?Ô!?�Ý—’Ð0°(¸NÑKÔKÐKÐKð	
ð 	
ð —\’\ )¨RÑ0Ô0ð	
ñ 	
ô 	
ˆð & Ð7Ðå”jÐ!1¸!È%ÐPÑPÔPˆå,¨[Ñ9Ô9ˆå14°^Ñ1DÔ1DˆÐ-Ñ.ØÐ,Ô-×4Ò4Ð5KÑLÔLÐLõ 	�ŠÐ(¨/Ñ:Ô:Ð:Ý�Š‰ŒˆàÐøåð %ð %ð %Ø7­s°1©v¬vÐ7Ð7ˆ	Ý�Š�T˜9Ñ%Ô%Ð%à#,ˆ˜Ñ Ý�ŠÐ(¨/Ñ:Ô:Ð:Ý�Š‰Œˆå˜)Ñ$Ô$Ð$Ð$Ð$Ð$Ð$Ð$øøøøð%øøøss   šA9r ÂA3r Ä r Ä)H+r Í6r ÎBr ÐA3r ÒAr ÓS* Ó)r Ó*
TÓ4TÔTÔ]8r ò
tòA4tôtôtc                  ó:   — t          ¦   «         pt          ¦   «         S )a‚  
    Check whether the Firecrawl backend is available.

    Availability is true when either:
    1) direct Firecrawl config (`FIRECRAWL_API_KEY` or `FIRECRAWL_API_URL`), or
    2) Firecrawl gateway origin + Nous Subscriber access token
       (fallback when direct Firecrawl is not configured).

    Returns:
        bool: True if direct Firecrawl or the tool-gateway can be used.
    )rM   r5   rF   r   r   r;   r;   s  s   € õ (Ñ)Ô)ÐEÕ-CÑ-EÔ-EÐEr   c                  óæ   — t          ¦   «                              dd¦  «                             ¦   «                              ¦   «         } | dv rt	          | ¦  «        S t          d„ dD ¦   «         ¦  «        S )z6Check whether the configured web backend is available.r)   r*   )r.   r+   r,   r-   c              3   ó4   K  — | ]}t          |¦  «        V — Œd S r   )r<   )r¬   r)   s     r   ú	<genexpr>z$check_web_api_key.<locals>.<genexpr>‡  s+   è è € ÐhÐh°'Õ$ WÑ-Ô-ÐhÐhÐhÐhÐhÐhr   )r'   r$   r4   r   r<   Úany)r6   s    r   Úcheck_web_api_keyr
  ‚  sm   € å!Ñ#Ô#×'Ò'¨	°2Ñ6Ô6×<Ò<Ñ>Ô>×DÒDÑFÔF€JØÐ?Ð?Ð?Ý$ ZÑ0Ô0Ð0ÝÐhÐhÐ=gÐhÑhÔhÑhÔhÐhr   c                  ó.   — t          ¦   «         \  } }}| duS )zICheck if an auxiliary text model is available for LLM content processing.Nrá   )rË   r©   s     r   rË  rË  Š  s   € å1Ñ3Ô3�L€FˆAˆqØ˜ÐÐr   Ú__main__u    ðŸŒ� Standalone Web Tools Modulez(========================================r/   r0   u   âœ… Web backend: r.   z!   Using Exa API (https://exa.ai)r+   z+   Using Parallel API (https://parallel.ai)r-   z(   Using Tavily API (https://tavily.com)z    Using self-hosted Firecrawl: r>   z#   Using direct Firecrawl cloud APIz!   Using Firecrawl tool-gateway: z0   Firecrawl backend selected but not configuredu$   â�Œ No web search backend configuredzWSet EXA_API_KEY, PARALLEL_API_KEY, TAVILY_API_KEY, FIRECRAWL_API_KEY, FIRECRAWL_API_URLu;   â�Œ No auxiliary model available for LLM content processingzVSet OPENROUTER_API_KEY, configure Nous Portal, or set OPENAI_BASE_URL + OPENAI_API_KEYuK   âš ï¸�  Without an auxiliary model, LLM content processing will be disabledu   âœ… Auxiliary model available: r…   u!   ðŸ› ï¸�  Web tools ready for use!u+   ðŸ§  LLM content processing available with z&   Default min length for processing: z charsu&   ðŸ�› Debug mode ENABLED - Session ID: z    Debug logs will be saved to: z/web_tools_debug_z.jsonu=   ðŸ�› Debug mode disabled (set WEB_TOOLS_DEBUG=true to enable)z
Basic usage:zI  from web_tools import web_search_tool, web_extract_tool, web_crawl_toolz  import asyncioz  # Search (synchronous)z/  results = web_search_tool('Python tutorials')z$  # Extract and crawl (asynchronous)z  async def main():z?      content = await web_extract_tool(['https://example.com'])zC      crawl_data = await web_crawl_tool('example.com', 'Find docs')z  asyncio.run(main())z
LLM-enhanced usage:zC  # Content automatically processed for pages >5000 chars (default)zA  content = await web_extract_tool(['https://python.org/about/'])z#  # Customize processing parametersz$  crawl_data = await web_crawl_tool(z      'docs.python.org',z      'Find key concepts',z,      model='google/gemini-3-flash-preview',z      min_length=3000z  )z  # Disable LLM processingzY  raw_content = await web_extract_tool(['https://example.com'], use_llm_processing=False)z
Debug mode:z  # Enable debug loggingz  export WEB_TOOLS_DEBUG=truez  # Debug logs capture:z$  # - All tool calls with parametersz  # - Original API responsesz  # - LLM compression metricsz  # - Final processed resultsz3  # Logs saved to: ./logs/web_tools_debug_UUID.jsonuL   
ðŸ“� Run 'python test_web_tools_llm.py' to test LLM processing capabilities)Úregistryr‰  Ú
web_searchzrSearch the web for information on any topic. Returns up to 5 relevant results with titles, URLs, and descriptions.ÚobjectÚstringz&The search query to look up on the web)rú  r†   )rú  Ú
propertiesÚrequired)r   r†   r}  rÖ   u   Extract content from web page URLs. Returns page content in markdown format. Also works with PDF URLs (arxiv papers, documents, etc.) â€” pass the PDF link directly and it converts to markdown text. Pages under 5000 chars return full markdown; larger pages are LLM-summarized and capped at ~5000 chars per page. Pages over 2M chars are refused. If a URL fails or times out, use the browser tool to access it instead.Úarrayrú  z:List of URLs to extract content from (max 5 URLs per call))rú  rµ   r†   ÚmaxItemsr"   c                 óL   — t          |                      dd¦  «        d¬¦  «        S )NrO  r*   rh  )rP  )r…  r$   ©ÚargsÚkws     r   r2  r2  $  s!   € �¨t¯xªx¸ÀÑ/DÔ/DÈAÐNÑNÔN€ r   u   ðŸ”�rè   )r   ÚtoolsetÚschemaÚhandlerÚcheck_fnÚrequires_envÚemojiÚmax_result_size_charsc                 ó®   — t          t          |                      d¦  «        t          ¦  «        r|                      dg ¦  «        d d…         ng d¦  «        S )Nr^  rh  rž  )rÅ  r›   r$   r±   r  s     r   r2  r2  .  sP   € Õ/Ý$.¨t¯xªx¸Ñ/?Ô/?ÅÑ$FÔ$FÐNˆ�Š�˜ÑÔ˜R˜a˜RÔ Ð ÈBÐPZñ \ô  \€ r   u   ðŸ“„)	r   r  r  r  r  r  Úis_asyncr  r  )r   N)r*   r   )r  Fr*   )rN  )rh  )mÚ__doc__rv   Úloggingr   rB  r  Útypingr   r   r   r   r{   r,   r   rÚ   r   r	   r
   Útools.debug_helpersr   Útools.managed_tool_gatewayr   r   rK   r   Útools.tool_backend_helpersr   r   Útools.url_safetyr   Útools.website_policyr   Ú	getLoggerÚ__name__r]   rœ   r   r   r°   r'   r9   r<   ra   rb   r4  rD   rG   r5   rM   rQ   rS   r±   r[   rf   rk   ro   rl   rp   r   rx   r€   r�   r¢   r¶   r¼   rÄ   rÉ   Ú$DEFAULT_MIN_LENGTH_FOR_SUMMARIZATIONrÓ   rß   râ   r‹  r²   r  rö   rõ   rG  rK  rM  r]  rg  rt  r{  r…  rÅ  rí  r;   r
  rË  ÚprintÚweb_availableÚtool_gateway_availabler   Úfirecrawl_key_availableÚfirecrawl_url_availableÚnous_availableÚdefault_summarizer_modelr)   rB   ÚexitÚactiveÚ
session_idÚlog_dirÚtools.registryr  r‰  ÚWEB_SEARCH_SCHEMAÚWEB_EXTRACT_SCHEMAÚregisterrF   r   r   ú<module>r<     sÎ  ðð'ð 'ðR €€€Ø €€€Ø 	€	€	€	Ø 	€	€	€	Ø €€€Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ø €€€Ø Ð Ð Ð Ð Ð ðð ð ð ð ð ð ð ð ð ð
 -Ð ,Ð ,Ð ,Ð ,Ð ,ðð ð ð ð ð ð ð ð ð ð
 SÐ RÐ RÐ RÐ RÐ RÐ RÐ RØ (Ð (Ð (Ð (Ð (Ð (Ø 5Ð 5Ð 5Ð 5Ð 5Ð 5à	ˆÔ	˜8Ñ	$Ô	$€ð
%�3ð %˜4ð %ð %ð %ð %ð˜$ð ð ð ð ð�cð ð ð ð ð6
 3ð 
¨4ð 
ð 
ð 
ð 
ð Ð ØÐ ð@ h¨u°T¸#¸s¸(´^ÀUÈ3ÐPXÐY\ÔP]Ð_gÐhkÔ_lÐKlÔEmÐ5mÔ/nÔ&oð @ð @ð @ð @ð"1 Cð 1ð 1ð 1ð 1ð
g ð gð gð gð gð
6 dð 6ð 6ð 6ð 6ð
ð ð ð ð¨ð ð ð ð ð˜4 œ9ð ð ð ð ð*$ð $ð $ðP Ð ØÐ ðð ð ð$"ð "ð "ð& �2”9Ð.Ð0HÑIÔIÐ ð˜cð ¨Dð °Tð ð ð ð ð(;¨tð ;¸ð ;ð ;ð ;ð ;ð"%ð %¨$ð %¸cð %È4ÐPTÐUXÐZ]ÐU]ÔP^ÔK_ð %ð %ð %ð %ðP˜Cð  Cð ð ð ð ð.
 3ð 
¨4°°S¸#°X´Ô+?ð 
ð 
ð 
ð 
ð¨#ð °$°t¸CÀ¸H´~Ô2Fð ð ð ð ð>
¨3ð 
°4¸¸S¸´>ð 
ð 
ð 
ð 
ð (,Ð $ðL cð L¨dð Lð Lð Lð Lð/ð /¨(°3¬-ð /À5ÈÐRUÌÐX`ÐadÔXeÐgkÐloÐqtÐltÔguÐIuÔCvð /ð /ð /ð /ð x°¤}ð ð ð ð ð
 
ˆ�kÐ+<Ð	=Ñ	=Ô	=€ð
 ØØØ:ðað aØðaà	ðað ðað �CŒ=ð	að
 ðað ˆc„]ðað að að aðP ØØðqð qØðqàðqð �CŒ=ðqð ð	qð
 ðqð ðqð ˆc„]ðqð qð qð qðhPØðPàðPð �CŒ=ðPð ð	Pð
 ðPð ˆc„]ðPð Pð Pð Pðf˜cð  cð ð ð ð ðF €ðð ð ð*;ð ;�sð ; 3ð ;°ð ;ð ;ð ;ð ;ð8�t˜C”yð  T¨$¨s°C¨x¬.Ô%9ð ð ð ð ðD;ð ;˜Cð ;¨ð ;°Dð ;ð ;ð ;ð ;ð>( $ s¤)ð (°°T¸#¸s¸(´^Ô0Dð (ð (ð (ð (ðV%ð %˜3ð % sð %°3ð %ð %ð %ð %ðH Ø#ØØ:ðE%ð E%Ø
ˆsŒ)ðE%àðE%ð ðE%ð �CŒ=ð	E%ð
 ðE%ð 	ðE%ð E%ð E%ð E%ðT
 ØØ#ØØ:ðZ%ð Z%Ø	ðZ%àðZ%ð ðZ%ð ð	Z%ð
 �CŒ=ðZ%ð ðZ%ð 	ðZ%ð Z%ð Z%ð Z%ð|F ð Fð Fð Fð Fði˜4ð ið ið ið ið˜tð ð ð ð ð ˆzÒÑðð 
€EÐ
,Ñ-Ô-Ð-Ø	€Eˆ(�O„O€Oð &Ð%Ñ'Ô'€MØ3Ð3Ñ5Ô5ÐØ"˜d 9 2¤9Ð-@À"Ñ#EÔ#E×#KÒ#KÑ#MÔ#MÑNÔNÐØ"˜d 9 2¤9Ð-@À"Ñ#EÔ#E×#KÒ#KÑ#MÔ#MÑNÔNÐØ*Ð*Ñ,Ô,€NØ<Ð<Ñ>Ô>Ðàð 
Ø�,‘.”.ˆØˆÐ+ 'Ð+Ð+Ñ,Ô,Ð,Ø�eÒÐØˆEÐ5Ñ6Ô6Ð6Ð6Ø˜
Ò"Ð"ØˆEÐ?Ñ@Ô@Ð@Ð@Ø˜Ò Ð ØˆEÐ<Ñ=Ô=Ð=Ð=à&ð JØ�Ðm¸¸¼ÐCVÑ9WÔ9W×9]Ò9]Ñ9_Ô9_×9fÒ9fÐgjÑ9kÔ9kÐmÐmÑnÔnÐnÐnØ(ð JØ�Ð;Ñ<Ô<Ð<Ð<Ø'ð JØ�ÐXÐ:TÐ:TÑ:VÔ:VÐXÐXÑYÔYÐYÐYà�ÐHÑIÔIÐIÐIàˆÐ4Ñ5Ô5Ð5Øˆð2Ø-Ð-Ñ/Ô/ð2ð 2ñ	
ô 	
ð 	
ð
 ð LØˆÐKÑLÔLÐLØˆÐfÑgÔgÐgØˆÐ[Ñ\Ô\Ð\Ð\àˆÐJÐ0HÐJÐJÑKÔKÐKàð ØˆˆQ‰Œˆà	€EÐ
-Ñ.Ô.Ð.àð eØˆÐVÐ<TÐVÐVÑWÔWÐWØˆÐcÐ7[ÐcÐcÐcÑdÔdÐdð „}ð OØˆÐJ°vÔ7HÐJÐJÑKÔKÐKØˆÐj°´ÐjÐjÐRXÔRcÐjÐjÐjÑkÔkÐkÐkàˆÐMÑNÔNÐNà	€EÐ
ÑÔÐØ	€EÐ
UÑVÔVÐVØ	€EÐ
ÑÔÐØ	€Eˆ"�I„I€IØ	€EÐ
$Ñ%Ô%Ð%Ø	€EÐ
;Ñ<Ô<Ð<Ø	€Eˆ"�I„I€IØ	€EÐ
0Ñ1Ô1Ð1Ø	€EÐ
Ñ Ô Ð Ø	€EÐ
KÑLÔLÐLØ	€EÐ
OÑPÔPÐPØ	€EÐ
!Ñ"Ô"Ð"àð kØˆÐ%Ñ&Ô&Ð&ØˆÐSÑTÔTÐTØˆÐQÑRÔRÐRØˆˆb‰	Œ	ˆ	ØˆÐ3Ñ4Ô4Ð4ØˆÐ4Ñ5Ô5Ð5ØˆÐ(Ñ)Ô)Ð)ØˆÐ*Ñ+Ô+Ð+ØˆÐ<Ñ=Ô=Ð=ØˆÐ%Ñ&Ô&Ð&Øˆˆe‰ŒˆØˆˆb‰	Œ	ˆ	ØˆÐ*Ñ+Ô+Ð+ØˆÐiÑjÔjÐjà	€Eˆ/ÑÔÐØ	€EÐ
$Ñ%Ô%Ð%Ø	€EÐ
)Ñ*Ô*Ð*Ø	€EÐ
#Ñ$Ô$Ð$Ø	€EÐ
0Ñ1Ô1Ð1Ø	€EÐ
(Ñ)Ô)Ð)Ø	€EÐ
)Ñ*Ô*Ð*Ø	€EÐ
)Ñ*Ô*Ð*Ø	€EÐ
?Ñ@Ô@Ð@à	€EÐ
YÑZÔZÐZð 0Ð /Ð /Ð /Ð /Ð /Ð /Ð /ð ð HààØ ØGðð ð
ð �Ið	ð 	ðð Ð ð  ð vààØØ  (Ð+Ø[Øð	ð ð
ð �Hðð ðð Ð ð" €Ô Ø	ØØØNÐNØØ"Ð"Ñ$Ô$Ø
Ø!ð	ñ 	ô 	ð 	ð €Ô Ø	ØØð\ð \àØ"Ð"Ñ$Ô$ØØ
Ø!ðñ ô ð ð ð r   