Files
ObsiGate/docs/features/ai-assistant-history.md
T
bruno 8e2b6203a1
CI / lint (push) Successful in 1m28s
CI / security (push) Successful in 58s
CI / test (push) Successful in 2m19s
CI / build (push) Successful in 54s
CI / e2e (push) Successful in 10m44s
feat: filtre de recherche dans la sidebar Historique IA (#98) + menus '@' et '/' depuis le menu '+' (BUG-048)
2026-09-16 16:11:54 -04:00

9.5 KiB
Raw Blame History

#94–#97 — Assistant IA : historique permanent, accès sidebar, bouton rond et panneau « + »

Statut : ✅ Livré (en attente de validation utilisateur) Effort : ~7 jours | Impact : 🟡 Références : Roadmap · Changelog

  • Description : quatre améliorations de l'Assistant IA livrées ensemble :
    1. #94 — bouton de soumission circulaire avec icône Lucide arrow-up (remplace l'avion ✈️).
    2. #95 — historique permanent des conversations persisté côté backend (les échanges survivent aux rechargements de page et aux navigateurs).
    3. #96 — accès rapide à l'historique depuis la sidebar de navigation (onglet dédié).
    4. #97 — panneau « + » extensible remplaçant « Attach an image » (modules : fichiers, image, contextes, skills, Deep Research, web, Canva).

A. Backend — persistance des conversations (#95) — ✅ livré

  • backend/ai_history.py (nouveau) : stockage JSON par utilisateur (data/ai_history/{username}.json), écriture atomique (tmp + shutil.move), plafond MAX_SESSIONS = 200 (purge des plus anciennes), tri par updatedAt desc.
  • list_sessions, get_session, upsert_session, delete_session ; la liste renvoie des résumés sans messages (_summary : titre, mode, vault, contexte, message_count, preview) pour rester légère.
  • backend/bookslm_routes.py : modèle Pydantic BookslmSession et 4 endpoints : - GET /api/ai/bookslm/history — liste des conversations (résumés). - GET /api/ai/bookslm/history/{session_id} — conversation complète (404 si absente). - PUT /api/ai/bookslm/history/{session_id} — création/mise à jour (l'id du corps est forcé à l'id du path → jamais d'écriture sous une autre clé). - DELETE /api/ai/bookslm/history/{session_id} — suppression (booléen ok).
  • Isolation par utilisateur (require_auth) ; saisies défensives (username/id vides) → [] ou None.

B. Frontend — sync serveur + cache local (#95) — ✅ livré

  • frontend/js/bookslm.js : clé local globale bookslm-sessions-all-{username} ; migration des anciennes clés périmées bookslm-sessions-<ctx> et bookslm-history-<ctx> à la première ouverture.
  • _loadHistory(preferredSessionId) async au chargement du panneau : lecture serveur (GET /history), hydratation du localStorage, repli hors-ligne silencieux si le serveur ne répond pas.
  • Synchronisation debounced 600 ms (_syncHistoryToServer → _flushHistoryToServer) via _dirtySessionIds / _deletedIds : PUT/DELETE seulement pour les sessions modifiées ; pas d'appel réseau à la simple ouverture.
  • _positionSession : nouvelle session insérée en tête, session rechargée remise à jour.
  • openContext(opts, preferredSessionId) async ; openWithSession(sessionOrId) public pour ouvrir une conversation connue (utilisé par la sidebar #96).
  • _notifyHistoryChanged() : événement bookslm:history-updated pour rafraîchir la sidebar #96 sans rechargement.

C. Frontend — sidebar & historique (#96) — ✅ livré

  • frontend/index.html : cinquième onglet #sidebar-tab-ai (icône Lucide messages-square) et panneau #sidebar-panel-ai (#ai-history-list, #ai-history-empty).
  • frontend/js/config.js : loadAISessionList() / renderAIHistoryList() (réutilise les classes .recent-* de l'UI), placeholder « Aucune conversation », listener bookslm:history-updated monté par initSidebarTabs() et actif quand l'onglet ai est affiché.
  • Le clic sur une conversation l'ouvre dans le panneau Assistant IA (via openWithSession) et bascule la sidebar.

D. Frontend — panneau « + » extensible (#97) — ✅ livré

  • Bouton « Attach an image » remplacé par un bouton « + » circulaire (frontend/js/bookslm.js, .bookslm-btn-plus).
  • Panneau overlay .bookslm-ext-menu (dropdown au-dessus de la zone de saisie, fermeture au clic extérieur / Échap) listant les modules.
  • Architecture modulaire : registre _extensions (objet d'enregistrement simple) — chaque entrée : id, icône, libellé i18n, action ; renderExtMenu() construit la liste ; un nouveau module s'ajoute en une entrée.
  • Modules livrés : Fichiers (sélecteur général .bookslm-files-input), Image (joindre une image), Contextes/fichiers, Skills, Deep Research (mode agent + prompt pré-rempli), Recherche sur Internet, Canva.
  • web/canva affichés désactivés avec badge « Bientôt » (.bookslm-ext-soon) — le catalogue d'outils #92 les alimentera.
  • _startDeepResearch() : active le mode agent, injecte le prompt Deep Research et déclenche l'envoi.

E. UI — bouton rond & icône (#94) — ✅ livré

  • .bookslm-btn-send circulaire (40 px, border-radius: 50%), icône Lucide arrow-up à la place de l'emoji ✈️, aligné en bas à droite de la zone de saisie.
  • i18n FR/EN : bookslm.add_options, bookslm.ext_files, bookslm.ext_image_hint, bookslm.ext_contexts, bookslm.ext_skills, bookslm.ext_deep_research, bookslm.ext_web, bookslm.ext_canva, bookslm.coming_soon, bookslm.soon, bookslm.ext_more_coming, bookslm.deep_research_prompt, bookslm.deep_research_started, bookslm.mode_*.

F. Tests — ✅ livré

  • tests/test_bookslm.py : TestBooksLMSessionHistoryEndpoints (7) + TestAIGatewayHistoryStore (4) — liste résumée sans messages, full 404, upsert qui force l'id et isole par utilisateur, delete, cap à 200, purge.
  • tests/frontend/ai.test.mjs : persistance/reouverture/suppression de sessions, migration de l'historique legacy, menu d'historique.
  • Vérifs : pytest 1088 passed / 6 skipped, ruff 0, mypy 0 (71 fichiers), frontend ai.test.mjs 84/84, unit.test.mjs 9/9, validate-imports 38 modules.

H. Complément — filtre de la sidebar et menu « + » (BUG-048, #98) — ✅ livré

En retour utilisateur sur la version 2.4.0 :

(1) Filtre fonctionnel sur l'onglet « Historique IA » (sidebar) — #98 — la barre de filtrage globale de la sidebar agissait uniquement sur les onglets Fichiers/Tags. Elle s'applique désormais aussi à l'historique IA :

  • Utile filterAIHistory(query) (frontend/js/config.js) : filtre le cache de sessions _aiSessionsCache (peuplé par loadAISessionList()) sur titre, aperçu, répertoire, contexte ou libellé de mode traduit, insensible à la casse et aux accents (_aiNorm : NFD + suppression des diacritiques + toLowerCase). Une requête sans résultat affiche bookslm.history_no_match (nouvelle clé i18n FR/EN) dans la liste, en plus de l'état vide d'origine ; un champ vide restaure tout.
  • Routage dans initSidebarFilter (frontend/js/sidebar.js) : la saisie (debounce 220 ms), le bouton casse Aa et le bouton « × » dirigent vers filterAIHistory quand l'onglet IA est actif (state.activeSidebarTab), au lieu de filterTagCloud. Le placeholder devient sidebar.filter_ai (« Filtrer l'historique IA… » / « Filter AI history… ») — résolu dans switchSidebarTab (config.js), qui re-charge aussi la liste à chaque entrée dans l'onglet en ré-appliquant la requête courante.

(2) Menu « + » du panneau Assistant — BUG-048 — « ajouter des contextes » ouvrait un menu « @ » jamais affiché (et idem pour « ajouter des skills » → « / ») : le clic sur une entrée du panneau .bookslm-ext-menu remontait au gestionnaire click du panneau (_hideMenus() + _menuSeq++), qui annulait le rendu asynchrone du menu ouvert juste après. e.stopPropagation() est ajouté sur chaque entrée de _renderExtMenu() (bookslm.js) : les menus « @ » (contextes) et « / » (skills) restent affichés. Le bouton d'ouverture porte bien l'icône Lucide plus (vérifié par test JSDOM).

Points d'attention

  • Le filtrage reste client-side : la charge est triviale vu le cap de 200 sessions (MAX_SESSIONS). Un futur filtrage serveur n'est justifié que si la rétention croît.
  • filterAIHistory est exportée en plus de loadAISessionList : validate-imports couvre le nouveau contrat d'import de sidebar.js.

Tests du complément

  • tests/frontend/ai-sidebar.test.mjs (nouveau, 6 tests) : rendu complet, filtre par titre (casse), accents (« cafe » → « café au lait »), aperçu/répertoire, restauration complète, message « aucune correspondance ».
  • tests/frontend/ai.test.mjs (+3) : clic « Contextes » → menu « @ » visible listé, clic « Skills » → menu « / » visible listé, icône plus présente sur le bouton « + ».
  • Vérifs : frontend IA 87/87, ai-sidebar 6/6, unit 9/9, 9 suites JSDOM vertes, validate-imports 38 modules ; backend inchangé (pytest / ruff / mypy valides).

G. Points d'attention

  • Le localStorage reste un cache : le serveur est la source de vérité (data/ai_history/). En cas de données locales corrompues, un localStorage.clear() réinitialise proprement.
  • MAX_SESSIONS = 200 : le comportement de purge est testé (TestAIGatewayHistoryStore) ; la rétention configurable (item #95 du backlog) pourra s'appuyer sur ce plafond.
  • Les modules web/Canva du panneau « + » sont volontairement désactivés tant que l'écosystème d'outils phase 2 (#92) n'est pas livré.