From 46fcd089c42cb8f33699b544c605abb3a31a823c Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Sun, 2 Nov 2025 19:22:01 +0100
Subject: [PATCH] Refactored workflow modes to the standard Dynamic (default),
Actionplan (option), Template (future)
---
modules/datamodels/datamodelChat.py | 34 ++++++++++--
.../chatPlayground/mainChatPlayground.py | 10 ++--
modules/interfaces/interfaceDbChatObjects.py | 5 +-
modules/routes/routeChatPlayground.py | 6 +--
.../workflows/processing/adaptive/__init__.py | 2 +-
.../processing/adaptive/contentValidator.py | 2 +-
.../processing/adaptive/intentAnalyzer.py | 2 +-
.../processing/adaptive/learningEngine.py | 2 +-
.../processing/adaptive/progressTracker.py | 2 +-
.../processing/modes/modeActionplan.py | 2 +-
.../modes/{modeReact.py => modeDynamic.py} | 52 +++++++++----------
.../processing/modes/modeTemplate.py | 41 +++++++++++++++
.../processing/shared/executionState.py | 2 +-
.../processing/shared/placeholderFactory.py | 26 +++++-----
...t.py => promptGenerationActionsDynamic.py} | 10 ++--
.../workflows/processing/workflowProcessor.py | 31 ++++++-----
modules/workflows/workflowManager.py | 9 ++--
17 files changed, 156 insertions(+), 82 deletions(-)
rename modules/workflows/processing/modes/{modeReact.py => modeDynamic.py} (96%)
create mode 100644 modules/workflows/processing/modes/modeTemplate.py
rename modules/workflows/processing/shared/{promptGenerationActionsReact.py => promptGenerationActionsDynamic.py} (96%)
diff --git a/modules/datamodels/datamodelChat.py b/modules/datamodels/datamodelChat.py
index 9b173fd1..680bd3cc 100644
--- a/modules/datamodels/datamodelChat.py
+++ b/modules/datamodels/datamodelChat.py
@@ -263,6 +263,23 @@ registerModelLabels(
)
+class WorkflowModeEnum(str, Enum):
+ WORKFLOW_ACTIONPLAN = "Actionplan"
+ WORKFLOW_DYNAMIC = "Dynamic"
+ WORKFLOW_TEMPLATE = "Template"
+
+
+registerModelLabels(
+ "WorkflowModeEnum",
+ {"en": "Workflow Mode", "fr": "Mode de workflow"},
+ {
+ "WORKFLOW_ACTIONPLAN": {"en": "Actionplan", "fr": "Actionplan"},
+ "WORKFLOW_DYNAMIC": {"en": "Dynamic", "fr": "Dynamique"},
+ "WORKFLOW_TEMPLATE": {"en": "Template", "fr": "Modèle"},
+ },
+)
+
+
class ChatWorkflow(BaseModel):
id: str = Field(
default_factory=lambda: str(uuid.uuid4()),
@@ -372,18 +389,25 @@ class ChatWorkflow(BaseModel):
frontend_readonly=True,
frontend_required=False,
)
- workflowMode: str = Field(
- default="Actionplan",
+ workflowMode: WorkflowModeEnum = Field(
+ default=WorkflowModeEnum.WORKFLOW_DYNAMIC,
description="Workflow mode selector",
frontend_type="select",
frontend_readonly=False,
frontend_required=False,
frontend_options=[
{
- "value": "Actionplan",
- "label": {"en": "Action Plan", "fr": "Plan d'actions"},
+ "value": WorkflowModeEnum.WORKFLOW_ACTIONPLAN.value,
+ "label": {"en": "Actionplan", "fr": "Actionplan"},
+ },
+ {
+ "value": WorkflowModeEnum.WORKFLOW_DYNAMIC.value,
+ "label": {"en": "Dynamic", "fr": "Dynamique"},
+ },
+ {
+ "value": WorkflowModeEnum.WORKFLOW_TEMPLATE.value,
+ "label": {"en": "Template", "fr": "Modèle"},
},
- {"value": "React", "label": {"en": "React", "fr": "Réactif"}},
],
)
maxSteps: int = Field(
diff --git a/modules/features/chatPlayground/mainChatPlayground.py b/modules/features/chatPlayground/mainChatPlayground.py
index 54d50cb4..8420cb41 100644
--- a/modules/features/chatPlayground/mainChatPlayground.py
+++ b/modules/features/chatPlayground/mainChatPlayground.py
@@ -2,13 +2,13 @@ import logging
from typing import Optional
from modules.datamodels.datamodelUam import User
-from modules.datamodels.datamodelChat import ChatWorkflow, UserInputRequest
+from modules.datamodels.datamodelChat import ChatWorkflow, UserInputRequest, WorkflowModeEnum
from modules.workflows.workflowManager import WorkflowManager
from modules.services import getInterface as getServices
logger = logging.getLogger(__name__)
-async def chatStart(interfaceDbChat, currentUser: User, userInput: UserInputRequest, workflowId: Optional[str] = None, workflowMode: str = "Actionplan") -> ChatWorkflow:
+async def chatStart(interfaceDbChat, currentUser: User, userInput: UserInputRequest, workflowId: Optional[str] = None, workflowMode: WorkflowModeEnum = WorkflowModeEnum.WORKFLOW_ACTIONPLAN) -> ChatWorkflow:
"""
Starts a new chat or continues an existing one, then launches processing asynchronously.
@@ -17,10 +17,10 @@ async def chatStart(interfaceDbChat, currentUser: User, userInput: UserInputRequ
currentUser: Current user
userInput: User input request
workflowId: Optional workflow ID to continue existing workflow
- workflowMode: "Actionplan" for traditional task planning, "React" for iterative react-style processing
+ workflowMode: "Actionplan" for traditional task planning, "Dynamic" for iterative dynamic-style processing, "Template" for template-based processing
- Example usage for React mode:
- workflow = await chatStart(interfaceDbChat, currentUser, userInput, workflowMode="React")
+ Example usage for Dynamic mode:
+ workflow = await chatStart(interfaceDbChat, currentUser, userInput, workflowMode=WorkflowModeEnum.WORKFLOW_DYNAMIC)
"""
try:
services = getServices(currentUser, None)
diff --git a/modules/interfaces/interfaceDbChatObjects.py b/modules/interfaces/interfaceDbChatObjects.py
index 78f8a2c5..87f0bf5b 100644
--- a/modules/interfaces/interfaceDbChatObjects.py
+++ b/modules/interfaces/interfaceDbChatObjects.py
@@ -17,7 +17,8 @@ from modules.datamodels.datamodelChat import (
ChatStat,
ChatLog,
ChatMessage,
- ChatWorkflow
+ ChatWorkflow,
+ WorkflowModeEnum
)
from modules.datamodels.datamodelUam import User
@@ -367,7 +368,7 @@ class ChatObjects:
messages=[],
stats=[],
mandateId=created.get("mandateId", self.currentUser.mandateId),
- workflowMode=created.get("workflowMode", "Actionplan"),
+ workflowMode=created.get("workflowMode", WorkflowModeEnum.WORKFLOW_DYNAMIC),
maxSteps=created.get("maxSteps", 1)
)
diff --git a/modules/routes/routeChatPlayground.py b/modules/routes/routeChatPlayground.py
index 300b415b..d376a12d 100644
--- a/modules/routes/routeChatPlayground.py
+++ b/modules/routes/routeChatPlayground.py
@@ -14,7 +14,7 @@ from modules.security.auth import limiter, getCurrentUser
import modules.interfaces.interfaceDbChatObjects as interfaceDbChatObjects
# Import models
-from modules.datamodels.datamodelChat import ChatWorkflow, UserInputRequest
+from modules.datamodels.datamodelChat import ChatWorkflow, UserInputRequest, WorkflowModeEnum
from modules.datamodels.datamodelUam import User
# Import workflow control functions
@@ -39,7 +39,7 @@ def getServiceChat(currentUser: User):
async def start_workflow(
request: Request,
workflowId: Optional[str] = Query(None, description="Optional ID of the workflow to continue"),
- workflowMode: str = Query("Actionplan", description="Workflow mode: 'Actionplan' or 'React'"),
+ workflowMode: WorkflowModeEnum = Query(WorkflowModeEnum.WORKFLOW_DYNAMIC, description="Workflow mode: 'Actionplan', 'Dynamic', or 'Template'"),
userInput: UserInputRequest = Body(...),
currentUser: User = Depends(getCurrentUser)
) -> ChatWorkflow:
@@ -48,7 +48,7 @@ async def start_workflow(
Corresponds to State 1 in the state machine documentation.
Args:
- workflowMode: "Actionplan" for traditional task planning, "React" for iterative react-style processing
+ workflowMode: "Actionplan" for traditional task planning, "Dynamic" for iterative dynamic-style processing, "Template" for template-based processing
"""
try:
# Get service center
diff --git a/modules/workflows/processing/adaptive/__init__.py b/modules/workflows/processing/adaptive/__init__.py
index afc0c963..df4da54b 100644
--- a/modules/workflows/processing/adaptive/__init__.py
+++ b/modules/workflows/processing/adaptive/__init__.py
@@ -1,4 +1,4 @@
-# adaptive module for React mode
+# adaptive module for Dynamic mode
# Provides adaptive learning capabilities
from .intentAnalyzer import IntentAnalyzer
diff --git a/modules/workflows/processing/adaptive/contentValidator.py b/modules/workflows/processing/adaptive/contentValidator.py
index 2709af7b..61bad944 100644
--- a/modules/workflows/processing/adaptive/contentValidator.py
+++ b/modules/workflows/processing/adaptive/contentValidator.py
@@ -1,5 +1,5 @@
# contentValidator.py
-# Content validation for adaptive React mode
+# Content validation for adaptive Dynamic mode
# Generic, document-aware validation system
import logging
diff --git a/modules/workflows/processing/adaptive/intentAnalyzer.py b/modules/workflows/processing/adaptive/intentAnalyzer.py
index caee37ce..4ad17861 100644
--- a/modules/workflows/processing/adaptive/intentAnalyzer.py
+++ b/modules/workflows/processing/adaptive/intentAnalyzer.py
@@ -1,5 +1,5 @@
# intentAnalyzer.py
-# Intent analysis for adaptive React mode - AI-based, language-agnostic
+# Intent analysis for adaptive Dynamic mode - AI-based, language-agnostic
import json
import logging
diff --git a/modules/workflows/processing/adaptive/learningEngine.py b/modules/workflows/processing/adaptive/learningEngine.py
index 7e8fe60b..5ed29e80 100644
--- a/modules/workflows/processing/adaptive/learningEngine.py
+++ b/modules/workflows/processing/adaptive/learningEngine.py
@@ -1,5 +1,5 @@
# learningEngine.py
-# Learning engine for adaptive React mode
+# Learning engine for adaptive Dynamic mode
import logging
from typing import Dict, Any, List
diff --git a/modules/workflows/processing/adaptive/progressTracker.py b/modules/workflows/processing/adaptive/progressTracker.py
index a94dacd8..573ed2ff 100644
--- a/modules/workflows/processing/adaptive/progressTracker.py
+++ b/modules/workflows/processing/adaptive/progressTracker.py
@@ -1,5 +1,5 @@
# progressTracker.py
-# Progress tracking for adaptive React mode
+# Progress tracking for adaptive Dynamic mode
import logging
from typing import Dict, Any, List
diff --git a/modules/workflows/processing/modes/modeActionplan.py b/modules/workflows/processing/modes/modeActionplan.py
index 40ce267c..e2406324 100644
--- a/modules/workflows/processing/modes/modeActionplan.py
+++ b/modules/workflows/processing/modes/modeActionplan.py
@@ -334,7 +334,7 @@ class ActionplanMode(BaseMode):
taskIndex, actionNumber, totalActions)
actionResults.append(result)
- # Enhanced validation: Content validation after each action (like React mode)
+ # Enhanced validation: Content validation after each action (like Dynamic mode)
if getattr(self, 'workflowIntent', None) and result.documents:
# Pass ALL documents to validator - validator decides what to validate (generic approach)
# Pass taskStep so validator can use task.objective and format fields
diff --git a/modules/workflows/processing/modes/modeReact.py b/modules/workflows/processing/modes/modeDynamic.py
similarity index 96%
rename from modules/workflows/processing/modes/modeReact.py
rename to modules/workflows/processing/modes/modeDynamic.py
index 32bd5d62..8a2d691d 100644
--- a/modules/workflows/processing/modes/modeReact.py
+++ b/modules/workflows/processing/modes/modeDynamic.py
@@ -1,5 +1,5 @@
-# modeReact.py
-# React mode implementation for workflows
+# modeDynamic.py
+# Dynamic mode implementation for workflows
import json
import logging
@@ -14,10 +14,10 @@ from modules.datamodels.datamodelChat import (
from modules.datamodels.datamodelChat import ChatWorkflow
from modules.workflows.processing.modes.modeBase import BaseMode
from modules.workflows.processing.shared.executionState import TaskExecutionState, shouldContinue
-from modules.workflows.processing.shared.promptGenerationActionsReact import (
- generateReactPlanSelectionPrompt,
- generateReactParametersPrompt,
- generateReactRefinementPrompt
+from modules.workflows.processing.shared.promptGenerationActionsDynamic import (
+ generateDynamicPlanSelectionPrompt,
+ generateDynamicParametersPrompt,
+ generateDynamicRefinementPrompt
)
from modules.workflows.processing.shared.placeholderFactory import extractReviewContent
from modules.workflows.processing.adaptive import IntentAnalyzer, ContentValidator, LearningEngine, ProgressTracker
@@ -25,8 +25,8 @@ from modules.workflows.processing.adaptive.adaptiveLearningEngine import Adaptiv
logger = logging.getLogger(__name__)
-class ReactMode(BaseMode):
- """React mode implementation - iterative plan-act-observe-refine loop"""
+class DynamicMode(BaseMode):
+ """Dynamic mode implementation - iterative plan-act-observe-refine loop"""
def __init__(self, services, workflow):
super().__init__(services, workflow)
@@ -41,13 +41,13 @@ class ReactMode(BaseMode):
async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
previousResults: List = None, enhancedContext: TaskContext = None) -> List[ActionItem]:
- """React mode doesn't use batch action generation - actions are generated iteratively"""
- # React mode generates actions one at a time in the execution loop
+ """Dynamic mode doesn't use batch action generation - actions are generated iteratively"""
+ # Dynamic mode generates actions one at a time in the execution loop
return []
async def executeTask(self, taskStep: TaskStep, workflow: ChatWorkflow, context: TaskContext,
taskIndex: int = None, totalTasks: int = None) -> TaskResult:
- """Execute task using React mode - iterative plan-act-observe-refine loop"""
+ """Execute task using Dynamic mode - iterative plan-act-observe-refine loop"""
logger.info(f"=== STARTING TASK {taskIndex or '?'}: {taskStep.objective} ===")
# Use workflow-level intent from planning phase (stored in workflow object)
@@ -79,9 +79,9 @@ class ReactMode(BaseMode):
await self.messageCreator.createTaskStartMessage(taskStep, workflow, taskIndex, totalTasks)
state = TaskExecutionState(taskStep)
- # React mode uses max_steps instead of max_retries
+ # Dynamic mode uses max_steps instead of max_retries
state.max_steps = max(1, int(getattr(workflow, 'maxSteps', 5)))
- logger.info(f"Using React mode execution with max_steps: {state.max_steps}")
+ logger.info(f"Using Dynamic mode execution with max_steps: {state.max_steps}")
step = 1
decision = None
@@ -95,7 +95,7 @@ class ReactMode(BaseMode):
try:
t0 = time.time()
selection = await self._planSelect(context)
- logger.info(f"React step {step}: Selected action: {selection}")
+ logger.info(f"Dynamic step {step}: Selected action: {selection}")
# Create user-friendly message BEFORE action execution
# Action intention message is now handled by the standard message creator in _actExecute
@@ -154,7 +154,7 @@ class ReactMode(BaseMode):
# Action completion message is now handled by the standard message creator in _actExecute
except Exception as e:
- logger.error(f"React step {step} error: {e}")
+ logger.error(f"Dynamic step {step} error: {e}")
break
# NEW: Use adaptive stopping logic
@@ -168,7 +168,7 @@ class ReactMode(BaseMode):
break
step += 1
- # Summarize task result for react mode
+ # Summarize task result for dynamic mode
status = TaskStatus.COMPLETED
success = True
# Get feedback from last decision if available
@@ -199,7 +199,7 @@ class ReactMode(BaseMode):
async def _planSelect(self, context: TaskContext) -> Dict[str, Any]:
"""Plan: select exactly one action. Returns {"action": {method, name}}"""
- bundle = generateReactPlanSelectionPrompt(self.services, context, self.adaptiveLearningEngine)
+ bundle = generateDynamicPlanSelectionPrompt(self.services, context, self.adaptiveLearningEngine)
promptTemplate = bundle.prompt
placeholders = bundle.placeholders
@@ -297,7 +297,7 @@ class ReactMode(BaseMode):
stage2Context.taskStep = getattr(context, 'taskStep', None)
stage2Context.workflowId = getattr(context, 'workflowId', None)
- # Set Stage 1 data directly on the permissive context (snake_case for promptGenerationActionsReact compatibility)
+ # Set Stage 1 data directly on the permissive context (snake_case for promptGenerationActionsDynamic compatibility)
if isinstance(selection, dict):
stage2Context.action_objective = selection.get('actionObjective', '')
stage2Context.parameters_context = selection.get('parametersContext', '')
@@ -308,7 +308,7 @@ class ReactMode(BaseMode):
stage2Context.learnings = []
# Build and send the Stage 2 parameters prompt (always)
- bundle = generateReactParametersPrompt(self.services, stage2Context, compoundActionName, self.adaptiveLearningEngine)
+ bundle = generateDynamicParametersPrompt(self.services, stage2Context, compoundActionName, self.adaptiveLearningEngine)
promptTemplate = bundle.prompt
placeholders = bundle.placeholders
@@ -596,7 +596,7 @@ class ReactMode(BaseMode):
reviewContext = ReviewContext(
taskStep=context.taskStep,
taskActions=[],
- actionResults=[], # React mode doesn't have action results in this context
+ actionResults=[], # Dynamic mode doesn't have action results in this context
stepResult={'observation': observationDict},
workflowId=context.workflowId,
previousResults=[]
@@ -640,7 +640,7 @@ class ReactMode(BaseMode):
# Update placeholders with enhanced review content
placeholders["REVIEW_CONTENT"] = enhancedReviewContent
- bundle = generateReactRefinementPrompt(self.services, context, enhancedReviewContent)
+ bundle = generateDynamicRefinementPrompt(self.services, context, enhancedReviewContent)
promptTemplate = bundle.prompt
placeholders = bundle.placeholders
@@ -707,10 +707,10 @@ class ReactMode(BaseMode):
qualityScore=5.0
)
- async def _createReactActionMessage(self, workflow: ChatWorkflow, selection: Dict[str, Any],
+ async def _createDynamicActionMessage(self, workflow: ChatWorkflow, selection: Dict[str, Any],
step: int, maxSteps: int, taskIndex: int, messageType: str,
result: ActionResult = None, observation: Observation = None):
- """Create user-friendly messages for React workflow actions"""
+ """Create user-friendly messages for Dynamic workflow actions"""
try:
action = selection.get('action', {})
method = action.get('method', '')
@@ -757,7 +757,7 @@ class ReactMode(BaseMode):
self.services.workflow.storeMessageWithDocuments(workflow, messageData, [])
except Exception as e:
- logger.error(f"Error creating React action message: {str(e)}")
+ logger.error(f"Error creating Dynamic action message: {str(e)}")
async def _generateActionIntentionMessage(self, method: str, actionName: str, userLanguage: str):
"""Generate user-friendly message explaining what action will do"""
@@ -817,7 +817,7 @@ Return only the user-friendly message, no technical details."""
return f"{method}.{actionName} action completed"
def _createActionItem(self, actionData: Dict[str, Any]) -> ActionItem:
- """Creates a new task action for React mode"""
+ """Creates a new task action for Dynamic mode"""
try:
import uuid
@@ -908,7 +908,7 @@ Return only the user-friendly message, no technical details."""
logger.error(f"Error updating workflow before executing action: {str(e)}")
def _createActionItem(self, actionData: Dict[str, Any]) -> ActionItem:
- """Creates a new task action for React mode"""
+ """Creates a new task action for Dynamic mode"""
try:
import uuid
diff --git a/modules/workflows/processing/modes/modeTemplate.py b/modules/workflows/processing/modes/modeTemplate.py
new file mode 100644
index 00000000..6b476a2d
--- /dev/null
+++ b/modules/workflows/processing/modes/modeTemplate.py
@@ -0,0 +1,41 @@
+# modeTemplate.py
+# Template mode implementation for workflows (placeholder for future use)
+
+import logging
+from typing import List, Dict, Any
+from modules.datamodels.datamodelChat import (
+ TaskStep, TaskContext, TaskResult, ActionItem, TaskStatus
+)
+from modules.datamodels.datamodelChat import ChatWorkflow
+from modules.workflows.processing.modes.modeBase import BaseMode
+
+logger = logging.getLogger(__name__)
+
+class TemplateMode(BaseMode):
+ """Template mode implementation - placeholder for future template-based workflow execution"""
+
+ def __init__(self, services, workflow):
+ super().__init__(services, workflow)
+ logger.warning("TemplateMode is not yet implemented - using placeholder implementation")
+
+ async def generateActionItems(self, taskStep: TaskStep, workflow: ChatWorkflow,
+ previousResults: List = None, enhancedContext: TaskContext = None) -> List[ActionItem]:
+ """Generate actions for a given task step using template-based approach"""
+ logger.warning("TemplateMode.generateActionItems not yet implemented")
+ # TODO: Implement template-based action generation
+ return []
+
+ async def executeTask(self, taskStep: TaskStep, workflow: ChatWorkflow, context: TaskContext,
+ taskIndex: int = None, totalTasks: int = None) -> TaskResult:
+ """Execute task using Template mode - placeholder implementation"""
+ logger.warning("TemplateMode.executeTask not yet implemented - returning placeholder result")
+
+ # Return placeholder task result
+ return TaskResult(
+ taskId=taskStep.id,
+ status=TaskStatus.COMPLETED,
+ success=False,
+ feedback="Template mode is not yet implemented",
+ error="Template mode is not yet implemented"
+ )
+
diff --git a/modules/workflows/processing/shared/executionState.py b/modules/workflows/processing/shared/executionState.py
index ba6a7d0c..a783e544 100644
--- a/modules/workflows/processing/shared/executionState.py
+++ b/modules/workflows/processing/shared/executionState.py
@@ -17,7 +17,7 @@ class TaskExecutionState:
self.current_action_index = 0
self.retry_count = 0
self.max_retries = 3
- # Iterative loop (react mode)
+ # Iterative loop (dynamic mode)
self.current_step = 0
self.max_steps = 5
diff --git a/modules/workflows/processing/shared/placeholderFactory.py b/modules/workflows/processing/shared/placeholderFactory.py
index 31310d21..68f75e23 100644
--- a/modules/workflows/processing/shared/placeholderFactory.py
+++ b/modules/workflows/processing/shared/placeholderFactory.py
@@ -8,22 +8,22 @@ NAMING CONVENTION:
- Placeholder names are in UPPER_CASE with underscores
- Function names are in camelCase
-MAPPING TABLE (keys → function) with usage [taskplan | actionplan | react]:
-{{KEY:USER_PROMPT}} -> extractUserPrompt() [taskplan, actionplan, react]
-{{KEY:USER_LANGUAGE}} -> extractUserLanguage() [actionplan, react]
+MAPPING TABLE (keys → function) with usage [taskplan | actionplan | dynamic]:
+{{KEY:USER_PROMPT}} -> extractUserPrompt() [taskplan, actionplan, dynamic]
+{{KEY:USER_LANGUAGE}} -> extractUserLanguage() [actionplan, dynamic]
{{KEY:LANGUAGE_USER_DETECTED}} -> extractLanguageUserDetected() [taskplan]
-{{KEY:WORKFLOW_HISTORY}} -> extractWorkflowHistory() [taskplan, actionplan, react]
-{{KEY:AVAILABLE_CONNECTIONS_INDEX}} -> extractAvailableConnectionsIndex() [actionplan, react]
+{{KEY:WORKFLOW_HISTORY}} -> extractWorkflowHistory() [taskplan, actionplan, dynamic]
+{{KEY:AVAILABLE_CONNECTIONS_INDEX}} -> extractAvailableConnectionsIndex() [actionplan, dynamic]
{{KEY:AVAILABLE_CONNECTIONS_SUMMARY}} -> extractAvailableConnectionsSummary() []
-{{KEY:AVAILABLE_DOCUMENTS_SUMMARY}} -> extractAvailableDocumentsSummary() [taskplan, actionplan, react]
-{{KEY:AVAILABLE_DOCUMENTS_INDEX}} -> extractAvailableDocumentsIndex() [react]
-{{KEY:AVAILABLE_METHODS}} -> extractAvailableMethods() [actionplan, react]
-{{KEY:REVIEW_CONTENT}} -> extractReviewContent() [actionplan, react]
-{{KEY:PREVIOUS_ACTION_RESULTS}} -> extractPreviousActionResults() [react]
-{{KEY:LEARNINGS_AND_IMPROVEMENTS}} -> extractLearningsAndImprovements() [react]
-{{KEY:LATEST_REFINEMENT_FEEDBACK}} -> extractLatestRefinementFeedback() [react]
+{{KEY:AVAILABLE_DOCUMENTS_SUMMARY}} -> extractAvailableDocumentsSummary() [taskplan, actionplan, dynamic]
+{{KEY:AVAILABLE_DOCUMENTS_INDEX}} -> extractAvailableDocumentsIndex() [dynamic]
+{{KEY:AVAILABLE_METHODS}} -> extractAvailableMethods() [actionplan, dynamic]
+{{KEY:REVIEW_CONTENT}} -> extractReviewContent() [actionplan, dynamic]
+{{KEY:PREVIOUS_ACTION_RESULTS}} -> extractPreviousActionResults() [dynamic]
+{{KEY:LEARNINGS_AND_IMPROVEMENTS}} -> extractLearningsAndImprovements() [dynamic]
+{{KEY:LATEST_REFINEMENT_FEEDBACK}} -> extractLatestRefinementFeedback() [dynamic]
-Following placeholders are populated directly by prompt builders with according context in promptGenerationActionsReact module:
+Following placeholders are populated directly by prompt builders with according context in promptGenerationActionsDynamic module:
- ACTION_OBJECTIVE,
- SELECTED_ACTION,
- ACTION_SIGNATURE
diff --git a/modules/workflows/processing/shared/promptGenerationActionsReact.py b/modules/workflows/processing/shared/promptGenerationActionsDynamic.py
similarity index 96%
rename from modules/workflows/processing/shared/promptGenerationActionsReact.py
rename to modules/workflows/processing/shared/promptGenerationActionsDynamic.py
index 338a3af6..9c1ac389 100644
--- a/modules/workflows/processing/shared/promptGenerationActionsReact.py
+++ b/modules/workflows/processing/shared/promptGenerationActionsDynamic.py
@@ -1,6 +1,6 @@
"""
-React Mode Prompt Generation
-Handles prompt templates for react mode action handling.
+Dynamic Mode Prompt Generation
+Handles prompt templates for dynamic mode action handling.
"""
import json
@@ -20,7 +20,7 @@ from modules.workflows.processing.shared.placeholderFactory import (
)
from modules.workflows.processing.shared.methodDiscovery import methods, getActionParameterList
-def generateReactPlanSelectionPrompt(services, context: Any, learningEngine=None) -> PromptBundle:
+def generateDynamicPlanSelectionPrompt(services, context: Any, learningEngine=None) -> PromptBundle:
"""Define placeholders first, then the template; return PromptBundle."""
placeholders: List[PromptPlaceholder] = [
PromptPlaceholder(label="USER_PROMPT", content=extractUserPrompt(context), summaryAllowed=False),
@@ -113,7 +113,7 @@ RULES:
return PromptBundle(prompt=template, placeholders=placeholders)
-def generateReactParametersPrompt(services, context: Any, compoundActionName: str, learningEngine=None) -> PromptBundle:
+def generateDynamicParametersPrompt(services, context: Any, compoundActionName: str, learningEngine=None) -> PromptBundle:
"""Define placeholders first, then the template; return PromptBundle.
Minimal Stage 2 (no fallback): consumes actionObjective, selectedAction, parametersContext only.
@@ -265,7 +265,7 @@ RULES:
return PromptBundle(prompt=template, placeholders=placeholders)
-def generateReactRefinementPrompt(services, context: Any, reviewContent: str) -> PromptBundle:
+def generateDynamicRefinementPrompt(services, context: Any, reviewContent: str) -> PromptBundle:
"""Define placeholders first, then the template; return PromptBundle."""
placeholders: List[PromptPlaceholder] = [
PromptPlaceholder(label="USER_PROMPT", content=extractUserPrompt(context), summaryAllowed=False),
diff --git a/modules/workflows/processing/workflowProcessor.py b/modules/workflows/processing/workflowProcessor.py
index 8e3798b8..36027d9e 100644
--- a/modules/workflows/processing/workflowProcessor.py
+++ b/modules/workflows/processing/workflowProcessor.py
@@ -4,10 +4,11 @@
import logging
from typing import Dict, Any, Optional, List
from modules.datamodels.datamodelChat import TaskStep, TaskContext, TaskPlan, TaskResult
-from modules.datamodels.datamodelChat import ChatWorkflow
+from modules.datamodels.datamodelChat import ChatWorkflow, WorkflowModeEnum
from modules.workflows.processing.modes.modeBase import BaseMode
from modules.workflows.processing.modes.modeActionplan import ActionplanMode
-from modules.workflows.processing.modes.modeReact import ReactMode
+from modules.workflows.processing.modes.modeDynamic import DynamicMode
+from modules.workflows.processing.modes.modeTemplate import TemplateMode
logger = logging.getLogger(__name__)
@@ -21,15 +22,18 @@ class WorkflowProcessor:
def __init__(self, services, workflow=None):
self.services = services
self.workflow = workflow
- self.mode = self._createMode(workflow.workflowMode if workflow else "Actionplan")
+ self.mode = self._createMode(workflow.workflowMode if workflow else WorkflowModeEnum.WORKFLOW_DYNAMIC)
- def _createMode(self, workflowMode: str) -> BaseMode:
+ def _createMode(self, workflowMode: WorkflowModeEnum) -> BaseMode:
"""Create the appropriate mode implementation based on workflow mode"""
- if workflowMode == "React":
- return ReactMode(self.services, self.workflow)
- else:
+ if workflowMode == WorkflowModeEnum.WORKFLOW_DYNAMIC:
+ return DynamicMode(self.services, self.workflow)
+ elif workflowMode == WorkflowModeEnum.WORKFLOW_ACTIONPLAN:
return ActionplanMode(self.services, self.workflow)
-
+ elif workflowMode == WorkflowModeEnum.WORKFLOW_TEMPLATE:
+ return TemplateMode(self.services, self.workflow)
+ else:
+ raise ValueError(f"Invalid workflow mode: {workflowMode}")
def _checkWorkflowStopped(self, workflow):
"""Check if workflow has been stopped by user and raise exception if so"""
try:
@@ -61,7 +65,7 @@ class WorkflowProcessor:
operationId,
"Workflow Planning",
"Task Plan Generation",
- f"Mode: {workflow.workflowMode}"
+ f"Mode: {workflow.workflowMode.value if hasattr(workflow.workflowMode, 'value') else workflow.workflowMode}"
)
# Initialize currentUserLanguage to empty at workflow start
@@ -70,7 +74,8 @@ class WorkflowProcessor:
logger.info(f"=== STARTING TASK PLAN GENERATION ===")
logger.info(f"Workflow ID: {workflow.id}")
logger.info(f"User Input: {userInput}")
- logger.info(f"Workflow Mode: {workflow.workflowMode}")
+ modeValue = workflow.workflowMode.value if hasattr(workflow.workflowMode, 'value') else workflow.workflowMode
+ logger.info(f"Workflow Mode: {modeValue}")
# Update progress - generating task plan
self.services.workflow.progressLogUpdate(operationId, 0.3, "Analyzing input")
@@ -116,7 +121,8 @@ class WorkflowProcessor:
logger.info(f"=== STARTING TASK EXECUTION ===")
logger.info(f"Task: {taskStep.objective}")
- logger.info(f"Mode: {workflow.workflowMode}")
+ modeValue = workflow.workflowMode.value if hasattr(workflow.workflowMode, 'value') else workflow.workflowMode
+ logger.info(f"Mode: {modeValue}")
# Update progress - executing task
self.services.workflow.progressLogUpdate(operationId, 0.2, "Executing")
@@ -143,7 +149,8 @@ class WorkflowProcessor:
logger.info(f"=== STARTING ACTION GENERATION ===")
logger.info(f"Task: {taskStep.objective}")
- logger.info(f"Mode: {workflow.workflowMode}")
+ modeValue = workflow.workflowMode.value if hasattr(workflow.workflowMode, 'value') else workflow.workflowMode
+ logger.info(f"Mode: {modeValue}")
# Delegate to the appropriate mode
return await self.mode.generateActionItems(taskStep, workflow, previousResults, enhancedContext)
diff --git a/modules/workflows/workflowManager.py b/modules/workflows/workflowManager.py
index 6b254007..9123d102 100644
--- a/modules/workflows/workflowManager.py
+++ b/modules/workflows/workflowManager.py
@@ -8,7 +8,8 @@ from modules.datamodels.datamodelChat import (
UserInputRequest,
ChatMessage,
ChatWorkflow,
- ChatDocument
+ ChatDocument,
+ WorkflowModeEnum
)
from modules.datamodels.datamodelChat import TaskContext
from modules.workflows.processing.workflowProcessor import WorkflowProcessor, WorkflowStoppedException
@@ -25,7 +26,7 @@ class WorkflowManager:
# Exported functions
- async def workflowStart(self, userInput: UserInputRequest, workflowId: Optional[str] = None, workflowMode: str = "React") -> ChatWorkflow:
+ async def workflowStart(self, userInput: UserInputRequest, workflowId: Optional[str] = None, workflowMode: WorkflowModeEnum = WorkflowModeEnum.WORKFLOW_DYNAMIC) -> ChatWorkflow:
"""Starts a new workflow or continues an existing one, then launches processing."""
try:
# Debug log to check workflowMode parameter
@@ -90,7 +91,7 @@ class WorkflowManager:
"mandateId": self.services.user.mandateId,
"messageIds": [],
"workflowMode": workflowMode,
- "maxSteps": 5 if workflowMode == "React" else 1, # Set maxSteps for React mode
+ "maxSteps": 5 if workflowMode == WorkflowModeEnum.WORKFLOW_DYNAMIC else 1, # Set maxSteps for Dynamic mode
}
workflow = self.services.workflow.createWorkflow(workflowData)
@@ -320,7 +321,7 @@ class WorkflowManager:
task_plan = await handling.generateTaskPlan(userInput.prompt, workflow)
if not task_plan or not task_plan.tasks:
raise Exception("No tasks generated in task plan.")
- workflow_mode = getattr(workflow, 'workflowMode', 'Actionplan')
+ workflow_mode = getattr(workflow, 'workflowMode', WorkflowModeEnum.WORKFLOW_DYNAMIC)
logger.info(f"Workflow object attributes: {workflow.__dict__ if hasattr(workflow, '__dict__') else 'No __dict__'}")
logger.info(f"Executing workflow mode={workflow_mode} with {len(task_plan.tasks)} tasks")
return task_plan