Underground-Digital/Workflow-Engine
0
1import json2from collections.abc import Mapping3from datetime import datetime4from typing import Any, Optional5 6from sqlalchemy import or_7 8from core.model_runtime.utils.encoders import jsonable_encoder9from core.tools.entities.api_entities import UserToolProvider10from core.tools.provider.workflow_tool_provider import WorkflowToolProviderController11from core.tools.tool_label_manager import ToolLabelManager12from core.tools.utils.workflow_configuration_sync import WorkflowToolConfigurationUtils13from extensions.ext_database import db14from models.model import App15from models.tools import WorkflowToolProvider16from models.workflow import Workflow17from services.tools.tools_transform_service import ToolTransformService18 19 20class WorkflowToolManageService:21 """22 Service class for managing workflow tools.23 """24 25 @staticmethod26 def create_workflow_tool(27 *,28 user_id: str,29 tenant_id: str,30 workflow_app_id: str,31 name: str,32 label: str,33 icon: dict,34 description: str,35 parameters: Mapping[str, Any],36 privacy_policy: str = "",37 labels: Optional[list[str]] = None,38 ) -> dict:39 WorkflowToolConfigurationUtils.check_parameter_configurations(parameters)40 41 # check if the name is unique42 existing_workflow_tool_provider = (43 db.session.query(WorkflowToolProvider)44 .filter(45 WorkflowToolProvider.tenant_id == tenant_id,46 # name or app_id47 or_(WorkflowToolProvider.name == name, WorkflowToolProvider.app_id == workflow_app_id),48 )49 .first()50 )51 52 if existing_workflow_tool_provider is not None:53 raise ValueError(f"Tool with name {name} or app_id {workflow_app_id} already exists")54 55 app = db.session.query(App).filter(App.id == workflow_app_id, App.tenant_id == tenant_id).first()56 if app is None:57 raise ValueError(f"App {workflow_app_id} not found")58 59 workflow = app.workflow60 if workflow is None:61 raise ValueError(f"Workflow not found for app {workflow_app_id}")62 63 workflow_tool_provider = WorkflowToolProvider(64 tenant_id=tenant_id,65 user_id=user_id,66 app_id=workflow_app_id,67 name=name,68 label=label,69 icon=json.dumps(icon),70 description=description,71 parameter_configuration=json.dumps(parameters),72 privacy_policy=privacy_policy,73 version=workflow.version,74 )75 76 try:77 WorkflowToolProviderController.from_db(workflow_tool_provider)78 except Exception as e:79 raise ValueError(str(e))80 81 db.session.add(workflow_tool_provider)82 db.session.commit()83 84 return {"result": "success"}85 86 @classmethod87 def update_workflow_tool(88 cls,89 user_id: str,90 tenant_id: str,91 workflow_tool_id: str,92 name: str,93 label: str,94 icon: dict,95 description: str,96 parameters: list[dict],97 privacy_policy: str = "",98 labels: Optional[list[str]] = None,99 ) -> dict:100 """101 Update a workflow tool.102 :param user_id: the user id103 :param tenant_id: the tenant id104 :param workflow_tool_id: workflow tool id105 :param name: name106 :param label: label107 :param icon: icon108 :param description: description109 :param parameters: parameters110 :param privacy_policy: privacy policy111 :param labels: labels112 :return: the updated tool113 """114 WorkflowToolConfigurationUtils.check_parameter_configurations(parameters)115 116 # check if the name is unique117 existing_workflow_tool_provider = (118 db.session.query(WorkflowToolProvider)119 .filter(120 WorkflowToolProvider.tenant_id == tenant_id,121 WorkflowToolProvider.name == name,122 WorkflowToolProvider.id != workflow_tool_id,123 )124 .first()125 )126 127 if existing_workflow_tool_provider is not None:128 raise ValueError(f"Tool with name {name} already exists")129 130 workflow_tool_provider: WorkflowToolProvider = (131 db.session.query(WorkflowToolProvider)132 .filter(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == workflow_tool_id)133 .first()134 )135 136 if workflow_tool_provider is None:137 raise ValueError(f"Tool {workflow_tool_id} not found")138 139 app: App = (140 db.session.query(App).filter(App.id == workflow_tool_provider.app_id, App.tenant_id == tenant_id).first()141 )142 143 if app is None:144 raise ValueError(f"App {workflow_tool_provider.app_id} not found")145 146 workflow: Workflow = app.workflow147 if workflow is None:148 raise ValueError(f"Workflow not found for app {workflow_tool_provider.app_id}")149 150 workflow_tool_provider.name = name151 workflow_tool_provider.label = label152 workflow_tool_provider.icon = json.dumps(icon)153 workflow_tool_provider.description = description154 workflow_tool_provider.parameter_configuration = json.dumps(parameters)155 workflow_tool_provider.privacy_policy = privacy_policy156 workflow_tool_provider.version = workflow.version157 workflow_tool_provider.updated_at = datetime.now()158 159 try:160 WorkflowToolProviderController.from_db(workflow_tool_provider)161 except Exception as e:162 raise ValueError(str(e))163 164 db.session.add(workflow_tool_provider)165 db.session.commit()166 167 if labels is not None:168 ToolLabelManager.update_tool_labels(169 ToolTransformService.workflow_provider_to_controller(workflow_tool_provider), labels170 )171 172 return {"result": "success"}173 174 @classmethod175 def list_tenant_workflow_tools(cls, user_id: str, tenant_id: str) -> list[UserToolProvider]:176 """177 List workflow tools.178 :param user_id: the user id179 :param tenant_id: the tenant id180 :return: the list of tools181 """182 db_tools = db.session.query(WorkflowToolProvider).filter(WorkflowToolProvider.tenant_id == tenant_id).all()183 184 tools = []185 for provider in db_tools:186 try:187 tools.append(ToolTransformService.workflow_provider_to_controller(provider))188 except:189 # skip deleted tools190 pass191 192 labels = ToolLabelManager.get_tools_labels(tools)193 194 result = []195 196 for tool in tools:197 user_tool_provider = ToolTransformService.workflow_provider_to_user_provider(198 provider_controller=tool, labels=labels.get(tool.provider_id, [])199 )200 ToolTransformService.repack_provider(user_tool_provider)201 user_tool_provider.tools = [202 ToolTransformService.tool_to_user_tool(203 tool.get_tools(user_id, tenant_id)[0], labels=labels.get(tool.provider_id, [])204 )205 ]206 result.append(user_tool_provider)207 208 return result209 210 @classmethod211 def delete_workflow_tool(cls, user_id: str, tenant_id: str, workflow_tool_id: str) -> dict:212 """213 Delete a workflow tool.214 :param user_id: the user id215 :param tenant_id: the tenant id216 :param workflow_app_id: the workflow app id217 """218 db.session.query(WorkflowToolProvider).filter(219 WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == workflow_tool_id220 ).delete()221 222 db.session.commit()223 224 return {"result": "success"}225 226 @classmethod227 def get_workflow_tool_by_tool_id(cls, user_id: str, tenant_id: str, workflow_tool_id: str) -> dict:228 """229 Get a workflow tool.230 :param user_id: the user id231 :param tenant_id: the tenant id232 :param workflow_app_id: the workflow app id233 :return: the tool234 """235 db_tool: WorkflowToolProvider = (236 db.session.query(WorkflowToolProvider)237 .filter(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == workflow_tool_id)238 .first()239 )240 241 if db_tool is None:242 raise ValueError(f"Tool {workflow_tool_id} not found")243 244 workflow_app: App = db.session.query(App).filter(App.id == db_tool.app_id, App.tenant_id == tenant_id).first()245 246 if workflow_app is None:247 raise ValueError(f"App {db_tool.app_id} not found")248 249 tool = ToolTransformService.workflow_provider_to_controller(db_tool)250 251 return {252 "name": db_tool.name,253 "label": db_tool.label,254 "workflow_tool_id": db_tool.id,255 "workflow_app_id": db_tool.app_id,256 "icon": json.loads(db_tool.icon),257 "description": db_tool.description,258 "parameters": jsonable_encoder(db_tool.parameter_configurations),259 "tool": ToolTransformService.tool_to_user_tool(260 tool.get_tools(user_id, tenant_id)[0], labels=ToolLabelManager.get_tool_labels(tool)261 ),262 "synced": workflow_app.workflow.version == db_tool.version,263 "privacy_policy": db_tool.privacy_policy,264 }265 266 @classmethod267 def get_workflow_tool_by_app_id(cls, user_id: str, tenant_id: str, workflow_app_id: str) -> dict:268 """269 Get a workflow tool.270 :param user_id: the user id271 :param tenant_id: the tenant id272 :param workflow_app_id: the workflow app id273 :return: the tool274 """275 db_tool: WorkflowToolProvider = (276 db.session.query(WorkflowToolProvider)277 .filter(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.app_id == workflow_app_id)278 .first()279 )280 281 if db_tool is None:282 raise ValueError(f"Tool {workflow_app_id} not found")283 284 workflow_app: App = db.session.query(App).filter(App.id == db_tool.app_id, App.tenant_id == tenant_id).first()285 286 if workflow_app is None:287 raise ValueError(f"App {db_tool.app_id} not found")288 289 tool = ToolTransformService.workflow_provider_to_controller(db_tool)290 291 return {292 "name": db_tool.name,293 "label": db_tool.label,294 "workflow_tool_id": db_tool.id,295 "workflow_app_id": db_tool.app_id,296 "icon": json.loads(db_tool.icon),297 "description": db_tool.description,298 "parameters": jsonable_encoder(db_tool.parameter_configurations),299 "tool": ToolTransformService.tool_to_user_tool(300 tool.get_tools(user_id, tenant_id)[0], labels=ToolLabelManager.get_tool_labels(tool)301 ),302 "synced": workflow_app.workflow.version == db_tool.version,303 "privacy_policy": db_tool.privacy_policy,304 }305 306 @classmethod307 def list_single_workflow_tools(cls, user_id: str, tenant_id: str, workflow_tool_id: str) -> list[dict]:308 """309 List workflow tool provider tools.310 :param user_id: the user id311 :param tenant_id: the tenant id312 :param workflow_app_id: the workflow app id313 :return: the list of tools314 """315 db_tool: WorkflowToolProvider = (316 db.session.query(WorkflowToolProvider)317 .filter(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == workflow_tool_id)318 .first()319 )320 321 if db_tool is None:322 raise ValueError(f"Tool {workflow_tool_id} not found")323 324 tool = ToolTransformService.workflow_provider_to_controller(db_tool)325 326 return [327 ToolTransformService.tool_to_user_tool(328 tool.get_tools(user_id, tenant_id)[0], labels=ToolLabelManager.get_tool_labels(tool)329 )330 ]331 