fix(vwb): execute-windows route vers la machine la plus active (pas alphabétique)
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.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user