§
    ÷žyj-  ã                  ól   — d Z ddlmZ ddlZddlZddlmZmZmZm	Z	 dd„Z
 G d	„ d
ej        ¦  «        ZdS )u  
Web Search Provider ABC
=======================

Defines the pluggable-backend interface for web search and content extraction.
Providers register instances via ``PluginContext.register_web_search_provider()``;
the active one (selected via ``web.search_backend`` / ``web.extract_backend`` /
``web.backend`` in ``config.yaml``) services every ``web_search`` /
``web_extract`` tool call.

Providers live in ``<repo>/plugins/web/<name>/`` (built-in, auto-loaded as
``kind: backend``) or ``~/.hermes/plugins/web/<name>/`` (user, opt-in via
``plugins.enabled``).

This ABC is the SINGLE plugin-facing surface for web providers â€” every
provider in the tree (brave-free, ddgs, searxng, exa, parallel, tavily,
firecrawl) implements it. The legacy in-tree ``tools.web_providers.base``
ABCs were deleted in PR #25182 along with the per-vendor inline helpers
in ``tools/web_tools.py``; the response-shape contract documented below
is preserved bit-for-bit so the tool wrapper does not have to translate.

Response shape (preserved from the legacy contract):

Search results::

    {
        "success": True,
        "data": {
            "web": [
                {"title": str, "url": str, "description": str, "position": int},
                ...
            ]
        }
    }

Extract results::

    {
        "success": True,
        "data": [
            {"url": str, "title": str, "content": str,
             "raw_content": str, "metadata": dict},
            ...
        ]
    }

On failure (either capability)::

    {"success": False, "error": str}
é    )ÚannotationsN)ÚAnyÚDictÚListÚOptionalÚnameÚstrÚreturnc                óª   — d}	 ddl m}  || ¦  «        }n# t          $ r d}Y nw xY w|€t          j        | d¦  «        }|pd                     ¦   «         S )u:  Config-aware env lookup for web providers.

    Resolves *name* via :func:`hermes_cli.config.get_env_value` (checks
    ``os.environ`` first, then ``~/.hermes/.env``) so credentials set
    through Hermes' config layer are visible even when they were never
    exported into the process environment â€” gateway sessions, delegate
    children, and subprocess agent runs (issue #40190). Falls back to a
    bare ``os.getenv`` when the config module is unavailable (stripped
    installs, early import contexts).

    Returns the stripped value, or ``""`` when unset.
    Nr   )Úget_env_valueÚ )Úhermes_cli.configr   Ú	ExceptionÚosÚgetenvÚstrip)r   Úvalr   s      ú?/home/ragecks/.hermes/hermes-agent/agent/web_search_provider.pyÚget_provider_envr   ;   s�   € ð €CðØ3Ð3Ð3Ð3Ð3Ð3àˆm˜DÑ!Ô!ˆˆøÝð ð ð Øˆˆˆðøøøà
€{ÝŒi˜˜bÑ!Ô!ˆØˆI�2×ÒÑÔÐs   „ –%¤%c                  ó¨   — e Zd ZdZeej        dd„¦   «         ¦   «         Zedd„¦   «         Zej        dd„¦   «         Z	dd„Z
dd	„Zddd„Zdd„Zdd„ZdS )ÚWebSearchProvideru³  Abstract base class for a web search/extract backend.

    Subclasses must implement :meth:`is_available` and at least one of
    :meth:`search` / :meth:`extract`. The :meth:`supports_search` /
    :meth:`supports_extract` capability flags let the registry route each
    tool call to the right provider, and let multi-capability providers
    (Firecrawl, Tavily, Exa, â€¦) advertise multiple capabilities from a
    single class.
    r
   r	   c                ó   — dS )a*  Stable short identifier used in ``web.search_backend`` /
        ``web.extract_backend`` / ``web.backend`` config keys.

        Lowercase, no spaces; hyphens permitted to preserve existing
        user-visible names. Examples: ``brave-free``, ``ddgs``,
        ``searxng``, ``firecrawl``.
        N© ©Úselfs    r   r   zWebSearchProvider.named   ó   € € € ó    c                ó   — | j         S )zEHuman-readable label shown in ``hermes tools``. Defaults to ``name``.)r   r   s    r   Údisplay_namezWebSearchProvider.display_nameo   s   € ð ŒyÐr   Úboolc                ó   — dS )u  Return True when this provider can service calls.

        Typically a cheap check (env var present, optional Python dep
        importable, instance URL set). Must NOT make network calls â€” this
        runs at tool-registration time and on every ``hermes tools`` paint.
        Nr   r   s    r   Úis_availablezWebSearchProvider.is_availablet   r   r   c                ó   — dS )z7Return True if this provider implements :meth:`search`.Tr   r   s    r   Úsupports_searchz!WebSearchProvider.supports_search}   s   € àˆtr   c                ó   — dS )uü  Return True if this provider implements :meth:`extract`.

        Both sync and async :meth:`extract` implementations are valid â€” the
        dispatcher detects coroutine functions via
        :func:`inspect.iscoroutinefunction` and awaits as needed. Sync
        implementations that perform blocking I/O (HTTP, SDK calls) should
        ideally wrap in :func:`asyncio.to_thread` at the call site; small
        providers can keep their sync shape and let the dispatcher handle
        threading.
        Fr   r   s    r   Úsupports_extractz"WebSearchProvider.supports_extract�   s	   € ð ˆur   é   ÚqueryÚlimitÚintúDict[str, Any]c                ó0   — t          | j        › d�¦  «        ‚)zÒExecute a web search.

        Override when :meth:`supports_search` returns True. The default
        raises NotImplementedError; callers should gate on
        :meth:`supports_search` before calling.
        z3 does not support search (override supports_search)©ÚNotImplementedErrorr   )r   r(   r)   s      r   ÚsearchzWebSearchProvider.searchŽ   s$   € õ "ØŒyÐMÐMÐMñ
