feat(ai): services partages A2 + SSE streaming B4 + confirmations UI B5 (#79)
CI / lint (push) Successful in 58s
CI / security (push) Successful in 40s
CI / test (push) Successful in 1m15s
CI / build (push) Successful in 37s
CI / e2e (push) Successful in 10m15s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
CI / lint (push) Successful in 58s
CI / security (push) Successful in 40s
CI / test (push) Successful in 1m15s
CI / build (push) Successful in 37s
CI / e2e (push) Successful in 10m15s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
This commit is contained in:
@@ -82,7 +82,7 @@ ObsiGate possède aujourd'hui **deux sous-systèmes IA** qui partagent la même
|
||||
|
||||
1. **Pas de tool calling** : parsing regex fragile, pas de résultats structurés, pas de multi-étapes.
|
||||
2. **2 actions seulement** (`create_file`, `create_directory`) ; ni lecture active, ni recherche, ni édition, ni suppression exposées au modèle.
|
||||
3. **SSE non réellement streaming** : la réponse complète est envoyée en un seul événement — `backend/bookslm_routes.py:211`.
|
||||
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,6 +93,22 @@ 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) :**
|
||||
|
||||
```
|
||||
backend/services/
|
||||
├── errors.py # ServiceError (code + status HTTP)
|
||||
├── paths.py # resolve_safe_path (anti path-traversal, source unique)
|
||||
├── vaults.py # list_accessible_vaults, browse_directory, get_vault_root
|
||||
├── files.py # read_raw_file, read_file_text (redaction + quota)
|
||||
└── search.py # search_vaults (pagination), list_tags
|
||||
```
|
||||
|
||||
Les routes `/api/vaults`, `/api/browse/{vault}`, `/api/file/{vault}/raw`, `/api/search` et
|
||||
`/api/tags` en sont de simples wrappers, tout comme les outils `list_vaults`, `list_directory`,
|
||||
`read_file`, `search_fulltext` et `list_tags`. Un `ServiceError` est traduit en `HTTPException`
|
||||
(handler global de `backend/main.py`) ou en `ToolError` (`backend/tools/registry.py`).
|
||||
|
||||
**Nouveau module `backend/tools/` :**
|
||||
|
||||
```
|
||||
@@ -129,7 +145,9 @@ boucle (max N itérations):
|
||||
```
|
||||
|
||||
- Fallback protocole texte (`obsigate-action`) si le modèle ne supporte pas les tools.
|
||||
- SSE réellement streaming.
|
||||
- SSE réellement streaming sur `/chat` (`ai_chat.stream_completion`) ; `/agent` reste buffered
|
||||
(les appels d'outils exigent la réponse complète avant exécution). Confirmations UI en deux temps
|
||||
(`confirmation` → `confirm`/`confirm_messages`).
|
||||
|
||||
### 3.4 Couche 4 — Serveur MCP
|
||||
|
||||
@@ -288,7 +306,8 @@ Voir `docs/ROADMAP.md` (item dédié) pour le détail des activités.
|
||||
## 9. Références
|
||||
|
||||
- `backend/ai.py`, `backend/ai_routes.py` — couche fournisseurs + actions éditeur
|
||||
- `backend/ai_chat.py` — chat completion provider-agnostique avec tool calling (OpenAI-compat + Gemini)
|
||||
- `backend/services/` — logique métier partagée (vaults, files, search) consommée par les routes et les outils
|
||||
- `backend/ai_chat.py` — chat completion provider-agnostique avec tool calling et streaming (OpenAI-compat + Gemini)
|
||||
- `backend/agent/loop.py` — agent loop in-app (multi-étapes, LLM injectable)
|
||||
- `backend/bookslm.py`, `backend/bookslm_routes.py` — assistant contextuel (+ endpoint `/agent`)
|
||||
- `frontend/js/ai.js`, `frontend/js/bookslm.js` — UI IA
|
||||
|
||||
+2
-4
@@ -43,11 +43,9 @@
|
||||
### 79. Assistant IA — Outils (function calling) & serveur MCP
|
||||
|
||||
- **Effort :** 10-15 jours | **Impact :** 🟡
|
||||
- **Statut :** 🔵 Phase 0 + B1/B2/B3/B7 + G livrés (2026-09-11). Détail complet : [features/ai-tools-mcp.md](./features/ai-tools-mcp.md)
|
||||
- **Statut :** 🔵 Phase 0 + A2 + B1/B2/B3/B4/B5/B6/B7 + G livrés (2026-09-11). Détail complet : [features/ai-tools-mcp.md](./features/ai-tools-mcp.md)
|
||||
- **Description :** Transformer l'assistant BooksLM en agent (lire, chercher, lister, ouvrir, modifier) via **function calling natif**, puis exposer ObsiGate à des **clients MCP externes** (Claude Desktop, Cursor…). Les deux fronts consomment une **couche d'outils partagée**.
|
||||
- **Reste à faire :**
|
||||
- [ ] **A2.** Extraire la logique métier des routes `backend/main.py` en services réutilisables (partiel)
|
||||
- [ ] **B4.** SSE réellement streaming ; **B5.** confirmations UI (carte Apply, diff) ; **B6.** outils navigation `open_file`/`reveal_in_tree`
|
||||
- [ ] **C.** Catalogue lecture & recherche (vaults, read, backlinks, backups, search, tags)
|
||||
- [ ] **D.** Catalogue mutations (create/edit/append/rename/move/delete) + confirmations two-step
|
||||
- [ ] **E.** Serveur MCP (Streamable HTTP `/mcp`, auth Bearer JWT, `propose`/`apply`, toggle par vault)
|
||||
@@ -182,7 +180,7 @@
|
||||
|---|---|---|
|
||||
| ✅ Complété | #1 → #59, #61, #63–68, #71, #72, #74–76, #78 | ~82 jours réalisés |
|
||||
| 🔵 P2 restant | #77 Desktop : signature code (optionnel), wizard 1er lancement (optionnel), 6 tests E2E **manuels** | ~1-2 jours |
|
||||
| ⚪ P3 restant | #62 Collaboration Yjs (5-7j) · #79 Assistant IA outils + MCP (10-15j, Phase 0 + G livrés) · #80 Assistant IA UX (livré, en attente vérif) | ~15-22 jours |
|
||||
| ⚪ P3 restant | #62 Collaboration Yjs (5-7j) · #79 Assistant IA outils + MCP (10-15j, Phase 0 + A2 + B + G livrés) · #80 Assistant IA UX (livré, en attente vérif) | ~15-22 jours |
|
||||
| ⚪ P4 restant | #69 Mobile éditeur (2-3j) · #70 Sémantique (4-5j) · #73 Sync (6-8j) | 11-16 jours |
|
||||
| **Total restant** | **6 items + finitions** | **~27-39 jours** |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# #79 — Assistant IA — Outils (function calling) & serveur MCP
|
||||
|
||||
> **Statut :** 🔵 En cours — Phase 0 + B1/B2/B3/B6/B7 + G livrés (2026-09-11)
|
||||
> **Statut :** 🔵 En cours — Phase 0 + A2 + B1/B2/B3/B4/B5/B6/B7 + G livrés (2026-09-11)
|
||||
> **Effort :** 10-15 jours | **Impact :** 🟡
|
||||
> **Références :** [Roadmap](../ROADMAP.md) · [Guide d'architecture IA](../AI_ARCHITECTURE_GUIDE.md)
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
|
||||
## A. Fondations — couche d'outils partagée (2-3 jours) — ✅ livré (2026-09-11)
|
||||
- [x] **A1.** Créer `backend/tools/` : `context.py` (`ToolContext` : user, allowed_vaults, mode, confirmed), `registry.py` (décorateur `@tool` + schéma JSON), `schemas.py`, `service.py`, `audit.py`
|
||||
- [ ] **A2.** Extraire la logique métier des routes de `backend/main.py` en fonctions de service réutilisables (les routes deviennent des wrappers) — *partiel : services lecture/recherche livrés (`list_vaults`, `list_directory`, `read_file`, `search_fulltext`, `list_tags`) ; refactor des routes `main.py` à suivre*
|
||||
- [x] **A2.** Extraire la logique métier des routes de `backend/main.py` en fonctions de service réutilisables (les routes deviennent des wrappers) — `backend/services/` (`errors.py`, `paths.py`, `vaults.py`, `files.py`, `search.py`) ; routes `/api/vaults`, `/api/browse`, `/api/file/{vault}/raw`, `/api/search`, `/api/tags` et outils `list_vaults`/`list_directory`/`read_file`/`search_fulltext`/`list_tags` délèguent à la même couche. Les `ServiceError` sont mappées vers `HTTPException` (routes) et `ToolError` (outils).
|
||||
- [x] **A3.** Contexte de permissions : chaque outil applique `check_vault_access` + `resolve_safe_path`
|
||||
- [x] **A4.** Audit : journalisation JSONL de chaque appel d'outil (qui, quoi, vault, résultat) — action `ai_tool_call`, arguments sensibles résumés
|
||||
- [x] **A5.** Tests unitaires du registry + services (sans IA) — `tests/test_tools.py` (30 tests)
|
||||
|
||||
## B. Function calling in-app (3-4 jours) — 🔵 partiel (B1/B2/B3/B7 livrés 2026-09-11)
|
||||
## B. Function calling in-app (3-4 jours) — ✅ livré (2026-09-11)
|
||||
- [x] **B1.** Abstraction tool-calling provider-agnostique : `backend/ai_chat.py` (`chat_completion`, `ToolCall`, `LLMResponse`) — OpenAI-compat (`tools`/`tool_choice`, parsing `tool_calls`) + Gemini (`functionDeclarations`/`functionCall`)
|
||||
- [x] **B2.** Agent loop `backend/agent/loop.py` : boucle tool→résultat→tool, limite d'itérations (10), truncation des résultats ; endpoint opt-in `POST /api/ai/bookslm/agent` (events SSE `tool`/`message`/`confirmation`)
|
||||
- [x] **B3.** Fallback : retry sans `tools` si le provider rejette les tools (400/404/422) → chat simple ; protocole texte `obsigate-action` conservé côté frontend
|
||||
- [ ] **B4.** SSE réellement streaming (corriger `bookslm_routes.py` — le message final reste envoyé en un seul événement)
|
||||
- [ ] **B5.** Confirmations UI : outils `read` auto, outils `write` via carte Apply (`bookslm.js:515`), aperçu diff pour `edit_file`
|
||||
- [x] **B4.** SSE réellement streaming — `ai_chat.stream_completion` (`_openai_stream` + `_gemini_stream`) alimente `/api/ai/bookslm/chat` token par token ; le middleware GZip laisse passer les endpoints SSE BooksLM.
|
||||
- [x] **B5.** Confirmations UI : toggle « mode agent » (front → `/agent`), événements `tool`/`confirmation`, carte Apply + aperçu diff (LCS) pour les mutations, reprise `confirm`/`confirm_messages` côté backend. *S'active dès que la phase D enregistre des outils `write`.*
|
||||
- [x] **B6.** Outils de navigation in-app : `open_file`, `reveal_in_tree` (événement `obsigate:open-file`) — livré via les liens cliquables de l'assistant (#80, [ai-assistant-ux.md](./ai-assistant-ux.md))
|
||||
- [x] **B7.** Tests : agent loop LLM mocké (`tests/test_agent_loop.py`), providers (`tests/test_ai_chat.py`), endpoint (`tests/test_bookslm.py`)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user