feat(lea): expose competence replay api

This commit is contained in:
Dom
2026-05-29 13:40:15 +02:00
parent 8ea4ed0ad2
commit 7ef98d8089

View File

@@ -41,6 +41,16 @@ from .execution_plan_runner import (
inject_plan_into_queue,
)
try:
from core.competences.catalog import load_competences
from core.competences.replay import build_competence_replay_payload, find_competence
COMPETENCE_API_AVAILABLE = True
except Exception: # pragma: no cover - allows partial deployments
load_competences = None
build_competence_replay_payload = None
find_competence = None
COMPETENCE_API_AVAILABLE = False
# Pipeline d'anonymisation PII (OCR + NER côté serveur).
# Import paresseux : on ne charge pas docTR tant qu'aucune image n'est reçue.
try:
@@ -688,6 +698,14 @@ class RawReplayRequest(BaseModel):
params: Optional[Dict[str, Any]] = None
class CompetenceReplayRequest(BaseModel):
"""Requête de test/replay supervisé d'une compétence Léa YAML."""
supervised: bool = True
start_replay: bool = False
session_id: str = ""
machine_id: Optional[str] = None
class SingleActionRequest(BaseModel):
"""Requête d'exécution d'une seule action (mode Copilot)."""
action: Dict[str, Any]
@@ -2074,6 +2092,81 @@ async def list_workflows(machine_id: Optional[str] = None):
return result
def _require_competence_api() -> None:
if not COMPETENCE_API_AVAILABLE:
raise HTTPException(status_code=503, detail="Catalogue compétences Léa indisponible")
def _parse_competence_states(state: Optional[str]) -> Optional[List[str]]:
if not state:
return None
states = [part.strip() for part in state.split(",") if part.strip()]
return states or None
@app.get("/api/v1/lea/competences")
async def list_lea_competences(state: Optional[str] = None):
"""Lister les compétences YAML connues par Léa, sans dépendance au VWB."""
_require_competence_api()
states = _parse_competence_states(state)
competences = load_competences(states=states) # type: ignore[misc]
return {
"success": True,
"competences": [competence.to_dict() for competence in competences],
"total": len(competences),
"states_filter": states,
}
@app.get("/api/v1/lea/competences/{competence_id}")
async def get_lea_competence(competence_id: str):
"""Retourner une compétence YAML et son plan de test supervisé."""
_require_competence_api()
try:
competence = find_competence(competence_id) # type: ignore[misc]
payload = build_competence_replay_payload(competence_id, supervised=True) # type: ignore[misc]
except KeyError:
raise HTTPException(status_code=404, detail=f"Compétence '{competence_id}' introuvable")
return {
"success": True,
"competence": competence.to_dict(),
"supervised_replay_preview": payload,
}
@app.post("/api/v1/lea/competences/{competence_id}/replay")
async def replay_lea_competence(competence_id: str, request: CompetenceReplayRequest):
"""Planifier ou lancer le replay supervisé d'une compétence Léa YAML."""
_require_competence_api()
try:
payload = build_competence_replay_payload( # type: ignore[misc]
competence_id,
supervised=request.supervised,
machine_id=request.machine_id,
session_id=request.session_id,
)
except KeyError:
raise HTTPException(status_code=404, detail=f"Compétence '{competence_id}' introuvable")
if not request.start_replay:
return {
"success": True,
"status": "planned",
"competence_id": competence_id,
"raw_replay_payload": payload,
}
replay_request = RawReplayRequest(**payload)
replay_result = await start_raw_replay(replay_request)
return {
"success": True,
"status": "started",
"competence_id": competence_id,
"raw_replay_payload": payload,
"replay": replay_result,
}
@app.post("/api/v1/traces/stream/reload-workflows")
async def reload_workflows():
"""Recharger les workflows depuis le disque.