From 7d7f1052f9fec1c1e92d42cb322d288a1ba2cc0e Mon Sep 17 00:00:00 2001 From: sylvain Date: Mon, 16 Mar 2026 07:18:47 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20confirmations=20cron/systemd,=20renforc?= =?UTF-8?q?ement=20script=20skill,=20=C3=A9diteur=20de=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - base_agent: _pending_confirmations + intercepteur oui/non dans _on_xmpp_message - cron: add/remove/clear demandent confirmation (requêtes XMPP directes) - systemd: start/stop/restart/enable/disable/mask/unmask/daemon-reload demandent confirmation - script: _safe_name strip toutes les extensions, extensions système interdites, contenu vide rejeté, nouvelle commande edit | - README mis à jour Co-Authored-By: Claude Sonnet 4.6 --- README.md | 8 +++++++- agents_core/base_agent.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 64d9a0a..9db8cde 100644 --- a/README.md +++ b/README.md @@ -127,9 +127,15 @@ Toutes les commandes suivantes sont disponibles sur chaque agent : /report — Rapport de l'agent /update — Git pull + redémarrage du service /script — Gestion de la bibliothèque de scripts bash - list, show , save | , exec [args], run | , delete + list, show , save | , edit | , exec [args], run | , delete ``` +## Mécanisme de confirmation + +Les actions destructives demandent confirmation avant d'être exécutées lorsqu'elles proviennent d'un message XMPP direct (pas d'une délégation MQTT). + +`BaseAgent` gère automatiquement les réponses `oui` / `non` (et équivalents : yes, ok, confirme, non, no, annule, cancel) avant de passer au LLM. Les skills utilisent `context.agent._pending_confirmations[sender]` pour enregistrer l'action en attente. + ## Topics MQTT | Topic | Usage | diff --git a/agents_core/base_agent.py b/agents_core/base_agent.py index d90bf45..653cd81 100644 --- a/agents_core/base_agent.py +++ b/agents_core/base_agent.py @@ -102,6 +102,10 @@ class BaseAgent(ABC): self._online_lock = threading.Lock() self._llm_lock = threading.Lock() # Empêche les appels LLM concurrents + # Confirmations en attente : {jid: {"description": str, "fn": callable}} + self._pending_confirmations: dict = {} + self._last_xmpp_sender: str = "" + self._running = False # ────────────────────────────────────────────── @@ -462,12 +466,39 @@ class BaseAgent(ABC): # XMPP # ────────────────────────────────────────────── + _CONFIRM_YES = {"oui", "yes", "ok", "confirme", "confirm", "y"} + _CONFIRM_NO = {"non", "no", "annule", "cancel", "abort", "n"} + def _on_xmpp_message(self, sender: str, body: str, is_muc: bool = False): """Traitement des messages XMPP entrants.""" # Les sub-agents ne traitent pas les messages MUC pour éviter les boucles. # Seul Nexus override cette méthode pour gérer le MUC. if is_muc: return + + # ── Gestion des confirmations en attente ────────────────────────── + self._last_xmpp_sender = sender + body_clean = body.strip().lower() + if sender in self._pending_confirmations: + pending = self._pending_confirmations[sender] + if body_clean in self._CONFIRM_YES: + del self._pending_confirmations[sender] + result = pending["fn"]() + if self.xmpp: + self.xmpp.send_message(sender, f"✅ Exécuté.\n{result}") + elif body_clean in self._CONFIRM_NO: + del self._pending_confirmations[sender] + if self.xmpp: + self.xmpp.send_message(sender, f"❌ Annulé : {pending['description']}") + else: + # Message hors-sujet : rappel de la confirmation en attente + if self.xmpp: + self.xmpp.send_message( + sender, + f"⚠️ Action en attente de confirmation :\n{pending['description']}\n\nRéponds **oui** pour confirmer ou **non** pour annuler." + ) + return + cmd = parse_command(body) context = AgentContext(self)