79 lines
3.3 KiB
Python
79 lines
3.3 KiB
Python
"""Fusion ACC-4.5 — conversion d'Agents & Skills Flowdeck au format
|
|
commun (contrat ACC-0.3, `dracodev-commons/contrats/skill-format.md`).
|
|
|
|
Preuve du format : trois presets de la galerie Flowdeck convertis en
|
|
`skills-communs/<nom>/SKILL.md` (compte-rendu-reunion, rapport-hebdo,
|
|
resume-document). Ils doivent être conformes au contrat, se convertir
|
|
en champs Flowdeck et s'installer dans un workspace via le chemin
|
|
existant (`skill_gallery.upsert_skill`).
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from app.services import skill_format, skill_gallery
|
|
|
|
RACINE = Path(__file__).resolve().parent.parent
|
|
CONVERTIS = ["compte-rendu-reunion", "rapport-hebdo", "resume-document"]
|
|
|
|
|
|
def _lire(nom: str) -> str:
|
|
return (RACINE / "skills-communs" / nom / "SKILL.md").read_text(encoding="utf-8")
|
|
|
|
|
|
def test_trois_skills_convertis_conformes():
|
|
for nom in CONVERTIS:
|
|
skill = skill_format.analyser_skill_md(_lire(nom))
|
|
assert skill_format.valider(skill) == [], (nom, skill_format.valider(skill))
|
|
assert skill["meta"]["name"] == nom
|
|
assert skill["meta"]["apps"] == ["flowdeck"]
|
|
assert skill["meta"]["version"] == "1.0.0"
|
|
# Toute écriture est déclarée, avec approbation explicite.
|
|
actions = {e["action"] for e in skill["meta"]["ecritures"]}
|
|
assert actions == {"flowdeck.create_document", "flowdeck.write_blocks"}
|
|
|
|
|
|
def test_conversion_vers_flowdeck_et_installation(client):
|
|
for nom in CONVERTIS:
|
|
skill = skill_format.analyser_skill_md(_lire(nom))
|
|
champs = skill_format.vers_champs_flowdeck(skill)
|
|
assert champs["name"] == nom
|
|
assert set(champs["allowed_tools"]) == {
|
|
"search_workspace", "read_document", "create_document", "write_blocks"}
|
|
assert "Procédure" in champs["prompt_template"]
|
|
assert "Garde-fous" in champs["prompt_template"]
|
|
row, cree = skill_gallery.upsert_skill(
|
|
champs, workspace_id=None, created_by=1)
|
|
assert cree is True and row["name"] == nom
|
|
|
|
|
|
def test_validation_rejette_les_ecarts():
|
|
incomplet = skill_format.analyser_skill_md(
|
|
"---\nname: mauvais nom\napps: [flowdeck]\n---\n\n## Procédure\n\nx\n")
|
|
erreurs = skill_format.valider(incomplet)
|
|
assert any("kebab" in e for e in erreurs)
|
|
assert any("description" in e for e in erreurs)
|
|
assert any("Quand l'utiliser" in e for e in erreurs)
|
|
with pytest.raises(ValueError):
|
|
skill_format.vers_champs_flowdeck(incomplet)
|
|
|
|
|
|
def test_ecritures_obligatoires_si_outil_ecrivant():
|
|
texte = (
|
|
"---\nname: supprime-tout\ndescription: x\nversion: 1.0.0\n"
|
|
"apps: [flowdeck]\ndomaines: [pro]\noutils: [flowdeck.delete_page]\n---\n\n"
|
|
"## Quand l'utiliser\n\nx\n\n## Procédure\n\nx\n\n## Garde-fous\n\nx\n")
|
|
erreurs = skill_format.valider(skill_format.analyser_skill_md(texte))
|
|
assert any("ecritures obligatoire" in e for e in erreurs)
|
|
|
|
|
|
def test_aller_retour_depuis_un_preset():
|
|
preset = skill_gallery.get_gallery("compte-rendu-reunion")
|
|
texte = skill_format.depuis_preset_flowdeck(preset, domaines=["pro"])
|
|
skill = skill_format.analyser_skill_md(texte)
|
|
assert skill_format.valider(skill) == []
|
|
champs = skill_format.vers_champs_flowdeck(skill)
|
|
assert champs["name"] == "compte-rendu-de-reunion"
|
|
assert "create_document" in champs["allowed_tools"]
|