- accents : classes de caracteres Unicode (\p{L}\p{N}\p{M}) pour les motifs
de liens et _looksLikePath (PATH_NAME_RE) -> les chemins/fichiers accentues
produisent enfin un lien cliquable ; comparaison de chemins normalisee NFC
(_normKey), donc une mention decomposee (e + accent combinant, style macOS)
correspond a une entree d'index precomposee, et inversement.
- prefixe de vault : _splitVaultPrefix() retire un premier segment egal au nom
d'un vault connu (TestVault/Recettes/Pizza Maison.md) ; _fetchPathsForVault()
interroge l'index de CE vault sans ecraser le cache du vault actif ;
_openFileLink/_revealPath recoivent le vault cible ; repli 'retirer le
premier segment' si le prefixe ne correspond a aucun vault connu.
Tests : frontend IA 62/62 (+5), 9 suites JSDOM, validate-imports 36 modules,
pytest 963 passed / 6 skipped. Verifie aussi contre l'instance live sur donnees
reelles accentuees/espaces (Recettes/Preparation.md, Recettes/Pat... ) : 8/8.
5.4 KiB
#88 — Assistant IA : contexte applicatif & fiabilité des liens
Statut : 🟢 corrigé / livré (en attente de vérification utilisateur) Version : 2.3.0 Composants :
frontend/js/bookslm.js,backend/bookslm.py,backend/bookslm_routes.pyBugs liés : BUG-041, BUG-042
Contexte
Trois troubles d'usage signalés sur l'Assistant IA (BooksLM) :
- Répertoire vide bloquant — ouvrir l'assistant sur un dossier ne contenant
aucun fichier markdown renvoyait
⚠ Error: Aucun fichier markdown trouvé dans ce dossier(HTTP 404) au lieu de répondre à la question de l'utilisateur. - Assistant Général aveugle — en mode Général, l'assistant ne savait que lister les vaults : il ne connaissait ni les documents ouverts, ni le répertoire courant, ni la page de résultats de recherche, ni les fichiers récemment modifiés.
- Liens de fichiers peu fiables — l'assistant produisait des liens vers des
noms de fichiers qui échouaient avec
File not found: …, sans règle claire (nom simple, dossier, chemin complet).
Conception
1. Dégradation gracieuse du dossier vide (BUG-041)
_resolve_system_prompt (backend/bookslm_routes.py) ne lève plus de 404 quand
le contexte d'un dossier est vide. Il construit le prompt Général (aide
applicative + actions), enrichi d'un bloc « Dossier vide », et prévient le
modèle qu'aucun contexte documentaire n'est disponible — il répond quand même et
propose une création de fichier si pertinent.
Le prompt Général reçoit en outre les fichiers récemment modifiés de
l'utilisateur (backend/services/recent.list_recent, best-effort).
2. Contexte applicatif de l'assistant Général (#88)
Le frontend envoie un nouveau champ app_context dans les requêtes /chat et
/agent (_buildAppContext()), contenant l'état vivant de l'interface :
| Champ | Contenu |
|---|---|
open_documents |
Documents ouverts dans les onglets/panneaux (via collectOpenDocuments()) |
current_path |
Document affiché dans le viewer |
directory |
Répertoire courant de l'assistant |
vault |
Vault sélectionné |
search_query / search_total |
Dernière recherche et nombre de résultats |
search_results |
Fichiers affichés sur la page de résultats (max 20) |
Côté backend, build_general_system_prompt(vaults, app_context, recent_files)
rend un bloc « Contexte applicatif actuel » ajouté au prompt Général.
3. Liens de fichiers déterministes (BUG-042)
Classification des liens (_classifyPath) :
| Forme | data-kind |
Action au clic |
|---|---|---|
Nom de fichier seul (readme.md) |
name |
Copie le nom dans le presse-papiers |
Chemin de dossier (projets/2026) |
dir |
Révèle le dossier dans l'arborescence |
Chemin de fichier (notes/a.md) |
file |
Ouvre le fichier dans le viewer |
Avant d'agir, _activatePath() résout le chemin contre l'index du vault
(_resolveExistingPath) : correspondance exacte, puis suffixe
(segment de tête omis par le modèle), puis basename unique. Les chemins non
résolus copient le nom au lieu d'ouvrir un lien mort — plus de File not found.
4. Espaces, accents et préfixe de vault dans les chemins (BUG-042)
Les noms de fichiers/dossiers pouvant contenir des espaces et des accents, la détection et la résolution sont adaptées :
- Liens markdown : la cible peut contenir des espaces, être encadrée par
<…>ou porter un"titre"; les URL percent-encodées (%20) sont décodées. - Code inline :
`Ma note.md`/`Recettes/Préparation.md`sont reconnus (_looksLikePathutilisePATH_NAME_RE, une classe Unicode\p{L}\p{N}\p{M}— les accents sont acceptés, le jeu de caractères reste strict pour rejeter extraits de code et commandes shell). - Mentions brutes : une mention avec espaces n'est liée que si elle existe
réellement dans l'index du vault (
_linkifySpacePaths+_confirmPathInCache), et l'acceptation se fait sur le plus long suffixe aligné sur un mot — ainsi « Ouvre Mon dossier/Ma note.md » ne crée pas de lien englobant « Ouvre » et la prose ordinaire n'est jamais liée à tort. Les chemins sans espace mais accentués sont liés par le motifPATH_WITH_DIR_RE, lui aussi Unicode-aware. - Normalisation Unicode :
_normKey()compare en NFC + minuscules, donc une mention décomposée (e+ accent combinant, comme sur macOS) correspond à une entrée d'index précomposée, et inversement. - Préfixe de vault :
_splitVaultPrefix()retire un premier segment égal au nom d'un vault connu (TestVault/Recettes/Pizza Maison.md→Recettes/Pizza Maison.md). La résolution interroge l'index de ce vault (_fetchPathsForVault, fetch ponctuel sans écraser le cache du vault actif), puis_openFileLink/_revealPathreçoivent le vault cible. Si le préfixe ne correspond à aucun vault connu,_resolveExistingPathretente en retirant le premier segment.
Tests
tests/frontend/ai.test.mjs: classification (name/file/dir), routage_activatePath(ouvre/révèle/copie), clic d'un lien « nom » → presse-papiers, et prise en charge des espaces (code inline, liens markdown%20, mentions brutes liées uniquement si présentes dans l'index, résolution au clic).tests/test_bookslm.py:build_general_system_promptavecapp_context+recent_files; prompt inchangé sans contexte ; chat sur dossier vide ne renvoie plus 404.