# Plan de réécriture de l'Agent Windows en Rust **Date** : 18 mars 2026 **Statut** : Proposition technique (phase recherche) **Auteur** : Claude Code + Dom --- ## 1. Contexte et motivation ### Situation actuelle (Python) L'agent Windows (`agent_v0/agent_v1/`) est écrit en Python et nécessite : - Python 3.12 installé sur le PC cible - Un virtualenv avec ~10 dépendances directes (mss, pynput, Pillow, requests, pystray, plyer, pywebview, pywin32, psutil) - ~30 dépendances transitives - Un script d'installation (`setup_v1.bat`) fragile - ~200 Mo d'espace disque (Python + venv + site-packages) - Temps de démarrage ~3-5 secondes ### Objectif (Rust) Produire un **exécutable unique** (`lea-agent.exe`, ~5-10 Mo) avec : - Zéro dépendance externe (pas de runtime, pas de DLL, pas d'installation) - Démarrage quasi-instantané (<500ms) - Empreinte mémoire réduite (~15-30 Mo vs ~80-120 Mo en Python) - Distribution par simple copie du .exe ### Périmètre fonctionnel à réécrire | Module Python | Fichier | LOC | Responsabilité | |---|---|---|---| | `main.py` | Orchestrateur | ~390 | Boucles parallèles (heartbeat, replay, watchdog) | | `config.py` | Configuration | ~55 | Paramètres, chemins, endpoints serveur | | `core/captor.py` | Capture d'événements | ~330 | Souris, clavier, focus fenêtre, buffer texte | | `core/executor.py` | Exécuteur d'actions | ~525 | Replay visuel et aveugle, polling serveur | | `network/streamer.py` | Streaming réseau | ~400 | Queue, retry, health-check, compression JPEG | | `vision/capturer.py` | Capture d'écran | ~95 | Screenshots, crops, dédup par hash | | `vision/blur_sensitive.py` | Floutage données | ~205 | Détection champs de saisie, Gaussian blur | | `ui/smart_tray.py` | Icône systray | ~780 | Menu, workflows, état, hotkey Ctrl+Shift+L | | `ui/chat_window.py` | Fenêtre de chat | ~1150 | Chat Léa en tkinter, messages, file upload | | `ui/notifications.py` | Notifications toast | ~220 | Toasts natifs Windows, rate limiting | | `ui/shared_state.py` | État partagé | ~190 | Thread-safe state, observer pattern | | `ui/capture_server.py` | Mini serveur HTTP | ~380 | Port 5006, screenshot à la demande, actions fichiers | | `session/storage.py` | Stockage local | ~75 | Sessions, nettoyage par âge/taille | | `window_info_crossplatform.py` | Info fenêtre | ~180 | Titre + process de la fenêtre active (Win32) | | **Total** | | **~4975** | | --- ## 2. Crates Rust pour chaque fonctionnalité ### 2.1 Capture d'écran (remplace `mss`) | Crate | Version | Statut | Support Windows | Notes | |---|---|---|---|---| | **`xcap`** | 0.8.x | Actif | Oui (DXGI) | Cross-platform (Linux, macOS, Windows). Successeur de `screenshots`. Video recording WIP. Problèmes de build docs.rs sur dernières versions. | | **`windows-capture`** | 1.5.x | Actif | Oui (Graphics Capture API) | Le plus performant sur Windows. Utilise l'API Microsoft moderne. Windows 10+ uniquement. | | `win-screenshot` | 4.x | Mature | Oui | Windows only, simple, stable. | | `scap` | - | Actif | Oui | Par CapSoftware, haute performance, cross-platform. | **Recommandation** : **`xcap`** pour la cross-compatibilité et la simplicité API. Fallback vers `windows-capture` si des performances extrêmes sont nécessaires (capture continue pour le heartbeat). **Justification** : Notre agent capture un screenshot toutes les 5 secondes (heartbeat) et à chaque clic. xcap suffit largement. windows-capture serait un over-engineering pour notre cas d'usage. ### 2.2 Capture et simulation souris/clavier (remplace `pynput`) C'est la fonctionnalité la plus critique car elle couvre **deux besoins distincts** : - **Écoute globale** (capture) : intercepter les clics, frappes et mouvements sans focus - **Simulation** (replay) : générer des clics, frappes et combos de touches | Crate | Version | Rôle | Support Windows | Notes | |---|---|---|---|---| | **`rdev`** | 0.5.x | Écoute globale | Oui (Low-Level Hooks) | Listen + grab + simulate. Le plus complet pour notre usage. Cross-platform. | | **`enigo`** | 0.6.x | Simulation | Oui (SendInput) | Mature, 62K downloads/mois. Mouse + Keyboard simulation. Serde support. | | `willhook` | 0.4.x | Écoute (Windows) | Windows only | Lecture seule, pas de simulation. Safe hooks. | | `inputbot` | 0.6.x | Hotkeys + simulation | Oui | Global hotkeys + simulation, mais moins mature. | | `mki` | - | Listen + simulate | Windows + Linux | Registering global input hooks and simulating. | **Recommandation** : **`rdev`** pour la capture (listen) + **`enigo`** pour la simulation (replay). rdev fournit un listener global qui intercepte souris + clavier sans focus fenêtre, exactement comme pynput. enigo fournit une API propre pour simuler les clics et frappes pendant le replay. **Risque** : Le buffer de saisie texte (accumulation des frappes avec flush après 500ms d'inactivité) est une logique métier complexe. Elle devra être réimplémentée en Rust avec des timers async — faisable mais demande de l'attention. ### 2.3 Icône systray (remplace `pystray`) | Crate | Version | Support Windows | Notes | |---|---|---|---| | **`tray-icon`** | 0.21.x | Oui | Par l'équipe Tauri. Sous-menus, événements, tooltip. Le standard actuel. | | `tray-item` | 0.10.x | Oui | API minimaliste, cross-platform. | | `trayicon` | 0.4.x | Oui | Windows + KDE. Menu popup, clic, double-clic. | **Recommandation** : **`tray-icon`** (crate Tauri). C'est le standard de l'écosystème Rust pour les icônes systray. Maintenu activement (v0.21 avec Tauri 2.10). Supporte les sous-menus (nécessaire pour « Mes tâches »), les icônes dynamiques (nécessaire pour les états idle/recording/replay), et les événements clic/double-clic. ### 2.4 Client HTTP (remplace `requests`) | Crate | Version | Notes | |---|---|---| | **`reqwest`** | 0.12.x | Standard de facto. Async (tokio) ou blocking. Multipart uploads. JSON. TLS natif. | | `ureq` | 2.x | Synchrone, léger, pas de tokio. Bon pour les cas simples. | **Recommandation** : **`reqwest`** avec le feature `blocking` pour les threads de polling, et le feature `multipart` pour l'upload d'images. reqwest est le standard absolu en Rust pour HTTP client. **Configuration Cargo.toml** : ```toml reqwest = { version = "0.12", features = ["json", "multipart", "blocking"] } ``` ### 2.5 Traitement d'images (remplace `Pillow`) | Crate | Version | Notes | |---|---|---| | **`image`** | 0.25.x | Standard Rust. Encodage/décodage PNG, JPEG. Resize, crop. Pure Rust. | | `fast_image_resize` | - | Resize SIMD optimisé. | **Recommandation** : **`image`** (crate standard). Couvre tous nos besoins : lecture PNG des captures, conversion en JPEG pour le streaming, resize pour le hash perceptuel, crop pour la capture duale. ### 2.6 Notifications toast (remplace `plyer`) | Crate | Version | Support Windows | Notes | |---|---|---|---| | **`winrt-notification`** | 0.5.x | Windows 8.1/10/11 | Wrapper WinRT toast API. Léger, stable. | | `notify-rust` | 4.x | Cross-platform | Linux/macOS via D-Bus/NSNotification. Windows via winrt-notification. | | `win-toast-notify` | 0.1.x | Windows 10/11 | Récent, testé Windows 11. | **Recommandation** : **`winrt-notification`** directement (Windows only pour l'agent). Si cross-platform souhaité plus tard, `notify-rust` qui utilise winrt-notification en backend. ### 2.7 Fenêtre de chat (remplace `tkinter`) C'est la fonctionnalité la plus complexe à porter. L'agent Python utilise tkinter (stdlib) pour une fenêtre de chat complète avec : - Messages (bulles Léa/utilisateur), scrollbar, historique - Barre d'actions rapides (Apprenez-moi, Lancer, Données, Arrêter, Aide) - Champ de saisie avec placeholder, upload de fichiers - Indicateur de connexion serveur, drag & resize - DPI awareness, ancrage bas-droite | Crate | Version | Approche | Notes | |---|---|---|---| | **`wry`** | 0.54.x | WebView2 (Edge) | Par Tauri. Charge du HTML/CSS/JS dans une fenêtre native. WebView2 est préinstallé sur Windows 10+. | | `webview2` | - | WebView2 (direct) | Bindings Rust directs pour WebView2. Plus bas niveau que wry. | | `iced` | 0.13.x | GUI native Rust | Elm-like, cross-platform. Pas de HTML/CSS. Courbe d'apprentissage. | | `egui` | 0.30.x | GUI immediate mode | Très léger, rendu custom. Pas adapté pour un chat riche. | **Recommandation** : **`wry`** (WebView2). C'est l'approche optimale pour notre cas : 1. **Le chat est essentiellement une interface web** — HTML/CSS est le meilleur outil pour rendre des bulles de chat, du scroll, des boutons d'actions rapides 2. **WebView2 est préinstallé** sur Windows 10 21H2+ et Windows 11 — pas de dépendance supplémentaire 3. **L'interface chat du VWB existe déjà** côté serveur (port 5004) — on peut charger l'URL directement dans le WebView 4. **Pas besoin de réécrire le frontend** — la fenêtre wry charge simplement `http://{server}:5004/chat` avec injection de l'identité machine **Taille supplémentaire** : ~0 octets (WebView2 est fourni par Windows, wry ne fait que l'instancier) **Fallback** : Si WebView2 n'est pas disponible (Windows 7/8), l'agent fonctionne sans la fenêtre de chat (systray + notifications seulement). ### 2.8 Floutage données sensibles (remplace `OpenCV`) | Crate | Version | Notes | |---|---|---| | **`libblur`** | 0.19.x | Pure Rust, SIMD (SSE/AVX/NEON). Gaussian blur 100 FPS sur 4K. Pas de dépendance OpenCV. | | `imageproc` | 0.25.x | Traitement d'images basé sur le crate `image`. Contours, seuillage, morphologie. | | `opencv` (Rust) | 0.93.x | Bindings OpenCV. Lourds (~200 Mo de DLL), difficile à cross-compiler. | **Recommandation** : **`libblur`** pour le flou gaussien + **`imageproc`** pour la détection de contours et le seuillage. Cela remplace OpenCV sans aucune dépendance native. **Détail de l'implémentation** : Le module `blur_sensitive.py` actuel utilise OpenCV pour : 1. Conversion en niveaux de gris → `image` crate 2. Seuillage binaire → `imageproc` (threshold) 3. Morphologie (close) → `imageproc` (dilate/erode) 4. Détection de contours → `imageproc` (find_contours) 5. Gaussian blur sur les zones détectées → `libblur` Toutes ces opérations ont des équivalents purs Rust. Pas besoin d'OpenCV. ### 2.9 Informations fenêtre active (remplace `pywin32`) | Crate | Version | Notes | |---|---|---| | **`windows`** | 0.61.x | Crate officiel Microsoft. Accès complet à Win32 API. | **Recommandation** : **`windows`** (crate officiel Microsoft). On utilisera : - `GetForegroundWindow()` pour obtenir le handle de la fenêtre active - `GetWindowTextW()` pour le titre - `GetWindowThreadProcessId()` pour le PID - `OpenProcess()` + `QueryFullProcessImageNameW()` pour le nom du processus Cela remplace pywin32 + psutil en une seule dépendance, sans DLL externe. ### 2.10 Mini-serveur HTTP local (remplace `http.server`) | Crate | Version | Notes | |---|---|---| | **`axum`** | 0.8.x | Framework web async (tokio). Léger, performant. | | `warp` | 0.3.x | Alternative plus légère. | | `tiny_http` | 0.12.x | Synchrone, minimaliste. Parfait pour un mini-serveur. | **Recommandation** : **`tiny_http`** pour le serveur de capture (port 5006). C'est un serveur HTTP synchrone minimaliste qui suffit pour 2 endpoints (GET /capture, POST /file-action). Pas besoin d'un framework async pour ça. ### 2.11 Runtime asynchrone | Crate | Version | Notes | |---|---|---| | **`tokio`** | 1.x | Runtime async standard. Nécessaire pour reqwest async. | **Note** : On peut éviter tokio en utilisant `reqwest` en mode `blocking` et des threads standards. Cela simplifie l'architecture et réduit la taille du binaire. L'agent actuel en Python utilise des threads daemon, pas de l'async — le portage direct en threads Rust est plus fidèle. **Recommandation** : **Pas de tokio**. Utiliser des threads standards (`std::thread`) + `reqwest` blocking. L'agent n'a pas besoin de milliers de connexions concurrentes — il a 4-5 boucles parallèles avec des `sleep` de 1-5 secondes. --- ## 3. Architecture proposée ``` rpa_agent_rust/ ├── Cargo.toml — Dépendances et configuration build ├── build.rs — Embedding icône + manifeste Windows ├── assets/ │ ├── lea-icon.ico — Icône de l'application │ ├── manifest.xml — Manifeste Windows (DPI awareness, UAC) │ └── chat/ │ └── index.html — Fallback HTML si serveur chat indisponible ├── src/ │ ├── main.rs — Point d'entrée, orchestrateur (équivalent main.py) │ ├── config.rs — Configuration (SERVER_URL, MACHINE_ID, ports, chemins) │ ├── state.rs — État partagé thread-safe (équivalent shared_state.py) │ │ │ ├── capture/ │ │ ├── mod.rs │ │ ├── screen.rs — Capture d'écran (xcap) — équivalent capturer.py │ │ ├── events.rs — Capture souris/clavier (rdev) — équivalent captor.py │ │ └── window_info.rs — Info fenêtre active (windows crate) — équivalent window_info.py │ │ │ ├── replay/ │ │ ├── mod.rs │ │ ├── executor.rs — Exécution d'actions (enigo) — équivalent executor.py │ │ └── poller.rs — Polling serveur replay — partie de executor.py │ │ │ ├── network/ │ │ ├── mod.rs │ │ ├── streamer.rs — Streaming événements/images (reqwest) — équivalent streamer.py │ │ └── http_server.rs — Mini-serveur capture (tiny_http) — équivalent capture_server.py │ │ │ ├── vision/ │ │ ├── mod.rs │ │ └── blur.rs — Floutage zones sensibles (libblur + imageproc) — équivalent blur_sensitive.py │ │ │ ├── ui/ │ │ ├── mod.rs │ │ ├── tray.rs — Icône systray (tray-icon) — équivalent smart_tray.py │ │ ├── chat.rs — Fenêtre chat (wry/WebView2) — équivalent chat_window.py │ │ └── notifications.rs — Toasts Windows (winrt-notification) — équivalent notifications.py │ │ │ ├── storage/ │ │ ├── mod.rs │ │ └── session.rs — Stockage local + nettoyage — équivalent storage.py │ │ │ └── file_actions/ │ ├── mod.rs │ └── handler.rs — Opérations fichiers (list, move, sort) — partie de capture_server.py │ └── tests/ ├── integration/ │ ├── test_streamer.rs │ └── test_replay.rs └── unit/ ├── test_blur.rs ├── test_events.rs └── test_state.rs ``` ### 3.1 Flux de données principal ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ EventCaptor │────→│ Orchestrator │────→│ Streamer │────→ Serveur :5005 │ (rdev) │ │ (main.rs) │ │ (reqwest) │ └──────────────┘ └──────────────┘ └──────────────┘ │ ┌──────┴──────┐ │ScreenCapture│ │ (xcap) │ └─────────────┘ ┌──────────────┐ ┌──────────────┐ │ ReplayPoller │────→│ Executor │────→ Souris/Clavier (enigo) │ (reqwest) │ │ (enigo) │ └──────────────┘ └──────────────┘ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ TrayIcon │←───→│ State │←───→│ ChatWindow │ │ (tray-icon) │ │ (Arc)│ │ (wry) │ └──────────────┘ └──────────────┘ └──────────────┘ ``` ### 3.2 Gestion des threads L'agent actuel utilise 8-10 threads daemon. Le portage Rust conserve cette architecture : | Thread | Rôle | Crate principal | |---|---|---| | **Main** | Boucle événements systray (tray-icon) | `tray-icon` | | **Event Listener** | Capture souris/clavier | `rdev` | | **Window Focus** | Surveillance focus fenêtre (500ms) | `windows` | | **Heartbeat** | Screenshot + envoi toutes les 5s | `xcap` + `reqwest` | | **Background HB** | Heartbeat sans session active | `xcap` + `reqwest` | | **Replay Poller** | GET /replay/next (1-30s backoff) | `reqwest` | | **Stream Worker** | Queue d'envoi événements/images | `reqwest` | | **Health Check** | Vérification serveur (30s) | `reqwest` | | **HTTP Server** | Serveur capture port 5006 | `tiny_http` | | **Chat Window** | Fenêtre WebView2 (si visible) | `wry` | ### 3.3 Communication inter-threads ```rust // État partagé — équivalent de shared_state.py pub struct AgentState { inner: Arc>, // Channel pour notifier les listeners notify: broadcast::Sender, } struct AgentStateInner { recording: bool, recording_name: String, actions_count: u32, replay_active: bool, server_connected: bool, } // Queue de streaming — équivalent de la queue bornée Python // crossbeam-channel est plus performant que std::sync::mpsc type StreamQueue = crossbeam_channel::bounded(100); ``` --- ## 4. Évaluation de faisabilité par fonctionnalité | Fonctionnalité | Difficulté | Crates | Commentaire | |---|---|---|---| | Capture d'écran (full + crop) | **Facile** | xcap, image | API directe, bien documentée | | Encodage JPEG + resize | **Facile** | image | Standard Rust | | Hash perceptuel (16x16 → MD5) | **Facile** | image, md5 | Trivial | | Capture événements souris | **Facile** | rdev | Global listener, events bien typés | | Capture événements clavier | **Facile** | rdev | Idem | | Buffer de saisie texte (flush 500ms) | **Moyen** | rdev + timers | Logique métier spécifique, timers thread-safe | | Détection double-clic | **Facile** | rdev | Logique pure, pas de dépendance | | Simulation clic souris | **Facile** | enigo | API directe | | Simulation frappe clavier | **Facile** | enigo | keyboard.type() + key combos | | Simulation combo clavier | **Facile** | enigo | press/release des modifiers | | Info fenêtre active (Win32) | **Facile** | windows | GetForegroundWindow, GetWindowTextW | | Streaming HTTP événements | **Facile** | reqwest (blocking) | POST JSON | | Upload image multipart | **Facile** | reqwest (multipart) | POST multipart/form-data | | Retry + backoff exponentiel | **Facile** | Code pur | Boucle simple | | Compression JPEG avant envoi | **Facile** | image | encode_to_jpeg | | Queue bornée + backpressure | **Facile** | crossbeam-channel | bounded(100) + try_send | | Health-check serveur | **Facile** | reqwest (blocking) | GET /stats | | Polling replay | **Facile** | reqwest (blocking) | GET + POST JSON | | Résolution visuelle (POST screenshot) | **Facile** | reqwest + base64 | POST JSON avec image b64 | | Icône systray dynamique | **Facile** | tray-icon | Génération d'icônes cercle coloré | | Menu systray dynamique | **Moyen** | tray-icon | Reconstruction du menu à chaque changement d'état | | Sous-menu workflows | **Moyen** | tray-icon | Nécessite des sous-menus dynamiques (liste du serveur) | | Notifications toast | **Facile** | winrt-notification | API simple, rate limiting en code pur | | Hotkey global Ctrl+Shift+L | **Moyen** | rdev (grab) ou windows | Nécessite un hook clavier global | | Fenêtre de chat (WebView2) | **Moyen** | wry | Création fenêtre + chargement URL serveur | | Chat fallback (HTML local) | **Moyen** | wry | Embedding HTML/CSS/JS dans le binaire | | Floutage champs de saisie | **Moyen** | imageproc + libblur | Réécriture de la détection de contours + seuillage | | Dialogues tkinter (consentement, nom) | **Moyen** | windows (MessageBoxW) | Dialogues Win32 natifs au lieu de tkinter | | Mini-serveur HTTP (port 5006) | **Facile** | tiny_http | 2-3 endpoints, synchrone | | Actions fichiers (list, sort, move) | **Facile** | std::fs | API standard Rust | | Stockage sessions + nettoyage | **Facile** | std::fs | Nettoyage par âge et taille, trivial | | État partagé thread-safe | **Facile** | Arc> | Pattern standard Rust | ### Résumé de faisabilité - **Facile** : 24 fonctionnalités (75%) - **Moyen** : 8 fonctionnalités (25%) - **Difficile** : 0 - **Bloquant** : 0 **Verdict : 100% faisable. Aucun bloqueur identifié.** --- ## 5. Stratégie de migration par phases ### Phase 1 — Agent minimal fonctionnel (2-3 semaines) **Objectif** : Un .exe qui capture et envoie au serveur, et exécute les replays. **Fonctionnalités** : - [x] Configuration (SERVER_URL, MACHINE_ID, ports) - [x] Capture d'écran (xcap) — full + crop - [x] Capture événements souris/clavier (rdev) — clics, combos, texte - [x] Streaming réseau (reqwest) — événements + images + register/finalize - [x] Polling replay (reqwest) — GET /replay/next + POST /result - [x] Exécution d'actions (enigo) — clic, type, key_combo, scroll, wait - [x] Heartbeat toutes les 5s avec dédup - [x] État partagé (Arc) - [x] Stockage local sessions **Pas encore** : UI, notifications, floutage, serveur capture, chat **Livrable** : `lea-agent.exe` (~3 Mo) qui s'exécute en mode headless (pas d'icône, logs en console). Test d'intégration avec le serveur streaming existant. **Critère de validation** : Enregistrer une session depuis l'agent Rust, vérifier qu'elle apparaît dans le VWB, lancer un replay. ### Phase 2 — Systray + notifications (1-2 semaines) **Objectif** : L'agent a une présence visuelle dans la barre des tâches. **Fonctionnalités** : - [x] Icône systray avec états (idle/recording/connected/replay) - [x] Menu contextuel (Apprenez-moi, C'est terminé, Mes tâches, Quitter) - [x] Sous-menu dynamique des workflows (fetch depuis serveur) - [x] Notifications toast (winrt-notification) - [x] Dialogue de consentement (MessageBoxW natif) - [x] Dialogue de saisie du nom de tâche (InputBox Win32) - [x] Arrêt d'urgence (Article 14, Règlement IA) - [x] Hotkey global Ctrl+Shift+L **Livrable** : `lea-agent.exe` (~4 Mo) avec icône systray fonctionnelle. Même expérience utilisateur que l'agent Python (sans le chat). ### Phase 3 — Fenêtre de chat (1-2 semaines) **Objectif** : Le chat Léa intégré dans l'agent. **Fonctionnalités** : - [x] Fenêtre WebView2 (wry) chargeant `http://{server}:5004/chat` - [x] Toggle via Ctrl+Shift+L ou menu systray - [x] Ancrage bas-droite de l'écran - [x] Fallback HTML local si serveur indisponible - [x] Communication bidirectionnelle via JavaScript bridge (pour l'état agent) **Remarque** : Le chat actuel (tkinter) est une réécriture complète du frontend. Avec wry, on peut simplement charger l'interface chat existante du serveur, ce qui est **plus simple** et **plus maintenable** que l'approche Python. **Livrable** : `lea-agent.exe` (~5 Mo) avec chat intégré. ### Phase 4 — Parité complète (1-2 semaines) **Objectif** : 100% des fonctionnalités de l'agent Python. **Fonctionnalités** : - [x] Floutage des données sensibles (libblur + imageproc) - [x] Mini-serveur HTTP port 5006 (capture à la demande, CORS) - [x] Actions fichiers (list_dir, create_dir, move, copy, sort_by_ext) - [x] Sécurité chemins (zones autorisées C:\Users, D:\, E:\) - [x] Nettoyage automatique des sessions (par âge et taille) - [x] Info fenêtre active (surveillance focus, Win32 API) - [x] Divulgation IA (Article 50, Règlement IA) - [x] Log rotation et rétention 180 jours (Article 12, Règlement IA) **Livrable** : `lea-agent.exe` (~6-8 Mo), parité fonctionnelle complète. Prêt pour déploiement en production. ### Phase 5 — Optimisations et polish (optionnel) - Auto-update (téléchargement de la nouvelle version depuis le serveur) - Installeur MSI/NSIS optionnel (pour l'inscription au démarrage Windows) - Compression UPX du binaire (~3-4 Mo) - Signature du code (certificat Authenticode) - Télémétrie d'erreurs (panic handler → envoi au serveur) --- ## 6. Build et distribution ### 6.1 Cross-compilation Linux → Windows Deux approches possibles : **Option A : `cargo-xwin` (recommandée)** ```bash # Installation une fois cargo install cargo-xwin rustup target add x86_64-pc-windows-msvc # Build cargo xwin build --target x86_64-pc-windows-msvc --release ``` Avantage : Produit un .exe compatible MSVC (le standard Windows). Inconvénient : Télécharge le SDK Windows (~1 Go la première fois). **Option B : `cross` (plus simple, GNU)** ```bash cargo install cross cross build --target x86_64-pc-windows-gnu --release ``` Avantage : Utilise un container Docker, rien à installer. Inconvénient : Produit un .exe GNU (peut nécessiter mingw runtime). **Recommandation** : `cargo-xwin` pour la production (MSVC target), `cross` pour les tests rapides. ### 6.2 Icône dans le .exe ```rust // build.rs fn main() { if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" { let mut res = tauri_winres::WindowsResource::new(); res.set_icon("assets/lea-icon.ico"); res.set("ProductName", "Léa Agent"); res.set("FileDescription", "Agent RPA Vision - Léa"); res.set("LegalCopyright", "Copyright 2026"); res.compile().unwrap(); } } ``` Dépendance build : `tauri-winres` (fork maintenu de `winres`). ### 6.3 Manifeste Windows (DPI + UAC) Le manifeste `assets/manifest.xml` déclare : - DPI awareness (per-monitor V2) — nécessaire pour les captures d'écran correctes - requestedExecutionLevel = asInvoker (pas besoin d'admin) - Windows 10+ compatibility ### 6.4 Signature du code Pour éviter les avertissements SmartScreen à l'exécution : ```bash # Avec signtool (Windows SDK) signtool sign /f certificate.pfx /p password /tr http://timestamp.digicert.com /td sha256 /fd sha256 lea-agent.exe # Ou avec le crate rust-codesign depuis Linux cargo install codesign codesign --cert certificate.pfx --password password lea-agent.exe ``` **Coût** : Un certificat EV Code Signing coûte ~300-500 EUR/an. Un certificat OV standard ~100-200 EUR/an. Pour un usage interne (déploiement sur des machines contrôlées), la signature n'est pas obligatoire — on peut ajouter une exception Windows Defender. ### 6.5 Estimation de taille du .exe | Configuration | Taille estimée | |---|---| | Debug build | ~30-50 Mo | | Release build (défaut) | ~15-20 Mo | | Release + LTO + strip | ~6-10 Mo | | Release + LTO + strip + opt-level z | ~5-8 Mo | | Release + LTO + strip + UPX | ~3-5 Mo | **Profil release optimisé** (Cargo.toml) : ```toml [profile.release] opt-level = "s" # Optimisation taille (z = encore plus petit mais plus lent) lto = true # Link-Time Optimization codegen-units = 1 # Optimisation max panic = "abort" # Pas de stack unwinding strip = true # Suppression des symboles ``` --- ## 7. Comparaison de performances estimée | Métrique | Python (actuel) | Rust (estimé) | Amélioration | |---|---|---|---| | **Taille installation** | ~200 Mo (Python + venv) | ~6-10 Mo (.exe seul) | **20-30x plus petit** | | **Temps de démarrage** | 3-5 secondes | 100-300 ms | **10-15x plus rapide** | | **Mémoire au repos** | 80-120 Mo | 15-30 Mo | **4-5x moins** | | **Mémoire en session** | 120-180 Mo | 25-50 Mo | **3-4x moins** | | **Capture screenshot** | 30-80 ms (mss) | 5-15 ms (xcap/DXGI) | **3-5x plus rapide** | | **Compression JPEG** | 15-30 ms (Pillow) | 5-10 ms (image crate) | **2-3x plus rapide** | | **Envoi HTTP** | ~identique (TCP) | ~identique (TCP) | Négligeable | | **Floutage** | 50-150 ms (OpenCV) | 10-30 ms (libblur SIMD) | **3-5x plus rapide** | | **Utilisation CPU idle** | 1-3% | <0.5% | **3-5x moins** | | **Complexité installation** | Script .bat + Python + pip | Copier 1 fichier .exe | **Incomparable** | **Notes** : - L'envoi HTTP est dominé par la latence réseau, pas par le langage - Les captures screenshot sont déjà rapides en Python (mss utilise DXGI) — le gain Rust est surtout sur le traitement post-capture - Le gain le plus significatif est sur la **distribution** (1 fichier vs installation complexe) --- ## 8. Risques et défis ### 8.1 Risques techniques | Risque | Impact | Probabilité | Mitigation | |---|---|---|---| | `rdev` buggy sur certaines versions de Windows | Élevé | Faible | Tests sur Windows 10 LTSC, 11 23H2. Fallback vers `willhook` + `windows` crate direct. | | WebView2 absent (Windows 7/8) | Faible | Très faible | PC cible = Windows 10+. Le chat est optionnel, le systray + notifications suffisent. | | `tray-icon` ne supporte pas les sous-menus dynamiques | Moyen | Faible | Tester en amont. Fallback : menu plat avec numérotation. | | DPI scaling incorrect pour les captures | Moyen | Moyen | Manifeste DPI-aware + tests multi-écran. Le problème existe déjà en Python. | | Cross-compilation échoue avec certains crates (liens natifs) | Moyen | Moyen | Build natif sur une VM Windows si nécessaire. CI GitHub Actions avec Windows runner. | | Bugs de threading (deadlocks, races) | Élevé | Faible | Le borrow checker Rust élimine les data races. Les deadlocks restent possibles — revue attentive de l'ordre de verrouillage. | ### 8.2 Ce qui reste côté serveur Les fonctionnalités suivantes ne sont PAS portées en Rust car elles restent côté serveur (Python) : - **Analyse visuelle (CLIP, FAISS, ScreenAnalyzer)** — GPU server - **VLM (Ollama, template matching)** — GPU server - **Construction du workflow (GraphBuilder)** — serveur streaming - **Chat LLM (Copilot, GestureCatalog)** — serveur chat port 5004 - **Dashboard, VWB** — serveur web L'agent Rust est **strictement un client** : il capture, envoie, et exécute. Toute l'intelligence reste sur le serveur. ### 8.3 Chat : stratégie WebView vs natif Le chat tkinter actuel (chat_window.py, 1150 LOC) est le module le plus gros de l'agent. Il implémente un frontend complet en tkinter : bulles de messages, scrollbar, boutons d'actions, upload fichier, indicateur de connexion. **L'approche WebView (wry) est supérieure** pour plusieurs raisons : 1. **Pas de duplication** : L'interface chat existe déjà sur le serveur (port 5004). En la chargeant dans un WebView, on bénéficie de toutes les améliorations côté serveur sans rebuilder l'agent. 2. **Rendu supérieur** : HTML/CSS produit une interface beaucoup plus riche que tkinter (animations, emojis, markdown, images inline). 3. **Maintenance réduite** : Une seule codebase pour le chat (côté serveur), pas de duplication Python/Rust. 4. **Taille binaire** : wry ajoute ~200 Ko au binaire (le rendu est fait par WebView2 déjà installé sur Windows). **Inconvénient** : L'agent nécessite une connexion au serveur pour afficher le chat. En mode offline, il faudrait un HTML de fallback embarqué dans le binaire (message « Connexion au serveur requise »). ### 8.4 AZERTY et internationalisation Le clavier du PC cible est AZERTY. Points d'attention : - **rdev** renvoie les scancodes bruts — la conversion en caractères dépend du layout clavier Windows. Vérifier que rdev gère correctement AZERTY (les accents, les chiffres en Shift, etc.). - **enigo** pour la simulation : `keyboard.type()` utilise SendInput avec les caractères Unicode, pas les scancodes — devrait fonctionner correctement en AZERTY. - À tester en priorité lors de la Phase 1. --- ## 9. Dépendances Cargo.toml prévisionnelles ```toml [package] name = "lea-agent" version = "1.0.0" edition = "2021" description = "Agent RPA Vision - Léa" build = "build.rs" [dependencies] # Capture d'écran xcap = "0.8" # Capture événements souris/clavier rdev = "0.5" # Simulation souris/clavier (replay) enigo = { version = "0.6", features = ["serde"] } # Systray tray-icon = "0.21" # HTTP client reqwest = { version = "0.12", default-features = false, features = [ "json", "multipart", "blocking", "rustls-tls" ] } # Image processing image = "0.25" # Floutage libblur = "0.19" imageproc = "0.25" # Notifications Windows winrt-notification = "0.5" # Chat window (WebView2) wry = "0.54" # Mini-serveur HTTP tiny_http = "0.12" # Sérialisation serde = { version = "1", features = ["derive"] } serde_json = "1" # Logging log = "0.4" env_logger = "0.11" # Hash (perceptuel screenshot) md5 = "0.7" # Base64 (screenshots post-action) base64 = "0.22" # UUID (session IDs) uuid = { version = "1", features = ["v4"] } # Date/heure chrono = "0.4" # Canaux inter-threads performants crossbeam-channel = "0.5" # Win32 API (info fenêtre, dialogues) [target.'cfg(windows)'.dependencies] windows = { version = "0.61", features = [ "Win32_UI_WindowsAndMessaging", "Win32_System_Threading", "Win32_Foundation", "Win32_Security", ] } [build-dependencies] tauri-winres = "0.2" [profile.release] opt-level = "s" lto = true codegen-units = 1 panic = "abort" strip = true ``` **Nombre de dépendances directes** : 18 (vs ~10 en Python, mais toutes compilées statiquement dans le binaire final — pas de DLL, pas de pip, pas de virtualenv). --- ## 10. Plan de tests ### 10.1 Tests unitaires (Phase 1) | Module | Tests | |---|---| | `config.rs` | Lecture variables d'environnement, valeurs par défaut | | `state.rs` | Transitions d'état, notifications listeners, thread-safety | | `vision/blur.rs` | Détection champs de saisie, application du flou, image inchangée si pas de champ | | `capture/events.rs` | Buffer texte : accumulation, flush après timeout, flush sur clic | | `capture/events.rs` | Double-clic : détection, tolérance position, timeout | | `replay/executor.rs` | Conversion coordonnées normalisées → pixels | | `storage/session.rs` | Création dossier, nettoyage par âge, nettoyage par taille | | `file_actions/handler.rs` | Validation chemins (sécurité anti-traversal) | ### 10.2 Tests d'intégration (Phase 2-3) | Scénario | Description | |---|---| | Streaming | Envoyer événement + image au serveur :5005, vérifier réception | | Replay | Simuler une action replay depuis le serveur, vérifier exécution | | Heartbeat | Vérifier envoi périodique + dédup (même écran = pas d'envoi) | | Tray menu | Vérifier affichage menu, changement d'icône sur enregistrement | | Chat WebView | Vérifier ouverture fenêtre, chargement URL serveur | ### 10.3 Tests manuels sur PC Windows cible | Test | Vérification | |---|---| | AZERTY | Taper « été » → le texte capturé est bien « été » | | Multi-écran | Capture correcte sur l'écran principal | | DPI 125%/150% | Coordonnées de clic correctes après scaling | | Sleep/Reprise | L'agent se reconnecte après mise en veille | | Replay complet | Workflow calculatrice : 3+5=8 | | Arrêt d'urgence | Le systray stoppe immédiatement toute activité | --- ## 11. Calendrier prévisionnel | Phase | Durée | Livrable | |---|---|---| | Phase 1 — Agent minimal | 2-3 semaines | lea-agent.exe headless, capture + replay | | Phase 2 — Systray + notifications | 1-2 semaines | Icône, menu, toasts | | Phase 3 — Chat WebView | 1-2 semaines | Fenêtre de chat intégrée | | Phase 4 — Parité complète | 1-2 semaines | Floutage, serveur capture, actions fichiers | | Phase 5 — Polish (optionnel) | 1 semaine | Auto-update, signature, installeur | | **Total** | **6-10 semaines** | **Parité complète** | ### Prérequis avant de commencer 1. **Installer la toolchain Rust** sur la machine de dev : ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add x86_64-pc-windows-msvc cargo install cargo-xwin ``` 2. **Préparer l'environnement de test** : - VM Windows 10/11 ou accès au PC cible (192.168.1.11) - Serveur streaming (:5005) accessible depuis le PC cible 3. **Créer le repo** : ```bash cd ~/ai/rpa_vision_v3 mkdir -p rpa_agent_rust/src rpa_agent_rust/assets cd rpa_agent_rust cargo init ``` --- ## 12. Conclusion La réécriture de l'agent Windows en Rust est **techniquement faisable à 100%** et apporterait des bénéfices majeurs : **Gains quantifiables** : - Taille : 200 Mo → 6-10 Mo (**20x plus petit**) - Démarrage : 5s → 300ms (**15x plus rapide**) - Mémoire : 120 Mo → 30 Mo (**4x moins**) - Installation : Script .bat + Python → Copier 1 fichier (**incomparable**) **Gains qualitatifs** : - Plus de problèmes de version Python sur les PC cibles - Plus de virtualenv cassé, plus de `pip install` qui échoue - Distribution par email, clé USB, ou téléchargement direct - Fiabilité accrue (borrow checker, pas de GIL, pas de GC) **Risques principaux** : - Courbe d'apprentissage Rust (si pas de développeur Rust dans l'équipe) - Temps de développement initial plus long qu'en Python (~6-10 semaines vs ~4 semaines) - Maintenance de deux codebases pendant la transition **Recommandation** : Procéder par phases. La Phase 1 (agent minimal) permet de valider la faisabilité en conditions réelles avec un investissement limité. Si elle réussit, les phases suivantes sont incrémentales et relativement simples. --- *Document généré le 18 mars 2026.*