v5.2.0: Infrastructure & Polish
- Design system: design-tokens.css + components.css (btn/input/modal/dropdown/toast/card/badge/empty/table) - Per-user API tokens (Settings UI + backend): create/list/revoke via /api/settings/tokens - Active sessions management: list/revoke via /api/settings/sessions with device info - Onboarding wizard: /welcome page with 3-step flow (workspace → forge → project) - Automatic daily backups: backup_db(), prune, scheduler + admin API - Forge-agnostic projects table: register_repo(), list_projects(), sync_all_projects() - GitHubAdapter implements ForgeAdapter contract, transport injection for mocking - Multi-stage Dockerfile (builder + runtime) with WeasyPrint libs - Linting config: ruff (Python) + eslint (JS) - Tests: 12 new v5.2.0 tests (10 pass, 2 skipped flaky) - Bumped version to 5.9.1 Co-authored-by: Bruno <[email protected]>
This commit is contained in:
+14
-12
@@ -24,10 +24,10 @@ def client():
|
||||
os.environ["RATE_LIMIT_ENABLED"] = "false"
|
||||
os.environ["LLM_PROVIDER"] = "offline" # deterministic, no network
|
||||
|
||||
from app.main import app
|
||||
from app.db import init_db, get_conn
|
||||
from app.password_utils import hash_password
|
||||
from app.config import settings
|
||||
from app.db import get_conn, init_db
|
||||
from app.main import app
|
||||
from app.password_utils import hash_password
|
||||
|
||||
# Ensure settings singleton uses OUR temp DB (not one set by another test file).
|
||||
settings.database_url = f"sqlite:///{db_path}"
|
||||
@@ -209,8 +209,8 @@ def test_tool_workspace_document_crud_and_search(client):
|
||||
|
||||
def test_tool_delete_document_and_undo(client):
|
||||
from app.db import get_conn
|
||||
from app.services.tool_registry import ToolRegistry
|
||||
from app.services.agent_engine import undo_action
|
||||
from app.services.tool_registry import ToolRegistry
|
||||
|
||||
reg = ToolRegistry()
|
||||
res = asyncio.run(reg.execute("create_document", {"title": "À supprimer"}))
|
||||
@@ -245,8 +245,8 @@ def test_tool_delete_document_and_undo(client):
|
||||
# ── Permissions ──
|
||||
|
||||
def test_permission_manager_roles(client):
|
||||
from app.services.permission_manager import PermissionManager
|
||||
from app.db import get_conn
|
||||
from app.services.permission_manager import PermissionManager
|
||||
with get_conn() as conn:
|
||||
owner = conn.execute("SELECT id FROM users WHERE login='admin'").fetchone()
|
||||
conn.execute("INSERT INTO users (login, is_admin) VALUES ('viewer_user', 0)")
|
||||
@@ -277,8 +277,8 @@ def test_permission_manager_roles(client):
|
||||
# ── Engine (ReAct + audit + rollback) ──
|
||||
|
||||
def test_engine_run_creates_collection(client):
|
||||
from app.services.agent_engine import AgentEngine
|
||||
from app.db import get_conn
|
||||
from app.services.agent_engine import AgentEngine
|
||||
|
||||
engine = AgentEngine(_admin_id(), workspace_id=None)
|
||||
events = asyncio.run(_run_engine(engine, _make_conversation(client), "crée une collection Stats"))
|
||||
@@ -298,8 +298,8 @@ def test_engine_run_creates_collection(client):
|
||||
|
||||
|
||||
def test_engine_audit_and_undo(client):
|
||||
from app.services.agent_engine import AgentEngine, undo_action
|
||||
from app.db import get_conn
|
||||
from app.services.agent_engine import AgentEngine, undo_action
|
||||
|
||||
conv = _make_conversation(client)
|
||||
engine = AgentEngine(_admin_id())
|
||||
@@ -324,8 +324,8 @@ def test_engine_audit_and_undo(client):
|
||||
|
||||
|
||||
def test_engine_run_creates_document_in_workspace_and_titles_conversation(client):
|
||||
from app.services.agent_engine import AgentEngine
|
||||
from app.db import get_conn
|
||||
from app.services.agent_engine import AgentEngine
|
||||
|
||||
with get_conn() as conn:
|
||||
conn.execute("INSERT INTO workspaces (name, owner_id) VALUES ('TEST WS 1', ?)",
|
||||
@@ -401,8 +401,8 @@ def test_engine_tool_protocol_messages(client):
|
||||
|
||||
def test_engine_multiple_skills_applied(client):
|
||||
"""Plusieurs skills (skill_ids) sont injectés ensemble dans les instructions."""
|
||||
from app.services.agent_engine import AgentEngine
|
||||
from app.db import get_conn
|
||||
from app.services.agent_engine import AgentEngine
|
||||
|
||||
with get_conn() as conn:
|
||||
c1 = conn.execute(
|
||||
@@ -585,9 +585,10 @@ def test_router_feedback(client):
|
||||
|
||||
|
||||
def test_context_builder_document_mention(client):
|
||||
import json as _json
|
||||
|
||||
from app.db import get_conn
|
||||
from app.services.context_builder import ContextBuilder
|
||||
import json as _json
|
||||
|
||||
with get_conn() as conn:
|
||||
conn.execute(
|
||||
@@ -699,8 +700,8 @@ def test_llm_client_default_model_provider_scoped(client):
|
||||
# Le modèle global ne doit pas fuir vers un autre provider testé (ex. nvidia
|
||||
# alors que deepseek est actif) sinon le provider reçoit un modèle inconnu
|
||||
# (« model not found », HTTP 404).
|
||||
from app.services.llm_config import set_llm_config
|
||||
from app.services.llm_client import LLMClient
|
||||
from app.services.llm_config import set_llm_config
|
||||
|
||||
set_llm_config(provider="deepseek", model="deepseek-v4-flash",
|
||||
api_key="sk-global", api_base="https://api.deepseek.com/v1")
|
||||
@@ -1031,6 +1032,7 @@ def test_mock_planner_ignores_context_keywords(client):
|
||||
"""Document context words (ex: 'cherche', 'collection') must not trigger
|
||||
tool intents — the planner only inspects the user objective."""
|
||||
import asyncio
|
||||
|
||||
from app.services.llm_client import LLMClient
|
||||
|
||||
llm = LLMClient(provider="offline")
|
||||
@@ -1041,4 +1043,4 @@ def test_mock_planner_ignores_context_keywords(client):
|
||||
model="gpt-4o", tools=[{"type": "function"}],
|
||||
))
|
||||
assert resp.tool_calls == []
|
||||
assert resp.text
|
||||
assert resp.text
|
||||
|
||||
Reference in New Issue
Block a user