fix(ai+editeur): BUG-046 erreur lisible et vault réel pour l'ajout IA au document; BUG-045 fin de la double scrollbar
CI / lint (push) Successful in 1m26s
CI / security (push) Successful in 57s
CI / test (push) Successful in 2m51s
CI / build (push) Successful in 54s
CI / e2e (push) Successful in 11m2s

BUG-046: 'Ajouter du texte au document courant' échouait avec 'Échec de
l'action: [object Object]'. Trois causes corrigées:
- continuation de confirmation sans payload -> second Appliquer POSTait
  sans 'message' (422); le payload d'origine est désormais transmis
- detail 422 FastAPI (tableau d'objets) stringifié tel quel -> nouvelle
  _responseError() qui aplatit en message lisible
- prompt documents/dossier muet sur le vault -> le modèle inventait
  'vault: test' et append_to_file échouait en silence; build_system_prompt
  nomme le vault et enjoint les outils d'écriture de l'utiliser exactement

BUG-045: double barre de défilement dans l'éditeur Editer (fichiers
longs): #editor-body overflow:auto + cm-editor height:100% sous la barre
IA -> corps et scroller CodeMirror défilant tous les deux. Flex column,
seul le scroller défile; override global .cm-scroller retiré. SW v20.

Vérifié: pytest 1038, ruff backend 0, tests frontend AI 84/84,
editor-inline 25/25, validate-imports 38 modules; Playwright sur
l'instance de test (un seul conteneur scrollable) et flux agent complet
append_to_file ok=true sur fichier réel
This commit is contained in:
2026-09-16 09:10:58 -04:00
parent e3df4bbf00
commit 3261917d62
10 changed files with 143 additions and 15 deletions
+27 -4
View File
@@ -2397,6 +2397,27 @@ class BooksLM {
return html;
}
/**
* Build a readable Error from a non-OK /chat or /agent response. BUG-046:
* a 422 validation error carries `detail` as an ARRAY of objects (FastAPI),
* which `new Error(detail)` stringified to "[object Object]" in the
* "Échec de l'action" toast. Flatten arrays / objects into their messages.
*/
async _responseError(resp) {
let detail = `HTTP ${resp.status}`;
try {
const body = await resp.json();
const d = body && body.detail;
if (typeof d === 'string' && d) detail = d;
else if (Array.isArray(d) && d.length) {
detail = d.map((item) => (item && (item.msg || item.message)) || JSON.stringify(item)).join(' · ');
} else if (d && typeof d === 'object') {
detail = d.msg || d.message || JSON.stringify(d);
}
} catch { /* no json body */ }
return new Error(detail);
}
async _applyConfirmation(msg) {
const conf = msg.confirmation;
if (!conf || conf._applying) return;
@@ -2413,7 +2434,11 @@ class BooksLM {
const sendBtn = this._panel && this._panel.querySelector('.bookslm-btn-send');
if (sendBtn) sendBtn.disabled = true;
const continuation = { role: 'assistant', content: '', sources: [], toolCalls: [], confirmation: null, payload: null };
// BUG-046: carry the original request payload over to the continuation.
// When an applied tool failed and the model re-proposed a confirmation,
// the continuation used to have `payload: null`: the second "Appliquer"
// then resumed without `message` → 422 → "[object Object]" toast.
const continuation = { role: 'assistant', content: '', sources: [], toolCalls: [], confirmation: null, payload: msg.payload ? { ...msg.payload } : null };
try {
let resp = await this._postChat(payload);
if (resp.status === 401 && AuthManager._authEnabled) {
@@ -2421,9 +2446,7 @@ class BooksLM {
resp = await this._postChat(payload);
}
if (!resp.ok) {
let detail = `HTTP ${resp.status}`;
try { detail = (await resp.json()).detail || detail; } catch { /* */ }
throw new Error(detail);
throw await this._responseError(resp);
}
// The confirmation is resolved: drop the card and show the continuation.
msg.confirmation = null;