)
        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.searx_search.tool
"""Tool for the SearxNG search API."""
from typing import Optional
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import Extra
from langchain.tools.base import BaseTool, Field
from langchain.utilities.searx_search import SearxSearchWrapper
[docs]class SearxSearchRun(BaseTool):
    """Tool that queries a Searx instance."""
    name: str = "searx_search"
    description: str = (
        "A meta search engine."
        "Useful for when you need to answer questions about current events."
        "Input should be a search query."
    )
    wrapper: SearxSearchWrapper
    kwargs: dict = Field(default_factory=dict)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return self.wrapper.run(query, **self.kwargs)
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return await self.wrapper.arun(query, **self.kwargs)
[docs]class SearxSearchResults(BaseTool):
    """Tool that queries a Searx instance and gets back json."""
    name: str = "Searx-Search-Results"
    description: str = (
        "A meta search engine."
        "Useful for when you need to answer questions about current events."


"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"
    )
    wrapper: SearxSearchWrapper
    num_results: int = 4
    kwargs: dict = Field(default_factory=dict)
    class Config:
        """Pydantic config."""
        extra = Extra.allow
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return str(self.wrapper.results(query, self.num_results, **self.kwargs))
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool asynchronously."""
        return (
            await self.wrapper.aresults(query, self.num_results, **self.kwargs)
        ).__str__()


Source code for langchain.tools.google_cloud.texttospeech
from __future__ import annotations
import tempfile
from typing import TYPE_CHECKING, Any, Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools.base import BaseTool
from langchain.utilities.vertexai import get_client_info
if TYPE_CHECKING:
    from google.cloud import texttospeech
def _import_google_cloud_texttospeech() -> Any:
    try:
        from google.cloud import texttospeech
    except ImportError as e:
        raise ImportError(
            "Cannot import google.cloud.texttospeech, please install "
            "`pip install google-cloud-texttospeech`."
        ) from e
    return texttospeech
def _encoding_file_extension_map(encoding: texttospeech.AudioEncoding) -> Optional[str]:
    texttospeech = _import_google_cloud_texttospeech()
    ENCODING_FILE_EXTENSION_MAP = {
        texttospeech.AudioEncoding.LINEAR16: ".wav",
        texttospeech.AudioEncoding.MP3: ".mp3",
        texttospeech.AudioEncoding.OGG_OPUS: ".ogg",
        texttospeech.AudioEncoding.MULAW: ".wav",
        texttospeech.AudioEncoding.ALAW: ".wav",
    }
    return ENCODING_FILE_EXTENSION_MAP.get(encoding)
[docs]class GoogleCloudTextToSpeechTool(BaseTool):
    """Tool that queries the Google Cloud Text to Speech API.
    In order to set this up, follow instructions at:
    https://cloud.google.com/text-to-speech/docs/before-you-begin
    """
    name: str = "google_cloud_texttospeech"
    description: str = (
        "A wrapper around Google Cloud Text-to-Speech. "
        "Useful for when you need to synthesize audio from text. "


"Useful for when you need to synthesize audio from text. "
        "It supports multiple languages, including English, German, Polish, "
        "Spanish, Italian, French, Portuguese, and Hindi. "
    )
    _client: Any
    def __init__(self, **kwargs: Any) -> None:
        """Initializes private fields."""
        texttospeech = _import_google_cloud_texttospeech()
        super().__init__(**kwargs)
        self._client = texttospeech.TextToSpeechClient(
            client_info=get_client_info(module="text-to-speech")
        )
    def _run(
        self,
        input_text: str,
        language_code: str = "en-US",
        ssml_gender: Optional[texttospeech.SsmlVoiceGender] = None,
        audio_encoding: Optional[texttospeech.AudioEncoding] = None,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        texttospeech = _import_google_cloud_texttospeech()
        ssml_gender = ssml_gender or texttospeech.SsmlVoiceGender.NEUTRAL
        audio_encoding = audio_encoding or texttospeech.AudioEncoding.MP3
        response = self._client.synthesize_speech(
            input=texttospeech.SynthesisInput(text=input_text),
            voice=texttospeech.VoiceSelectionParams(
                language_code=language_code, ssml_gender=ssml_gender
            ),
            audio_config=texttospeech.AudioConfig(audio_encoding=audio_encoding),
        )
        suffix = _encoding_file_extension_map(audio_encoding)
        with tempfile.NamedTemporaryFile(mode="bx", suffix=suffix, delete=False) as f:
            f.write(response.audio_content)
        return f.name


Source code for langchain.tools.dataforseo_api_search.tool
"""Tool for the DataForSeo SERP 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.dataforseo_api_search import DataForSeoAPIWrapper
[docs]class DataForSeoAPISearchRun(BaseTool):
    """Tool that queries the DataForSeo Google search API."""
    name: str = "dataforseo_api_search"
    description: str = (
        "A robust Google Search API provided by DataForSeo."
        "This tool is handy when you need information about trending topics "
        "or current events."
    )
    api_wrapper: DataForSeoAPIWrapper
    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 DataForSeoAPISearchResults(BaseTool):
    """Tool that queries the DataForSeo Google Search API
    and get back json."""
    name: str = "DataForSeo-Results-JSON"
    description: str = (
        "A comprehensive Google Search API provided by DataForSeo."


"A comprehensive Google Search API provided by DataForSeo."
        "This tool is useful for obtaining real-time data on current events "
        "or popular searches."
        "The input should be a search query and the output is a JSON object "
        "of the query results."
    )
    api_wrapper: DataForSeoAPIWrapper = Field(default_factory=DataForSeoAPIWrapper)
    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.shell.tool
import asyncio
import platform
import warnings
from typing import Any, List, Optional, Type, Union
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field, root_validator
from langchain.tools.base import BaseTool
[docs]class ShellInput(BaseModel):
    """Commands for the Bash Shell tool."""
    commands: Union[str, List[str]] = Field(
        ...,
        description="List of shell commands to run. Deserialized using json.loads",
    )
    """List of shell commands to run."""
    @root_validator
    def _validate_commands(cls, values: dict) -> dict:
        """Validate commands."""
        # TODO: Add real validators
        commands = values.get("commands")
        if not isinstance(commands, list):
            values["commands"] = [commands]
        # Warn that the bash tool is not safe
        warnings.warn(
            "The shell tool has no safeguards by default. Use at your own risk."
        )
        return values
def _get_default_bash_process() -> Any:
    """Get default bash process."""
    try:
        from langchain_experimental.llm_bash.bash import BashProcess
    except ImportError:
        raise ImportError(
            "BashProcess has been moved to langchain experimental."
            "To use this tool, install langchain-experimental "
            "with `pip install langchain-experimental`."
        )
    return BashProcess(return_err_output=True)
def _get_platform() -> str:
    """Get platform."""
    system = platform.system()
    if system == "Darwin":
        return "MacOS"
    return system


if system == "Darwin":
        return "MacOS"
    return system
