From ef13a96cd3ed716073e09bb8f4f2f4e38d3ada28 Mon Sep 17 00:00:00 2001 From: shaohuzhang1 Date: Thu, 2 Jul 2026 15:11:21 +0800 Subject: [PATCH] feat: Migration direct reply node --- .../workflow/nodes/reply_node/__init__.py | 9 +++ .../workflow/nodes/reply_node/reply_node.py | 63 +++++++++++++++++++ apps/application/workflow/workflow_manage.py | 7 +-- 3 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 apps/application/workflow/nodes/reply_node/__init__.py create mode 100644 apps/application/workflow/nodes/reply_node/reply_node.py diff --git a/apps/application/workflow/nodes/reply_node/__init__.py b/apps/application/workflow/nodes/reply_node/__init__.py new file mode 100644 index 00000000000..5bdd7388bc7 --- /dev/null +++ b/apps/application/workflow/nodes/reply_node/__init__.py @@ -0,0 +1,9 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎虎虎 + @file: __init__.py + @date:2026/7/2 10:00 + @desc: +""" +from .reply_node import ReplyNode diff --git a/apps/application/workflow/nodes/reply_node/reply_node.py b/apps/application/workflow/nodes/reply_node/reply_node.py new file mode 100644 index 00000000000..cdd79e7acef --- /dev/null +++ b/apps/application/workflow/nodes/reply_node/reply_node.py @@ -0,0 +1,63 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎虎虎 + @file: reply_node.py + @date:2026/7/2 10:00 + @desc: +""" +from typing import List + +from django.utils.translation import gettext_lazy as _ +from rest_framework import serializers + +from application.workflow.common import WorkflowType +from application.workflow.i_node import INode +from application.workflow.message.struct.content import NodeInfo +from application.workflow.message.struct.text_content import TextContent +from application.workflow.status import Status + + +class ReplyNodeSerializer(serializers.Serializer): + reply_type = serializers.CharField(required=True, label=_("Response Type")) + fields = serializers.ListField(required=False, label=_("Reference Field")) + content = serializers.CharField(required=False, allow_blank=True, allow_null=True, + label=_("Direct answer content")) + is_result = serializers.BooleanField(required=False, label=_('Whether to return content')) + + +class ReplyNode(INode): + serializer_class = ReplyNodeSerializer + supported_workflow_type_list = [WorkflowType.APPLICATION, WorkflowType.KNOWLEDGE, WorkflowType.TOOL] + type = 'reply-node' + + def execute(self): + node_params = self.get_parameters() + workflow_params = self.get_workflow_parameters() + chat_record_id = workflow_params.get('chat_record_id') + + reply_type = node_params.get('reply_type') + fields = node_params.get('fields') + content = node_params.get('content') + is_result = node_params.get('is_result', False) + + if reply_type == 'referencing': + result = self._get_reference_content(fields) + else: + result = self._generate_reply_content(content) + + self.write_context('answer', result) + + if is_result: + node_info = NodeInfo(self.get_node_id(), self.get_node_name(), Status.SUCCESS) + self.write(TextContent(str(chat_record_id), result, Status.SUCCESS, node_info)) + + def _generate_reply_content(self, prompt): + if prompt is None: + return '' + return self.workflow_manage.generate_prompt(prompt) + + def _get_reference_content(self, fields: List[str]): + if fields and len(fields) >= 2: + return str(self.workflow_manage.get_reference_field(fields[0], fields[1:])) + return '' diff --git a/apps/application/workflow/workflow_manage.py b/apps/application/workflow/workflow_manage.py index bedf8aea182..b70b720e069 100644 --- a/apps/application/workflow/workflow_manage.py +++ b/apps/application/workflow/workflow_manage.py @@ -62,10 +62,10 @@ def run(self): 工作流执行 @return: None """ + self.nodes.append(self.start_node) self._run_async(self.start_node) def _run(self, node): - self.nodes.append(node) node.run() def next_nodes(self, nodes: Optional[List[Node]]): @@ -84,16 +84,11 @@ def next_nodes(self, nodes: Optional[List[Node]]): self._run_async(inst) def assertion_end(self): - """ - 如果节点执行结束没有下一个节点 就结束工作流 - @return: - """ with self._lock: if self.done: return if not self.is_end(): return - self.done = True self.end() def is_end(self):