messageing aligned
This commit is contained in:
parent
0e034e253d
commit
91aff56e1c
7 changed files with 177 additions and 296 deletions
|
|
@ -192,7 +192,8 @@ class HandlingTasks:
|
|||
|
||||
task_plan = TaskPlan(
|
||||
overview=task_plan_dict.get('overview', ''),
|
||||
tasks=tasks
|
||||
tasks=tasks,
|
||||
userMessage=task_plan_dict.get('userMessage', '')
|
||||
)
|
||||
|
||||
# Set workflow totals for progress tracking
|
||||
|
|
@ -217,24 +218,19 @@ class HandlingTasks:
|
|||
"""Create a chat message containing the task plan with user-friendly messages"""
|
||||
try:
|
||||
# Build task plan summary
|
||||
task_summary = f"📋 **Task Plan Generated**\n\n"
|
||||
task_summary += f"**Overview:** {task_plan.overview}\n\n"
|
||||
task_summary += f"**Total Tasks:** {len(task_plan.tasks)}\n\n"
|
||||
|
||||
# Add each task with its user message
|
||||
for i, task in enumerate(task_plan.tasks):
|
||||
task_summary += f"**Task {i+1}:** {task.objective}\n"
|
||||
if task.userMessage:
|
||||
task_summary += f" 💬 {task.userMessage}\n"
|
||||
if task.success_criteria:
|
||||
criteria_str = ', '.join(task.success_criteria)
|
||||
task_summary += f" ✅ Success Criteria: {criteria_str}\n"
|
||||
task_summary += "\n"
|
||||
|
||||
task_summary = f"📋 **Task Plan**\n\n"
|
||||
|
||||
# Get overall user message from task plan if available
|
||||
overall_message = task_plan.userMessage
|
||||
if overall_message:
|
||||
task_summary += f"**Plan Summary:** {overall_message}\n\n"
|
||||
task_summary += f"{overall_message}\n\n"
|
||||
|
||||
# Add each task with its user message
|
||||
for i, task in enumerate(task_plan.tasks):
|
||||
if task.userMessage:
|
||||
task_summary += f"💬 {task.userMessage}\n"
|
||||
task_summary += "\n"
|
||||
|
||||
|
||||
# Create workflow message
|
||||
message_data = {
|
||||
|
|
@ -269,76 +265,6 @@ class HandlingTasks:
|
|||
except Exception as e:
|
||||
logger.error(f"Error creating task plan message: {str(e)}")
|
||||
|
||||
async def createDocumentContextMessage(self, documents: List, workflow):
|
||||
"""Create a chat message with document context and workflow labeling"""
|
||||
try:
|
||||
# Get current workflow context and stats
|
||||
workflow_context = self.service.getWorkflowContext()
|
||||
workflow_stats = self.service.getWorkflowStats()
|
||||
|
||||
# Create a simple document context message without AI dependency
|
||||
message_text = f"📄 **Document Context**\n\n"
|
||||
message_text += f"**Total Documents:** {len(documents)}\n\n"
|
||||
|
||||
# Add workflow context information
|
||||
current_round = workflow_context.get('currentRound', 0)
|
||||
current_task = workflow_context.get('currentTask', 0)
|
||||
total_tasks = workflow_stats.get('totalTasks', 0)
|
||||
current_action = workflow_context.get('currentAction', 0)
|
||||
total_actions = workflow_stats.get('totalActions', 0)
|
||||
|
||||
message_text += f"**Workflow Context:**\n"
|
||||
message_text += f"- Round: {current_round}\n"
|
||||
if total_tasks > 0:
|
||||
message_text += f"- Task: {current_task}/{total_tasks}\n"
|
||||
else:
|
||||
message_text += f"- Task: {current_task}\n"
|
||||
if total_actions > 0:
|
||||
message_text += f"- Action: {current_action}/{total_actions}\n"
|
||||
else:
|
||||
message_text += f"- Action: {current_action}\n"
|
||||
message_text += f"- Status: {workflow_stats.get('workflowStatus', 'unknown')}\n\n"
|
||||
|
||||
# Add document list
|
||||
if documents:
|
||||
message_text += "**Available Documents:**\n"
|
||||
for i, doc in enumerate(documents[:5]): # Show first 5 documents
|
||||
message_text += f"- {doc.fileName if hasattr(doc, 'fileName') else f'Document {i+1}'}\n"
|
||||
if len(documents) > 5:
|
||||
message_text += f"- ... and {len(documents) - 5} more documents\n"
|
||||
message_text += "\n"
|
||||
|
||||
message_text += "Document context information is available for processing."
|
||||
|
||||
# Create workflow message
|
||||
message_data = {
|
||||
"workflowId": workflow.id,
|
||||
"role": "assistant",
|
||||
"message": message_text,
|
||||
"status": "step",
|
||||
"sequenceNr": len(workflow.messages) + 1,
|
||||
"publishedAt": get_utc_timestamp(),
|
||||
"documentsLabel": "document_context",
|
||||
"documents": [], # Empty documents for context message
|
||||
# Add workflow context fields
|
||||
"roundNumber": workflow_context.get('currentRound', 0),
|
||||
"taskNumber": workflow_context.get('currentTask', 0),
|
||||
"actionNumber": workflow_context.get('currentAction', 0),
|
||||
# Add progress status
|
||||
"taskProgress": "pending",
|
||||
"actionProgress": "pending"
|
||||
}
|
||||
|
||||
message = self.chatInterface.createWorkflowMessage(message_data)
|
||||
if message:
|
||||
workflow.messages.append(message)
|
||||
logger.info(f"Document context message created with {len(documents)} documents")
|
||||
else:
|
||||
logger.error("Failed to create document context message")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating document context message: {str(e)}")
|
||||
|
||||
async def generateTaskActions(self, task_step, workflow, previous_results=None, enhanced_context=None) -> List[TaskAction]:
|
||||
"""Generate actions for a given task step."""
|
||||
try:
|
||||
|
|
@ -546,25 +472,13 @@ class HandlingTasks:
|
|||
|
||||
# Create database log entry for task start in format expected by frontend
|
||||
if task_index is not None:
|
||||
if total_tasks is not None:
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"Executing task {task_index}/{total_tasks}",
|
||||
"type": "info"
|
||||
})
|
||||
else:
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"Executing task {task_index}/?",
|
||||
"type": "info"
|
||||
})
|
||||
|
||||
|
||||
# Create a task start message for the user
|
||||
task_progress = f"{task_index}/{total_tasks}" if total_tasks is not None else str(task_index)
|
||||
task_start_message = {
|
||||
"workflowId": workflow.id,
|
||||
"role": "assistant",
|
||||
"message": f"🚀 Starting Task {task_progress}\n\nObjective: {task_step.objective}",
|
||||
"message": f"🚀 **Task {task_progress}**",
|
||||
"status": "step",
|
||||
"sequenceNr": len(workflow.messages) + 1,
|
||||
"publishedAt": get_utc_timestamp(),
|
||||
|
|
@ -617,11 +531,6 @@ class HandlingTasks:
|
|||
logger.error("No actions defined for task step, aborting task execution")
|
||||
break
|
||||
|
||||
# Create document context message if documents are available
|
||||
available_docs = self.service.getAvailableDocuments(workflow)
|
||||
if available_docs:
|
||||
await self.createDocumentContextMessage(available_docs, workflow)
|
||||
|
||||
action_results = []
|
||||
for action_idx, action in enumerate(actions):
|
||||
# Check workflow status before each action execution
|
||||
|
|
@ -639,18 +548,11 @@ class HandlingTasks:
|
|||
# Log action start in format expected by frontend
|
||||
logger.info(f"Task {task_index} - Starting action {action_number}/{total_actions}")
|
||||
|
||||
# Create database log entry for action start
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"Task {task_index} - Starting action {action_number}/{total_actions}",
|
||||
"type": "info"
|
||||
})
|
||||
|
||||
# Create an action start message for the user
|
||||
action_start_message = {
|
||||
"workflowId": workflow.id,
|
||||
"role": "assistant",
|
||||
"message": f"⚡ Task {task_index} - Action {action_number}/{total_actions}\n\nMethod: {action.execMethod}.{action.execAction}",
|
||||
"message": f"⚡ **Action {action_number}/{total_actions}** (Method {action.execMethod}.{action.execAction})",
|
||||
"status": "step",
|
||||
"sequenceNr": len(workflow.messages) + 1,
|
||||
"publishedAt": get_utc_timestamp(),
|
||||
|
|
@ -694,34 +596,19 @@ class HandlingTasks:
|
|||
if success:
|
||||
logger.info(f"=== TASK {task_index or '?'} COMPLETED SUCCESSFULLY: {task_step.objective} ===")
|
||||
|
||||
# Create database log entry for task completion
|
||||
if total_tasks is not None:
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"🎯 Task {task_index}/{total_tasks} completed",
|
||||
"type": "success"
|
||||
})
|
||||
else:
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"🎯 Task {task_index}/? completed",
|
||||
"type": "success"
|
||||
})
|
||||
|
||||
# Create a task completion message for the user
|
||||
task_progress = f"{task_index}/{total_tasks}" if total_tasks is not None else str(task_index)
|
||||
|
||||
# Enhanced completion message with criteria details
|
||||
completion_message = f"🎯 Task {task_progress} Completed Successfully!\n\nObjective: {task_step.objective}\n\nFeedback: {feedback or 'Task completed successfully'}"
|
||||
completion_message = f"🎯 **Task {task_progress}**\n\n✅ {feedback or 'Task completed successfully'}"
|
||||
|
||||
# Add criteria status if available
|
||||
if hasattr(review_result, 'met_criteria') and review_result.met_criteria:
|
||||
completion_message += f"\n\n✅ **Success Criteria Met:**\n"
|
||||
for criterion in review_result.met_criteria:
|
||||
completion_message += f"• {criterion}\n"
|
||||
completion_message += f"\n• {criterion}\n"
|
||||
|
||||
if hasattr(review_result, 'quality_score'):
|
||||
completion_message += f"\n📊 **Quality Score:** {review_result.quality_score}/10"
|
||||
completion_message += f"\n📊 Score {review_result.quality_score}/10"
|
||||
|
||||
task_completion_message = {
|
||||
"workflowId": workflow.id,
|
||||
|
|
@ -740,10 +627,6 @@ class HandlingTasks:
|
|||
"taskProgress": "success"
|
||||
}
|
||||
|
||||
# Add user-friendly message if available
|
||||
if task_step.userMessage:
|
||||
task_completion_message["message"] += f"\n\n💬 {task_step.userMessage}"
|
||||
|
||||
message = self.chatInterface.createWorkflowMessage(task_completion_message)
|
||||
if message:
|
||||
workflow.messages.append(message)
|
||||
|
|
@ -824,7 +707,7 @@ class HandlingTasks:
|
|||
retry_message = {
|
||||
"workflowId": workflow.id,
|
||||
"role": "assistant",
|
||||
"message": f"🔄 Task {task_index} requires retry: {review_result.improvements}",
|
||||
"message": f"🔄 **Task {task_index}** needs retry: {review_result.improvements}",
|
||||
"status": "step",
|
||||
"sequenceNr": len(workflow.messages) + 1,
|
||||
"publishedAt": get_utc_timestamp(),
|
||||
|
|
@ -843,19 +726,19 @@ class HandlingTasks:
|
|||
continue
|
||||
else:
|
||||
logger.error(f"=== TASK {task_index or '?'} FAILED: {task_step.objective} after {attempt+1} attempts ===")
|
||||
|
||||
task_progress = f"{task_index}/{total_tasks}" if total_tasks is not None else str(task_index)
|
||||
|
||||
# Create user-facing error message for task failure
|
||||
error_message = f"❌ Task {task_index or '?'} - '{task_step.objective}' failed after {attempt+1} attempts\n\n"
|
||||
error_message += f"Objective: {task_step.objective}\n\n"
|
||||
error_message = f"**Task {task_progress}**\n\n❌ '{task_step.objective}' {attempt+1}x failed\n\n"
|
||||
|
||||
# Add specific error details if available
|
||||
if review_result and hasattr(review_result, 'reason') and review_result.reason:
|
||||
error_message += f"Reason: {review_result.reason}\n\n"
|
||||
error_message += f"{review_result.reason}\n\n"
|
||||
|
||||
# Add criteria progress information if available
|
||||
if retry_context and hasattr(retry_context, 'criteria_progress'):
|
||||
progress = retry_context.criteria_progress
|
||||
error_message += f"📊 **Progress Summary:**\n"
|
||||
error_message += f"📊 **Details**\n"
|
||||
if progress.get('met_criteria'):
|
||||
error_message += f"✅ Met criteria: {', '.join(progress['met_criteria'])}\n"
|
||||
if progress.get('unmet_criteria'):
|
||||
|
|
@ -908,19 +791,18 @@ class HandlingTasks:
|
|||
logger.error(f"=== TASK {task_index or '?'} FAILED AFTER ALL RETRIES: {task_step.objective} ===")
|
||||
|
||||
# Create user-facing error message for task failure
|
||||
error_message = f"❌ Task {task_index or '?'} - '{task_step.objective}' failed after all retries\n\n"
|
||||
error_message += f"Objective: {task_step.objective}\n\n"
|
||||
error_message = f"**Task {task_index or '?'}**\n\n❌ '{task_step.objective}' failed after all retries\n\n"
|
||||
error_message += f"{task_step.objective}\n\n"
|
||||
|
||||
# Add specific error details if available
|
||||
if retry_context and hasattr(retry_context, 'previous_review_result') and retry_context.previous_review_result:
|
||||
reason = retry_context.previous_review_result.get('reason', '')
|
||||
if reason and reason != "Task failed after all retries.":
|
||||
error_message += f"Reason: {reason}\n\n"
|
||||
error_message += f"{reason}\n\n"
|
||||
|
||||
# Add retry information
|
||||
error_message += f"Retries attempted: {retry_context.retry_count if retry_context else 'Unknown'}\n"
|
||||
error_message += f"Status: Task failed permanently\n\n"
|
||||
error_message += "Please check the connection and try again, or contact support if the issue persists."
|
||||
error_message += f"Status: Task failed permanently"
|
||||
|
||||
# Create workflow message for user
|
||||
message_data = {
|
||||
|
|
@ -1170,7 +1052,8 @@ class HandlingTasks:
|
|||
processingTime=createdAction.get("processingTime"),
|
||||
timestamp=float(createdAction.get("timestamp", get_utc_timestamp())),
|
||||
result=createdAction.get("result"),
|
||||
resultDocuments=createdAction.get("resultDocuments", [])
|
||||
resultDocuments=createdAction.get("resultDocuments", []),
|
||||
userMessage=createdAction.get("userMessage")
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -1241,20 +1124,6 @@ class HandlingTasks:
|
|||
# Log action results
|
||||
logger.info(f"Action completed successfully")
|
||||
|
||||
# Create database log entry for action completion
|
||||
if total_actions is not None:
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"✅ Task {task_num} - Action {action_num}/{total_actions} completed",
|
||||
"type": "success"
|
||||
})
|
||||
else:
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"✅ Task {task_num} - Action {action_num}/? completed",
|
||||
"type": "success"
|
||||
})
|
||||
|
||||
if created_documents:
|
||||
logger.info(f"Output documents ({len(created_documents)}):")
|
||||
for i, doc in enumerate(created_documents):
|
||||
|
|
@ -1276,19 +1145,12 @@ class HandlingTasks:
|
|||
await self.createActionMessage(action, result, workflow, result_label, [], task_step, task_index)
|
||||
|
||||
# Create database log entry for action failure
|
||||
if total_actions is not None:
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"❌ Task {task_num} - Action {action_num}/{total_actions} failed: {result.error}",
|
||||
"type": "error"
|
||||
})
|
||||
else:
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"❌ Task {task_num} - Action {action_num}/? failed: {result.error}",
|
||||
"type": "error"
|
||||
})
|
||||
|
||||
self.chatInterface.createWorkflowLog({
|
||||
"workflowId": workflow.id,
|
||||
"message": f"❌ **Task {task_num}**\n\n❌ **Action {action_num}/{total_actions}** failed: {result.error}",
|
||||
"type": "error"
|
||||
})
|
||||
|
||||
# Log action summary
|
||||
logger.info(f"=== TASK {task_num} ACTION {action_num} COMPLETED ===")
|
||||
|
||||
|
|
@ -1336,89 +1198,25 @@ class HandlingTasks:
|
|||
|
||||
# Create a more meaningful message that includes task context
|
||||
task_objective = task_step.objective if task_step else 'Unknown task'
|
||||
|
||||
|
||||
# Add comprehensive workflow context
|
||||
current_round = workflow_context.get('currentRound', 0)
|
||||
current_task = workflow_context.get('currentTask', 0)
|
||||
total_tasks = workflow_stats.get('totalTasks', 0)
|
||||
current_action = workflow_context.get('currentAction', 0)
|
||||
total_actions = workflow_stats.get('totalActions', 0)
|
||||
|
||||
# Build a user-friendly message based on success/failure
|
||||
if result.success:
|
||||
if created_documents and len(created_documents) > 0:
|
||||
doc_names = [doc.fileName for doc in created_documents[:3]]
|
||||
if len(created_documents) > 3:
|
||||
doc_names.append(f"... and {len(created_documents) - 3} more")
|
||||
|
||||
# Enhanced message with workflow context
|
||||
message_text = f"✅ **Task {task_index or '?'} - Action {action.execMethod}.{action.execAction} Completed**\n\n"
|
||||
message_text += f"**Objective:** {task_objective}\n\n"
|
||||
message_text += f"**Generated {len(created_documents)} document(s):** {', '.join(doc_names)}\n\n"
|
||||
message_text += f"**Result Label:** {result_label}\n"
|
||||
|
||||
# Add comprehensive workflow context
|
||||
current_round = workflow_context.get('currentRound', 0)
|
||||
current_task = workflow_context.get('currentTask', 0)
|
||||
total_tasks = workflow_stats.get('totalTasks', 0)
|
||||
current_action = workflow_context.get('currentAction', 0)
|
||||
total_actions = workflow_stats.get('totalActions', 0)
|
||||
|
||||
message_text += f"**Workflow Context:**\n"
|
||||
message_text += f"- Round: {current_round}\n"
|
||||
if total_tasks > 0:
|
||||
message_text += f"- Task: {current_task}/{total_tasks}\n"
|
||||
else:
|
||||
message_text += f"- Task: {current_task}\n"
|
||||
if total_actions > 0:
|
||||
message_text += f"- Action: {current_action}/{total_actions}\n"
|
||||
else:
|
||||
message_text += f"- Action: {current_action}\n"
|
||||
message_text += f"- Status: {workflow_stats.get('workflowStatus', 'unknown')}"
|
||||
else:
|
||||
message_text = f"✅ **Task {task_index or '?'} - Action {action.execMethod}.{action.execAction} Completed**\n\n"
|
||||
message_text += f"**Objective:** {task_objective}\n\n"
|
||||
message_text += "**Action executed successfully**\n\n"
|
||||
message_text += f"**Result Label:** {result_label}\n"
|
||||
|
||||
# Add comprehensive workflow context
|
||||
current_round = workflow_context.get('currentRound', 0)
|
||||
current_task = workflow_context.get('currentTask', 0)
|
||||
total_tasks = workflow_stats.get('totalTasks', 0)
|
||||
current_action = workflow_context.get('currentAction', 0)
|
||||
total_actions = workflow_stats.get('totalActions', 0)
|
||||
|
||||
message_text += f"**Workflow Context:**\n"
|
||||
message_text += f"- Round: {current_round}\n"
|
||||
if total_tasks > 0:
|
||||
message_text += f"- Task: {current_task}/{total_tasks}\n"
|
||||
else:
|
||||
message_text += f"- Task: {current_task}\n"
|
||||
if total_actions > 0:
|
||||
message_text += f"- Action: {current_action}/{total_actions}\n"
|
||||
else:
|
||||
message_text += f"- Action: {current_action}\n"
|
||||
message_text += f"- Status: {workflow_stats.get('workflowStats', 'unknown')}"
|
||||
message_text = f"**Action {current_action}/{total_actions} ({action.execMethod}.{action.execAction})**\n\n"
|
||||
message_text += f"✅ {task_objective}\n\n"
|
||||
else:
|
||||
# ⚠️ FAILURE MESSAGE - Show error details to user
|
||||
error_details = result.error if result.error else "Unknown error occurred"
|
||||
message_text = f"❌ **Task {task_index or '?'} - Action {action.execMethod}.{action.execAction} Failed**\n\n"
|
||||
message_text += f"**Objective:** {task_objective}\n\n"
|
||||
message_text += f"**Error:** {error_details}\n\n"
|
||||
message_text += f"**Result Label:** {result_label}\n"
|
||||
|
||||
# Add comprehensive workflow context
|
||||
current_round = workflow_context.get('currentRound', 0)
|
||||
current_task = workflow_context.get('currentTask', 0)
|
||||
total_tasks = workflow_stats.get('totalTasks', 0)
|
||||
current_action = workflow_context.get('currentAction', 0)
|
||||
total_actions = workflow_stats.get('totalActions', 0)
|
||||
|
||||
message_text += f"**Workflow Context:**\n"
|
||||
message_text += f"- Round: {current_round}\n"
|
||||
if total_tasks > 0:
|
||||
message_text += f"- Task: {current_task}/{total_tasks}\n"
|
||||
else:
|
||||
message_text += f"- Task: {current_task}\n"
|
||||
if total_actions > 0:
|
||||
message_text += f"- Action: {current_action}/{total_actions}\n"
|
||||
message_text += f"- Action: {current_action}\n"
|
||||
message_text += f"- Status: {workflow_stats.get('workflowStatus', 'unknown')}\n\n"
|
||||
message_text += "Please check the connection and try again."
|
||||
|
||||
message_text = f"**Action {current_action}/{total_actions} ({action.execMethod}.{action.execAction})**\n\n"
|
||||
message_text += f"❌ {task_objective}\n\n"
|
||||
message_text += f"{error_details}\n\n"
|
||||
|
||||
message_data = {
|
||||
"workflowId": workflow.id,
|
||||
"role": "assistant",
|
||||
|
|
@ -1432,19 +1230,12 @@ class HandlingTasks:
|
|||
"documentsLabel": result_label,
|
||||
"documents": created_documents,
|
||||
# Add workflow context fields - extract from result_label to match document reference
|
||||
"roundNumber": workflow_context.get('currentRound', 0),
|
||||
"taskNumber": task_index,
|
||||
"actionNumber": self._extractActionNumberFromLabel(result_label) if result_label else workflow_context.get('currentAction', 0),
|
||||
"roundNumber": current_round,
|
||||
"taskNumber": current_task,
|
||||
"actionNumber": current_action,
|
||||
"actionProgress": "success" if result.success else "fail"
|
||||
}
|
||||
|
||||
# Add user-friendly message if available
|
||||
if action.userMessage:
|
||||
if result.success:
|
||||
message_data["message"] += f"\n\n💬 {action.userMessage}"
|
||||
else:
|
||||
message_data["message"] += f"\n\n💬 Action was intended to: {action.userMessage}"
|
||||
|
||||
# Add debugging for error messages
|
||||
if not result.success:
|
||||
logger.info(f"Creating ERROR message: {message_text}")
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ INSTRUCTIONS:
|
|||
3. Focus on business outcomes, not technical operations
|
||||
4. Each task should produce meaningful, usable outputs
|
||||
5. Ensure proper handover between tasks using result labels
|
||||
6. Generate user-friendly messages for each task in the user's language ({user_language})
|
||||
7. Detect the language of the user request and include it in languageUserDetected
|
||||
6. Detect the language of the user request and include it in languageUserDetected
|
||||
7. Generate user-friendly messages for each task in the user's request language
|
||||
8. Return a JSON object with the exact structure shown below
|
||||
|
||||
TASK GROUPING PRINCIPLES:
|
||||
|
|
@ -63,15 +63,15 @@ TASK PLANNING PRINCIPLES:
|
|||
- Keep tasks at a meaningful level of abstraction
|
||||
- Each task should produce results that can be used by subsequent tasks
|
||||
- Ensure clear dependencies and handovers between tasks
|
||||
- Provide clear, actionable user messages in the user's language ({user_language})
|
||||
- Provide clear, actionable user messages in the user's request language
|
||||
- Group related activities to minimize task fragmentation
|
||||
- Only create multiple tasks when dealing with truly different, independent objectives
|
||||
|
||||
REQUIRED JSON STRUCTURE:
|
||||
{{
|
||||
"overview": "Brief description of the overall plan",
|
||||
"userMessage": "User-friendly message explaining the task plan in {user_language}",
|
||||
"languageUserDetected": "en", // Language code detected from user request (en, de, fr, it, es, etc.)
|
||||
"userMessage": "User-friendly message explaining the task plan in user's request language",
|
||||
"tasks": [
|
||||
{{
|
||||
"id": "task_1",
|
||||
|
|
@ -79,7 +79,7 @@ REQUIRED JSON STRUCTURE:
|
|||
"dependencies": ["task_0"], // IDs of tasks that must complete first
|
||||
"success_criteria": ["criteria1", "criteria2"],
|
||||
"estimated_complexity": "low|medium|high",
|
||||
"userMessage": "User-friendly message explaining what this task will accomplish in {user_language}"
|
||||
"userMessage": "User-friendly message explaining what this task will accomplish in user's request language"
|
||||
}}
|
||||
]
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -350,16 +350,19 @@ class ServiceCenter:
|
|||
doc_exchange = None
|
||||
if message.documents:
|
||||
if message.actionId and message.documentsLabel:
|
||||
# Use new document label format
|
||||
# Validate that we use the same label as in the message
|
||||
validated_label = self._validateDocumentLabelConsistency(message)
|
||||
|
||||
# Use the message's actual documentsLabel
|
||||
doc_refs = []
|
||||
for doc in message.documents:
|
||||
doc_ref = self.getDocumentReferenceFromChatDocument(doc, message)
|
||||
doc_refs.append(doc_ref)
|
||||
|
||||
doc_exchange = DocumentExchange(
|
||||
documentsLabel=message.documentsLabel,
|
||||
doc_exchange = DocumentExchange(
|
||||
documentsLabel=validated_label,
|
||||
documents=doc_refs
|
||||
)
|
||||
)
|
||||
else:
|
||||
# Generate new labels for documents without explicit labels
|
||||
doc_refs = []
|
||||
|
|
@ -444,8 +447,21 @@ class ServiceCenter:
|
|||
if document_list["chat"]:
|
||||
context += "CURRENT ROUND DOCUMENTS:\n"
|
||||
for exchange in document_list["chat"]:
|
||||
# Generate docList reference for the exchange (using message ID)
|
||||
doc_list_ref = f"docList:{exchange.documentsLabel}"
|
||||
# Generate docList reference for the exchange (using message ID and label)
|
||||
# Find the message that corresponds to this exchange
|
||||
message_id = None
|
||||
for message in self.workflow.messages:
|
||||
if hasattr(message, 'documentsLabel') and message.documentsLabel == exchange.documentsLabel:
|
||||
message_id = message.id
|
||||
break
|
||||
|
||||
if message_id:
|
||||
doc_list_ref = f"docList:{message_id}:{exchange.documentsLabel}"
|
||||
else:
|
||||
# Fallback to label-only format if message ID not found
|
||||
doc_list_ref = f"docList:{exchange.documentsLabel}"
|
||||
|
||||
logger.debug(f"Using document label for action planning: {exchange.documentsLabel} (message_id: {message_id})")
|
||||
context += f"- {doc_list_ref} contains:\n"
|
||||
# Generate docItem references for each document in the list
|
||||
for doc_ref in exchange.documents:
|
||||
|
|
@ -460,8 +476,21 @@ class ServiceCenter:
|
|||
if document_list["history"]:
|
||||
context += "WORKFLOW HISTORY DOCUMENTS:\n"
|
||||
for exchange in document_list["history"]:
|
||||
# Generate docList reference for the exchange (using message ID)
|
||||
doc_list_ref = f"docList:{exchange.documentsLabel}"
|
||||
# Generate docList reference for the exchange (using message ID and label)
|
||||
# Find the message that corresponds to this exchange
|
||||
message_id = None
|
||||
for message in self.workflow.messages:
|
||||
if hasattr(message, 'documentsLabel') and message.documentsLabel == exchange.documentsLabel:
|
||||
message_id = message.id
|
||||
break
|
||||
|
||||
if message_id:
|
||||
doc_list_ref = f"docList:{message_id}:{exchange.documentsLabel}"
|
||||
else:
|
||||
# Fallback to label-only format if message ID not found
|
||||
doc_list_ref = f"docList:{exchange.documentsLabel}"
|
||||
|
||||
logger.debug(f"Using history document label for action planning: {exchange.documentsLabel} (message_id: {message_id})")
|
||||
context += f"- {doc_list_ref} contains:\n"
|
||||
# Generate docItem references for each document in the list
|
||||
for doc_ref in exchange.documents:
|
||||
|
|
@ -481,6 +510,16 @@ class ServiceCenter:
|
|||
logger.error(f"Error generating enhanced document context: {str(e)}")
|
||||
return "NO DOCUMENTS AVAILABLE - Error generating document context."
|
||||
|
||||
def _validateDocumentLabelConsistency(self, message) -> str:
|
||||
"""Validate that the document label used for references matches the message's actual label"""
|
||||
if not hasattr(message, 'documentsLabel') or not message.documentsLabel:
|
||||
logger.debug(f"Message {message.id} has no documentsLabel, returning None")
|
||||
return None
|
||||
|
||||
# Simply return the message's actual documentsLabel - no correction, just validation
|
||||
logger.debug(f"Using message's documentsLabel for references: '{message.documentsLabel}'")
|
||||
return message.documentsLabel
|
||||
|
||||
def _extractDocumentInfoFromReference(self, doc_ref: str) -> Dict[str, str]:
|
||||
"""Extract document information from reference string"""
|
||||
try:
|
||||
|
|
@ -569,19 +608,56 @@ class ServiceCenter:
|
|||
if message.documents:
|
||||
for doc in message.documents:
|
||||
if doc.id == doc_id:
|
||||
doc_name = getattr(doc, 'fileName', 'unknown')
|
||||
logger.debug(f"Found docItem reference {doc_ref}: {doc_name}")
|
||||
all_documents.append(doc)
|
||||
break
|
||||
elif doc_ref.startswith("docList:"):
|
||||
# docList:<messageId>:<label> - extract message ID and find document list
|
||||
# docList:<messageId>:<label> or docList:<label> - extract message ID and find document list
|
||||
parts = doc_ref.split(':')
|
||||
if len(parts) >= 2:
|
||||
if len(parts) >= 3:
|
||||
# Format: docList:<messageId>:<label>
|
||||
message_id = parts[1]
|
||||
label = parts[2]
|
||||
# Find the message by ID and get all its documents
|
||||
for message in self.workflow.messages:
|
||||
if str(message.id) == message_id:
|
||||
if message.documents:
|
||||
doc_names = [doc.fileName for doc in message.documents if hasattr(doc, 'fileName')]
|
||||
logger.debug(f"Found docList reference {doc_ref}: {len(message.documents)} documents - {doc_names}")
|
||||
all_documents.extend(message.documents)
|
||||
else:
|
||||
logger.debug(f"Found docList reference {doc_ref} but message has no documents")
|
||||
break
|
||||
elif len(parts) >= 2:
|
||||
# Format: docList:<label> - find message by documentsLabel
|
||||
label = parts[1]
|
||||
logger.debug(f"Looking for message with documentsLabel: {label}")
|
||||
# Find messages with matching documentsLabel
|
||||
matching_messages = []
|
||||
for message in self.workflow.messages:
|
||||
# Check both attribute and raw data for documentsLabel
|
||||
msg_label = getattr(message, 'documentsLabel', None)
|
||||
if msg_label == label:
|
||||
matching_messages.append(message)
|
||||
logger.debug(f"Found message {message.id} with matching documentsLabel: {msg_label}")
|
||||
else:
|
||||
# Debug: show what labels we're comparing
|
||||
logger.debug(f"Message {message.id} has documentsLabel: '{msg_label}' (looking for: '{label}')")
|
||||
|
||||
if matching_messages:
|
||||
# Use the newest message (highest publishedAt)
|
||||
matching_messages.sort(key=lambda msg: getattr(msg, 'publishedAt', 0), reverse=True)
|
||||
newest_message = matching_messages[0]
|
||||
|
||||
if newest_message.documents:
|
||||
doc_names = [doc.fileName for doc in newest_message.documents if hasattr(doc, 'fileName')]
|
||||
logger.debug(f"Found docList reference {doc_ref}: {len(newest_message.documents)} documents - {doc_names}")
|
||||
all_documents.extend(newest_message.documents)
|
||||
else:
|
||||
logger.debug(f"Found docList reference {doc_ref} but message has no documents")
|
||||
else:
|
||||
logger.debug(f"No messages found with documentsLabel: {label}")
|
||||
else:
|
||||
# Direct label reference (round1_task2_action3_contextinfo)
|
||||
# Search for messages with matching documentsLabel to find the actual documents
|
||||
|
|
@ -619,8 +695,9 @@ class ServiceCenter:
|
|||
logger.debug(f"Newest message has {len(newest_message.documents) if newest_message.documents else 0} documents")
|
||||
|
||||
if newest_message.documents:
|
||||
doc_names = [doc.fileName for doc in newest_message.documents if hasattr(doc, 'fileName')]
|
||||
logger.debug(f"Added {len(newest_message.documents)} documents from newest message {newest_message.id}: {doc_names}")
|
||||
all_documents.extend(newest_message.documents)
|
||||
logger.debug(f"Added {len(newest_message.documents)} documents from newest message {newest_message.id}")
|
||||
else:
|
||||
logger.debug(f"No documents found in newest message {newest_message.id}")
|
||||
else:
|
||||
|
|
@ -641,8 +718,9 @@ class ServiceCenter:
|
|||
|
||||
logger.debug(f"Using fallback message {newest_fallback.id} with documentsLabel: {getattr(newest_fallback, 'documentsLabel', 'unknown')}")
|
||||
if newest_fallback.documents:
|
||||
doc_names = [doc.fileName for doc in newest_fallback.documents if hasattr(doc, 'fileName')]
|
||||
logger.debug(f"Added {len(newest_fallback.documents)} documents from fallback message {newest_fallback.id}: {doc_names}")
|
||||
all_documents.extend(newest_fallback.documents)
|
||||
logger.debug(f"Added {len(newest_fallback.documents)} documents from fallback message {newest_fallback.id}")
|
||||
else:
|
||||
logger.debug(f"No documents found in fallback message {newest_fallback.id}")
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -441,6 +441,10 @@ class MethodDocument(MethodBase):
|
|||
if len(lines) > 2:
|
||||
formatted_content = '\n'.join(lines[1:-1])
|
||||
|
||||
# For HTML format, check if AI returned complete HTML document
|
||||
if extension == ".html" and (formatted_content.startswith('<!DOCTYPE') or formatted_content.startswith('<html')):
|
||||
return formatted_content
|
||||
|
||||
return formatted_content
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -643,7 +647,22 @@ class MethodDocument(MethodBase):
|
|||
raise Exception("AI report generation failed - AI is required for report generation")
|
||||
|
||||
# Clean up the AI response and ensure it's valid HTML
|
||||
if not aiReport.strip().startswith('<html'):
|
||||
aiReport = aiReport.strip()
|
||||
|
||||
# Strip fenced code blocks like ```html ... ``` if present
|
||||
if aiReport.startswith("```") and aiReport.endswith("```"):
|
||||
lines = aiReport.split('\n')
|
||||
if len(lines) >= 2:
|
||||
# remove first and last fence lines (language tag allowed on first)
|
||||
aiReport = '\n'.join(lines[1:-1]).strip()
|
||||
|
||||
# Check if AI response starts with DOCTYPE or html tag (complete HTML document)
|
||||
if aiReport.startswith('<!DOCTYPE') or aiReport.startswith('<html'):
|
||||
# AI returned complete HTML document, use it directly
|
||||
return aiReport
|
||||
else:
|
||||
# AI returned HTML content without document structure, wrap it
|
||||
|
||||
# Check if AI response already contains a title/header
|
||||
has_title = any(title.lower() in aiReport.lower() for title in [title, "outlook", "report", "status"])
|
||||
|
||||
|
|
@ -660,9 +679,6 @@ class MethodDocument(MethodBase):
|
|||
html.append(aiReport)
|
||||
html.append("</body></html>")
|
||||
return '\n'.join(html)
|
||||
else:
|
||||
# AI returned complete HTML, use it directly
|
||||
return aiReport
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating AI report: {str(e)}")
|
||||
|
|
|
|||
|
|
@ -270,15 +270,6 @@ async def get_workflow_messages(
|
|||
# Get all messages
|
||||
allMessages = interfaceChat.getWorkflowMessages(workflowId)
|
||||
|
||||
# Debug logging: Log attributes for each message
|
||||
logger.debug(f"Retrieved {len(allMessages)} messages for workflow {workflowId}")
|
||||
for i, message in enumerate(allMessages):
|
||||
logger.debug(f"Message {i+1} (ID: {message.id}): {message}")
|
||||
logger.debug(f" - Type: {getattr(message, 'type', 'N/A')}")
|
||||
logger.debug(f" - Content: {getattr(message, 'content', 'N/A')[:100]}...")
|
||||
logger.debug(f" - PublishedAt: {getattr(message, 'publishedAt', 'N/A')}")
|
||||
logger.debug(f" - All attributes: {message.__dict__}")
|
||||
|
||||
# Apply selective data transfer if messageId is provided
|
||||
if messageId:
|
||||
# Find the index of the message with the given ID
|
||||
|
|
|
|||
|
|
@ -141,6 +141,12 @@ class WorkflowManager:
|
|||
self.chatManager.handlingTasks._checkWorkflowStopped()
|
||||
|
||||
# Create initial message using interface
|
||||
# Generate the correct documentsLabel that matches what getDocumentReferenceList() will create
|
||||
round_num = workflow.currentRound
|
||||
task_num = 0
|
||||
action_num = 0
|
||||
context_label = f"round{round_num}_task{task_num}_action{action_num}_context"
|
||||
|
||||
messageData = {
|
||||
"workflowId": workflow.id,
|
||||
"role": "user",
|
||||
|
|
@ -148,7 +154,7 @@ class WorkflowManager:
|
|||
"status": "first",
|
||||
"sequenceNr": 1,
|
||||
"publishedAt": get_utc_timestamp(),
|
||||
"documentsLabel": "workflow_start",
|
||||
"documentsLabel": context_label,
|
||||
"documents": [],
|
||||
# Add workflow context fields
|
||||
"roundNumber": workflow.currentRound,
|
||||
|
|
@ -390,7 +396,7 @@ class WorkflowManager:
|
|||
summary_message = {
|
||||
"workflowId": workflow.id,
|
||||
"role": "assistant",
|
||||
"message": f"Workflow completed successfully. Completed {workflow_result.completed_tasks}/{workflow_result.total_tasks} tasks in {workflow_result.execution_time:.2f} seconds.",
|
||||
"message": f"Workflow completed successfully.",
|
||||
"status": "last",
|
||||
"sequenceNr": len(workflow.messages) + 1,
|
||||
"publishedAt": get_utc_timestamp(),
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
TODO
|
||||
|
||||
# System
|
||||
- Backend/UI fix Table Connections mit korrekten Token Infos, View jedesmal neu laden im formGeneric
|
||||
- model reference diagram for all models. who uses who? --> to see the basic building blocks
|
||||
- chat workflow: messages to user in user language
|
||||
- neutralizer to activate AND put back placeholders to the returned data
|
||||
|
||||
# Tests
|
||||
|
|
|
|||
Loading…
Reference in a new issue