Initial commit — nexus v2.0
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Skill DELEGATE — déléguer une tâche à un agent spécialisé via MQTT.
|
||||
|
||||
Usage LLM : SKILL:delegate ARGS:<agent_id> | <tâche>
|
||||
"""
|
||||
DESCRIPTION = "Déléguer une tâche à un agent spécialisé"
|
||||
USAGE = "SKILL:delegate ARGS:<agent_id> | <tâche>"
|
||||
|
||||
|
||||
def run(args: str, context) -> str:
|
||||
if "|" not in args:
|
||||
return "Format invalide. Usage : SKILL:delegate ARGS:<agent_id> | <tâche>"
|
||||
|
||||
agent_id, task = args.split("|", 1)
|
||||
agent_id = agent_id.strip()
|
||||
task = task.strip()
|
||||
|
||||
# Vérifier que l'agent est connu
|
||||
caps = context.registry.get(agent_id)
|
||||
if caps is None:
|
||||
known = [a.agent_id for a in context.registry.all_agents()]
|
||||
return f"Agent '{agent_id}' inconnu. Agents connus : {', '.join(known)}"
|
||||
|
||||
# Envoyer la tâche via MQTT
|
||||
sent = context.mqtt.send_to(
|
||||
recipient_id=agent_id,
|
||||
payload=task,
|
||||
reply_to=context.mqtt.topic_inbox(),
|
||||
)
|
||||
|
||||
return f"Tâche déléguée à {agent_id} (id={sent.correlation_id[:8]}). Attente de la réponse..."
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Skill MEMORY — mémorisation persistante clé/valeur (SQLite).
|
||||
|
||||
Usage LLM :
|
||||
SKILL:memory ARGS:set | <clé> | <valeur>
|
||||
SKILL:memory ARGS:get | <clé>
|
||||
SKILL:memory ARGS:list
|
||||
SKILL:memory ARGS:delete | <clé>
|
||||
"""
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
DESCRIPTION = "Mémorisation persistante d'informations clé/valeur"
|
||||
USAGE = "SKILL:memory ARGS:set|<clé>|<valeur> ou get|<clé> ou list"
|
||||
|
||||
DB_PATH = os.path.join(os.path.dirname(__file__), "..", "data", "memory.db")
|
||||
|
||||
|
||||
def _connect():
|
||||
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.execute("""
|
||||
CREATE TABLE IF NOT EXISTS memory (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL,
|
||||
updated_at TEXT DEFAULT (datetime('now'))
|
||||
)
|
||||
""")
|
||||
return conn
|
||||
|
||||
|
||||
def run(args: str, context) -> str:
|
||||
parts = [p.strip() for p in args.split("|")]
|
||||
action = parts[0].lower() if parts else ""
|
||||
|
||||
with _connect() as conn:
|
||||
if action == "set" and len(parts) >= 3:
|
||||
key, value = parts[1], "|".join(parts[2:])
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO memory (key, value, updated_at) VALUES (?, ?, datetime('now'))",
|
||||
(key, value)
|
||||
)
|
||||
return f"Mémorisé : {key} = {value}"
|
||||
|
||||
if action == "get" and len(parts) >= 2:
|
||||
row = conn.execute("SELECT value FROM memory WHERE key = ?", (parts[1],)).fetchone()
|
||||
return row[0] if row else f"Clé '{parts[1]}' introuvable."
|
||||
|
||||
if action == "list":
|
||||
rows = conn.execute("SELECT key, value FROM memory ORDER BY key").fetchall()
|
||||
if not rows:
|
||||
return "Mémoire vide."
|
||||
return "\n".join(f" {k}: {v}" for k, v in rows)
|
||||
|
||||
if action == "delete" and len(parts) >= 2:
|
||||
conn.execute("DELETE FROM memory WHERE key = ?", (parts[1],))
|
||||
return f"Clé '{parts[1]}' supprimée."
|
||||
|
||||
return "Usage : SKILL:memory ARGS:set|clé|valeur ou get|clé ou list ou delete|clé"
|
||||
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Skill MQTT_SEND — publier un message sur n'importe quel topic MQTT.
|
||||
|
||||
Permet au LLM (et à l'utilisateur) de publier librement sur le bus.
|
||||
|
||||
Usage LLM : SKILL:mqtt_send ARGS:<topic> | <message>
|
||||
"""
|
||||
DESCRIPTION = "Publier un message sur un topic MQTT arbitraire"
|
||||
USAGE = "SKILL:mqtt_send ARGS:<topic> | <message>"
|
||||
|
||||
|
||||
def run(args: str, context) -> str:
|
||||
if "|" not in args:
|
||||
return "Format invalide. Usage : SKILL:mqtt_send ARGS:<topic> | <message>"
|
||||
|
||||
topic, message = args.split("|", 1)
|
||||
topic = topic.strip()
|
||||
message = message.strip()
|
||||
|
||||
if not topic:
|
||||
return "Topic vide."
|
||||
|
||||
context.mqtt.publish_raw(topic, message)
|
||||
return f"Message publié sur '{topic}'."
|
||||
@@ -0,0 +1,27 @@
|
||||
"""
|
||||
Skill WEB_READ — lire le contenu d'une URL.
|
||||
|
||||
Usage LLM : SKILL:web_read ARGS:<url>
|
||||
"""
|
||||
DESCRIPTION = "Lire le contenu d'une page web"
|
||||
USAGE = "SKILL:web_read ARGS:<url>"
|
||||
|
||||
|
||||
def run(args: str, context) -> str:
|
||||
url = args.strip()
|
||||
if not url:
|
||||
return "URL vide."
|
||||
try:
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
resp = requests.get(url, timeout=15, headers={"User-Agent": "Mozilla/5.0"})
|
||||
resp.raise_for_status()
|
||||
soup = BeautifulSoup(resp.text, "html.parser")
|
||||
# Supprime scripts et styles
|
||||
for tag in soup(["script", "style", "nav", "footer"]):
|
||||
tag.decompose()
|
||||
text = soup.get_text(separator="\n", strip=True)
|
||||
# Tronqué à 3000 caractères
|
||||
return text[:3000] + ("..." if len(text) > 3000 else "")
|
||||
except Exception as e:
|
||||
return f"Erreur lecture URL : {e}"
|
||||
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Skill WEB_SEARCH — recherche DuckDuckGo.
|
||||
|
||||
Usage LLM : SKILL:web_search ARGS:<requête>
|
||||
"""
|
||||
DESCRIPTION = "Recherche web via DuckDuckGo"
|
||||
USAGE = "SKILL:web_search ARGS:<requête de recherche>"
|
||||
|
||||
|
||||
def run(args: str, context) -> str:
|
||||
query = args.strip()
|
||||
if not query:
|
||||
return "Requête vide."
|
||||
try:
|
||||
from duckduckgo_search import DDGS
|
||||
results = []
|
||||
with DDGS() as ddgs:
|
||||
for r in ddgs.text(query, max_results=5):
|
||||
results.append(f"- {r['title']}\n {r['href']}\n {r['body'][:200]}")
|
||||
return "\n\n".join(results) if results else "Aucun résultat."
|
||||
except ImportError:
|
||||
return "Module duckduckgo_search non installé (pip install duckduckgo-search)"
|
||||
except Exception as e:
|
||||
return f"Erreur recherche : {e}"
|
||||
Reference in New Issue
Block a user