devstein / langchain

⚡ Building applications with LLMs through composability ⚡
MIT License
1 stars 0 forks source link

Async Support | Search Tools #19

Open devstein opened 1 year ago

devstein commented 1 year ago

Feature request

None of the search tools have async support.

Motivation

Async calls are being used langchain setup with FastAPI. Not having async support for these tools blocks there use.

Your contribution

Happy to help out where needed.

dosubot[bot] commented 1 year ago

Relevant Files

langchain/tools/google_search/tool.py

Explanation

langchain/tools/google_search/tool.py

To add async support to the GoogleSearchRun and GoogleSearchResults classes, you need to update the _arun methods to call the appropriate async methods from the GoogleSearchAPIWrapper. First, you need to ensure that the GoogleSearchAPIWrapper has async methods for running the search and getting the results. Then, update the _arun methods as follows:

class GoogleSearchRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.async_run(query)

class GoogleSearchResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.async_results(query, self.num_results))

Make sure to update the GoogleSearchAPIWrapper to have the async_run and async_results methods that support asynchronous calls.

langchain/tools/bing_search/tool.py

To add async support to the BingSearchRun and BingSearchResults classes, you need to update the _arun methods to call the appropriate async methods from the BingSearchAPIWrapper. First, you need to ensure that the BingSearchAPIWrapper has async methods for running the search and getting the results. Then, update the _arun methods as follows:

class BingSearchRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.async_run(query)
    ...

class BingSearchResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.async_results(query, self.num_results))
    ...

Make sure to implement the async_run and async_results methods in the BingSearchAPIWrapper class to support asynchronous calls.

langchain/tools/searx_search/tool.py

To add async support to the SearxSearchRun and SearxSearchResults classes, you need to update the SearxSearchWrapper class to include async methods for running the search and getting the results. Then, update the _arun methods in both classes to use the new async methods from the wrapper.

  1. Update the SearxSearchWrapper class to include async methods for running the search and getting the results. Add the following methods to the SearxSearchWrapper class:
async def arun(self, query: str) -> str:
    # Implement the async version of the run method here

async def aresults(self, query: str, num_results: int) -> List[Dict[str, Any]]:
    # Implement the async version of the results method here
  1. Update the _arun methods in both SearxSearchRun and SearxSearchResults classes to use the new async methods from the wrapper:

In SearxSearchRun class, update the _arun method:

async def _arun(
    self,
    query: str,
    run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
    """Use the tool asynchronously."""
    return await self.wrapper.arun(query)

In SearxSearchResults class, update the _arun method:

async def _arun(
    self,
    query: str,
    run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
    """Use the tool asynchronously."""
    return (await self.wrapper.aresults(query, self.num_results)).__str__()

With these changes, the SearxSearchRun and SearxSearchResults classes will have async support.

langchain/tools/metaphor_search/tool.py

To add async support to the MetaphorSearchResults class, you need to update the MetaphorSearchAPIWrapper class to include async methods. Here's how you would update the file:

  1. Update the imports to include asyncio and httpx:
import asyncio
import httpx
  1. Add async methods to the MetaphorSearchAPIWrapper class:
class MetaphorSearchAPIWrapper:
    ...
    async def results_async(self, query: str, num_results: int) -> List[Dict]:
        """Get search results asynchronously."""
        async with httpx.AsyncClient() as client:
            response = await client.get(
                self.url,
                params={"query": query, "num_results": num_results},
            )
        response.raise_for_status()
        return response.json()

With these changes, the MetaphorSearchResults class will be able to use the async method results_async from the MetaphorSearchAPIWrapper class.

langchain/tools/graphql/tool.py

To complete the request, we need to update the _arun method in the BaseGraphQLTool class to support async calls. First, we need to make sure that the GraphQLAPIWrapper class has async support. Assuming it does, we can update the _arun method as follows:

import json
from typing import Optional

from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.tools.base import BaseTool
from langchain.utilities.graphql import GraphQLAPIWrapper

class BaseGraphQLTool(BaseTool):
    """Base tool for querying a GraphQL API."""

    graphql_wrapper: GraphQLAPIWrapper

    name = "query_graphql"
    description = """\
    Input to this tool is a detailed and correct GraphQL query, output is a result from the API.
    If the query is not correct, an error message will be returned.
    If an error is returned with 'Bad request' in it, rewrite the query and try again.
    If an error is returned with 'Unauthorized' in it, do not try again, but tell the user to change their authentication.

    Example Input: query {{ allUsers {{ id, name, email }} }}\
    """  # noqa: E501

    class Config:
        """Configuration for this pydantic object."""

        arbitrary_types_allowed = True

    def _run(
        self,
        tool_input: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        result = self.graphql_wrapper.run(tool_input)
        return json.dumps(result, indent=2)

    async def _arun(
        self,
        tool_input: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Graphql tool asynchronously."""
        result = await self.graphql_wrapper.arun(tool_input)
        return json.dumps(result, indent=2)

This change assumes that the GraphQLAPIWrapper class has an arun method that supports async calls. If it doesn't, you'll need to update the GraphQLAPIWrapper class to add async support before making this change.

langchain/tools/google_places/tool.py

To complete the request, I would update the file to add async support for the GooglePlacesTool class. Here's how I would update the file:

"""Tool for the Google search API."""

from typing import Optional

from pydantic import BaseModel, Field

from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.tools.base import BaseTool
from langchain.utilities.google_places_api import GooglePlacesAPIWrapper

class GooglePlacesSchema(BaseModel):
    query: str = Field(..., description="Query for goole maps")

class GooglePlacesTool(BaseTool):
    """Tool that adds the capability to query the Google places API."""

    name = "Google Places"
    description = (
        "A wrapper around Google Places. "
        "Useful for when you need to validate or "
        "discover addressed from ambiguous text. "
        "Input should be a search query."
    )
    api_wrapper: GooglePlacesAPIWrapper = Field(default_factory=GooglePlacesAPIWrapper)

    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return self.api_wrapper.run(query)

    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.arun(query)

I added the async support by changing the _arun method to call the arun method of the GooglePlacesAPIWrapper class. Make sure to also update the GooglePlacesAPIWrapper class to have an arun method that supports async calls.

langchain/tools/ddg_search/tool.py

To add async support to the DuckDuckGoSearchRun and DuckDuckGoSearchResults classes, you need to update the _arun methods to use the async version of the DuckDuckGoSearchAPIWrapper. First, you need to update the DuckDuckGoSearchAPIWrapper class to support async calls. Then, update the _arun methods in both classes to use the async version of the API wrapper.

  1. Update the DuckDuckGoSearchAPIWrapper class to support async calls. Add an async def arun(self, query: str) -> str: method that makes an async request to the DuckDuckGo API.

  2. Update the _arun method in the DuckDuckGoSearchRun class:

async def _arun(
    self,
    query: str,
    run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
    """Use the tool asynchronously."""
    return await self.api_wrapper.arun(query)
  1. Update the _arun method in the DuckDuckGoSearchResults class:
async def _arun(
    self,
    query: str,
    run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
    """Use the tool asynchronously."""
    return str(await self.api_wrapper.aresults(query, self.num_results))
  1. Add an async def aresults(self, query: str, num_results: int) -> List[Dict[str, Any]]: method to the DuckDuckGoSearchAPIWrapper class that makes an async request to the DuckDuckGo API and returns the results.

After making these changes, both the DuckDuckGoSearchRun and DuckDuckGoSearchResults classes will support async calls.

langchain/tools/google_serper/tool.py

To add async support to the GoogleSerperRun and GoogleSerperResults classes, update the _arun methods to use the async version of the API wrapper methods. Also, update the GoogleSerperAPIWrapper class to include async methods if they are not already present.

  1. Update the GoogleSerperAPIWrapper class to include async methods for arun and aresults if they are not already present.

  2. Update the _arun methods in both GoogleSerperRun and GoogleSerperResults classes to use the async version of the API wrapper methods:

class GoogleSerperRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.arun(query))

class GoogleSerperResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.aresults(query))

These changes will ensure that the GoogleSerperRun and GoogleSerperResults classes support async calls.

dosubot[bot] commented 1 year ago

Relevant Files

langchain/tools/google_search/tool.py

Explanation

langchain/tools/google_search/tool.py

To add async support to the GoogleSearchRun and GoogleSearchResults classes, you need to update the _arun methods to call the appropriate async methods from the GoogleSearchAPIWrapper. First, you need to ensure that the GoogleSearchAPIWrapper has async methods for running the search and getting the results. Then, update the _arun methods as follows:

class GoogleSearchRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.async_run(query)

class GoogleSearchResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.async_results(query, self.num_results))

Make sure to update the GoogleSearchAPIWrapper to have the async_run and async_results methods that support asynchronous calls.

langchain/tools/bing_search/tool.py

To add async support to the BingSearchRun and BingSearchResults classes, you need to update the _arun methods to call the appropriate async methods from the BingSearchAPIWrapper. First, you need to ensure that the BingSearchAPIWrapper has async methods for running the search and getting the results. Then, update the _arun methods as follows:

class BingSearchRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.async_run(query)
    ...

class BingSearchResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.async_results(query, self.num_results))
    ...

Make sure to implement the async_run and async_results methods in the BingSearchAPIWrapper class to support asynchronous calls.

langchain/tools/searx_search/tool.py

To add async support to the SearxSearchRun and SearxSearchResults classes, you need to update the SearxSearchWrapper class to include async methods for running the search and getting the results. Then, update the _arun methods in both classes to use the new async methods from the wrapper.

  1. Update the SearxSearchWrapper class to include async methods for running the search and getting the results. Add the following methods to the SearxSearchWrapper class:
async def arun(self, query: str) -> str:
    # Implement the async version of the run method here

async def aresults(self, query: str, num_results: int) -> List[Dict[str, Any]]:
    # Implement the async version of the results method here
  1. Update the _arun methods in both SearxSearchRun and SearxSearchResults classes to use the new async methods from the wrapper:

In SearxSearchRun class, update the _arun method:

async def _arun(
    self,
    query: str,
    run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
    """Use the tool asynchronously."""
    return await self.wrapper.arun(query)

In SearxSearchResults class, update the _arun method:

async def _arun(
    self,
    query: str,
    run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
    """Use the tool asynchronously."""
    return (await self.wrapper.aresults(query, self.num_results)).__str__()

With these changes, the SearxSearchRun and SearxSearchResults classes will have async support.

langchain/tools/metaphor_search/tool.py

To add async support to the MetaphorSearchResults class, you need to update the MetaphorSearchAPIWrapper class to include async methods. Here's how you would update the file:

  1. Update the imports to include asyncio and httpx:
import asyncio
import httpx
  1. Add async methods to the MetaphorSearchAPIWrapper class:
class MetaphorSearchAPIWrapper:
    ...
    async def results_async(self, query: str, num_results: int) -> List[Dict]:
        """Get search results asynchronously."""
        async with httpx.AsyncClient() as client:
            response = await client.get(
                self.url,
                params={"query": query, "num_results": num_results},
            )
        response.raise_for_status()
        return response.json()

With these changes, the MetaphorSearchResults class will be able to use the async method results_async from the MetaphorSearchAPIWrapper class.

langchain/tools/graphql/tool.py

To complete the request, we need to update the _arun method in the BaseGraphQLTool class to support async calls. First, we need to make sure that the GraphQLAPIWrapper class has async support. Assuming it does, we can update the _arun method as follows:

import json
from typing import Optional

from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.tools.base import BaseTool
from langchain.utilities.graphql import GraphQLAPIWrapper

class BaseGraphQLTool(BaseTool):
    """Base tool for querying a GraphQL API."""

    graphql_wrapper: GraphQLAPIWrapper

    name = "query_graphql"
    description = """\
    Input to this tool is a detailed and correct GraphQL query, output is a result from the API.
    If the query is not correct, an error message will be returned.
    If an error is returned with 'Bad request' in it, rewrite the query and try again.
    If an error is returned with 'Unauthorized' in it, do not try again, but tell the user to change their authentication.

    Example Input: query {{ allUsers {{ id, name, email }} }}\
    """  # noqa: E501

    class Config:
        """Configuration for this pydantic object."""

        arbitrary_types_allowed = True

    def _run(
        self,
        tool_input: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        result = self.graphql_wrapper.run(tool_input)
        return json.dumps(result, indent=2)

    async def _arun(
        self,
        tool_input: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Graphql tool asynchronously."""
        result = await self.graphql_wrapper.arun(tool_input)
        return json.dumps(result, indent=2)

This change assumes that the GraphQLAPIWrapper class has an arun method that supports async calls. If it doesn't, you'll need to update the GraphQLAPIWrapper class to add async support before making this change.

langchain/tools/google_places/tool.py

To complete the request, I would update the file to add async support for the GooglePlacesTool class. Here's how I would update the file:

"""Tool for the Google search API."""

from typing import Optional

from pydantic import BaseModel, Field

from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.tools.base import BaseTool
from langchain.utilities.google_places_api import GooglePlacesAPIWrapper

class GooglePlacesSchema(BaseModel):
    query: str = Field(..., description="Query for goole maps")

class GooglePlacesTool(BaseTool):
    """Tool that adds the capability to query the Google places API."""

    name = "Google Places"
    description = (
        "A wrapper around Google Places. "
        "Useful for when you need to validate or "
        "discover addressed from ambiguous text. "
        "Input should be a search query."
    )
    api_wrapper: GooglePlacesAPIWrapper = Field(default_factory=GooglePlacesAPIWrapper)

    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return self.api_wrapper.run(query)

    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.arun(query)

I added the async support by changing the _arun method to call the arun method of the GooglePlacesAPIWrapper class. Make sure to also update the GooglePlacesAPIWrapper class to have an arun method that supports async calls.

langchain/tools/ddg_search/tool.py

To add async support to the DuckDuckGoSearchRun and DuckDuckGoSearchResults classes, you need to update the _arun methods to use the async version of the DuckDuckGoSearchAPIWrapper. First, you need to create an async version of the run and results methods in the DuckDuckGoSearchAPIWrapper class. Then, update the _arun methods in both classes to use the async methods.

  1. Update the DuckDuckGoSearchAPIWrapper class to include async methods:
class DuckDuckGoSearchAPIWrapper:
    ...
    async def async_run(self, query: str) -> str:
        # Implement the async version of the run method

    async def async_results(self, query: str, num_results: int) -> List[Dict[str, Any]]:
        # Implement the async version of the results method
  1. Update the _arun method in the DuckDuckGoSearchRun class:
class DuckDuckGoSearchRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.async_run(query)
  1. Update the _arun method in the DuckDuckGoSearchResults class:
class DuckDuckGoSearchResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.async_results(query, self.num_results))

With these changes, both DuckDuckGoSearchRun and DuckDuckGoSearchResults classes will have async support.

langchain/tools/google_serper/tool.py

To add async support to the GoogleSerperRun and GoogleSerperResults classes, update the _arun methods to use the async version of the API wrapper methods. Also, update the GoogleSerperAPIWrapper class to include async methods if they are not already present.

  1. Update the GoogleSerperAPIWrapper class to include async methods for arun and aresults if they are not already present.

  2. Update the _arun methods in both GoogleSerperRun and GoogleSerperResults classes to use the async version of the API wrapper methods:

class GoogleSerperRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.arun(query))

class GoogleSerperResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.aresults(query))

These changes will ensure that the GoogleSerperRun and GoogleSerperResults classes support async calls.

dosubot[bot] commented 1 year ago

Relevant Files

Explanation

langchain/tools/google_search/tool.py

To add async support to the GoogleSearchRun and GoogleSearchResults classes, you need to update the _arun methods to call the appropriate async methods from the GoogleSearchAPIWrapper. First, you need to ensure that the GoogleSearchAPIWrapper has async methods for running the search and getting the results. Then, update the _arun methods as follows:

class GoogleSearchRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.async_run(query)

class GoogleSearchResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.async_results(query, self.num_results))

Make sure to update the GoogleSearchAPIWrapper to have the async_run and async_results methods that support asynchronous calls.

langchain/tools/bing_search/tool.py

To add async support to the BingSearchRun and BingSearchResults classes, you need to update the _arun methods to call the appropriate async methods from the BingSearchAPIWrapper. First, you need to ensure that the BingSearchAPIWrapper has async methods for running the search and getting the results. Then, update the _arun methods as follows:

class BingSearchRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.async_run(query)
    ...

class BingSearchResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.async_results(query, self.num_results))
    ...

Make sure to implement the async_run and async_results methods in the BingSearchAPIWrapper class to support asynchronous calls.

langchain/tools/searx_search/tool.py

To add async support to the SearxSearchRun and SearxSearchResults classes, you need to update the SearxSearchWrapper class to include async methods for running the search and getting the results. Then, update the _arun methods in both classes to use the new async methods from the wrapper.

  1. Update the SearxSearchWrapper class to include async methods for running the search and getting the results. Add the following methods to the SearxSearchWrapper class:
async def arun(self, query: str) -> str:
    # Implement the async version of the run method here

async def aresults(self, query: str, num_results: int) -> List[Dict[str, Any]]:
    # Implement the async version of the results method here
  1. Update the _arun methods in both SearxSearchRun and SearxSearchResults classes to use the new async methods from the wrapper:

In SearxSearchRun class, update the _arun method:

async def _arun(
    self,
    query: str,
    run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
    """Use the tool asynchronously."""
    return await self.wrapper.arun(query)

In SearxSearchResults class, update the _arun method:

async def _arun(
    self,
    query: str,
    run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
    """Use the tool asynchronously."""
    return (await self.wrapper.aresults(query, self.num_results)).__str__()

With these changes, the SearxSearchRun and SearxSearchResults classes will have async support.

langchain/tools/metaphor_search/tool.py

To add async support to the MetaphorSearchResults class, you need to update the MetaphorSearchAPIWrapper class to include async methods. Here's how you would update the file:

  1. Update the imports to include asyncio and httpx:
import asyncio
import httpx
  1. Add async methods to the MetaphorSearchAPIWrapper class:
class MetaphorSearchAPIWrapper:
    ...
    async def results_async(self, query: str, num_results: int) -> List[Dict]:
        """Get search results asynchronously."""
        async with httpx.AsyncClient() as client:
            response = await client.get(
                self.url,
                params={"query": query, "num_results": num_results},
            )
        response.raise_for_status()
        return response.json()

With these changes, the MetaphorSearchResults class will be able to use the async method results_async from the MetaphorSearchAPIWrapper class.

langchain/tools/graphql/tool.py

To complete the request, we need to update the _arun method in the BaseGraphQLTool class to support async calls. First, we need to make sure that the GraphQLAPIWrapper class has async support. Assuming it does, we can update the _arun method as follows:

import json
from typing import Optional

from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.tools.base import BaseTool
from langchain.utilities.graphql import GraphQLAPIWrapper

class BaseGraphQLTool(BaseTool):
    """Base tool for querying a GraphQL API."""

    graphql_wrapper: GraphQLAPIWrapper

    name = "query_graphql"
    description = """\
    Input to this tool is a detailed and correct GraphQL query, output is a result from the API.
    If the query is not correct, an error message will be returned.
    If an error is returned with 'Bad request' in it, rewrite the query and try again.
    If an error is returned with 'Unauthorized' in it, do not try again, but tell the user to change their authentication.

    Example Input: query {{ allUsers {{ id, name, email }} }}\
    """  # noqa: E501

    class Config:
        """Configuration for this pydantic object."""

        arbitrary_types_allowed = True

    def _run(
        self,
        tool_input: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        result = self.graphql_wrapper.run(tool_input)
        return json.dumps(result, indent=2)

    async def _arun(
        self,
        tool_input: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Graphql tool asynchronously."""
        result = await self.graphql_wrapper.arun(tool_input)
        return json.dumps(result, indent=2)

This change assumes that the GraphQLAPIWrapper class has an arun method that supports async calls. If it doesn't, you'll need to update the GraphQLAPIWrapper class to add async support before making this change.

langchain/tools/google_places/tool.py

To complete the request, I would update the file to add async support for the GooglePlacesTool class. Here's how I would update the file:

"""Tool for the Google search API."""

from typing import Optional

from pydantic import BaseModel, Field

from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.tools.base import BaseTool
from langchain.utilities.google_places_api import GooglePlacesAPIWrapper

class GooglePlacesSchema(BaseModel):
    query: str = Field(..., description="Query for goole maps")

class GooglePlacesTool(BaseTool):
    """Tool that adds the capability to query the Google places API."""

    name = "Google Places"
    description = (
        "A wrapper around Google Places. "
        "Useful for when you need to validate or "
        "discover addressed from ambiguous text. "
        "Input should be a search query."
    )
    api_wrapper: GooglePlacesAPIWrapper = Field(default_factory=GooglePlacesAPIWrapper)

    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return self.api_wrapper.run(query)

    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.arun(query)

I added the async support by implementing the _arun method and calling the arun method of the GooglePlacesAPIWrapper class. Note that you'll also need to update the GooglePlacesAPIWrapper class to support async calls.

langchain/tools/ddg_search/tool.py

To add async support to the DuckDuckGoSearchRun and DuckDuckGoSearchResults classes, you need to update the _arun methods to use the async version of the DuckDuckGoSearchAPIWrapper. First, you need to create an async version of the run and results methods in the DuckDuckGoSearchAPIWrapper class. Then, update the _arun methods in both classes to use the async methods.

  1. Update the DuckDuckGoSearchAPIWrapper class to include async methods:
class DuckDuckGoSearchAPIWrapper:
    ...
    async def async_run(self, query: str) -> str:
        # Implement the async version of the run method

    async def async_results(self, query: str, num_results: int) -> List[Dict[str, Any]]:
        # Implement the async version of the results method
  1. Update the _arun method in the DuckDuckGoSearchRun class:
class DuckDuckGoSearchRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.api_wrapper.async_run(query)
  1. Update the _arun method in the DuckDuckGoSearchResults class:
class DuckDuckGoSearchResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.async_results(query, self.num_results))

With these changes, both DuckDuckGoSearchRun and DuckDuckGoSearchResults classes will have async support.

langchain/tools/google_serper/tool.py

To add async support to the GoogleSerperRun and GoogleSerperResults classes, update the _arun methods to use the async version of the API wrapper methods. Also, update the GoogleSerperAPIWrapper class to include async methods if they are not already present.

  1. Update the GoogleSerperAPIWrapper class to include async methods for arun and aresults if they are not already present.

  2. Update the _arun methods in both GoogleSerperRun and GoogleSerperResults classes to use the async version of the API wrapper methods:

class GoogleSerperRun(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.arun(query))

class GoogleSerperResults(BaseTool):
    ...
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return str(await self.api_wrapper.aresults(query))

These changes will ensure that the GoogleSerperRun and GoogleSerperResults classes support async calls.