feat: replay E2E fonctionnel — 25/25 actions, 0 retries, SomEngine via serveur

Validé sur PC Windows (DESKTOP-58D5CAC, 2560x1600) :
- 8 clics résolus visuellement (1 anchor_template, 1 som_text_match, 6 som_vlm)
- Score moyen 0.75, temps moyen 1.6s
- Texte tapé correctement (bonjour, test word, date, email)
- 0 retries, 2 actions non vérifiées (OK)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-03-31 14:04:41 +02:00
parent 5e0b53cfd1
commit a7de6a488b
79542 changed files with 6091757 additions and 1 deletions

View File

@@ -0,0 +1,615 @@
# Design Document - Workflow Composition
## Overview
Ce document décrit l'architecture et la conception pour la composition et le contrôle de flux des workflows dans RPA Vision V3. Le système permet de chaîner des workflows, créer des sous-workflows réutilisables, fusionner des workflows similaires, et utiliser des structures de contrôle (boucles, conditions, déclencheurs).
## Architecture
```mermaid
graph TB
subgraph "Composition Layer"
WC[WorkflowChainer]
SR[SubWorkflowRegistry]
WM[WorkflowMerger]
SE[SequenceExtractor]
end
subgraph "Control Flow Layer"
LE[LoopExecutor]
CE[ConditionalEvaluator]
TM[TriggerManager]
end
subgraph "Data Layer"
VM[VariableManager]
DG[DependencyGraph]
EL[ExecutionLogger]
end
subgraph "Existing Core"
WG[WorkflowGraph]
EX[ExecutionLoop]
TR[TargetResolver]
end
WC --> VM
WC --> EL
SR --> DG
WM --> WG
SE --> SR
LE --> EX
CE --> TR
TM --> EX
VM --> EL
DG --> SR
```
## Components and Interfaces
### 1. WorkflowChainer
Gère l'exécution séquentielle de workflows chaînés.
```python
@dataclass
class ChainConfig:
"""Configuration de chaînage entre workflows."""
source_workflow_id: str
target_workflow_id: str
variable_mapping: Dict[str, str] # source_var -> target_var
on_failure: Literal["retry", "skip", "abort"]
max_retries: int = 3
class WorkflowChainer:
def __init__(self, variable_manager: VariableManager, logger: ExecutionLogger):
self.variable_manager = variable_manager
self.logger = logger
self.chains: Dict[str, List[ChainConfig]] = {}
def add_chain(self, config: ChainConfig) -> None:
"""Ajoute une configuration de chaînage."""
def validate_chain(self, source_id: str, target_id: str) -> ValidationResult:
"""Valide la compatibilité entre deux workflows."""
def execute_chain(self, start_workflow_id: str, context: ExecutionContext) -> ChainResult:
"""Exécute une chaîne de workflows."""
def to_dict(self) -> Dict[str, Any]:
"""Sérialise la configuration de chaînage."""
@classmethod
def from_dict(cls, data: Dict[str, Any], ...) -> 'WorkflowChainer':
"""Désérialise la configuration de chaînage."""
```
### 2. SubWorkflowRegistry
Gère les sous-workflows réutilisables et leurs références.
```python
@dataclass
class SubWorkflowDefinition:
"""Définition d'un sous-workflow."""
workflow_id: str
name: str
input_parameters: List[ParameterDef]
output_values: List[ParameterDef]
@dataclass
class ReferenceNode:
"""Node qui référence un sous-workflow."""
node_id: str
sub_workflow_id: str
input_bindings: Dict[str, str] # param_name -> variable_name
output_bindings: Dict[str, str]
class SubWorkflowRegistry:
def __init__(self, dependency_graph: DependencyGraph):
self.dependency_graph = dependency_graph
self.definitions: Dict[str, SubWorkflowDefinition] = {}
self.references: Dict[str, List[ReferenceNode]] = {}
def register(self, definition: SubWorkflowDefinition) -> None:
"""Enregistre un sous-workflow."""
def create_reference(self, parent_workflow_id: str, ref: ReferenceNode) -> None:
"""Crée une référence vers un sous-workflow."""
def execute_reference(self, ref: ReferenceNode, context: ExecutionContext) -> ExecutionResult:
"""Exécute un sous-workflow via sa référence."""
def get_dependents(self, workflow_id: str) -> List[str]:
"""Retourne les workflows qui dépendent de ce sous-workflow."""
def to_dict(self) -> Dict[str, Any]:
"""Sérialise le registre."""
@classmethod
def from_dict(cls, data: Dict[str, Any], ...) -> 'SubWorkflowRegistry':
"""Désérialise le registre."""
```
### 3. WorkflowMerger
Détecte et fusionne les workflows similaires.
```python
@dataclass
class MergeCandidate:
"""Candidat à la fusion."""
workflow_a_id: str
workflow_b_id: str
similarity_score: float
shared_nodes: List[str]
conflicts: List[NodeConflict]
@dataclass
class NodeConflict:
"""Conflit entre deux nodes."""
node_id: str
action_a: str
action_b: str
class WorkflowMerger:
def __init__(self, similarity_threshold: float = 0.9):
self.similarity_threshold = similarity_threshold
def calculate_similarity(self, workflow_a: WorkflowGraph, workflow_b: WorkflowGraph) -> float:
"""Calcule la similarité entre deux workflows."""
def find_merge_candidates(self, workflows: List[WorkflowGraph]) -> List[MergeCandidate]:
"""Trouve les paires de workflows candidats à la fusion."""
def merge(self, workflow_a: WorkflowGraph, workflow_b: WorkflowGraph,
conflict_resolutions: Dict[str, str]) -> WorkflowGraph:
"""Fusionne deux workflows en préservant tous les chemins uniques."""
def get_unique_paths(self, workflow: WorkflowGraph) -> List[List[str]]:
"""Extrait tous les chemins uniques d'un workflow."""
```
### 4. SequenceExtractor
Détecte et extrait les séquences communes.
```python
@dataclass
class CommonSequence:
"""Séquence commune détectée."""
nodes: List[str]
occurrences: List[SequenceOccurrence]
priority: Literal["high", "medium", "low"]
@dataclass
class SequenceOccurrence:
"""Occurrence d'une séquence dans un workflow."""
workflow_id: str
start_index: int
end_index: int
class SequenceExtractor:
def __init__(self, registry: SubWorkflowRegistry, min_sequence_length: int = 3):
self.registry = registry
self.min_sequence_length = min_sequence_length
def find_common_sequences(self, workflows: List[WorkflowGraph]) -> List[CommonSequence]:
"""Trouve les séquences communes entre workflows."""
def extract_as_subworkflow(self, sequence: CommonSequence, name: str) -> SubWorkflowDefinition:
"""Extrait une séquence comme sous-workflow."""
def replace_with_references(self, sequence: CommonSequence, sub_workflow_id: str) -> None:
"""Remplace les occurrences par des références."""
```
### 5. LoopExecutor
Gère l'exécution des boucles.
```python
@dataclass
class LoopConfig:
"""Configuration d'une boucle."""
loop_id: str
loop_type: Literal["count", "condition"]
max_iterations: Optional[int] # Pour type "count"
exit_condition: Optional[VisualCondition] # Pour type "condition"
body_nodes: List[str]
safety_limit: int = 1000
@dataclass
class LoopState:
"""État d'exécution d'une boucle."""
loop_id: str
current_iteration: int
started_at: datetime
last_condition_result: Optional[bool]
class LoopExecutor:
def __init__(self, execution_loop: ExecutionLoop, safety_limit: int = 1000):
self.execution_loop = execution_loop
self.safety_limit = safety_limit
self.active_loops: Dict[str, LoopState] = {}
def start_loop(self, config: LoopConfig, context: ExecutionContext) -> LoopState:
"""Démarre une nouvelle boucle."""
def execute_iteration(self, loop_id: str, context: ExecutionContext) -> IterationResult:
"""Exécute une itération de la boucle."""
def should_continue(self, loop_id: str, context: ExecutionContext) -> bool:
"""Évalue si la boucle doit continuer."""
def increment_counter(self, loop_id: str) -> int:
"""Incrémente le compteur et retourne la nouvelle valeur."""
def to_dict(self) -> Dict[str, Any]:
"""Sérialise l'état des boucles."""
@classmethod
def from_dict(cls, data: Dict[str, Any], ...) -> 'LoopExecutor':
"""Désérialise l'état des boucles."""
```
### 6. ConditionalEvaluator
Évalue les conditions et détermine les branches à exécuter.
```python
@dataclass
class BranchConfig:
"""Configuration d'une branche conditionnelle."""
branch_id: str
condition: VisualCondition
target_node: str
priority: int # Ordre d'évaluation
@dataclass
class ConditionalNode:
"""Node conditionnel avec plusieurs branches."""
node_id: str
branches: List[BranchConfig]
default_branch: Optional[str]
@dataclass
class VisualCondition:
"""Condition basée sur l'état visuel."""
condition_type: Literal["element_present", "element_absent", "text_equals", "text_contains"]
target_element: Optional[str] # ID ou template
expected_text: Optional[str]
class ConditionalEvaluator:
def __init__(self, target_resolver: TargetResolver):
self.target_resolver = target_resolver
def evaluate_condition(self, condition: VisualCondition, screenshot: np.ndarray) -> bool:
"""Évalue une condition visuelle."""
def evaluate_node(self, node: ConditionalNode, screenshot: np.ndarray) -> str:
"""Évalue un node conditionnel et retourne l'ID de la branche à exécuter."""
def to_dict(self) -> Dict[str, Any]:
"""Sérialise la configuration."""
@classmethod
def from_dict(cls, data: Dict[str, Any], ...) -> 'ConditionalEvaluator':
"""Désérialise la configuration."""
```
### 7. TriggerManager
Gère les déclencheurs automatiques.
```python
@dataclass
class ScheduleTrigger:
"""Déclencheur basé sur un horaire."""
trigger_id: str
workflow_id: str
cron_expression: Optional[str]
interval_seconds: Optional[int]
@dataclass
class FileTrigger:
"""Déclencheur basé sur l'apparition d'un fichier."""
trigger_id: str
workflow_id: str
watch_directory: str
file_pattern: str
@dataclass
class VisualTrigger:
"""Déclencheur basé sur la détection visuelle."""
trigger_id: str
workflow_id: str
target_element: str
check_interval_seconds: int
@dataclass
class TriggerContext:
"""Contexte passé au workflow lors du déclenchement."""
trigger_id: str
trigger_type: str
fired_at: datetime
file_path: Optional[str]
detected_element: Optional[Dict[str, Any]]
class TriggerManager:
def __init__(self, execution_loop: ExecutionLoop, concurrency_mode: Literal["concurrent", "queue"]):
self.execution_loop = execution_loop
self.concurrency_mode = concurrency_mode
self.triggers: Dict[str, Union[ScheduleTrigger, FileTrigger, VisualTrigger]] = {}
self.execution_queue: List[Tuple[str, TriggerContext]] = []
def register_trigger(self, trigger: Union[ScheduleTrigger, FileTrigger, VisualTrigger]) -> None:
"""Enregistre un déclencheur."""
def fire_trigger(self, trigger_id: str) -> TriggerContext:
"""Déclenche manuellement un trigger et retourne le contexte."""
def handle_concurrent_triggers(self, workflow_id: str, contexts: List[TriggerContext]) -> None:
"""Gère les déclenchements concurrents."""
def to_dict(self) -> Dict[str, Any]:
"""Sérialise la configuration des triggers."""
@classmethod
def from_dict(cls, data: Dict[str, Any], ...) -> 'TriggerManager':
"""Désérialise la configuration des triggers."""
```
### 8. DependencyGraph
Gère le graphe de dépendances entre workflows.
```python
class DependencyGraph:
def __init__(self):
self.dependencies: Dict[str, Set[str]] = {} # workflow -> sous-workflows utilisés
self.dependents: Dict[str, Set[str]] = {} # sous-workflow -> workflows qui l'utilisent
def add_dependency(self, workflow_id: str, sub_workflow_id: str) -> None:
"""Ajoute une dépendance."""
def remove_dependency(self, workflow_id: str, sub_workflow_id: str) -> None:
"""Supprime une dépendance."""
def get_dependencies(self, workflow_id: str) -> Set[str]:
"""Retourne les dépendances d'un workflow."""
def get_dependents(self, workflow_id: str) -> Set[str]:
"""Retourne les workflows qui dépendent de celui-ci."""
def has_circular_dependency(self, workflow_id: str, sub_workflow_id: str) -> bool:
"""Vérifie si l'ajout créerait une dépendance circulaire."""
def get_usage_stats(self, workflow_id: str) -> Dict[str, int]:
"""Retourne les statistiques d'utilisation."""
```
### 9. VariableManager (Extension)
Extension du VariableManager existant pour les variables globales.
```python
class GlobalVariableManager:
def __init__(self):
self.global_vars: Dict[str, Any] = {}
self.override_log: List[VariableOverride] = []
def set_global(self, name: str, value: Any, source_workflow: str) -> None:
"""Définit une variable globale."""
def get_global(self, name: str, default: Any = None) -> Any:
"""Récupère une variable globale."""
def transfer_to_workflow(self, target_workflow_id: str) -> Dict[str, Any]:
"""Transfère les variables au workflow suivant."""
def get_final_state(self) -> Dict[str, Any]:
"""Retourne l'état final des variables."""
def to_dict(self) -> Dict[str, Any]:
"""Sérialise le contexte d'exécution."""
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'GlobalVariableManager':
"""Désérialise le contexte d'exécution."""
```
## Data Models
```python
@dataclass
class WorkflowCompositionConfig:
"""Configuration complète de composition."""
chains: List[ChainConfig]
sub_workflows: Dict[str, SubWorkflowDefinition]
references: Dict[str, List[ReferenceNode]]
loops: Dict[str, LoopConfig]
conditionals: Dict[str, ConditionalNode]
triggers: List[Union[ScheduleTrigger, FileTrigger, VisualTrigger]]
@dataclass
class ExecutionContext:
"""Contexte d'exécution partagé."""
chain_id: str
current_workflow_id: str
global_variables: Dict[str, Any]
execution_log: List[LogEntry]
trigger_context: Optional[TriggerContext]
@dataclass
class LogEntry:
"""Entrée du log d'exécution unifié."""
timestamp: datetime
workflow_id: str
node_id: str
event_type: str
details: Dict[str, Any]
@dataclass
class ValidationResult:
"""Résultat de validation."""
is_valid: bool
errors: List[str]
warnings: List[str]
```
## Correctness Properties
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
### Property Reflection
Après analyse des critères d'acceptation, voici les propriétés consolidées en éliminant les redondances :
- Les propriétés de round-trip (1.6, 2.6, 6.6, 7.6, 8.6, 9.4) peuvent être combinées en une seule propriété générique de sérialisation
- Les propriétés de propagation de variables (1.2, 9.1, 9.5) peuvent être combinées
- Les propriétés de validation de dépendances (5.2, 5.3) peuvent être combinées
### Properties
**Property 1: Round-trip de sérialisation**
*Pour tout* objet de configuration (ChainConfig, LoopConfig, ConditionalNode, Trigger, ExecutionContext), la sérialisation suivie de la désérialisation doit produire un objet équivalent.
**Validates: Requirements 1.6, 2.6, 6.6, 7.6, 8.6, 9.4**
**Property 2: Propagation des variables dans les chaînes**
*Pour tout* workflow A avec des variables de contexte chaîné vers un workflow B, toutes les variables mappées doivent être accessibles dans B avec leurs valeurs correctes, et en cas de conflit de noms, la valeur la plus récente prévaut.
**Validates: Requirements 1.2, 9.1, 9.5**
**Property 3: Validation de compatibilité de chaînage**
*Pour toute* paire de workflows (A, B) avec une configuration de chaînage, la validation doit détecter les incompatibilités entre l'état final de A et l'état initial de B.
**Validates: Requirements 1.4**
**Property 4: Log unifié complet**
*Pour toute* chaîne de workflows exécutée, le log unifié doit contenir exactement tous les événements de tous les workflows dans l'ordre chronologique.
**Validates: Requirements 1.5**
**Property 5: Retour de contrôle après sous-workflow**
*Pour tout* workflow parent appelant un sous-workflow via une référence, après complétion du sous-workflow, l'exécution doit reprendre au node suivant la référence dans le parent.
**Validates: Requirements 2.1, 2.2**
**Property 6: Propagation d'erreur de sous-workflow**
*Pour toute* erreur survenant dans un sous-workflow, l'erreur doit être propagée au workflow parent avec le contexte complet (stack trace, état des variables, node en échec).
**Validates: Requirements 2.5**
**Property 7: Détection de similarité pour fusion**
*Pour toute* paire de workflows avec un score de similarité supérieur à 0.9, le système doit générer une suggestion de fusion.
**Validates: Requirements 3.1**
**Property 8: Préservation des chemins lors de la fusion**
*Pour tout* merge de workflows A et B, le workflow résultant doit contenir tous les chemins uniques de A et tous les chemins uniques de B.
**Validates: Requirements 3.2**
**Property 9: Combinaison des statistiques lors de la fusion**
*Pour tout* merge de workflows A et B, les statistiques du résultat doivent être la combinaison (somme ou union selon le type) des statistiques de A et B.
**Validates: Requirements 3.3**
**Property 10: Détection de séquences communes**
*Pour toute* séquence de nodes identique apparaissant dans N workflows (N >= 2), le système doit la détecter et suggérer son extraction.
**Validates: Requirements 4.1**
**Property 11: Remplacement par références après extraction**
*Pour toute* extraction de séquence en sous-workflow, toutes les occurrences originales doivent être remplacées par des nodes de référence pointant vers le nouveau sous-workflow.
**Validates: Requirements 4.2**
**Property 12: Priorisation des séquences fréquentes**
*Pour toute* séquence apparaissant dans 3 workflows ou plus, elle doit être marquée comme candidat haute priorité.
**Validates: Requirements 4.3**
**Property 13: Validation des dépendances**
*Pour toute* tentative de suppression d'un sous-workflow avec des dépendants, un avertissement doit être généré listant tous les workflows affectés. *Pour toute* configuration créant une dépendance circulaire, elle doit être rejetée avec une erreur.
**Validates: Requirements 5.2, 5.3**
**Property 14: Incrémentation du compteur de boucle**
*Pour toute* boucle, après chaque itération complète, le compteur doit être incrémenté exactement de 1.
**Validates: Requirements 6.2**
**Property 15: Terminaison de boucle à la limite**
*Pour toute* boucle avec une limite de N itérations, elle doit terminer après exactement N itérations (ou moins si la condition de sortie est atteinte).
**Validates: Requirements 6.3**
**Property 16: Garde de sécurité des boucles**
*Pour toute* boucle, le nombre d'itérations ne doit jamais dépasser 1000, et un warning doit être loggé si cette limite est atteinte.
**Validates: Requirements 6.5**
**Property 17: Ordre d'évaluation des branches conditionnelles**
*Pour tout* node conditionnel avec plusieurs branches dont les conditions sont vraies, seule la première branche (par ordre de priorité) doit être exécutée.
**Validates: Requirements 7.2**
**Property 18: Branche par défaut ou erreur**
*Pour tout* node conditionnel où aucune condition n'est satisfaite, la branche par défaut doit être exécutée si elle existe, sinon une erreur doit être levée.
**Validates: Requirements 7.3**
**Property 19: Passage du contexte de déclenchement**
*Pour tout* déclenchement de trigger, le contexte (timestamp, chemin fichier ou élément détecté) doit être passé au workflow.
**Validates: Requirements 8.4**
**Property 20: Gestion des déclenchements concurrents**
*Pour tout* workflow avec plusieurs triggers configurés, les exécutions concurrentes doivent être gérées selon la configuration (concurrent ou queue).
**Validates: Requirements 8.5**
**Property 21: Lecture de variable avec défaut**
*Pour toute* lecture d'une variable globale non définie, la valeur par défaut spécifiée doit être retournée.
**Validates: Requirements 9.2**
**Property 22: Préservation de l'état final des variables**
*Pour toute* chaîne de workflows complétée, le log d'exécution doit contenir l'état final de toutes les variables globales.
**Validates: Requirements 9.3**
## Error Handling
### Erreurs de chaînage
- **ChainValidationError** : Incompatibilité entre workflows
- **ChainExecutionError** : Échec pendant l'exécution d'une chaîne
- **VariableTransferError** : Échec du transfert de variables
### Erreurs de sous-workflows
- **SubWorkflowNotFoundError** : Référence vers un sous-workflow inexistant
- **CircularDependencyError** : Dépendance circulaire détectée
- **SubWorkflowExecutionError** : Échec dans un sous-workflow
### Erreurs de boucles
- **LoopSafetyLimitError** : Limite de sécurité atteinte (1000 itérations)
- **LoopConditionError** : Erreur lors de l'évaluation de la condition
### Erreurs de conditions
- **NoMatchingBranchError** : Aucune branche ne correspond et pas de défaut
- **ConditionEvaluationError** : Erreur lors de l'évaluation d'une condition
### Erreurs de triggers
- **TriggerConfigurationError** : Configuration de trigger invalide
- **ConcurrentExecutionError** : Erreur de gestion des exécutions concurrentes
## Testing Strategy
### Bibliothèque de Property-Based Testing
Le projet utilise **Hypothesis** pour Python, déjà configuré dans le projet.
### Tests unitaires
- Tests des composants individuels (ChainConfig, LoopConfig, etc.)
- Tests des validations (compatibilité, dépendances circulaires)
- Tests des cas limites (boucle vide, chaîne d'un seul workflow)
### Tests property-based
Chaque propriété de correction sera implémentée comme un test property-based avec :
- Minimum 100 itérations par test
- Annotation explicite référençant la propriété du design
- Format : `**Feature: workflow-composition, Property {number}: {property_text}**`
### Stratégie de génération
- Générateurs de workflows aléatoires avec nodes, transitions, et configurations
- Générateurs de configurations de chaînage valides et invalides
- Générateurs de conditions visuelles simulées
- Générateurs de contextes d'exécution avec variables
### Tests d'intégration
- Exécution de chaînes complètes avec plusieurs workflows
- Exécution de boucles avec conditions visuelles simulées
- Déclenchement de triggers et vérification du contexte

View File

@@ -0,0 +1,133 @@
# Requirements Document
## Introduction
Ce document définit les exigences pour la composition et le contrôle de flux des workflows dans RPA Vision V3. Il couvre le chaînage, les sous-workflows, la fusion, ainsi que les structures de contrôle fondamentales (boucles, conditions, déclencheurs) essentielles à tout système RPA.
## Glossaire
- **Workflow** : Graphe de transitions entre états d'écran représentant un processus automatisé
- **Chaînage** : Exécution séquentielle de plusieurs workflows où la fin de l'un déclenche le début du suivant
- **Sous-workflow** : Workflow réutilisable pouvant être appelé depuis d'autres workflows
- **Fusion** : Combinaison de deux workflows partageant des nodes similaires en un seul workflow optimisé
- **Node de référence** : Node spécial qui appelle un sous-workflow
- **Boucle** : Répétition d'une séquence de nodes N fois ou jusqu'à une condition
- **Branchement conditionnel** : Choix du chemin d'exécution basé sur l'état de l'écran
- **Déclencheur** : Événement qui lance automatiquement un workflow (horaire, fichier, écran)
- **Variable globale** : Donnée partagée entre workflows d'une même exécution
- **Condition visuelle** : Évaluation basée sur la détection d'un élément à l'écran
- **Compteur de boucle** : Variable incrémentée à chaque itération d'une boucle
- **Garde de sécurité** : Limite maximale d'itérations pour éviter les boucles infinies
## Requirements
### Requirement 1
**User Story:** En tant qu'utilisateur, je veux chaîner plusieurs workflows ensemble, afin de construire des processus complexes à partir de blocs simples.
#### Acceptance Criteria
1. WHEN a workflow reaches an end node with a chain configuration THEN the system SHALL automatically start the specified next workflow
2. WHEN chaining workflows THEN the system SHALL pass context variables from the ending workflow to the starting workflow
3. WHEN a chained workflow fails THEN the system SHALL provide options to retry, skip, or abort the entire chain
4. WHEN defining a chain THEN the system SHALL validate that the end state of workflow A is compatible with the entry state of workflow B
5. WHEN executing a chain THEN the system SHALL maintain a unified execution log across all chained workflows
6. WHEN serializing a workflow chain THEN the system SHALL preserve chain configuration and deserialize it correctly
### Requirement 2
**User Story:** En tant qu'utilisateur, je veux créer des sous-workflows réutilisables, afin d'éviter de dupliquer des séquences communes comme la connexion ou la navigation.
#### Acceptance Criteria
1. WHEN a workflow contains a reference node THEN the system SHALL execute the referenced sub-workflow at that point
2. WHEN a sub-workflow completes THEN the system SHALL return control to the calling workflow at the next node
3. WHEN a sub-workflow is modified THEN the system SHALL automatically update all workflows that reference it
4. WHEN creating a sub-workflow THEN the system SHALL allow defining input parameters and output values
5. WHEN a sub-workflow fails THEN the system SHALL propagate the error to the parent workflow with full context
6. WHEN serializing a workflow with sub-workflow references THEN the system SHALL preserve reference configurations and deserialize them correctly
### Requirement 3
**User Story:** En tant qu'utilisateur, je veux que le système détecte et fusionne les workflows similaires, afin de réduire la redondance et améliorer la maintenabilité.
#### Acceptance Criteria
1. WHEN two workflows share nodes with similarity above 0.9 THEN the system SHALL suggest merging them
2. WHEN merging workflows THEN the system SHALL preserve all unique paths from both workflows
3. WHEN merging workflows THEN the system SHALL combine statistics and learning data from both sources
4. WHEN a merge is proposed THEN the system SHALL show a visual diff of the changes before applying
5. WHEN merged workflows have conflicting actions on the same node THEN the system SHALL prompt the user to resolve the conflict
### Requirement 4
**User Story:** En tant qu'utilisateur, je veux extraire automatiquement les séquences communes en sous-workflows, afin de garder mes workflows DRY (Don't Repeat Yourself).
#### Acceptance Criteria
1. WHEN the system detects identical sequences in multiple workflows THEN the system SHALL suggest extracting them as a sub-workflow
2. WHEN extracting a sub-workflow THEN the system SHALL replace the original sequences with reference nodes
3. WHEN a sequence appears in 3 or more workflows THEN the system SHALL flag it as a high-priority extraction candidate
4. WHEN extracting THEN the system SHALL preserve the original workflows as backups until the user confirms
### Requirement 5
**User Story:** En tant qu'utilisateur, je veux gérer les dépendances entre workflows, afin de comprendre et maintenir les relations entre mes workflows.
#### Acceptance Criteria
1. WHEN viewing a workflow THEN the system SHALL display its dependencies (sub-workflows it calls) and dependents (workflows that call it)
2. WHEN deleting a sub-workflow THEN the system SHALL warn about all workflows that depend on it
3. WHEN a circular dependency is detected THEN the system SHALL prevent the configuration and display an error
4. WHEN listing workflows THEN the system SHALL show dependency count and usage statistics
### Requirement 6
**User Story:** En tant qu'utilisateur, je veux créer des boucles dans mes workflows, afin de répéter des actions jusqu'à atteindre un objectif.
#### Acceptance Criteria
1. WHEN defining a loop node THEN the system SHALL allow specifying a fixed iteration count or a visual condition for termination
2. WHEN a loop iteration completes THEN the system SHALL increment the loop counter and evaluate the exit condition
3. WHEN a loop reaches its maximum iteration limit THEN the system SHALL exit the loop and continue to the next node
4. WHEN a loop condition is based on visual detection THEN the system SHALL capture and analyze the screen at each iteration
5. WHEN a loop exceeds the safety guard limit of 1000 iterations THEN the system SHALL terminate the loop and log a warning
6. WHEN serializing a workflow with loops THEN the system SHALL preserve loop configuration and deserialize it correctly
### Requirement 7
**User Story:** En tant qu'utilisateur, je veux créer des branchements conditionnels, afin d'adapter le comportement du workflow selon l'état de l'écran.
#### Acceptance Criteria
1. WHEN defining a conditional node THEN the system SHALL allow specifying multiple branches with visual conditions
2. WHEN evaluating a conditional node THEN the system SHALL test each branch condition in order and execute the first matching branch
3. WHEN no branch condition matches THEN the system SHALL execute the default branch or raise an error if none is defined
4. WHEN a condition is based on element presence THEN the system SHALL use the visual matching engine to detect the element
5. WHEN a condition is based on element text THEN the system SHALL use OCR to extract and compare the text value
6. WHEN serializing a workflow with conditions THEN the system SHALL preserve all branch configurations and deserialize them correctly
### Requirement 8
**User Story:** En tant qu'utilisateur, je veux configurer des déclencheurs automatiques, afin que mes workflows s'exécutent sans intervention manuelle.
#### Acceptance Criteria
1. WHEN defining a schedule trigger THEN the system SHALL allow specifying cron expressions or time intervals
2. WHEN defining a file trigger THEN the system SHALL monitor a directory and start the workflow when a matching file appears
3. WHEN defining a visual trigger THEN the system SHALL periodically capture the screen and start the workflow when a target element is detected
4. WHEN a trigger fires THEN the system SHALL pass trigger context (timestamp, file path, or detected element) to the workflow
5. WHEN multiple triggers are configured for the same workflow THEN the system SHALL handle concurrent executions or queue them based on configuration
6. WHEN serializing trigger configurations THEN the system SHALL preserve all settings and deserialize them correctly
### Requirement 9
**User Story:** En tant qu'utilisateur, je veux gérer des variables globales entre workflows, afin de partager des données dans une chaîne d'exécution.
#### Acceptance Criteria
1. WHEN a workflow sets a global variable THEN the system SHALL make it available to all subsequent workflows in the chain
2. WHEN a workflow reads a global variable THEN the system SHALL return the current value or a default if not set
3. WHEN a workflow chain completes THEN the system SHALL preserve the final variable state in the execution log
4. WHEN serializing execution context THEN the system SHALL include all global variables and deserialize them correctly
5. WHEN a variable name conflict occurs between workflows THEN the system SHALL use the most recent value and log the override

