diff --git a/agent_v0/server_v1/api_stream.py b/agent_v0/server_v1/api_stream.py index ef41f5be5..9e86342f5 100644 --- a/agent_v0/server_v1/api_stream.py +++ b/agent_v0/server_v1/api_stream.py @@ -2168,8 +2168,9 @@ async def get_next_action(session_id: str, machine_id: str = "default"): # Else: queue a changé entre temps (race condition bénigne), on envoie quand même # Sauvegarder l'action envoyée pour le retry (si la vérification échoue) + # NE PAS écraser si _schedule_retry a déjà mis le bon retry_count action_id_sent = action.get("action_id", "") - if action_id_sent: + if action_id_sent and action_id_sent not in _retry_pending: _retry_pending[action_id_sent] = { "action": dict(action), "retry_count": 0, @@ -2228,6 +2229,18 @@ async def report_action_result(report: ReplayResultReport): retry_count = retry_info["retry_count"] if retry_info else 0 original_action = retry_info["action"] if retry_info else None + # Guard de sécurité : détecter le retry_count depuis l'action_id si non trouvé + # Évite la boucle infinie si _retry_pending est désynchronisé + if retry_count == 0 and "_retry" in action_id: + import re + retry_suffixes = re.findall(r"_retry\d+", action_id) + retry_count = max(retry_count, len(retry_suffixes)) + if retry_count > 0: + logger.warning( + f"retry_count corrigé par action_id : {retry_count} " + f"(action_id contient {len(retry_suffixes)} suffixes _retry)" + ) + # Mettre à jour le dernier screenshot reçu screenshot_after = report.screenshot_after or report.screenshot if screenshot_after: