diff --git a/visual_workflow_builder/backend/api_v3/dag_execute.py b/visual_workflow_builder/backend/api_v3/dag_execute.py index 4835ee5d0..cafb291ee 100644 --- a/visual_workflow_builder/backend/api_v3/dag_execute.py +++ b/visual_workflow_builder/backend/api_v3/dag_execute.py @@ -1082,8 +1082,13 @@ def execute_windows(): if not data.get('session_id'): data['session_id'] = 'agent_demo_user' - # Injecter le machine_id pour le ciblage multi-machine - # Chercher la première machine Windows connectée si pas spécifié + # Injecter le machine_id pour le ciblage multi-machine. + # Cibler la machine Windows la plus récemment active (heartbeat last_activity) + # plutôt que la première dans l'ordre arbitraire renvoyé par /machines : + # un workflow enregistré sur PC A doit pouvoir être rejoué sur PC B (vision + # 100 % visuelle, recalcul anchors+coords selon la résolution courante). + # Le workflow.machine_id signale l'origine d'enregistrement, pas la cible + # d'exécution — la cible doit être l'agent qui POLLE actuellement. if 'machine_id' not in data or not data.get('machine_id'): try: machines_resp = req.get( @@ -1093,11 +1098,19 @@ def execute_windows(): ) if machines_resp.ok: machines = machines_resp.json().get('machines', []) - for m in machines: - mid = m.get('machine_id', '') - if mid and mid != 'default' and 'windows' in mid.lower(): - data['machine_id'] = mid - break + # Filtrer Windows + non default, trier par last_activity desc + windows_machines = [ + m for m in machines + if m.get('machine_id') + and m['machine_id'] != 'default' + and 'windows' in m['machine_id'].lower() + ] + windows_machines.sort( + key=lambda m: m.get('last_activity', ''), + reverse=True, + ) + if windows_machines: + data['machine_id'] = windows_machines[0]['machine_id'] except Exception: pass