From 576caa26214b828daf192e67620daef8a407527a Mon Sep 17 00:00:00 2001 From: sylvain Date: Sat, 7 Mar 2026 21:24:25 +0000 Subject: [PATCH] =?UTF-8?q?Suivi=20temps=20r=C3=A9el=20des=20agents=20:=20?= =?UTF-8?q?MQTT=20status/retain=20+=20injection=20dynamique=20dans=20le=20?= =?UTF-8?q?prompt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - on_mqtt_status : dict AGENTS_ONLINE + agents_online.json + notif XMPP si changement - _get_agents_context() : liste agents avec statut [EN LIGNE/hors ligne] à chaque LLM call - system_prompt : retrait liste hardcodée, agents injectés dynamiquement Co-Authored-By: Claude Sonnet 4.6 --- agent1.py | 56 +++++++++++++++++++++++++++++++++++++--- config/system_prompt.txt | 14 +++++----- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/agent1.py b/agent1.py index 831b80c..0b1edeb 100644 --- a/agent1.py +++ b/agent1.py @@ -40,7 +40,26 @@ SYSTEM_PROMPT = load_system_prompt() load_skills() conversation_history = [] -xmpp_bot = None # référence globale pour répondre via XMPP depuis MQTT +xmpp_bot = None # référence globale pour répondre via XMPP depuis MQTT +AGENTS_ONLINE = {} # {agent_name: {status, jid, mqtt_inbox, last_seen}} + +REGISTRY_FILE = CONFIG_DIR / "agents_registry.json" +AGENTS_ONLINE_FILE = CONFIG_DIR / "agents_online.json" + +def _get_agents_context() -> str: + """Construit dynamiquement la liste des agents (registre + statut en ligne).""" + try: + registry = json.loads(REGISTRY_FILE.read_text(encoding="utf-8")) + except Exception: + registry = {} + if not registry: + return "Aucun agent enregistré." + lines = ["Agents disponibles :"] + for name, info in registry.items(): + online = name in AGENTS_ONLINE and AGENTS_ONLINE[name].get("status") == "online" + status = "[EN LIGNE]" if online else "[hors ligne]" + lines.append("- {} {} : {}".format(name, status, info.get("speciality", ""))) + return "\n".join(lines) # ── LLM ────────────────────────────────────────────────────────────────── def call_ollama(messages: list) -> str: @@ -57,7 +76,8 @@ def ask_llm(user_message: str, history: list = None) -> str: if history is None: history = conversation_history history.append({"role": "user", "content": user_message}) - messages = [{"role": "system", "content": SYSTEM_PROMPT}] + history + full_prompt = SYSTEM_PROMPT + "\n\n" + _get_agents_context() + messages = [{"role": "system", "content": full_prompt}] + history try: MAX_STEPS = 10 for _ in range(MAX_STEPS): @@ -133,6 +153,34 @@ def on_mqtt_notification(client, userdata, msg): except Exception as e: print("[MQTT] Erreur parsing notification scheduler : {}".format(e)) +def on_mqtt_status(client, userdata, msg): + """Suit le statut en ligne/hors-ligne des agents (LWT + retain).""" + import time + try: + data = json.loads(msg.payload.decode(errors="replace")) + agent = data.get("agent", "?") + status = data.get("status", "?") + + was_online = AGENTS_ONLINE.get(agent, {}).get("status") == "online" + AGENTS_ONLINE[agent] = {**data, "last_seen": time.time()} + + # Sauvegarder pour la skill agents_online + AGENTS_ONLINE_FILE.write_text( + json.dumps(AGENTS_ONLINE, indent=2, ensure_ascii=False), encoding="utf-8") + + # Notifier sylvain uniquement si le statut change + is_online = status == "online" + if is_online == was_online: + return + emoji = "[EN LIGNE]" if is_online else "[HORS LIGNE]" + print("[STATUS] {} → {}".format(agent, status)) + if xmpp_bot: + xmpp_bot.send_message(mto=ADMIN_JID, + mbody="{} {}".format(emoji, agent), + mtype='chat') + except Exception as e: + print("[MQTT] Erreur parsing status : {}".format(e)) + def on_mqtt_register(client, userdata, msg): """Reçoit les déclarations de mise en ligne des agents et met à jour le registre.""" try: @@ -183,6 +231,7 @@ def start_mqtt_listener(): sub.message_callback_add("agents/errors", on_mqtt_error) sub.message_callback_add("agents/scheduler/notifications", on_mqtt_notification) sub.message_callback_add("agents/register", on_mqtt_register) + sub.message_callback_add("agents/status/+", on_mqtt_status) sub.on_message = on_mqtt_message # fallback sub.connect(MQTT_HOST, MQTT_PORT) sub.subscribe([ @@ -190,8 +239,9 @@ def start_mqtt_listener(): ("agents/errors", 0), ("agents/scheduler/notifications", 0), ("agents/register", 0), + ("agents/status/+", 0), ]) - print("[MQTT] Agent1 écoute sur {}, agents/errors, agents/scheduler/notifications, agents/register".format(MQTT_INBOX)) + print("[MQTT] Agent1 écoute sur {}, agents/errors, agents/status/+, agents/register".format(MQTT_INBOX)) sub.loop_forever() # ── BOT XMPP ───────────────────────────────────────────────────────────── diff --git a/config/system_prompt.txt b/config/system_prompt.txt index 5349511..869bc77 100644 --- a/config/system_prompt.txt +++ b/config/system_prompt.txt @@ -2,24 +2,23 @@ Tu es agent1, chef d'orchestre d'un réseau d'agents autonomes spécialisés. Tu reçois les instructions de sylvain (via XMPP ou CLI) et tu décides de les traiter toi-même ou de les déléguer. Les agents ne peuvent pas travailler en parallèle : tu exécutes les tâches séquentiellement. -Agents disponibles sous tes ordres : - -- agent2_debian13 : Administration Debian (apt, systemd, conteneurs LXC/Docker, KVM, réseau, sécurité, exécution de commandes système) +La liste des agents disponibles et leur statut (EN LIGNE / hors ligne) est injectée dynamiquement +à la suite de ce prompt. Utilise ces informations pour choisir quel agent solliciter. Commandes disponibles : DELEGATE: | → Déléguer une tâche unique à un agent spécialisé - → Exemple : DELEGATE: agent2_debian13 | Vérifie l'espace disque + → Exemple : DELEGATE: trouducul | Vérifie l'espace disque PLAN: | ;; | ;; ... → Exécuter un plan de tâches séquentiel (le résultat de chaque étape est transmis à la suivante) - → Exemple : PLAN: agent2_debian13 | apt update ;; agent2_debian13 | apt upgrade -y + → Exemple : PLAN: trouducul | apt update ;; trouducul | apt upgrade -y SCHEDULE: | | → Planifier une tâche récurrente → Fréquences : daily HH:MM | every Xh | every Xmin | weekly HH:MM - → Exemple : SCHEDULE: daily 03:00 | agent2_debian13 | apt update && apt upgrade -y + → Exemple : SCHEDULE: daily 03:00 | trouducul | apt update && apt upgrade -y PLAN_LIST: → Afficher toutes les tâches planifiées @@ -49,7 +48,8 @@ RECALL: → Récupérer une information mémorisée ⚠ RÈGLES : -- Tâche Debian/système → DELEGATE: agent2_debian13 (ou PLAN: pour plusieurs étapes) +- Utilise le nom exact de l'agent tel qu'il apparaît dans la liste ci-dessous pour DELEGATE +- Délègue uniquement à un agent [EN LIGNE] — si l'agent est hors ligne, informe sylvain - Tâche récurrente → SCHEDULE: - Actualité/info récente → SEARCH: - Un seul agent à la fois (pas de parallélisme)