diff --git a/modules/features/automation/mainAutomation.py b/modules/features/automation/mainAutomation.py index a7e381e1..aead6767 100644 --- a/modules/features/automation/mainAutomation.py +++ b/modules/features/automation/mainAutomation.py @@ -129,6 +129,7 @@ REQUIRED_SERVICES = [ {"serviceKey": "billing", "meta": {"usage": "AI call billing"}}, {"serviceKey": "extraction", "meta": {"usage": "Workflow method actions"}}, {"serviceKey": "sharepoint", "meta": {"usage": "SharePoint actions (listDocuments, uploadDocument, etc.)"}}, + {"serviceKey": "generation", "meta": {"usage": "Action completion messages, document creation from results"}}, ] @@ -158,7 +159,8 @@ def getAutomationServices( _workflow = workflow if _workflow is None: - _workflow = type("_Placeholder", (), {"featureCode": FEATURE_CODE})() + # Placeholder must have 'id' and 'workflowMode' to avoid AttributeError when services use context.workflow + _workflow = type("_Placeholder", (), {"featureCode": FEATURE_CODE, "id": None, "workflowMode": None})() ctx = ServiceCenterContext( user=user, mandate_id=mandateId, @@ -170,6 +172,7 @@ def getAutomationServices( hub.user = user hub.mandateId = mandateId hub.featureInstanceId = featureInstanceId + hub._service_context = ctx # Store context so workflow updates propagate to services hub.workflow = workflow hub.featureCode = FEATURE_CODE hub.allowedProviders = None @@ -206,6 +209,7 @@ class _AutomationServiceHub: user = None mandateId = None featureInstanceId = None + _service_context = None # ServiceCenterContext; when workflow is set, context.workflow is updated workflow = None featureCode = "automation" allowedProviders = None diff --git a/modules/features/chatplayground/mainChatplayground.py b/modules/features/chatplayground/mainChatplayground.py index d01c1c23..269f74d5 100644 --- a/modules/features/chatplayground/mainChatplayground.py +++ b/modules/features/chatplayground/mainChatplayground.py @@ -57,6 +57,7 @@ REQUIRED_SERVICES = [ {"serviceKey": "billing", "meta": {"usage": "AI call billing"}}, {"serviceKey": "extraction", "meta": {"usage": "Workflow method actions"}}, {"serviceKey": "sharepoint", "meta": {"usage": "SharePoint actions (listDocuments, uploadDocument, etc.)"}}, + {"serviceKey": "generation", "meta": {"usage": "Action completion messages, document creation from results"}}, ] # Template roles for this feature # Role names MUST follow convention: {featureCode}-{roleName} diff --git a/modules/serviceCenter/services/serviceAi/mainServiceAi.py b/modules/serviceCenter/services/serviceAi/mainServiceAi.py index 08f3ccb3..eff5671f 100644 --- a/modules/serviceCenter/services/serviceAi/mainServiceAi.py +++ b/modules/serviceCenter/services/serviceAi/mainServiceAi.py @@ -31,15 +31,18 @@ AiCallRequest.model_rebuild() class _ServicesAdapter: - """Adapter providing Services-like interface from (context, get_service).""" - + """Adapter providing Services-like interface from (context, get_service). + Workflow is read from context dynamically so propagation updates are visible.""" def __init__(self, context, get_service: Callable[[str], Any]): self._context = context self._get_service = get_service self.user = context.user self.mandateId = context.mandate_id self.featureInstanceId = context.feature_instance_id - self.workflow = context.workflow + + @property + def workflow(self): + return self._context.workflow @property def chat(self): diff --git a/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py b/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py index db0d2346..8fccd4e4 100644 --- a/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py +++ b/modules/serviceCenter/services/serviceGeneration/mainServiceGeneration.py @@ -19,19 +19,22 @@ logger = logging.getLogger(__name__) class _ServicesAdapter: - """Adapter providing Services-like interface from (context, get_service).""" - + """Adapter providing Services-like interface from (context, get_service). + Workflow is read from context dynamically so propagation updates are visible.""" def __init__(self, context, get_service: Callable[[str], Any]): self._context = context self._get_service = get_service self.user = context.user self.mandateId = context.mandate_id self.featureInstanceId = context.feature_instance_id - self.workflow = context.workflow chat = get_service("chat") self.interfaceDbComponent = chat.interfaceDbComponent self.interfaceDbChat = chat.interfaceDbChat + @property + def workflow(self): + return self._context.workflow + @property def chat(self): return self._get_service("chat") diff --git a/modules/workflows/processing/workflowProcessor.py b/modules/workflows/processing/workflowProcessor.py index 72f45cce..3f83379b 100644 --- a/modules/workflows/processing/workflowProcessor.py +++ b/modules/workflows/processing/workflowProcessor.py @@ -27,9 +27,14 @@ class WorkflowProcessor: def __init__(self, services): self.services = services - self.mode = self._createMode(services.workflow.workflowMode) - self.mode.processor = self # So mode can call persistTaskResult for per-action chaining self.workflow = services.workflow + if not self.workflow: + raise ValueError("WorkflowProcessor requires services.workflow (set by WorkflowManager before processing)") + workflowMode = getattr(self.workflow, 'workflowMode', None) + if not workflowMode: + raise ValueError("WorkflowProcessor requires services.workflow.workflowMode") + self.mode = self._createMode(workflowMode) + self.mode.processor = self # So mode can call persistTaskResult for per-action chaining self.workflowExecOperationId = None # Will be set by workflowManager for task hierarchy def _createMode(self, workflowMode: WorkflowModeEnum) -> BaseMode: