fix: filtre UIA-aware + polling pré-vérif tolérant
Filtre d'événements parasites basé sur la CIBLE UIA : - Un clic n'est filtré que si son uia_snapshot indique que l'élément cliqué (ou un parent) est dans la fenêtre de Léa. - Avant : on filtrait sur window.title qui pouvait être "Lea" même quand le clic visait la taskbar (Léa au premier plan). - Après : on regarde où va VRAIMENT le clic via parent_path UIA. Extraction du expected_window depuis le parent_path UIA : - Priorité au nom de la fenêtre racine du parent_path (plus fiable). - Fallback sur window.title si pas de snapshot UIA ou pas de racine. - Les fenêtres Léa sont neutralisées (effective_title=""). Pré-vérif avec polling tolérant (executor.py) : - 5 tentatives avec 300ms entre chaque (total 1.5s max). - Ignore les transitions "unknown_window" et fenêtre Léa. - Évite les faux négatifs sur fenêtres en cours de changement. Note : le filtrage reste basé sur des heuristiques. Un tri intelligent par gemma4 au build reste à implémenter pour gérer les workflows enregistrés avec des actions parasites (mail, chat, etc.). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -526,38 +526,66 @@ class ActionExecutorV1:
|
||||
)
|
||||
if expected_title and expected_title != "unknown_window":
|
||||
from ..window_info_crossplatform import get_active_window_info
|
||||
current_info = get_active_window_info()
|
||||
current_title = current_info.get("title", "")
|
||||
|
||||
current_app = _app_name(current_title)
|
||||
expected_app = _app_name(expected_title)
|
||||
title_match = (
|
||||
current_app == expected_app
|
||||
or expected_title.lower() in current_title.lower()
|
||||
or current_title.lower() in expected_title.lower()
|
||||
)
|
||||
# Ignorer la fenêtre de Léa elle-même (overlay agent)
|
||||
# On utilise `messages.est_fenetre_lea` centralisé pour la
|
||||
# cohérence avec les autres modules (tests, activity panel).
|
||||
from ..ui.messages import est_fenetre_lea
|
||||
is_lea_window = est_fenetre_lea(current_title)
|
||||
|
||||
if not title_match and not is_lea_window:
|
||||
logger.warning(
|
||||
f"[LEA] Fenêtre incorrecte : attendu '{expected_title}', "
|
||||
f"actuel '{current_title}'"
|
||||
# Polling court pour laisser le temps à la fenêtre de
|
||||
# se stabiliser (évite les faux négatifs sur transitions
|
||||
# rapides : menu qui se ferme, taskbar qui perd le focus, etc.)
|
||||
current_title = ""
|
||||
title_match = False
|
||||
is_lea_window = False
|
||||
for attempt in range(5):
|
||||
current_info = get_active_window_info()
|
||||
current_title = current_info.get("title", "")
|
||||
|
||||
# Si on tombe sur Léa elle-même → on attend un peu
|
||||
if est_fenetre_lea(current_title):
|
||||
is_lea_window = True
|
||||
time.sleep(0.3)
|
||||
continue
|
||||
|
||||
# Si on tombe sur unknown_window → on attend aussi
|
||||
if not current_title or current_title == "unknown_window":
|
||||
time.sleep(0.3)
|
||||
continue
|
||||
|
||||
current_app = _app_name(current_title)
|
||||
expected_app = _app_name(expected_title)
|
||||
title_match = (
|
||||
current_app == expected_app
|
||||
or expected_title.lower() in current_title.lower()
|
||||
or current_title.lower() in expected_title.lower()
|
||||
)
|
||||
print(f" [PRÉ-VÉRIF] STOP — fenêtre '{current_title}' ≠ attendu '{expected_title}'")
|
||||
# Notification utilisateur en français naturel
|
||||
try:
|
||||
self.notifier.replay_wrong_window(current_title, expected_title)
|
||||
except Exception:
|
||||
pass
|
||||
result["success"] = False
|
||||
result["error"] = f"Fenêtre incorrecte: '{current_title}' (attendu: '{expected_title}')"
|
||||
return result
|
||||
elif is_lea_window:
|
||||
logger.info("[LEA] Fenêtre de Léa détectée — ignorée, on continue")
|
||||
if title_match:
|
||||
break
|
||||
# Sinon on retente un peu au cas où la fenêtre
|
||||
# est en cours de transition
|
||||
time.sleep(0.3)
|
||||
|
||||
if not title_match:
|
||||
if is_lea_window:
|
||||
# Si après 5 essais on est encore sur Léa,
|
||||
# on ignore (l'utilisateur a Léa au premier plan)
|
||||
logger.info("[LEA] Fenêtre de Léa persistante — ignorée, on continue")
|
||||
elif not current_title or current_title == "unknown_window":
|
||||
# unknown_window persistant : on continue avec un
|
||||
# warning, UIA décidera peut-être
|
||||
logger.warning(
|
||||
f"[LEA] Fenêtre active inconnue — on tente quand même"
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
f"[LEA] Fenêtre incorrecte : attendu '{expected_title}', "
|
||||
f"actuel '{current_title}'"
|
||||
)
|
||||
print(f" [PRÉ-VÉRIF] STOP — fenêtre '{current_title}' ≠ attendu '{expected_title}'")
|
||||
try:
|
||||
self.notifier.replay_wrong_window(current_title, expected_title)
|
||||
except Exception:
|
||||
pass
|
||||
result["success"] = False
|
||||
result["error"] = f"Fenêtre incorrecte: '{current_title}' (attendu: '{expected_title}')"
|
||||
return result
|
||||
else:
|
||||
logger.info(f"[LEA] Pré-vérif OK : '{current_title}'")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user