""" Continuous Workflow Engine - Self-driving automation loop """ import asyncio import logging import uuid from datetime import datetime from typing import Dict, Any, List, Optional from enum import Enum from sqlalchemy.ext.asyncio import AsyncSession from app.core.database import get_db from app.core.config import get_settings logger = logging.getLogger(__name__) settings = get_settings() class WorkflowState(Enum): """Workflow execution states.""" IDLE = "idle" RUNNING = "running" COMPLETED = "completed" FAILED = "failed" PAUSED = "paused" class WorkflowStage(Enum): """Workflow stages.""" TRIGGER = "trigger" REASONING = "reasoning" PLANNING = "planning" EXECUTION = "execution" QUALITY_GATES = "quality_gates" DEPLOYMENT = "deployment" MONITORING = "monitoring" NOTIFICATION = "notification" class ContinuousWorkflowEngine: """ Self-driving continuous workflow engine. Runs the full workflow loop continuously. """ def __init__(self): self.is_running = False self.current_iteration = 0 self.state = WorkflowState.IDLE self.current_stage = None self.progress = 0.0 self.history: List[Dict] = [] self.subscribers: List[asyncio.Queue] = [] async def start(self): """Start the continuous workflow loop.""" self.is_running = True self.state = WorkflowState.RUNNING logger.info("πŸš€ Continuous workflow engine started") await self._notify({ "type": "engine_start", "timestamp": datetime.utcnow().isoformat(), }) while self.is_running: try: await self._run_iteration() self.current_iteration += 1 await asyncio.sleep(10) # Brief pause between iterations except Exception as e: logger.error(f"Workflow iteration error: {e}") await self._notify({ "type": "error", "error": str(e), "iteration": self.current_iteration, }) self.state = WorkflowState.IDLE async def stop(self): """Stop the workflow engine.""" self.is_running = False self.state = WorkflowState.PAUSED logger.info("⏸️ Workflow engine paused") await self._notify({ "type": "engine_stop", "timestamp": datetime.utcnow().isoformat(), }) async def _run_iteration(self): """Run one complete workflow iteration.""" iteration_id = str(uuid.uuid4()) start_time = datetime.utcnow() logger.info(f"πŸ”„ Starting iteration {self.current_iteration}") await self._update_stage(WorkflowStage.TRIGGER, 5) # ===== STAGE 1: TRIGGER ===== work_available = await self._check_for_work() if not work_available: logger.info("No work available, skipping iteration") await self._update_stage(WorkflowStage.TRIGGER, 100) await asyncio.sleep(1) return await self._update_stage(WorkflowStage.REASONING, 20) # ===== STAGE 2: REASONING ===== analysis = await self._run_reasoning() await self._update_stage(WorkflowStage.PLANNING, 35) # ===== STAGE 3: PLANNING ===== plan = await self._run_planning(analysis) await self._update_stage(WorkflowStage.EXECUTION, 50) # ===== STAGE 4: EXECUTION ===== execution_result = await self._run_execution(plan) await self._update_stage(WorkflowStage.QUALITY_GATES, 75) # ===== STAGE 5: QUALITY GATES ===== quality_passed = await self._run_quality_gates(execution_result) await self._update_stage(WorkflowStage.DEPLOYMENT, 85) # ===== STAGE 6: DEPLOYMENT ===== if quality_passed: await self._run_deployment(execution_result) await self._update_stage(WorkflowStage.MONITORING, 95) # ===== STAGE 7: MONITORING ===== await self._run_monitoring() await self._update_stage(WorkflowStage.NOTIFICATION, 100) # ===== STAGE 8: NOTIFICATION ===== await self._run_notification(quality_passed) # Record iteration duration = (datetime.utcnow() - start_time).total_seconds() self.history.append({ "iteration": self.current_iteration, "id": iteration_id, "start_time": start_time.isoformat(), "duration": duration, "status": "completed" if quality_passed else "failed", "changes": execution_result.get("changes", 0), }) logger.info(f"βœ… Iteration {self.current_iteration} completed in {duration:.1f}s") async def _check_for_work(self) -> bool: """Check if there's any work to do.""" # Check for: Git changes, Issues, Alerts, Scheduled tasks # For now, simulate with small random chance await asyncio.sleep(0.5) return True # Always run for demo async def _run_reasoning(self) -> Dict: """Run reasoning engine.""" await asyncio.sleep(1) result = { "issues_found": ["code_smell", "test_gap", "security"], "priority": "medium", "estimated_impact": "medium", } await self._notify({ "type": "stage_update", "stage": "reasoning", "data": result, }) return result async def _run_planning(self, analysis: Dict) -> Dict: """Run planning system.""" await asyncio.sleep(1) result = { "tasks": [ {"type": "code", "files": ["app/services/test.py"]}, {"type": "test", "coverage_delta": 5}, {"type": "docs", "files": ["README.md"]}, ], "dependencies": [], } await self._notify({ "type": "stage_update", "stage": "planning", "data": result, }) return result async def _run_execution(self, plan: Dict) -> Dict: """Run execution engine with agents.""" await asyncio.sleep(2) result = { "changes": 3, "files_modified": ["test.py", "README.md"], "tests_added": 10, "docs_updated": True, } await self._notify({ "type": "stage_update", "stage": "execution", "data": result, }) return result async def _run_quality_gates(self, execution: Dict) -> bool: """Run quality gates.""" await asyncio.sleep(1) result = { "lint": "passed", "tests": "passed", "security_scan": "passed", "all_green": True, } await self._notify({ "type": "stage_update", "stage": "quality_gates", "data": result, }) return True async def _run_deployment(self, execution: Dict): """Run deployment.""" await asyncio.sleep(1) await self._notify({ "type": "stage_update", "stage": "deployment", "data": {"deployed": True, "environment": "production"}, }) async def _run_monitoring(self): """Run monitoring.""" await asyncio.sleep(0.5) await self._notify({ "type": "stage_update", "stage": "monitoring", "data": {"metrics_collected": True}, }) async def _run_notification(self, success: bool): """Run notification.""" await self._notify({ "type": "stage_update", "stage": "notification", "data": { "sent": True, "channels": ["telegram"], "status": "success" if success else "failed", }, }) async def _update_stage(self, stage: WorkflowStage, progress: float): """Update current stage and notify subscribers.""" self.current_stage = stage self.progress = progress await self._notify({ "type": "stage_change", "stage": stage.value, "progress": progress, "iteration": self.current_iteration, "state": self.state.value, }) async def _notify(self, message: Dict): """Send notification to all subscribers.""" for queue in self.subscribers: try: await queue.put(message) except: pass def subscribe(self) -> asyncio.Queue: """Subscribe to workflow updates.""" queue = asyncio.Queue() self.subscribers.append(queue) return queue def unsubscribe(self, queue: asyncio.Queue): """Unsubscribe from updates.""" if queue in self.subscribers: self.subscribers.remove(queue) def get_status(self) -> Dict: """Get current workflow status.""" return { "is_running": self.is_running, "iteration": self.current_iteration, "state": self.state.value, "current_stage": self.current_stage.value if self.current_stage else None, "progress": self.progress, "history": self.history[-10:], # Last 10 iterations } # Global workflow engine instance workflow_engine = ContinuousWorkflowEngine()