feat(ai): catalogue d'outils mutations + confirmations two-step (#79 phase D)
CI / lint (push) Successful in 59s
CI / security (push) Successful in 45s
CI / test (push) Successful in 1m22s
CI / build (push) Successful in 37s
CI / e2e (push) Successful in 10m37s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s

This commit is contained in:
2026-09-11 20:52:02 -04:00
parent 31b65ade5b
commit 83c412b33d
13 changed files with 1747 additions and 589 deletions
+11 -5
View File
@@ -81,7 +81,9 @@ ObsiGate possède aujourd'hui **deux sous-systèmes IA** qui partagent la même
### 2.5 Limites de l'existant
1. **Pas de tool calling** : parsing regex fragile, pas de résultats structurés, pas de multi-étapes.
→ **résolu** (phases B/C/D) : tool calling natif, catalogue lecture/recherche + mutations.
2. **2 actions seulement** (`create_file`, `create_directory`) ; ni lecture active, ni recherche, ni édition, ni suppression exposées au modèle.
→ **résolu** (phases C/D) : catalogue complet (lecture, recherche, mutations avec confirmation).
3. **SSE** : ~~non réellement streaming~~ → **corrigé** (B4) : `ai_chat.stream_completion` alimente `/api/ai/bookslm/chat` token par token ; le tool-calling (`/agent`) reste non-streaming (les appels d'outils exigent la réponse complète).
4. **`PROVIDERS` chargé une seule fois** : les modèles par défaut ne sont modifiables que par variables d'environnement (pas de persistance UI).
@@ -93,7 +95,7 @@ ObsiGate possède aujourd'hui **deux sous-systèmes IA** qui partagent la même
Extraire la logique métier des routes de `backend/main.py` vers des fonctions réutilisables (services). Les routes REST, l'agent in-app et le serveur MCP appellent ces mêmes services.
**Nouveau module `backend/services/` (A2 lecture/recherche + C) :**
**Nouveau module `backend/services/` (A2 lecture/recherche + C + D mutations) :**
```
backend/services/
@@ -101,17 +103,21 @@ backend/services/
├── paths.py # resolve_safe_path (anti path-traversal, source unique)
├── vaults.py # list_accessible_vaults, browse_directory, get_vault_root, list_all_files
├── files.py # read_raw_file, read_file_text (redaction + quota)
├── mutations.py # create/edit/append/rename/move/delete/restore/replace (D)
├── search.py # search_vaults (pagination), list_tags, advanced_search_vaults, search_paths
├── backups.py # get_backup_dir, list_backup_files, diff_backup
├── backups.py # get_backup_dir, create_backup, list_backup_files, diff_backup
├── graph.py # get_graph (nodes/edges, wikilinks)
└── recent.py # list_recent, humanize_mtime
```
Les routes `/api/vaults`, `/api/browse/{vault}`, `/api/file/{vault}/raw`, `/api/search`, `/api/tags`,
`/api/recent`, `/api/vault/{vault}/files`, `/api/file/{vault}/backups`, `/api/file/{vault}/diff`,
`/api/graph/{vault}`, `/api/tree-search` et `/api/search/advanced` en sont de simples wrappers, tout
comme les outils correspondants du catalogue (phase C). Un `ServiceError` est traduit en
`HTTPException` (handler global de `backend/main.py`) ou en `ToolError` (`backend/tools/registry.py`).
`/api/graph/{vault}`, `/api/tree-search`, `/api/search/advanced` (phase C) ainsi que
`/api/file/{vault}` (POST/PATCH/DELETE), `/api/file/{vault}/save`, `/api/file/{vault}/restore`,
`/api/directory/{vault}` (POST/PATCH/DELETE), `/api/move/{vault}` et `/api/search/replace` (phase D)
en sont de simples wrappers, tout comme les outils correspondants du catalogue. Un `ServiceError`
est traduit en `HTTPException` (handler global de `backend/main.py`) ou en `ToolError`
(`backend/tools/registry.py`).
**Nouveau module `backend/tools/` :**