# agents_core Bibliothèque partagée pour le système multi-agents. Fournit toutes les briques communes : communication MQTT/XMPP (avec chiffrement OMEMO), LLM, coordination des appels Ollama, gestion des tâches, chargement des skills, et découverte des capacités entre agents. ## Installation ```bash pip install -e /opt/agents_core ``` ## Architecture ``` XMPP (slixmpp + OMEMO) MQTT (Mosquitto local) utilisateur ←→ nexus ←→ agents/nexus/inbox ←→ agents/+/status (retained) ←→ agents/+/capabilities (retained) ←→ agents/broadcast ←→ agents/llm/switch (retained) ←→ agents/llm/request (coordinateur) ←→ agents/llm/release (coordinateur) ←→ agents/scripts/execution ``` ## Modules | Fichier | Rôle | |---------|------| | `base_agent.py` | Classe abstraite `BaseAgent` — à hériter dans chaque agent | | `mqtt_client.py` | Client MQTT (paho), reconnexion auto, publish/subscribe/unsubscribe/reply | | `xmpp_client.py` | Client XMPP (slixmpp 1.13), reconnexion auto, MUC, OMEMO E2E, thread-safe | | `omemo_storage.py` | Backend SQLite pour les clés/sessions OMEMO (XEP-0384, BTBV) | | `llm_client.py` | Wrapper Ollama — chat, historique, extraction de skill calls | | `llm_coordinator.py` | Coordinateur MQTT — limite les appels Ollama simultanés (sémaphore) | | `message_bus.py` | Enveloppe `Message` standard (type, payload, sender, reply_to…) | | `skill_loader.py` | Auto-découverte et exécution des plugins `.py` dans `skills/` | | `task_queue.py` | Queue SQLite FIFO avec worker thread | | `capabilities.py` | `AgentCapabilities` + `CapabilitiesRegistry` — annuaire des agents | | `command_parser.py` | Parse `/cmd`, `@agent msg`, langage naturel | ## Créer un agent ```python from agents_core import BaseAgent, AgentContext class MonAgent(BaseAgent): AGENT_TYPE = "mon_type" DESCRIPTION = "Description courte utilisée pour le routage LLM" DEFAULT_CONFIG_PATH = "/opt/mon_agent/config/config.json" def get_skills_dir(self) -> str: return "/opt/mon_agent/skills" def on_start(self): self.mqtt.send_to("nexus", f"{self.agent_id} en ligne.") if __name__ == "__main__": MonAgent().run() ``` ## Format config.json ```json { "agent_id": "mon_agent", "xmpp": { "jid": "mon_agent@xmpp.ovh", "password": "...", "admin_jid": "sylvain@xmpp.ovh", "muc_room": "agents@muc.xmpp.ovh" }, "mqtt": { "host": "localhost", "port": 1883 }, "llm": { "base_url": "http://192.168.7.119:11434", "model": "qwen3:8b", "temperature": 0.3 }, "llm_profiles": { "local": "qwen3:8b", "cloud": "gpt-oss:120b-cloud" }, "queue_db": "/opt/mon_agent/data/queue.db", "use_omemo": true, "use_llm_coordinator": true } ``` ## Créer un skill Un skill est un fichier `.py` dans le dossier `skills/` de l'agent : ```python # skills/mon_skill.py NAME = "mon_skill" DESCRIPTION = "Fait quelque chose d'utile. Args: " def run(args: str, context) -> str: # context.agent, context.mqtt, context.xmpp, context.llm, context.config return f"Résultat pour : {args}" ``` Le LLM appelle le skill avec : `SKILL:mon_skill ARGS:paramètre` ## Hooks disponibles dans BaseAgent | Méthode | Déclencheur | |---------|-------------| | `on_start()` | Au démarrage, après connexion MQTT | | `on_xmpp_connected()` | Quand la connexion XMPP est établie | | `on_agent_status_change(agent_id, status)` | Quand un agent passe online/offline | | `on_broadcast(msg)` | Réception d'un message broadcast MQTT | | `handle_custom_command(cmd, args, msg)` | Commande `/xxx` non gérée par BaseAgent | | `setup_extra_subscriptions()` | Pour ajouter des souscriptions MQTT custom | ## Commandes système intégrées (BaseAgent) Toutes les commandes suivantes sont disponibles sur chaque agent : ``` /status — État de la queue de tâches /pause — Pause du traitement /resume — Reprise /report — Rapport de l'agent /update — Git pull + redémarrage du service /script — Gestion de la bibliothèque de scripts bash 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 | |-------|-------| | `agents/{id}/inbox` | Tâches entrantes | | `agents/{id}/status` | Statut online/offline (retained + LWT) | | `agents/{id}/capabilities` | Skills déclarés (retained) | | `agents/broadcast` | Message à tous les agents | | `agents/llm/switch` | Changement de modèle LLM global (retained) | | `agents/llm/request` | Demande de slot LLM (coordinateur) | | `agents/llm/release` | Libération de slot LLM (coordinateur) | | `agents/{id}/llm/grant/{uuid}` | Accord de slot LLM | | `agents/scripts/execution` | Notification d'exécution de script | ## Coordinateur LLM Pour éviter de surcharger Ollama, un sémaphore MQTT limite les appels concurrents : - Nexus instancie `LLMCoordinator(max_concurrent=1)` - Chaque agent publie sur `agents/llm/request` avant d'appeler le LLM - Il attend le grant sur `agents/{id}/llm/grant/{uuid}` (timeout 90s) - Il publie sur `agents/llm/release` après ## Dépendances - Python ≥ 3.10 - paho-mqtt ≥ 1.6 - slixmpp ≥ 1.13 - slixmpp-omemo ≥ 2.1.0 - requests ≥ 2.28