View File

@@ -0,0 +1,211 @@
# Implementation Plan - Workflow Composition
- [x] 1. Créer les modèles de données de base
- [x] 1.1 Créer les dataclasses de configuration (ChainConfig, LoopConfig, ConditionalNode, etc.)
- Fichier: `core/workflow/composition_models.py`
- Inclure les méthodes `to_dict()` et `from_dict()` pour chaque classe
- _Requirements: 1.6, 6.6, 7.6, 8.6_
- [x]* 1.2 Écrire le test property-based pour la sérialisation round-trip
- **Property 1: Round-trip de sérialisation**
- **Validates: Requirements 1.6, 2.6, 6.6, 7.6, 8.6, 9.4**
- [x] 2. Implémenter le DependencyGraph
- [x] 2.1 Créer la classe DependencyGraph
- Fichier: `core/workflow/dependency_graph.py`
- Méthodes: `add_dependency`, `remove_dependency`, `get_dependencies`, `get_dependents`
- _Requirements: 5.1, 5.4_
- [x] 2.2 Implémenter la détection de dépendances circulaires
- Méthode: `has_circular_dependency` avec algorithme DFS
- _Requirements: 5.3_
- [x]* 2.3 Écrire le test property-based pour la validation des dépendances
- **Property 13: Validation des dépendances**
- **Validates: Requirements 5.2, 5.3**
- [x] 3. Implémenter le GlobalVariableManager
- [x] 3.1 Créer la classe GlobalVariableManager
- Fichier: `core/workflow/global_variable_manager.py`
- Méthodes: `set_global`, `get_global`, `transfer_to_workflow`, `get_final_state`
- _Requirements: 9.1, 9.2, 9.3_
- [x] 3.2 Implémenter la gestion des conflits de variables
- Logger les overrides, garder la valeur la plus récente
- _Requirements: 9.5_
- [x]* 3.3 Écrire les tests property-based pour les variables
- **Property 2: Propagation des variables dans les chaînes**
- **Validates: Requirements 1.2, 9.1, 9.5**
- [x]* 3.4 Écrire le test property-based pour la lecture avec défaut
- **Property 21: Lecture de variable avec défaut**
- **Validates: Requirements 9.2**
- [x] 4. Checkpoint - Vérifier que tous les tests passent
- Ensure all tests pass, ask the user if questions arise.
- [x] 5. Implémenter le LoopExecutor
- [x] 5.1 Créer la classe LoopExecutor
- Fichier: `core/workflow/loop_executor.py`
- Méthodes: `start_loop`, `execute_iteration`, `should_continue`, `increment_counter`
- _Requirements: 6.1, 6.2, 6.3, 6.4_
- [x] 5.2 Implémenter la garde de sécurité (1000 itérations max)
- Lever LoopSafetyLimitError et logger un warning
- _Requirements: 6.5_
- [x]* 5.3 Écrire le test property-based pour l'incrémentation du compteur
- **Property 14: Incrémentation du compteur de boucle**
- **Validates: Requirements 6.2**
- [x]* 5.4 Écrire le test property-based pour la terminaison à la limite
- **Property 15: Terminaison de boucle à la limite**
- **Validates: Requirements 6.3**
- [x]* 5.5 Écrire le test property-based pour la garde de sécurité
- **Property 16: Garde de sécurité des boucles**
- **Validates: Requirements 6.5**
- [x] 6. Implémenter le ConditionalEvaluator
- [x] 6.1 Créer la classe ConditionalEvaluator
- Fichier: `core/workflow/conditional_evaluator.py`
- Méthodes: `evaluate_condition`, `evaluate_node`
- Intégration avec TargetResolver existant
- _Requirements: 7.1, 7.4, 7.5_
- [x] 6.2 Implémenter l'évaluation ordonnée des branches
- Tester les branches par ordre de priorité, retourner la première qui match
- _Requirements: 7.2_
- [x] 6.3 Implémenter la gestion de la branche par défaut
- Exécuter le défaut ou lever NoMatchingBranchError
- _Requirements: 7.3_
- [x]* 6.4 Écrire le test property-based pour l'ordre d'évaluation
- **Property 17: Ordre d'évaluation des branches conditionnelles**
- **Validates: Requirements 7.2**
- [x]* 6.5 Écrire le test property-based pour la branche par défaut
- **Property 18: Branche par défaut ou erreur**
- **Validates: Requirements 7.3**
- [x] 7. Checkpoint - Vérifier que tous les tests passent
- Ensure all tests pass, ask the user if questions arise.
- [x] 8. Implémenter le SubWorkflowRegistry
- [x] 8.1 Créer la classe SubWorkflowRegistry
- Fichier: `core/workflow/subworkflow_registry.py`
- Méthodes: `register`, `create_reference`, `execute_reference`, `get_dependents`
- Intégration avec DependencyGraph
- _Requirements: 2.1, 2.4_
- [x] 8.2 Implémenter le retour de contrôle après exécution
- Sauvegarder le contexte parent, exécuter le sous-workflow, restaurer
- _Requirements: 2.2_
- [x] 8.3 Implémenter la propagation d'erreur
- Capturer les erreurs du sous-workflow avec contexte complet
- _Requirements: 2.5_
- [x]* 8.4 Écrire le test property-based pour le retour de contrôle
- **Property 5: Retour de contrôle après sous-workflow**
- **Validates: Requirements 2.1, 2.2**
- [x]* 8.5 Écrire le test property-based pour la propagation d'erreur
- **Property 6: Propagation d'erreur de sous-workflow**
- **Validates: Requirements 2.5**
- [x] 9. Implémenter le WorkflowChainer
- [x] 9.1 Créer la classe WorkflowChainer
- Fichier: `core/workflow/workflow_chainer.py`
- Méthodes: `add_chain`, `validate_chain`, `execute_chain`
- Intégration avec GlobalVariableManager
- _Requirements: 1.1, 1.2, 1.3_
- [x] 9.2 Implémenter la validation de compatibilité
- Vérifier que l'état final de A est compatible avec l'état initial de B
- _Requirements: 1.4_
- [x] 9.3 Implémenter le log unifié
- Maintenir un ExecutionLogger partagé entre tous les workflows de la chaîne
- _Requirements: 1.5_
- [x]* 9.4 Écrire le test property-based pour la validation de compatibilité
- **Property 3: Validation de compatibilité de chaînage**
- **Validates: Requirements 1.4**
- [x]* 9.5 Écrire le test property-based pour le log unifié
- **Property 4: Log unifié complet**
- **Validates: Requirements 1.5**
- [x] 10. Checkpoint - Vérifier que tous les tests passent
- Ensure all tests pass, ask the user if questions arise.
- [x] 11. Implémenter le WorkflowMerger
- [x] 11.1 Créer la classe WorkflowMerger
- Fichier: `core/workflow/workflow_merger.py`
- Méthodes: `calculate_similarity`, `find_merge_candidates`, `merge`, `get_unique_paths`
- _Requirements: 3.1, 3.4, 3.5_
- [x] 11.2 Implémenter la préservation des chemins uniques
- Extraire tous les chemins de A et B, les combiner dans le résultat
- _Requirements: 3.2_
- [x] 11.3 Implémenter la combinaison des statistiques
- Fusionner les stats d'apprentissage des deux sources
- _Requirements: 3.3_
- [x]* 11.4 Écrire le test property-based pour la détection de similarité
- **Property 7: Détection de similarité pour fusion**
- **Validates: Requirements 3.1**
- [x]* 11.5 Écrire le test property-based pour la préservation des chemins
- **Property 8: Préservation des chemins lors de la fusion**
- **Validates: Requirements 3.2**
- [x]* 11.6 Écrire le test property-based pour la combinaison des stats
- **Property 9: Combinaison des statistiques lors de la fusion**
- **Validates: Requirements 3.3**
- [x] 12. Implémenter le SequenceExtractor
- [x] 12.1 Créer la classe SequenceExtractor
- Fichier: `core/workflow/sequence_extractor.py`
- Méthodes: `find_common_sequences`, `extract_as_subworkflow`, `replace_with_references`
- Intégration avec SubWorkflowRegistry
- _Requirements: 4.1, 4.4_
- [x] 12.2 Implémenter le remplacement par références
- Remplacer les séquences originales par des ReferenceNodes
- _Requirements: 4.2_
- [x] 12.3 Implémenter la priorisation
- Marquer haute priorité les séquences dans 3+ workflows
- _Requirements: 4.3_
- [x]* 12.4 Écrire le test property-based pour la détection de séquences
- **Property 10: Détection de séquences communes**
- **Validates: Requirements 4.1**
- [x]* 12.5 Écrire le test property-based pour le remplacement
- **Property 11: Remplacement par références après extraction**
- **Validates: Requirements 4.2**
- [x]* 12.6 Écrire le test property-based pour la priorisation
- **Property 12: Priorisation des séquences fréquentes**
- **Validates: Requirements 4.3**
- [x] 13. Checkpoint - Vérifier que tous les tests passent
- Ensure all tests pass, ask the user if questions arise.
- [x] 14. Implémenter le TriggerManager
- [x] 14.1 Créer la classe TriggerManager
- Fichier: `core/workflow/trigger_manager.py`
- Méthodes: `register_trigger`, `fire_trigger`, `handle_concurrent_triggers`
- Support pour ScheduleTrigger, FileTrigger, VisualTrigger
- _Requirements: 8.1, 8.2, 8.3_
- [x] 14.2 Implémenter le passage du contexte de déclenchement
- Créer TriggerContext avec timestamp, file_path, detected_element
- _Requirements: 8.4_
- [x] 14.3 Implémenter la gestion des déclenchements concurrents
- Mode concurrent ou queue selon configuration
- _Requirements: 8.5_
- [x]* 14.4 Écrire le test property-based pour le contexte de déclenchement
- **Property 19: Passage du contexte de déclenchement**
- **Validates: Requirements 8.4**
- [x]* 14.5 Écrire le test property-based pour la concurrence
- **Property 20: Gestion des déclenchements concurrents**
- **Validates: Requirements 8.5**
- [x] 15. Implémenter le ExecutionLogger unifié
- [x] 15.1 Créer/étendre la classe ExecutionLogger
- Fichier: `core/workflow/execution_logger.py`
- Support pour les logs multi-workflows avec contexte de chaîne
- Méthode `get_final_variable_state`
- _Requirements: 1.5, 9.3_
- [x]* 15.2 Écrire le test property-based pour la préservation de l'état final
- **Property 22: Préservation de l'état final des variables**
- **Validates: Requirements 9.3**
- [x] 16. Intégration avec le système existant
- [x] 16.1 Intégrer les nouveaux composants dans WorkflowGraph
- Ajouter les champs pour loops, conditionals, references
- Mettre à jour `to_dict()` et `from_dict()`
- _Requirements: 1.6, 2.6, 6.6, 7.6_
- [x] 16.2 Intégrer avec ExecutionLoop
- Ajouter le support pour LoopExecutor et ConditionalEvaluator
- _Requirements: 6.2, 7.2_
- [x] 16.3 Mettre à jour la CLI pour les nouvelles fonctionnalités
- Commandes pour chaîner, créer des sous-workflows, configurer des triggers
- _Requirements: 1.1, 2.1, 8.1_
- [x] 17. Checkpoint final - Vérifier que tous les tests passent
- Ensure all tests pass, ask the user if questions arise.