mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 19:04:42 +02:00
Asa peut AGIR sur le homelab (l'autre moitié de la vision), via le vrai agent Hermes, profil par défaut, tous ses outils — avec confirmation et jeton. Découverte : Hermes n'a pas d'API HTTP (appli TUI), mais un mode one-shot `hermes -z "<prompt>" --yolo`. On s'appuie dessus. storage-01 — exécuteur : - tools/hermes-exec/server.py : service HTTP qui lance `hermes -z --yolo` en user hermes, derrière un jeton Bearer (compare_digest), timeout + audit, une action à la fois. - rôle Ansible hermes_exec : systemd (User=hermes, env hermes-agent), jeton via EnvironmentFile 0640 (Vault vault_hermes_exec_token) ; ajouté au playbook storage-01. STT-server (0.5.0 → 0.6.0) : - agent.py : pont vers hermes-exec (jeton) + détection confirme/annule. - contexts.py : contexte « agent » (court-circuite le LLM). - app.py : flux dédié — handshake 2 temps par session (pending action) → sur « confirme », appelle hermes-exec ; « annule » annule. /v1/contexts masque « agent » si désactivé. - config : STT_ACTIONS_ENABLED (opt-in, défaut false) + URL + jeton (secret k8s). - deployment : env actions + secret stt-server-secrets/hermes-exec-token (optionnel). Sécurité : opt-in désactivé par défaut ; jeton obligatoire (sinon contexte caché + exécuteur refuse tout) ; --yolo atteint seulement jeton+confirmation en main ; audit storage-01. Client : AUCUN changement (le contexte « agent » apparaît tout seul dans le sélecteur). Validé en local : exécuteur (401 sans/mauvais jeton, exec avec bon jeton via echo), handshake serveur (TestClient : confirme→exécute, annule→annule, agent masqué si OFF). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
89 lines
5.3 KiB
Python
89 lines
5.3 KiB
Python
"""Configuration du STT-server — via variables d'environnement (12-factor / k8s)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
|
|
class Settings:
|
|
# LiteLLM (s01) — joint en IP directe depuis le cluster (cf. open-webui).
|
|
litellm_url: str = os.getenv(
|
|
"STT_LITELLM_URL", "http://192.168.10.1:4000/v1/chat/completions"
|
|
)
|
|
litellm_key: str = os.getenv("STT_LITELLM_KEY", "lm-studio")
|
|
# Modèle par défaut + alias LiteLLM autorisés (le client peut en demander un par requête)
|
|
model: str = os.getenv("STT_MODEL", "hermes-default")
|
|
allowed_models: list[str] = [
|
|
m.strip()
|
|
for m in os.getenv(
|
|
"STT_ALLOWED_MODELS",
|
|
"hermes-default,qwen3-8b,claude-sonnet-4-6,claude-opus-4-7",
|
|
).split(",")
|
|
if m.strip()
|
|
]
|
|
|
|
system_prompt: str = os.getenv(
|
|
"STT_SYSTEM_PROMPT",
|
|
"Tu es Hermes, l'assistant vocal du homelab Funk. "
|
|
"Réponds toujours en français, de façon concise (2-3 phrases maximum), "
|
|
"sans markdown ni listes. "
|
|
"Pour toute question sur Funk (cluster, machines, services, matériel, configuration), "
|
|
"appuie-toi EXCLUSIVEMENT sur la documentation fournie ci-dessous. "
|
|
"Règle stricte : si la doc ne mentionne pas explicitement l'élément demandé, réponds "
|
|
"« la doc Funk ne le précise pas » — n'affirme JAMAIS un oui ni un non par déduction, "
|
|
"et n'invente aucun détail (modèle, marque, nombre, nom).",
|
|
)
|
|
max_tokens: int = int(os.getenv("STT_MAX_TOKENS", "200"))
|
|
temperature: float = float(os.getenv("STT_TEMPERATURE", "0.7"))
|
|
# Timeout PAR tentative vers LiteLLM (brain fait jusqu'à 2 tentatives). Une réponse vocale
|
|
# avec /no_think tient en quelques secondes → 30s suffit, et borne l'attente d'un blip backend.
|
|
request_timeout: float = float(os.getenv("STT_REQUEST_TIMEOUT", "30"))
|
|
# Qwen3 est un modèle « thinking » → ajoute `/no_think` pour désactiver le raisonnement
|
|
# (sinon content vide / timeout). Inoffensif pour les modèles non-Qwen.
|
|
disable_thinking: bool = os.getenv("STT_DISABLE_THINKING", "true").lower() == "true"
|
|
|
|
# Mémoire long-terme (Qdrant) — dégrade proprement si Qdrant/embeddings injoignables
|
|
memory_longterm: bool = os.getenv("STT_MEMORY_LONGTERM", "true").lower() == "true"
|
|
qdrant_url: str = os.getenv("STT_QDRANT_URL", "http://192.168.10.1:6333")
|
|
qdrant_collection: str = os.getenv("STT_QDRANT_COLLECTION", "stt-memory")
|
|
# Embeddings : instance dédiée nomic-embed-text sur llama-server gpu-01 (:1238, dim 768).
|
|
embed_url: str = os.getenv("STT_EMBED_URL", "http://192.168.10.20:1238/v1/embeddings")
|
|
embed_model: str = os.getenv("STT_EMBED_MODEL", "nomic-embed-text")
|
|
memory_top_k: int = int(os.getenv("STT_MEMORY_TOPK", "3"))
|
|
# Le recall (embed + recherche) est sur le chemin de réponse : timeout SERRÉ pour qu'un
|
|
# embed lent/mort dégrade vite (souvenirs vides) au lieu d'ajouter des secondes au client.
|
|
# Le store tourne en tâche de fond (après la réponse) → timeout plus large toléré.
|
|
memory_recall_timeout: float = float(os.getenv("STT_MEMORY_RECALL_TIMEOUT", "4"))
|
|
memory_store_timeout: float = float(os.getenv("STT_MEMORY_STORE_TIMEOUT", "20"))
|
|
|
|
# RAG documentaire : ancre les réponses dans la doc Funk (collection `funk-docs`,
|
|
# même embedder nomic :1238 que la mémoire → le vecteur de requête est réutilisé).
|
|
# Sans ça, le modèle répond de connaissances générales (hallucine sur le homelab).
|
|
docs_rag: bool = os.getenv("STT_DOCS_RAG", "true").lower() == "true"
|
|
docs_collection: str = os.getenv("STT_DOCS_COLLECTION", "funk-docs")
|
|
docs_top_k: int = int(os.getenv("STT_DOCS_TOPK", "6"))
|
|
# nomic étale les scores plus bas → seuil permissif (aligné sur rag-query).
|
|
docs_min_score: float = float(os.getenv("STT_DOCS_MIN_SCORE", "0.45"))
|
|
# Sur le chemin de réponse (1 recherche Qdrant, vecteur déjà calculé) → timeout serré.
|
|
docs_timeout: float = float(os.getenv("STT_DOCS_TIMEOUT", "4"))
|
|
|
|
# Contextes présélectionnables (visualiseur + presets live). Le contexte « funk »
|
|
# garde le system_prompt grounding-strict ci-dessus ; les autres injectent des
|
|
# données live. URLs surchargeables selon la résolution réseau in-cluster.
|
|
default_context: str = os.getenv("STT_DEFAULT_CONTEXT", "funk")
|
|
sources_timeout: float = float(os.getenv("STT_SOURCES_TIMEOUT", "4"))
|
|
ghostfolio_url: str = os.getenv("STT_GHOSTFOLIO_URL", "http://ghostfolio.lab.local")
|
|
# Jeton « Security token » du compte Ghostfolio (vide → données indisponibles).
|
|
ghostfolio_token: str = os.getenv("STT_GHOSTFOLIO_TOKEN", "")
|
|
prometheus_url: str = os.getenv("STT_PROMETHEUS_URL", "http://prometheus.lab.local")
|
|
alertmanager_url: str = os.getenv("STT_ALERTMANAGER_URL", "http://alertmanager.lab.local")
|
|
|
|
# Actions via Hermes (contexte « agent ») — OPT-IN, désactivé par défaut.
|
|
# Le contexte « agent » n'est exposé que si actions_enabled ET un jeton est présent.
|
|
actions_enabled: bool = os.getenv("STT_ACTIONS_ENABLED", "false").lower() == "true"
|
|
hermes_exec_url: str = os.getenv("STT_HERMES_EXEC_URL", "http://192.168.10.1:9096")
|
|
hermes_exec_token: str = os.getenv("STT_HERMES_EXEC_TOKEN", "")
|
|
hermes_exec_timeout: float = float(os.getenv("STT_HERMES_EXEC_TIMEOUT", "130"))
|
|
|
|
|
|
settings = Settings()
|