From d8bc271a218649923c1903c9447dce8bb6ef5c65 Mon Sep 17 00:00:00 2001
From: leehuwuj <leehuwuj@gmail.com>
Date: Thu, 30 May 2024 09:11:21 +0700
Subject: [PATCH] add local tool that combine openapi and request tool

---
 helpers/tools.ts                              | 32 +++-------
 .../python/agent/tools/openapi_action.py      | 59 +++++++++++++++++++
 2 files changed, 68 insertions(+), 23 deletions(-)
 create mode 100644 templates/components/engines/python/agent/tools/openapi_action.py

diff --git a/helpers/tools.ts b/helpers/tools.ts
index 2f7bb75d..70ee8772 100644
--- a/helpers/tools.ts
+++ b/helpers/tools.ts
@@ -118,8 +118,8 @@ export const supportedTools: Tool[] = [
     ],
   },
   {
-    display: "OpenAPI",
-    name: "openapi.OpenAPIToolSpec",
+    display: "OpenAPI action",
+    name: "openapi_action.OpenAPIActionToolSpec",
     dependencies: [
       {
         name: "llama-index-tools-openapi",
@@ -129,35 +129,21 @@ export const supportedTools: Tool[] = [
         name: "jsonschema",
         version: "^4.22.0",
       },
-    ],
-    config: {
-      url: "The URL of the OpenAPI schema",
-    },
-    supportedFrameworks: ["fastapi"],
-    type: ToolType.LLAMAHUB,
-    envVars: [
       {
-        name: TOOL_SYSTEM_PROMPT_ENV_VAR,
-        description: "System prompt for openapi tool.",
-        value: `You can use the provided OpenAPI schema to see the available endpoints to make requests with the HTTP Request tool.`,
+        name: "llama-index-tools-requests",
+        version: "0.1.3",
       },
     ],
-  },
-  {
-    display: "HTTP Request",
-    name: "requests.RequestsToolSpec",
-    dependencies: [],
-    supportedFrameworks: ["fastapi"],
-    type: ToolType.LLAMAHUB,
     config: {
-      domain_headers:
-        "A mapping of domain to its headers. Example: example.com: {}",
+      openapi_uri: "The URL or file path of the OpenAPI schema",
     },
+    supportedFrameworks: ["fastapi"],
+    type: ToolType.LOCAL,
     envVars: [
       {
         name: TOOL_SYSTEM_PROMPT_ENV_VAR,
-        description: "System prompt for openapi tool.",
-        value: `You can make HTTP requests to the provided domain.`,
+        description: "System prompt for openapi action tool.",
+        value: `You are an OpenAPI action agent. You help users to make requests to the provided OpenAPI schema.`,
       },
     ],
   },
diff --git a/templates/components/engines/python/agent/tools/openapi_action.py b/templates/components/engines/python/agent/tools/openapi_action.py
new file mode 100644
index 00000000..d47fa665
--- /dev/null
+++ b/templates/components/engines/python/agent/tools/openapi_action.py
@@ -0,0 +1,59 @@
+import inspect
+from typing import Dict, List, Tuple
+from llama_index.tools.openapi import OpenAPIToolSpec
+from llama_index.tools.requests import RequestsToolSpec
+
+
+class OpenAPIActionToolSpec(OpenAPIToolSpec, RequestsToolSpec):
+    """
+    A combination of OpenAPI and Requests tool specs that can parse OpenAPI specs and make requests.
+
+    openapi_uri: str: The file path or URL to the OpenAPI spec.
+    domain_headers: dict: Whitelist domains and the headers to use.
+    """
+
+    spec_functions = OpenAPIToolSpec.spec_functions + RequestsToolSpec.spec_functions
+
+    def __init__(self, openapi_uri: str, domain_headers: dict = {}, **kwargs):
+        # Load the OpenAPI spec
+        openapi_spec, servers = self.load_openapi_spec(openapi_uri)
+
+        # Add the servers to the domain headers if they are not already present
+        for server in servers:
+            if server not in domain_headers:
+                domain_headers[server] = {}
+
+        OpenAPIToolSpec.__init__(self, spec=openapi_spec)
+        RequestsToolSpec.__init__(self, domain_headers)
+
+    @staticmethod
+    def load_openapi_spec(uri: str) -> Tuple[Dict, List[str]]:
+        """
+        Load an OpenAPI spec from a URI.
+
+        Args:
+            uri (str): A file path or URL to the OpenAPI spec.
+
+        Returns:
+            List[Document]: A list of Document objects.
+        """
+        import yaml
+        from urllib.parse import urlparse
+
+        if uri.startswith("http"):
+            import requests
+
+            response = requests.get(uri).text
+            spec = yaml.safe_load(response)
+        elif uri.startswith("file"):
+            filepath = uri[7:]  # Remove the 'file://' scheme
+            with open(filepath, "r") as file:
+                spec = yaml.safe_load(file)
+        else:
+            raise ValueError(
+                "Could not initialize OpenAPIActionToolSpec because invalid OpenAPI URI provided. "
+                "Only HTTP and file path are supported."
+            )
+        # Add the servers to the whitelist
+        servers = [urlparse(server["url"]).netloc for server in spec.get("servers", [])]
+        return spec, servers
-- 
GitLab