[docs]class ShellTool(BaseTool):
    """Tool to run shell commands."""
    process: Any = Field(default_factory=_get_default_bash_process)
    """Bash process to run commands."""
    name: str = "terminal"
    """Name of tool."""
    description: str = f"Run shell commands on this {_get_platform()} machine."
    """Description of tool."""
    args_schema: Type[BaseModel] = ShellInput
    """Schema for input arguments."""
    def _run(
        self,
        commands: Union[str, List[str]],
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Run commands and return final output."""
        return self.process.run(commands)
    async def _arun(
        self,
        commands: Union[str, List[str]],
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> str:
        """Run commands asynchronously and return final output."""
        return await asyncio.get_event_loop().run_in_executor(
            None, self.process.run, commands
        )


Source code for langchain.tools.arxiv.tool
"""Tool for the Arxiv 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.arxiv import ArxivAPIWrapper
[docs]class ArxivInput(BaseModel):
    query: str = Field(description="search query to look up")
[docs]class ArxivQueryRun(BaseTool):
    """Tool that searches the Arxiv API."""
    name: str = "arxiv"
    description: str = (
        "A wrapper around Arxiv.org "
        "Useful for when you need to answer questions about Physics, Mathematics, "
        "Computer Science, Quantitative Biology, Quantitative Finance, Statistics, "
        "Electrical Engineering, and Economics "
        "from scientific articles on arxiv.org. "
        "Input should be a search query."
    )
    api_wrapper: ArxivAPIWrapper = Field(default_factory=ArxivAPIWrapper)
    args_schema: Type[BaseModel] = ArxivInput
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Arxiv tool."""
        return self.api_wrapper.run(query)


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):
        pass
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.tavily_search.tool
"""Tool for the Tavily search API."""
from typing import Dict, List, Optional, Type, Union
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.base import BaseTool
from langchain.utilities.tavily_search import TavilySearchAPIWrapper
[docs]class TavilyInput(BaseModel):
    query: str = Field(description="search query to look up")
[docs]class TavilySearchResults(BaseTool):
    """Tool that queries the Tavily Search API and gets back json."""
    name: str = "tavily_search_results_json"
    description: str = (
        "A search engine optimized for comprehensive, accurate, and trusted results. "
        "Useful for when you need to answer questions about current events. "
        "Input should be a search query."
    )
    api_wrapper: TavilySearchAPIWrapper
    max_results: int = 5
    args_schema: Type[BaseModel] = TavilyInput
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> Union[List[Dict], str]:
        """Use the tool."""
        try:
            return self.api_wrapper.results(
                query,
                self.max_results,
            )
        except Exception as e:
            return repr(e)
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> Union[List[Dict], str]:


) -> Union[List[Dict], str]:
        """Use the tool asynchronously."""
        try:
            return await self.api_wrapper.results_async(
                query,
                self.max_results,
            )
        except Exception as e:
            return repr(e)
[docs]class TavilyAnswer(BaseTool):
    """Tool that queries the Tavily Search API and gets back an answer."""
    name: str = "tavily_answer"
    description: str = (
        "A search engine optimized for comprehensive, accurate, and trusted results. "
        "Useful for when you need to answer questions about current events. "
        "Input should be a search query. "
        "This returns only the answer - not the original source data."
    )
    api_wrapper: TavilySearchAPIWrapper
    args_schema: Type[BaseModel] = TavilyInput
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> Union[List[Dict], str]:
        """Use the tool."""
        try:
            return self.api_wrapper.raw_results(
                query,
                max_results=5,
                include_answer=True,
                search_depth="basic",
            )["answer"]
        except Exception as e:
            return repr(e)
    async def _arun(
        self,
        query: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> Union[List[Dict], str]:
        """Use the tool asynchronously."""
        try:
            result = await self.api_wrapper.raw_results_async(
                query,
                max_results=5,
                include_answer=True,
                search_depth="basic",
            )


include_answer=True,
                search_depth="basic",
            )
            return result["answer"]
        except Exception as e:
            return repr(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.wolfram_alpha.tool
"""Tool for the Wolfram Alpha API."""
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools.base import BaseTool
from langchain.utilities.wolfram_alpha import WolframAlphaAPIWrapper
[docs]class WolframAlphaQueryRun(BaseTool):
    """Tool that queries using the Wolfram Alpha SDK."""
    name: str = "wolfram_alpha"
    description: str = (
        "A wrapper around Wolfram Alpha. "
        "Useful for when you need to answer questions about Math, "
        "Science, Technology, Culture, Society and Everyday Life. "
        "Input should be a search query."
    )
    api_wrapper: WolframAlphaAPIWrapper
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the WolframAlpha tool."""
        return self.api_wrapper.run(query)


Source code for langchain.tools.multion.update_session
import asyncio
from typing import TYPE_CHECKING, Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.base import BaseTool
if TYPE_CHECKING:
    # This is for linting and IDE typehints
    import multion
else:
    try:
        # We do this so pydantic can resolve the types when instantiating
        import multion
    except ImportError:
        pass
[docs]class UpdateSessionSchema(BaseModel):
    """Input for UpdateSessionTool."""
    sessionId: str = Field(
        ...,
        description="""The sessionID,
        received from one of the createSessions run before""",
    )
    query: str = Field(
        ...,
        description="The query to run in multion agent.",
    )
    url: str = Field(
        "https://www.google.com/",
        description="""The Url to run the agent at. \
        Note: accepts only secure links having https://""",
    )
[docs]class MultionUpdateSession(BaseTool):
    """Tool that updates an existing Multion Browser Window with provided fields.
    Attributes:
        name: The name of the tool. Default: "update_multion_session"
        description: The description of the tool.
        args_schema: The schema for the tool's arguments. Default: UpdateSessionSchema
    """
    name: str = "update_multion_session"
    description: str = """Use this tool to update \
an existing corresponding Multion Browser Window with provided fields. \
Note: sessionId must be received from previous Browser window creation."""


Note: sessionId must be received from previous Browser window creation."""
    args_schema: Type[UpdateSessionSchema] = UpdateSessionSchema
    sessionId: str = ""
    def _run(
        self,
        sessionId: str,
        query: str,
        url: Optional[str] = "https://www.google.com/",
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> dict:
        try:
            try:
                response = multion.update_session(
                    sessionId, {"input": query, "url": url}
                )
                content = {"sessionId": sessionId, "Response": response["message"]}
                self.sessionId = sessionId
                return content
            except Exception as e:
                print(f"{e}, retrying...")
                return {"error": f"{e}", "Response": "retrying..."}
        except Exception as e:
            raise Exception(f"An error occurred: {e}")
    async def _arun(
        self,
        sessionId: str,
        query: str,
        url: Optional[str] = "https://www.google.com/",
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> dict:
        loop = asyncio.get_running_loop()
        result = await loop.run_in_executor(None, self._run, sessionId, query, url)
        return result


Source code for langchain.tools.multion.close_session
import asyncio
from typing import TYPE_CHECKING, Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.base import BaseTool
if TYPE_CHECKING:
    # This is for linting and IDE typehints
    import multion
else:
    try:
        # We do this so pydantic can resolve the types when instantiating
        import multion
    except ImportError:
        pass
[docs]class CloseSessionSchema(BaseModel):
    """Input for UpdateSessionTool."""
    sessionId: str = Field(
        ...,
        description="""The sessionId, received from one of the createSessions
        or updateSessions run before""",
    )
[docs]class MultionCloseSession(BaseTool):
    """Tool that closes an existing Multion Browser Window with provided fields.
    Attributes:
        name: The name of the tool. Default: "close_multion_session"
        description: The description of the tool.
        args_schema: The schema for the tool's arguments. Default: UpdateSessionSchema
    """
    name: str = "close_multion_session"
    description: str = """Use this tool to close \
an existing corresponding Multion Browser Window with provided fields. \
Note: SessionId must be received from previous Browser window creation."""
    args_schema: Type[CloseSessionSchema] = CloseSessionSchema
    sessionId: str = ""
    def _run(
        self,
        sessionId: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> None:
        try:
            try:
                multion.close_session(sessionId)


try:
            try:
                multion.close_session(sessionId)
            except Exception as e:
                print(f"{e}, retrying...")
        except Exception as e:
            raise Exception(f"An error occurred: {e}")
    async def _arun(
        self,
        sessionId: str,
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> None:
        loop = asyncio.get_running_loop()
        await loop.run_in_executor(None, self._run, sessionId)


Source code for langchain.tools.multion.create_session
import asyncio
from typing import TYPE_CHECKING, Optional, Type
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForToolRun,
)
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.base import BaseTool
if TYPE_CHECKING:
    # This is for linting and IDE typehints
    import multion
else:
    try:
        # We do this so pydantic can resolve the types when instantiating
        import multion
    except ImportError:
        pass
[docs]class CreateSessionSchema(BaseModel):
    """Input for CreateSessionTool."""
    query: str = Field(
        ...,
        description="The query to run in multion agent.",
    )
    url: str = Field(
        "https://www.google.com/",
        description="""The Url to run the agent at. Note: accepts only secure \
            links having https://""",
    )
