Source code for langchain.tools.azure_cognitive_services.speech2text
from __future__ import annotations
import logging
import time
from typing import Any, Dict, Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import root_validator
from langchain.tools.azure_cognitive_services.utils import (
    detect_file_src_type,
    download_audio_from_url,
)
from langchain.tools.base import BaseTool
from langchain.utils import get_from_dict_or_env
logger = logging.getLogger(__name__)
[docs]class AzureCogsSpeech2TextTool(BaseTool):
    """Tool that queries the Azure Cognitive Services Speech2Text API.
    In order to set this up, follow instructions at:
    https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/get-started-speech-to-text?pivots=programming-language-python
    """
    azure_cogs_key: str = ""  #: :meta private:
    azure_cogs_region: str = ""  #: :meta private:
    speech_language: str = "en-US"  #: :meta private:
    speech_config: Any  #: :meta private:
    name: str = "azure_cognitive_services_speech2text"
    description: str = (
        "A wrapper around Azure Cognitive Services Speech2Text. "
        "Useful for when you need to transcribe audio to text. "
        "Input should be a url to an audio file."
    )
    @root_validator(pre=True)
    def validate_environment(cls, values: Dict) -> Dict:
        """Validate that api key and endpoint exists in environment."""
        azure_cogs_key = get_from_dict_or_env(
            values, "azure_cogs_key", "AZURE_COGS_KEY"
        )


)
        azure_cogs_region = get_from_dict_or_env(
            values, "azure_cogs_region", "AZURE_COGS_REGION"
        )
        try:
            import azure.cognitiveservices.speech as speechsdk
            values["speech_config"] = speechsdk.SpeechConfig(
                subscription=azure_cogs_key, region=azure_cogs_region
            )
        except ImportError:
            raise ImportError(
                "azure-cognitiveservices-speech is not installed. "
                "Run `pip install azure-cognitiveservices-speech` to install."
            )
        return values
    def _continuous_recognize(self, speech_recognizer: Any) -> str:
        done = False
        text = ""
        def stop_cb(evt: Any) -> None:
            """callback that stop continuous recognition"""
            speech_recognizer.stop_continuous_recognition_async()
            nonlocal done
            done = True
        def retrieve_cb(evt: Any) -> None:
            """callback that retrieves the intermediate recognition results"""
            nonlocal text
            text += evt.result.text
        # retrieve text on recognized events
        speech_recognizer.recognized.connect(retrieve_cb)
        # stop continuous recognition on either session stopped or canceled events
        speech_recognizer.session_stopped.connect(stop_cb)
        speech_recognizer.canceled.connect(stop_cb)
        # Start continuous speech recognition
        speech_recognizer.start_continuous_recognition_async()
        while not done:
            time.sleep(0.5)
        return text
    def _speech2text(self, audio_path: str, speech_language: str) -> str:
        try:
            import azure.cognitiveservices.speech as speechsdk
        except ImportError:
            pass


except ImportError:
            pass
        audio_src_type = detect_file_src_type(audio_path)
        if audio_src_type == "local":
            audio_config = speechsdk.AudioConfig(filename=audio_path)
        elif audio_src_type == "remote":
            tmp_audio_path = download_audio_from_url(audio_path)
            audio_config = speechsdk.AudioConfig(filename=tmp_audio_path)
        else:
            raise ValueError(f"Invalid audio path: {audio_path}")
        self.speech_config.speech_recognition_language = speech_language
        speech_recognizer = speechsdk.SpeechRecognizer(self.speech_config, audio_config)
        return self._continuous_recognize(speech_recognizer)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        try:
            text = self._speech2text(query, self.speech_language)
            return text
        except Exception as e:
            raise RuntimeError(f"Error while running AzureCogsSpeech2TextTool: {e}")


Source code for langchain.tools.brave_search.tool
from __future__ import annotations
from typing import Any, Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools.base import BaseTool
from langchain.utilities.brave_search import BraveSearchWrapper
[docs]class BraveSearch(BaseTool):
    """Tool that queries the BraveSearch."""
    name: str = "brave_search"
    description: str = (
        "a search engine. "
        "useful for when you need to answer questions about current events."
        " input should be a search query."
    )
    search_wrapper: BraveSearchWrapper
[docs]    @classmethod
    def from_api_key(
        cls, api_key: str, search_kwargs: Optional[dict] = None, **kwargs: Any
    ) -> BraveSearch:
        """Create a tool from an api key.
        Args:
            api_key: The api key to use.
            search_kwargs: Any additional kwargs to pass to the search wrapper.
            **kwargs: Any additional kwargs to pass to the tool.
        Returns:
            A tool.
        """
        wrapper = BraveSearchWrapper(api_key=api_key, search_kwargs=search_kwargs or {})
        return cls(search_wrapper=wrapper, **kwargs)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return self.search_wrapper.run(query)


Source code for langchain.tools.golden_query.tool
"""Tool for the Golden API."""
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools.base import BaseTool
from langchain.utilities.golden_query import GoldenQueryAPIWrapper
[docs]class GoldenQueryRun(BaseTool):
    """Tool that adds the capability to query using the Golden API and get back JSON."""
    name: str = "Golden Query"
    description: str = (
        "A wrapper around Golden Query API."
        " Useful for getting entities that match"
        " a natural language query from Golden's Knowledge Base."
        "\nExample queries:"
        "\n- companies in nanotech"
        "\n- list of cloud providers starting in 2019"
        "\nInput should be the natural language query."
        "\nOutput is a paginated list of results or an error object"
        " in JSON format."
    )
    api_wrapper: GoldenQueryAPIWrapper
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Golden tool."""
        return self.api_wrapper.run(query)


Source code for langchain.tools.ddg_search.tool
"""Tool for the DuckDuckGo search API."""
import warnings
from typing import Any, Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import Field
from langchain.tools.base import BaseTool
from langchain.utilities.duckduckgo_search import DuckDuckGoSearchAPIWrapper
[docs]class DuckDuckGoSearchRun(BaseTool):
    """Tool that queries the DuckDuckGo search API."""
    name: str = "duckduckgo_search"
    description: str = (
        "A wrapper around DuckDuckGo Search. "
        "Useful for when you need to answer questions about current events. "
        "Input should be a search query."
    )
    api_wrapper: DuckDuckGoSearchAPIWrapper = Field(
        default_factory=DuckDuckGoSearchAPIWrapper
    )
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return self.api_wrapper.run(query)
[docs]class DuckDuckGoSearchResults(BaseTool):
    """Tool that queries the DuckDuckGo search API and gets back json."""
    name: str = "DuckDuckGo Results JSON"
    description: str = (
        "A wrapper around Duck Duck Go Search. "
        "Useful for when you need to answer questions about current events. "
        "Input should be a search query. Output is a JSON array of the query results"
    )
    num_results: int = 4
    api_wrapper: DuckDuckGoSearchAPIWrapper = Field(
        default_factory=DuckDuckGoSearchAPIWrapper


default_factory=DuckDuckGoSearchAPIWrapper
    )
    backend: str = "api"
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        res = self.api_wrapper.results(query, self.num_results, backend=self.backend)
        res_strs = [", ".join([f"{k}: {v}" for k, v in d.items()]) for d in res]
        return ", ".join([f"[{rs}]" for rs in res_strs])
[docs]def DuckDuckGoSearchTool(*args: Any, **kwargs: Any) -> DuckDuckGoSearchRun:
    """
    Deprecated. Use DuckDuckGoSearchRun instead.
    Args:
        *args:
        **kwargs:
    Returns:
        DuckDuckGoSearchRun
    """
    warnings.warn(
        "DuckDuckGoSearchTool will be deprecated in the future. "
        "Please use DuckDuckGoSearchRun instead.",
        DeprecationWarning,
    )
    return DuckDuckGoSearchRun(*args, **kwargs)


Source code for langchain.tools.ainetwork.transfer
import json
from typing import Optional, Type
from langchain.callbacks.manager import AsyncCallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.ainetwork.base import AINBaseTool
[docs]class TransferSchema(BaseModel):
    address: str = Field(..., description="Address to transfer AIN to")
    amount: int = Field(..., description="Amount of AIN to transfer")
[docs]class AINTransfer(AINBaseTool):
    name: str = "AINtransfer"
    description: str = "Transfers AIN to a specified address"
    args_schema: Type[TransferSchema] = TransferSchema
    async def _arun(
        self,
        address: str,
        amount: int,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        try:
            res = await self.interface.wallet.transfer(address, amount, nonce=-1)
            return json.dumps(res, ensure_ascii=False)
        except Exception as e:
            return f"{type(e).__name__}: {str(e)}"


Source code for langchain.tools.ainetwork.rule
import builtins
import json
from typing import Optional, Type
from langchain.callbacks.manager import AsyncCallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.ainetwork.base import AINBaseTool, OperationType
[docs]class RuleSchema(BaseModel):
    type: OperationType = Field(...)
    path: str = Field(..., description="Path on the blockchain where the rule applies")
    eval: Optional[str] = Field(None, description="eval string to determine permission")
[docs]class AINRuleOps(AINBaseTool):
    name: str = "AINruleOps"
    description: str = """
Covers the write `rule` for the AINetwork Blockchain database. The SET type specifies write permissions using the `eval` variable as a JavaScript eval string.
In order to AINvalueOps with SET at the path, the execution result of the `eval` string must be true.
## Path Rules
1. Allowed characters for directory: `[a-zA-Z_0-9]`
2. Use `$<key>` for template variables as directory.
## Eval String Special Variables
- auth.addr: Address of the writer for the path
- newData: New data for the path
- data: Current data for the path
- currentTime: Time in seconds
- lastBlockNumber: Latest processed block number
## Eval String Functions
- getValue(<path>)
- getRule(<path>)
- getOwner(<path>)
- getFunction(<path>)
- evalRule(<path>, <value to set>, auth, currentTime)
- evalOwner(<path>, 'write_owner', auth)
## SET Example
- type: SET
- path: /apps/langchain_project_1/$from/$to/$img


- path: /apps/langchain_project_1/$from/$to/$img
- eval: auth.addr===$from&&!getValue('/apps/image_db/'+$img)
## GET Example
- type: GET
- path: /apps/langchain_project_1
"""  # noqa: E501
    args_schema: Type[BaseModel] = RuleSchema
    async def _arun(
        self,
        type: OperationType,
        path: str,
        eval: Optional[str] = None,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        from ain.types import ValueOnlyTransactionInput
        try:
            if type is OperationType.SET:
                if eval is None:
                    raise ValueError("'eval' is required for SET operation.")
                res = await self.interface.db.ref(path).setRule(
                    transactionInput=ValueOnlyTransactionInput(
                        value={".rule": {"write": eval}}
                    )
                )
            elif type is OperationType.GET:
                res = await self.interface.db.ref(path).getRule()
            else:
                raise ValueError(f"Unsupported 'type': {type}.")
            return json.dumps(res, ensure_ascii=False)
        except Exception as e:
            return f"{builtins.type(e).__name__}: {str(e)}"


Source code for langchain.tools.ainetwork.utils
"""AINetwork Blockchain tool utils."""
from __future__ import annotations
import os
from typing import TYPE_CHECKING, Literal, Optional
if TYPE_CHECKING:
    from ain.ain import Ain
[docs]def authenticate(network: Optional[Literal["mainnet", "testnet"]] = "testnet") -> Ain:
    """Authenticate using the AIN Blockchain"""
    try:
        from ain.ain import Ain
    except ImportError as e:
        raise ImportError(
            "Cannot import ain-py related modules. Please install the package with "
            "`pip install ain-py`."
        ) from e
    if network == "mainnet":
        provider_url = "https://mainnet-api.ainetwork.ai/"
        chain_id = 1
        if "AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY" in os.environ:
            private_key = os.environ["AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY"]
        else:
            raise EnvironmentError(
                "Error: The AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY environmental variable "
                "has not been set."
            )
    elif network == "testnet":
        provider_url = "https://testnet-api.ainetwork.ai/"
        chain_id = 0
        if "AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY" in os.environ:
            private_key = os.environ["AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY"]
        else:
            raise EnvironmentError(
                "Error: The AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY environmental variable "
                "has not been set."
            )
    elif network is None:
        if (
            "AIN_BLOCKCHAIN_PROVIDER_URL" in os.environ
            and "AIN_BLOCKCHAIN_CHAIN_ID" in os.environ
            and "AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY" in os.environ
        ):


and "AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY" in os.environ
        ):
            provider_url = os.environ["AIN_BLOCKCHAIN_PROVIDER_URL"]
            chain_id = int(os.environ["AIN_BLOCKCHAIN_CHAIN_ID"])
            private_key = os.environ["AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY"]
        else:
            raise EnvironmentError(
                "Error: The AIN_BLOCKCHAIN_PROVIDER_URL and "
                "AIN_BLOCKCHAIN_ACCOUNT_PRIVATE_KEY and AIN_BLOCKCHAIN_CHAIN_ID "
                "environmental variable has not been set."
            )
    else:
        raise ValueError(f"Unsupported 'network': {network}")
    ain = Ain(provider_url, chain_id)
    ain.wallet.addAndSetDefaultAccount(private_key)
    return ain


Source code for langchain.tools.ainetwork.owner
import builtins
import json
from typing import List, Optional, Type, Union
from langchain.callbacks.manager import AsyncCallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.ainetwork.base import AINBaseTool, OperationType
[docs]class RuleSchema(BaseModel):
    type: OperationType = Field(...)
    path: str = Field(..., description="Blockchain reference path")
    address: Optional[Union[str, List[str]]] = Field(
        None, description="A single address or a list of addresses"
    )
    write_owner: Optional[bool] = Field(
        False, description="Authority to edit the `owner` property of the path"
    )
    write_rule: Optional[bool] = Field(
        False, description="Authority to edit `write rule` for the path"
    )
    write_function: Optional[bool] = Field(
        False, description="Authority to `set function` for the path"
    )
    branch_owner: Optional[bool] = Field(
        False, description="Authority to initialize `owner` of sub-paths"
    )
[docs]class AINOwnerOps(AINBaseTool):
    name: str = "AINownerOps"
    description: str = """
Rules for `owner` in AINetwork Blockchain database.
An address set as `owner` can modify permissions according to its granted authorities
## Path Rule
- (/[a-zA-Z_0-9]+)+
- Permission checks ascend from the most specific (child) path to broader (parent) paths until an `owner` is located.
## Address Rules
- 0x[0-9a-fA-F]{40}: 40-digit hexadecimal address


- *: All addresses permitted
- Defaults to the current session's address
## SET
- `SET` alters permissions for specific addresses, while other addresses remain unaffected.
- When removing an address of `owner`, set all authorities for that address to false.
- message `write_owner permission evaluated false` if fail
### Example
- type: SET
- path: /apps/langchain
- address: [<address 1>, <address 2>]
- write_owner: True
- write_rule: True
- write_function: True
- branch_owner: True
## GET
- Provides all addresses with `owner` permissions and their authorities in the path.
### Example
- type: GET
- path: /apps/langchain
"""  # noqa: E501
    args_schema: Type[BaseModel] = RuleSchema
    async def _arun(
        self,
        type: OperationType,
        path: str,
        address: Optional[Union[str, List[str]]] = None,
        write_owner: Optional[bool] = None,
        write_rule: Optional[bool] = None,
        write_function: Optional[bool] = None,
        branch_owner: Optional[bool] = None,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        from ain.types import ValueOnlyTransactionInput
        try:
            if type is OperationType.SET:
                if address is None:
                    address = self.interface.wallet.defaultAccount.address
                if isinstance(address, str):
                    address = [address]
                res = await self.interface.db.ref(path).setOwner(
                    transactionInput=ValueOnlyTransactionInput(
                        value={
                            ".owner": {
                                "owners": {
                                    address: {
                                        "write_owner": write_owner or False,


address: {
                                        "write_owner": write_owner or False,
                                        "write_rule": write_rule or False,
                                        "write_function": write_function or False,
                                        "branch_owner": branch_owner or False,
                                    }
                                    for address in address
                                }
                            }
                        }
                    )
                )
            elif type is OperationType.GET:
                res = await self.interface.db.ref(path).getOwner()
            else:
                raise ValueError(f"Unsupported 'type': {type}.")
            return json.dumps(res, ensure_ascii=False)
        except Exception as e:
            return f"{builtins.type(e).__name__}: {str(e)}"


Source code for langchain.tools.ainetwork.app
import builtins
import json
from enum import Enum
from typing import List, Optional, Type, Union
from langchain.callbacks.manager import AsyncCallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.ainetwork.base import AINBaseTool
[docs]class AppOperationType(str, Enum):
    SET_ADMIN = "SET_ADMIN"
    GET_CONFIG = "GET_CONFIG"
[docs]class AppSchema(BaseModel):
    type: AppOperationType = Field(...)
    appName: str = Field(..., description="Name of the application on the blockchain")
    address: Optional[Union[str, List[str]]] = Field(
        None,
        description=(
            "A single address or a list of addresses. Default: current session's "
            "address"
        ),
    )
[docs]class AINAppOps(AINBaseTool):
    name: str = "AINappOps"
    description: str = """
Create an app in the AINetwork Blockchain database by creating the /apps/<appName> path.
An address set as `admin` can grant `owner` rights to other addresses (refer to `AINownerOps` for more details).
Also, `admin` is initialized to have all `owner` permissions and `rule` allowed for that path.
## appName Rule
- [a-z_0-9]+
## address Rules
- 0x[0-9a-fA-F]{40}
- Defaults to the current session's address
- Multiple addresses can be specified if needed
## SET_ADMIN Example 1
- type: SET_ADMIN
- appName: ain_project
### Result:
1. Path /apps/ain_project created.
2. Current session's address registered as admin.


2. Current session's address registered as admin.
## SET_ADMIN Example 2
- type: SET_ADMIN
- appName: test_project
- address: [<address1>, <address2>]
### Result:
1. Path /apps/test_project created.
2. <address1> and <address2> registered as admin.
"""  # noqa: E501
    args_schema: Type[BaseModel] = AppSchema
    async def _arun(
        self,
        type: AppOperationType,
        appName: str,
        address: Optional[Union[str, List[str]]] = None,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        from ain.types import ValueOnlyTransactionInput
        from ain.utils import getTimestamp
        try:
            if type is AppOperationType.SET_ADMIN:
                if address is None:
                    address = self.interface.wallet.defaultAccount.address
                if isinstance(address, str):
                    address = [address]
                res = await self.interface.db.ref(
                    f"/manage_app/{appName}/create/{getTimestamp()}"
                ).setValue(
                    transactionInput=ValueOnlyTransactionInput(
                        value={"admin": {address: True for address in address}}
                    )
                )
            elif type is AppOperationType.GET_CONFIG:
                res = await self.interface.db.ref(
                    f"/manage_app/{appName}/config"
                ).getValue()
            else:
                raise ValueError(f"Unsupported 'type': {type}.")
            return json.dumps(res, ensure_ascii=False)
        except Exception as e:
            return f"{builtins.type(e).__name__}: {str(e)}"


Source code for langchain.tools.ainetwork.base
"""Base class for AINetwork tools."""
from __future__ import annotations
import asyncio
import threading
from enum import Enum
from typing import TYPE_CHECKING, Any, Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import Field
from langchain.tools.ainetwork.utils import authenticate
from langchain.tools.base import BaseTool
if TYPE_CHECKING:
    from ain.ain import Ain
[docs]class OperationType(str, Enum):
    SET = "SET"
    GET = "GET"
[docs]class AINBaseTool(BaseTool):
    """Base class for the AINetwork tools."""
    interface: Ain = Field(default_factory=authenticate)
    """The interface object for the AINetwork Blockchain."""
    def _run(
        self,
        *args: Any,
        run_manager: Optional[CallbackManagerForToolRun] = None,
        **kwargs: Any,
    ) -> str:
        try:
            loop = asyncio.get_event_loop()
        except RuntimeError:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
        if loop.is_closed():
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
        if loop.is_running():
            result_container = []
            def thread_target() -> None:
                nonlocal result_container
                new_loop = asyncio.new_event_loop()
                asyncio.set_event_loop(new_loop)
                try:
                    result_container.append(
                        new_loop.run_until_complete(self._arun(*args, **kwargs))
                    )
                except Exception as e:
                    result_container.append(e)
                finally:
                    new_loop.close()
            thread = threading.Thread(target=thread_target)


new_loop.close()
            thread = threading.Thread(target=thread_target)
            thread.start()
            thread.join()
            result = result_container[0]
            if isinstance(result, Exception):
                raise result
            return result
        else:
            result = loop.run_until_complete(self._arun(*args, **kwargs))
            loop.close()
            return result


Source code for langchain.tools.ainetwork.value
import builtins
import json
from typing import Optional, Type, Union
from langchain.callbacks.manager import AsyncCallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.ainetwork.base import AINBaseTool, OperationType
[docs]class ValueSchema(BaseModel):
    type: OperationType = Field(...)
    path: str = Field(..., description="Blockchain reference path")
    value: Optional[Union[int, str, float, dict]] = Field(
        None, description="Value to be set at the path"
    )
[docs]class AINValueOps(AINBaseTool):
    name: str = "AINvalueOps"
    description: str = """
