فهرست منبع

feat(Tools): Refactor the base table plugin (#9182)

Co-authored-by: 黎斌 <libin.23@bytedance.com>
走在修行的大街上 6 ماه پیش
والد
کامیت
a9db06f5e7
43فایلهای تغییر یافته به همراه1230 افزوده شده و 1282 حذف شده
  1. BIN
      api/core/tools/provider/builtin/feishu_base/_assets/icon.png
  2. 0 47
      api/core/tools/provider/builtin/feishu_base/_assets/icon.svg
  3. 2 3
      api/core/tools/provider/builtin/feishu_base/feishu_base.py
  4. 25 3
      api/core/tools/provider/builtin/feishu_base/feishu_base.yaml
  5. 0 56
      api/core/tools/provider/builtin/feishu_base/tools/add_base_record.py
  6. 0 66
      api/core/tools/provider/builtin/feishu_base/tools/add_base_record.yaml
  7. 21 0
      api/core/tools/provider/builtin/feishu_base/tools/add_records.py
  8. 91 0
      api/core/tools/provider/builtin/feishu_base/tools/add_records.yaml
  9. 10 33
      api/core/tools/provider/builtin/feishu_base/tools/create_base.py
  10. 17 22
      api/core/tools/provider/builtin/feishu_base/tools/create_base.yaml
  11. 0 48
      api/core/tools/provider/builtin/feishu_base/tools/create_base_table.py
  12. 0 106
      api/core/tools/provider/builtin/feishu_base/tools/create_base_table.yaml
  13. 20 0
      api/core/tools/provider/builtin/feishu_base/tools/create_table.py
  14. 61 0
      api/core/tools/provider/builtin/feishu_base/tools/create_table.yaml
  15. 0 56
      api/core/tools/provider/builtin/feishu_base/tools/delete_base_records.py
  16. 0 60
      api/core/tools/provider/builtin/feishu_base/tools/delete_base_records.yaml
  17. 0 46
      api/core/tools/provider/builtin/feishu_base/tools/delete_base_tables.py
  18. 0 48
      api/core/tools/provider/builtin/feishu_base/tools/delete_base_tables.yaml
  19. 20 0
      api/core/tools/provider/builtin/feishu_base/tools/delete_records.py
  20. 86 0
      api/core/tools/provider/builtin/feishu_base/tools/delete_records.yaml
  21. 19 0
      api/core/tools/provider/builtin/feishu_base/tools/delete_tables.py
  22. 49 0
      api/core/tools/provider/builtin/feishu_base/tools/delete_tables.yaml
  23. 9 31
      api/core/tools/provider/builtin/feishu_base/tools/get_base_info.py
  24. 7 38
      api/core/tools/provider/builtin/feishu_base/tools/get_base_info.yaml
  25. 0 48
      api/core/tools/provider/builtin/feishu_base/tools/get_tenant_access_token.py
  26. 0 39
      api/core/tools/provider/builtin/feishu_base/tools/get_tenant_access_token.yaml
  27. 0 65
      api/core/tools/provider/builtin/feishu_base/tools/list_base_records.py
  28. 0 108
      api/core/tools/provider/builtin/feishu_base/tools/list_base_records.yaml
  29. 0 47
      api/core/tools/provider/builtin/feishu_base/tools/list_base_tables.py
  30. 0 65
      api/core/tools/provider/builtin/feishu_base/tools/list_base_tables.yaml
  31. 19 0
      api/core/tools/provider/builtin/feishu_base/tools/list_tables.py
  32. 50 0
      api/core/tools/provider/builtin/feishu_base/tools/list_tables.yaml
  33. 0 49
      api/core/tools/provider/builtin/feishu_base/tools/read_base_record.py
  34. 0 60
      api/core/tools/provider/builtin/feishu_base/tools/read_base_record.yaml
  35. 21 0
      api/core/tools/provider/builtin/feishu_base/tools/read_records.py
  36. 86 0
      api/core/tools/provider/builtin/feishu_base/tools/read_records.yaml
  37. 39 0
      api/core/tools/provider/builtin/feishu_base/tools/search_records.py
  38. 163 0
      api/core/tools/provider/builtin/feishu_base/tools/search_records.yaml
  39. 0 60
      api/core/tools/provider/builtin/feishu_base/tools/update_base_record.py
  40. 0 78
      api/core/tools/provider/builtin/feishu_base/tools/update_base_record.yaml
  41. 21 0
      api/core/tools/provider/builtin/feishu_base/tools/update_records.py
  42. 91 0
      api/core/tools/provider/builtin/feishu_base/tools/update_records.yaml
  43. 303 0
      api/core/tools/utils/feishu_api_utils.py

BIN
api/core/tools/provider/builtin/feishu_base/_assets/icon.png


+ 0 - 47
api/core/tools/provider/builtin/feishu_base/_assets/icon.svg

@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="240px" height="240px" viewBox="0 0 240 240" enable-background="new 0 0 240 240" xml:space="preserve">  <image id="image0" width="240" height="240" x="0" y="0"
-    xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAADwCAMAAAAJixmgAAAAIGNIUk0AAHomAACAhAAA+gAAAIDo
-AAB1MAAA6mAAADqYAAAXcJy6UTwAAAINUExURQAAAJ9g6qNg6qRd6KNe6aVg6J9g6p9g359a6qRd
-66Ne66Re66Rd66Rd66Re7Z9g559g76Ne7aRe6qJd76Fe66Ne66Re66Vd7KNc6aRe66Nd66Re7KRd
-66Nc6p9g36Re7KRf7KRe7KNe7KNc76Va6qVd66Ne66Re66Nd6qRb6KRe66Zd66Ve7KJd6aNe66Fe
-7KRd6p9Y56Re66Je6qRb6qNe66Re7KNc56Jf6qNe6qRe6qFe6KNe6qRf66Rf66Ne7KNe6qRe6qRd
-66Rd7KFe6aNc6qNe6qJd7Z9b6KNd659Z7KNd66Ne6aRe66Re7KNc66Nd66Ne66Jd6qNe6qNc6aJd
-6qNd6qRe66Jd7KFe6qJe66Re6qNe66Jd66Jd6aRd6qRd66Va759V6qVd6qFe56Ne6KJd6KRe66Zj
-67eB79Gu9eLM+OjX+uXS+dSz9bJ37s6p9LV87q9y7de49vn1/f///9q99qlo7NGu9Kxt7d/H+Pz5
-/vz6/qdj68CQ8e7h+/Pq/Maa8rqG8NzC9/Pr/Myk8+DH+OXR+cyk9Pn1/ujW+u3g+7iB7+vc+r2L
-8N3C9//+//bw/cmf87uG8OPM+ebR+axt7Muk8/Dm/Mif8/n0/c+p9MOV8fHm++7g+/n0/vbv/bqG
-78CQ8Kxu7cCR8ePM+LqH8MCP8bV87+LM+bqF8Muk9OLL+NSy9bqF75VHsr4AAABndFJOUwAYSHCA
-WDAQMJfn57+PVyAQb98/gO/mllDPr1/ebwiHn+6eLzCvf/63OL4/xkfOT58g9odfZ65Aj3fHT2+X
-j3f3z7efgEjPRzi3KKd/7sZAv+6fri+P3rY3X77G5j9oxn4fGGCAbzcMFjqxAAAAAWJLR0R1qGqY
-+wAAAAd0SU1FB+gGDQkfBmABjhYAAAXYSURBVHja7d35WxtFGAfwbUGDtRWKilAwFg+2VHtwqa31
-qlfV1qta7/vYkDQhJFnTliQWhFYoDaVY8ECw3vffaHgefZ5CZvbZIbMz83a/35/ngfkwx+5m3iyW
-hSAIgiAIgiAIgiAIgiAIQjAbNtbVa0vdNRuvjSjlNly3ydGd6zdvuaFRDbdpa7Nu7f9p3nJjU/De
-m27W7bwyLbcEbW5t021cm7atQc7thm26fYw01wdHbjdmAa9Kx61NwXijt+mm8dLWHgi5cbtuGDed
-t98RAPjOu3S7PBLEIBsNdjq7pIvNBjv2ju5wgR17593hAjvOPbtCBnZ27wkZWK6YAljqOqYAlrpX
-kwA79t6ecIGd3r6mcIGdjv6QgaUtYypgaZOaDFjWpKYDlrRT0wE7LQMhA9v3yvgEhBBYziqmBJay
-iimBpQwxKbDdFw0X2Nl8X8jAEuY0LbB9f80H58TAtT9C0AJLmNPEwL37QgaufRFTA29rCBfY2V/r
-OQQ18O4HQgau+aGYGrjzQMjAdhfAVzm41idEcuBa7zwANjwAAwwwwKQCcIDg2GA8cXx1kqnBGK/5
-UHpta16SqWETwZlszq1O7tMhZuv8CVZrXnKpk8aBh05xOptgDY+Y13VHsj7FysB8QSFerG5e+kzI
-67qnRw0DDye4fT0+Vv3nyQp6XffzjFng0XH+Apyoaj10Rhh8dtAs8BeT3K4W0lWtx6aEwedKlMHT
-Z4XB58tmgUvnuF0dr95vMjPC4IS/a7EysAeB1dV0QdB7IZs3C8zftWYvMloLz2nGVq8ZXJyYZfZ0
-Ms4cmjmxbcvvZVjpvfTcl9UbV+FSmXMzPTwz6ZtbuDTntxNqn5bmp+dWZ3reo3VmzmemMzHfXcDj
-IcAAA0wqAAMMMMCkAjDAAANMKgADDDDApAIwwBLB+XI6vjrp0kmB1rx4/RSN4PwC67BlfCHPbB0r
-nRc4ePjq67zPXqgD82oeCuzqjIuzAl7X/eaET7E68ASvxiP3LaPGQ/BoiXyNRzEl6DXvuNSjxoNx
-IB66Go91lDyErsbDNPDidyGb0h5jxqjxKMbp13hw5/RkmnGcLXxZWvI3o1XeeMSXmT0dSbGGpjjx
-vZB3mV0pohPs5EeXLlTPxNOcW8viIqM1N7wbVK3gCvnywtrb/h/4RR4CDw+L/gpLlYNNCMAAAwww
-qQAMMMAAkwrAAAMMMKkADDDAAJMKwIGCfxwcW5OMUGte/H9KqxIcKyerD4xyyZ+K7ObTP/s/Xiok
-fzEPnE+zqzZy7OqMskhNC+dLyHrB3BKAcVZ1hkeFBDvGfWHaQ8D6SvyE2ItaXHckXvTVD0MPxNfx
-0gPTDsQ96q6uztdaeNR4uPGq1ut5ccmvZoE9ypYYO+xvvwuDp/4wC+xRw8CoVlhHYZppLx/il6kU
-WDUPpSVB8PKf/vqh7jrM3XjZLxDjVITwwq4U0Qp2MlmWYWSG84o4IfFyat5nL5Q+PAynT02tTiJ1
-Oea/NS9//f2P7xd54PEQYIABJhWAAQYYYFIBWDSN23UTFIM3PKiboBgceUg3QTHYevgR3QbF4IFN
-ug2Kwa2P6jYoBncf1G1QDO55TLdBMTj6OKldS8I/5G1v1o1QDKa1iCWAad16SADTmtMywKTmtAww
-qX1aBth6Yr9uhmIwpW1LCtja86Ruh2IwoSGWA7aeIrOKJYGjXb26JWrB1qGndUsUg63+Dt0UxeBI
-H41JLQ1sPfOsbotiMJGdWiKYxjKWCY4eaNHNUQu2IoeP6PaoBVMQywUTEEsGW5F9hq9j2eDK1ek5
-WzdKLdg6tMNkcQBgsxey3ReVDras51+wdcO44K4AvCuD/KKh5I7+QMCW1fCSkWT76MsBgQ0lHzks
-f8+6gvzKMcPI9quvBeitJPL6GyYNs/3mrmC9K+kZOPqWbQba3vl28N6VRBve2ftuRW1rhFd+97H3
-3lfj/S8fdLd+WFevKx99/EkQdxwIgiAIgiAIgiAIgiAIgiBB519+T+5Fl+ldNwAAACV0RVh0ZGF0
-ZTpjcmVhdGUAMjAyNC0wNi0xM1QwOTozMTowNiswMDowMPHqs70AAAAldEVYdGRhdGU6bW9kaWZ5
-ADIwMjQtMDYtMTNUMDk6MzE6MDYrMDA6MDCAtwsBAAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDI0
-LTA2LTEzVDA5OjMxOjA2KzAwOjAw16Iq3gAAAABJRU5ErkJggg==" />
-</svg>

+ 2 - 3
api/core/tools/provider/builtin/feishu_base/feishu_base.py

@@ -1,8 +1,7 @@
-from core.tools.provider.builtin.feishu_base.tools.get_tenant_access_token import GetTenantAccessTokenTool
 from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
+from core.tools.utils.feishu_api_utils import auth
 
 
 class FeishuBaseProvider(BuiltinToolProviderController):
     def _validate_credentials(self, credentials: dict) -> None:
-        GetTenantAccessTokenTool()
-        pass
+        auth(credentials)

+ 25 - 3
api/core/tools/provider/builtin/feishu_base/feishu_base.yaml

@@ -5,10 +5,32 @@ identity:
     en_US: Feishu Base
     zh_Hans: 飞书多维表格
   description:
-    en_US: Feishu Base
-    zh_Hans: 飞书多维表格
-  icon: icon.svg
+    en_US: |
+      Feishu base, requires the following permissions: bitable:app.
+    zh_Hans: |
+      飞书多维表格,需要开通以下权限: bitable:app。
+  icon: icon.png
   tags:
     - social
     - productivity
 credentials_for_provider:
+  app_id:
+    type: text-input
+    required: true
+    label:
+      en_US: APP ID
+    placeholder:
+      en_US: Please input your feishu app id
+      zh_Hans: 请输入你的飞书 app id
+    help:
+      en_US: Get your app_id and app_secret from Feishu
+      zh_Hans: 从飞书获取您的 app_id 和 app_secret
+    url: https://open.larkoffice.com/app
+  app_secret:
+    type: secret-input
+    required: true
+    label:
+      en_US: APP Secret
+    placeholder:
+      en_US: Please input your app secret
+      zh_Hans: 请输入你的飞书 app secret

+ 0 - 56
api/core/tools/provider/builtin/feishu_base/tools/add_base_record.py

@@ -1,56 +0,0 @@
-import json
-from typing import Any, Union
-
-import httpx
-
-from core.tools.entities.tool_entities import ToolInvokeMessage
-from core.tools.tool.builtin_tool import BuiltinTool
-
-
-class AddBaseRecordTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        app_token = tool_parameters.get("app_token", "")
-        if not app_token:
-            return self.create_text_message("Invalid parameter app_token")
-
-        table_id = tool_parameters.get("table_id", "")
-        if not table_id:
-            return self.create_text_message("Invalid parameter table_id")
-
-        fields = tool_parameters.get("fields", "")
-        if not fields:
-            return self.create_text_message("Invalid parameter fields")
-
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
-
-        params = {}
-        payload = {"fields": json.loads(fields)}
-
-        try:
-            res = httpx.post(
-                url.format(app_token=app_token, table_id=table_id),
-                headers=headers,
-                params=params,
-                json=payload,
-                timeout=30,
-            )
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to add base record, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to add base record. {}".format(e))

+ 0 - 66
api/core/tools/provider/builtin/feishu_base/tools/add_base_record.yaml

@@ -1,66 +0,0 @@
-identity:
-  name: add_base_record
-  author: Doug Lea
-  label:
-    en_US: Add Base Record
-    zh_Hans: 在多维表格数据表中新增一条记录
-description:
-  human:
-    en_US: Add Base Record
-    zh_Hans: |
-      在多维表格数据表中新增一条记录,详细请参考:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/app-table-record/create
-  llm: Add a new record in the multidimensional table data table.
-parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
-  - name: app_token
-    type: string
-    required: true
-    label:
-      en_US: app_token
-      zh_Hans: 多维表格
-    human_description:
-      en_US: bitable app token
-      zh_Hans: 多维表格的唯一标识符 app_token
-    llm_description: bitable app token
-    form: llm
-
-  - name: table_id
-    type: string
-    required: true
-    label:
-      en_US: table_id
-      zh_Hans: 多维表格的数据表
-    human_description:
-      en_US: bitable table id
-      zh_Hans: 多维表格数据表的唯一标识符 table_id
-    llm_description: bitable table id
-    form: llm
-
-  - name: fields
-    type: string
-    required: true
-    label:
-      en_US: fields
-      zh_Hans: 数据表的列字段内容
-    human_description:
-      en_US: The fields of the Base data table are the columns of the data table.
-      zh_Hans: |
-        要增加一行多维表格记录,字段结构拼接如下:{"多行文本":"多行文本内容","单选":"选项1","多选":["选项1","选项2"],"复选框":true,"人员":[{"id":"ou_2910013f1e6456f16a0ce75ede950a0a"}],"群组":[{"id":"oc_cd07f55f14d6f4a4f1b51504e7e97f48"}],"电话号码":"13026162666"}
-        当前接口支持的字段类型为:多行文本、单选、条码、多选、日期、人员、附件、复选框、超链接、数字、单向关联、双向关联、电话号码、地理位置。
-        不同类型字段的数据结构请参考数据结构概述:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure
-    llm_description: |
-      要增加一行多维表格记录,字段结构拼接如下:{"多行文本":"多行文本内容","单选":"选项1","多选":["选项1","选项2"],"复选框":true,"人员":[{"id":"ou_2910013f1e6456f16a0ce75ede950a0a"}],"群组":[{"id":"oc_cd07f55f14d6f4a4f1b51504e7e97f48"}],"电话号码":"13026162666"}
-      当前接口支持的字段类型为:多行文本、单选、条码、多选、日期、人员、附件、复选框、超链接、数字、单向关联、双向关联、电话号码、地理位置。
-      不同类型字段的数据结构请参考数据结构概述:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure
-    form: llm

+ 21 - 0
api/core/tools/provider/builtin/feishu_base/tools/add_records.py

@@ -0,0 +1,21 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
+
+
+class AddRecordsTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
+
+        app_token = tool_parameters.get("app_token")
+        table_id = tool_parameters.get("table_id")
+        table_name = tool_parameters.get("table_name")
+        records = tool_parameters.get("records")
+        user_id_type = tool_parameters.get("user_id_type", "open_id")
+
+        res = client.add_records(app_token, table_id, table_name, records, user_id_type)
+        return self.create_json_message(res)

+ 91 - 0
api/core/tools/provider/builtin/feishu_base/tools/add_records.yaml

@@ -0,0 +1,91 @@
+identity:
+  name: add_records
+  author: Doug Lea
+  label:
+    en_US: Add Records
+    zh_Hans: 新增多条记录
+description:
+  human:
+    en_US: Add Multiple Records to Multidimensional Table
+    zh_Hans: 在多维表格数据表中新增多条记录
+  llm: A tool for adding multiple records to a multidimensional table. (在多维表格数据表中新增多条记录)
+parameters:
+  - name: app_token
+    type: string
+    required: true
+    label:
+      en_US: app_token
+      zh_Hans: app_token
+    human_description:
+      en_US: Unique identifier for the multidimensional table, supports inputting document URL.
+      zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
+    llm_description: 多维表格的唯一标识符,支持输入文档 URL。
+    form: llm
+
+  - name: table_id
+    type: string
+    required: false
+    label:
+      en_US: table_id
+      zh_Hans: table_id
+    human_description:
+      en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: table_name
+    type: string
+    required: false
+    label:
+      en_US: table_name
+      zh_Hans: table_name
+    human_description:
+      en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: records
+    type: string
+    required: true
+    label:
+      en_US: records
+      zh_Hans: 记录列表
+    human_description:
+      en_US: |
+        List of records to be added in this request. Example value: [{"multi-line-text":"text content","single_select":"option 1","date":1674206443000}]
+        For supported field types, refer to the integration guide (https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification). For data structures of different field types, refer to the data structure overview (https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure).
+      zh_Hans: |
+        本次请求将要新增的记录列表,示例值:[{"多行文本":"文本内容","单选":"选项 1","日期":1674206443000}]。
+        当前接口支持的字段类型请参考接入指南(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification),不同类型字段的数据结构请参考数据结构概述(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure)。
+    llm_description: |
+      本次请求将要新增的记录列表,示例值:[{"多行文本":"文本内容","单选":"选项 1","日期":1674206443000}]。
+      当前接口支持的字段类型请参考接入指南(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification),不同类型字段的数据结构请参考数据结构概述(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure)。
+    form: llm
+
+  - name: user_id_type
+    type: select
+    required: false
+    options:
+      - value: open_id
+        label:
+          en_US: open_id
+          zh_Hans: open_id
+      - value: union_id
+        label:
+          en_US: union_id
+          zh_Hans: union_id
+      - value: user_id
+        label:
+          en_US: user_id
+          zh_Hans: user_id
+    default: "open_id"
+    label:
+      en_US: user_id_type
+      zh_Hans: 用户 ID 类型
+    human_description:
+      en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
+      zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    form: form

+ 10 - 33
api/core/tools/provider/builtin/feishu_base/tools/create_base.py

@@ -1,41 +1,18 @@
-import json
-from typing import Any, Union
-
-import httpx
+from typing import Any
 
 from core.tools.entities.tool_entities import ToolInvokeMessage
 from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
 
 
 class CreateBaseTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        name = tool_parameters.get("name", "")
-        folder_token = tool_parameters.get("folder_token", "")
-
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
 
-        params = {}
-        payload = {"name": name, "folder_token": folder_token}
+        name = tool_parameters.get("name")
+        folder_token = tool_parameters.get("folder_token")
 
-        try:
-            res = httpx.post(url, headers=headers, params=params, json=payload, timeout=30)
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to create base, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to create base. {}".format(e))
+        res = client.create_base(name, folder_token)
+        return self.create_json_message(res)

+ 17 - 22
api/core/tools/provider/builtin/feishu_base/tools/create_base.yaml

@@ -6,32 +6,21 @@ identity:
     zh_Hans: 创建多维表格
 description:
   human:
-    en_US: Create base
+    en_US: Create Multidimensional Table in Specified Directory
     zh_Hans: 在指定目录下创建多维表格
-  llm: A tool for create a multidimensional table in the specified directory.
+  llm: A tool for creating a multidimensional table in a specified directory. (在指定目录下创建多维表格)
 parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
   - name: name
     type: string
     required: false
     label:
       en_US: name
-      zh_Hans: name
+      zh_Hans: 多维表格 App 名字
     human_description:
-      en_US: Base App Name
-      zh_Hans: 多维表格App名字
-    llm_description: Base App Name
+      en_US: |
+        Name of the multidimensional table App. Example value: "A new multidimensional table".
+      zh_Hans: 多维表格 App 名字,示例值:"一篇新的多维表格"。
+    llm_description: 多维表格 App 名字,示例值:"一篇新的多维表格"。
     form: llm
 
   - name: folder_token
@@ -39,9 +28,15 @@ parameters:
     required: false
     label:
       en_US: folder_token
-      zh_Hans: 多维表格App归属文件夹
+      zh_Hans: 多维表格 App 归属文件夹
     human_description:
-      en_US: Base App home folder. The default is empty, indicating that Base will be created in the cloud space root directory.
-      zh_Hans: 多维表格App归属文件夹。默认为空,表示多维表格将被创建在云空间根目录。
-    llm_description: Base App home folder. The default is empty, indicating that Base will be created in the cloud space root directory.
+      en_US: |
+        Folder where the multidimensional table App belongs. Default is empty, meaning the table will be created in the root directory of the cloud space. Example values: Fa3sfoAgDlMZCcdcJy1cDFg8nJc or https://svi136aogf123.feishu.cn/drive/folder/Fa3sfoAgDlMZCcdcJy1cDFg8nJc.
+        The folder_token must be an existing folder and supports inputting folder token or folder URL.
+      zh_Hans: |
+        多维表格 App 归属文件夹。默认为空,表示多维表格将被创建在云空间根目录。示例值: Fa3sfoAgDlMZCcdcJy1cDFg8nJc 或者 https://svi136aogf123.feishu.cn/drive/folder/Fa3sfoAgDlMZCcdcJy1cDFg8nJc。
+        folder_token 必须是已存在的文件夹,支持输入文件夹 token 或者文件夹 URL。
+    llm_description: |
+      多维表格 App 归属文件夹。默认为空,表示多维表格将被创建在云空间根目录。示例值: Fa3sfoAgDlMZCcdcJy1cDFg8nJc 或者 https://svi136aogf123.feishu.cn/drive/folder/Fa3sfoAgDlMZCcdcJy1cDFg8nJc。
+      folder_token 必须是已存在的文件夹,支持输入文件夹 token 或者文件夹 URL。
     form: llm

+ 0 - 48
api/core/tools/provider/builtin/feishu_base/tools/create_base_table.py

@@ -1,48 +0,0 @@
-import json
-from typing import Any, Union
-
-import httpx
-
-from core.tools.entities.tool_entities import ToolInvokeMessage
-from core.tools.tool.builtin_tool import BuiltinTool
-
-
-class CreateBaseTableTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        app_token = tool_parameters.get("app_token", "")
-        if not app_token:
-            return self.create_text_message("Invalid parameter app_token")
-
-        name = tool_parameters.get("name", "")
-
-        fields = tool_parameters.get("fields", "")
-        if not fields:
-            return self.create_text_message("Invalid parameter fields")
-
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
-
-        params = {}
-        payload = {"table": {"name": name, "fields": json.loads(fields)}}
-
-        try:
-            res = httpx.post(url.format(app_token=app_token), headers=headers, params=params, json=payload, timeout=30)
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to create base table, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to create base table. {}".format(e))

+ 0 - 106
api/core/tools/provider/builtin/feishu_base/tools/create_base_table.yaml

@@ -1,106 +0,0 @@
-identity:
-  name: create_base_table
-  author: Doug Lea
-  label:
-    en_US: Create Base Table
-    zh_Hans: 多维表格新增一个数据表
-description:
-  human:
-    en_US: Create base table
-    zh_Hans: |
-      多维表格新增一个数据表,详细请参考:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/app-table/create
-  llm: A tool for add a new data table to the multidimensional table.
-parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
-  - name: app_token
-    type: string
-    required: true
-    label:
-      en_US: app_token
-      zh_Hans: 多维表格
-    human_description:
-      en_US: bitable app token
-      zh_Hans: 多维表格的唯一标识符 app_token
-    llm_description: bitable app token
-    form: llm
-
-  - name: name
-    type: string
-    required: false
-    label:
-      en_US: name
-      zh_Hans: name
-    human_description:
-      en_US: Multidimensional table data table name
-      zh_Hans: 多维表格数据表名称
-    llm_description: Multidimensional table data table name
-    form: llm
-
-  - name: fields
-    type: string
-    required: true
-    label:
-      en_US: fields
-      zh_Hans: fields
-    human_description:
-      en_US: Initial fields of the data table
-      zh_Hans: |
-        数据表的初始字段,格式为:[{"field_name":"多行文本","type":1},{"field_name":"数字","type":2},{"field_name":"单选","type":3},{"field_name":"多选","type":4},{"field_name":"日期","type":5}]。
-        field_name:字段名;
-        type: 字段类型;可选值有
-        1:多行文本
-        2:数字
-        3:单选
-        4:多选
-        5:日期
-        7:复选框
-        11:人员
-        13:电话号码
-        15:超链接
-        17:附件
-        18:单向关联
-        20:公式
-        21:双向关联
-        22:地理位置
-        23:群组
-        1001:创建时间
-        1002:最后更新时间
-        1003:创建人
-        1004:修改人
-        1005:自动编号
-    llm_description: |
-      数据表的初始字段,格式为:[{"field_name":"多行文本","type":1},{"field_name":"数字","type":2},{"field_name":"单选","type":3},{"field_name":"多选","type":4},{"field_name":"日期","type":5}]。
-      field_name:字段名;
-      type: 字段类型;可选值有
-      1:多行文本
-      2:数字
-      3:单选
-      4:多选
-      5:日期
-      7:复选框
-      11:人员
-      13:电话号码
-      15:超链接
-      17:附件
-      18:单向关联
-      20:公式
-      21:双向关联
-      22:地理位置
-      23:群组
-      1001:创建时间
-      1002:最后更新时间
-      1003:创建人
-      1004:修改人
-      1005:自动编号
-    form: llm

+ 20 - 0
api/core/tools/provider/builtin/feishu_base/tools/create_table.py

@@ -0,0 +1,20 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
+
+
+class CreateTableTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
+
+        app_token = tool_parameters.get("app_token")
+        table_name = tool_parameters.get("table_name")
+        default_view_name = tool_parameters.get("default_view_name")
+        fields = tool_parameters.get("fields")
+
+        res = client.create_table(app_token, table_name, default_view_name, fields)
+        return self.create_json_message(res)

+ 61 - 0
api/core/tools/provider/builtin/feishu_base/tools/create_table.yaml

@@ -0,0 +1,61 @@
+identity:
+  name: create_table
+  author: Doug Lea
+  label:
+    en_US: Create Table
+    zh_Hans: 新增数据表
+description:
+  human:
+    en_US: Add a Data Table to Multidimensional Table
+    zh_Hans: 在多维表格中新增一个数据表
+  llm: A tool for adding a data table to a multidimensional table. (在多维表格中新增一个数据表)
+parameters:
+  - name: app_token
+    type: string
+    required: true
+    label:
+      en_US: app_token
+      zh_Hans: app_token
+    human_description:
+      en_US: Unique identifier for the multidimensional table, supports inputting document URL.
+      zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
+    llm_description: 多维表格的唯一标识符,支持输入文档 URL。
+    form: llm
+
+  - name: table_name
+    type: string
+    required: true
+    label:
+      en_US: Table Name
+      zh_Hans: 数据表名称
+    human_description:
+      en_US: |
+        The name of the data table, length range: 1 character to 100 characters.
+      zh_Hans: 数据表名称,长度范围:1 字符 ~ 100 字符。
+    llm_description: 数据表名称,长度范围:1 字符 ~ 100 字符。
+    form: llm
+
+  - name: default_view_name
+    type: string
+    required: false
+    label:
+      en_US: Default View Name
+      zh_Hans: 默认表格视图的名称
+    human_description:
+      en_US: The name of the default table view, defaults to "Table" if not filled.
+      zh_Hans: 默认表格视图的名称,不填则默认为"表格"。
+    llm_description: 默认表格视图的名称,不填则默认为"表格"。
+    form: llm
+
+  - name: fields
+    type: string
+    required: true
+    label:
+      en_US: Initial Fields
+      zh_Hans: 初始字段
+    human_description:
+      en_US: |
+        Initial fields of the data table, format: [ { "field_name": "Multi-line Text","type": 1 },{ "field_name": "Number","type": 2 },{ "field_name": "Single Select","type": 3 },{ "field_name": "Multiple Select","type": 4 },{ "field_name": "Date","type": 5 } ]. For field details, refer to: https://open.larkoffice.com/document/server-docs/docs/bitable-v1/app-table-field/guide
+      zh_Hans: 数据表的初始字段,格式为:[{"field_name":"多行文本","type":1},{"field_name":"数字","type":2},{"field_name":"单选","type":3},{"field_name":"多选","type":4},{"field_name":"日期","type":5}]。字段详情参考:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/app-table-field/guide
+    llm_description: 数据表的初始字段,格式为:[{"field_name":"多行文本","type":1},{"field_name":"数字","type":2},{"field_name":"单选","type":3},{"field_name":"多选","type":4},{"field_name":"日期","type":5}]。字段详情参考:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/app-table-field/guide
+    form: llm

+ 0 - 56
api/core/tools/provider/builtin/feishu_base/tools/delete_base_records.py

@@ -1,56 +0,0 @@
-import json
-from typing import Any, Union
-
-import httpx
-
-from core.tools.entities.tool_entities import ToolInvokeMessage
-from core.tools.tool.builtin_tool import BuiltinTool
-
-
-class DeleteBaseRecordsTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_delete"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        app_token = tool_parameters.get("app_token", "")
-        if not app_token:
-            return self.create_text_message("Invalid parameter app_token")
-
-        table_id = tool_parameters.get("table_id", "")
-        if not table_id:
-            return self.create_text_message("Invalid parameter table_id")
-
-        record_ids = tool_parameters.get("record_ids", "")
-        if not record_ids:
-            return self.create_text_message("Invalid parameter record_ids")
-
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
-
-        params = {}
-        payload = {"records": json.loads(record_ids)}
-
-        try:
-            res = httpx.post(
-                url.format(app_token=app_token, table_id=table_id),
-                headers=headers,
-                params=params,
-                json=payload,
-                timeout=30,
-            )
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to delete base records, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to delete base records. {}".format(e))

+ 0 - 60
api/core/tools/provider/builtin/feishu_base/tools/delete_base_records.yaml

@@ -1,60 +0,0 @@
-identity:
-  name: delete_base_records
-  author: Doug Lea
-  label:
-    en_US: Delete Base Records
-    zh_Hans: 在多维表格数据表中删除多条记录
-description:
-  human:
-    en_US: Delete base records
-    zh_Hans: |
-      该接口用于删除多维表格数据表中的多条记录,单次调用中最多删除 500 条记录。
-  llm: A tool for delete multiple records in a multidimensional table data table, up to 500 records can be deleted in a single call.
-parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
-  - name: app_token
-    type: string
-    required: true
-    label:
-      en_US: app_token
-      zh_Hans: 多维表格
-    human_description:
-      en_US: bitable app token
-      zh_Hans: 多维表格的唯一标识符 app_token
-    llm_description: bitable app token
-    form: llm
-
-  - name: table_id
-    type: string
-    required: true
-    label:
-      en_US: table_id
-      zh_Hans: 多维表格的数据表
-    human_description:
-      en_US: bitable table id
-      zh_Hans: 多维表格数据表的唯一标识符 table_id
-    llm_description: bitable table id
-    form: llm
-
-  - name: record_ids
-    type: string
-    required: true
-    label:
-      en_US: record_ids
-      zh_Hans: record_ids
-    human_description:
-      en_US: A list of multiple record IDs to be deleted, for example ["recwNXzPQv","recpCsf4ME"]
-      zh_Hans: 待删除的多条记录id列表,示例为 ["recwNXzPQv","recpCsf4ME"]
-    llm_description: A list of multiple record IDs to be deleted, for example ["recwNXzPQv","recpCsf4ME"]
-    form: llm

+ 0 - 46
api/core/tools/provider/builtin/feishu_base/tools/delete_base_tables.py

@@ -1,46 +0,0 @@
-import json
-from typing import Any, Union
-
-import httpx
-
-from core.tools.entities.tool_entities import ToolInvokeMessage
-from core.tools.tool.builtin_tool import BuiltinTool
-
-
-class DeleteBaseTablesTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/batch_delete"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        app_token = tool_parameters.get("app_token", "")
-        if not app_token:
-            return self.create_text_message("Invalid parameter app_token")
-
-        table_ids = tool_parameters.get("table_ids", "")
-        if not table_ids:
-            return self.create_text_message("Invalid parameter table_ids")
-
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
-
-        params = {}
-        payload = {"table_ids": json.loads(table_ids)}
-
-        try:
-            res = httpx.post(url.format(app_token=app_token), headers=headers, params=params, json=payload, timeout=30)
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to delete base tables, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to delete base tables. {}".format(e))

+ 0 - 48
api/core/tools/provider/builtin/feishu_base/tools/delete_base_tables.yaml

@@ -1,48 +0,0 @@
-identity:
-  name: delete_base_tables
-  author: Doug Lea
-  label:
-    en_US: Delete Base Tables
-    zh_Hans: 删除多维表格中的数据表
-description:
-  human:
-    en_US: Delete base tables
-    zh_Hans: |
-      删除多维表格中的数据表
-  llm: A tool for deleting a data table in a multidimensional table
-parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
-  - name: app_token
-    type: string
-    required: true
-    label:
-      en_US: app_token
-      zh_Hans: 多维表格
-    human_description:
-      en_US: bitable app token
-      zh_Hans: 多维表格的唯一标识符 app_token
-    llm_description: bitable app token
-    form: llm
-
-  - name: table_ids
-    type: string
-    required: true
-    label:
-      en_US: table_ids
-      zh_Hans: table_ids
-    human_description:
-      en_US: The ID list of the data tables to be deleted. Currently, a maximum of 50 data tables can be deleted at a time. The example is ["tbl1TkhyTWDkSoZ3","tblsRc9GRRXKqhvW"]
-      zh_Hans: 待删除数据表的id列表,当前一次操作最多支持50个数据表,示例为 ["tbl1TkhyTWDkSoZ3","tblsRc9GRRXKqhvW"]
-    llm_description: The ID list of the data tables to be deleted. Currently, a maximum of 50 data tables can be deleted at a time. The example is ["tbl1TkhyTWDkSoZ3","tblsRc9GRRXKqhvW"]
-    form: llm

+ 20 - 0
api/core/tools/provider/builtin/feishu_base/tools/delete_records.py

@@ -0,0 +1,20 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
+
+
+class DeleteRecordsTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
+
+        app_token = tool_parameters.get("app_token")
+        table_id = tool_parameters.get("table_id")
+        table_name = tool_parameters.get("table_name")
+        record_ids = tool_parameters.get("record_ids")
+
+        res = client.delete_records(app_token, table_id, table_name, record_ids)
+        return self.create_json_message(res)

+ 86 - 0
api/core/tools/provider/builtin/feishu_base/tools/delete_records.yaml

@@ -0,0 +1,86 @@
+identity:
+  name: delete_records
+  author: Doug Lea
+  label:
+    en_US: Delete Records
+    zh_Hans: 删除多条记录
+description:
+  human:
+    en_US: Delete Multiple Records from Multidimensional Table
+    zh_Hans: 删除多维表格数据表中的多条记录
+  llm: A tool for deleting multiple records from a multidimensional table. (删除多维表格数据表中的多条记录)
+parameters:
+  - name: app_token
+    type: string
+    required: true
+    label:
+      en_US: app_token
+      zh_Hans: app_token
+    human_description:
+      en_US: Unique identifier for the multidimensional table, supports inputting document URL.
+      zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
+    llm_description: 多维表格的唯一标识符,支持输入文档 URL。
+    form: llm
+
+  - name: table_id
+    type: string
+    required: false
+    label:
+      en_US: table_id
+      zh_Hans: table_id
+    human_description:
+      en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: table_name
+    type: string
+    required: false
+    label:
+      en_US: table_name
+      zh_Hans: table_name
+    human_description:
+      en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: record_ids
+    type: string
+    required: true
+    label:
+      en_US: Record IDs
+      zh_Hans: 记录 ID 列表
+    human_description:
+      en_US: |
+        List of IDs for the records to be deleted, example value: ["recwNXzPQv"].
+      zh_Hans: 删除的多条记录 ID 列表,示例值:["recwNXzPQv"]。
+    llm_description: 删除的多条记录 ID 列表,示例值:["recwNXzPQv"]。
+    form: llm
+
+  - name: user_id_type
+    type: select
+    required: false
+    options:
+      - value: open_id
+        label:
+          en_US: open_id
+          zh_Hans: open_id
+      - value: union_id
+        label:
+          en_US: union_id
+          zh_Hans: union_id
+      - value: user_id
+        label:
+          en_US: user_id
+          zh_Hans: user_id
+    default: "open_id"
+    label:
+      en_US: user_id_type
+      zh_Hans: 用户 ID 类型
+    human_description:
+      en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
+      zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    form: form

+ 19 - 0
api/core/tools/provider/builtin/feishu_base/tools/delete_tables.py

@@ -0,0 +1,19 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
+
+
+class DeleteTablesTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
+
+        app_token = tool_parameters.get("app_token")
+        table_ids = tool_parameters.get("table_ids")
+        table_names = tool_parameters.get("table_names")
+
+        res = client.delete_tables(app_token, table_ids, table_names)
+        return self.create_json_message(res)

+ 49 - 0
api/core/tools/provider/builtin/feishu_base/tools/delete_tables.yaml

@@ -0,0 +1,49 @@
+identity:
+  name: delete_tables
+  author: Doug Lea
+  label:
+    en_US: Delete Tables
+    zh_Hans: 删除数据表
+description:
+  human:
+    en_US: Batch Delete Data Tables from Multidimensional Table
+    zh_Hans: 批量删除多维表格中的数据表
+  llm: A tool for batch deleting data tables from a multidimensional table. (批量删除多维表格中的数据表)
+parameters:
+  - name: app_token
+    type: string
+    required: true
+    label:
+      en_US: app_token
+      zh_Hans: app_token
+    human_description:
+      en_US: Unique identifier for the multidimensional table, supports inputting document URL.
+      zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
+    llm_description: 多维表格的唯一标识符,支持输入文档 URL。
+    form: llm
+
+  - name: table_ids
+    type: string
+    required: false
+    label:
+      en_US: Table IDs
+      zh_Hans: 数据表 ID
+    human_description:
+      en_US: |
+        IDs of the tables to be deleted. Each operation supports deleting up to 50 tables. Example: ["tbl1TkhyTWDkSoZ3"]. Ensure that either table_ids or table_names is not empty.
+      zh_Hans: 待删除的数据表的 ID,每次操作最多支持删除 50 个数据表。示例值:["tbl1TkhyTWDkSoZ3"]。请确保 table_ids 和 table_names 至少有一个不为空。
+    llm_description: 待删除的数据表的 ID,每次操作最多支持删除 50 个数据表。示例值:["tbl1TkhyTWDkSoZ3"]。请确保 table_ids 和 table_names 至少有一个不为空。
+    form: llm
+
+  - name: table_names
+    type: string
+    required: false
+    label:
+      en_US: Table Names
+      zh_Hans: 数据表名称
+    human_description:
+      en_US: |
+        Names of the tables to be deleted. Each operation supports deleting up to 50 tables. Example: ["Table1", "Table2"]. Ensure that either table_names or table_ids is not empty.
+      zh_Hans: 待删除的数据表的名称,每次操作最多支持删除 50 个数据表。示例值:["数据表1", "数据表2"]。请确保 table_names 和 table_ids 至少有一个不为空。
+    llm_description: 待删除的数据表的名称,每次操作最多支持删除 50 个数据表。示例值:["数据表1", "数据表2"]。请确保 table_names 和 table_ids 至少有一个不为空。
+    form: llm

+ 9 - 31
api/core/tools/provider/builtin/feishu_base/tools/get_base_info.py

@@ -1,39 +1,17 @@
-import json
-from typing import Any, Union
-
-import httpx
+from typing import Any
 
 from core.tools.entities.tool_entities import ToolInvokeMessage
 from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
 
 
 class GetBaseInfoTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        app_token = tool_parameters.get("app_token", "")
-        if not app_token:
-            return self.create_text_message("Invalid parameter app_token")
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
 
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
+        app_token = tool_parameters.get("app_token")
 
-        try:
-            res = httpx.get(url.format(app_token=app_token), headers=headers, timeout=30)
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to get base info, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to get base info. {}".format(e))
+        res = client.get_base_info(app_token)
+        return self.create_json_message(res)

+ 7 - 38
api/core/tools/provider/builtin/feishu_base/tools/get_base_info.yaml

@@ -6,49 +6,18 @@ identity:
     zh_Hans: 获取多维表格元数据
 description:
   human:
-    en_US: Get base info
-    zh_Hans: |
-      获取多维表格元数据,响应体如下:
-      {
-          "code": 0,
-          "msg": "success",
-          "data": {
-              "app": {
-                  "app_token": "appbcbWCzen6D8dezhoCH2RpMAh",
-                  "name": "mybase",
-                  "revision": 1,
-                  "is_advanced": false,
-                  "time_zone": "Asia/Beijing"
-              }
-          }
-      }
-      app_token: 多维表格的 app_token;
-      name: 多维表格的名字;
-      revision: 多维表格的版本号;
-      is_advanced: 多维表格是否开启了高级权限。取值包括:(true-表示开启了高级权限,false-表示关闭了高级权限);
-      time_zone: 文档时区;
-  llm: A tool to get Base Metadata, imported parameter is Unique Device Identifier app_token of Base, app_token is required.
+    en_US: Get Metadata Information of Specified Multidimensional Table
+    zh_Hans: 获取指定多维表格的元数据信息
+  llm: A tool for getting metadata information of a specified multidimensional table. (获取指定多维表格的元数据信息)
 parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
   - name: app_token
     type: string
     required: true
     label:
       en_US: app_token
-      zh_Hans: 多维表格
+      zh_Hans: app_token
     human_description:
-      en_US: bitable app token
-      zh_Hans: 多维表格的唯一标识符 app_token
-    llm_description: bitable app token
+      en_US: Unique identifier for the multidimensional table, supports inputting document URL.
+      zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
+    llm_description: 多维表格的唯一标识符,支持输入文档 URL。
     form: llm

+ 0 - 48
api/core/tools/provider/builtin/feishu_base/tools/get_tenant_access_token.py

@@ -1,48 +0,0 @@
-import json
-from typing import Any, Union
-
-import httpx
-
-from core.tools.entities.tool_entities import ToolInvokeMessage
-from core.tools.tool.builtin_tool import BuiltinTool
-
-
-class GetTenantAccessTokenTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
-
-        app_id = tool_parameters.get("app_id", "")
-        if not app_id:
-            return self.create_text_message("Invalid parameter app_id")
-
-        app_secret = tool_parameters.get("app_secret", "")
-        if not app_secret:
-            return self.create_text_message("Invalid parameter app_secret")
-
-        headers = {
-            "Content-Type": "application/json",
-        }
-        params = {}
-        payload = {"app_id": app_id, "app_secret": app_secret}
-
-        """
-        {
-            "code": 0,
-            "msg": "ok",
-            "tenant_access_token": "t-caecc734c2e3328a62489fe0648c4b98779515d3",
-            "expire": 7200
-        }
-        """
-        try:
-            res = httpx.post(url, headers=headers, params=params, json=payload, timeout=30)
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to get tenant access token, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to get tenant access token. {}".format(e))

+ 0 - 39
api/core/tools/provider/builtin/feishu_base/tools/get_tenant_access_token.yaml

@@ -1,39 +0,0 @@
-identity:
-  name: get_tenant_access_token
-  author: Doug Lea
-  label:
-    en_US: Get Tenant Access Token
-    zh_Hans: 获取飞书自建应用的 tenant_access_token
-description:
-  human:
-    en_US: Get tenant access token
-    zh_Hans: |
-      获取飞书自建应用的 tenant_access_token,响应体示例:
-      {"code":0,"msg":"ok","tenant_access_token":"t-caecc734c2e3328a62489fe0648c4b98779515d3","expire":7200}
-      tenant_access_token: 租户访问凭证;
-      expire: tenant_access_token 的过期时间,单位为秒;
-  llm: A tool for obtaining a tenant access token. The input parameters must include app_id and app_secret.
-parameters:
-  - name: app_id
-    type: string
-    required: true
-    label:
-      en_US: app_id
-      zh_Hans: 应用唯一标识
-    human_description:
-      en_US: app_id is the unique identifier of the Lark Open Platform application
-      zh_Hans: app_id 是飞书开放平台应用的唯一标识
-    llm_description: app_id is the unique identifier of the Lark Open Platform application
-    form: llm
-
-  - name: app_secret
-    type: secret-input
-    required: true
-    label:
-      en_US: app_secret
-      zh_Hans: 应用秘钥
-    human_description:
-      en_US: app_secret is the secret key of the application
-      zh_Hans: app_secret 是应用的秘钥
-    llm_description: app_secret is the secret key of the application
-    form: llm

+ 0 - 65
api/core/tools/provider/builtin/feishu_base/tools/list_base_records.py

@@ -1,65 +0,0 @@
-import json
-from typing import Any, Union
-
-import httpx
-
-from core.tools.entities.tool_entities import ToolInvokeMessage
-from core.tools.tool.builtin_tool import BuiltinTool
-
-
-class ListBaseRecordsTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/search"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        app_token = tool_parameters.get("app_token", "")
-        if not app_token:
-            return self.create_text_message("Invalid parameter app_token")
-
-        table_id = tool_parameters.get("table_id", "")
-        if not table_id:
-            return self.create_text_message("Invalid parameter table_id")
-
-        page_token = tool_parameters.get("page_token", "")
-        page_size = tool_parameters.get("page_size", "")
-        sort_condition = tool_parameters.get("sort_condition", "")
-        filter_condition = tool_parameters.get("filter_condition", "")
-
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
-
-        params = {
-            "page_token": page_token,
-            "page_size": page_size,
-        }
-
-        payload = {"automatic_fields": True}
-        if sort_condition:
-            payload["sort"] = json.loads(sort_condition)
-        if filter_condition:
-            payload["filter"] = json.loads(filter_condition)
-
-        try:
-            res = httpx.post(
-                url.format(app_token=app_token, table_id=table_id),
-                headers=headers,
-                params=params,
-                json=payload,
-                timeout=30,
-            )
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to list base records, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to list base records. {}".format(e))

+ 0 - 108
api/core/tools/provider/builtin/feishu_base/tools/list_base_records.yaml

@@ -1,108 +0,0 @@
-identity:
-  name: list_base_records
-  author: Doug Lea
-  label:
-    en_US: List Base Records
-    zh_Hans: 查询多维表格数据表中的现有记录
-description:
-  human:
-    en_US: List base records
-    zh_Hans: |
-      查询多维表格数据表中的现有记录,单次最多查询 500 行记录,支持分页获取。
-  llm: Query existing records in a multidimensional table data table. A maximum of 500 rows of records can be queried at a time, and paging retrieval is supported.
-parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
-  - name: app_token
-    type: string
-    required: true
-    label:
-      en_US: app_token
-      zh_Hans: 多维表格
-    human_description:
-      en_US: bitable app token
-      zh_Hans: 多维表格的唯一标识符 app_token
-    llm_description: bitable app token
-    form: llm
-
-  - name: table_id
-    type: string
-    required: true
-    label:
-      en_US: table_id
-      zh_Hans: 多维表格的数据表
-    human_description:
-      en_US: bitable table id
-      zh_Hans: 多维表格数据表的唯一标识符 table_id
-    llm_description: bitable table id
-    form: llm
-
-  - name: page_token
-    type: string
-    required: false
-    label:
-      en_US: page_token
-      zh_Hans: 分页标记
-    human_description:
-      en_US: Pagination mark. If it is not filled in the first request, it means to traverse from the beginning.
-      zh_Hans: 分页标记,第一次请求不填,表示从头开始遍历。
-    llm_description: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。
-    form: llm
-
-  - name: page_size
-    type: number
-    required: false
-    default: 20
-    label:
-      en_US: page_size
-      zh_Hans: 分页大小
-    human_description:
-      en_US: paging size
-      zh_Hans: 分页大小,默认值为 20,最大值为 100。
-    llm_description: The default value of paging size is 20 and the maximum value is 100.
-    form: llm
-
-  - name: sort_condition
-    type: string
-    required: false
-    label:
-      en_US: sort_condition
-      zh_Hans: 排序条件
-    human_description:
-      en_US: sort condition
-      zh_Hans: |
-        排序条件,格式为:[{"field_name":"多行文本","desc":true}]。
-        field_name: 字段名称;
-        desc: 是否倒序排序;
-    llm_description: |
-      Sorting conditions, the format is: [{"field_name":"multi-line text","desc":true}].
-    form: llm
-
-  - name: filter_condition
-    type: string
-    required: false
-    label:
-      en_US: filter_condition
-      zh_Hans: 筛选条件
-    human_description:
-      en_US: filter condition
-      zh_Hans: |
-        筛选条件,格式为:{"conjunction":"and","conditions":[{"field_name":"字段1","operator":"is","value":["文本内容"]}]}。
-        conjunction:条件逻辑连接词;
-        conditions:筛选条件集合;
-        field_name:筛选条件的左值,值为字段的名称;
-        operator:条件运算符;
-        value:目标值;
-    llm_description: |
-      The format of the filter condition is: {"conjunction":"and","conditions":[{"field_name":"Field 1","operator":"is","value":["text content"]}]}.
-    form: llm

+ 0 - 47
api/core/tools/provider/builtin/feishu_base/tools/list_base_tables.py

@@ -1,47 +0,0 @@
-import json
-from typing import Any, Union
-
-import httpx
-
-from core.tools.entities.tool_entities import ToolInvokeMessage
-from core.tools.tool.builtin_tool import BuiltinTool
-
-
-class ListBaseTablesTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        app_token = tool_parameters.get("app_token", "")
-        if not app_token:
-            return self.create_text_message("Invalid parameter app_token")
-
-        page_token = tool_parameters.get("page_token", "")
-        page_size = tool_parameters.get("page_size", "")
-
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
-
-        params = {
-            "page_token": page_token,
-            "page_size": page_size,
-        }
-
-        try:
-            res = httpx.get(url.format(app_token=app_token), headers=headers, params=params, timeout=30)
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to list base tables, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to list base tables. {}".format(e))

+ 0 - 65
api/core/tools/provider/builtin/feishu_base/tools/list_base_tables.yaml

@@ -1,65 +0,0 @@
-identity:
-  name: list_base_tables
-  author: Doug Lea
-  label:
-    en_US: List Base Tables
-    zh_Hans: 根据 app_token 获取多维表格下的所有数据表
-description:
-  human:
-    en_US: List base tables
-    zh_Hans: |
-      根据 app_token 获取多维表格下的所有数据表
-  llm: A tool for getting all data tables under a multidimensional table based on app_token.
-parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
-  - name: app_token
-    type: string
-    required: true
-    label:
-      en_US: app_token
-      zh_Hans: 多维表格
-    human_description:
-      en_US: bitable app token
-      zh_Hans: 多维表格的唯一标识符 app_token
-    llm_description: bitable app token
-    form: llm
-
-  - name: page_token
-    type: string
-    required: false
-    label:
-      en_US: page_token
-      zh_Hans: 分页标记
-    human_description:
-      en_US: Pagination mark. If it is not filled in the first request, it means to traverse from the beginning.
-      zh_Hans: 分页标记,第一次请求不填,表示从头开始遍历。
-    llm_description: |
-      Pagination token. If it is not filled in the first request, it means to start traversal from the beginning.
-      If there are more items in the pagination query result, a new page_token will be returned at the same time.
-      The page_token can be used to obtain the query result in the next traversal.
-      分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。
-    form: llm
-
-  - name: page_size
-    type: number
-    required: false
-    default: 20
-    label:
-      en_US: page_size
-      zh_Hans: 分页大小
-    human_description:
-      en_US: paging size
-      zh_Hans: 分页大小,默认值为 20,最大值为 100。
-    llm_description: The default value of paging size is 20 and the maximum value is 100.
-    form: llm

+ 19 - 0
api/core/tools/provider/builtin/feishu_base/tools/list_tables.py

@@ -0,0 +1,19 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
+
+
+class ListTablesTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
+
+        app_token = tool_parameters.get("app_token")
+        page_token = tool_parameters.get("page_token")
+        page_size = tool_parameters.get("page_size", 20)
+
+        res = client.list_tables(app_token, page_token, page_size)
+        return self.create_json_message(res)

+ 50 - 0
api/core/tools/provider/builtin/feishu_base/tools/list_tables.yaml

@@ -0,0 +1,50 @@
+identity:
+  name: list_tables
+  author: Doug Lea
+  label:
+    en_US: List Tables
+    zh_Hans: 列出数据表
+description:
+  human:
+    en_US: Get All Data Tables under Multidimensional Table
+    zh_Hans: 获取多维表格下的所有数据表
+  llm: A tool for getting all data tables under a multidimensional table. (获取多维表格下的所有数据表)
+parameters:
+  - name: app_token
+    type: string
+    required: true
+    label:
+      en_US: app_token
+      zh_Hans: app_token
+    human_description:
+      en_US: Unique identifier for the multidimensional table, supports inputting document URL.
+      zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
+    llm_description: 多维表格的唯一标识符,支持输入文档 URL。
+    form: llm
+
+  - name: page_size
+    type: number
+    required: false
+    default: 20
+    label:
+      en_US: page_size
+      zh_Hans: 分页大小
+    human_description:
+      en_US: |
+        Page size, default value: 20, maximum value: 100.
+      zh_Hans: 分页大小,默认值:20,最大值:100。
+    llm_description: 分页大小,默认值:20,最大值:100。
+    form: llm
+
+  - name: page_token
+    type: string
+    required: false
+    label:
+      en_US: page_token
+      zh_Hans: 分页标记
+    human_description:
+      en_US: |
+        Page token, leave empty for the first request to start from the beginning; a new page_token will be returned if there are more items in the paginated query results, which can be used for the next traversal. Example value: "tblsRc9GRRXKqhvW".
+      zh_Hans: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。示例值:"tblsRc9GRRXKqhvW"。
+    llm_description: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。示例值:"tblsRc9GRRXKqhvW"。
+    form: llm

+ 0 - 49
api/core/tools/provider/builtin/feishu_base/tools/read_base_record.py

@@ -1,49 +0,0 @@
-import json
-from typing import Any, Union
-
-import httpx
-
-from core.tools.entities.tool_entities import ToolInvokeMessage
-from core.tools.tool.builtin_tool import BuiltinTool
-
-
-class ReadBaseRecordTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/{record_id}"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        app_token = tool_parameters.get("app_token", "")
-        if not app_token:
-            return self.create_text_message("Invalid parameter app_token")
-
-        table_id = tool_parameters.get("table_id", "")
-        if not table_id:
-            return self.create_text_message("Invalid parameter table_id")
-
-        record_id = tool_parameters.get("record_id", "")
-        if not record_id:
-            return self.create_text_message("Invalid parameter record_id")
-
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
-
-        try:
-            res = httpx.get(
-                url.format(app_token=app_token, table_id=table_id, record_id=record_id), headers=headers, timeout=30
-            )
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to read base record, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to read base record. {}".format(e))

+ 0 - 60
api/core/tools/provider/builtin/feishu_base/tools/read_base_record.yaml

@@ -1,60 +0,0 @@
-identity:
-  name: read_base_record
-  author: Doug Lea
-  label:
-    en_US: Read Base Record
-    zh_Hans: 根据 record_id 的值检索多维表格数据表的记录
-description:
-  human:
-    en_US: Read base record
-    zh_Hans: |
-      根据 record_id 的值检索多维表格数据表的记录
-  llm: Retrieve records from a multidimensional table based on the value of record_id
-parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
-  - name: app_token
-    type: string
-    required: true
-    label:
-      en_US: app_token
-      zh_Hans: 多维表格
-    human_description:
-      en_US: bitable app token
-      zh_Hans: 多维表格的唯一标识符 app_token
-    llm_description: bitable app token
-    form: llm
-
-  - name: table_id
-    type: string
-    required: true
-    label:
-      en_US: table_id
-      zh_Hans: 多维表格的数据表
-    human_description:
-      en_US: bitable table id
-      zh_Hans: 多维表格数据表的唯一标识符 table_id
-    llm_description: bitable table id
-    form: llm
-
-  - name: record_id
-    type: string
-    required: true
-    label:
-      en_US: record_id
-      zh_Hans: 单条记录的 id
-    human_description:
-      en_US: The id of a single record
-      zh_Hans: 单条记录的 id
-    llm_description: The id of a single record
-    form: llm

+ 21 - 0
api/core/tools/provider/builtin/feishu_base/tools/read_records.py

@@ -0,0 +1,21 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
+
+
+class ReadRecordsTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
+
+        app_token = tool_parameters.get("app_token")
+        table_id = tool_parameters.get("table_id")
+        table_name = tool_parameters.get("table_name")
+        record_ids = tool_parameters.get("record_ids")
+        user_id_type = tool_parameters.get("user_id_type", "open_id")
+
+        res = client.read_records(app_token, table_id, table_name, record_ids, user_id_type)
+        return self.create_json_message(res)

+ 86 - 0
api/core/tools/provider/builtin/feishu_base/tools/read_records.yaml

@@ -0,0 +1,86 @@
+identity:
+  name: read_records
+  author: Doug Lea
+  label:
+    en_US: Read Records
+    zh_Hans: 批量获取记录
+description:
+  human:
+    en_US: Batch Retrieve Records from Multidimensional Table
+    zh_Hans: 批量获取多维表格数据表中的记录信息
+  llm: A tool for batch retrieving records from a multidimensional table, supporting up to 100 records per call. (批量获取多维表格数据表中的记录信息,单次调用最多支持查询 100 条记录)
+
+parameters:
+  - name: app_token
+    type: string
+    required: true
+    label:
+      en_US: app_token
+      zh_Hans: app_token
+    human_description:
+      en_US: Unique identifier for the multidimensional table, supports inputting document URL.
+      zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
+    llm_description: 多维表格的唯一标识符,支持输入文档 URL。
+    form: llm
+
+  - name: table_id
+    type: string
+    required: false
+    label:
+      en_US: table_id
+      zh_Hans: table_id
+    human_description:
+      en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: table_name
+    type: string
+    required: false
+    label:
+      en_US: table_name
+      zh_Hans: table_name
+    human_description:
+      en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: record_ids
+    type: string
+    required: true
+    label:
+      en_US: record_ids
+      zh_Hans: 记录 ID 列表
+    human_description:
+      en_US: List of record IDs, which can be obtained by calling the "Query Records API".
+      zh_Hans: 记录 ID 列表,可以通过调用"查询记录接口"获取。
+    llm_description: 记录 ID 列表,可以通过调用"查询记录接口"获取。
+    form: llm
+
+  - name: user_id_type
+    type: select
+    required: false
+    options:
+      - value: open_id
+        label:
+          en_US: open_id
+          zh_Hans: open_id
+      - value: union_id
+        label:
+          en_US: union_id
+          zh_Hans: union_id
+      - value: user_id
+        label:
+          en_US: user_id
+          zh_Hans: user_id
+    default: "open_id"
+    label:
+      en_US: user_id_type
+      zh_Hans: 用户 ID 类型
+    human_description:
+      en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
+      zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    form: form

+ 39 - 0
api/core/tools/provider/builtin/feishu_base/tools/search_records.py

@@ -0,0 +1,39 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
+
+
+class SearchRecordsTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
+
+        app_token = tool_parameters.get("app_token")
+        table_id = tool_parameters.get("table_id")
+        table_name = tool_parameters.get("table_name")
+        view_id = tool_parameters.get("view_id")
+        field_names = tool_parameters.get("field_names")
+        sort = tool_parameters.get("sort")
+        filters = tool_parameters.get("filter")
+        page_token = tool_parameters.get("page_token")
+        automatic_fields = tool_parameters.get("automatic_fields", False)
+        user_id_type = tool_parameters.get("user_id_type", "open_id")
+        page_size = tool_parameters.get("page_size", 20)
+
+        res = client.search_record(
+            app_token,
+            table_id,
+            table_name,
+            view_id,
+            field_names,
+            sort,
+            filters,
+            page_token,
+            automatic_fields,
+            user_id_type,
+            page_size,
+        )
+        return self.create_json_message(res)

+ 163 - 0
api/core/tools/provider/builtin/feishu_base/tools/search_records.yaml

@@ -0,0 +1,163 @@
+identity:
+  name: search_records
+  author: Doug Lea
+  label:
+    en_US: Search Records
+    zh_Hans: 查询记录
+description:
+  human:
+    en_US: Query records in a multidimensional table, up to 500 rows per query.
+    zh_Hans: 查询多维表格数据表中的记录,单次最多查询 500 行记录。
+  llm: A tool for querying records in a multidimensional table, up to 500 rows per query. (查询多维表格数据表中的记录,单次最多查询 500 行记录)
+parameters:
+  - name: app_token
+    type: string
+    required: true
+    label:
+      en_US: app_token
+      zh_Hans: app_token
+    human_description:
+      en_US: Unique identifier for the multidimensional table, supports inputting document URL.
+      zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
+    llm_description: 多维表格的唯一标识符,支持输入文档 URL。
+    form: llm
+
+  - name: table_id
+    type: string
+    required: false
+    label:
+      en_US: table_id
+      zh_Hans: table_id
+    human_description:
+      en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: table_name
+    type: string
+    required: false
+    label:
+      en_US: table_name
+      zh_Hans: table_name
+    human_description:
+      en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: view_id
+    type: string
+    required: false
+    label:
+      en_US: view_id
+      zh_Hans: 视图唯一标识
+    human_description:
+      en_US: |
+        Unique identifier for a view in a multidimensional table. It can be found in the URL's query parameter with the key 'view'. For example: https://svi136aogf123.feishu.cn/base/KWC8bYsYXahYqGsTtqectNn9n3e?table=tblE8a2fmBIEflaE&view=vewlkAVpRx.
+      zh_Hans: 多维表格中视图的唯一标识,可在多维表格的 URL 地址栏中找到,query 参数中 key 为 view 的部分。例如:https://svi136aogf123.feishu.cn/base/KWC8bYsYXahYqGsTtqectNn9n3e?table=tblE8a2fmBIEflaE&view=vewlkAVpRx。
+    llm_description: 多维表格中视图的唯一标识,可在多维表格的 URL 地址栏中找到,query 参数中 key 为 view 的部分。例如:https://svi136aogf123.feishu.cn/base/KWC8bYsYXahYqGsTtqectNn9n3e?table=tblE8a2fmBIEflaE&view=vewlkAVpRx。
+    form: llm
+
+  - name: field_names
+    type: string
+    required: false
+    label:
+      en_US: field_names
+      zh_Hans: 字段名称
+    human_description:
+      en_US: |
+        Field names to specify which fields to include in the returned records. Example value: ["Field1", "Field2"].
+      zh_Hans: 字段名称,用于指定本次查询返回记录中包含的字段。示例值:["字段1","字段2"]。
+    llm_description: 字段名称,用于指定本次查询返回记录中包含的字段。示例值:["字段1","字段2"]。
+    form: llm
+
+  - name: sort
+    type: string
+    required: false
+    label:
+      en_US: sort
+      zh_Hans: 排序条件
+    human_description:
+      en_US: |
+        Sorting conditions, for example: [{"field_name":"Multiline Text","desc":true}].
+      zh_Hans: 排序条件,例如:[{"field_name":"多行文本","desc":true}]。
+    llm_description: 排序条件,例如:[{"field_name":"多行文本","desc":true}]。
+    form: llm
+
+  - name: filter
+    type: string
+    required: false
+    label:
+      en_US: filter
+      zh_Hans: 筛选条件
+    human_description:
+      en_US: Object containing filter information. For details on how to fill in the filter, refer to the record filter parameter guide (https://open.larkoffice.com/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/record-filter-guide).
+      zh_Hans: 包含条件筛选信息的对象。了解如何填写 filter,参考记录筛选参数填写指南(https://open.larkoffice.com/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/record-filter-guide)。
+    llm_description: 包含条件筛选信息的对象。了解如何填写 filter,参考记录筛选参数填写指南(https://open.larkoffice.com/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/record-filter-guide)。
+    form: llm
+
+  - name: automatic_fields
+    type: boolean
+    required: false
+    label:
+      en_US: automatic_fields
+      zh_Hans: automatic_fields
+    human_description:
+      en_US: Whether to return automatically calculated fields. Default is false, meaning they are not returned.
+      zh_Hans: 是否返回自动计算的字段。默认为 false,表示不返回。
+    llm_description: 是否返回自动计算的字段。默认为 false,表示不返回。
+    form: form
+
+  - name: user_id_type
+    type: select
+    required: false
+    options:
+      - value: open_id
+        label:
+          en_US: open_id
+          zh_Hans: open_id
+      - value: union_id
+        label:
+          en_US: union_id
+          zh_Hans: union_id
+      - value: user_id
+        label:
+          en_US: user_id
+          zh_Hans: user_id
+    default: "open_id"
+    label:
+      en_US: user_id_type
+      zh_Hans: 用户 ID 类型
+    human_description:
+      en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
+      zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    form: form
+
+  - name: page_size
+    type: number
+    required: false
+    default: 20
+    label:
+      en_US: page_size
+      zh_Hans: 分页大小
+    human_description:
+      en_US: |
+        Page size, default value: 20, maximum value: 500.
+      zh_Hans: 分页大小,默认值:20,最大值:500。
+    llm_description: 分页大小,默认值:20,最大值:500。
+    form: llm
+
+  - name: page_token
+    type: string
+    required: false
+    label:
+      en_US: page_token
+      zh_Hans: 分页标记
+    human_description:
+      en_US: |
+        Page token, leave empty for the first request to start from the beginning; a new page_token will be returned if there are more items in the paginated query results, which can be used for the next traversal. Example value: "tblsRc9GRRXKqhvW".
+      zh_Hans: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。示例值:"tblsRc9GRRXKqhvW"。
+    llm_description: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。示例值:"tblsRc9GRRXKqhvW"。
+    form: llm

+ 0 - 60
api/core/tools/provider/builtin/feishu_base/tools/update_base_record.py

@@ -1,60 +0,0 @@
-import json
-from typing import Any, Union
-
-import httpx
-
-from core.tools.entities.tool_entities import ToolInvokeMessage
-from core.tools.tool.builtin_tool import BuiltinTool
-
-
-class UpdateBaseRecordTool(BuiltinTool):
-    def _invoke(
-        self, user_id: str, tool_parameters: dict[str, Any]
-    ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
-        url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/{record_id}"
-
-        access_token = tool_parameters.get("Authorization", "")
-        if not access_token:
-            return self.create_text_message("Invalid parameter access_token")
-
-        app_token = tool_parameters.get("app_token", "")
-        if not app_token:
-            return self.create_text_message("Invalid parameter app_token")
-
-        table_id = tool_parameters.get("table_id", "")
-        if not table_id:
-            return self.create_text_message("Invalid parameter table_id")
-
-        record_id = tool_parameters.get("record_id", "")
-        if not record_id:
-            return self.create_text_message("Invalid parameter record_id")
-
-        fields = tool_parameters.get("fields", "")
-        if not fields:
-            return self.create_text_message("Invalid parameter fields")
-
-        headers = {
-            "Content-Type": "application/json",
-            "Authorization": f"Bearer {access_token}",
-        }
-
-        params = {}
-        payload = {"fields": json.loads(fields)}
-
-        try:
-            res = httpx.put(
-                url.format(app_token=app_token, table_id=table_id, record_id=record_id),
-                headers=headers,
-                params=params,
-                json=payload,
-                timeout=30,
-            )
-            res_json = res.json()
-            if res.is_success:
-                return self.create_text_message(text=json.dumps(res_json))
-            else:
-                return self.create_text_message(
-                    f"Failed to update base record, status code: {res.status_code}, response: {res.text}"
-                )
-        except Exception as e:
-            return self.create_text_message("Failed to update base record. {}".format(e))

+ 0 - 78
api/core/tools/provider/builtin/feishu_base/tools/update_base_record.yaml

@@ -1,78 +0,0 @@
-identity:
-  name: update_base_record
-  author: Doug Lea
-  label:
-    en_US: Update Base Record
-    zh_Hans: 更新多维表格数据表中的一条记录
-description:
-  human:
-    en_US: Update base record
-    zh_Hans: |
-      更新多维表格数据表中的一条记录,详细请参考:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/app-table-record/update
-  llm: Update a record in a multidimensional table data table
-parameters:
-  - name: Authorization
-    type: string
-    required: true
-    label:
-      en_US: token
-      zh_Hans: 凭证
-    human_description:
-      en_US: API access token parameter, tenant_access_token or user_access_token
-      zh_Hans: API 的访问凭证参数,tenant_access_token 或 user_access_token
-    llm_description: API access token parameter, tenant_access_token or user_access_token
-    form: llm
-
-  - name: app_token
-    type: string
-    required: true
-    label:
-      en_US: app_token
-      zh_Hans: 多维表格
-    human_description:
-      en_US: bitable app token
-      zh_Hans: 多维表格的唯一标识符 app_token
-    llm_description: bitable app token
-    form: llm
-
-  - name: table_id
-    type: string
-    required: true
-    label:
-      en_US: table_id
-      zh_Hans: 多维表格的数据表
-    human_description:
-      en_US: bitable table id
-      zh_Hans: 多维表格数据表的唯一标识符 table_id
-    llm_description: bitable table id
-    form: llm
-
-  - name: record_id
-    type: string
-    required: true
-    label:
-      en_US: record_id
-      zh_Hans: 单条记录的 id
-    human_description:
-      en_US: The id of a single record
-      zh_Hans: 单条记录的 id
-    llm_description: The id of a single record
-    form: llm
-
-  - name: fields
-    type: string
-    required: true
-    label:
-      en_US: fields
-      zh_Hans: 数据表的列字段内容
-    human_description:
-      en_US: The fields of a multidimensional table data table, that is, the columns of the data table.
-      zh_Hans: |
-        要更新一行多维表格记录,字段结构拼接如下:{"多行文本":"多行文本内容","单选":"选项1","多选":["选项1","选项2"],"复选框":true,"人员":[{"id":"ou_2910013f1e6456f16a0ce75ede950a0a"}],"群组":[{"id":"oc_cd07f55f14d6f4a4f1b51504e7e97f48"}],"电话号码":"13026162666"}
-        当前接口支持的字段类型为:多行文本、单选、条码、多选、日期、人员、附件、复选框、超链接、数字、单向关联、双向关联、电话号码、地理位置。
-        不同类型字段的数据结构请参考数据结构概述:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure
-    llm_description: |
-      要更新一行多维表格记录,字段结构拼接如下:{"多行文本":"多行文本内容","单选":"选项1","多选":["选项1","选项2"],"复选框":true,"人员":[{"id":"ou_2910013f1e6456f16a0ce75ede950a0a"}],"群组":[{"id":"oc_cd07f55f14d6f4a4f1b51504e7e97f48"}],"电话号码":"13026162666"}
-      当前接口支持的字段类型为:多行文本、单选、条码、多选、日期、人员、附件、复选框、超链接、数字、单向关联、双向关联、电话号码、地理位置。
-      不同类型字段的数据结构请参考数据结构概述:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure
-    form: llm

+ 21 - 0
api/core/tools/provider/builtin/feishu_base/tools/update_records.py

@@ -0,0 +1,21 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+from core.tools.utils.feishu_api_utils import FeishuRequest
+
+
+class UpdateRecordsTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
+        app_id = self.runtime.credentials.get("app_id")
+        app_secret = self.runtime.credentials.get("app_secret")
+        client = FeishuRequest(app_id, app_secret)
+
+        app_token = tool_parameters.get("app_token")
+        table_id = tool_parameters.get("table_id")
+        table_name = tool_parameters.get("table_name")
+        records = tool_parameters.get("records")
+        user_id_type = tool_parameters.get("user_id_type", "open_id")
+
+        res = client.update_records(app_token, table_id, table_name, records, user_id_type)
+        return self.create_json_message(res)

+ 91 - 0
api/core/tools/provider/builtin/feishu_base/tools/update_records.yaml

@@ -0,0 +1,91 @@
+identity:
+  name: update_records
+  author: Doug Lea
+  label:
+    en_US: Update Records
+    zh_Hans: 更新多条记录
+description:
+  human:
+    en_US: Update Multiple Records in Multidimensional Table
+    zh_Hans: 更新多维表格数据表中的多条记录
+  llm: A tool for updating multiple records in a multidimensional table. (更新多维表格数据表中的多条记录)
+parameters:
+  - name: app_token
+    type: string
+    required: true
+    label:
+      en_US: app_token
+      zh_Hans: app_token
+    human_description:
+      en_US: Unique identifier for the multidimensional table, supports inputting document URL.
+      zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
+    llm_description: 多维表格的唯一标识符,支持输入文档 URL。
+    form: llm
+
+  - name: table_id
+    type: string
+    required: false
+    label:
+      en_US: table_id
+      zh_Hans: table_id
+    human_description:
+      en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: table_name
+    type: string
+    required: false
+    label:
+      en_US: table_name
+      zh_Hans: table_name
+    human_description:
+      en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
+      zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
+    form: llm
+
+  - name: records
+    type: string
+    required: true
+    label:
+      en_US: records
+      zh_Hans: 记录列表
+    human_description:
+      en_US: |
+        List of records to be updated in this request. Example value: [{"fields":{"multi-line-text":"text content","single_select":"option 1","date":1674206443000},"record_id":"recupK4f4RM5RX"}].
+        For supported field types, refer to the integration guide (https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification). For data structures of different field types, refer to the data structure overview (https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure).
+      zh_Hans: |
+        本次请求将要更新的记录列表,示例值:[{"fields":{"多行文本":"文本内容","单选":"选项 1","日期":1674206443000},"record_id":"recupK4f4RM5RX"}]。
+        当前接口支持的字段类型请参考接入指南(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification),不同类型字段的数据结构请参考数据结构概述(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure)。
+    llm_description: |
+      本次请求将要更新的记录列表,示例值:[{"fields":{"多行文本":"文本内容","单选":"选项 1","日期":1674206443000},"record_id":"recupK4f4RM5RX"}]。
+      当前接口支持的字段类型请参考接入指南(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification),不同类型字段的数据结构请参考数据结构概述(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure)。
+    form: llm
+
+  - name: user_id_type
+    type: select
+    required: false
+    options:
+      - value: open_id
+        label:
+          en_US: open_id
+          zh_Hans: open_id
+      - value: union_id
+        label:
+          en_US: union_id
+          zh_Hans: union_id
+      - value: user_id
+        label:
+          en_US: user_id
+          zh_Hans: user_id
+    default: "open_id"
+    label:
+      en_US: user_id_type
+      zh_Hans: 用户 ID 类型
+    human_description:
+      en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
+      zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
+    form: form

+ 303 - 0
api/core/tools/utils/feishu_api_utils.py

@@ -1,3 +1,4 @@
+import json
 from typing import Optional
 
 import httpx
@@ -17,6 +18,41 @@ def auth(credentials):
         raise ToolProviderCredentialValidationError(str(e))
 
 
+def convert_add_records(json_str):
+    try:
+        data = json.loads(json_str)
+        if not isinstance(data, list):
+            raise ValueError("Parsed data must be a list")
+        converted_data = [{"fields": json.dumps(item, ensure_ascii=False)} for item in data]
+        return converted_data
+    except json.JSONDecodeError:
+        raise ValueError("The input string is not valid JSON")
+    except Exception as e:
+        raise ValueError(f"An error occurred while processing the data: {e}")
+
+
+def convert_update_records(json_str):
+    try:
+        data = json.loads(json_str)
+        if not isinstance(data, list):
+            raise ValueError("Parsed data must be a list")
+
+        converted_data = [
+            {"fields": json.dumps(record["fields"], ensure_ascii=False), "record_id": record["record_id"]}
+            for record in data
+            if "fields" in record and "record_id" in record
+        ]
+
+        if len(converted_data) != len(data):
+            raise ValueError("Each record must contain 'fields' and 'record_id'")
+
+        return converted_data
+    except json.JSONDecodeError:
+        raise ValueError("The input string is not valid JSON")
+    except Exception as e:
+        raise ValueError(f"An error occurred while processing the data: {e}")
+
+
 class FeishuRequest:
     API_BASE_URL = "https://lark-plugin-api.solutionsuite.cn/lark-plugin"
 
@@ -517,3 +553,270 @@ class FeishuRequest:
         }
         res = self._send_request(url, method="GET", params=params)
         return res.get("data")
+
+    def create_base(
+        self,
+        name: str,
+        folder_token: str,
+    ) -> dict:
+        # 创建多维表格
+        url = f"{self.API_BASE_URL}/base/create_base"
+        payload = {
+            "name": name,
+            "folder_token": folder_token,
+        }
+        res = self._send_request(url, payload=payload)
+        return res.get("data")
+
+    def add_records(
+        self,
+        app_token: str,
+        table_id: str,
+        table_name: str,
+        records: str,
+        user_id_type: str = "open_id",
+    ) -> dict:
+        # 新增多条记录
+        url = f"{self.API_BASE_URL}/base/add_records"
+        params = {
+            "app_token": app_token,
+            "table_id": table_id,
+            "table_name": table_name,
+            "user_id_type": user_id_type,
+        }
+        payload = {
+            "records": convert_add_records(records),
+        }
+        res = self._send_request(url, params=params, payload=payload)
+        return res.get("data")
+
+    def update_records(
+        self,
+        app_token: str,
+        table_id: str,
+        table_name: str,
+        records: str,
+        user_id_type: str,
+    ) -> dict:
+        # 更新多条记录
+        url = f"{self.API_BASE_URL}/base/update_records"
+        params = {
+            "app_token": app_token,
+            "table_id": table_id,
+            "table_name": table_name,
+            "user_id_type": user_id_type,
+        }
+        payload = {
+            "records": convert_update_records(records),
+        }
+        res = self._send_request(url, params=params, payload=payload)
+        return res.get("data")
+
+    def delete_records(
+        self,
+        app_token: str,
+        table_id: str,
+        table_name: str,
+        record_ids: str,
+    ) -> dict:
+        # 删除多条记录
+        url = f"{self.API_BASE_URL}/base/delete_records"
+        params = {
+            "app_token": app_token,
+            "table_id": table_id,
+            "table_name": table_name,
+        }
+        if not record_ids:
+            record_id_list = []
+        else:
+            try:
+                record_id_list = json.loads(record_ids)
+            except json.JSONDecodeError:
+                raise ValueError("The input string is not valid JSON")
+        payload = {
+            "records": record_id_list,
+        }
+        res = self._send_request(url, params=params, payload=payload)
+        return res.get("data")
+
+    def search_record(
+        self,
+        app_token: str,
+        table_id: str,
+        table_name: str,
+        view_id: str,
+        field_names: str,
+        sort: str,
+        filters: str,
+        page_token: str,
+        automatic_fields: bool = False,
+        user_id_type: str = "open_id",
+        page_size: int = 20,
+    ) -> dict:
+        # 查询记录,单次最多查询 500 行记录。
+        url = f"{self.API_BASE_URL}/base/search_record"
+        params = {
+            "app_token": app_token,
+            "table_id": table_id,
+            "table_name": table_name,
+            "user_id_type": user_id_type,
+            "page_token": page_token,
+            "page_size": page_size,
+        }
+
+        if not field_names:
+            field_name_list = []
+        else:
+            try:
+                field_name_list = json.loads(field_names)
+            except json.JSONDecodeError:
+                raise ValueError("The input string is not valid JSON")
+
+        if not sort:
+            sort_list = []
+        else:
+            try:
+                sort_list = json.loads(sort)
+            except json.JSONDecodeError:
+                raise ValueError("The input string is not valid JSON")
+
+        if not filters:
+            filter_dict = {}
+        else:
+            try:
+                filter_dict = json.loads(filters)
+            except json.JSONDecodeError:
+                raise ValueError("The input string is not valid JSON")
+
+        payload = {}
+
+        if view_id:
+            payload["view_id"] = view_id
+        if field_names:
+            payload["field_names"] = field_name_list
+        if sort:
+            payload["sort"] = sort_list
+        if filters:
+            payload["filter"] = filter_dict
+        if automatic_fields:
+            payload["automatic_fields"] = automatic_fields
+        res = self._send_request(url, params=params, payload=payload)
+        return res.get("data")
+
+    def get_base_info(
+        self,
+        app_token: str,
+    ) -> dict:
+        # 获取多维表格元数据
+        url = f"{self.API_BASE_URL}/base/get_base_info"
+        params = {
+            "app_token": app_token,
+        }
+        res = self._send_request(url, method="GET", params=params)
+        return res.get("data")
+
+    def create_table(
+        self,
+        app_token: str,
+        table_name: str,
+        default_view_name: str,
+        fields: str,
+    ) -> dict:
+        # 新增一个数据表
+        url = f"{self.API_BASE_URL}/base/create_table"
+        params = {
+            "app_token": app_token,
+        }
+        if not fields:
+            fields_list = []
+        else:
+            try:
+                fields_list = json.loads(fields)
+            except json.JSONDecodeError:
+                raise ValueError("The input string is not valid JSON")
+        payload = {
+            "name": table_name,
+            "fields": fields_list,
+        }
+        if default_view_name:
+            payload["default_view_name"] = default_view_name
+        res = self._send_request(url, params=params, payload=payload)
+        return res.get("data")
+
+    def delete_tables(
+        self,
+        app_token: str,
+        table_ids: str,
+        table_names: str,
+    ) -> dict:
+        # 删除多个数据表
+        url = f"{self.API_BASE_URL}/base/delete_tables"
+        params = {
+            "app_token": app_token,
+        }
+        if not table_ids:
+            table_id_list = []
+        else:
+            try:
+                table_id_list = json.loads(table_ids)
+            except json.JSONDecodeError:
+                raise ValueError("The input string is not valid JSON")
+
+        if not table_names:
+            table_name_list = []
+        else:
+            try:
+                table_name_list = json.loads(table_names)
+            except json.JSONDecodeError:
+                raise ValueError("The input string is not valid JSON")
+
+        payload = {
+            "table_ids": table_id_list,
+            "table_names": table_name_list,
+        }
+        res = self._send_request(url, params=params, payload=payload)
+        return res.get("data")
+
+    def list_tables(
+        self,
+        app_token: str,
+        page_token: str,
+        page_size: int = 20,
+    ) -> dict:
+        # 列出多维表格下的全部数据表
+        url = f"{self.API_BASE_URL}/base/list_tables"
+        params = {
+            "app_token": app_token,
+            "page_token": page_token,
+            "page_size": page_size,
+        }
+        res = self._send_request(url, method="GET", params=params)
+        return res.get("data")
+
+    def read_records(
+        self,
+        app_token: str,
+        table_id: str,
+        table_name: str,
+        record_ids: str,
+        user_id_type: str = "open_id",
+    ) -> dict:
+        url = f"{self.API_BASE_URL}/base/read_records"
+        params = {
+            "app_token": app_token,
+            "table_id": table_id,
+            "table_name": table_name,
+        }
+        if not record_ids:
+            record_id_list = []
+        else:
+            try:
+                record_id_list = json.loads(record_ids)
+            except json.JSONDecodeError:
+                raise ValueError("The input string is not valid JSON")
+        payload = {
+            "record_ids": record_id_list,
+            "user_id_type": user_id_type,
+        }
+        res = self._send_request(url, method="GET", params=params, payload=payload)
+        return res.get("data")