Files
rpa_vision_v3/docs/PLAN_AGENT_RUST.md
Dom 792cc2aa9a docs: plan de migration agent Windows Python → Rust
É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>
2026-03-18 19:35:41 +01:00

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 :

  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<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 :

  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

[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 :

    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 :

    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.