7.77.0 — corbeille réparée (FK favorites/recents) + MCP workspaces
- detach_page_references : nettoyage des références NO ACTION avant toute suppression définitive (unitaire, Empty Trash, purge 30 j) - MCP : list_workspaces / get_workspace ; descriptions collections clarifiées (bases de données, pas des workspaces) - 96 tests verts sur le périmètre (MCP, trash, cohérence)
This commit is contained in:
@@ -10,9 +10,11 @@ Authentification : les jetons d'API personnels existants
|
||||
Le service d'agents reçoit un jeton dédié créé par l'utilisateur ;
|
||||
il lit et écrit en son nom.
|
||||
|
||||
Objet exposé : les **collections** (les projets/espaces de travail
|
||||
de Flowdeck) et leurs pages, la recherche par titre, et le registre
|
||||
des dépôts (table ``projects``). Doctrine du programme : Flowdeck
|
||||
Objets exposés : les **workspaces** (conteneurs de pages) et leurs
|
||||
pages, les **collections** (bases de données type Notion — ne pas
|
||||
confondre : une collection vit dans un workspace ou une page), la
|
||||
recherche par titre, et le registre des dépôts (table ``projects``).
|
||||
Doctrine du programme : Flowdeck
|
||||
référence les tâches, il ne les copie pas — aucune tâche TikTak ne
|
||||
transite par ici. Écritures limitées à la création/mise à jour de
|
||||
pages et à la création de collections ; aucune suppression.
|
||||
@@ -30,9 +32,24 @@ from app.routers.public_api import _token_owner
|
||||
router = APIRouter(tags=["mcp"])
|
||||
|
||||
OUTILS = [
|
||||
{"name": "list_workspaces",
|
||||
"description": "Liste les WORKSPACES Flowdeck — les conteneurs de pages "
|
||||
"de l'utilisateur (ex. Techno, Famille Charest), avec leur "
|
||||
"nombre de pages actives. À ne pas confondre avec les "
|
||||
"collections (bases de données).",
|
||||
"inputSchema": {"type": "object", "properties": {}}},
|
||||
{"name": "get_workspace",
|
||||
"description": "Lit un workspace et l'arborescence de ses pages "
|
||||
"(titres, parent, section) — pages classiques, pas les "
|
||||
"lignes des collections.",
|
||||
"inputSchema": {"type": "object",
|
||||
"properties": {"id": {"type": "integer"}},
|
||||
"required": ["id"]}},
|
||||
{"name": "list_collections",
|
||||
"description": "Liste les collections Flowdeck (projets / espaces de travail) "
|
||||
"avec leur nombre de pages.",
|
||||
"description": "Liste les COLLECTIONS Flowdeck — les bases de données "
|
||||
"de type Notion (tables, CRM, calendriers, formulaires), "
|
||||
"avec leur nombre de lignes. Ce ne sont PAS les workspaces : "
|
||||
"une collection vit dans un workspace ou dans une page.",
|
||||
"inputSchema": {"type": "object", "properties": {}}},
|
||||
{"name": "get_collection",
|
||||
"description": "Lit une collection et ses pages (titres et propriétés).",
|
||||
@@ -97,6 +114,25 @@ def _page_resume(row) -> dict:
|
||||
|
||||
def _appel_outil(nom: str, args: dict):
|
||||
with get_conn() as conn:
|
||||
if nom == "list_workspaces":
|
||||
rows = conn.execute(
|
||||
"SELECT w.id, w.name, w.owner_id, "
|
||||
"(SELECT COUNT(*) FROM pages p WHERE p.workspace_id = w.id "
|
||||
" AND p.deleted_at IS NULL) AS page_count "
|
||||
"FROM workspaces w ORDER BY w.name").fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
if nom == "get_workspace":
|
||||
ws = conn.execute("SELECT * FROM workspaces WHERE id = ?",
|
||||
(int(args.get("id", 0)),)).fetchone()
|
||||
if ws is None:
|
||||
return {"erreur": "workspace introuvable"}
|
||||
pages = conn.execute(
|
||||
"SELECT id, title, parent_id, parent_section, updated_at "
|
||||
"FROM pages WHERE workspace_id = ? AND deleted_at IS NULL "
|
||||
"ORDER BY parent_id, title LIMIT 300", (ws["id"],)).fetchall()
|
||||
return {"workspace": {"id": ws["id"], "name": ws["name"],
|
||||
"owner_id": ws["owner_id"]},
|
||||
"pages": [dict(p) for p in pages]}
|
||||
if nom == "list_collections":
|
||||
rows = conn.execute(
|
||||
"SELECT c.*, (SELECT COUNT(*) FROM collection_pages p "
|
||||
|
||||
Reference in New Issue
Block a user