ô 
ð 	
r   Úurlsú	List[str]Úkwargsr   c                ó0   — t          | j        › d�¦  «        ‚)u$  Extract content from one or more URLs.

        Override when :meth:`supports_extract` returns True. The default
        raises NotImplementedError; callers should gate on
        :meth:`supports_extract` before calling.

        Return shape: a list of result dicts matching what the legacy
        :func:`tools.web_tools.web_extract_tool` post-processing pipeline
        expects::

            [
                {
                    "url": str,
                    "title": str,
                    "content": str,
                    "raw_content": str,
                    "metadata": dict,           # optional
                    "error": str,               # optional, only on per-URL failure
                },
                ...
            ]

        Implementations MAY be ``async def`` â€” the dispatcher detects
        coroutines via :func:`inspect.iscoroutinefunction` and awaits.

        ``kwargs`` may carry forward-compat fields (``format``, ``include_raw``,
        ``max_chars``) â€” implementations should ignore unknown keys.
        z5 does not support extract (override supports_extract)r-   )r   r0   r2   s      r   ÚextractzWebSearchProvider.extract™   s$   € õ: "ØŒyÐOÐOÐOñ
ô 
ð 	
r   c                ó   — | j         ddg dœS )uç  Return provider metadata for the ``hermes tools`` picker.

        Used by ``hermes_cli/tools_config.py`` to inject this provider as a
        row in the Web Search / Web Extract picker. Shape::

            {
                "name": "Brave Search (Free)",
                "badge": "free",
                "tag": "No paid tier needed â€” uses Brave's free API.",
                "env_vars": [
                    {"key": "BRAVE_SEARCH_API_KEY",
                     "prompt": "Brave Search API key",
                     "url": "https://brave.com/search/api/"},
                ],
            }

        Default: minimal entry derived from ``display_name``. Override to
        expose API key prompts, badges, and instance URL fields.
        r   )r   ÚbadgeÚtagÚenv_vars)r   r   s    r   Úget_setup_schemaz"WebSearchProvider.get_setup_schemaº   s"   € ð* Ô%ØØØð	
ð 
ð 	
r   N)r
   r	   )r
   r    )r'   )r(   r	   r)   r*   r
   r+   )r0   r1   r2   r   r
   r   )r
   r+   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚpropertyÚabcÚabstractmethodr   r   r"   r$   r&   r/   r4   r9   r   r   r   r   r   Y   sú   € € € € € ðð ð ØÔðð ð ñ Ôñ „Xðð ðð ð ñ „Xðð 	Ôðð ð ñ Ôððð ð ð ðð ð ð ð	
ð 	
ð 	
ð 	
ð 	
ð
ð 
ð 
ð 
ðB
ð 
ð 
ð 
ð 
ð 
r   r   )r   r	   r
   r	   )r=   Ú
__future__r   r?   r   Útypingr   r   r   r   r   ÚABCr   r   r   r   ú<module>rD      s®   ðð1ð 1ðf #Ð "Ð "Ð "Ð "Ð "à 
€
€
€
Ø 	€	€	€	Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,ðð ð ð ð<z
ð z
ð z
ð z
ð z
˜œñ z
ô z
ð z
ð z
ð z
r   