diff --git a/ansible/roles/litellm/files/ask-agent b/ansible/roles/litellm/files/ask-agent index 8f68781..4e23b12 100644 --- a/ansible/roles/litellm/files/ask-agent +++ b/ansible/roles/litellm/files/ask-agent @@ -33,6 +33,13 @@ AGENT="$1" QUESTION="$2" shift 2 +# Qwen3 thinking mode : les agents rapides (system/monitor) doivent répondre +# directement sans passer du temps en raisonnement interne. +# /no_think désactive le mode thinking pour system et monitor. +case "$AGENT" in + system|monitor) QUESTION="/no_think ${QUESTION}" ;; +esac + while [ $# -gt 0 ]; do case "$1" in --max-tokens) MAX_TOKENS="$2"; shift 2 ;; diff --git a/hermes-skills/funk/agent-delegation/SKILL.md b/hermes-skills/funk/agent-delegation/SKILL.md index 039f1d2..3f67635 100644 --- a/hermes-skills/funk/agent-delegation/SKILL.md +++ b/hermes-skills/funk/agent-delegation/SKILL.md @@ -1,7 +1,7 @@ --- name: agent-delegation -description: "Délègue des sous-tâches aux agents spécialisés du cluster Funk. Utilise system/monitor pour les tâches rapides et légères, brain pour l'analyse complexe." -version: 1.0.0 +description: "Délègue des sous-tâches aux agents spécialisés du cluster Funk via ask-agent. OBLIGATOIRE pour toute analyse de logs, métriques ou monitoring système." +version: 1.1.0 author: Funk Lab license: MIT platforms: [linux] @@ -12,73 +12,88 @@ metadata: # Délégation inter-agents — Cluster Funk -**Contexte important** : Tu tournes EN LOCAL sur `storage-01`. Ne jamais SSH vers `storage-01` depuis toi-même — lance les commandes directement via le terminal. `systemctl`, `journalctl`, `cat /proc/mdstat`, etc. s'exécutent localement sans SSH. +## Contexte critique -Le cluster Funk dispose de 4 agents avec des capacités différentes. Utilise la commande shell `ask-agent` (disponible dans `/usr/local/bin/`) pour déléguer des sous-tâches aux agents spécialisés. +Tu tournes **EN LOCAL sur `storage-01`**. Ne jamais SSH vers `storage-01` depuis toi-même — toutes les commandes locales (systemctl, journalctl, cat /proc/mdstat, etc.) s'exécutent directement via Terminal sans SSH. + +## Règle de délégation OBLIGATOIRE + +**Tu DOIS utiliser `ask-agent` via Terminal dans ces situations :** + +| Situation | Agent à utiliser | +|---|---| +| Analyser des logs système ou service | `monitor` | +| Évaluer l'état de santé de services | `monitor` | +| Résumer des métriques, sorties de commandes | `system` | +| Toute question de formatage ou calcul simple | `system` | +| Architecture, revue de code, raisonnement complexe | `brain` | + +**Ne réponds JAMAIS directement à une demande d'analyse** — collecte d'abord les données, puis délègue. + +## Syntaxe exacte + +`ask-agent` est une commande shell. Elle s'exécute toujours via l'outil `terminal` : + +``` +terminal: ask-agent system "ta question courte" +terminal: ask-agent monitor "analyse ces données : " +terminal: ask-agent brain "raisonnement complexe : " +``` + +**Ne jamais appeler `ask-agent` sans passer par le terminal.** `ask-agent` n'est pas un outil Hermes natif, c'est un binaire shell dans `/usr/local/bin/ask-agent`. ## Agents disponibles -| Agent | Modèle | Vitesse | Coût | Usage idéal | -|---|---|---|---|---| -| `system` | Qwen3-1.7B CPU (port 1236) | ~21 tok/s | Gratuit | Calculs rapides, parsing, formatage, résumés courts | -| `monitor` | Qwen3-1.7B CPU (port 1237) | ~21 tok/s | Gratuit | Analyse métriques, logs, santé système, alertes | -| `brain` | Claude Sonnet 4.6 (API) | Variable | Payant | Raisonnement complexe, architecture, revue de code | -| `funk-ai` | Qwen3-8B GPU (port 1234) | ~35 tok/s | Gratuit | Tâches générales (toi-même) | +| Agent | Modèle | Port | Usage | +|---|---|---|---| +| `system` | Qwen3-1.7B CPU | :1236 | Calculs, formatage, résumés courts, questions Linux | +| `monitor` | Qwen3-1.7B CPU | :1237 | Analyse logs, métriques, santé système, alertes | +| `brain` | Claude Sonnet 4.6 API | - | Raisonnement complexe, architecture, revue critique | +| `funk-ai` | Qwen3-8B GPU | :1234 | Tâches générales (toi-même — rarement utile) | -## Règle fondamentale - -**`ask-agent` est une commande shell.** Pour déléguer, utilise l'outil Terminal avec exactement cette syntaxe : - -``` -Terminal: ask-agent system "ta question" -Terminal: ask-agent monitor "ta question" -Terminal: ask-agent brain "ta question" -``` - -Ne jamais SSH vers storage-01 pour des commandes locales. Utilise `Terminal` directement. - -## Pattern type : collecter + déléguer +## Pattern OBLIGATOIRE : collecter → déléguer ```bash -# 1. Collecter les données localement (PAS via SSH) -Terminal: systemctl --state=failed --no-pager +# ÉTAPE 1 — Collecter les données localement (Terminal direct, PAS via SSH) +terminal: systemctl --state=failed --no-pager -# 2. Passer le résultat à un agent pour analyse -Terminal: ask-agent monitor "voici les services en erreur systemd : — résume les problèmes" +# ÉTAPE 2 — Déléguer l'analyse à l'agent approprié +terminal: ask-agent monitor "voici les services en erreur : — identifie les causes et priorités" ``` -## Utilisation +## Exemples concrets ```bash -# Services en erreur sur storage-01 (LOCAL, pas SSH) -Terminal: systemctl --state=failed --no-pager -Terminal: ask-agent monitor "analyse ces services en erreur : " +# Monitoring services +terminal: systemctl --state=failed --no-pager +terminal: ask-agent monitor "services systemd en erreur : — résume en 3 points" -# Déléguer une analyse de logs -Terminal: journalctl -u hermes-agent -n 20 --no-pager -Terminal: ask-agent system "résume ces logs en 3 points : " +# Analyse logs hermes +terminal: journalctl -u hermes-agent -n 30 --no-pager +terminal: ask-agent monitor "analyse ces logs hermes-agent : — y a-t-il des erreurs ?" -# Question simple rapide -Terminal: ask-agent system "quelle commande pour vider le cache DNS sous AlmaLinux ?" +# Espace disque +terminal: df -h /srv/data +terminal: ask-agent system "est-ce que cette utilisation disque est critique : " -# Analyse complexe -Terminal: ask-agent brain "explique pourquoi ce log Kubernetes indique un crash : " +# Question Linux simple +terminal: ask-agent system "quelle commande pour lister les connexions TCP actives sur AlmaLinux ?" -# Avec prompt système -Terminal: ask-agent system "état du RAID normal ?" --system "Tu es expert Linux AlmaLinux, réponds en 1 phrase." +# Analyse complexe k8s +terminal: kubectl get nodes +terminal: ask-agent brain "un nœud k8s est NotReady, que vérifier en priorité : " ``` -## Quand déléguer à quel agent +## Différence avec delegate_task -| Situation | Agent | -|---|---| -| Question Linux simple, formatage, résumé court | `system` | -| Analyse logs, métriques, santé système | `monitor` | -| Raisonnement complexe, revue critique, architecture | `brain` | +- **`ask-agent`** : appel direct LiteLLM, réponse immédiate, pas besoin de gateway Hermes actif → pour analyses rapides et questions ponctuelles +- **`delegate_task`** : spawn d'un agent Hermes complet avec sessions, mémoire, tools → pour tâches longues multi-étapes + +Pour le monitoring et les analyses système, **toujours utiliser `ask-agent`**. ## Notes techniques -- `ask-agent` appelle LiteLLM sur `http://127.0.0.1:4000/v1` avec la clé `lm-studio` +- `ask-agent` appelle `http://127.0.0.1:4000/v1/chat/completions` via LiteLLM - Timeout : 120s -- Les agents `system` et `monitor` tournent sur des CPUs isolés (14 threads chacun) — ils ne bloquent pas le GPU -- `brain` consomme des tokens API Anthropic — réserver aux cas qui le justifient +- `system` et `monitor` tournent sur CPUs isolés — ils ne bloquent pas le GPU +- `brain` consomme des tokens API Anthropic — réserver aux cas complexes diff --git a/hermes-skills/funk/agent-delegation/test.sh b/hermes-skills/funk/agent-delegation/test.sh new file mode 100755 index 0000000..60bb37e --- /dev/null +++ b/hermes-skills/funk/agent-delegation/test.sh @@ -0,0 +1,169 @@ +#!/usr/bin/env bash +# test.sh — Validation end-to-end du skill agent-delegation et de ask-agent +# +# Usage : bash test.sh +# Doit tourner sur storage-01 (ou depuis le poste perso via SSH) +# +# Vérifie : +# 1. ask-agent CLI disponible et fonctionnel (system, monitor, brain) +# 2. Skill agent-delegation présent dans le profil funk-ai +# 3. Hermes funk-ai appelle réellement Terminal: ask-agent quand demandé + +set -uo pipefail + +PASS=0 +FAIL=0 +SKIP=0 + +green() { echo -e "\033[32m✓ $*\033[0m"; } +red() { echo -e "\033[31m✗ $*\033[0m"; } +yellow(){ echo -e "\033[33m~ $*\033[0m"; } + +pass() { green "$1"; ((PASS++)); } +fail() { red "$1"; ((FAIL++)); } +skip() { yellow "$1 (SKIP)"; ((SKIP++)); } + +echo "" +echo "═══════════════════════════════════════════════════════" +echo " Test agent-delegation + ask-agent — Funk Cluster" +echo "═══════════════════════════════════════════════════════" +echo "" + +# ── Test 1 : ask-agent disponible ──────────────────────────────────────────── +echo "▸ [1] ask-agent CLI disponible sur storage-01" +if command -v ask-agent &>/dev/null; then + pass "ask-agent trouvé : $(which ask-agent)" +else + fail "ask-agent introuvable dans PATH" +fi + +# ── Test 2 : LiteLLM accessible ────────────────────────────────────────────── +echo "▸ [2] LiteLLM proxy accessible (127.0.0.1:4000)" +if curl -sf -o /dev/null http://127.0.0.1:4000/health -H "Authorization: Bearer lm-studio"; then + pass "LiteLLM répond" +else + fail "LiteLLM inaccessible — vérifier : sudo systemctl status litellm" +fi + +# ── Test 3 : ask-agent system ───────────────────────────────────────────────── +echo "▸ [3] ask-agent system — réponse non vide" +RESP=$(ask-agent system "Réponds juste: OK" --max-tokens 200 2>&1) || true +if [ -n "$RESP" ] && echo "$RESP" | grep -qiv "error\|failed\|curl"; then + pass "ask-agent system répond : ${RESP:0:80}..." +else + fail "ask-agent system a échoué : $RESP" +fi + +# ── Test 4 : ask-agent monitor ──────────────────────────────────────────────── +echo "▸ [4] ask-agent monitor — réponse non vide" +RESP=$(ask-agent monitor "Réponds juste: OK" --max-tokens 200 2>&1) || true +if [ -n "$RESP" ] && echo "$RESP" | grep -qiv "error\|failed\|curl"; then + pass "ask-agent monitor répond : ${RESP:0:80}..." +else + fail "ask-agent monitor a échoué : $RESP" +fi + +# ── Test 5 : ask-agent brain ────────────────────────────────────────────────── +echo "▸ [5] ask-agent brain — réponse non vide" +if curl -sf http://127.0.0.1:4000/v1/models -H "Authorization: Bearer lm-studio" | grep -q "claude"; then + RESP=$(ask-agent brain "Réponds juste: OK" --max-tokens 200 2>&1) || true + if [ -n "$RESP" ] && echo "$RESP" | grep -qiv "error\|failed\|curl"; then + pass "ask-agent brain répond : ${RESP:0:80}..." + else + fail "ask-agent brain a échoué : $RESP" + fi +else + skip "ask-agent brain — claude-sonnet non disponible dans LiteLLM" +fi + +# ── Test 6 : ask-agent avec données réelles ─────────────────────────────────── +echo "▸ [6] ask-agent monitor — analyse données système réelles" +DISK=$(df -h /srv/data | tail -1) +RESP=$(ask-agent monitor "Est-ce que cette utilisation disque est critique ? $DISK — réponds en une phrase." --max-tokens 100 2>&1) || true +if [ -n "$RESP" ] && echo "$RESP" | grep -qiv "error\|failed\|curl"; then + pass "ask-agent monitor analyse données réelles : ${RESP:0:120}..." +else + fail "ask-agent monitor analyse échouée : $RESP" +fi + +# ── Test 7 : Skill dans répertoire global HERMES_HOME ──────────────────────── +echo "▸ [7] Skill agent-delegation dans HERMES_HOME/skills/" +SKILL_GLOBAL="${HERMES_HOME:-/srv/data/hermes}/skills/funk/agent-delegation/SKILL.md" +if [ -f "$SKILL_GLOBAL" ]; then + pass "Skill global : $SKILL_GLOBAL" +else + fail "Skill absent : $SKILL_GLOBAL" +fi + +# ── Test 8 : Skill dans le profil funk-ai ──────────────────────────────────── +echo "▸ [8] Skill agent-delegation dans profil funk-ai" +SKILL_PROFILE="${HERMES_HOME:-/srv/data/hermes}/profiles/funk-ai/skills/funk/agent-delegation/SKILL.md" +if [ -f "$SKILL_PROFILE" ]; then + pass "Skill profil : $SKILL_PROFILE" +else + fail "Skill absent du profil — copier et redémarrer hermes-agent" +fi + +# ── Test 9 : Skill enabled dans hermes skills list ─────────────────────────── +echo "▸ [9] Skill agent-delegation enabled dans hermes skills list" +HERMES_BIN="${HOME:-/opt/hermes}/.local/bin/hermes" +if [ -x "$HERMES_BIN" ]; then + STATUS=$(HERMES_HOME="${HERMES_HOME:-/srv/data/hermes}" "$HERMES_BIN" skills list 2>/dev/null | grep "agent-delegation" || echo "") + if echo "$STATUS" | grep -q "enabled"; then + pass "Skill enabled : $STATUS" + else + fail "Skill non trouvé ou disabled dans hermes skills list" + fi +else + skip "hermes binaire introuvable : $HERMES_BIN" +fi + +# ── Test 10 : Hermes funk-ai appelle Terminal ask-agent ─────────────────────── +echo "▸ [10] Hermes funk-ai appelle Terminal: ask-agent (test fonctionnel)" +if [ -x "$HERMES_BIN" ]; then + RESP=$(HERMES_HOME="${HERMES_HOME:-/srv/data/hermes}" bash -c \ + "cd ${HERMES_HOME:-/srv/data/hermes} && $HERMES_BIN -z \ + 'Exécute via ton outil terminal exactement cette commande et affiche le résultat brut : ask-agent system \"Réponds OK\"' \ + 2>/dev/null") || true + + # Vérifier dans la dernière session que le tool terminal a été appelé avec ask-agent + LAST_SESSION=$(ls -t "${HERMES_HOME:-/srv/data/hermes}/profiles/funk-ai/sessions/session_"*.json 2>/dev/null | head -1) + if [ -n "$LAST_SESSION" ]; then + TOOL_CALL=$(python3 -c " +import json +with open('$LAST_SESSION') as f: + data = json.load(f) +for msg in data.get('messages', []): + if msg.get('role') == 'tool': + content = msg.get('content', '') + if 'ask-agent' in content or 'OK' in content: + print('FOUND') + break +" 2>/dev/null || echo "") + if [ "$TOOL_CALL" = "FOUND" ]; then + pass "Hermes a appelé Terminal: ask-agent et reçu une réponse" + else + # Fallback : vérifier juste que la réponse contient OK + if echo "$RESP" | grep -qi "OK"; then + pass "Hermes a obtenu la réponse ask-agent : ${RESP:0:100}" + else + fail "Hermes n'a pas appelé ask-agent via Terminal — réponse : ${RESP:0:200}" + fi + fi + else + skip "Impossible de lire la session — test de session ignoré" + fi +else + skip "hermes binaire introuvable — test fonctionnel ignoré" +fi + +# ── Résumé ──────────────────────────────────────────────────────────────────── +echo "" +echo "═══════════════════════════════════════════════════════" +echo " Résultats : ✓ $PASS passés ✗ $FAIL échoués ~ $SKIP ignorés" +echo "═══════════════════════════════════════════════════════" +echo "" + +if [ $FAIL -gt 0 ]; then + exit 1 +fi