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
+13 -1
View File
@@ -414,12 +414,16 @@ def _build_directory_tree(target_dir: Path, vault_root: Path) -> str:
return "\n".join(lines)
def build_system_prompt(context: dict[str, Any], scope: str = "directory") -> str:
def build_system_prompt(context: dict[str, Any], scope: str = "directory", vault_name: str | None = None) -> str:
"""Build a system prompt for document-scoped AI chat.
Args:
context: Output of collect_directory_context()/collect_files_context().
scope: "directory" (whole folder) or "documents" (open files).
vault_name: Vault the context files belong to. When set, the prompt
states it explicitly with write-tool guidance (BUG-046: without
it the model invented vault names — e.g. "test" — and every
confirmed ``append_to_file``/``edit_file`` call failed).
Returns:
System prompt string with file contents.
@@ -469,6 +473,14 @@ def build_system_prompt(context: dict[str, Any], scope: str = "directory") -> st
prompt += "\nFin du contexte. Réponds à la question de l'utilisateur en te basant uniquement sur ces documents."
if vault_name:
prompt += (
f"\n\nCes documents appartiennent au vault « {vault_name} ». Quand tu utilises un outil "
"d'écriture (`append_to_file`, `edit_file`, `create_file`), passe TOUJOURS "
f"exactement `\"vault\": \"{vault_name}\"` (jamais un nom inventé) et un `path` "
"relatif au vault, identique à celui affiché ci-dessus."
)
return prompt
+2 -2
View File
@@ -223,7 +223,7 @@ def _resolve_system_prompt(req, current_user) -> str:
recent_files=_recent_files_for_prompt(current_user),
)
elif effective_mode == "documents":
prompt = build_system_prompt(context, scope="documents")
prompt = build_system_prompt(context, scope="documents", vault_name=req.vault)
elif context["file_count"] == 0:
# Empty (or unreadable) directory: don't block the request. Answer as
# the General assistant would, telling the model the folder is empty so
@@ -240,7 +240,7 @@ def _resolve_system_prompt(req, current_user) -> str:
"documentaire, et propose une action de création si c'est pertinent.\n"
)
else:
prompt = build_system_prompt(context, scope="directory")
prompt = build_system_prompt(context, scope="directory", vault_name=req.vault)
skill_id = getattr(req, "skill", None)
if skill_id: