From 6fdedbfe9dbca63ff5f0190602efdb5537d3e390 Mon Sep 17 00:00:00 2001 From: Dom Date: Wed, 6 May 2026 20:23:44 +0200 Subject: [PATCH] =?UTF-8?q?fix(vwb):=20execute-windows=20route=20vers=20la?= =?UTF-8?q?=20machine=20la=20plus=20active=20(pas=20alphab=C3=A9tique)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quand le frontend ne passe pas de machine_id explicite, le backend VWB auto-sélectionne une machine Windows en interrogeant /api/v1/traces/ stream/machines. Le code prenait la première de la liste sans tri, donc l'ordre dépendait de l'ordre arbitraire renvoyé par le streaming server. Conséquence reproduite ce 2026-05-06 : un replay du workflow Urgence a été dispatché vers DESKTOP-ST3VBSD_windows alors que l'agent V1 actif polait depuis DESKTOP-58D5CAC_windows. /replay/next ne dispatchait aucune action puisque state.machine_id != polling_machine_id. Symptôme côté Dom : "rien ne se passe sur Windows". Correction : tri explicite par last_activity desc avant sélection. La machine retenue est désormais celle qui a heartbeaté le plus récemment (= celle qui POLLE actuellement le serveur). Le workflow.machine_id (machine d'origine d'enregistrement) reste distinct de la cible d'exécution : un workflow enregistré sur PC A peut être rejoué sur PC B grâce au pipeline 100% visuel qui recalcule anchors et coordonnées selon la résolution courante. C'était la vraie intention architecturale, masquée par le bug de tri. --- .../backend/api_v3/dag_execute.py | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) 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