feat(stt): Phase 3 — actions admin pilotées par le LLM (admin_action) (#51)

Asa peut désormais AGIR sur le homelab quand on le demande explicitement, via
un outil de la boucle agentique — mais jamais sans confirmation.

- Outil admin_action(description) (contexte asa) : le LLM PROPOSE une action,
  n'exécute rien. brain.ask_with_tools gagne `confirm_tools` : un tel outil
  arrête la boucle et surface sa réponse (la question de confirmation).
- _handle_agentic : stocke la proposition en pending par session ; au tour
  suivant « confirme » → agent.run_action → hermes-exec (hermes -z --yolo),
  « annule » → oubli. Réutilise le handshake + jeton du contexte agent.
- admin_action n'est exposé que si _actions_available() (STT_ACTIONS_ENABLED
  + jeton) ; sinon retiré des schémas envoyés au modèle.
- Factorisation du ctx_debug du visualiseur. 1 test unitaire (confirm_tools
  arrête la boucle). Serveur 0.9.0 ; doc stt.md + journal.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ALI YESILKAYA 2026-06-22 22:51:11 +02:00 committed by GitHub
parent dc7a2093ae
commit 3ea4c3c706
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 163 additions and 28 deletions

View file

@ -146,6 +146,12 @@ async def _web_search(args: dict, deps: ToolDeps) -> str:
return "\n".join(lines)
async def _admin_action_placeholder(args: dict, deps: ToolDeps) -> str:
# Jamais atteint : app.py intercepte admin_action dans son dispatch (handshake de
# confirmation). Présent uniquement pour que le schéma soit exposé au LLM via le registre.
return "Action en attente de confirmation."
# --- Registre : nom → (schéma OpenAI, exécuteur) --------------------------------
_TOOLS: dict[str, tuple[dict, object]] = {
@ -243,6 +249,30 @@ _TOOLS: dict[str, tuple[dict, object]] = {
},
_web_search,
),
"admin_action": (
{
"type": "function",
"function": {
"name": "admin_action",
"description": "PROPOSE une action d'administration qui MODIFIE le homelab "
"(redémarrer un service/déploiement, relancer un pod, appliquer un changement…). "
"N'exécute RIEN directement : l'utilisateur devra confirmer vocalement. À utiliser "
"uniquement pour une demande explicite d'AGIR, jamais pour une simple lecture.",
"parameters": {
"type": "object",
"properties": {
"description": {
"type": "string",
"description": "Action à effectuer, en une phrase claire et impérative "
"(ex. « redémarrer le déploiement open-webui »).",
}
},
"required": ["description"],
},
},
},
_admin_action_placeholder,
),
}