1818from langchain_core .messages import AIMessage , HumanMessage , SystemMessage , ToolMessage
1919from rest_framework import serializers
2020
21+ from application .workflow .message .aggregator import AggregationManager
2122from application .flow .tools import get_tools , mcp_response_generator
2223from application .models import Application , ApplicationAccessToken , ApplicationApiKey
2324from application .workflow .common import WorkflowType
2425from application .workflow .i_node import INode
25- from application .workflow .message .struct .content import NodeInfo , Position
26+ from application .workflow .message .struct .content import NodeInfo , Position , Content
2627from application .workflow .message .struct .reasoning_content import ReasoningContent
2728from application .workflow .message .struct .text_content import TextContent
2829from application .workflow .message .struct .tool_content import ToolContent
2930from application .workflow .status import Status
3031from application .workflow .tools import Reasoning
3132from common .exception .app_exception import AppApiException
3233from common .utils .common import guess_image_format
34+ from common .utils .messages_util import to_ai_message_list , to_human_message_list
3335from common .utils .rsa_util import rsa_long_decrypt
3436from common .utils .shared_resource_auth import filter_authorized_ids
3537from common .utils .tool_code import ToolExecutor
@@ -96,7 +98,8 @@ def _get_node_message(chat_record, runtime_node_id):
9698 node_details = chat_record .get_node_details_runtime_node_id (runtime_node_id )
9799 if node_details is None :
98100 return []
99- return [HumanMessage (node_details .get ("question" )), AIMessage (node_details .get ("answer" ))]
101+ return [* to_human_message_list (node_details .get ("question" )), * to_ai_message_list (node_details .get ("messages" ))]
102+ return [HumanMessage (node_details .get ("question" )), AIMessage (node_details .get ("messages" ))]
100103
101104
102105def _get_workflow_message (chat_record ):
@@ -193,6 +196,12 @@ class AIChatNode(INode):
193196 supported_workflow_type_list = [WorkflowType .APPLICATION , WorkflowType .KNOWLEDGE , WorkflowType .TOOL ]
194197 type = "ai-chat-node"
195198
199+ def write (self , message : Content ):
200+ super ().write (message )
201+ if not self .data .get ("messages" ):
202+ self .data ["messages" ] = []
203+ self .data ["messages" ].append (message )
204+
196205 def execute (self ):
197206 workflow_params = self .get_workflow_parameters ()
198207 node_params = self .get_parameters ()
@@ -254,7 +263,7 @@ def execute(self):
254263 "reasoning_content_end" : "</think>" ,
255264 "reasoning_content_start" : "<think>" ,
256265 }
257- self .write_context ( "model_setting" , model_setting )
266+ self .data [ "model_setting" ] = model_setting
258267
259268 chat_model = get_model_instance_by_model_workspace_id (model_id , workspace_id , ** (model_params_setting or {}))
260269
@@ -263,12 +272,12 @@ def execute(self):
263272 "history_message" ,
264273 [{"content" : message .content , "role" : message .type } for message in (history_message or [])],
265274 )
266-
267- question = self ._generate_prompt_question (prompt , chat_model , vision , image_list , video_list )
268- self .write_context ( "question" , question . content )
275+ question_str = self . workflow_manage . generate_prompt ( prompt )
276+ question = self ._generate_prompt_question (question_str , chat_model , vision , image_list , video_list )
277+ self .data [ "question" ] = { " content" : question_str , "image_list" : image_list , "video_list" : video_list }
269278
270279 system = self .workflow_manage .generate_prompt (system )
271- self .write_context ( "system" , system )
280+ self .data [ "system" ] = system
272281
273282 message_list = [* history_message , question ]
274283
@@ -321,7 +330,7 @@ def execute(self):
321330 r , chat_model , message_list_with_system , question .content , is_result , text_content_id
322331 )
323332
324- def _generate_prompt_question (self , prompt , model , vision , image_list , video_list ):
333+ def _generate_prompt_question (self , question_str , model , vision , image_list , video_list ):
325334 images = []
326335 videos = []
327336 if vision :
@@ -334,9 +343,7 @@ def _generate_prompt_question(self, prompt, model, vision, image_list, video_lis
334343 if video_list :
335344 video = self .workflow_manage .get_reference_field (video_list [0 ], video_list [1 :])
336345 videos = _process_videos (video , model )
337- return HumanMessage (
338- content = [* videos , * images , {"type" : "text" , "text" : self .workflow_manage .generate_prompt (prompt )}]
339- )
346+ return HumanMessage (content = [* videos , * images , {"type" : "text" , "text" : question_str }])
340347
341348 def _stream_response (self , response , chat_model , message_list , question , reasoning_content_id , text_content_id ):
342349 node_info = NodeInfo (self .get_node_id (), self .get_node_name (), Status .RUNNING )
@@ -436,11 +443,10 @@ def _invoke_response(self, response, chat_model, message_list, question, is_resu
436443 def _write_final_context (self , chat_model , message_list , question , answer , reasoning_content ):
437444 message_tokens = chat_model .get_num_tokens_from_messages (message_list )
438445 answer_tokens = chat_model .get_num_tokens (answer )
439- self .write_context ( "message_tokens" , message_tokens )
440- self .write_context ( "answer_tokens" , answer_tokens )
446+ self .data [ "message_tokens" ] = message_tokens
447+ self .data [ "answer_tokens" ] = answer_tokens
441448 self .write_context ("answer" , answer )
442- self .write_context ("question" , question )
443- self .write_context ("reasoning_content" , reasoning_content )
449+ self .data ["reasoning_content" ] = reasoning_content
444450
445451 def _handle_mcp (
446452 self ,
@@ -498,7 +504,6 @@ def _handle_mcp(
498504
499505 tools = get_tools (source_type , chat_id , tool_ids , workspace_id )
500506 if tool_ids and len (tool_ids ) > 0 :
501- self .write_context ("tool_ids" , tool_ids )
502507 custom_tools_map = {
503508 str (t .id ): t for t in QuerySet (Tool ).filter (id__in = tool_ids , tool_type = ToolType .CUSTOM , is_active = True )
504509 }
@@ -516,7 +521,6 @@ def _handle_mcp(
516521 mcp_servers_config [str (tool .id )] = tool_config
517522
518523 if application_ids and len (application_ids ) > 0 :
519- self .write_context ("application_ids" , application_ids )
520524 apps_map = {str (a .id ): a for a in QuerySet (Application ).filter (id__in = application_ids , is_publish = True )}
521525 app_keys_map = {
522526 str (ak .application_id ): ak
@@ -550,7 +554,6 @@ def _handle_mcp(
550554 mcp_servers_config [app .name ] = app_config
551555
552556 if skill_tool_ids and len (skill_tool_ids ) > 0 :
553- self .write_context ("skill_tool_ids" , skill_tool_ids )
554557 skill_file_items = []
555558 skill_tools_map = {str (t .id ): t for t in QuerySet (Tool ).filter (id__in = skill_tool_ids , is_active = True )}
556559 for tool_id in skill_tool_ids :
@@ -632,14 +635,19 @@ def _get_reference_content(self, fields):
632635
633636 def get_details (self , index : int = 0 , position : dict = None , old_details : dict = None , ** kwargs ):
634637 details = super ().get_details (index , position , old_details , ** kwargs )
638+ aggregation = AggregationManager ()
639+ for m in self .data .get ("messages" ):
640+ aggregation .aggregate (m )
641+ messages = aggregation .get_contents ()
635642 details .update (
636643 {
637- "question" : self .get_context ("question" ),
644+ "question" : self .data . get ("question" ),
638645 "answer" : self .get_context ("answer" ),
639646 "reasoning_content" : self .get_context ("reasoning_content" ),
640647 "message_tokens" : self .get_context ("message_tokens" ),
641648 "answer_tokens" : self .get_context ("answer_tokens" ),
642649 "history_message" : self .get_context ("history_message" ),
650+ "messages" : messages ,
643651 }
644652 )
645653 return details
0 commit comments