feat: menu + — Compétences-skills « Gérer » + « Parcourir » — phase 2/8 (v7.52.0)
- Sous-menu « Compétences-skills » : 11 skills builtin + skills enregistrés,
libellés affichés « Deep research » (/research) et « Skill-creator »
(/create-new-skill) via FD_SKILL_ALIAS (slugs intacts) ; le clic épingle le
skill au contexte, même chemin que la palette /.
- « Gérer les compétences » : section du menu + formulaire intégré (nom,
description, prompt) — création, édition, suppression (chip épinglé nettoyé),
export JSON téléchargé, import fichier avec overwrite (pas de doublon).
- « Parcourir les compétences » : section galerie filtrable (nom/description/
slug), installation en 1 clic (installGallerySkill réutilisé).
- PATCH /api/agent/skills/{skill_id} créé : édition partielle, whitelist de
colonnes, 400/401/404/409. OpenAPI régénéré : 515 chemins, version 7.52.0.
- En-tête ← + titre de section dans le menu (navigation à 3 niveaux).
- Fix : épingler un skill enregistré n'efface plus le message déjà tapé
(_pinDbSkill ne vide le composer que s'il est vide).
- Tests : tests/test_v752_skills_menu.py (7) + test_v751 adapté. Suite
complète 1280 verts (-n auto), ruff 0, eslint 0 problème.
This commit is contained in:
@@ -498,6 +498,43 @@ def create_skill(request: Request, body: dict = Body(default={})):
|
||||
return {"id": cur.lastrowid, "name": name, "status": "created"}
|
||||
|
||||
|
||||
@router.patch("/skills/{skill_id}")
|
||||
def update_skill(request: Request, skill_id: int, body: dict = Body(default={})):
|
||||
"""Édition d'un skill enregistré (v7.52.0 — « Gérer les compétences »).
|
||||
|
||||
Seuls les champs présents dans ``body`` sont mis à jour ; la liste des
|
||||
colonnes est figée ici (jamais interpolée depuis la requête).
|
||||
"""
|
||||
_current_user_id(request)
|
||||
fields: dict = {}
|
||||
if "name" in body:
|
||||
name = str(body.get("name") or "").strip()
|
||||
if not name:
|
||||
raise HTTPException(status_code=400, detail="name est requis")
|
||||
fields["name"] = name
|
||||
if "description" in body:
|
||||
fields["description"] = str(body.get("description") or "")
|
||||
if "prompt_template" in body:
|
||||
fields["prompt_template"] = str(body.get("prompt_template") or "")
|
||||
if "allowed_tools" in body:
|
||||
fields["allowed_tools_json"] = json.dumps(body.get("allowed_tools") or [])
|
||||
if not fields:
|
||||
raise HTTPException(status_code=400, detail="Aucun champ à mettre à jour")
|
||||
cols = ", ".join(f"{k}=?" for k in fields)
|
||||
with get_conn() as conn:
|
||||
if not conn.execute("SELECT id FROM agent_skills WHERE id=?", (skill_id,)).fetchone():
|
||||
raise HTTPException(status_code=404, detail="Skill introuvable")
|
||||
try:
|
||||
conn.execute(
|
||||
f"UPDATE agent_skills SET {cols} WHERE id=?",
|
||||
(*fields.values(), skill_id),
|
||||
)
|
||||
conn.commit()
|
||||
except Exception as exc: # noqa: BLE001 — contrainte UNIQUE(name)
|
||||
raise HTTPException(status_code=409, detail=f"Skill existe déjà: {exc}") from exc
|
||||
return {"id": skill_id, "status": "updated", "fields": sorted(fields)}
|
||||
|
||||
|
||||
@router.post("/skills/{skill_id}/apply")
|
||||
def apply_skill(request: Request, skill_id: int):
|
||||
"""Create a conversation pre-loaded with a skill, ready to run."""
|
||||
|
||||
Reference in New Issue
Block a user