Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions apps/locales/en_US/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -9236,6 +9236,5 @@ msgstr "Batch delete"
msgid "Batch move"
msgstr "Batch move"




msgid "There is a circular dependency in the tool workflow"
msgstr "There is a circular dependency in the tool workflow"
3 changes: 3 additions & 0 deletions apps/locales/zh_CN/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -9358,3 +9358,6 @@ msgstr "批量删除"

msgid "Batch move"
msgstr "批量移动"

msgid "There is a circular dependency in the tool workflow"
msgstr "工具工作流存在循环依赖"
3 changes: 2 additions & 1 deletion apps/locales/zh_Hant/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -9356,4 +9356,5 @@ msgstr "批量刪除"
msgid "Batch move"
msgstr "批量移動"


msgid "There is a circular dependency in the tool workflow"
msgstr "工具工作流存在迴圈依賴"
47 changes: 46 additions & 1 deletion apps/tools/serializers/tool_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from django.db.models import QuerySet, Q
from django.http import HttpResponse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_lazy as _, gettext
from rest_framework import serializers, status
from rest_framework.utils.formatting import lazy_format

Expand Down Expand Up @@ -52,6 +52,47 @@
tool_executor = ToolExecutor()


def is_valid_tool_workflow_circular_dependency(workflow, _id, visited=None, stack=None):
"""
workflow: 当前要检查的 workflow 对象
visited: 全局已经访问过的 workflow id
stack: 当前递归栈里的 workflow id
"""
if visited is None:
visited = set()
if stack is None:
stack = set()

if _id in stack:
return False

if _id in visited:
return True

stack.add(_id)

for node in workflow.get('nodes', []):
child_tool_ids = []
if node.get('type') == 'ai-chat-node':
node_data = node.get('properties', {}).get('node_data', {})
child_tool_ids = node_data.get('tool_ids') or []
if node.get('type') == 'tool-workflow-lib-node':
child_tool_id = node.get('properties', {}).get('node_data', {}).get('tool_lib_id')
child_tool_ids.append(child_tool_id)
for child_tool_id in child_tool_ids:
if child_tool_id:
child_workflow = QuerySet(ToolWorkflow).filter(tool_id=child_tool_id).first()
if child_workflow:
if not is_valid_tool_workflow_circular_dependency(child_workflow.work_flow, str(child_tool_id),
visited,
stack):
return False

stack.remove(_id)
visited.add(_id)
return True


def hand_node(node, update_tool_map):
if node.get('type') == 'tool-lib-node':
tool_lib_id = (node.get('properties', {}).get('node_data', {}).get('tool_lib_id') or '')
Expand Down Expand Up @@ -233,6 +274,10 @@ def edit(self, instance: Dict):
tool = QuerySet(Tool).filter(id=self.data.get("tool_id")).first()
workflow_id = tool.workspace_id
if instance.get("work_flow"):
dependency = is_valid_tool_workflow_circular_dependency(workflow=instance.get('work_flow'),
_id=str(tool.id))
if not dependency:
raise Exception(gettext('There is a circular dependency in the tool workflow'))
QuerySet(ToolWorkflow).update_or_create(tool_id=self.data.get("tool_id"),
create_defaults={'id': uuid.uuid7(),
'tool_id': self.data.get(
Expand Down
Loading