VWB Executor :
- _check_screen_for_patterns() : capture écran + OCR + pattern matching
- _handle_detected_pattern() : clic automatique sur dialogues connus
- Vérifie entre chaque étape en mode intelligent/debug
- Si un dialogue bloque (OK, Save, Cancel), Léa le gère seule
Stream Processor :
- Enrichit les ScreenState avec ui_pattern/ui_pattern_action/ui_pattern_target
- Les patterns détectés sont loggés et stockés dans les résultats
- Permet au GraphBuilder de savoir quels écrans sont des dialogues
Phase 2 du plan "connaissance native de l'environnement".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Le grounding se déclenche pour by_text_source="vlm" (pas juste "ocr")
Les textes lus par gemma4 (onglets, labels) sont du texte visible,
le grounding doit les chercher comme n'importe quel texte OCR.
2. gemma4 est automatiquement déchargé après le build_replay
pour libérer la VRAM et permettre à qwen2.5vl de charger au replay.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Quand l'OCR et SomEngine ne trouvent pas de texte sur un élément cliqué,
gemma4 (Ollama 0.20 Docker) analyse le screenshot fenêtre + position du
clic pour identifier l'élément ("voiture elec", "Settings", etc.).
Résultat : 0 clic sans by_text (vs 3 avant). Validation locale 7/8 (87%).
L'onglet Bloc-notes est maintenant correctement identifié.
Docker : ollama/ollama:0.20.2 sur port 11435 (GEMMA4_PORT env var).
Host : Ollama 0.16.3 sur port 11434 (qwen2.5vl grounding).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pré-vérification : avant chaque clic, vérifie que le titre de la
fenêtre active correspond à celui de l'enregistrement. Stop si mismatch.
Post-vérification : après chaque clic, vérifie que le titre a changé
vers expected_window_title (titre du prochain clic). Warning si mismatch.
expected_window_title enrichi dans build_replay depuis la séquence des clics.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le premier clic (barre de recherche Windows) a un titre
"unknown_window" qui déclenchait la coupure de fin de session.
Ajout d'un guard : pas de coupure avant 3 actions significatives.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Utilise shot_XXXX_window.png (capture fenêtre active) au lieu du
full screen pour le grounding VLM. Image plus petite, ciblée,
sans bruit (taskbar, autres fenêtres).
Coordonnées fenêtre converties en coordonnées écran via window_rect.
window_capture (rect, window_size, click_relative) ajouté au target_spec.
Résultat : 50% → 80% de précision sur la session VM (16/20 clics).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Résolution 4/4 (100%) validée localement :
- Texte OCR (by_text_source="ocr") → grounding Qwen2.5-VL (dist < 0.04)
- Icônes sans texte (by_text_source="") → template matching crop 80x80 (dist = 0.000)
Le VLM identify element est supprimé pour les icônes (descriptions
non-déterministes qui faisaient échouer le grounding). Le template
matching est instantané et parfait quand le crop est net (80x80).
Ajout de by_text_source dans target_spec pour distinguer OCR vs VLM.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Nouvelle approche basée sur les recherches état de l'art :
- _resolve_by_grounding() : le VLM retourne directement les coordonnées
(pas de SomEngine + numérotation intermédiaire)
- Utilise Qwen2.5-VL (entraîné pour le GUI grounding) au lieu de qwen3-vl
- Parse les formats natifs : bbox_2d, JSON x/y, arrays bruts
- Fallback multi-image : screenshot + crop → grounding sans description
- Identification des icônes via Qwen2.5-VL (meilleur que qwen3-vl)
Résultats sur session réelle (validation locale) :
- Éléments avec texte (Word, Document, Fichier) : 100% corrects
- Icônes sans texte (Windows logo, disquette) : en cours d'amélioration
Cascade strict mode :
0. Grounding VLM direct (Qwen2.5-VL) — NOUVEAU
0.5. Template matching pour icônes
1. VLM Quick Find (fallback)
1.5. SoM + VLM
2. Template matching strict
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pour les environnements Citrix avec détection de robots :
- Souris : courbe de Bézier quadratique avec déviation aléatoire
et vitesse variable (25 étapes, plus lent début/fin)
- Texte : frappe caractère par caractère via KeyCode.from_char()
avec délai aléatoire 40-120ms (pas de copier-coller)
- Plus de presse-papiers (Ctrl+V détectable)
Annulation du fix raw_keys→clipboard (plus nécessaire).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Crop réduit de 150x150 à 80x80 (config + fallback serveur)
Plus discriminant pour les icônes de barre de titre
2. Email AZERTY : supprimer raw_keys quand le texte contient des
chars fusionnés depuis key_combos (@ de AltGr) → copier-coller
Le @ était perdu car absent des raw_keys individuels
3. Anchor match : template matching sur screenshot entier puis
élément SomEngine le plus proche (max 100px)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le VLM 8B répond souvent avec "several UI elements", "I can see",
etc. au lieu d'un label court. Ces réponses remplissaient by_text
avec du non-sens, empêchant le som_anchor_match de se déclencher
pour les icônes sans texte (disquette, fermer, etc.).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
build_replay (stream_processor.py) :
- Remplir by_text depuis vision_info.text ou som_element.label
- VLM identification pour les éléments sans texte (icônes)
- Nettoyage du bavardage VLM (retrait préfixes courants)
resolve_target (api_stream.py) :
- Nouveau som_anchor_match : template matching du crop anchor vs régions YOLO
- Pour les icônes sans texte (disquette, loupe, etc.)
- Cascade : text match → anchor match → VLM
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 1 : enrichit chaque clic avec som_element (id, label, bbox) via YOLO+docTR
Phase 2 : nouvelle résolution SoM+VLM — SomEngine numérote, VLM identifie le mark
10 tests unitaires ajoutés, conftest unit/ pour le bon path agent_v0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Screenshots de référence (res_shot_XXXX.png) attachés aux actions click/key_combo
- _attach_expected_screenshots() charge les screenshots résultat de l'enregistrement
- _verify_visual_state() dans executor : 2 étages de vérification
- Étage 1 : template matching rapide (~100ms), score > 0.7 = OK, < 0.3 = FAIL
- Étage 2 : VLM compare current vs expected (~4s), MATCH/MISMATCH
- Résultat attaché à chaque action (visual_verification dans result)
- Note : executor sur Windows (/tmp/executor_win.py) à synchroniser manuellement
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>
Worker VLM séparé :
- run_worker.py : process distinct du serveur HTTP
- Communication par fichiers (_worker_queue.txt + _replay_active.lock)
- Service systemd rpa-worker.service
- Le serveur HTTP ne charge plus CLIP/VLM (mode léger)
- StreamProcessor._ensure_initialized() désactivé dans le serveur
VLM direct depuis l'agent :
- L'agent appelle Ollama directement (port 11434, LAN)
- Ollama configuré sur 0.0.0.0 (OLLAMA_HOST)
- Pas de passage par le serveur streaming (évite le blocage GIL)
- Fallback serveur supprimé (VLM direct ou STOP)
Popup handler hybride :
- VLM identifie le bouton ("Oui", "OK") — pas de coordonnées
- Template matching localise le texte sur l'écran (PIL + cv2)
- _find_text_on_screen() : rend le texte en image, matchTemplate
- _vlm_identify_popup_button() : prompt simple, prefill texte
Resolve visuel hybride :
- Cascade : template anchor → VLM+template texte → VLM direct (legacy)
- _hybrid_vlm_resolve() : VLM identifie + template localise
- _template_match_anchor() : match direct crop, seuil 0.80
- Seuil strict 0.90 pour template matching en mode replay
Analyse VLM temps réel désactivée :
- process_screenshot() ne fait plus de VLM (stockage uniquement)
- L'analyse est différée au worker séparé
- Le serveur HTTP reste réactif en permanence
VLM prefill fix :
- num_ctx augmenté (2048 → 8192 pour images 1080p)
- bbox_2d au lieu de click_point (plus fiable)
- Coordonnées 0-1000 (format natif qwen3-vl)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Analyse VLM :
- 1 seul appel VLM par screenshot au lieu de 30 (~15s vs 6.5min)
- Sélection screenshots par hash perceptuel (3-4 utiles sur 12)
- Fallback classification individuelle si appel unique échoue
- Estimation : ~1min par workflow au lieu de 78min
Rust agent :
- Léa (Edge mode app) s'ouvre automatiquement au démarrage
- Plus besoin de systray pour lancer le chat
- Fix URL chat /chat → /
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Workflows appris par Léa visibles dans le VWB ("Appris par Léa")
- Bouton "Importer" pour éditer un workflow appris
- Bouton "Exporter pour Léa" pour rendre un workflow VWB exécutable
- Conversion bidirectionnelle core ↔ VWB via learned_workflow_bridge
- Liste unifiée dans le chat Léa (merged + dédupliquée)
- reload_workflows() sur le streaming server (pas de redémarrage)
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>