Avant ce fix, le _heartbeat_loop côté Agent V1 deploy Windows
n'enrichissait pas son payload, donc QW1 multi-écran ne s'activait sur Windows
que via les events window_capture (déclenchés par les clics), pas en continu.
La source agent_v0/agent_v1/main.py portait déjà l'enrichissement (commit 2d71e2a24)
mais le snapshot deploy/windows_client/agent_v1/main.py n'avait pas été synchronisé.
Désormais chaque heartbeat porte monitor_index + monitors_geometry, le serveur
peut donc résoudre l'écran cible en permanence, même sans clic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cleanup post-review QW1 :
- Émission bus lea:monitor_routed dans /replay/next (idx, source, replay_id, action_id, offset, wh)
via logger.info "[BUS] lea:monitor_routed ..." (le serveur streaming n'a pas
de SocketIO local, agent_chat émet déjà lea:* sur 5004 ; ici on logge en INFO
bien lisible, prêt pour un parser/pont futur)
- Executor Agent V1 (deploy/windows_client) lit action.monitor_resolution.{offset_x, offset_y, idx}
et applique l'offset aux coords absolues du clic/type/scroll/popup quand idx >= 0
- composite_fallback (idx=-1) : pas d'offset appliqué (backward compat mono-écran)
- Log INFO "QW1 monitor cible idx=N source=X offset=(dx,dy) — appliqué aux coords"
émis une fois par action quand un offset non nul s'applique
Tests : baseline 95 passed (e2e + phase0_integration + stream_processor + monitor_router + grounding_offset)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Côté client Agent V1 :
- helpers _get_monitors_geometry() / _get_active_monitor_index() via screeninfo
(fallback gracieux [] / None si screeninfo absent)
- _enrich_with_monitor_info() ajouté aux payloads dict de capture_dual,
capture_active_window, et heartbeat_event poussé par main.py
- screeninfo>=0.8 ajouté aux requirements (source + deploy Windows)
- Deploy capturer.py reçoit l'enrichissement de manière additive (pas de
copie verbatim qui aurait introduit BLUR_SENSITIVE absent côté deploy)
Côté serveur :
- import resolve_target_monitor depuis monitor_router (créé en QW1.1)
- /replay/next : enrichissement action.monitor_resolution avant envoi
au client (idx, offset_x/y, w, h, source de la décision)
- live_session_manager.add_event : propagation monitor_index +
monitors_geometry depuis window_capture ET depuis le payload event
brut (cas heartbeat enrichi sans window/window_title)
Cascade de résolution (cf monitor_router.py) :
1. action.monitor_index (hérité de la session source)
2. session.last_focused_monitor (focus actif vu en dernier heartbeat)
3. composite_fallback (offset 0,0) — backward compat strict
Backward 100% : si geometry vide, fallback composite identique au
comportement actuel mss.monitors[0].
Tests : baseline 89/89 préservée, monitor_router 4/4 OK (total 93/93).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Compatible Flask-SocketIO 5.3.x côté serveur. Ajouté aux deux requirements
client (agent_v1/ et deploy/windows_client/) — le second est utilisé par
l'installeur Pauline (setup_v1.bat).
ATTENTION : redéploiement client requis (PC Windows + VM Linux) avant la démo
GHT Sud 95. La dep ne sert à rien tant que J3.2 (FeedbackBusClient) n'est pas en
place ; aucun impact runtime sur l'agent V1 actuel.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
"Fichier" dans "*,Ceci est un test – Bloc-notes" était rejeté
parce que le titre attendu était "test.txt – Bloc-notes".
Maintenant la comparaison extrait le nom d'app (Bloc-notes)
et accepte le match si c'est la même application.
Résout : "Ajouter un nouvel onglet" bloqué quand un fichier
différent est ouvert dans Bloc-notes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Premier replay fonctionnel de bout en bout (Bloc-notes, Chrome).
Corrections critiques :
- Fix double-lancement agent (Lea.bat start /b + verrou PID)
- Sérialisation replay (threading.Lock dans poll_and_execute)
- Garde UIA bbox >50% écran (rejet conteneurs "Bureau")
- Filtre fenêtres bruit système (systray overflow)
- Auto-nettoyage replays bloqués (paused_need_help)
Cascade visuelle complète dans session_cleaner :
- UIA local (10ms) → template matching (100ms) → serveur docTR/VLM
- Nettoyage bureau pré-replay (clic "Afficher le bureau")
- Crops 80x80 + vlm_description pour chaque clic
Grounding contraint à la fenêtre active :
- Capture croppée à la fenêtre au lieu de l'écran entier
- Conversion coordonnées fenêtre → écran
- Élimine les faux positifs taskbar/systray
Mode apprentissage supervisé (SUPERVISE → capture humaine) :
- Léa passe en mode capture quand elle est perdue
- Capture mini-workflow humain (clics + frappes + combos)
- Fin par Ctrl+Shift+L ou timeout inactivité 10s
- Correction stockée dans target_memory.db via serveur
Deploy Windows complet (grounding.py, policy.py, uia_helper.py).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Symétrie avec le fix 7cc03f6f1 (no_screen_change strict → paused_need_help).
Avant : si l'agent détecte en pré-vérification que la fenêtre active
n'est pas celle attendue, l'erreur retombait dans la branche retry+stop
legacy → 3 retries inutiles puis status=error et queue vidée.
C'est une violation de feedback_failure_is_learning.md : un échec Léa
n'est jamais un "stop avec error", c'est un moment pédagogique.
Maintenant :
1. L'agent envoie warning="wrong_window" dans le résultat (en plus
de l'error textuel existant). Ajouté aux 2 chemins :
- pré-vérif (expected_window_before mismatch, executor.py ~587)
- post-vérif strict (expected_window_title timeout, executor.py ~820)
2. Le serveur détecte warning="wrong_window" AVANT la branche
retry+stop legacy → redirection vers paused_need_help
3. pause_message explicite : "Je m'attendais à voir la bonne fenêtre
mais je vois autre chose. Peux-tu vérifier que l'application est
au premier plan ?"
4. Queue intacte (l'action reste en tête, prête à être relancée)
5. log_replay_failure pour l'apprentissage futur
Cause fréquente identifiée : les popups de Léa elle-même (notifications,
fenêtre de chat) volent le focus Windows pendant le replay → l'app cible
perd le premier plan → pré-vérif détecte le mismatch. Bug UX séparé à
traiter (Léa ne devrait pas prendre le focus pendant un replay actif).
Appliqué aux 2 copies de l'agent (dev + deploy).
Tests : 56 E2E + Phase0 passent, 0 régression.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- agent_rust/ supprimé entièrement (on reste sur Python pour Léa)
- deploy/build/Lea/ supprimé (package stale avec fichiers obsolètes)
- deploy/build_lea_exe.sh supprimé (script PyInstaller Rust, obsolète)
- window_info*.py dupliqués retirés du package Windows
- __pycache__ nettoyé du deploy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Popup handling via double appel VLM (détection + localisation précise du bouton)
- Reconstruction texte depuis raw_keys (numpad /, @ AltGr fusionné)
- Clipboard paste pour texte riche, raw_keys pour commandes simples (Win+R)
- Skip des release orphelins dans raw_keys (fix menu Démarrer parasite)
- Auth Bearer sur toutes les requêtes agent → streaming server
- Endpoints /replay/next et /stream/image publics (agent Rust legacy)
- alt_gr ajouté dans _MODIFIER_ONLY_KEYS
- _key_combo_printable_char détecte ctrl+@ comme caractère imprimable
- start.bat tue les anciens process (python + rpa-agent) au démarrage
- Heartbeat avec token Bearer dans main.py et deploy/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Suppression du .git embarqué dans agent_v0/ — le code est maintenant
tracké normalement dans le repo principal.
Inclut : agent_v1 (client), server_v1 (streaming), lea_ui (chat client)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>