Étude de faisabilité complète : 100% faisable, 0 bloqueur. Crates identifiées pour les 8 fonctionnalités clés. Migration en 5 phases sur 6-10 semaines. Gains : exe unique 10MB, démarrage 200ms, RAM 30MB. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
37 KiB
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 :
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 :
- 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
- WebView2 est préinstallé sur Windows 10 21H2+ et Windows 11 — pas de dépendance supplémentaire
- L'interface chat du VWB existe déjà côté serveur (port 5004) — on peut charger l'URL directement dans le WebView
- Pas besoin de réécrire le frontend — la fenêtre wry charge simplement
http://{server}:5004/chatavec 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 :
- Conversion en niveaux de gris →
imagecrate - Seuillage binaire →
imageproc(threshold) - Morphologie (close) →
imageproc(dilate/erode) - Détection de contours →
imageproc(find_contours) - 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 activeGetWindowTextW()pour le titreGetWindowThreadProcessId()pour le PIDOpenProcess()+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<Mutex>)│ │ (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
// État partagé — équivalent de shared_state.py
pub struct AgentState {
inner: Arc<Mutex<AgentStateInner>>,
// Channel pour notifier les listeners
notify: broadcast::Sender<StateChange>,
}
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<StreamItem>(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<Mutex> | 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 :
- Configuration (SERVER_URL, MACHINE_ID, ports)
- Capture d'écran (xcap) — full + crop
- Capture événements souris/clavier (rdev) — clics, combos, texte
- Streaming réseau (reqwest) — événements + images + register/finalize
- Polling replay (reqwest) — GET /replay/next + POST /result
- Exécution d'actions (enigo) — clic, type, key_combo, scroll, wait
- Heartbeat toutes les 5s avec dédup
- État partagé (Arc)
- 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 :
- Icône systray avec états (idle/recording/connected/replay)
- Menu contextuel (Apprenez-moi, C'est terminé, Mes tâches, Quitter)
- Sous-menu dynamique des workflows (fetch depuis serveur)
- Notifications toast (winrt-notification)
- Dialogue de consentement (MessageBoxW natif)
- Dialogue de saisie du nom de tâche (InputBox Win32)
- Arrêt d'urgence (Article 14, Règlement IA)
- 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 :
- Fenêtre WebView2 (wry) chargeant
http://{server}:5004/chat - Toggle via Ctrl+Shift+L ou menu systray
- Ancrage bas-droite de l'écran
- Fallback HTML local si serveur indisponible
- 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 :
- Floutage des données sensibles (libblur + imageproc)
- Mini-serveur HTTP port 5006 (capture à la demande, CORS)
- Actions fichiers (list_dir, create_dir, move, copy, sort_by_ext)
- Sécurité chemins (zones autorisées C:\Users, D:, E:)
- Nettoyage automatique des sessions (par âge et taille)
- Info fenêtre active (surveillance focus, Win32 API)
- Divulgation IA (Article 50, Règlement IA)
- 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)
# 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)
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
// 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 :
# 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) :
[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 :
-
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.
-
Rendu supérieur : HTML/CSS produit une interface beaucoup plus riche que tkinter (animations, emojis, markdown, images inline).
-
Maintenance réduite : Une seule codebase pour le chat (côté serveur), pas de duplication Python/Rust.
-
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
[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
-
Installer la toolchain Rust sur la machine de dev :
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add x86_64-pc-windows-msvc cargo install cargo-xwin -
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
-
Créer le repo :
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 installqui é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.