407 lines
14 KiB
Markdown
407 lines
14 KiB
Markdown
# Automation Feature Analysis: Moving Automation Handler to Features Layer
|
|
|
|
## Executive Summary
|
|
|
|
**Status: ✅ HIGHLY RECOMMENDED - Architectural Improvement**
|
|
|
|
Moving automation workflow handler functionality from `interfaces/interfaceDbChatObjects.py` to a new feature in `features/` is **architecturally correct** and aligns with separation of concerns.
|
|
|
|
---
|
|
|
|
## Current Architecture Analysis
|
|
|
|
### Current Location: `interfaces/interfaceDbChatObjects.py`
|
|
|
|
**Automation-related methods:**
|
|
1. `executeAutomation(automationId: str)` - Executes automation workflow immediately (test mode)
|
|
2. `syncAutomationEvents()` - Syncs scheduler with all active automations
|
|
3. `_createAutomationEventHandler(automationId: str)` - Creates event handler for scheduled execution
|
|
4. `_parseScheduleToCron(schedule: str)` - Parses schedule string to cron kwargs
|
|
5. `_planToPrompt(plan: Dict)` - Converts plan structure to prompt string
|
|
6. `_replacePlaceholders(template: str, placeholders: Dict)` - Replaces placeholders in template
|
|
|
|
**Dependencies:**
|
|
- Uses `getAutomationDefinition()` - Database access (should stay in interface)
|
|
- Uses `chatStart()` from `features.chatPlayground` - Already imports from features
|
|
- Uses `eventManager` from `shared.eventManagement` - Foundation layer
|
|
- Creates workflows using `WorkflowModeEnum.WORKFLOW_AUTOMATION`
|
|
|
|
---
|
|
|
|
## Why This Should Be a Feature
|
|
|
|
### 1. **Business Logic vs. Data Access**
|
|
|
|
**Current Problem:**
|
|
- Automation execution logic is **business logic** (orchestration, workflow creation)
|
|
- It's mixed with **data access** (interface layer)
|
|
- Interface layer should only provide data access, not business orchestration
|
|
|
|
**After Move:**
|
|
- Interface layer: `getAutomationDefinition()`, `saveAutomationDefinition()` (data access)
|
|
- Feature layer: `executeAutomation()`, `syncAutomationEvents()` (business logic)
|
|
|
|
### 2. **Feature Pattern Consistency**
|
|
|
|
**Existing Features Pattern:**
|
|
- `features/chatPlayground/` - Chat workflow execution
|
|
- `features/chatAlthaus/` - Scheduled data updates
|
|
- `features/syncDelta/` - Sync management
|
|
- `features/neutralizePlayground/` - Neutralization workflows
|
|
|
|
**Automation Handler Pattern:**
|
|
- Scheduled execution (like `chatAlthaus`)
|
|
- Workflow orchestration (like `chatPlayground`)
|
|
- Event-driven (like `syncDelta`)
|
|
|
|
**Conclusion:** Automation handler fits the feature pattern perfectly.
|
|
|
|
### 3. **Dependency Direction**
|
|
|
|
**Current Violation:**
|
|
- `interfaces/` imports from `features/` (line 1927: `from modules.features.chatPlayground.mainChatPlayground import chatStart`)
|
|
- This creates bidirectional dependency: `interfaces/ ↔ features/`
|
|
|
|
**After Move:**
|
|
- `features/automation/` imports from `interfaces/` (correct direction)
|
|
- `features/automation/` imports from `features/chatPlayground/` (feature-to-feature)
|
|
- Eliminates `interfaces/ → features/` import
|
|
|
|
### 4. **Separation of Concerns**
|
|
|
|
**Interface Layer Should:**
|
|
- ✅ Provide data access (`getAutomationDefinition`, `saveAutomationDefinition`)
|
|
- ✅ Handle CRUD operations
|
|
- ❌ NOT orchestrate workflows
|
|
- ❌ NOT manage scheduling
|
|
- ❌ NOT execute business logic
|
|
|
|
**Feature Layer Should:**
|
|
- ✅ Orchestrate workflows
|
|
- ✅ Manage scheduling
|
|
- ✅ Execute business logic
|
|
- ✅ Coordinate between services and interfaces
|
|
|
|
---
|
|
|
|
## Proposed Architecture
|
|
|
|
### New Structure: `features/automation/`
|
|
|
|
```
|
|
features/automation/
|
|
├── mainAutomation.py # Main automation service
|
|
│ ├── executeAutomation() # Execute automation workflow
|
|
│ ├── syncAutomationEvents() # Sync scheduler with automations
|
|
│ └── _createAutomationEventHandler() # Create event handler
|
|
└── subAutomationUtils.py # Utility functions
|
|
├── _parseScheduleToCron() # Parse schedule to cron
|
|
├── _planToPrompt() # Convert plan to prompt
|
|
└── _replacePlaceholders() # Replace template placeholders
|
|
```
|
|
|
|
### Interface Layer (Keep)
|
|
|
|
```
|
|
interfaces/interfaceDbChatObjects.py
|
|
├── getAutomationDefinition() # Data access - KEEP
|
|
├── saveAutomationDefinition() # Data access - KEEP
|
|
└── (other CRUD methods) # Data access - KEEP
|
|
```
|
|
|
|
### Feature Lifecycle Integration
|
|
|
|
```
|
|
features/featuresLifecycle.py
|
|
├── start()
|
|
│ └── from features.automation import mainAutomation
|
|
│ mainAutomation.startScheduler(eventUser)
|
|
└── stop()
|
|
└── mainAutomation.stopScheduler()
|
|
```
|
|
|
|
---
|
|
|
|
## Detailed Functionality Analysis
|
|
|
|
### Functions to Move
|
|
|
|
#### 1. `executeAutomation(automationId: str)` → `features/automation/mainAutomation.py`
|
|
|
|
**Current Implementation:**
|
|
- Loads automation definition (calls interface method)
|
|
- Replaces placeholders in template
|
|
- Creates UserInputRequest
|
|
- Calls `chatStart()` from `features.chatPlayground`
|
|
- Returns ChatWorkflow
|
|
|
|
**Dependencies:**
|
|
- `getAutomationDefinition()` - Interface method (import from interface)
|
|
- `_replacePlaceholders()` - Utility (move to feature)
|
|
- `_planToPrompt()` - Utility (move to feature)
|
|
- `chatStart()` - Feature method (import from feature)
|
|
- `getInterface()` - Interface factory (import from interface)
|
|
|
|
**After Move:**
|
|
```python
|
|
# features/automation/mainAutomation.py
|
|
from modules.interfaces.interfaceDbChatObjects import getInterface as getChatInterface
|
|
from modules.interfaces.interfaceDbAppObjects import getInterface as getAppInterface
|
|
from modules.features.chatPlayground.mainChatPlayground import chatStart
|
|
from .subAutomationUtils import replacePlaceholders, planToPrompt
|
|
|
|
async def executeAutomation(automationId: str, chatInterface) -> ChatWorkflow:
|
|
"""Execute automation workflow immediately."""
|
|
# Load automation (uses interface)
|
|
automation = chatInterface.getAutomationDefinition(automationId)
|
|
# ... rest of logic
|
|
```
|
|
|
|
#### 2. `syncAutomationEvents()` → `features/automation/mainAutomation.py`
|
|
|
|
**Current Implementation:**
|
|
- Gets all automation definitions (calls interface method)
|
|
- Parses schedules
|
|
- Registers cron jobs with eventManager
|
|
- Creates event handlers
|
|
|
|
**Dependencies:**
|
|
- `getRecordset()` - Interface method (via chatInterface)
|
|
- `_parseScheduleToCron()` - Utility (move to feature)
|
|
- `_createAutomationEventHandler()` - Handler creation (move to feature)
|
|
- `eventManager` - Foundation layer (import from shared)
|
|
|
|
**After Move:**
|
|
```python
|
|
# features/automation/mainAutomation.py
|
|
from modules.shared.eventManagement import eventManager
|
|
from modules.interfaces.interfaceDbChatObjects import getInterface as getChatInterface
|
|
from .subAutomationUtils import parseScheduleToCron
|
|
|
|
async def syncAutomationEvents(chatInterface) -> Dict[str, Any]:
|
|
"""Sync scheduler with all active automations."""
|
|
# Get automations (uses interface)
|
|
allAutomations = chatInterface.db.getRecordset(AutomationDefinition)
|
|
# ... rest of logic
|
|
```
|
|
|
|
#### 3. `_createAutomationEventHandler(automationId: str)` → `features/automation/mainAutomation.py`
|
|
|
|
**Current Implementation:**
|
|
- Creates async handler function
|
|
- Gets event user
|
|
- Loads automation
|
|
- Executes automation with creator user context
|
|
|
|
**Dependencies:**
|
|
- `getRootInterface()` - Interface factory (import from interface)
|
|
- `getInterface()` - Interface factories (import from interfaces)
|
|
- `executeAutomation()` - Will be in same module
|
|
|
|
**After Move:**
|
|
```python
|
|
# features/automation/mainAutomation.py
|
|
def createAutomationEventHandler(automationId: str):
|
|
"""Create event handler function for scheduled automation."""
|
|
async def handler():
|
|
# Uses interfaces and executeAutomation from same module
|
|
await executeAutomation(automationId, eventInterface)
|
|
return handler
|
|
```
|
|
|
|
#### 4. Utility Functions → `features/automation/subAutomationUtils.py`
|
|
|
|
**Functions:**
|
|
- `_parseScheduleToCron(schedule: str)` - Parse schedule to cron kwargs
|
|
- `_planToPrompt(plan: Dict)` - Convert plan to prompt string
|
|
- `_replacePlaceholders(template: str, placeholders: Dict)` - Replace placeholders
|
|
|
|
**Dependencies:**
|
|
- No external dependencies (pure utility functions)
|
|
|
|
---
|
|
|
|
## Migration Plan
|
|
|
|
### Phase 1: Create Feature Structure
|
|
|
|
1. Create `features/automation/` directory
|
|
2. Create `features/automation/__init__.py`
|
|
3. Create `features/automation/mainAutomation.py`
|
|
4. Create `features/automation/subAutomationUtils.py`
|
|
|
|
### Phase 2: Move Functions
|
|
|
|
1. Move utility functions to `subAutomationUtils.py`
|
|
2. Move `executeAutomation()` to `mainAutomation.py`
|
|
3. Move `syncAutomationEvents()` to `mainAutomation.py`
|
|
4. Move `_createAutomationEventHandler()` to `mainAutomation.py`
|
|
|
|
### Phase 3: Update Dependencies
|
|
|
|
1. Update `features/featuresLifecycle.py` to use new feature
|
|
2. Update `routes/routeAdminAutomationEvents.py` to use new feature
|
|
3. Update any other call sites
|
|
|
|
### Phase 4: Cleanup Interface
|
|
|
|
1. Remove moved functions from `interfaceDbChatObjects.py`
|
|
2. Keep only data access methods (`getAutomationDefinition`, etc.)
|
|
3. Remove import from `features.chatPlayground` from interface
|
|
|
|
### Phase 5: Update Documentation
|
|
|
|
1. Update `BIDIRECTIONAL_IMPORTS.md` to reflect resolved dependency
|
|
2. Document new feature structure
|
|
|
|
---
|
|
|
|
## Benefits
|
|
|
|
### ✅ Architectural Benefits
|
|
|
|
1. **Correct Separation of Concerns**
|
|
- Interface layer: Data access only
|
|
- Feature layer: Business logic and orchestration
|
|
|
|
2. **Resolves Bidirectional Dependency**
|
|
- Eliminates `interfaces/ → features/` import
|
|
- Only `features/ → interfaces/` remains (correct direction)
|
|
|
|
3. **Consistency with Existing Patterns**
|
|
- Matches other feature implementations
|
|
- Follows established architecture
|
|
|
|
4. **Better Testability**
|
|
- Feature logic can be tested independently
|
|
- Interface layer remains focused
|
|
|
|
### ✅ Maintainability Benefits
|
|
|
|
1. **Clearer Code Organization**
|
|
- Automation logic in one place
|
|
- Easier to find and modify
|
|
|
|
2. **Reduced Coupling**
|
|
- Interface layer doesn't depend on features
|
|
- Features depend on interfaces (correct direction)
|
|
|
|
3. **Easier to Extend**
|
|
- New automation features can be added to feature module
|
|
- Interface layer remains stable
|
|
|
|
---
|
|
|
|
## Risks and Considerations
|
|
|
|
### 🟢 Low Risk
|
|
|
|
- **Functionality preservation** - Logic doesn't change, only location
|
|
- **Interface methods remain** - Data access methods stay in interface
|
|
- **Lazy imports** - Already using lazy imports for event handlers
|
|
|
|
### 🟡 Medium Risk
|
|
|
|
- **Call site updates** - Need to update routes and lifecycle
|
|
- **Interface method access** - Feature needs to call interface methods
|
|
- **Event user context** - Need to ensure proper user context handling
|
|
|
|
### 🔴 Potential Issues
|
|
|
|
1. **Interface method access** - Feature needs `chatInterface` instance
|
|
- **Solution:** Pass interface instance as parameter or create in feature
|
|
|
|
2. **Event handler context** - Event handlers need interface access
|
|
- **Solution:** Create interface instances in handler (already doing this)
|
|
|
|
3. **Backward compatibility** - Existing code calling `chatInterface.executeAutomation()`
|
|
- **Solution:** Update all call sites, or create wrapper method in interface (deprecated)
|
|
|
|
---
|
|
|
|
## Call Sites Analysis
|
|
|
|
### Current Call Sites
|
|
|
|
1. **`features/featuresLifecycle.py` (line 20)**
|
|
```python
|
|
await chatInterface.syncAutomationEvents()
|
|
```
|
|
**Update:** Import and call feature directly
|
|
|
|
2. **`routes/routeAdminAutomationEvents.py` (line 97)**
|
|
```python
|
|
result = await chatInterface.syncAutomationEvents()
|
|
```
|
|
**Update:** Import and call feature directly
|
|
|
|
3. **`interfaces/interfaceDbChatObjects.py` (lines 1683, 1714, 1744)**
|
|
```python
|
|
asyncio.create_task(self.syncAutomationEvents())
|
|
```
|
|
**Update:** Remove (will be handled by feature lifecycle)
|
|
|
|
4. **`_createAutomationEventHandler()` (line 2105)**
|
|
```python
|
|
await creatorInterface.executeAutomation(automationId)
|
|
```
|
|
**Update:** Call feature method instead
|
|
|
|
### Proposed Call Sites
|
|
|
|
1. **`features/featuresLifecycle.py`**
|
|
```python
|
|
from modules.features.automation import mainAutomation
|
|
await mainAutomation.syncAutomationEvents(chatInterface)
|
|
```
|
|
|
|
2. **`routes/routeAdminAutomationEvents.py`**
|
|
```python
|
|
from modules.features.automation import mainAutomation
|
|
result = await mainAutomation.syncAutomationEvents(chatInterface)
|
|
```
|
|
|
|
3. **`features/automation/mainAutomation.py` (event handler)**
|
|
```python
|
|
from .mainAutomation import executeAutomation
|
|
await executeAutomation(automationId, eventInterface)
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Checklist
|
|
|
|
- [ ] Create `features/automation/` directory structure
|
|
- [ ] Create `features/automation/__init__.py`
|
|
- [ ] Create `features/automation/mainAutomation.py`
|
|
- [ ] Create `features/automation/subAutomationUtils.py`
|
|
- [ ] Move `_parseScheduleToCron()` to `subAutomationUtils.py`
|
|
- [ ] Move `_planToPrompt()` to `subAutomationUtils.py`
|
|
- [ ] Move `_replacePlaceholders()` to `subAutomationUtils.py`
|
|
- [ ] Move `executeAutomation()` to `mainAutomation.py`
|
|
- [ ] Move `syncAutomationEvents()` to `mainAutomation.py`
|
|
- [ ] Move `_createAutomationEventHandler()` to `mainAutomation.py`
|
|
- [ ] Update `features/featuresLifecycle.py` to use feature
|
|
- [ ] Update `routes/routeAdminAutomationEvents.py` to use feature
|
|
- [ ] Remove moved functions from `interfaceDbChatObjects.py`
|
|
- [ ] Remove `features.chatPlayground` import from `interfaceDbChatObjects.py`
|
|
- [ ] Update `BIDIRECTIONAL_IMPORTS.md`
|
|
- [ ] Test automation execution (manual)
|
|
- [ ] Test automation scheduling (scheduled)
|
|
- [ ] Verify no circular dependencies
|
|
|
|
---
|
|
|
|
## Conclusion
|
|
|
|
**✅ STRONGLY RECOMMENDED: Move to Features Layer**
|
|
|
|
This refactoring is:
|
|
- **Architecturally correct** - Business logic belongs in features, not interfaces
|
|
- **Resolves dependency violation** - Eliminates `interfaces/ → features/` import
|
|
- **Consistent with patterns** - Matches existing feature implementations
|
|
- **Low risk** - Logic doesn't change, only location
|
|
- **Improves maintainability** - Clearer separation of concerns
|
|
|
|
**Recommendation: PROCEED** with moving automation handler functionality to `features/automation/` following the plan above.
|
|
|