Files
agent2/agent2.py
T
sylvain 47f88f7cde Initial commit : agent2 basé sur agent1
- agent2.py : bot XMPP agent2@xmpp.ovh
- skills/ : web_search, web_read, memory, prompt_memory (ChromaDB), mqtt
- Chemins mis à jour vers /opt/agent2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 11:10:47 +00:00

120 lines
4.4 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import asyncio
import sys
import requests
import json
from pathlib import Path
from slixmpp import ClientXMPP
# Ajouter /opt/agent2 au path pour importer les skills
sys.path.insert(0, "/opt/agent2")
from skills.loader import load_skills, run_skills
# ── CONFIG ───────────────────────────────────────────────────────────────
CONFIG_DIR = Path("/opt/agent2/config")
CONFIG_FILE = CONFIG_DIR / "config.json"
PROMPT_FILE = CONFIG_DIR / "system_prompt.txt"
def load_config():
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
return json.load(f)
def load_system_prompt():
with open(PROMPT_FILE, "r", encoding="utf-8") as f:
return f.read()
cfg = load_config()
OLLAMA_URL = cfg["ollama_url"]
MODEL = cfg["model"]
XMPP_JID = cfg["xmpp_jid"]
XMPP_PASS = cfg["xmpp_pass"]
ADMIN_JID = cfg["admin_jid"]
SYSTEM_PROMPT = load_system_prompt()
# Charger les skills au démarrage
load_skills()
conversation_history = []
# ── LLM ──────────────────────────────────────────────────────────────────
def call_ollama(messages: list) -> str:
payload = {
"model" : MODEL,
"messages": messages,
"stream" : False,
"options" : {"temperature": 0.3}
}
response = requests.post(OLLAMA_URL, json=payload, timeout=180)
data = response.json()
return data["message"]["content"]
def ask_llm(user_message: str) -> str:
conversation_history.append({"role": "user", "content": user_message})
messages = [{"role": "system", "content": SYSTEM_PROMPT}] + conversation_history
try:
# Boucle agentique : le LLM peut enchaîner plusieurs skills
MAX_STEPS = 5
for _ in range(MAX_STEPS):
reply = call_ollama(messages)
skill_triggered, result = run_skills(reply)
if not skill_triggered:
# Réponse finale sans commande
conversation_history.append({"role": "assistant", "content": reply})
return reply
# Injecter le résultat du skill et relancer le LLM
messages.append({"role": "assistant", "content": reply})
messages.append({"role": "user", "content": "[Résultat skill]\n" + result})
# Sécurité : trop d'étapes
reply = call_ollama(messages)
conversation_history.append({"role": "assistant", "content": reply})
return reply
except Exception as e:
error_reply = "Erreur : " + str(e)
conversation_history.append({"role": "assistant", "content": error_reply})
return error_reply
# ── BOT XMPP ─────────────────────────────────────────────────────────────
class AgentBot(ClientXMPP):
def __init__(self):
ClientXMPP.__init__(self, XMPP_JID, XMPP_PASS)
self.add_event_handler("session_start", self.session_start)
self.add_event_handler("message", self.message)
self.register_plugin('xep_0030')
self.register_plugin('xep_0199')
async def session_start(self, event):
self.send_presence()
await self.get_roster()
self.send_message(mto=ADMIN_JID, mbody="Agent en ligne !", mtype='chat')
async def message(self, msg):
if msg['type'] not in ('chat', 'normal'):
return
if str(msg['from']).split('/')[0] != ADMIN_JID:
return
user_input = msg['body'].strip()
if user_input == "!reset":
conversation_history.clear()
self.send_message(mto=ADMIN_JID, mbody="Conversation reinitialisee.", mtype='chat')
return
loop = asyncio.get_event_loop()
reply = await loop.run_in_executor(None, ask_llm, user_input)
self.send_message(mto=ADMIN_JID, mbody=reply, mtype='chat')
# ── MAIN ─────────────────────────────────────────────────────────────────
if __name__ == "__main__":
bot = AgentBot()
bot.connect()
bot.loop.run_forever()