File d'attente SQLite FIFO + pause/resume + rapport journalier
- task_queue.py : module FIFO persistant (queue.db), QoS 1 - agent2_ansible.py : intégration queue, topic agents/agent2_ansible/control commandes : pause / resume / report (stats envoyées sur agents/daily_report) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+67
-26
@@ -7,17 +7,20 @@ import threading
|
||||
import requests
|
||||
import json
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from slixmpp import ClientXMPP
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
BASE_DIR = Path(__file__).parent.resolve()
|
||||
sys.path.insert(0, str(BASE_DIR))
|
||||
from skills.loader import load_skills, run_skills
|
||||
from task_queue import TaskQueue
|
||||
|
||||
# ── CONFIG ───────────────────────────────────────────────────────────────
|
||||
CONFIG_DIR = BASE_DIR / "config"
|
||||
CONFIG_FILE = CONFIG_DIR / "config.json"
|
||||
PROMPT_FILE = CONFIG_DIR / "system_prompt.txt"
|
||||
QUEUE_DB = BASE_DIR / "queue.db"
|
||||
|
||||
def load_config():
|
||||
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
|
||||
@@ -43,6 +46,7 @@ SYSTEM_PROMPT = load_system_prompt()
|
||||
load_skills()
|
||||
|
||||
conversation_history = []
|
||||
start_time = datetime.now()
|
||||
|
||||
# ── LLM ──────────────────────────────────────────────────────────────────
|
||||
def call_ollama(messages: list) -> str:
|
||||
@@ -78,18 +82,57 @@ def ask_llm(user_message: str, history: list = None) -> str:
|
||||
history.append({"role": "assistant", "content": err})
|
||||
return err
|
||||
|
||||
# ── MQTT LISTENER ─────────────────────────────────────────────────────────
|
||||
# ── MQTT ──────────────────────────────────────────────────────────────────
|
||||
mqtt_publish_client = None
|
||||
task_queue: TaskQueue = None
|
||||
|
||||
def mqtt_publish(topic: str, message: str):
|
||||
global mqtt_publish_client
|
||||
if mqtt_publish_client:
|
||||
mqtt_publish_client.publish(topic, message)
|
||||
|
||||
def _process_task(task: str) -> str:
|
||||
"""Worker appelé par la TaskQueue pour chaque tâche."""
|
||||
mqtt_history = []
|
||||
return ask_llm(task, history=mqtt_history)
|
||||
|
||||
def on_mqtt_message(client, userdata, msg):
|
||||
"""Enqueue la tâche — le worker la traitera en FIFO."""
|
||||
task = msg.payload.decode(errors="replace")
|
||||
print(f"[MQTT] Tâche reçue, mise en queue : {task[:100]}")
|
||||
task_queue.enqueue(task)
|
||||
|
||||
def on_control_message(client, userdata, msg):
|
||||
"""Gère les commandes de contrôle : pause / resume / report."""
|
||||
try:
|
||||
data = json.loads(msg.payload.decode(errors="replace"))
|
||||
command = data.get("command", "")
|
||||
print(f"[CONTROL] Commande reçue : {command}")
|
||||
|
||||
if command == "pause":
|
||||
task_queue.pause()
|
||||
|
||||
elif command == "resume":
|
||||
task_queue.resume()
|
||||
|
||||
elif command == "report":
|
||||
stats = task_queue.get_stats()
|
||||
uptime_s = int((datetime.now() - start_time).total_seconds())
|
||||
payload = json.dumps({
|
||||
"agent" : MQTT_CLIENT,
|
||||
"timestamp" : datetime.now().isoformat(timespec='seconds'),
|
||||
"uptime_s" : uptime_s,
|
||||
"paused" : task_queue.paused,
|
||||
**stats
|
||||
}, ensure_ascii=False)
|
||||
mqtt_publish("agents/daily_report", payload)
|
||||
print(f"[CONTROL] Rapport envoyé sur agents/daily_report")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[CONTROL] Erreur : {e}")
|
||||
|
||||
def register_to_agent1():
|
||||
"""Publie une déclaration de mise en ligne sur agents/register."""
|
||||
import json as _json
|
||||
payload = _json.dumps({
|
||||
payload = json.dumps({
|
||||
"agent" : MQTT_CLIENT,
|
||||
"jid" : XMPP_JID,
|
||||
"mqtt_inbox": MQTT_INBOX,
|
||||
@@ -98,23 +141,12 @@ def register_to_agent1():
|
||||
mqtt_publish("agents/register", payload)
|
||||
print("[REGISTER] Déclaration envoyée à agent1.")
|
||||
|
||||
def on_mqtt_message(client, userdata, msg):
|
||||
task = msg.payload.decode(errors="replace")
|
||||
print(f"[MQTT] Tâche reçue d'agent1 : {task[:100]}")
|
||||
# Historique isolé par tâche MQTT (pas mélangé avec XMPP)
|
||||
mqtt_history = []
|
||||
reply = ask_llm(task, history=mqtt_history)
|
||||
print(f"[MQTT] Réponse envoyée : {reply[:100]}")
|
||||
mqtt_publish(MQTT_OUTBOX, reply)
|
||||
|
||||
def start_mqtt_listener():
|
||||
global mqtt_publish_client
|
||||
global mqtt_publish_client, task_queue
|
||||
|
||||
# Client dédié à la publication
|
||||
import json as _json
|
||||
_status_topic = "agents/status/{}".format(MQTT_CLIENT)
|
||||
_offline_payload = _json.dumps({"status": "offline", "agent": MQTT_CLIENT})
|
||||
_online_payload = _json.dumps({
|
||||
_status_topic = "agents/status/{}".format(MQTT_CLIENT)
|
||||
_offline_payload = json.dumps({"status": "offline", "agent": MQTT_CLIENT})
|
||||
_online_payload = json.dumps({
|
||||
"status" : "online",
|
||||
"agent" : MQTT_CLIENT,
|
||||
"jid" : XMPP_JID,
|
||||
@@ -122,20 +154,31 @@ def start_mqtt_listener():
|
||||
})
|
||||
|
||||
mqtt_publish_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
|
||||
client_id=MQTT_CLIENT + "_pub")
|
||||
client_id=MQTT_CLIENT + "_pub",
|
||||
clean_session=False)
|
||||
mqtt_publish_client.will_set(_status_topic, _offline_payload, retain=True)
|
||||
mqtt_publish_client.connect(MQTT_HOST, MQTT_PORT)
|
||||
mqtt_publish_client.loop_start()
|
||||
mqtt_publish_client.publish(_status_topic, _online_payload, retain=True)
|
||||
register_to_agent1()
|
||||
|
||||
# Client dédié à la souscription
|
||||
# Initialiser et démarrer la queue
|
||||
task_queue = TaskQueue(QUEUE_DB, _process_task, mqtt_publish, MQTT_OUTBOX)
|
||||
task_queue.start_worker()
|
||||
|
||||
# Client souscription (QoS 1 + session persistante)
|
||||
sub_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
|
||||
client_id=MQTT_CLIENT + "_sub")
|
||||
client_id=MQTT_CLIENT + "_sub",
|
||||
clean_session=False)
|
||||
sub_client.message_callback_add("agents/{}/control".format(MQTT_CLIENT),
|
||||
on_control_message)
|
||||
sub_client.on_message = on_mqtt_message
|
||||
sub_client.connect(MQTT_HOST, MQTT_PORT)
|
||||
sub_client.subscribe(MQTT_INBOX)
|
||||
print(f"[MQTT] Écoute sur {MQTT_INBOX}")
|
||||
sub_client.subscribe([
|
||||
(MQTT_INBOX, 1),
|
||||
("agents/{}/control".format(MQTT_CLIENT), 1),
|
||||
])
|
||||
print(f"[MQTT] Écoute sur {MQTT_INBOX} + agents/{MQTT_CLIENT}/control")
|
||||
sub_client.loop_forever()
|
||||
|
||||
# ── BOT XMPP ─────────────────────────────────────────────────────────────
|
||||
@@ -175,11 +218,9 @@ class AgentBot(ClientXMPP):
|
||||
|
||||
# ── MAIN ─────────────────────────────────────────────────────────────────
|
||||
if __name__ == "__main__":
|
||||
# Lancer le listener MQTT dans un thread séparé
|
||||
mqtt_thread = threading.Thread(target=start_mqtt_listener, daemon=True)
|
||||
mqtt_thread.start()
|
||||
|
||||
# Lancer le bot XMPP
|
||||
bot = AgentBot()
|
||||
bot.connect()
|
||||
bot.loop.run_forever()
|
||||
|
||||
Reference in New Issue
Block a user