- 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.
105 lines
5.4 KiB
Markdown
105 lines
5.4 KiB
Markdown
# #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.py`
|
|
> **Bugs liés :** BUG-041, BUG-042
|
|
|
|
## Contexte
|
|
|
|
Trois troubles d'usage signalés sur l'Assistant IA (BooksLM) :
|
|
|
|
1. **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.
|
|
2. **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.
|
|
3. **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 (`_looksLikePath` utilise `PATH_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 motif `PATH_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`/`_revealPath` reçoivent le vault cible. Si le préfixe ne
|
|
correspond à aucun vault connu, `_resolveExistingPath` retente 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_prompt` avec `app_context` +
|
|
`recent_files` ; prompt inchangé sans contexte ; chat sur dossier vide ne
|
|
renvoie plus 404.
|