| 
					
				 | 
			
			
				@@ -9,6 +9,7 @@ from sqlalchemy.orm import Session 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, InvokeFrom, WorkflowAppGenerateEntity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from core.app.entities.queue_entities import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    QueueAgentLogEvent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     QueueIterationCompletedEvent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     QueueIterationNextEvent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     QueueIterationStartEvent, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -21,6 +22,7 @@ from core.app.entities.queue_entities import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     QueueParallelBranchRunSucceededEvent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from core.app.entities.task_entities import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    AgentLogStreamResponse, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     IterationNodeCompletedStreamResponse, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     IterationNodeNextStreamResponse, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     IterationNodeStartStreamResponse, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -63,6 +65,7 @@ class WorkflowCycleManage: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     _task_state: WorkflowTaskState 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     _workflow_system_variables: dict[SystemVariableKey, Any] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     _wip_workflow_node_executions: dict[str, WorkflowNodeExecution] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    _wip_workflow_agent_logs: dict[str, list[AgentLogStreamResponse.Data]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def _handle_workflow_run_start(self) -> WorkflowRun: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         max_sequence = ( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -283,9 +286,16 @@ class WorkflowCycleManage: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         inputs = WorkflowEntry.handle_special_values(event.inputs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         process_data = WorkflowEntry.handle_special_values(event.process_data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         outputs = WorkflowEntry.handle_special_values(event.outputs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        execution_metadata = ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            json.dumps(jsonable_encoder(event.execution_metadata)) if event.execution_metadata else None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        execution_metadata_dict = event.execution_metadata 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if self._wip_workflow_agent_logs.get(event.node_execution_id): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not execution_metadata_dict: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                execution_metadata_dict = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            execution_metadata_dict[NodeRunMetadataKey.AGENT_LOG] = self._wip_workflow_agent_logs.get( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                event.node_execution_id, [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        execution_metadata = json.dumps(jsonable_encoder(execution_metadata_dict)) if execution_metadata_dict else None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         finished_at = datetime.now(UTC).replace(tzinfo=None) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         elapsed_time = (finished_at - event.start_at).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -332,9 +342,16 @@ class WorkflowCycleManage: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         outputs = WorkflowEntry.handle_special_values(event.outputs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         finished_at = datetime.now(UTC).replace(tzinfo=None) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         elapsed_time = (finished_at - event.start_at).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        execution_metadata = ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            json.dumps(jsonable_encoder(event.execution_metadata)) if event.execution_metadata else None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        execution_metadata_dict = event.execution_metadata 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if self._wip_workflow_agent_logs.get(event.node_execution_id): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not execution_metadata_dict: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                execution_metadata_dict = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            execution_metadata_dict[NodeRunMetadataKey.AGENT_LOG] = self._wip_workflow_agent_logs.get( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                event.node_execution_id, [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        execution_metadata = json.dumps(jsonable_encoder(execution_metadata_dict)) if execution_metadata_dict else None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         db.session.query(WorkflowNodeExecution).filter(WorkflowNodeExecution.id == workflow_node_execution.id).update( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 WorkflowNodeExecution.status: WorkflowNodeExecutionStatus.FAILED.value, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -746,3 +763,52 @@ class WorkflowCycleManage: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             raise Exception(f"Workflow node execution not found: {node_execution_id}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return workflow_node_execution 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def _handle_agent_log(self, task_id: str, event: QueueAgentLogEvent) -> AgentLogStreamResponse: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Handle agent log 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :param task_id: task id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :param event: agent log event 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :return: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        node_execution = self._wip_workflow_node_executions.get(event.node_execution_id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if not node_execution: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            raise Exception(f"Workflow node execution not found: {event.node_execution_id}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        node_execution_id = node_execution.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        original_agent_logs = self._wip_workflow_agent_logs.get(node_execution_id, []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # try to find the log with the same id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for log in original_agent_logs: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if log.id == event.id: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # update the log 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                log.status = event.status 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                log.error = event.error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                log.data = event.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # append the log 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            original_agent_logs.append( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                AgentLogStreamResponse.Data( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    id=event.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    parent_id=event.parent_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    node_execution_id=node_execution_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    error=event.error, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    status=event.status, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    data=event.data, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self._wip_workflow_agent_logs[node_execution_id] = original_agent_logs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return AgentLogStreamResponse( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            task_id=task_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            data=AgentLogStreamResponse.Data( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                node_execution_id=node_execution_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                id=event.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                parent_id=event.parent_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                error=event.error, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                status=event.status, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                data=event.data, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ) 
			 |