
    `gj*(                        d Z ddlmZ ddlZddlZddlmZmZmZ ddl	m
Z
  ej                  e      ZddZddZddZdd	ZeZeZdd
Z G d de
      Zy)u  Parallel.ai web search + content extraction — plugin form.

Subclasses :class:`agent.web_search_provider.WebSearchProvider`. Uses two
distinct Parallel SDK clients:

- ``Parallel`` (sync)        — for :meth:`search`
- ``AsyncParallel`` (async)  — for :meth:`extract`

This is the first plugin to exercise the **async-extract** code path in
the ABC: :meth:`extract` is declared ``async def``, and the dispatcher
in :func:`tools.web_tools.web_extract_tool` detects coroutines via
:func:`inspect.iscoroutinefunction` and awaits.

Config keys this provider responds to::

    web:
      search_backend: "parallel"      # explicit per-capability
      extract_backend: "parallel"     # explicit per-capability
      backend: "parallel"             # shared fallback
      # Optional: search mode (default "agentic"; also "fast" or "one-shot")
      # via the PARALLEL_SEARCH_MODE env var.

Env vars::

    PARALLEL_API_KEY=...             # https://parallel.ai (required)
    PARALLEL_SEARCH_MODE=agentic     # optional: agentic|fast|one-shot
    )annotationsN)AnyDictList)WebSearchProviderc                     	 ddl m}   | dd       y# t        $ r Y yt        $ r}t        t	        |            d}~ww xY w)aM  Trigger lazy install of the parallel SDK if it isn't present.

    Mirrors the lazy-deps pattern used by the legacy implementation.
    Swallows benign ImportError from the lazy_deps helper itself; if the
    SDK is genuinely missing the subsequent ``from parallel import ...``
    raises ImportError that the caller can handle.
    r   )ensurezsearch.parallelF)promptN)tools.lazy_depsr	   ImportError	Exceptionstr)_lazy_ensureexcs     P/root/.hermes/venv/lib/python3.12/site-packages/plugins/web/parallel/provider.py_ensure_parallel_sdk_installedr   .   s?    $:&u5  $#c(##$s    	??:?c                     ddl m}  t        | dd      }||S ddlm}  |d      }|st        d      t                ddlm}  ||      }|| _	        |S )	zLazy-load + cache the sync Parallel client.

    Cache lives on :mod:`tools.web_tools` (as ``_parallel_client``) so unit
    tests that reset that name between cases keep working.
    r   N_parallel_clientget_provider_envPARALLEL_API_KEYVPARALLEL_API_KEY environment variable not set. Get your API key at https://parallel.ai)Parallelapi_key)
tools.web_tools	web_toolsgetattragent.web_search_providerr   
ValueErrorr   parallelr   r   )_wtcachedr   r   r   clients         r   _get_sync_clientr%   @   sf     "S,d3F:12G6
 	

 #$!g&F!CM    c                     ddl m}  t        | dd      }||S ddlm}  |d      }|st        d      t                ddlm}  ||      }|| _	        |S )	z}Lazy-load + cache the async Parallel client.

    Cache lives on :mod:`tools.web_tools` (as ``_async_parallel_client``).
    r   N_async_parallel_clientr   r   r   )AsyncParallelr   )
r   r   r   r   r   r    r   r!   r)   r(   )r"   r#   r   r   r)   r$   s         r   _get_async_clientr*   ]   sf    
 "S2D9F:12G6
 	

 #$&7+F!'CMr&   c                 ,    ddl m}  d| _        d| _        y)zDrop both cached clients so tests can re-instantiate cleanly.

    Clears the canonical slots on :mod:`tools.web_tools` (where
    :func:`_get_sync_client` / :func:`_get_async_client` read/write them).
    r   N)r   r   r   r(   )r"   s    r   _reset_clients_for_testsr,   y   s     "C!%Cr&   c                 v    t        j                  dd      j                         j                         } | dvrd} | S )zDReturn the validated PARALLEL_SEARCH_MODE value (default "agentic").PARALLEL_SEARCH_MODEagentic>   one-shotfastr/   )osgetenvlowerstrip)modes    r   _resolve_search_moder7      s8    99+Y7==?EEGD22Kr&   c                  r    e Zd ZdZedd       Zedd       ZddZddZddZ	dddZ
	 	 	 	 	 	 ddZdd	Zy
)ParallelWebSearchProviderz,Parallel.ai search + async extract provider.c                     y)Nr!    selfs    r   namezParallelWebSearchProvider.name       r&   c                     y)Nr   r;   r<   s    r   display_namez&ParallelWebSearchProvider.display_name   r?   r&   c                0    ddl m} t         |d            S )zBReturn True when ``PARALLEL_API_KEY`` is set to a non-empty value.r   r   r   )r   r   bool)r=   r   s     r   is_availablez&ParallelWebSearchProvider.is_available   s    >$%7899r&   c                     yNTr;   r<   s    r   supports_searchz)ParallelWebSearchProvider.supports_search       r&   c                     yrF   r;   r<   s    r   supports_extractz*ParallelWebSearchProvider.supports_extract   rH   r&   c           	        	 ddl m}  |       rdddS t               }t        j	                  d|||       t               j                  j                  |g||t        |d            }g }t        |j                  xs g       D ]]  \  }}|j                  xs g }	|j                  |j                  xs d	|j                  xs d	|	rd
j                  |	      nd	|dz   d       _ dd|idS # t         $ r}
dt#        |
      dcY d}
~
S d}
~
wt$        $ r}
dd|
 dcY d}
~
S d}
~
wt&        $ r(}
t        j)                  d|
       dd|
 dcY d}
~
S d}
~
ww xY w)zExecute a Parallel search (sync).

        Uses the ``beta.search`` endpoint with the configured mode
        (``PARALLEL_SEARCH_MODE`` env var, default "agentic"). Limit is
        capped at 20 server-side.
        r   is_interruptedFInterrupted)successerrorz)Parallel search: '%s' (mode=%s, limit=%d)   )search_queries	objectiver6   max_results     )urltitledescriptionpositionTweb)rO   dataNParallel SDK not installed: zParallel search error: %szParallel search failed: )tools.interruptrM   r7   loggerinfor%   betasearchmin	enumerateresultsexcerptsappendrX   rY   joinr    r   r   r   warning)r=   querylimitrM   r6   responseweb_resultsiresultrg   r   s              r   rc   z ParallelWebSearchProvider.search   sg   '	Q6#(=AA')DKK;UD% ()..55 %wrN	 6 H K&x'7'7'=2> 		6!??0b""%zz/R!'!3=Esxx'92$%E		  $e[-ABB 	9$s3x88 	 7u=   	QNN6<$1I#/OPP	QsG   C* CC* *	E3D EEDEE+EEEc           
     $  K   	 ddl m}  |       r|D cg c]  }|ddd
 c}S t        j                  dt	        |             t               j                  j                  |d       d	{   }g }|j                  xs g D ]m  }|j                  xs d}|sd
j                  |j                  xs g       }|j                  xs d}	|j                  xs d}
|j                  |	|
|||	|
dd       o |j                  xs g D ]S  }|j                  |j                  xs ddd|j                   xs |j"                  xs dd|j                  xs did       U |S c c}w 7 # t$        $ r.}|D cg c]  }|ddt'        |      d nc c}w c}cY d	}~S d	}~wt(        $ r(}|D cg c]  }|ddd| d nc c}w c}cY d	}~S d	}~wt*        $ r>}t        j-                  d|       |D cg c]  }|ddd| d nc c}w c}cY d	}~S d	}~ww xY ww)uS  Extract content from one or more URLs via the async SDK.

        Returns the legacy list-of-results shape that
        :func:`tools.web_tools.web_extract_tool` expects: one entry per
        successful URL plus one entry per failed URL with an ``error``
        field. Errors are not raised — they're returned as per-URL items.
        r   rL   rN   rU   )rX   rP   rY   zParallel extract: %d URL(s)T)urlsfull_contentNz

)	sourceURLrY   )rX   rY   contentraw_contentmetadatazextraction failedrt   )rX   rY   ru   rP   rw   )rX   rY   ru   rP   r^   zParallel extract error: %szParallel extract failed: )r_   rM   r`   ra   lenr*   rb   extractrf   rs   ri   rg   rX   rY   rh   errorsru   
error_typer    r   r   r   rj   )r=   rr   kwargsrM   urm   rf   rp   ru   rX   rY   rP   r   s                r   ry   z!ParallelWebSearchProvider.extract   s5    7	6MQHIAC  KK5s4yA.055==! >  H
 -/G"**0b  --3$kk&//*?R@Gjj&B*"!&#*'.25$F  ".B 	$yyB!##%!&!Y%2B2B!YFY%0%))/r$B	 NM
