gateway/modules/workflows/processing/shared/executionState.py
2025-10-05 16:28:44 +02:00

81 lines
No EOL
3.2 KiB
Python

# executionState.py
# Contains all execution state management logic
import logging
from typing import List
from datetime import datetime, UTC
from modules.datamodels.datamodelChat import TaskStep
from modules.datamodels.datamodelChat import ActionResult
logger = logging.getLogger(__name__)
class TaskExecutionState:
"""Manages execution state for a task with retry logic"""
def __init__(self, task_step: TaskStep):
self.task_step = task_step
self.successful_actions: List[ActionResult] = [] # Preserved across retries
self.failed_actions: List[ActionResult] = [] # For analysis
self.current_action_index = 0
self.retry_count = 0
self.max_retries = 3
# Iterative loop (react mode)
self.current_step = 0
self.max_steps = 5
def addSuccessfulAction(self, action_result: ActionResult):
"""Add a successful action to the state"""
self.successful_actions.append(action_result)
self.current_action_index += 1
def addFailedAction(self, action_result: ActionResult):
"""Add a failed action to the state for analysis"""
self.failed_actions.append(action_result)
self.current_action_index += 1
def canRetry(self) -> bool:
"""Check if task can be retried"""
return self.retry_count < self.max_retries
def incrementRetryCount(self):
"""Increment retry count"""
self.retry_count += 1
def getFailurePatterns(self) -> list:
"""Analyze failure patterns from failed actions"""
patterns = []
for action in self.failed_actions:
error = action.error.lower() if action.error else ''
if "timeout" in error:
patterns.append("timeout_issues")
elif "document_not_found" in error or "file not found" in error:
patterns.append("document_reference_issues")
elif "empty_result" in error or "no content" in error:
patterns.append("content_extraction_issues")
elif "invalid_format" in error or "wrong format" in error:
patterns.append("format_issues")
elif "permission" in error or "access denied" in error:
patterns.append("permission_issues")
return list(set(patterns))
def shouldContinue(observation, review=None, current_step: int = 0, max_steps: int = 5) -> bool:
"""Helper to decide if the iterative loop should continue
- Stop if review indicates 'stop' or success criteria are met
- Stop on failure with no retry path
- Stop if max steps reached
"""
try:
if current_step >= max_steps:
return False
if review and isinstance(review, dict):
decision = review.get('decision') or review.get('status')
if decision in ('stop', 'success'):
return False
# If observation exists but indicates hard failure with no documents repeatedly
if observation and isinstance(observation, dict):
if observation.get('success') is False and observation.get('documentsCount', 0) == 0:
# allow next step once; the caller can cap by max_steps
return True
return True
except Exception:
return False