feat: agent Rust complet — systray, chat, enregistrement, floutage (2.4 MB)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-03-18 23:18:09 +01:00
parent ad7ff3bce4
commit 90ee91caf9
11 changed files with 2329 additions and 191 deletions

View File

@@ -1,8 +1,8 @@
//! Boucle de polling replay.
//!
//! Poll le serveur toutes les secondes pour récupérer les actions à exécuter.
//! Quand une action est reçue, l'exécute via executor et rapporte le résultat.
//! Gère le backoff exponentiel en cas d'indisponibilité du serveur.
//! Poll le serveur toutes les secondes pour recuperer les actions a executer.
//! Quand une action est recue, l'execute via executor et rapporte le resultat.
//! Gere le backoff exponentiel en cas d'indisponibilite du serveur.
//!
//! Reproduit le comportement de _replay_poll_loop dans agent_v1/main.py.
@@ -10,35 +10,50 @@ use crate::capture;
use crate::config::Config;
use crate::executor;
use crate::network;
use crate::notifications;
use crate::state::AgentState;
use reqwest::blocking::Client;
use std::thread;
use std::time::Duration;
/// Boucle de polling replay (tourne dans un thread dédié).
/// Boucle de polling replay (tourne dans un thread dedie).
///
/// - Poll GET /replay/next toutes les secondes
/// - Exécute l'action via executor
/// - Execute l'action via executor
/// - Capture un screenshot post-action
/// - Rapporte le résultat via POST /replay/result
/// - Rapporte le resultat via POST /replay/result
/// - Backoff exponentiel si le serveur est indisponible
pub fn replay_poll_loop(config: &Config) {
pub fn replay_poll_loop(config: &Config, state: &AgentState) {
let client = Client::new();
let mut poll_count: u64 = 0;
let mut backoff = config.replay_poll_interval_s;
let backoff_max = 30.0_f64;
let backoff_factor = 1.5_f64;
let backoff = config.replay_poll_interval_s;
let _backoff_max = 30.0_f64;
let _backoff_factor = 1.5_f64;
let mut replay_active = false;
let mut last_conn_error_logged = false;
println!(
"[REPLAY] Boucle replay demarree — poll toutes les {:.0}s sur {}",
config.replay_poll_interval_s, config.server_url
);
loop {
while state.is_running() {
// Verifier l'arret d'urgence
if state
.emergency_stop
.load(std::sync::atomic::Ordering::SeqCst)
{
if replay_active {
println!("[REPLAY] ARRET D'URGENCE — replay interrompu");
replay_active = false;
state.set_replay_active(false);
}
thread::sleep(Duration::from_secs(1));
continue;
}
poll_count += 1;
// Log périodique toutes les 60s pour confirmer que la boucle tourne
// Log periodique toutes les 60s pour confirmer que la boucle tourne
let polls_per_minute = (60.0 / backoff).ceil() as u64;
if polls_per_minute > 0 && poll_count % polls_per_minute == 0 {
println!(
@@ -51,12 +66,10 @@ pub fn replay_poll_loop(config: &Config) {
match network::poll_next_action(&client, config) {
Some(action) => {
// Reset backoff et flag d'erreur
backoff = config.replay_poll_interval_s;
last_conn_error_logged = false;
if !replay_active {
replay_active = true;
state.set_replay_active(true);
notifications::replay_started("workflow");
println!("[REPLAY] Replay demarre");
}
@@ -67,10 +80,10 @@ pub fn replay_poll_loop(config: &Config) {
action_type, action_id
);
// Obtenir les dimensions de l'écran
// Obtenir les dimensions de l'ecran
let (sw, sh) = capture::screen_dimensions().unwrap_or((1920, 1080));
// Exécuter l'action (avec config pour la résolution visuelle)
// Executer l'action (avec config pour la resolution visuelle)
println!(">>> Execution de l'action {}...", action_type);
let mut result = executor::execute_action(&action, sw, sh, config);
println!(
@@ -78,7 +91,7 @@ pub fn replay_poll_loop(config: &Config) {
result.success, result.error
);
// Capture screenshot post-action (après 500ms)
// Capture screenshot post-action (apres 500ms)
thread::sleep(Duration::from_millis(500));
if let Some(img) = capture::capture_screenshot() {
let b64 = capture::screenshot_to_jpeg_base64(&img, 60);
@@ -87,35 +100,26 @@ pub fn replay_poll_loop(config: &Config) {
}
}
// Rapporter le résultat au serveur (TOUJOURS, même en erreur)
// Rapporter le resultat au serveur (TOUJOURS, meme en erreur)
network::report_result(&client, config, &result);
// Poll plus rapidement pour enchaîner les actions
// Poll plus rapidement pour enchainer les actions
thread::sleep(Duration::from_millis(200));
continue;
}
None => {
// Pas d'action — soit pas de replay, soit serveur indisponible
if replay_active {
println!("[REPLAY] Replay termine — retour en mode capture");
replay_active = false;
state.set_replay_active(false);
notifications::replay_finished(true);
}
// Vérifier si c'est un timeout/erreur réseau (backoff)
// Le poll_next_action retourne None aussi si le serveur refuse
// On ne peut pas distinguer facilement, donc on garde le backoff simple
}
}
// Si on a eu des erreurs récentes, le backoff est > 1s
let sleep_duration = Duration::from_secs_f64(backoff);
thread::sleep(sleep_duration);
// Note: le backoff augmente seulement quand poll_next_action renvoie None
// et qu'on suspecte une erreur réseau. Pour l'instant, on garde le poll
// à intervalles constants (1s). Le backoff sera implémenté plus finement
// quand on aura un meilleur signal d'erreur réseau.
let _ = (backoff_max, backoff_factor, &mut last_conn_error_logged);
}
println!("[REPLAY] Boucle arretee.");
}