libs/partners/exa/langchain_exa/tools.py PYTHON 243 lines View on github.com → Search inside
1"""Tool for the Exa Search API."""23from __future__ import annotations45from typing import Any, Literal67from exa_py import Exa  # type: ignore[untyped-import]8from exa_py.api import (9    HighlightsContentsOptions,  # type: ignore[untyped-import]10    TextContentsOptions,  # type: ignore[untyped-import]11)12from langchain_core.callbacks import (13    CallbackManagerForToolRun,14)15from langchain_core.tools import BaseTool16from pydantic import Field, SecretStr, model_validator1718from langchain_exa._utilities import initialize_client192021class ExaSearchResults(BaseTool):  # type: ignore[override]22    r"""Exa Search tool.2324    Setup:25        Install `langchain-exa` and set environment variable `EXA_API_KEY`.2627        ```bash28        pip install -U langchain-exa29        export EXA_API_KEY="your-api-key"30        ```3132    Instantiation:33        ```python34        from langchain-exa import ExaSearchResults3536        tool = ExaSearchResults()37        ```3839    Invocation with args:40        ```python41        tool.invoke({"query": "what is the weather in SF", "num_results": 1})42        ```4344        ```python45        SearchResponse(46            results=[47                Result(48                    url="https://www.wunderground.com/weather/37.8,-122.4",49                    id="https://www.wunderground.com/weather/37.8,-122.4",50                    title="San Francisco, CA Weather Conditionsstar_ratehome",51                    score=0.1843988299369812,52                    published_date="2023-02-23T01:17:06.594Z",53                    author=None,54                    text="The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.",55                    highlights=None,56                    highlight_scores=None,57                    summary=None,58                )59            ],60            autoprompt_string=None,61        )62        ```6364    Invocation with ToolCall:6566        ```python67        tool.invoke(68            {69                "args": {"query": "what is the weather in SF", "num_results": 1},70                "id": "1",71                "name": tool.name,72                "type": "tool_call",73            }74        )75        ```7677        ```python78        ToolMessage(79            content="Title: San Francisco, CA Weather Conditionsstar_ratehome\nURL: https://www.wunderground.com/weather/37.8,-122.4\nID: https://www.wunderground.com/weather/37.8,-122.4\nScore: 0.1843988299369812\nPublished Date: 2023-02-23T01:17:06.594Z\nAuthor: None\nText: The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.\nHighlights: None\nHighlight Scores: None\nSummary: None\n",80            name="exa_search_results_json",81            tool_call_id="1",82        )83        ```84    """  # noqa: E5018586    name: str = "exa_search_results_json"87    description: str = (88        "Exa Search, one of the best web search APIs built for AI. "89        "Input should be an Exa-optimized query. "90        "Output is a JSON array of the query results"91    )92    client: Exa = Field(default=None)  # type: ignore[assignment]93    exa_api_key: SecretStr = Field(default=SecretStr(""))9495    @model_validator(mode="before")96    @classmethod97    def validate_environment(cls, values: dict) -> Any:98        """Validate the environment."""99        return initialize_client(values)100101    def _run(102        self,103        query: str,104        num_results: int = 10,105        text_contents_options: TextContentsOptions  # noqa: FBT001106        | dict[str, Any]107        | bool108        | None = None,109        highlights: HighlightsContentsOptions | bool | None = None,  # noqa: FBT001110        include_domains: list[str] | None = None,111        exclude_domains: list[str] | None = None,112        start_crawl_date: str | None = None,113        end_crawl_date: str | None = None,114        start_published_date: str | None = None,115        end_published_date: str | None = None,116        use_autoprompt: bool | None = None,  # noqa: FBT001117        livecrawl: Literal["always", "fallback", "never"] | None = None,118        summary: bool | dict[str, str] | None = None,  # noqa: FBT001119        type: Literal["auto", "deep", "fast"] | None = None,  # noqa: A002120        run_manager: CallbackManagerForToolRun | None = None,121    ) -> list[dict] | str:122        # TODO: rename `type` to something else, as it is a reserved keyword123        """Use the tool.124125        Args:126            query: The search query.127            num_results: The number of search results to return (1 to 100). Default: 10128            text_contents_options: How to set the page content of the results. Can be True or a dict with options like max_characters.129            highlights: Whether to include highlights in the results.130            include_domains: A list of domains to include in the search.131            exclude_domains: A list of domains to exclude from the search.132            start_crawl_date: The start date for the crawl (in YYYY-MM-DD format).133            end_crawl_date: The end date for the crawl (in YYYY-MM-DD format).134            start_published_date: The start date for when the document was published (in YYYY-MM-DD format).135            end_published_date: The end date for when the document was published (in YYYY-MM-DD format).136            use_autoprompt: Whether to use autoprompt for the search.137            livecrawl: Option to crawl live webpages if content is not in the index. Options: "always", "fallback", "never"138            summary: Whether to include a summary of the content. Can be a boolean or a dict with a custom query.139            type: The type of search, 'auto', 'deep', or 'fast'.140            run_manager: The run manager for callbacks.141142        """  # noqa: E501143        try:144            return self.client.search_and_contents(145                query,146                num_results=num_results,147                text=text_contents_options,148                highlights=highlights,149                include_domains=include_domains,150                exclude_domains=exclude_domains,151                start_crawl_date=start_crawl_date,152                end_crawl_date=end_crawl_date,153                start_published_date=start_published_date,154                end_published_date=end_published_date,155                use_autoprompt=use_autoprompt,156                livecrawl=livecrawl,157                summary=summary,158                type=type,159            )  # type: ignore[call-overload, misc]160        except Exception as e:161            return repr(e)162163164class ExaFindSimilarResults(BaseTool):  # type: ignore[override]165    """Tool that queries the Metaphor Search API and gets back json."""166167    name: str = "exa_find_similar_results_json"168    description: str = (169        "A wrapper around Exa Find Similar. "170        "Input should be an Exa-optimized query. "171        "Output is a JSON array of the query results"172    )173    client: Exa = Field(default=None)  # type: ignore[assignment]174    exa_api_key: SecretStr = Field(default=SecretStr(""))175    exa_base_url: str | None = None176177    @model_validator(mode="before")178    @classmethod179    def validate_environment(cls, values: dict) -> Any:180        """Validate the environment."""181        return initialize_client(values)182183    def _run(184        self,185        url: str,186        num_results: int = 10,187        text_contents_options: TextContentsOptions  # noqa: FBT001188        | dict[str, Any]189        | bool190        | None = None,191        highlights: HighlightsContentsOptions | bool | None = None,  # noqa: FBT001192        include_domains: list[str] | None = None,193        exclude_domains: list[str] | None = None,194        start_crawl_date: str | None = None,195        end_crawl_date: str | None = None,196        start_published_date: str | None = None,197        end_published_date: str | None = None,198        exclude_source_domain: bool | None = None,  # noqa: FBT001199        category: str | None = None,200        livecrawl: Literal["always", "fallback", "never"] | None = None,201        summary: bool | dict[str, str] | None = None,  # noqa: FBT001202        run_manager: CallbackManagerForToolRun | None = None,203    ) -> list[dict] | str:204        """Use the tool.205206        Args:207            url: The URL to find similar pages for.208            num_results: The number of search results to return (1 to 100). Default: 10209            text_contents_options: How to set the page content of the results. Can be True or a dict with options like max_characters.210            highlights: Whether to include highlights in the results.211            include_domains: A list of domains to include in the search.212            exclude_domains: A list of domains to exclude from the search.213            start_crawl_date: The start date for the crawl (in YYYY-MM-DD format).214            end_crawl_date: The end date for the crawl (in YYYY-MM-DD format).215            start_published_date: The start date for when the document was published (in YYYY-MM-DD format).216            end_published_date: The end date for when the document was published (in YYYY-MM-DD format).217            exclude_source_domain: If `True`, exclude pages from the same domain as the source URL.218            category: Filter for similar pages by category.219            livecrawl: Option to crawl live webpages if content is not in the index. Options: "always", "fallback", "never"220            summary: Whether to include a summary of the content. Can be a boolean or a dict with a custom query.221            run_manager: The run manager for callbacks.222223        """  # noqa: E501224        try:225            return self.client.find_similar_and_contents(226                url,227                num_results=num_results,228                text=text_contents_options,229                highlights=highlights,230                include_domains=include_domains,231                exclude_domains=exclude_domains,232                start_crawl_date=start_crawl_date,233                end_crawl_date=end_crawl_date,234                start_published_date=start_published_date,235                end_published_date=end_published_date,236                exclude_source_domain=exclude_source_domain,237                category=category,238                livecrawl=livecrawl,239                summary=summary,240            )  # type: ignore[call-overload, misc]241        except Exception as e:242            return repr(e)

Code quality findings 2

Ensure try blocks have corresponding except or finally blocks
try-without-except
try:
Ensure try blocks have corresponding except or finally blocks
try-without-except
try:

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.