From c2a614eddce272afedc1af798e2ca68589a6fc3b Mon Sep 17 00:00:00 2001 From: Virat Singh Date: Sun, 21 Jan 2024 18:08:55 -0500 Subject: [PATCH] community: Add PolygonLastQuote Tool and Toolkit (#15990) **Description:** In this PR, I am adding a `PolygonLastQuote` Tool, which can be used to get the latest price quote for a given ticker / stock. Additionally, I've added a Polygon Toolkit, which we can use to encapsulate future tools that we build for Polygon. **Twitter handle:** [@virattt](https://twitter.com/virattt) --------- Co-authored-by: Harrison Chase --- docs/docs/integrations/toolkits/gmail.ipynb | 2 +- docs/docs/integrations/toolkits/polygon.ipynb | 187 ++++++++++++++++++ docs/docs/integrations/tools/polygon.ipynb | 29 +-- .../agent_toolkits/__init__.py | 2 + .../agent_toolkits/polygon/__init__.py | 1 + .../agent_toolkits/polygon/toolkit.py | 27 +++ .../langchain_community/tools/__init__.py | 9 + .../tools/polygon/__init__.py | 7 + .../tools/polygon/last_quote.py | 34 ++++ .../unit_tests/agent_toolkits/test_imports.py | 1 + .../tests/unit_tests/tools/test_imports.py | 1 + .../tests/unit_tests/tools/test_public_api.py | 1 + 12 files changed, 286 insertions(+), 15 deletions(-) create mode 100644 docs/docs/integrations/toolkits/polygon.ipynb create mode 100644 libs/community/langchain_community/agent_toolkits/polygon/__init__.py create mode 100644 libs/community/langchain_community/agent_toolkits/polygon/toolkit.py create mode 100644 libs/community/langchain_community/tools/polygon/__init__.py create mode 100644 libs/community/langchain_community/tools/polygon/last_quote.py diff --git a/docs/docs/integrations/toolkits/gmail.ipynb b/docs/docs/integrations/toolkits/gmail.ipynb index dcbcadabc2..d9cafb0f5f 100644 --- a/docs/docs/integrations/toolkits/gmail.ipynb +++ b/docs/docs/integrations/toolkits/gmail.ipynb @@ -294,7 +294,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.1" + "version": "3.10.1" } }, "nbformat": 4, diff --git a/docs/docs/integrations/toolkits/polygon.ipynb b/docs/docs/integrations/toolkits/polygon.ipynb new file mode 100644 index 0000000000..87c8aa0af9 --- /dev/null +++ b/docs/docs/integrations/toolkits/polygon.ipynb @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e6fd05db-21c2-4227-9900-0840bc62cb31", + "metadata": {}, + "source": [ + "# Polygon IO Toolkit\n", + "\n", + "This notebook shows how to use agents to interact with the [Polygon IO](https://polygon.io/) toolkit. The toolkit provides access to Polygon's Stock Market Data API." + ] + }, + { + "cell_type": "markdown", + "id": "a4da342d", + "metadata": {}, + "source": [ + "## Example Use\n", + "\n", + "\n", + "### Setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c17b33e0", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --upgrade --quiet langchain-community > /dev/null" + ] + }, + { + "cell_type": "markdown", + "id": "3cd00ad2", + "metadata": {}, + "source": [ + "Get your Polygon IO API key [here](https://polygon.io/), and then set it below.\n", + "Note that the tool used in this example requires a \"Stocks Advanced\" subscription" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a180a2b8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "········\n" + ] + } + ], + "source": [ + "import getpass\n", + "import os\n", + "\n", + "os.environ[\"POLYGON_API_KEY\"] = getpass.getpass()" + ] + }, + { + "cell_type": "markdown", + "id": "ed6f89fa", + "metadata": {}, + "source": [ + "It's also helpful (but not needed) to set up [LangSmith](https://smith.langchain.com/) for best-in-class observability" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56670cf6", + "metadata": {}, + "outputs": [], + "source": [ + "# os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n", + "# os.environ[\"LANGCHAIN_API_KEY\"] = getpass.getpass()" + ] + }, + { + "cell_type": "markdown", + "id": "7d93e6bd-03d7-4d3c-b915-8b73164e2ad8", + "metadata": {}, + "source": [ + "### Initializing the agent" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "648a2cb2-308e-4b2e-9b73-37109be4e258", + "metadata": { + "is_executing": true + }, + "outputs": [], + "source": [ + "from langchain import hub\n", + "from langchain.agents import AgentExecutor, create_openai_functions_agent\n", + "from langchain_community.agent_toolkits.polygon.toolkit import PolygonToolkit\n", + "from langchain_community.utilities.polygon import PolygonAPIWrapper\n", + "from langchain_openai import ChatOpenAI\n", + "\n", + "llm = ChatOpenAI(temperature=0)\n", + "\n", + "instructions = \"\"\"You are an assistant.\"\"\"\n", + "base_prompt = hub.pull(\"langchain-ai/openai-functions-template\")\n", + "prompt = base_prompt.partial(instructions=instructions)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "18650040-0ff8-4c0f-a4f2-be6aad7fe63e", + "metadata": {}, + "outputs": [], + "source": [ + "polygon = PolygonAPIWrapper()\n", + "toolkit = PolygonToolkit.from_polygon_api_wrapper(polygon)\n", + "agent = create_openai_functions_agent(llm, toolkit.get_tools(), prompt)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "fd7463e4-8716-4d1d-860a-770533eaa742", + "metadata": {}, + "outputs": [], + "source": [ + "agent_executor = AgentExecutor(\n", + " agent=agent,\n", + " tools=toolkit.get_tools(),\n", + " verbose=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "71f05fc9-d80d-4614-b9a3-e0a5e43cbbbb", + "metadata": {}, + "source": [ + "### Get the last price quote for a stock" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b97409f3-dc87-425d-b555-406cf8466a28", + "metadata": {}, + "outputs": [], + "source": [ + "agent_executor.invoke({\"input\": \"What is the latest stock price for AAPL?\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e666ee1", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/integrations/tools/polygon.ipynb b/docs/docs/integrations/tools/polygon.ipynb index 7f7be71168..62b078d0d8 100644 --- a/docs/docs/integrations/tools/polygon.ipynb +++ b/docs/docs/integrations/tools/polygon.ipynb @@ -40,6 +40,7 @@ }, "outputs": [], "source": [ + "from langchain_community.tools.polygon.last_quote import PolygonLastQuote\n", "from langchain_community.utilities.polygon import PolygonAPIWrapper" ] }, @@ -52,7 +53,7 @@ }, "outputs": [], "source": [ - "polygon = PolygonAPIWrapper()" + "tool = PolygonLastQuote(api_wrapper=PolygonAPIWrapper())" ] }, { @@ -63,20 +64,20 @@ "id": "068991a6", "outputId": "c5cdc6ec-03cf-4084-cc6f-6ae792d91d39" }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'results': {'P': 185.86, 'S': 1, 'T': 'AAPL', 'X': 11, 'i': [604], 'p': 185.81, 'q': 106551669, 's': 2, 't': 1705098436014023700, 'x': 12, 'y': 1705098436014009300, 'z': 3}}" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [ + { + "data": { + "text/plain": [ + "{'results': {'P': 185.86, 'S': 1, 'T': 'AAPL', 'X': 11, 'i': [604], 'p': 185.81, 'q': 106551669, 's': 2, 't': 1705098436014023700, 'x': 12, 'y': 1705098436014009300, 'z': 3}}" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "polygon.run(\"get_last_quote\", \"AAPL\")" + "tool.run(\"AAPL\")" ] } ], diff --git a/libs/community/langchain_community/agent_toolkits/__init__.py b/libs/community/langchain_community/agent_toolkits/__init__.py index b39e2751f7..9b5279ee85 100644 --- a/libs/community/langchain_community/agent_toolkits/__init__.py +++ b/libs/community/langchain_community/agent_toolkits/__init__.py @@ -34,6 +34,7 @@ from langchain_community.agent_toolkits.openapi.toolkit import OpenAPIToolkit from langchain_community.agent_toolkits.playwright.toolkit import ( PlayWrightBrowserToolkit, ) +from langchain_community.agent_toolkits.polygon.toolkit import PolygonToolkit from langchain_community.agent_toolkits.powerbi.base import create_pbi_agent from langchain_community.agent_toolkits.powerbi.chat_base import create_pbi_chat_agent from langchain_community.agent_toolkits.powerbi.toolkit import PowerBIToolkit @@ -59,6 +60,7 @@ __all__ = [ "O365Toolkit", "OpenAPIToolkit", "PlayWrightBrowserToolkit", + "PolygonToolkit", "PowerBIToolkit", "SlackToolkit", "SteamToolkit", diff --git a/libs/community/langchain_community/agent_toolkits/polygon/__init__.py b/libs/community/langchain_community/agent_toolkits/polygon/__init__.py new file mode 100644 index 0000000000..b9a3bf13b7 --- /dev/null +++ b/libs/community/langchain_community/agent_toolkits/polygon/__init__.py @@ -0,0 +1 @@ +"""Polygon Toolkit""" diff --git a/libs/community/langchain_community/agent_toolkits/polygon/toolkit.py b/libs/community/langchain_community/agent_toolkits/polygon/toolkit.py new file mode 100644 index 0000000000..748c84c1ee --- /dev/null +++ b/libs/community/langchain_community/agent_toolkits/polygon/toolkit.py @@ -0,0 +1,27 @@ +from typing import List + +from langchain_community.agent_toolkits.base import BaseToolkit +from langchain_community.tools import BaseTool +from langchain_community.tools.polygon import PolygonLastQuote +from langchain_community.utilities.polygon import PolygonAPIWrapper + + +class PolygonToolkit(BaseToolkit): + """Polygon Toolkit.""" + + tools: List[BaseTool] = [] + + @classmethod + def from_polygon_api_wrapper( + cls, polygon_api_wrapper: PolygonAPIWrapper + ) -> "PolygonToolkit": + tools = [ + PolygonLastQuote( + api_wrapper=polygon_api_wrapper, + ) + ] + return cls(tools=tools) + + def get_tools(self) -> List[BaseTool]: + """Get the tools in the toolkit.""" + return self.tools diff --git a/libs/community/langchain_community/tools/__init__.py b/libs/community/langchain_community/tools/__init__.py index 8bce838f88..b00e023871 100644 --- a/libs/community/langchain_community/tools/__init__.py +++ b/libs/community/langchain_community/tools/__init__.py @@ -472,6 +472,12 @@ def _import_plugin() -> Any: return AIPluginTool +def _import_polygon_tool_PolygonLastQuote() -> Any: + from langchain_community.tools.polygon.last_quote import PolygonLastQuote + + return PolygonLastQuote + + def _import_powerbi_tool_InfoPowerBITool() -> Any: from langchain_community.tools.powerbi.tool import InfoPowerBITool @@ -907,6 +913,8 @@ def __getattr__(name: str) -> Any: return _import_playwright_NavigateTool() elif name == "AIPluginTool": return _import_plugin() + elif name == "PolygonLastQuote": + return _import_polygon_tool_PolygonLastQuote() elif name == "InfoPowerBITool": return _import_powerbi_tool_InfoPowerBITool() elif name == "ListPowerBITool": @@ -1085,6 +1093,7 @@ __all__ = [ "OpenAPISpec", "OpenWeatherMapQueryRun", "PubmedQueryRun", + "PolygonLastQuote", "RedditSearchRun", "QueryCheckerTool", "QueryPowerBITool", diff --git a/libs/community/langchain_community/tools/polygon/__init__.py b/libs/community/langchain_community/tools/polygon/__init__.py new file mode 100644 index 0000000000..acc8bc4ac7 --- /dev/null +++ b/libs/community/langchain_community/tools/polygon/__init__.py @@ -0,0 +1,7 @@ +"""Polygon IO tools.""" + +from langchain_community.tools.polygon.last_quote import PolygonLastQuote + +__all__ = [ + "PolygonLastQuote", +] diff --git a/libs/community/langchain_community/tools/polygon/last_quote.py b/libs/community/langchain_community/tools/polygon/last_quote.py new file mode 100644 index 0000000000..55fe3d9301 --- /dev/null +++ b/libs/community/langchain_community/tools/polygon/last_quote.py @@ -0,0 +1,34 @@ +from typing import Optional, Type + +from langchain_core.callbacks import CallbackManagerForToolRun +from langchain_core.pydantic_v1 import BaseModel +from langchain_core.tools import BaseTool + +from langchain_community.utilities.polygon import PolygonAPIWrapper + + +class Inputs(BaseModel): + query: str + + +class PolygonLastQuote(BaseTool): + """Tool that gets the last quote of a ticker from Polygon""" + + mode: str = "get_last_quote" + name: str = "polygon_last_quote" + description: str = ( + "A wrapper around Polygon's Last Quote API. " + "This tool is useful for fetching the latest price of a stock. " + "Input should be the ticker that you want to query the last price quote for." + ) + args_schema: Type[BaseModel] = Inputs + + api_wrapper: PolygonAPIWrapper + + def _run( + self, + query: str, + run_manager: Optional[CallbackManagerForToolRun] = None, + ) -> str: + """Use the Polygon API tool.""" + return self.api_wrapper.run(self.mode, ticker=query) diff --git a/libs/community/tests/unit_tests/agent_toolkits/test_imports.py b/libs/community/tests/unit_tests/agent_toolkits/test_imports.py index c6557b7391..416b66849b 100644 --- a/libs/community/tests/unit_tests/agent_toolkits/test_imports.py +++ b/libs/community/tests/unit_tests/agent_toolkits/test_imports.py @@ -14,6 +14,7 @@ EXPECTED_ALL = [ "O365Toolkit", "OpenAPIToolkit", "PlayWrightBrowserToolkit", + "PolygonToolkit", "PowerBIToolkit", "SlackToolkit", "SteamToolkit", diff --git a/libs/community/tests/unit_tests/tools/test_imports.py b/libs/community/tests/unit_tests/tools/test_imports.py index 424540de09..9fdcf157e9 100644 --- a/libs/community/tests/unit_tests/tools/test_imports.py +++ b/libs/community/tests/unit_tests/tools/test_imports.py @@ -79,6 +79,7 @@ EXPECTED_ALL = [ "OpenAPISpec", "OpenWeatherMapQueryRun", "PubmedQueryRun", + "PolygonLastQuote", "RedditSearchRun", "QueryCheckerTool", "QueryPowerBITool", diff --git a/libs/community/tests/unit_tests/tools/test_public_api.py b/libs/community/tests/unit_tests/tools/test_public_api.py index 624262f3d1..0f6102c45e 100644 --- a/libs/community/tests/unit_tests/tools/test_public_api.py +++ b/libs/community/tests/unit_tests/tools/test_public_api.py @@ -81,6 +81,7 @@ _EXPECTED = [ "OpenAPISpec", "OpenWeatherMapQueryRun", "PubmedQueryRun", + "PolygonLastQuote", "RedditSearchRun", "QueryCheckerTool", "QueryPowerBITool",