D  	]W[\RSArCHM\\\ 	  B2B^_b^c@de    	NN7=  B2B[\_[`@ab  	s   HE" EE" HAE" ,E -C-E" HE" "	H+F/FFHHH G$F65G=H>HHH)G;:HHHHHc                    dddddddgdS )	Nr   paidz2Objective-tuned search + parallel page extraction.r   zParallel API keyzhttps://parallel.ai)keyr
   rX   )r>   badgetagenv_varsr;   r<   s    r   get_setup_schemaz*ParallelWebSearchProvider.get_setup_schema  s*    G .00	
 	
r&   Nreturnr   )r   rC   )   )rk   r   rl   intr   Dict[str, Any])rr   z	List[str]r|   r   r   zList[Dict[str, Any]])r   r   )__name__
__module____qualname____doc__propertyr>   rA   rD   rG   rJ   rc   ry   r   r;   r&   r   r9   r9      sh    6   :.Q`AA),A	AF
r&   r9   )r   None)r   r   r   )r   
__future__r   loggingr2   typingr   r   r   r   r   	getLoggerr   r`   r   r%   r*   r,   _get_parallel_client_get_async_parallel_clientr7   r9   r;   r&   r   <module>r      sf   8 #  	 " " 7			8	$$$:8	& ( . V
 1 V
r&   