gateway/modules/workflow/managerWorkflow.py
2025-07-10 16:13:05 +02:00

282 lines
12 KiB
Python

from typing import Dict, Any, List, Optional
import logging
from datetime import datetime, UTC
import uuid
import asyncio
from modules.interfaces.interfaceAppObjects import User
from modules.interfaces.interfaceChatModel import (UserInputRequest, ChatMessage, ChatWorkflow, TaskItem, TaskStatus)
from modules.interfaces.interfaceChatObjects import ChatObjects
from modules.workflow.managerChat import ChatManager
logger = logging.getLogger(__name__)
class WorkflowStoppedException(Exception):
"""Exception raised when workflow is stopped by user"""
pass
class WorkflowManager:
"""Manager for workflow processing and coordination"""
def __init__(self, chatInterface: ChatObjects, currentUser: User):
self.chatInterface = chatInterface
self.chatManager = ChatManager(currentUser, chatInterface)
self.currentUser = currentUser
def _checkWorkflowStopped(self, workflow: ChatWorkflow) -> None:
"""Check if workflow has been stopped"""
if workflow.status == "stopped":
raise WorkflowStoppedException("Workflow was stopped by user")
async def workflowProcess(self, userInput: UserInputRequest, workflow: ChatWorkflow) -> None:
"""Process a workflow with user input using unified workflow phases"""
try:
# Initialize chat manager
await self.chatManager.initialize(workflow)
# Set user language
self.chatManager.setUserLanguage(userInput.userLanguage)
# Send first message
message = await self._sendFirstMessage(userInput, workflow)
# Execute unified workflow
workflow_result = await self.chatManager.executeUnifiedWorkflow(userInput.prompt, workflow)
# Process workflow results
await self._processWorkflowResults(workflow, workflow_result, message)
# Send last message
await self._sendLastMessage(workflow)
except WorkflowStoppedException:
logger.info("Workflow stopped by user")
# Update workflow status to stopped
workflow.status = "stopped"
workflow.lastActivity = datetime.now(UTC).isoformat()
self.chatInterface.updateWorkflow(workflow.id, {
"status": "stopped",
"lastActivity": workflow.lastActivity
})
# Add log entry
self.chatInterface.createWorkflowLog({
"workflowId": workflow.id,
"message": "Workflow stopped by user",
"type": "warning",
"status": "stopped",
"progress": 100
})
except Exception as e:
logger.error(f"Workflow processing error: {str(e)}")
# Update workflow status to failed
workflow.status = "failed"
workflow.lastActivity = datetime.now(UTC).isoformat()
self.chatInterface.updateWorkflow(workflow.id, {
"status": "failed",
"lastActivity": workflow.lastActivity
})
# Create error message
error_message = {
"workflowId": workflow.id,
"role": "assistant",
"message": f"Workflow processing failed: {str(e)}",
"status": "last",
"sequenceNr": len(workflow.messages) + 1,
"publishedAt": datetime.now(UTC).isoformat()
}
message = self.chatInterface.createWorkflowMessage(error_message)
if message:
workflow.messages.append(message)
# Add error log entry
self.chatInterface.createWorkflowLog({
"workflowId": workflow.id,
"message": f"Workflow failed: {str(e)}",
"type": "error",
"status": "failed",
"progress": 100
})
raise
async def _sendFirstMessage(self, userInput: UserInputRequest, workflow: ChatWorkflow) -> ChatMessage:
"""Send first message to start workflow"""
try:
# Create initial message using interface
messageData = {
"workflowId": workflow.id,
"role": "user",
"message": userInput.prompt,
"status": "first",
"sequenceNr": 1,
"publishedAt": datetime.now(UTC).isoformat()
}
# Add documents if any
if userInput.listFileId:
# Process file IDs and add to message data
documents = await self.chatManager.processFileIds(userInput.listFileId)
messageData["documents"] = documents
# Create message using interface
message = self.chatInterface.createWorkflowMessage(messageData)
if message:
workflow.messages.append(message)
return message
else:
raise Exception("Failed to create first message")
except Exception as e:
logger.error(f"Error sending first message: {str(e)}")
raise
async def _sendLastMessage(self, workflow: ChatWorkflow) -> None:
"""Send last message to complete workflow"""
try:
# Generate feedback
feedback = await self.chatManager.generateWorkflowFeedback(workflow)
# Create last message using interface
messageData = {
"workflowId": workflow.id,
"role": "assistant",
"message": feedback,
"status": "last",
"sequenceNr": len(workflow.messages) + 1,
"publishedAt": datetime.now(UTC).isoformat()
}
# Create message using interface
message = self.chatInterface.createWorkflowMessage(messageData)
if message:
workflow.messages.append(message)
# Update workflow status to completed
workflow.status = "completed"
workflow.lastActivity = datetime.now(UTC).isoformat()
# Update workflow in database
self.chatInterface.updateWorkflow(workflow.id, {
"status": "completed",
"lastActivity": workflow.lastActivity
})
# Add completion log entry
self.chatInterface.createWorkflowLog({
"workflowId": workflow.id,
"message": "Workflow completed successfully",
"type": "success",
"status": "completed",
"progress": 100
})
except Exception as e:
logger.error(f"Error sending last message: {str(e)}")
raise
async def _processWorkflowResults(self, workflow: ChatWorkflow, workflow_result: Dict[str, Any], initial_message: ChatMessage) -> None:
"""Process workflow results and create appropriate messages"""
try:
if workflow_result.get('status') == 'failed':
# Create error message
error_message = {
"workflowId": workflow.id,
"role": "assistant",
"message": f"Workflow failed: {workflow_result.get('error', 'Unknown error')}",
"status": "last",
"sequenceNr": len(workflow.messages) + 1,
"publishedAt": datetime.now(UTC).isoformat()
}
message = self.chatInterface.createWorkflowMessage(error_message)
if message:
workflow.messages.append(message)
# Update workflow status to failed
workflow.status = "failed"
workflow.lastActivity = datetime.now(UTC).isoformat()
self.chatInterface.updateWorkflow(workflow.id, {
"status": "failed",
"lastActivity": workflow.lastActivity
})
return
# Process successful workflow results
workflow_results = workflow_result.get('workflow_results', [])
for i, result in enumerate(workflow_results):
task_step = result['task_step']
action_results = result['action_results']
review_result = result['review_result']
# Create message for task step
step_message = {
"workflowId": workflow.id,
"role": "assistant",
"message": f"Completed task: {task_step.get('description', 'Unknown')}",
"status": "step",
"sequenceNr": len(workflow.messages) + 1,
"publishedAt": datetime.now(UTC).isoformat()
}
# Add action details if available
if action_results:
successful_actions = [r for r in action_results if r.get('status') == 'completed']
step_message["message"] += f"\nExecuted {len(successful_actions)}/{len(action_results)} actions successfully."
message = self.chatInterface.createWorkflowMessage(step_message)
if message:
workflow.messages.append(message)
# Create final summary message
successful_tasks = workflow_result.get('successful_tasks', 0)
total_tasks = workflow_result.get('total_tasks', 0)
summary_message = {
"workflowId": workflow.id,
"role": "assistant",
"message": f"Workflow completed successfully. Completed {successful_tasks}/{total_tasks} tasks.",
"status": "last",
"sequenceNr": len(workflow.messages) + 1,
"publishedAt": datetime.now(UTC).isoformat()
}
message = self.chatInterface.createWorkflowMessage(summary_message)
if message:
workflow.messages.append(message)
# Update workflow status to completed for successful workflows
workflow.status = "completed"
workflow.lastActivity = datetime.now(UTC).isoformat()
self.chatInterface.updateWorkflow(workflow.id, {
"status": "completed",
"lastActivity": workflow.lastActivity
})
except Exception as e:
logger.error(f"Error processing workflow results: {str(e)}")
# Create error message
error_message = {
"workflowId": workflow.id,
"role": "assistant",
"message": f"Error processing workflow results: {str(e)}",
"status": "last",
"sequenceNr": len(workflow.messages) + 1,
"publishedAt": datetime.now(UTC).isoformat()
}
message = self.chatInterface.createWorkflowMessage(error_message)
if message:
workflow.messages.append(message)
# Update workflow status to failed
workflow.status = "failed"
workflow.lastActivity = datetime.now(UTC).isoformat()
self.chatInterface.updateWorkflow(workflow.id, {
"status": "failed",
"lastActivity": workflow.lastActivity
})