Covers the read and write value for the AINetwork Blockchain database.
## SET
- Set a value at a given path
### Example
- type: SET
- path: /apps/langchain_test_1/object
- value: {1: 2, "34": 56}
## GET
- Retrieve a value at a given path
### Example
- type: GET
- path: /apps/langchain_test_1/DB
## Special paths
- `/accounts/<address>/balance`: Account balance
- `/accounts/<address>/nonce`: Account nonce
- `/apps`: Applications
- `/consensus`: Consensus
- `/checkin`: Check-in
- `/deposit/<service id>/<address>/<deposit id>`: Deposit
- `/deposit_accounts/<service id>/<address>/<account id>`: Deposit accounts
- `/escrow`: Escrow
- `/payments`: Payment
- `/sharding`: Sharding
- `/token/name`: Token name
- `/token/symbol`: Token symbol
- `/token/total_supply`: Token total supply


- `/token/symbol`: Token symbol
- `/token/total_supply`: Token total supply
- `/transfer/<address from>/<address to>/<key>/value`: Transfer
- `/withdraw/<service id>/<address>/<withdraw id>`: Withdraw
"""
    args_schema: Type[BaseModel] = ValueSchema
    async def _arun(
        self,
        type: OperationType,
        path: str,
        value: Optional[Union[int, str, float, dict]] = None,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        from ain.types import ValueOnlyTransactionInput
        try:
            if type is OperationType.SET:
                if value is None:
                    raise ValueError("'value' is required for SET operation.")
                res = await self.interface.db.ref(path).setValue(
                    transactionInput=ValueOnlyTransactionInput(value=value)
                )
            elif type is OperationType.GET:
                res = await self.interface.db.ref(path).getValue()
            else:
                raise ValueError(f"Unsupported 'type': {type}.")
            return json.dumps(res, ensure_ascii=False)
        except Exception as e:
            return f"{builtins.type(e).__name__}: {str(e)}"


Source code for langchain.tools.sleep.tool
"""Tool for agent to sleep."""
from asyncio import sleep as asleep
from time import sleep
from typing import Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.base import BaseTool
[docs]class SleepInput(BaseModel):
    """Input for CopyFileTool."""
    sleep_time: int = Field(..., description="Time to sleep in seconds")
[docs]class SleepTool(BaseTool):
    """Tool that adds the capability to sleep."""
    name: str = "sleep"
    args_schema: Type[BaseModel] = SleepInput
    description: str = "Make agent sleep for a specified number of seconds."
    def _run(
        self,
        sleep_time: int,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Sleep tool."""
        sleep(sleep_time)
        return f"Agent slept for {sleep_time} seconds."
    async def _arun(
        self,
        sleep_time: int,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the sleep tool asynchronously."""
        await asleep(sleep_time)
        return f"Agent slept for {sleep_time} seconds."


Source code for langchain.tools.youtube.search
"""
Adapted from https://github.com/venuv/langchain_yt_tools
CustomYTSearchTool searches YouTube videos related to a person
and returns a specified number of video URLs.
Input to this tool should be a comma separated list,
 - the first part contains a person name
 - and the second(optional) a number that is the
    maximum number of video results to return
 """
import json
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools import BaseTool
[docs]class YouTubeSearchTool(BaseTool):
    """Tool that queries YouTube."""
    name: str = "youtube_search"
    description: str = (
        "search for youtube videos associated with a person. "
        "the input to this tool should be a comma separated list, "
        "the first part contains a person name and the second a "
        "number that is the maximum number of video results "
        "to return aka num_results. the second part is optional"
    )
    def _search(self, person: str, num_results: int) -> str:
        from youtube_search import YoutubeSearch
        results = YoutubeSearch(person, num_results).to_json()
        data = json.loads(results)
        url_suffix_list = [
            "https://www.youtube.com" + video["url_suffix"] for video in data["videos"]
        ]
        return str(url_suffix_list)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        values = query.split(",")
        person = values[0]
        if len(values) > 1:


person = values[0]
        if len(values) > 1:
            num_results = int(values[1])
        else:
            num_results = 2
        return self._search(person, num_results)


Source code for langchain.tools.vectorstore.tool
"""Tools for interacting with vectorstores."""
import json
from typing import Any, Dict, Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.llms.openai import OpenAI
from langchain.pydantic_v1 import BaseModel, Field
from langchain.schema.language_model import BaseLanguageModel
from langchain.schema.vectorstore import VectorStore
from langchain.tools.base import BaseTool
[docs]class BaseVectorStoreTool(BaseModel):
    """Base class for tools that use a VectorStore."""
    vectorstore: VectorStore = Field(exclude=True)
    llm: BaseLanguageModel = Field(default_factory=lambda: OpenAI(temperature=0))
    class Config(BaseTool.Config):
        """Configuration for this pydantic object."""
        arbitrary_types_allowed = True
def _create_description_from_template(values: Dict[str, Any]) -> Dict[str, Any]:
    values["description"] = values["template"].format(name=values["name"])
    return values
[docs]class VectorStoreQATool(BaseVectorStoreTool, BaseTool):
    """Tool for the VectorDBQA chain. To be initialized with name and chain."""
[docs]    @staticmethod
    def get_description(name: str, description: str) -> str:
        template: str = (
            "Useful for when you need to answer questions about {name}. "
            "Whenever you need information about {description} "
            "you should ALWAYS use this. "
            "Input should be a fully formed question."
        )
        return template.format(name=name, description=description)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""


) -> str:
        """Use the tool."""
        from langchain.chains.retrieval_qa.base import RetrievalQA
        chain = RetrievalQA.from_chain_type(
            self.llm, retriever=self.vectorstore.as_retriever()
        )
        return chain.run(
            query, callbacks=run_manager.get_child() if run_manager else None
        )
[docs]class VectorStoreQAWithSourcesTool(BaseVectorStoreTool, BaseTool):
    """Tool for the VectorDBQAWithSources chain."""
[docs]    @staticmethod
    def get_description(name: str, description: str) -> str:
        template: str = (
            "Useful for when you need to answer questions about {name} and the sources "
            "used to construct the answer. "
            "Whenever you need information about {description} "
            "you should ALWAYS use this. "
            " Input should be a fully formed question. "
            "Output is a json serialized dictionary with keys `answer` and `sources`. "
            "Only use this tool if the user explicitly asks for sources."
        )
        return template.format(name=name, description=description)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        from langchain.chains.qa_with_sources.retrieval import (
            RetrievalQAWithSourcesChain,
        )
        chain = RetrievalQAWithSourcesChain.from_chain_type(
            self.llm, retriever=self.vectorstore.as_retriever()
        )
        return json.dumps(
            chain(
                {chain.question_key: query},
                return_only_outputs=True,


chain(
                {chain.question_key: query},
                return_only_outputs=True,
                callbacks=run_manager.get_child() if run_manager else None,
            )
        )


Source code for langchain.tools.eleven_labs.models
from enum import Enum
[docs]class ElevenLabsModel(str, Enum):
    """Models available for Eleven Labs Text2Speech."""
    MULTI_LINGUAL = "eleven_multilingual_v1"
    MONO_LINGUAL = "eleven_monolingual_v1"


Source code for langchain.tools.eleven_labs.text2speech
import tempfile
from enum import Enum
from typing import Any, Dict, Optional, Union
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import root_validator
from langchain.tools.base import BaseTool
from langchain.utils import get_from_dict_or_env
def _import_elevenlabs() -> Any:
    try:
        import elevenlabs
    except ImportError as e:
        raise ImportError(
            "Cannot import elevenlabs, please install `pip install elevenlabs`."
        ) from e
    return elevenlabs
[docs]class ElevenLabsModel(str, Enum):
    """Models available for Eleven Labs Text2Speech."""
    MULTI_LINGUAL = "eleven_multilingual_v1"
    MONO_LINGUAL = "eleven_monolingual_v1"
[docs]class ElevenLabsText2SpeechTool(BaseTool):
    """Tool that queries the Eleven Labs Text2Speech API.
    In order to set this up, follow instructions at:
    https://docs.elevenlabs.io/welcome/introduction
    """
    model: Union[ElevenLabsModel, str] = ElevenLabsModel.MULTI_LINGUAL
    name: str = "eleven_labs_text2speech"
    description: str = (
        "A wrapper around Eleven Labs Text2Speech. "
        "Useful for when you need to convert text to speech. "
        "It supports multiple languages, including English, German, Polish, "
        "Spanish, Italian, French, Portuguese, and Hindi. "
    )
    @root_validator(pre=True)
    def validate_environment(cls, values: Dict) -> Dict:
        """Validate that api key exists in environment."""


"""Validate that api key exists in environment."""
        _ = get_from_dict_or_env(values, "eleven_api_key", "ELEVEN_API_KEY")
        return values
    def _run(
        self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool."""
        elevenlabs = _import_elevenlabs()
        try:
            speech = elevenlabs.generate(text=query, model=self.model)
            with tempfile.NamedTemporaryFile(
                mode="bx", suffix=".wav", delete=False
            ) as f:
                f.write(speech)
            return f.name
        except Exception as e:
            raise RuntimeError(f"Error while running ElevenLabsText2SpeechTool: {e}")
[docs]    def play(self, speech_file: str) -> None:
        """Play the text as speech."""
        elevenlabs = _import_elevenlabs()
        with open(speech_file, mode="rb") as f:
            speech = f.read()
        elevenlabs.play(speech)
[docs]    def stream_speech(self, query: str) -> None:
        """Stream the text as speech as it is generated.
        Play the text in your speakers."""
        elevenlabs = _import_elevenlabs()
        speech_stream = elevenlabs.generate(text=query, model=self.model, stream=True)
        elevenlabs.stream(speech_stream)


Source code for langchain.tools.zapier.tool
"""## Zapier Natural Language Actions API
\
Full docs here: https://nla.zapier.com/start/
**Zapier Natural Language Actions** gives you access to the 5k+ apps, 20k+ actions
on Zapier's platform through a natural language API interface.
NLA supports apps like Gmail, Salesforce, Trello, Slack, Asana, HubSpot, Google Sheets,
Microsoft Teams, and thousands more apps: https://zapier.com/apps
Zapier NLA handles ALL the underlying API auth and translation from
natural language --> underlying API call --> return simplified output for LLMs
The key idea is you, or your users, expose a set of actions via an oauth-like setup
window, which you can then query and execute via a REST API.
NLA offers both API Key and OAuth for signing NLA API requests.
1. Server-side (API Key): for quickly getting started, testing, and production scenarios
    where LangChain will only use actions exposed in the developer's Zapier account
    (and will use the developer's connected accounts on Zapier.com)
2. User-facing (Oauth): for production scenarios where you are deploying an end-user
    facing application and LangChain needs access to end-user's exposed actions and
    connected accounts on Zapier.com
This quick start will focus on the server-side use case for brevity.
Review [full docs](https://nla.zapier.com/start/) for user-facing oauth developer
support.
Typically, you'd use SequentialChain, here's a basic example:
    1. Use NLA to find an email in Gmail
    2. Use LLMChain to generate a draft reply to (1)


2. Use LLMChain to generate a draft reply to (1)
    3. Use NLA to send the draft reply (2) to someone in Slack via direct message
In code, below:
```python
import os
# get from https://platform.openai.com/
os.environ["OPENAI_API_KEY"] = os.environ.get("OPENAI_API_KEY", "")
# get from https://nla.zapier.com/docs/authentication/
os.environ["ZAPIER_NLA_API_KEY"] = os.environ.get("ZAPIER_NLA_API_KEY", "")
from langchain.llms import OpenAI
from langchain.agents import initialize_agent
from langchain.agents.agent_toolkits import ZapierToolkit
from langchain.utilities.zapier import ZapierNLAWrapper
## step 0. expose gmail 'find email' and slack 'send channel message' actions
# first go here, log in, expose (enable) the two actions:
#    https://nla.zapier.com/demo/start
#    -- for this example, can leave all fields "Have AI guess"
# in an oauth scenario, you'd get your own <provider> id (instead of 'demo')
# which you route your users through first
llm = OpenAI(temperature=0)
zapier = ZapierNLAWrapper()
## To leverage OAuth you may pass the value `nla_oauth_access_token` to
## the ZapierNLAWrapper. If you do this there is no need to initialize
## the ZAPIER_NLA_API_KEY env variable
# zapier = ZapierNLAWrapper(zapier_nla_oauth_access_token="TOKEN_HERE")
toolkit = ZapierToolkit.from_zapier_nla_wrapper(zapier)
agent = initialize_agent(
    toolkit.get_tools(),
    llm,


agent = initialize_agent(
    toolkit.get_tools(),
    llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)
agent.run(("Summarize the last email I received regarding Silicon Valley Bank. "
    "Send the summary to the #test-zapier channel in slack."))
```
"""
from typing import Any, Dict, Optional
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import Field, root_validator
from langchain.tools.base import BaseTool
from langchain.tools.zapier.prompt import BASE_ZAPIER_TOOL_PROMPT
from langchain.utilities.zapier import ZapierNLAWrapper
[docs]class ZapierNLARunAction(BaseTool):
    """
    Args:
        action_id: a specific action ID (from list actions) of the action to execute
            (the set api_key must be associated with the action owner)
        instructions: a natural language instruction string for using the action
            (eg. "get the latest email from Mike Knoop" for "Gmail: find email" action)
        params: a dict, optional. Any params provided will *override* AI guesses
            from `instructions` (see "understanding the AI guessing flow" here:
            https://nla.zapier.com/docs/using-the-api#ai-guessing)
    """
    api_wrapper: ZapierNLAWrapper = Field(default_factory=ZapierNLAWrapper)
    action_id: str
    params: Optional[dict] = None
    base_prompt: str = BASE_ZAPIER_TOOL_PROMPT
    zapier_description: str
    params_schema: Dict[str, str] = Field(default_factory=dict)
    name: str = ""


name: str = ""
    description: str = ""
    @root_validator
    def set_name_description(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        zapier_description = values["zapier_description"]
        params_schema = values["params_schema"]
        if "instructions" in params_schema:
            del params_schema["instructions"]
        # Ensure base prompt (if overridden) contains necessary input fields
        necessary_fields = {"{zapier_description}", "{params}"}
        if not all(field in values["base_prompt"] for field in necessary_fields):
            raise ValueError(
                "Your custom base Zapier prompt must contain input fields for "
                "{zapier_description} and {params}."
            )
        values["name"] = zapier_description
        values["description"] = values["base_prompt"].format(
            zapier_description=zapier_description,
            params=str(list(params_schema.keys())),
        )
        return values
    def _run(
        self, instructions: str, run_manager: Optional[CallbackManagerForToolRun] = None
    ) -> str:
        """Use the Zapier NLA tool to return a list of all exposed user actions."""
        return self.api_wrapper.run_as_str(self.action_id, instructions, self.params)
    async def _arun(
        self,
        instructions: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Zapier NLA tool to return a list of all exposed user actions."""
        return await self.api_wrapper.arun_as_str(
            self.action_id,
            instructions,
            self.params,
        )
ZapierNLARunAction.__doc__ = (


)
ZapierNLARunAction.__doc__ = (
    ZapierNLAWrapper.run.__doc__ + ZapierNLARunAction.__doc__  # type: ignore
)
# other useful actions
[docs]class ZapierNLAListActions(BaseTool):
    """
    Args:
        None
    """
    name: str = "ZapierNLA_list_actions"
    description: str = BASE_ZAPIER_TOOL_PROMPT + (
        "This tool returns a list of the user's exposed actions."
    )
    api_wrapper: ZapierNLAWrapper = Field(default_factory=ZapierNLAWrapper)
    def _run(
        self,
        _: str = "",
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Zapier NLA tool to return a list of all exposed user actions."""
        return self.api_wrapper.list_as_str()
    async def _arun(
        self,
        _: str = "",
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Zapier NLA tool to return a list of all exposed user actions."""
        return await self.api_wrapper.alist_as_str()
ZapierNLAListActions.__doc__ = (
    ZapierNLAWrapper.list.__doc__ + ZapierNLAListActions.__doc__  # type: ignore
)


Source code for langchain.tools.gmail.utils
"""Gmail tool utils."""
from __future__ import annotations
import logging
import os
from typing import TYPE_CHECKING, List, Optional, Tuple
if TYPE_CHECKING:
    from google.auth.transport.requests import Request
    from google.oauth2.credentials import Credentials
    from google_auth_oauthlib.flow import InstalledAppFlow
    from googleapiclient.discovery import Resource
    from googleapiclient.discovery import build as build_resource
logger = logging.getLogger(__name__)
[docs]def import_google() -> Tuple[Request, Credentials]:
    """Import google libraries.
    Returns:
        Tuple[Request, Credentials]: Request and Credentials classes.
    """
    # google-auth-httplib2
    try:
        from google.auth.transport.requests import Request  # noqa: F401
        from google.oauth2.credentials import Credentials  # noqa: F401
    except ImportError:
        raise ImportError(
            "You need to install google-auth-httplib2 to use this toolkit. "
            "Try running pip install --upgrade google-auth-httplib2"
        )
    return Request, Credentials
[docs]def import_installed_app_flow() -> InstalledAppFlow:
    """Import InstalledAppFlow class.
    Returns:
        InstalledAppFlow: InstalledAppFlow class.
    """
    try:
        from google_auth_oauthlib.flow import InstalledAppFlow
    except ImportError:
        raise ImportError(
            "You need to install google-auth-oauthlib to use this toolkit. "
            "Try running pip install --upgrade google-auth-oauthlib"
        )
    return InstalledAppFlow
[docs]def import_googleapiclient_resource_builder() -> build_resource:
    """Import googleapiclient.discovery.build function.
    Returns:


"""Import googleapiclient.discovery.build function.
    Returns:
        build_resource: googleapiclient.discovery.build function.
    """
    try:
        from googleapiclient.discovery import build
    except ImportError:
        raise ImportError(
            "You need to install googleapiclient to use this toolkit. "
            "Try running pip install --upgrade google-api-python-client"
        )
    return build
DEFAULT_SCOPES = ["https://mail.google.com/"]
DEFAULT_CREDS_TOKEN_FILE = "token.json"
DEFAULT_CLIENT_SECRETS_FILE = "credentials.json"
[docs]def get_gmail_credentials(
    token_file: Optional[str] = None,
    client_secrets_file: Optional[str] = None,
    scopes: Optional[List[str]] = None,
) -> Credentials:
    """Get credentials."""
    # From https://developers.google.com/gmail/api/quickstart/python
    Request, Credentials = import_google()
    InstalledAppFlow = import_installed_app_flow()
    creds = None
    scopes = scopes or DEFAULT_SCOPES
    token_file = token_file or DEFAULT_CREDS_TOKEN_FILE
    client_secrets_file = client_secrets_file or DEFAULT_CLIENT_SECRETS_FILE
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists(token_file):
        creds = Credentials.from_authorized_user_file(token_file, scopes)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:


creds.refresh(Request())
        else:
            # https://developers.google.com/gmail/api/quickstart/python#authorize_credentials_for_a_desktop_application # noqa
            flow = InstalledAppFlow.from_client_secrets_file(
                client_secrets_file, scopes
            )
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open(token_file, "w") as token:
            token.write(creds.to_json())
    return creds
[docs]def build_resource_service(
    credentials: Optional[Credentials] = None,
    service_name: str = "gmail",
    service_version: str = "v1",
) -> Resource:
    """Build a Gmail service."""
    credentials = credentials or get_gmail_credentials()
    builder = import_googleapiclient_resource_builder()
    return builder(service_name, service_version, credentials=credentials)
[docs]def clean_email_body(body: str) -> str:
    """Clean email body."""
    try:
        from bs4 import BeautifulSoup
        try:
            soup = BeautifulSoup(str(body), "html.parser")
            body = soup.get_text()
            return str(body)
        except Exception as e:
            logger.error(e)
            return str(body)
    except ImportError:
        logger.warning("BeautifulSoup not installed. Skipping cleaning.")
        return str(body)


Source code for langchain.tools.gmail.send_message
"""Send Gmail messages."""
import base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from typing import Any, Dict, List, Optional, Union
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.gmail.base import GmailBaseTool
[docs]class SendMessageSchema(BaseModel):
    """Input for SendMessageTool."""
    message: str = Field(
        ...,
        description="The message to send.",
    )
    to: Union[str, List[str]] = Field(
        ...,
        description="The list of recipients.",
    )
    subject: str = Field(
        ...,
        description="The subject of the message.",
    )
    cc: Optional[Union[str, List[str]]] = Field(
        None,
        description="The list of CC recipients.",
    )
    bcc: Optional[Union[str, List[str]]] = Field(
        None,
        description="The list of BCC recipients.",
    )
[docs]class GmailSendMessage(GmailBaseTool):
    """Tool that sends a message to Gmail."""
    name: str = "send_gmail_message"
    description: str = (
        "Use this tool to send email messages." " The input is the message, recipients"
    )
    def _prepare_message(
        self,
        message: str,
        to: Union[str, List[str]],
        subject: str,
        cc: Optional[Union[str, List[str]]] = None,
        bcc: Optional[Union[str, List[str]]] = None,
    ) -> Dict[str, Any]:
        """Create a message for an email."""


) -> Dict[str, Any]:
        """Create a message for an email."""
        mime_message = MIMEMultipart()
        mime_message.attach(MIMEText(message, "html"))
        mime_message["To"] = ", ".join(to if isinstance(to, list) else [to])
        mime_message["Subject"] = subject
        if cc is not None:
            mime_message["Cc"] = ", ".join(cc if isinstance(cc, list) else [cc])
        if bcc is not None:
            mime_message["Bcc"] = ", ".join(bcc if isinstance(bcc, list) else [bcc])
        encoded_message = base64.urlsafe_b64encode(mime_message.as_bytes()).decode()
        return {"raw": encoded_message}
    def _run(
        self,
        message: str,
        to: Union[str, List[str]],
        subject: str,
        cc: Optional[Union[str, List[str]]] = None,
        bcc: Optional[Union[str, List[str]]] = None,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Run the tool."""
        try:
            create_message = self._prepare_message(message, to, subject, cc=cc, bcc=bcc)
            send_message = (
                self.api_resource.users()
                .messages()
                .send(userId="me", body=create_message)
            )
            sent_message = send_message.execute()
            return f'Message sent. Message Id: {sent_message["id"]}'
        except Exception as error:
            raise Exception(f"An error occurred: {error}")


Source code for langchain.tools.gmail.get_message
import base64
import email
from typing import Dict, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.gmail.base import GmailBaseTool
from langchain.tools.gmail.utils import clean_email_body
[docs]class SearchArgsSchema(BaseModel):
    """Input for GetMessageTool."""
    message_id: str = Field(
        ...,
        description="The unique ID of the email message, retrieved from a search.",
    )
[docs]class GmailGetMessage(GmailBaseTool):
    """Tool that gets a message by ID from Gmail."""
    name: str = "get_gmail_message"
    description: str = (
        "Use this tool to fetch an email by message ID."
        " Returns the thread ID, snippet, body, subject, and sender."
    )
    args_schema: Type[SearchArgsSchema] = SearchArgsSchema
    def _run(
        self,
        message_id: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> Dict:
        """Run the tool."""
        query = (
            self.api_resource.users()
            .messages()
            .get(userId="me", format="raw", id=message_id)
        )
        message_data = query.execute()
        raw_message = base64.urlsafe_b64decode(message_data["raw"])
        email_msg = email.message_from_bytes(raw_message)
        subject = email_msg["Subject"]
        sender = email_msg["From"]
        message_body = ""
        if email_msg.is_multipart():
            for part in email_msg.walk():
                ctype = part.get_content_type()
                cdispo = str(part.get("Content-Disposition"))


cdispo = str(part.get("Content-Disposition"))
                if ctype == "text/plain" and "attachment" not in cdispo:
                    message_body = part.get_payload(decode=True).decode("utf-8")
                    break
        else:
            message_body = email_msg.get_payload(decode=True).decode("utf-8")
        body = clean_email_body(message_body)
        return {
            "id": message_id,
            "threadId": message_data["threadId"],
            "snippet": message_data["snippet"],
            "body": body,
            "subject": subject,
            "sender": sender,
        }


Source code for langchain.tools.gmail.create_draft
import base64
from email.message import EmailMessage
from typing import List, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.gmail.base import GmailBaseTool
[docs]class CreateDraftSchema(BaseModel):
    """Input for CreateDraftTool."""
    message: str = Field(
        ...,
        description="The message to include in the draft.",
    )
    to: List[str] = Field(
        ...,
        description="The list of recipients.",
    )
    subject: str = Field(
        ...,
        description="The subject of the message.",
    )
    cc: Optional[List[str]] = Field(
        None,
        description="The list of CC recipients.",
    )
    bcc: Optional[List[str]] = Field(
        None,
        description="The list of BCC recipients.",
    )
[docs]class GmailCreateDraft(GmailBaseTool):
    """Tool that creates a draft email for Gmail."""
    name: str = "create_gmail_draft"
    description: str = (
        "Use this tool to create a draft email with the provided message fields."
    )
    args_schema: Type[CreateDraftSchema] = CreateDraftSchema
    def _prepare_draft_message(
        self,
        message: str,
        to: List[str],
        subject: str,
        cc: Optional[List[str]] = None,
        bcc: Optional[List[str]] = None,
    ) -> dict:
        draft_message = EmailMessage()
        draft_message.set_content(message)
        draft_message["To"] = ", ".join(to)
        draft_message["Subject"] = subject


draft_message["Subject"] = subject
        if cc is not None:
            draft_message["Cc"] = ", ".join(cc)
        if bcc is not None:
            draft_message["Bcc"] = ", ".join(bcc)
        encoded_message = base64.urlsafe_b64encode(draft_message.as_bytes()).decode()
        return {"message": {"raw": encoded_message}}
    def _run(
        self,
        message: str,
        to: List[str],
        subject: str,
        cc: Optional[List[str]] = None,
        bcc: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        try:
            create_message = self._prepare_draft_message(message, to, subject, cc, bcc)
            draft = (
                self.api_resource.users()
                .drafts()
                .create(userId="me", body=create_message)
                .execute()
            )
            output = f'Draft created. Draft Id: {draft["id"]}'
            return output
        except Exception as e:
            raise Exception(f"An error occurred: {e}")


Source code for langchain.tools.gmail.base
"""Base class for Gmail tools."""
from __future__ import annotations
from typing import TYPE_CHECKING
from langchain.pydantic_v1 import Field
from langchain.tools.base import BaseTool
from langchain.tools.gmail.utils import build_resource_service
if TYPE_CHECKING:
    # This is for linting and IDE typehints
    from googleapiclient.discovery import Resource
else:
    try:
        # We do this so pydantic can resolve the types when instantiating
        from googleapiclient.discovery import Resource
    except ImportError:
        pass
[docs]class GmailBaseTool(BaseTool):
    """Base class for Gmail tools."""
    api_resource: Resource = Field(default_factory=build_resource_service)
[docs]    @classmethod
    def from_api_resource(cls, api_resource: Resource) -> "GmailBaseTool":
        """Create a tool from an api resource.
        Args:
            api_resource: The api resource to use.
        Returns:
            A tool.
        """
        return cls(service=api_resource)


Source code for langchain.tools.gmail.get_thread
from typing import Dict, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.gmail.base import GmailBaseTool
[docs]class GetThreadSchema(BaseModel):
    """Input for GetMessageTool."""
    # From https://support.google.com/mail/answer/7190?hl=en
    thread_id: str = Field(
        ...,
        description="The thread ID.",
    )
[docs]class GmailGetThread(GmailBaseTool):
    """Tool that gets a thread by ID from Gmail."""
    name: str = "get_gmail_thread"
    description: str = (
        "Use this tool to search for email messages."
        " The input must be a valid Gmail query."
        " The output is a JSON list of messages."
    )
    args_schema: Type[GetThreadSchema] = GetThreadSchema
    def _run(
        self,
        thread_id: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> Dict:
        """Run the tool."""
        query = self.api_resource.users().threads().get(userId="me", id=thread_id)
        thread_data = query.execute()
        if not isinstance(thread_data, dict):
            raise ValueError("The output of the query must be a list.")
        messages = thread_data["messages"]
        thread_data["messages"] = []
        keys_to_keep = ["id", "snippet", "snippet"]
        # TODO: Parse body.
        for message in messages:
            thread_data["messages"].append(
                {k: message[k] for k in keys_to_keep if k in message}
            )
        return thread_data


Source code for langchain.tools.gmail.search
import base64
import email
from enum import Enum
from typing import Any, Dict, List, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.gmail.base import GmailBaseTool
from langchain.tools.gmail.utils import clean_email_body
[docs]class Resource(str, Enum):
    """Enumerator of Resources to search."""
    THREADS = "threads"
    MESSAGES = "messages"
[docs]class SearchArgsSchema(BaseModel):
    """Input for SearchGmailTool."""
    # From https://support.google.com/mail/answer/7190?hl=en
    query: str = Field(
        ...,
        description="The Gmail query. Example filters include from:sender,"
        " to:recipient, subject:subject, -filtered_term,"
        " in:folder, is:important|read|starred, after:year/mo/date, "
        "before:year/mo/date, label:label_name"
        ' "exact phrase".'
        " Search newer/older than using d (day), m (month), and y (year): "
        "newer_than:2d, older_than:1y."
        " Attachments with extension example: filename:pdf. Multiple term"
        " matching example: from:amy OR from:david.",
    )
    resource: Resource = Field(
        default=Resource.MESSAGES,
        description="Whether to search for threads or messages.",
    )
    max_results: int = Field(
        default=10,
        description="The maximum number of results to return.",
    )
[docs]class GmailSearch(GmailBaseTool):
    """Tool that searches for messages or threads in Gmail."""


"""Tool that searches for messages or threads in Gmail."""
    name: str = "search_gmail"
    description: str = (
        "Use this tool to search for email messages or threads."
        " The input must be a valid Gmail query."
        " The output is a JSON list of the requested resource."
    )
    args_schema: Type[SearchArgsSchema] = SearchArgsSchema
    def _parse_threads(self, threads: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        # Add the thread message snippets to the thread results
        results = []
        for thread in threads:
            thread_id = thread["id"]
            thread_data = (
                self.api_resource.users()
                .threads()
                .get(userId="me", id=thread_id)
                .execute()
            )
            messages = thread_data["messages"]
            thread["messages"] = []
            for message in messages:
                snippet = message["snippet"]
                thread["messages"].append({"snippet": snippet, "id": message["id"]})
            results.append(thread)
        return results
    def _parse_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        results = []
        for message in messages:
            message_id = message["id"]
            message_data = (
                self.api_resource.users()
                .messages()
                .get(userId="me", format="raw", id=message_id)
                .execute()
            )
            raw_message = base64.urlsafe_b64decode(message_data["raw"])
            email_msg = email.message_from_bytes(raw_message)
            subject = email_msg["Subject"]
            sender = email_msg["From"]
            message_body = ""
            if email_msg.is_multipart():


message_body = ""
            if email_msg.is_multipart():
                for part in email_msg.walk():
                    ctype = part.get_content_type()
                    cdispo = str(part.get("Content-Disposition"))
                    if ctype == "text/plain" and "attachment" not in cdispo:
                        message_body = part.get_payload(decode=True).decode("utf-8")
                        break
            else:
                message_body = email_msg.get_payload(decode=True).decode("utf-8")
            body = clean_email_body(message_body)
            results.append(
                {
                    "id": message["id"],
                    "threadId": message_data["threadId"],
                    "snippet": message_data["snippet"],
                    "body": body,
                    "subject": subject,
                    "sender": sender,
                }
            )
        return results
    def _run(
        self,
        query: str,
        resource: Resource = Resource.MESSAGES,
        max_results: int = 10,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> List[Dict[str, Any]]:
        """Run the tool."""
        results = (
            self.api_resource.users()
            .messages()
            .list(userId="me", q=query, maxResults=max_results)
            .execute()
            .get(resource.value, [])
        )
        if resource == Resource.THREADS:
            return self._parse_threads(results)
        elif resource == Resource.MESSAGES:
            return self._parse_messages(results)
        else:
            raise NotImplementedError(f"Resource of type {resource} not implemented.")


Source code for langchain.tools.playwright.extract_hyperlinks
from __future__ import annotations
import json
from typing import TYPE_CHECKING, Any, Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field, root_validator
from langchain.tools.playwright.base import BaseBrowserTool
from langchain.tools.playwright.utils import aget_current_page, get_current_page
if TYPE_CHECKING:
    pass
[docs]class ExtractHyperlinksToolInput(BaseModel):
    """Input for ExtractHyperlinksTool."""
    absolute_urls: bool = Field(
        default=False,
        description="Return absolute URLs instead of relative URLs",
    )
[docs]class ExtractHyperlinksTool(BaseBrowserTool):
    """Extract all hyperlinks on the page."""
    name: str = "extract_hyperlinks"
    description: str = "Extract all hyperlinks on the current webpage"
    args_schema: Type[BaseModel] = ExtractHyperlinksToolInput
    @root_validator
    def check_bs_import(cls, values: dict) -> dict:
        """Check that the arguments are valid."""
        try:
            from bs4 import BeautifulSoup  # noqa: F401
        except ImportError:
            raise ImportError(
                "The 'beautifulsoup4' package is required to use this tool."
                " Please install it with 'pip install beautifulsoup4'."
            )
        return values
[docs]    @staticmethod
    def scrape_page(page: Any, html_content: str, absolute_urls: bool) -> str:
        from urllib.parse import urljoin
        from bs4 import BeautifulSoup
        # Parse the HTML content with BeautifulSoup
        soup = BeautifulSoup(html_content, "lxml")


soup = BeautifulSoup(html_content, "lxml")
        # Find all the anchor elements and extract their href attributes
        anchors = soup.find_all("a")
        if absolute_urls:
            base_url = page.url
            links = [urljoin(base_url, anchor.get("href", "")) for anchor in anchors]
        else:
            links = [anchor.get("href", "") for anchor in anchors]
        # Return the list of links as a JSON string
        return json.dumps(links)
    def _run(
        self,
        absolute_urls: bool = False,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        if self.sync_browser is None:
            raise ValueError(f"Synchronous browser not provided to {self.name}")
        page = get_current_page(self.sync_browser)
        html_content = page.content()
        return self.scrape_page(page, html_content, absolute_urls)
    async def _arun(
        self,
        absolute_urls: bool = False,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        if self.async_browser is None:
            raise ValueError(f"Asynchronous browser not provided to {self.name}")
        page = await aget_current_page(self.async_browser)
        html_content = await page.content()
        return self.scrape_page(page, html_content, absolute_urls)


Source code for langchain.tools.playwright.navigate_back
from __future__ import annotations
from typing import Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel
from langchain.tools.playwright.base import BaseBrowserTool
from langchain.tools.playwright.utils import (
    aget_current_page,
    get_current_page,
)
[docs]class NavigateBackTool(BaseBrowserTool):
    """Navigate back to the previous page in the browser history."""
    name: str = "previous_webpage"
    description: str = "Navigate back to the previous page in the browser history"
    args_schema: Type[BaseModel] = BaseModel
    def _run(self, run_manager: Optional[CallbackManagerForToolRun] = None) -> str:
        """Use the tool."""
        if self.sync_browser is None:
            raise ValueError(f"Synchronous browser not provided to {self.name}")
        page = get_current_page(self.sync_browser)
        response = page.go_back()
        if response:
            return (
                f"Navigated back to the previous page with URL '{response.url}'."
                f" Status code {response.status}"
            )
        else:
            return "Unable to navigate back; no previous page in the history"
    async def _arun(
        self,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        if self.async_browser is None:
            raise ValueError(f"Asynchronous browser not provided to {self.name}")
        page = await aget_current_page(self.async_browser)
        response = await page.go_back()
        if response:
            return (


response = await page.go_back()
        if response:
            return (
                f"Navigated back to the previous page with URL '{response.url}'."
                f" Status code {response.status}"
            )
        else:
            return "Unable to navigate back; no previous page in the history"


Source code for langchain.tools.playwright.extract_text
from __future__ import annotations
from typing import Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, root_validator
from langchain.tools.playwright.base import BaseBrowserTool
from langchain.tools.playwright.utils import aget_current_page, get_current_page
[docs]class ExtractTextTool(BaseBrowserTool):
    """Tool for extracting all the text on the current webpage."""
    name: str = "extract_text"
    description: str = "Extract all the text on the current webpage"
    args_schema: Type[BaseModel] = BaseModel
    @root_validator
    def check_acheck_bs_importrgs(cls, values: dict) -> dict:
        """Check that the arguments are valid."""
        try:
            from bs4 import BeautifulSoup  # noqa: F401
        except ImportError:
            raise ImportError(
                "The 'beautifulsoup4' package is required to use this tool."
                " Please install it with 'pip install beautifulsoup4'."
            )
        return values
    def _run(self, run_manager: Optional[CallbackManagerForToolRun] = None) -> str:
        """Use the tool."""
        # Use Beautiful Soup since it's faster than looping through the elements
        from bs4 import BeautifulSoup
        if self.sync_browser is None:
            raise ValueError(f"Synchronous browser not provided to {self.name}")
        page = get_current_page(self.sync_browser)
        html_content = page.content()
        # Parse the HTML content with BeautifulSoup
        soup = BeautifulSoup(html_content, "lxml")
        return " ".join(text for text in soup.stripped_strings)
    async def _arun(


async def _arun(
        self, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool."""
        if self.async_browser is None:
            raise ValueError(f"Asynchronous browser not provided to {self.name}")
        # Use Beautiful Soup since it's faster than looping through the elements
        from bs4 import BeautifulSoup
        page = await aget_current_page(self.async_browser)
        html_content = await page.content()
        # Parse the HTML content with BeautifulSoup
        soup = BeautifulSoup(html_content, "lxml")
        return " ".join(text for text in soup.stripped_strings)


Source code for langchain.tools.playwright.utils
"""Utilities for the Playwright browser tools."""
from __future__ import annotations
import asyncio
from typing import TYPE_CHECKING, Any, Coroutine, TypeVar
if TYPE_CHECKING:
    from playwright.async_api import Browser as AsyncBrowser
    from playwright.async_api import Page as AsyncPage
    from playwright.sync_api import Browser as SyncBrowser
    from playwright.sync_api import Page as SyncPage
[docs]async def aget_current_page(browser: AsyncBrowser) -> AsyncPage:
    """
    Asynchronously get the current page of the browser.
    Args:
        browser: The browser (AsyncBrowser) to get the current page from.
    Returns:
        AsyncPage: The current page.
    """
    if not browser.contexts:
        context = await browser.new_context()
        return await context.new_page()
    context = browser.contexts[0]  # Assuming you're using the default browser context
    if not context.pages:
        return await context.new_page()
    # Assuming the last page in the list is the active one
    return context.pages[-1]
[docs]def get_current_page(browser: SyncBrowser) -> SyncPage:
    """
    Get the current page of the browser.
    Args:
        browser: The browser to get the current page from.
    Returns:
        SyncPage: The current page.
    """
    if not browser.contexts:
        context = browser.new_context()
        return context.new_page()
    context = browser.contexts[0]  # Assuming you're using the default browser context
    if not context.pages:
        return context.new_page()
    # Assuming the last page in the list is the active one
    return context.pages[-1]


return context.pages[-1]
[docs]def create_async_playwright_browser(headless: bool = True) -> AsyncBrowser:
    """
    Create an async playwright browser.
    Args:
        headless: Whether to run the browser in headless mode. Defaults to True.
    Returns:
        AsyncBrowser: The playwright browser.
    """
    from playwright.async_api import async_playwright
    browser = run_async(async_playwright().start())
    return run_async(browser.chromium.launch(headless=headless))
[docs]def create_sync_playwright_browser(headless: bool = True) -> SyncBrowser:
    """
    Create a playwright browser.
    Args:
        headless: Whether to run the browser in headless mode. Defaults to True.
    Returns:
        SyncBrowser: The playwright browser.
    """
    from playwright.sync_api import sync_playwright
    browser = sync_playwright().start()
    return browser.chromium.launch(headless=headless)
T = TypeVar("T")
[docs]def run_async(coro: Coroutine[Any, Any, T]) -> T:
    """Run an async coroutine.
    Args:
        coro: The coroutine to run. Coroutine[Any, Any, T]
    Returns:
        T: The result of the coroutine.
    """
    event_loop = asyncio.get_event_loop()
    return event_loop.run_until_complete(coro)


Source code for langchain.tools.playwright.get_elements
from __future__ import annotations
import json
from typing import TYPE_CHECKING, List, Optional, Sequence, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.playwright.base import BaseBrowserTool
from langchain.tools.playwright.utils import aget_current_page, get_current_page
if TYPE_CHECKING:
    from playwright.async_api import Page as AsyncPage
    from playwright.sync_api import Page as SyncPage
[docs]class GetElementsToolInput(BaseModel):
    """Input for GetElementsTool."""
    selector: str = Field(
        ...,
        description="CSS selector, such as '*', 'div', 'p', 'a', #id, .classname",
    )
    attributes: List[str] = Field(
        default_factory=lambda: ["innerText"],
        description="Set of attributes to retrieve for each element",
    )
async def _aget_elements(
    page: AsyncPage, selector: str, attributes: Sequence[str]
) -> List[dict]:
    """Get elements matching the given CSS selector."""
    elements = await page.query_selector_all(selector)
    results = []
    for element in elements:
        result = {}
        for attribute in attributes:
            if attribute == "innerText":
                val: Optional[str] = await element.inner_text()
            else:
                val = await element.get_attribute(attribute)
            if val is not None and val.strip() != "":
                result[attribute] = val
        if result:
            results.append(result)
    return results
def _get_elements(
    page: SyncPage, selector: str, attributes: Sequence[str]


page: SyncPage, selector: str, attributes: Sequence[str]
) -> List[dict]:
    """Get elements matching the given CSS selector."""
    elements = page.query_selector_all(selector)
    results = []
    for element in elements:
        result = {}
        for attribute in attributes:
            if attribute == "innerText":
                val: Optional[str] = element.inner_text()
            else:
                val = element.get_attribute(attribute)
            if val is not None and val.strip() != "":
                result[attribute] = val
        if result:
            results.append(result)
    return results
[docs]class GetElementsTool(BaseBrowserTool):
    """Tool for getting elements in the current web page matching a CSS selector."""
    name: str = "get_elements"
    description: str = (
        "Retrieve elements in the current web page matching the given CSS selector"
    )
    args_schema: Type[BaseModel] = GetElementsToolInput
    def _run(
        self,
        selector: str,
        attributes: Sequence[str] = ["innerText"],
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        if self.sync_browser is None:
            raise ValueError(f"Synchronous browser not provided to {self.name}")
        page = get_current_page(self.sync_browser)
        # Navigate to the desired webpage before using this tool
        results = _get_elements(page, selector, attributes)
        return json.dumps(results, ensure_ascii=False)
    async def _arun(
        self,
        selector: str,
        attributes: Sequence[str] = ["innerText"],
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:


) -> str:
        """Use the tool."""
        if self.async_browser is None:
            raise ValueError(f"Asynchronous browser not provided to {self.name}")
        page = await aget_current_page(self.async_browser)
        # Navigate to the desired webpage before using this tool
        results = await _aget_elements(page, selector, attributes)
        return json.dumps(results, ensure_ascii=False)


Source code for langchain.tools.playwright.base
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Tuple, Type
from langchain.pydantic_v1 import root_validator
from langchain.tools.base import BaseTool
if TYPE_CHECKING:
    from playwright.async_api import Browser as AsyncBrowser
    from playwright.sync_api import Browser as SyncBrowser
else:
    try:
        # We do this so pydantic can resolve the types when instantiating
        from playwright.async_api import Browser as AsyncBrowser
        from playwright.sync_api import Browser as SyncBrowser
    except ImportError:
        pass
[docs]def lazy_import_playwright_browsers() -> Tuple[Type[AsyncBrowser], Type[SyncBrowser]]:
    """
    Lazy import playwright browsers.
    Returns:
        Tuple[Type[AsyncBrowser], Type[SyncBrowser]]:
            AsyncBrowser and SyncBrowser classes.
    """
    try:
        from playwright.async_api import Browser as AsyncBrowser  # noqa: F401
        from playwright.sync_api import Browser as SyncBrowser  # noqa: F401
    except ImportError:
        raise ImportError(
            "The 'playwright' package is required to use the playwright tools."
            " Please install it with 'pip install playwright'."
        )
    return AsyncBrowser, SyncBrowser
[docs]class BaseBrowserTool(BaseTool):
    """Base class for browser tools."""
    sync_browser: Optional["SyncBrowser"] = None
    async_browser: Optional["AsyncBrowser"] = None
    @root_validator
    def validate_browser_provided(cls, values: dict) -> dict:
        """Check that the arguments are valid."""
        lazy_import_playwright_browsers()
        if values.get("async_browser") is None and values.get("sync_browser") is None:


raise ValueError("Either async_browser or sync_browser must be specified.")
        return values
[docs]    @classmethod
    def from_browser(
        cls,
        sync_browser: Optional[SyncBrowser] = None,
        async_browser: Optional[AsyncBrowser] = None,
    ) -> BaseBrowserTool:
        """Instantiate the tool."""
        lazy_import_playwright_browsers()
        return cls(sync_browser=sync_browser, async_browser=async_browser)


Source code for langchain.tools.playwright.current_page
from __future__ import annotations
from typing import Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel
from langchain.tools.playwright.base import BaseBrowserTool
from langchain.tools.playwright.utils import aget_current_page, get_current_page
[docs]class CurrentWebPageTool(BaseBrowserTool):
    """Tool for getting the URL of the current webpage."""
    name: str = "current_webpage"
    description: str = "Returns the URL of the current page"
    args_schema: Type[BaseModel] = BaseModel
    def _run(
        self,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        if self.sync_browser is None:
            raise ValueError(f"Synchronous browser not provided to {self.name}")
        page = get_current_page(self.sync_browser)
        return str(page.url)
    async def _arun(
        self,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        if self.async_browser is None:
            raise ValueError(f"Asynchronous browser not provided to {self.name}")
        page = await aget_current_page(self.async_browser)
        return str(page.url)


Source code for langchain.tools.playwright.navigate
from __future__ import annotations
from typing import Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.playwright.base import BaseBrowserTool
from langchain.tools.playwright.utils import (
    aget_current_page,
    get_current_page,
)
[docs]class NavigateToolInput(BaseModel):
    """Input for NavigateToolInput."""
    url: str = Field(..., description="url to navigate to")
[docs]class NavigateTool(BaseBrowserTool):
    """Tool for navigating a browser to a URL."""
    name: str = "navigate_browser"
    description: str = "Navigate a browser to the specified URL"
    args_schema: Type[BaseModel] = NavigateToolInput
    def _run(
        self,
        url: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        if self.sync_browser is None:
            raise ValueError(f"Synchronous browser not provided to {self.name}")
        page = get_current_page(self.sync_browser)
        response = page.goto(url)
        status = response.status if response else "unknown"
        return f"Navigating to {url} returned status code {status}"
    async def _arun(
        self,
        url: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        if self.async_browser is None:
            raise ValueError(f"Asynchronous browser not provided to {self.name}")
        page = await aget_current_page(self.async_browser)


page = await aget_current_page(self.async_browser)
        response = await page.goto(url)
        status = response.status if response else "unknown"
        return f"Navigating to {url} returned status code {status}"


Source code for langchain.tools.playwright.click
from __future__ import annotations
from typing import Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.playwright.base import BaseBrowserTool
from langchain.tools.playwright.utils import (
    aget_current_page,
    get_current_page,
)
[docs]class ClickToolInput(BaseModel):
    """Input for ClickTool."""
    selector: str = Field(..., description="CSS selector for the element to click")
[docs]class ClickTool(BaseBrowserTool):
    """Tool for clicking on an element with the given CSS selector."""
    name: str = "click_element"
    description: str = "Click on an element with the given CSS selector"
    args_schema: Type[BaseModel] = ClickToolInput
    visible_only: bool = True
    """Whether to consider only visible elements."""
    playwright_strict: bool = False
    """Whether to employ Playwright's strict mode when clicking on elements."""
    playwright_timeout: float = 1_000
    """Timeout (in ms) for Playwright to wait for element to be ready."""
    def _selector_effective(self, selector: str) -> str:
        if not self.visible_only:
            return selector
        return f"{selector} >> visible=1"
    def _run(
        self,
        selector: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        if self.sync_browser is None:
            raise ValueError(f"Synchronous browser not provided to {self.name}")
        page = get_current_page(self.sync_browser)


page = get_current_page(self.sync_browser)
        # Navigate to the desired webpage before using this tool
        selector_effective = self._selector_effective(selector=selector)
        from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
        try:
            page.click(
                selector_effective,
                strict=self.playwright_strict,
                timeout=self.playwright_timeout,
            )
        except PlaywrightTimeoutError:
            return f"Unable to click on element '{selector}'"
        return f"Clicked element '{selector}'"
    async def _arun(
        self,
        selector: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        if self.async_browser is None:
            raise ValueError(f"Asynchronous browser not provided to {self.name}")
        page = await aget_current_page(self.async_browser)
        # Navigate to the desired webpage before using this tool
        selector_effective = self._selector_effective(selector=selector)
        from playwright.async_api import TimeoutError as PlaywrightTimeoutError
        try:
            await page.click(
                selector_effective,
                strict=self.playwright_strict,
                timeout=self.playwright_timeout,
            )
        except PlaywrightTimeoutError:
            return f"Unable to click on element '{selector}'"
        return f"Clicked element '{selector}'"


Source code for langchain.tools.json.tool
# flake8: noqa
"""Tools for working with JSON specs."""
from __future__ import annotations
import json
import re
from pathlib import Path
from typing import Dict, List, Optional, Union
from langchain.pydantic_v1 import BaseModel
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.tools.base import BaseTool
def _parse_input(text: str) -> List[Union[str, int]]:
    """Parse input of the form data["key1"][0]["key2"] into a list of keys."""
    _res = re.findall(r"\[.*?]", text)
    # strip the brackets and quotes, convert to int if possible
    res = [i[1:-1].replace('"', "").replace("'", "") for i in _res]
    res = [int(i) if i.isdigit() else i for i in res]
    return res
[docs]class JsonSpec(BaseModel):
    """Base class for JSON spec."""
    dict_: Dict
    max_value_length: int = 200
[docs]    @classmethod
    def from_file(cls, path: Path) -> JsonSpec:
        """Create a JsonSpec from a file."""
        if not path.exists():
            raise FileNotFoundError(f"File not found: {path}")
        dict_ = json.loads(path.read_text())
        return cls(dict_=dict_)
[docs]    def keys(self, text: str) -> str:
        """Return the keys of the dict at the given path.
        Args:
            text: Python representation of the path to the dict (e.g. data["key1"][0]["key2"]).
        """
        try:
            items = _parse_input(text)


"""
        try:
            items = _parse_input(text)
            val = self.dict_
            for i in items:
                if i:
                    val = val[i]
            if not isinstance(val, dict):
                raise ValueError(
                    f"Value at path `{text}` is not a dict, get the value directly."
                )
            return str(list(val.keys()))
        except Exception as e:
            return repr(e)
[docs]    def value(self, text: str) -> str:
        """Return the value of the dict at the given path.
        Args:
            text: Python representation of the path to the dict (e.g. data["key1"][0]["key2"]).
        """
        try:
            items = _parse_input(text)
            val = self.dict_
            for i in items:
                val = val[i]
            if isinstance(val, dict) and len(str(val)) > self.max_value_length:
                return "Value is a large dictionary, should explore its keys directly"
            str_val = str(val)
            if len(str_val) > self.max_value_length:
                str_val = str_val[: self.max_value_length] + "..."
            return str_val
        except Exception as e:
            return repr(e)
[docs]class JsonListKeysTool(BaseTool):
    """Tool for listing keys in a JSON spec."""
    name: str = "json_spec_list_keys"
    description: str = """
    Can be used to list all keys at a given path.
    Before calling this you should be SURE that the path to this exists.
    The input is a text representation of the path to the dict in Python syntax (e.g. data["key1"][0]["key2"]).
    """


"""
    spec: JsonSpec
    def _run(
        self,
        tool_input: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        return self.spec.keys(tool_input)
    async def _arun(
        self,
        tool_input: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        return self._run(tool_input)
[docs]class JsonGetValueTool(BaseTool):
    """Tool for getting a value in a JSON spec."""
    name: str = "json_spec_get_value"
    description: str = """
    Can be used to see value in string format at a given path.
    Before calling this you should be SURE that the path to this exists.
    The input is a text representation of the path to the dict in Python syntax (e.g. data["key1"][0]["key2"]).
    """
    spec: JsonSpec
    def _run(
        self,
        tool_input: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        return self.spec.value(tool_input)
    async def _arun(
        self,
        tool_input: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        return self._run(tool_input)


Source code for langchain.tools.google_serper.tool
"""Tool for the Serper.dev Google Search API."""
from typing import Optional
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import Field
from langchain.tools.base import BaseTool
from langchain.utilities.google_serper import GoogleSerperAPIWrapper
[docs]class GoogleSerperRun(BaseTool):
    """Tool that queries the Serper.dev Google search API."""
    name: str = "google_serper"
    description: str = (
        "A low-cost Google Search API."
        "Useful for when you need to answer questions about current events."
        "Input should be a search query."
    )
    api_wrapper: GoogleSerperAPIWrapper
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return str(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)).__str__()
[docs]class GoogleSerperResults(BaseTool):
    """Tool that queries the Serper.dev Google Search API
    and get back json."""
    name: str = "google_serrper_results_json"
    description: str = (
        "A low-cost Google Search API."
        "Useful for when you need to answer questions about current events."
        "Input should be a search query. Output is a JSON object of the query results"


"Input should be a search query. Output is a JSON object of the query results"
    )
    api_wrapper: GoogleSerperAPIWrapper = Field(default_factory=GoogleSerperAPIWrapper)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return str(self.api_wrapper.results(query))
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return (await self.api_wrapper.aresults(query)).__str__()


Source code for langchain.tools.pubmed.tool
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import Field
from langchain.tools.base import BaseTool
from langchain.utilities.pubmed import PubMedAPIWrapper
[docs]class PubmedQueryRun(BaseTool):
    """Tool that searches the PubMed API."""
    name: str = "PubMed"
    description: str = (
        "A wrapper around PubMed. "
        "Useful for when you need to answer questions about medicine, health, "
        "and biomedical topics "
        "from biomedical literature, MEDLINE, life science journals, and online books. "
        "Input should be a search query."
    )
    api_wrapper: PubMedAPIWrapper = Field(default_factory=PubMedAPIWrapper)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the PubMed tool."""
        return self.api_wrapper.run(query)


Source code for langchain.tools.openweathermap.tool
"""Tool for the OpenWeatherMap API."""
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import Field
from langchain.tools.base import BaseTool
from langchain.utilities import OpenWeatherMapAPIWrapper
[docs]class OpenWeatherMapQueryRun(BaseTool):
    """Tool that queries the OpenWeatherMap API."""
    api_wrapper: OpenWeatherMapAPIWrapper = Field(
        default_factory=OpenWeatherMapAPIWrapper
    )
    name: str = "OpenWeatherMap"
    description: str = (
        "A wrapper around OpenWeatherMap API. "
        "Useful for fetching current weather information for a specified location. "
        "Input should be a location string (e.g. London,GB)."
    )
    def _run(
        self, location: str, run_manager: Optional[CallbackManagerForToolRun] = None
    ) -> str:
        """Use the OpenWeatherMap tool."""
        return self.api_wrapper.run(location)


Source code for langchain.tools.searchapi.tool
"""Tool for the SearchApi.io search API."""
from typing import Optional
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import Field
from langchain.tools.base import BaseTool
from langchain.utilities.searchapi import SearchApiAPIWrapper
[docs]class SearchAPIRun(BaseTool):
    """Tool that queries the SearchApi.io search API."""
    name: str = "searchapi"
    description: str = (
        "Google search API provided by SearchApi.io."
        "This tool is handy when you need to answer questions about current events."
        "Input should be a search query."
    )
    api_wrapper: SearchApiAPIWrapper
    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)
[docs]class SearchAPIResults(BaseTool):
    """Tool that queries the SearchApi.io search API and returns JSON."""
    name: str = "searchapi_results_json"
    description: str = (
        "Google search API provided by SearchApi.io."
        "This tool is handy when you need to answer questions about current events."
        "The input should be a search query and the output is a JSON object "
        "with the query results."
    )


"with the query results."
    )
    api_wrapper: SearchApiAPIWrapper = Field(default_factory=SearchApiAPIWrapper)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return str(self.api_wrapper.results(query))
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return (await self.api_wrapper.aresults(query)).__str__()


Source code for langchain.tools.google_places.tool
"""Tool for the Google search API."""
from typing import Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.base import BaseTool
from langchain.utilities.google_places_api import GooglePlacesAPIWrapper
[docs]class GooglePlacesSchema(BaseModel):
    """Input for GooglePlacesTool."""
    query: str = Field(..., description="Query for google maps")
[docs]class GooglePlacesTool(BaseTool):
    """Tool that queries the Google places API."""
    name: str = "google_places"
    description: str = (
        "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)
    args_schema: Type[BaseModel] = GooglePlacesSchema
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return self.api_wrapper.run(query)