From e5c818d1a576e81106cef84bc9dd8ec09087d169 Mon Sep 17 00:00:00 2001 From: jingrow Date: Fri, 21 Nov 2025 11:37:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BA=20Local=20Tool=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=AE=8C=E6=95=B4=E7=9A=84=20API=20=E7=AB=AF=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 get_local_tool_list: 获取公开工具列表 - 新增 get_my_local_tool_list: 获取当前团队工具列表 - 新增 get_local_tool: 获取工具详情 - 新增 create_local_tool: 创建工具 - 新增 update_local_tool: 更新工具 - 新增 delete_local_tool: 删除工具 参考 Local Node 和 Local App 的实现模式,包含团队权限验证和批量查询优化 --- jcloud/api/jlocal.py | 245 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/jcloud/api/jlocal.py b/jcloud/api/jlocal.py index 23737cf..93408f5 100644 --- a/jcloud/api/jlocal.py +++ b/jcloud/api/jlocal.py @@ -221,6 +221,63 @@ def get_local_agent_list(filters=None, order_by=None, limit_start=None, limit_pa return result +@jingrow.whitelist(allow_guest=True) +def get_local_tool_list(filters=None, order_by=None, limit_start=None, limit_page_length=None): + """获取本地工具列表""" + + # 构建查询条件 + query_filters = {"public": 1} + + if filters: + if isinstance(filters, str): + import json + filters = json.loads(filters) + query_filters.update(filters) + + # 默认排序 + if not order_by: + order_by = "tool_name asc" + + # 获取工具列表 + tools = jingrow.get_all( + "Local Tool", + filters=query_filters, + fields=[ + "name", "tool_name", "title", "subtitle", + "enabled", "public", "team", "status", "repository_url", + "file_url", "tool_image", "creation", "modified" + ], + order_by=order_by, + limit_start=limit_start, + limit_page_length=limit_page_length + ) + + # 批量获取团队用户名称 + team_user_names = _get_team_user_names(tools) + + # 格式化返回数据 + result = [] + for tool in tools: + tool_data = { + "name": tool.name, + "tool_name": tool.tool_name, + "title": tool.title, + "subtitle": tool.subtitle, + "enabled": tool.enabled, + "public": tool.public, + "team": team_user_names.get(tool.team), + "status": tool.status, + "repository_url": tool.repository_url, + "file_url": tool.file_url, + "tool_image": tool.tool_image, + "creation": tool.creation, + "modified": tool.modified + } + result.append(tool_data) + + return result + + @jingrow.whitelist(allow_guest=True) def get_local_app(name): """获取本地应用详情""" @@ -638,6 +695,67 @@ def get_my_local_agent_list(filters=None, order_by=None, limit_start=None, limit return result +@dashboard_whitelist() +def get_my_local_tool_list(filters=None, order_by=None, limit_start=None, limit_page_length=None): + """获取当前团队的工具列表""" + + team = get_current_team() + if not team: + return {"success": False, "message": "未找到当前团队信息"} + + # 构建查询条件 + query_filters = {"team": team} + + if filters: + if isinstance(filters, str): + import json + filters = json.loads(filters) + query_filters.update(filters) + + # 默认排序 + if not order_by: + order_by = "tool_name asc" + + # 获取工具列表 + tools = jingrow.get_all( + "Local Tool", + filters=query_filters, + fields=[ + "name", "tool_name", "title", "subtitle", + "enabled", "public", "team", "status", "repository_url", + "file_url", "tool_image", "creation", "modified" + ], + order_by=order_by, + limit_start=limit_start, + limit_page_length=limit_page_length + ) + + # 批量获取团队用户名称 + team_user_names = _get_team_user_names(tools) + + # 格式化返回数据 + result = [] + for tool in tools: + tool_data = { + "name": tool.name, + "tool_name": tool.tool_name, + "title": tool.title, + "subtitle": tool.subtitle, + "enabled": tool.enabled, + "public": tool.public, + "team": team_user_names.get(tool.team), + "status": tool.status, + "repository_url": tool.repository_url, + "file_url": tool.file_url, + "tool_image": tool.tool_image, + "creation": tool.creation, + "modified": tool.modified + } + result.append(tool_data) + + return result + + @jingrow.whitelist(allow_guest=True) def get_local_agent(name): """获取本地Agent详情""" @@ -671,6 +789,38 @@ def get_local_agent(name): return agent_data +@jingrow.whitelist(allow_guest=True) +def get_local_tool(name): + """获取本地工具详情""" + + if not jingrow.db.exists("Local Tool", name): + return {"success": False, "message": "工具不存在"} + + tool = jingrow.get_pg("Local Tool", name) + + # 获取团队关联用户的名称 + team_user_names = _get_team_user_names([tool]) + + tool_data = { + "name": tool.name, + "tool_name": tool.tool_name, + "title": tool.title, + "subtitle": tool.subtitle, + "description": tool.description, + "enabled": tool.enabled, + "public": tool.public, + "team": team_user_names.get(tool.team), + "status": tool.status, + "repository_url": tool.repository_url, + "file_url": tool.file_url, + "tool_image": tool.tool_image, + "creation": tool.creation, + "modified": tool.modified + } + + return tool_data + + @dashboard_whitelist() def create_local_agent(agent_data): """创建本地Agent""" @@ -705,6 +855,37 @@ def create_local_agent(agent_data): return {"success": True, "name": agent.name, "message": "Agent创建成功"} +@dashboard_whitelist() +def create_local_tool(tool_data): + """创建本地工具""" + team = get_current_team() + + if isinstance(tool_data, str): + import json + tool_data = json.loads(tool_data) + + # 检查工具名称是否已存在 + existing_tool = jingrow.db.exists("Local Tool", {"tool_name": tool_data["tool_name"]}) + if existing_tool: + return {"error": "工具名称已存在,请使用其他名称"} + + # 创建工具 + tool = jingrow.get_pg({ + "pagetype": "Local Tool", + "tool_name": tool_data["tool_name"], + "title": tool_data["title"], + "subtitle": tool_data.get("subtitle", ""), + "description": tool_data.get("description", ""), + "team": team, + "repository_url": tool_data.get("repository_url"), + "file_url": tool_data.get("file_url"), + "tool_image": tool_data.get("tool_image") + }) + + tool.insert() + return {"success": True, "name": tool.name, "message": "工具创建成功"} + + @dashboard_whitelist() def update_local_agent(name, agent_data): """更新本地Agent""" @@ -746,6 +927,47 @@ def update_local_agent(name, agent_data): return {"success": True, "name": agent.name, "updated_fields": updated_fields, "message": "Agent更新成功"} +@dashboard_whitelist() +def update_local_tool(name, tool_data): + """更新本地工具""" + + team = get_current_team() + if not team: + return {"success": False, "message": "未找到当前团队信息"} + + if not jingrow.db.exists("Local Tool", name): + return {"success": False, "message": "工具不存在"} + + tool = jingrow.get_pg("Local Tool", name) + + # 验证权限:只能更新自己团队的工具 + if tool.team != team: + return {"success": False, "message": "您没有权限操作此工具"} + + # 解析 JSON 数据 + if isinstance(tool_data, str): + try: + import json + tool_data = json.loads(tool_data) + except json.JSONDecodeError: + return {"success": False, "message": "JSON 数据格式错误"} + + # 更新字段 + updated_fields = [] + for field, value in tool_data.items(): + if hasattr(tool, field): + setattr(tool, field, value) + updated_fields.append(field) + + # 检查是否有字段被更新 + if not updated_fields: + return {"success": False, "message": "没有有效的字段被更新"} + + # 使用 ignore_permissions=True 因为我们已经手动验证了团队权限 + tool.save(ignore_permissions=True) + return {"success": True, "name": tool.name, "updated_fields": updated_fields, "message": "工具更新成功"} + + @dashboard_whitelist() def delete_local_node(name): """删除本地节点""" @@ -790,3 +1012,26 @@ def delete_local_agent(name): agent.delete(ignore_permissions=True) return {"success": True, "message": "Agent删除成功"} + + +@dashboard_whitelist() +def delete_local_tool(name): + """删除本地工具""" + + team = get_current_team() + if not team: + return {"success": False, "message": "未找到当前团队信息"} + + if not jingrow.db.exists("Local Tool", name): + return {"success": False, "message": "工具不存在"} + + tool = jingrow.get_pg("Local Tool", name) + + # 验证权限:只能删除自己团队的工具 + if tool.team != team: + return {"success": False, "message": "您没有权限操作此工具"} + + # 使用 ignore_permissions=True 因为我们已经手动验证了团队权限 + tool.delete(ignore_permissions=True) + + return {"success": True, "message": "工具删除成功"}