[docs]class MultionCreateSession(BaseTool):
    """Tool that creates a new Multion Browser Window with provided fields.
    Attributes:
        name: The name of the tool. Default: "create_multion_session"
        description: The description of the tool.
        args_schema: The schema for the tool's arguments.
    """
    name: str = "create_multion_session"
    description: str = """
        Create a new web browsing session based on a user's command or request. \
        The command should include the full info required for the session. \
        Also include an url (defaults to google.com if no better option) \
        to start the session. \
        Use this tool to create a new Browser Window with provided fields. \


Use this tool to create a new Browser Window with provided fields. \
        Always the first step to run any activities that can be done using browser.
        """
    args_schema: Type[CreateSessionSchema] = CreateSessionSchema
    def _run(
        self,
        query: str,
        url: Optional[str] = "https://www.google.com/",
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> dict:
        try:
            response = multion.new_session({"input": query, "url": url})
            return {
                "sessionId": response["session_id"],
                "Response": response["message"],
            }
        except Exception as e:
            raise Exception(f"An error occurred: {e}")
    async def _arun(
        self,
        query: str,
        url: Optional[str] = "https://www.google.com/",
        run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
    ) -> dict:
        loop = asyncio.get_running_loop()
        result = await loop.run_in_executor(None, self._run, query, url)
        return result


Source code for langchain.tools.gitlab.tool
"""
This tool allows agents to interact with the python-gitlab library
and operate on a GitLab repository.
To use this tool, you must first set as environment variables:
    GITLAB_PRIVATE_ACCESS_TOKEN
    GITLAB_REPOSITORY -> format: {owner}/{repo}
"""
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.gitlab import GitLabAPIWrapper
[docs]class GitLabAction(BaseTool):
    """Tool for interacting with the GitLab API."""
    api_wrapper: GitLabAPIWrapper = Field(default_factory=GitLabAPIWrapper)
    mode: str
    name: str = ""
    description: str = ""
    def _run(
        self,
        instructions: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the GitLab API to run an operation."""
        return self.api_wrapper.run(self.mode, instructions)


Source code for langchain.tools.google_search.tool
"""Tool for the Google search API."""
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools.base import BaseTool
from langchain.utilities.google_search import GoogleSearchAPIWrapper
[docs]class GoogleSearchRun(BaseTool):
    """Tool that queries the Google search API."""
    name: str = "google_search"
    description: str = (
        "A wrapper around Google Search. "
        "Useful for when you need to answer questions about current events. "
        "Input should be a search query."
    )
    api_wrapper: GoogleSearchAPIWrapper
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return self.api_wrapper.run(query)
[docs]class GoogleSearchResults(BaseTool):
    """Tool that queries the Google Search API and gets back json."""
    name: str = "Google Search Results JSON"
    description: str = (
        "A wrapper around Google 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: GoogleSearchAPIWrapper
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return str(self.api_wrapper.results(query, self.num_results))


Source code for langchain.tools.amadeus.closest_airport
from typing import Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.chains import LLMChain
from langchain.chat_models import ChatOpenAI
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.amadeus.base import AmadeusBaseTool
[docs]class ClosestAirportSchema(BaseModel):
    """Schema for the AmadeusClosestAirport tool."""
    location: str = Field(
        description=(
            " The location for which you would like to find the nearest airport "
            " along with optional details such as country, state, region, or "
            " province, allowing for easy processing and identification of "
            " the closest airport. Examples of the format are the following:\n"
            " Cali, Colombia\n "
            " Lincoln, Nebraska, United States\n"
            " New York, United States\n"
            " Sydney, New South Wales, Australia\n"
            " Rome, Lazio, Italy\n"
            " Toronto, Ontario, Canada\n"
        )
    )
[docs]class AmadeusClosestAirport(AmadeusBaseTool):
    """Tool for finding the closest airport to a particular location."""
    name: str = "closest_airport"
    description: str = (
        "Use this tool to find the closest airport to a particular location."
    )
    args_schema: Type[ClosestAirportSchema] = ClosestAirportSchema
    def _run(
        self,
        location: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        template = (
            " What is the nearest airport to {location}? Please respond with the "


" What is the nearest airport to {location}? Please respond with the "
            " airport's International Air Transport Association (IATA) Location "
            ' Identifier in the following JSON format. JSON: "iataCode": "IATA '
            ' Location Identifier" '
        )
        llm = ChatOpenAI(temperature=0)
        llm_chain = LLMChain.from_string(llm=llm, template=template)
        output = llm_chain.run(location=location)
        return output


Source code for langchain.tools.amadeus.base
"""Base class for Amadeus tools."""
from __future__ import annotations
from typing import TYPE_CHECKING
from langchain.pydantic_v1 import Field
from langchain.tools.amadeus.utils import authenticate
from langchain.tools.base import BaseTool
if TYPE_CHECKING:
    from amadeus import Client
[docs]class AmadeusBaseTool(BaseTool):
    """Base Tool for Amadeus."""
    client: Client = Field(default_factory=authenticate)


Source code for langchain.tools.amadeus.utils
"""O365 tool utils."""
from __future__ import annotations
import logging
import os
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from amadeus import Client
logger = logging.getLogger(__name__)
[docs]def authenticate() -> Client:
    """Authenticate using the Amadeus API"""
    try:
        from amadeus import Client
    except ImportError as e:
        raise ImportError(
            "Cannot import amadeus. Please install the package with "
            "`pip install amadeus`."
        ) from e
    if "AMADEUS_CLIENT_ID" in os.environ and "AMADEUS_CLIENT_SECRET" in os.environ:
        client_id = os.environ["AMADEUS_CLIENT_ID"]
        client_secret = os.environ["AMADEUS_CLIENT_SECRET"]
    else:
        logger.error(
            "Error: The AMADEUS_CLIENT_ID and AMADEUS_CLIENT_SECRET environmental "
            "variables have not been set. Visit the following link on how to "
            "acquire these authorization tokens: "
            "https://developers.amadeus.com/register"
        )
        return None
    client = Client(client_id=client_id, client_secret=client_secret)
    return client


Source code for langchain.tools.amadeus.flight_search
import logging
from datetime import datetime as dt
from typing import Dict, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.amadeus.base import AmadeusBaseTool
logger = logging.getLogger(__name__)
[docs]class FlightSearchSchema(BaseModel):
    """Schema for the AmadeusFlightSearch tool."""
    originLocationCode: str = Field(
        description=(
            " The three letter International Air Transport "
            " Association (IATA) Location Identifier for the "
            " search's origin airport. "
        )
    )
    destinationLocationCode: str = Field(
        description=(
            " The three letter International Air Transport "
            " Association (IATA) Location Identifier for the "
            " search's destination airport. "
        )
    )
    departureDateTimeEarliest: str = Field(
        description=(
            " The earliest departure datetime from the origin airport "
            " for the flight search in the following format: "
            ' "YYYY-MM-DDTHH:MM", where "T" separates the date and time '
            ' components. For example: "2023-06-09T10:30:00" represents '
            " June 9th, 2023, at 10:30 AM. "
        )
    )
    departureDateTimeLatest: str = Field(
        description=(
            " The latest departure datetime from the origin airport "
            " for the flight search in the following format: "
            ' "YYYY-MM-DDTHH:MM", where "T" separates the date and time '


' components. For example: "2023-06-09T10:30:00" represents '
            " June 9th, 2023, at 10:30 AM. "
        )
    )
    page_number: int = Field(
        default=1,
        description="The specific page number of flight results to retrieve",
    )
[docs]class AmadeusFlightSearch(AmadeusBaseTool):
    """Tool for searching for a single flight between two airports."""
    name: str = "single_flight_search"
    description: str = (
        " Use this tool to search for a single flight between the origin and "
        " destination airports at a departure between an earliest and "
        " latest datetime. "
    )
    args_schema: Type[FlightSearchSchema] = FlightSearchSchema
    def _run(
        self,
        originLocationCode: str,
        destinationLocationCode: str,
        departureDateTimeEarliest: str,
        departureDateTimeLatest: str,
        page_number: int = 1,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> list:
        try:
            from amadeus import ResponseError
        except ImportError as e:
            raise ImportError(
                "Unable to import amadeus, please install with `pip install amadeus`."
            ) from e
        RESULTS_PER_PAGE = 10
        # Authenticate and retrieve a client
        client = self.client
        # Check that earliest and latest dates are in the same day
        earliestDeparture = dt.strptime(departureDateTimeEarliest, "%Y-%m-%dT%H:%M:%S")
        latestDeparture = dt.strptime(departureDateTimeLatest, "%Y-%m-%dT%H:%M:%S")


if earliestDeparture.date() != latestDeparture.date():
            logger.error(
                " Error: Earliest and latest departure dates need to be the "
                " same date. If you're trying to search for round-trip "
                " flights, call this function for the outbound flight first, "
                " and then call again for the return flight. "
            )
            return [None]
        # Collect all results from the API
        try:
            response = client.shopping.flight_offers_search.get(
                originLocationCode=originLocationCode,
                destinationLocationCode=destinationLocationCode,
                departureDate=latestDeparture.strftime("%Y-%m-%d"),
                adults=1,
            )
        except ResponseError as error:
            print(error)
        # Generate output dictionary
        output = []
        for offer in response.data:
            itinerary: Dict = {}
            itinerary["price"] = {}
            itinerary["price"]["total"] = offer["price"]["total"]
            currency = offer["price"]["currency"]
            currency = response.result["dictionaries"]["currencies"][currency]
            itinerary["price"]["currency"] = {}
            itinerary["price"]["currency"] = currency
            segments = []
            for segment in offer["itineraries"][0]["segments"]:
                flight = {}
                flight["departure"] = segment["departure"]
                flight["arrival"] = segment["arrival"]
                flight["flightNumber"] = segment["number"]
                carrier = segment["carrierCode"]
                carrier = response.result["dictionaries"]["carriers"][carrier]
                flight["carrier"] = carrier
                segments.append(flight)
            itinerary["segments"] = []
            itinerary["segments"] = segments
            output.append(itinerary)
        # Filter out flights after latest departure time


output.append(itinerary)
        # Filter out flights after latest departure time
        for index, offer in enumerate(output):
            offerDeparture = dt.strptime(
                offer["segments"][0]["departure"]["at"], "%Y-%m-%dT%H:%M:%S"
            )
            if offerDeparture > latestDeparture:
                output.pop(index)
        # Return the paginated results
        startIndex = (page_number - 1) * RESULTS_PER_PAGE
        endIndex = startIndex + RESULTS_PER_PAGE
        return output[startIndex:endIndex]


Source code for langchain.tools.wikipedia.tool
"""Tool for the Wikipedia API."""
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools.base import BaseTool
from langchain.utilities.wikipedia import WikipediaAPIWrapper
[docs]class WikipediaQueryRun(BaseTool):
    """Tool that searches the Wikipedia API."""
    name: str = "Wikipedia"
    description: str = (
        "A wrapper around Wikipedia. "
        "Useful for when you need to answer general questions about "
        "people, places, companies, facts, historical events, or other subjects. "
        "Input should be a search query."
    )
    api_wrapper: WikipediaAPIWrapper
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Wikipedia 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, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.base import BaseTool
from langchain.utilities.duckduckgo_search import DuckDuckGoSearchAPIWrapper
[docs]class DDGInput(BaseModel):
    query: str = Field(description="search query to look up")
[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
    )
    args_schema: Type[BaseModel] = DDGInput
    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. "


"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
    )
    backend: str = "api"
    args_schema: Type[BaseModel] = DDGInput
    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.zapier.tool
"""[DEPRECATED]
## 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._api import warn_deprecated
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


zapier_description: str
    params_schema: Dict[str, str] = Field(default_factory=dict)
    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."""
        warn_deprecated(
            since="0.0.319",
            message=(
                "This tool will be deprecated on 2023-11-17. See "
                "https://nla.zapier.com/sunset/ for details"
            ),
        )
        return self.api_wrapper.run_as_str(self.action_id, instructions, self.params)
    async def _arun(
        self,
        instructions: str,


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."""
        warn_deprecated(
            since="0.0.319",
            message=(
                "This tool will be deprecated on 2023-11-17. See "
                "https://nla.zapier.com/sunset/ for details"
            ),
        )
        return await self.api_wrapper.arun_as_str(
            self.action_id,
            instructions,
            self.params,
        )
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."""
        warn_deprecated(
            since="0.0.319",
            message=(
                "This tool will be deprecated on 2023-11-17. See "


"This tool will be deprecated on 2023-11-17. See "
                "https://nla.zapier.com/sunset/ for details"
            ),
        )
        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."""
        warn_deprecated(
            since="0.0.319",
            message=(
                "This tool will be deprecated on 2023-11-17. See "
                "https://nla.zapier.com/sunset/ for details"
            ),
        )
        return await self.api_wrapper.alist_as_str()
ZapierNLAListActions.__doc__ = (
    ZapierNLAWrapper.list.__doc__ + ZapierNLAListActions.__doc__  # type: ignore
)


Source code for langchain.tools.human.tool
"""Tool for asking human input."""
from typing import Callable, Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import Field
from langchain.tools.base import BaseTool
def _print_func(text: str) -> None:
    print("\n")
    print(text)
[docs]class HumanInputRun(BaseTool):
    """Tool that asks user for input."""
    name: str = "human"
    description: str = (
        "You can ask a human for guidance when you think you "
        "got stuck or you are not sure what to do next. "
        "The input should be a question for the human."
    )
    prompt_func: Callable[[str], None] = Field(default_factory=lambda: _print_func)
    input_func: Callable = Field(default_factory=lambda: input)
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Human input tool."""
        self.prompt_func(query)
        return self.input_func()


Source code for langchain.tools.google_scholar.tool
"""Tool for the Google Scholar"""
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools.base import BaseTool
from langchain.utilities.google_scholar import GoogleScholarAPIWrapper
[docs]class GoogleScholarQueryRun(BaseTool):
    """Tool that queries the Google search API."""
    name: str = "google_scholar"
    description: str = (
        "A wrapper around Google Scholar Search. "
        "Useful for when you need to get information about"
        "research papers from Google Scholar"
        "Input should be a search query."
    )
    api_wrapper: GoogleScholarAPIWrapper
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the 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.openweathermap 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.github.tool
"""
This tool allows agents to interact with the pygithub library
and operate on a GitHub repository.
To use this tool, you must first set as environment variables:
    GITHUB_API_TOKEN
    GITHUB_REPOSITORY -> format: {owner}/{repo}
"""
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.github import GitHubAPIWrapper
[docs]class GitHubAction(BaseTool):
    """Tool for interacting with the GitHub API."""
    api_wrapper: GitHubAPIWrapper = Field(default_factory=GitHubAPIWrapper)
    mode: str
    name: str = ""
    description: str = ""
    def _run(
        self,
        instructions: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the GitHub API to run an operation."""
        return self.api_wrapper.run(self.mode, instructions)


Source code for langchain.tools.bing_search.tool
"""Tool for the Bing search API."""
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools.base import BaseTool
from langchain.utilities.bing_search import BingSearchAPIWrapper
[docs]class BingSearchRun(BaseTool):
    """Tool that queries the Bing search API."""
    name: str = "bing_search"
    description: str = (
        "A wrapper around Bing Search. "
        "Useful for when you need to answer questions about current events. "
        "Input should be a search query."
    )
    api_wrapper: BingSearchAPIWrapper
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return self.api_wrapper.run(query)
[docs]class BingSearchResults(BaseTool):
    """Tool that queries the Bing Search API and gets back json."""
    name: str = "Bing Search Results JSON"
    description: str = (
        "A wrapper around Bing 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: BingSearchAPIWrapper
    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return str(self.api_wrapper.results(query, self.num_results))


Source code for langchain.tools.file_management.delete
import os
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.tools.file_management.utils import (
    INVALID_PATH_TEMPLATE,
    BaseFileToolMixin,
    FileValidationError,
)
[docs]class FileDeleteInput(BaseModel):
    """Input for DeleteFileTool."""
    file_path: str = Field(..., description="Path of the file to delete")
[docs]class DeleteFileTool(BaseFileToolMixin, BaseTool):
    """Tool that deletes a file."""
    name: str = "file_delete"
    args_schema: Type[BaseModel] = FileDeleteInput
    description: str = "Delete a file"
    def _run(
        self,
        file_path: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        try:
            file_path_ = self.get_relative_path(file_path)
        except FileValidationError:
            return INVALID_PATH_TEMPLATE.format(arg_name="file_path", value=file_path)
        if not file_path_.exists():
            return f"Error: no such file or directory: {file_path}"
        try:
            os.remove(file_path_)
            return f"File deleted successfully: {file_path}."
        except Exception as e:
            return "Error: " + str(e)
    # TODO: Add aiofiles method


Source code for langchain.tools.file_management.file_search
import fnmatch
import os
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.tools.file_management.utils import (
    INVALID_PATH_TEMPLATE,
    BaseFileToolMixin,
    FileValidationError,
)
[docs]class FileSearchInput(BaseModel):
    """Input for FileSearchTool."""
    dir_path: str = Field(
        default=".",
        description="Subdirectory to search in.",
    )
    pattern: str = Field(
        ...,
        description="Unix shell regex, where * matches everything.",
    )
[docs]class FileSearchTool(BaseFileToolMixin, BaseTool):
    """Tool that searches for files in a subdirectory that match a regex pattern."""
    name: str = "file_search"
    args_schema: Type[BaseModel] = FileSearchInput
    description: str = (
        "Recursively search for files in a subdirectory that match the regex pattern"
    )
    def _run(
        self,
        pattern: str,
        dir_path: str = ".",
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        try:
            dir_path_ = self.get_relative_path(dir_path)
        except FileValidationError:
            return INVALID_PATH_TEMPLATE.format(arg_name="dir_path", value=dir_path)
        matches = []
        try:
            for root, _, filenames in os.walk(dir_path_):
                for filename in fnmatch.filter(filenames, pattern):
                    absolute_path = os.path.join(root, filename)
                    relative_path = os.path.relpath(absolute_path, dir_path_)


relative_path = os.path.relpath(absolute_path, dir_path_)
                    matches.append(relative_path)
            if matches:
                return "\n".join(matches)
            else:
                return f"No files found for pattern {pattern} in directory {dir_path}"
        except Exception as e:
            return "Error: " + str(e)
    # TODO: Add aiofiles method


Source code for langchain.tools.file_management.write
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.tools.file_management.utils import (
    INVALID_PATH_TEMPLATE,
    BaseFileToolMixin,
    FileValidationError,
)
[docs]class WriteFileInput(BaseModel):
    """Input for WriteFileTool."""
    file_path: str = Field(..., description="name of file")
    text: str = Field(..., description="text to write to file")
    append: bool = Field(
        default=False, description="Whether to append to an existing file."
    )
[docs]class WriteFileTool(BaseFileToolMixin, BaseTool):
    """Tool that writes a file to disk."""
    name: str = "write_file"
    args_schema: Type[BaseModel] = WriteFileInput
    description: str = "Write file to disk"
    def _run(
        self,
        file_path: str,
        text: str,
        append: bool = False,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        try:
            write_path = self.get_relative_path(file_path)
        except FileValidationError:
            return INVALID_PATH_TEMPLATE.format(arg_name="file_path", value=file_path)
        try:
            write_path.parent.mkdir(exist_ok=True, parents=False)
            mode = "a" if append else "w"
            with write_path.open(mode, encoding="utf-8") as f:
                f.write(text)
            return f"File written successfully to {file_path}."
        except Exception as e:
            return "Error: " + str(e)


except Exception as e:
            return "Error: " + str(e)
    # TODO: Add aiofiles method


Source code for langchain.tools.file_management.move
import shutil
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.tools.file_management.utils import (
    INVALID_PATH_TEMPLATE,
    BaseFileToolMixin,
    FileValidationError,
)
[docs]class FileMoveInput(BaseModel):
    """Input for MoveFileTool."""
    source_path: str = Field(..., description="Path of the file to move")
    destination_path: str = Field(..., description="New path for the moved file")
[docs]class MoveFileTool(BaseFileToolMixin, BaseTool):
    """Tool that moves a file."""
    name: str = "move_file"
    args_schema: Type[BaseModel] = FileMoveInput
    description: str = "Move or rename a file from one location to another"
    def _run(
        self,
        source_path: str,
        destination_path: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        try:
            source_path_ = self.get_relative_path(source_path)
        except FileValidationError:
            return INVALID_PATH_TEMPLATE.format(
                arg_name="source_path", value=source_path
            )
        try:
            destination_path_ = self.get_relative_path(destination_path)
        except FileValidationError:
            return INVALID_PATH_TEMPLATE.format(
                arg_name="destination_path_", value=destination_path_
            )
        if not source_path_.exists():
            return f"Error: no such file or directory {source_path}"
        try:
            # shutil.move expects str args in 3.8
            shutil.move(str(source_path_), destination_path_)


shutil.move(str(source_path_), destination_path_)
            return f"File moved successfully from {source_path} to {destination_path}."
        except Exception as e:
            return "Error: " + str(e)
    # TODO: Add aiofiles method


Source code for langchain.tools.file_management.list_dir
import os
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.tools.file_management.utils import (
    INVALID_PATH_TEMPLATE,
    BaseFileToolMixin,
    FileValidationError,
)
[docs]class DirectoryListingInput(BaseModel):
    """Input for ListDirectoryTool."""
    dir_path: str = Field(default=".", description="Subdirectory to list.")
[docs]class ListDirectoryTool(BaseFileToolMixin, BaseTool):
    """Tool that lists files and directories in a specified folder."""
    name: str = "list_directory"
    args_schema: Type[BaseModel] = DirectoryListingInput
    description: str = "List files and directories in a specified folder"
    def _run(
        self,
        dir_path: str = ".",
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        try:
            dir_path_ = self.get_relative_path(dir_path)
        except FileValidationError:
            return INVALID_PATH_TEMPLATE.format(arg_name="dir_path", value=dir_path)
        try:
            entries = os.listdir(dir_path_)
            if entries:
                return "\n".join(entries)
            else:
                return f"No files found in directory {dir_path}"
        except Exception as e:
            return "Error: " + str(e)
    # TODO: Add aiofiles method


Source code for langchain.tools.file_management.utils
import sys
from pathlib import Path
from typing import Optional
from langchain.pydantic_v1 import BaseModel
[docs]def is_relative_to(path: Path, root: Path) -> bool:
    """Check if path is relative to root."""
    if sys.version_info >= (3, 9):
        # No need for a try/except block in Python 3.8+.
        return path.is_relative_to(root)
    try:
        path.relative_to(root)
        return True
    except ValueError:
        return False
INVALID_PATH_TEMPLATE = (
    "Error: Access denied to {arg_name}: {value}."
    " Permission granted exclusively to the current working directory"
)
[docs]class FileValidationError(ValueError):
    """Error for paths outside the root directory."""
[docs]class BaseFileToolMixin(BaseModel):
    """Mixin for file system tools."""
    root_dir: Optional[str] = None
    """The final path will be chosen relative to root_dir if specified."""
[docs]    def get_relative_path(self, file_path: str) -> Path:
        """Get the relative path, returning an error if unsupported."""
        if self.root_dir is None:
            return Path(file_path)
        return get_validated_relative_path(Path(self.root_dir), file_path)
[docs]def get_validated_relative_path(root: Path, user_path: str) -> Path:
    """Resolve a relative path, raising an error if not within the root directory."""
    # Note, this still permits symlinks from outside that point within the root.
    # Further validation would be needed if those are to be disallowed.
    root = root.resolve()
    full_path = (root / user_path).resolve()


root = root.resolve()
    full_path = (root / user_path).resolve()
    if not is_relative_to(full_path, root):
        raise FileValidationError(
            f"Path {user_path} is outside of the allowed directory {root}"
        )
    return full_path


Source code for langchain.tools.file_management.read
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.tools.file_management.utils import (
    INVALID_PATH_TEMPLATE,
    BaseFileToolMixin,
    FileValidationError,
)
[docs]class ReadFileInput(BaseModel):
    """Input for ReadFileTool."""
    file_path: str = Field(..., description="name of file")
[docs]class ReadFileTool(BaseFileToolMixin, BaseTool):
    """Tool that reads a file."""
    name: str = "read_file"
    args_schema: Type[BaseModel] = ReadFileInput
    description: str = "Read file from disk"
    def _run(
        self,
        file_path: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        try:
            read_path = self.get_relative_path(file_path)
        except FileValidationError:
            return INVALID_PATH_TEMPLATE.format(arg_name="file_path", value=file_path)
        if not read_path.exists():
            return f"Error: no such file or directory: {file_path}"
        try:
            with read_path.open("r", encoding="utf-8") as f:
                content = f.read()
            return content
        except Exception as e:
            return "Error: " + str(e)
    # TODO: Add aiofiles method


Source code for langchain.tools.file_management.copy
import shutil
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.tools.file_management.utils import (
    INVALID_PATH_TEMPLATE,
    BaseFileToolMixin,
    FileValidationError,
)
[docs]class FileCopyInput(BaseModel):
    """Input for CopyFileTool."""
    source_path: str = Field(..., description="Path of the file to copy")
    destination_path: str = Field(..., description="Path to save the copied file")
[docs]class CopyFileTool(BaseFileToolMixin, BaseTool):
    """Tool that copies a file."""
    name: str = "copy_file"
    args_schema: Type[BaseModel] = FileCopyInput
    description: str = "Create a copy of a file in a specified location"
    def _run(
        self,
        source_path: str,
        destination_path: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        try:
            source_path_ = self.get_relative_path(source_path)
        except FileValidationError:
            return INVALID_PATH_TEMPLATE.format(
                arg_name="source_path", value=source_path
            )
        try:
            destination_path_ = self.get_relative_path(destination_path)
        except FileValidationError:
            return INVALID_PATH_TEMPLATE.format(
                arg_name="destination_path", value=destination_path
            )
        try:
            shutil.copy2(source_path_, destination_path_, follow_symlinks=False)
            return f"File copied successfully from {source_path} to {destination_path}."
        except Exception as e:


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.graphql.tool
import json
from typing import Optional
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.tools.base import BaseTool
from langchain.utilities.graphql import GraphQLAPIWrapper
[docs]class BaseGraphQLTool(BaseTool):
    """Base tool for querying a GraphQL API."""
    graphql_wrapper: GraphQLAPIWrapper
    name: str = "query_graphql"
    description: str = """\
    Input to this tool is a detailed and correct GraphQL query, output is a result from the API.
    If the query is not correct, an error message will be returned.
    If an error is returned with 'Bad request' in it, rewrite the query and try again.
    If an error is returned with 'Unauthorized' in it, do not try again, but tell the user to change their authentication.
    Example Input: query {{ allUsers {{ id, name, email }} }}\
    """  # noqa: E501
    class Config:
        """Configuration for this pydantic object."""
        arbitrary_types_allowed = True
    def _run(
        self,
        tool_input: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        result = self.graphql_wrapper.run(tool_input)
        return json.dumps(result, indent=2)


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.clickup.tool
"""
This tool allows agents to interact with the clickup library
and operate on a Clickup instance.
To use this tool, you must first set as environment variables:
    client_secret
    client_id
    code
Below is a sample script that uses the Clickup tool:
```python
from langchain.agents import AgentType
from langchain.agents import initialize_agent
from langchain.agents.agent_toolkits.clickup.toolkit import ClickupToolkit
from langchain.llms import OpenAI
from langchain.utilities.clickup import ClickupAPIWrapper
llm = OpenAI(temperature=0)
clickup = ClickupAPIWrapper()
toolkit = ClickupToolkit.from_clickup_api_wrapper(clickup)
agent = initialize_agent(
    toolkit.get_tools(),
    llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)
```
"""
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.clickup import ClickupAPIWrapper
[docs]class ClickupAction(BaseTool):
    """Tool that queries the  Clickup API."""
    api_wrapper: ClickupAPIWrapper = Field(default_factory=ClickupAPIWrapper)
    mode: str
    name: str = ""
    description: str = ""
    def _run(
        self,
        instructions: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the  Clickup API to run an operation."""
        return self.api_wrapper.run(self.mode, instructions)


Source code for langchain.tools.office365.events_search
"""Util that Searches calendar events in Office 365.
Free, but setup is required. See link below.
https://learn.microsoft.com/en-us/graph/auth/
"""
from datetime import datetime as dt
from typing import Any, Dict, List, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Extra, Field
from langchain.tools.office365.base import O365BaseTool
from langchain.tools.office365.utils import clean_body
[docs]class SearchEventsInput(BaseModel):
    """Input for SearchEmails Tool."""
    """From https://learn.microsoft.com/en-us/graph/search-query-parameter"""
    start_datetime: str = Field(
        description=(
            " The start datetime for the search query in the following format: "
            ' YYYY-MM-DDTHH:MM:SS±hh:mm, where "T" separates the date and time '
            " components, and the time zone offset is specified as ±hh:mm. "
            ' For example: "2023-06-09T10:30:00+03:00" represents June 9th, '
            " 2023, at 10:30 AM in a time zone with a positive offset of 3 "
            " hours from Coordinated Universal Time (UTC)."
        )
    )
    end_datetime: str = Field(
        description=(
            " The end datetime for the search query in the following format: "
            ' YYYY-MM-DDTHH:MM:SS±hh:mm, where "T" separates the date and time '
            " components, and the time zone offset is specified as ±hh:mm. "


" components, and the time zone offset is specified as ±hh:mm. "
            ' For example: "2023-06-09T10:30:00+03:00" represents June 9th, '
            " 2023, at 10:30 AM in a time zone with a positive offset of 3 "
            " hours from Coordinated Universal Time (UTC)."
        )
    )
    max_results: int = Field(
        default=10,
        description="The maximum number of results to return.",
    )
    truncate: bool = Field(
        default=True,
        description=(
            "Whether the event's body is truncated to meet token number limits. Set to "
            "False for searches that will retrieve very few results, otherwise, set to "
            "True."
        ),
    )
[docs]class O365SearchEvents(O365BaseTool):
    """Class for searching calendar events in Office 365
    Free, but setup is required
    """
    name: str = "events_search"
    args_schema: Type[BaseModel] = SearchEventsInput
    description: str = (
        " Use this tool to search for the user's calendar events."
        " The input must be the start and end datetimes for the search query."
        " The output is a JSON list of all the events in the user's calendar"
        " between the start and end times. You can assume that the user can "
        " not schedule any meeting over existing meetings, and that the user "
        "is busy during meetings. Any times without events are free for the user. "
    )
    class Config:
        """Configuration for this pydantic object."""
        extra = Extra.forbid
    def _run(
        self,


extra = Extra.forbid
    def _run(
        self,
        start_datetime: str,
        end_datetime: str,
        max_results: int = 10,
        truncate: bool = True,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> List[Dict[str, Any]]:
        TRUNCATE_LIMIT = 150
        # Get calendar object
        schedule = self.account.schedule()
        calendar = schedule.get_default_calendar()
        # Process the date range parameters
        start_datetime_query = dt.strptime(start_datetime, "%Y-%m-%dT%H:%M:%S%z")
        end_datetime_query = dt.strptime(end_datetime, "%Y-%m-%dT%H:%M:%S%z")
        # Run the query
        q = calendar.new_query("start").greater_equal(start_datetime_query)
        q.chain("and").on_attribute("end").less_equal(end_datetime_query)
        events = calendar.get_events(query=q, include_recurring=True, limit=max_results)
        # Generate output dict
        output_events = []
        for event in events:
            output_event = {}
            output_event["organizer"] = event.organizer
            output_event["subject"] = event.subject
            if truncate:
                output_event["body"] = clean_body(event.body)[:TRUNCATE_LIMIT]
            else:
                output_event["body"] = clean_body(event.body)
            # Get the time zone from the search parameters
            time_zone = start_datetime_query.tzinfo
            # Assign the datetimes in the search time zone
            output_event["start_datetime"] = event.start.astimezone(time_zone).strftime(
                "%Y-%m-%dT%H:%M:%S%z"
            )


"%Y-%m-%dT%H:%M:%S%z"
            )
            output_event["end_datetime"] = event.end.astimezone(time_zone).strftime(
                "%Y-%m-%dT%H:%M:%S%z"
            )
            output_event["modified_date"] = event.modified.astimezone(
                time_zone
            ).strftime("%Y-%m-%dT%H:%M:%S%z")
            output_events.append(output_event)
        return output_events


Source code for langchain.tools.office365.messages_search
"""Util that Searches email messages in Office 365.
Free, but setup is required. See link below.
https://learn.microsoft.com/en-us/graph/auth/
"""
from typing import Any, Dict, List, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Extra, Field
from langchain.tools.office365.base import O365BaseTool
from langchain.tools.office365.utils import clean_body
[docs]class SearchEmailsInput(BaseModel):
    """Input for SearchEmails Tool."""
    """From https://learn.microsoft.com/en-us/graph/search-query-parameter"""
    folder: str = Field(
        default=None,
        description=(
            " If the user wants to search in only one folder, the name of the folder. "
            'Default folders are "inbox", "drafts", "sent items", "deleted ttems", but '
            "users can search custom folders as well."
        ),
    )
    query: str = Field(
        description=(
            "The Microsoift Graph v1.0 $search query. Example filters include "
            "from:sender, from:sender, to:recipient, subject:subject, "
            "recipients:list_of_recipients, body:excitement, importance:high, "
            "received>2022-12-01, received<2021-12-01, sent>2022-12-01, "
            "sent<2021-12-01, hasAttachments:true  attachment:api-catalog.md, "
            "cc:samanthab@contoso.com, bcc:samanthab@contoso.com, body:excitement date "


"range example: received:2023-06-08..2023-06-09  matching example: "
            "from:amy OR from:david."
        )
    )
    max_results: int = Field(
        default=10,
        description="The maximum number of results to return.",
    )
    truncate: bool = Field(
        default=True,
        description=(
            "Whether the email body is truncated to meet token number limits. Set to "
            "False for searches that will retrieve very few results, otherwise, set to "
            "True"
        ),
    )
[docs]class O365SearchEmails(O365BaseTool):
    """Class for searching email messages in Office 365
    Free, but setup is required
    """
    name: str = "messages_search"
    args_schema: Type[BaseModel] = SearchEmailsInput
    description: str = (
        "Use this tool to search for email messages."
        " The input must be a valid Microsoft Graph v1.0 $search query."
        " The output is a JSON list of the requested resource."
    )
    class Config:
        """Configuration for this pydantic object."""
        extra = Extra.forbid
    def _run(
        self,
        query: str,
        folder: str = "",
        max_results: int = 10,
        truncate: bool = True,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> List[Dict[str, Any]]:
        # Get mailbox object
        mailbox = self.account.mailbox()
        # Pull the folder if the user wants to search in a folder
        if folder != "":
            mailbox = mailbox.get_folder(folder_name=folder)


if folder != "":
            mailbox = mailbox.get_folder(folder_name=folder)
        # Retrieve messages based on query
        query = mailbox.q().search(query)
        messages = mailbox.get_messages(limit=max_results, query=query)
        # Generate output dict
        output_messages = []
        for message in messages:
            output_message = {}
            output_message["from"] = message.sender
            if truncate:
                output_message["body"] = message.body_preview
            else:
                output_message["body"] = clean_body(message.body)
            output_message["subject"] = message.subject
            output_message["date"] = message.modified.strftime("%Y-%m-%dT%H:%M:%S%z")
            output_message["to"] = []
            for recipient in message.to._recipients:
                output_message["to"].append(str(recipient))
            output_message["cc"] = []
            for recipient in message.cc._recipients:
                output_message["cc"].append(str(recipient))
            output_message["bcc"] = []
            for recipient in message.bcc._recipients:
                output_message["bcc"].append(str(recipient))
            output_messages.append(output_message)
        return output_messages


Source code for langchain.tools.office365.base
"""Base class for Office 365 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.office365.utils import authenticate
if TYPE_CHECKING:
    from O365 import Account
[docs]class O365BaseTool(BaseTool):
    """Base class for the Office 365 tools."""
    account: Account = Field(default_factory=authenticate)
    """The account object for the Office 365 account."""


Source code for langchain.tools.office365.utils
"""O365 tool utils."""
from __future__ import annotations
import logging
import os
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from O365 import Account
logger = logging.getLogger(__name__)
[docs]def clean_body(body: str) -> str:
    """Clean body of a message or event."""
    try:
        from bs4 import BeautifulSoup
        try:
            # Remove HTML
            soup = BeautifulSoup(str(body), "html.parser")
            body = soup.get_text()
            # Remove return characters
            body = "".join(body.splitlines())
            # Remove extra spaces
            body = " ".join(body.split())
            return str(body)
        except Exception:
            return str(body)
    except ImportError:
        return str(body)
[docs]def authenticate() -> Account:
    """Authenticate using the Microsoft Grah API"""
    try:
        from O365 import Account
    except ImportError as e:
        raise ImportError(
            "Cannot import 0365. Please install the package with `pip install O365`."
        ) from e
    if "CLIENT_ID" in os.environ and "CLIENT_SECRET" in os.environ:
        client_id = os.environ["CLIENT_ID"]
        client_secret = os.environ["CLIENT_SECRET"]
        credentials = (client_id, client_secret)
    else:
        logger.error(
            "Error: The CLIENT_ID and CLIENT_SECRET environmental variables have not "
            "been set. Visit the following link on how to acquire these authorization "
            "tokens: https://learn.microsoft.com/en-us/graph/auth/"
        )
        return None
    account = Account(credentials)
    if account.is_authenticated is False:
        if not account.authenticate(
            scopes=[


if account.is_authenticated is False:
        if not account.authenticate(
            scopes=[
                "https://graph.microsoft.com/Mail.ReadWrite",
                "https://graph.microsoft.com/Mail.Send",
                "https://graph.microsoft.com/Calendars.ReadWrite",
                "https://graph.microsoft.com/MailboxSettings.ReadWrite",
            ]
        ):
            print("Error: Could not authenticate")
            return None
        else:
            return account
    else:
        return account


Source code for langchain.tools.office365.send_message
from typing import List, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.office365.base import O365BaseTool
[docs]class SendMessageSchema(BaseModel):
    """Input for SendMessageTool."""
    body: str = Field(
        ...,
        description="The message body to be sent.",
    )
    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 O365SendMessage(O365BaseTool):
    """Tool for sending an email in Office 365."""
    name: str = "send_email"
    description: str = (
        "Use this tool to send an email with the provided message fields."
    )
    args_schema: Type[SendMessageSchema] = SendMessageSchema
    def _run(
        self,
        body: str,
        to: List[str],
        subject: str,
        cc: Optional[List[str]] = None,
        bcc: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        # Get mailbox object
        mailbox = self.account.mailbox()
        message = mailbox.new_message()
        # Assign message values
        message.body = body
        message.subject = subject


# Assign message values
        message.body = body
        message.subject = subject
        message.to.add(to)
        if cc is not None:
            message.cc.add(cc)
        if bcc is not None:
            message.bcc.add(cc)
        message.send()
        output = "Message sent: " + str(message)
        return output


Source code for langchain.tools.office365.create_draft_message
from typing import List, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.office365.base import O365BaseTool
[docs]class CreateDraftMessageSchema(BaseModel):
    """Input for SendMessageTool."""
    body: str = Field(
        ...,
        description="The message body 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 O365CreateDraftMessage(O365BaseTool):
    """Tool for creating a draft email in Office 365."""
    name: str = "create_email_draft"
    description: str = (
        "Use this tool to create a draft email with the provided message fields."
    )
    args_schema: Type[CreateDraftMessageSchema] = CreateDraftMessageSchema
    def _run(
        self,
        body: str,
        to: List[str],
        subject: str,
        cc: Optional[List[str]] = None,
        bcc: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        # Get mailbox object
        mailbox = self.account.mailbox()
        message = mailbox.new_message()
        # Assign message values


message = mailbox.new_message()
        # Assign message values
        message.body = body
        message.subject = subject
        message.to.add(to)
        if cc is not None:
            message.cc.add(cc)
        if bcc is not None:
            message.bcc.add(cc)
        message.save_draft()
        output = "Draft created: " + str(message)
        return output


Source code for langchain.tools.office365.send_event
"""Util that sends calendar events in Office 365.
Free, but setup is required. See link below.
https://learn.microsoft.com/en-us/graph/auth/
"""
from datetime import datetime as dt
from typing import List, Optional, Type
from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools.office365.base import O365BaseTool
[docs]class SendEventSchema(BaseModel):
    """Input for CreateEvent Tool."""
    body: str = Field(
        ...,
        description="The message body to include in the event.",
    )
    attendees: List[str] = Field(
        ...,
        description="The list of attendees for the event.",
    )
    subject: str = Field(
        ...,
        description="The subject of the event.",
    )
    start_datetime: str = Field(
        description=" The start datetime for the event in the following format: "
        ' YYYY-MM-DDTHH:MM:SS±hh:mm, where "T" separates the date and time '
        " components, and the time zone offset is specified as ±hh:mm. "
        ' For example: "2023-06-09T10:30:00+03:00" represents June 9th, '
        " 2023, at 10:30 AM in a time zone with a positive offset of 3 "
        " hours from Coordinated Universal Time (UTC).",
    )
    end_datetime: str = Field(
        description=" The end datetime for the event in the following format: "
        ' YYYY-MM-DDTHH:MM:SS±hh:mm, where "T" separates the date and time '


" components, and the time zone offset is specified as ±hh:mm. "
        ' For example: "2023-06-09T10:30:00+03:00" represents June 9th, '
        " 2023, at 10:30 AM in a time zone with a positive offset of 3 "
        " hours from Coordinated Universal Time (UTC).",
    )
[docs]class O365SendEvent(O365BaseTool):
    """Tool for sending calendar events in Office 365."""
    name: str = "send_event"
    description: str = (
        "Use this tool to create and send an event with the provided event fields."
    )
    args_schema: Type[SendEventSchema] = SendEventSchema
    def _run(
        self,
        body: str,
        attendees: List[str],
        subject: str,
        start_datetime: str,
        end_datetime: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        # Get calendar object
        schedule = self.account.schedule()
        calendar = schedule.get_default_calendar()
        event = calendar.new_event()
        event.body = body
        event.subject = subject
        event.start = dt.strptime(start_datetime, "%Y-%m-%dT%H:%M:%S%z")
        event.end = dt.strptime(end_datetime, "%Y-%m-%dT%H:%M:%S%z")
        for attendee in attendees:
            event.attendees.add(attendee)
        # TO-DO: Look into PytzUsageWarning
        event.save()
        output = "Event sent: " + str(event)
        return output