fix(ai): contexte applicatif de l'assistant, dossier vide et liens fiables (#88, BUG-041, BUG-042)
CI / lint (push) Successful in 1m16s
CI / security (push) Successful in 50s
CI / test (push) Successful in 3m0s
CI / build (push) Successful in 47s
CI / e2e (push) Successful in 10m58s

- BUG-041 : le contexte d'un dossier vide ne renvoie plus 404 ; il degrade
  vers le prompt General enrichi d'un bloc « Dossier vide ».
- BUG-042 : liens de fichiers deterministes (nom -> presse-papiers,
  dossier -> arborescence, chemin -> viewer) et resolution du chemin contre
  l'index du vault (exact -> suffixe -> basename) avant ouverture, fin des
  'File not found'.
- #88 : app_context (documents ouverts, repertoire/vault courants, recherche
  + resultats affiches) et fichiers recemment modifies injectes dans le
  prompt General.

Tests : pytest 963 passed / 6 skipped, ruff 0, mypy 0, frontend 52/52 +
validate-imports 36 modules.
This commit is contained in:
2026-09-14 11:28:30 -04:00
parent 05ed36240b
commit 314e37c433
11 changed files with 464 additions and 32 deletions
+35 -3
View File
@@ -527,15 +527,17 @@ class TestBooksLMChatEndpoint:
)
assert resp.status_code == 404
def test_chat_empty_directory(self, bookslm_client):
"""Chat endpoint returns 404 for empty directory."""
def test_chat_empty_directory_does_not_block(self, bookslm_client):
"""Chat on an empty directory must not 404 — it answers without context."""
token, _ = _login_bookslm(bookslm_client)
resp = bookslm_client.post(
"/api/ai/bookslm/chat",
json={"vault": "TestVault", "directory": "nonexistent", "message": "Hello"},
headers={"Authorization": f"Bearer {token}"},
)
assert resp.status_code == 404
# 200 (stream opened) or 500 (no AI key) — never 404/422.
assert resp.status_code in (200, 500), f"unexpected {resp.status_code}: {resp.text[:200]}"
assert resp.status_code != 404
def test_chat_request_accepts_provider_and_model(self, bookslm_client):
"""The chat endpoint schema accepts provider + model fields without rejecting.
@@ -641,6 +643,36 @@ class TestGeneralPrompt:
assert "Beta" in prompt
assert "obsigate-action" in prompt
def test_general_prompt_includes_app_context(self):
"""The General assistant is told what the user is currently doing."""
from backend.bookslm import build_general_system_prompt
prompt = build_general_system_prompt(
["Alpha"],
app_context={
"vault": "Alpha",
"directory": "notes",
"current_path": "notes/a.md",
"open_documents": [{"vault": "Alpha", "path": "notes/a.md"}],
"search_query": "auth",
"search_total": 3,
"search_results": [{"vault": "Alpha", "path": "notes/auth.md"}],
},
recent_files=[{"vault": "Alpha", "path": "notes/recent.md"}],
)
assert "Contexte applicatif actuel" in prompt
assert "notes/a.md" in prompt
assert "notes/recent.md" in prompt
assert "auth" in prompt
def test_general_prompt_without_app_context_is_unchanged(self):
"""No context → no app-context block (backwards compatible)."""
from backend.bookslm import build_general_system_prompt
prompt = build_general_system_prompt(["Alpha"])
assert "Contexte applicatif actuel" not in prompt
def test_documents_prompt_scope(self):
from backend.bookslm import build_system_prompt