Ajout !agentUPDATE/UPGRADE : mises à jour agents depuis git

- skills/agent_update.py : check_update (git fetch + log) et do_upgrade (git pull + systemctl restart)
- agent1.py : commandes !agentUPDATE <nom>, !agentsUPDATE, !agentUPGRADE <nom>, !agentsUPGRADE
  - _handle_agent_command retourne (handled, reply) pour gérer le self-upgrade agent1
  - !agentUPGRADE agent1 : envoie la réponse XMPP avant systemctl restart
  - !agentsUPGRADE : met à jour tous les agents puis agent1 en dernier
- agents_registry.json : ajout install_path, service_name, git_branch + entrée agent1
- README.md : documentation des nouvelles commandes
- TODO.md : tâches marquées comme terminées

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 15:55:31 +00:00
parent 1c951f46f1
commit 3575b391b6
5 changed files with 262 additions and 24 deletions
+124 -15
View File
@@ -137,10 +137,11 @@ def _get_all_agents() -> list:
return []
# ── COMMANDES !agent ──────────────────────────────────────────────────────
def _handle_agent_command(text: str) -> str | None:
def _handle_agent_command(text: str) -> tuple:
"""
Gère les commandes !agentON/OFF et !agentsON/OFF.
Retourne la réponse ou None si ce n'est pas une commande agent.
Gère toutes les commandes !agent*.
Retourne (handled: bool, reply: str|None).
reply=None signifie que la réponse XMPP a déjà été envoyée (ex: self-upgrade).
"""
global SLEEP_MODE
@@ -152,7 +153,7 @@ def _handle_agent_command(text: str) -> str | None:
for a in agents:
_send_control(a, "pause")
SLEEP_MODE = True
return "[VEILLE] Agent1 en veille. {} agent(s) mis en pause.\nEnvoyez !agentsON ou !agentON agent1 pour reprendre.".format(len(agents))
return True, "[VEILLE] Agent1 en veille. {} agent(s) mis en pause.\nEnvoyez !agentsON ou !agentON agent1 pour reprendre.".format(len(agents))
# !agentsON — sortie veille agent1 + resume tous les agents
if t == "!agentsON":
@@ -160,27 +161,134 @@ def _handle_agent_command(text: str) -> str | None:
for a in agents:
_send_control(a, "resume")
SLEEP_MODE = False
return "[ACTIF] Agent1 actif. {} agent(s) relancés.".format(len(agents))
return True, "[ACTIF] Agent1 actif. {} agent(s) relancés.".format(len(agents))
# !agentOFF <nom>
if t.startswith("!agentOFF "):
name = t[len("!agentOFF "):].strip()
if name == "agent1":
SLEEP_MODE = True
return "[VEILLE] Agent1 en veille. Envoyez !agentON agent1 pour reprendre."
return True, "[VEILLE] Agent1 en veille. Envoyez !agentON agent1 pour reprendre."
_send_control(name, "pause")
return "[PAUSE] Commande pause envoyée à {}.".format(name)
return True, "[PAUSE] Commande pause envoyée à {}.".format(name)
# !agentON <nom>
if t.startswith("!agentON "):
name = t[len("!agentON "):].strip()
if name == "agent1":
SLEEP_MODE = False
return "[ACTIF] Agent1 actif."
return True, "[ACTIF] Agent1 actif."
_send_control(name, "resume")
return "[ACTIF] Commande resume envoyée à {}.".format(name)
return True, "[ACTIF] Commande resume envoyée à {}.".format(name)
return None
# !agentsUPDATE — vérifier les mises à jour de tous les agents
if t == "!agentsUPDATE":
return True, _handle_update_all()
# !agentUPDATE <nom>
if t.startswith("!agentUPDATE "):
name = t[len("!agentUPDATE "):].strip()
return True, _handle_update_one(name)
# !agentsUPGRADE — mettre à jour tous les agents
if t == "!agentsUPGRADE":
return True, _handle_upgrade_all()
# !agentUPGRADE <nom>
if t.startswith("!agentUPGRADE "):
name = t[len("!agentUPGRADE "):].strip()
return True, _handle_upgrade_one(name)
return False, None
# ── MISE À JOUR DEPUIS GIT ───────────────────────────────────────────────
def _get_agent_git_info(name: str) -> dict | None:
"""Retourne {install_path, service_name, git_branch} depuis le registre, ou None."""
try:
registry = json.loads(REGISTRY_FILE.read_text(encoding="utf-8"))
agent = registry.get(name, {})
if "install_path" not in agent:
return None
return {
"install_path": agent["install_path"],
"service_name": agent.get("service_name", name),
"git_branch" : agent.get("git_branch", "main"),
}
except Exception:
return None
def _handle_update_one(name: str) -> str:
from skills.agent_update import check_update
info = _get_agent_git_info(name)
if not info:
return "[{}] Infos git absentes du registre (install_path manquant).".format(name)
return check_update(name, info["install_path"], info["git_branch"])
def _handle_update_all() -> str:
from skills.agent_update import check_update
try:
registry = json.loads(REGISTRY_FILE.read_text(encoding="utf-8"))
except Exception:
return "Erreur lecture registre."
results = []
for name, info in registry.items():
if "install_path" not in info:
continue
results.append(check_update(name, info["install_path"], info.get("git_branch", "main")))
return "\n\n".join(results) if results else "Aucun agent avec install_path dans le registre."
def _handle_upgrade_one(name: str) -> str:
from skills.agent_update import do_upgrade
info = _get_agent_git_info(name)
if not info:
return "[{}] Infos git absentes du registre.".format(name)
self_upgrade = (name == "agent1")
msg = do_upgrade(name, info["install_path"], info["service_name"],
info["git_branch"], self_upgrade=self_upgrade)
if self_upgrade and "Redémarrage en cours" in msg:
# Envoyer le message XMPP avant le restart
if xmpp_bot:
xmpp_bot.send_message(mto=ADMIN_JID, mbody=msg, mtype='chat')
import subprocess
subprocess.Popen(["systemctl", "restart", info["service_name"]])
return None # Réponse déjà envoyée manuellement
return msg
def _handle_upgrade_all() -> str:
from skills.agent_update import do_upgrade
try:
registry = json.loads(REGISTRY_FILE.read_text(encoding="utf-8"))
except Exception:
return "Erreur lecture registre."
results = []
agent1_info = None
for name, info in registry.items():
if "install_path" not in info:
continue
if name == "agent1":
agent1_info = (name, info) # traiter en dernier
continue
msg = do_upgrade(name, info["install_path"],
info.get("service_name", name), info.get("git_branch", "main"))
results.append(msg)
summary = "\n\n".join(results) if results else "Aucun agent mis à jour."
if agent1_info:
name, info = agent1_info
pull_msg = do_upgrade(name, info["install_path"],
info.get("service_name", "agent"), info.get("git_branch", "main"),
self_upgrade=True)
summary += "\n\n" + pull_msg
if xmpp_bot:
xmpp_bot.send_message(mto=ADMIN_JID, mbody=summary, mtype='chat')
import subprocess
subprocess.Popen(["systemctl", "restart", info.get("service_name", "agent")])
return None # Réponse déjà envoyée
return summary
# ── GESTION CONFIGS AVEC CONFIRMATION ────────────────────────────────────
def _handle_config_command(text: str) -> str | None:
@@ -495,11 +603,12 @@ class AgentBot(ClientXMPP):
user_input = msg['body'].strip()
# ── Commandes !agentON/OFF (prioritaires, toujours traitées) ──────
agent_reply = _handle_agent_command(user_input)
if agent_reply is not None:
self.send_message(mto=ADMIN_JID, mbody=agent_reply, mtype='chat')
return
# ── Commandes !agent* (prioritaires, toujours traitées) ──────────
handled, agent_reply = _handle_agent_command(user_input)
if handled:
if agent_reply is not None:
self.send_message(mto=ADMIN_JID, mbody=agent_reply, mtype='chat')
return # None = réponse déjà envoyée manuellement (ex: self-upgrade)
# ── Mode veille : ignorer tout sauf commandes agent ───────────────
if SLEEP_MODE: