feat(server): R1 — import auto du workflow appris vers la DB VWB (gated)
finalize_session appelle _maybe_import_to_vwb : si RPA_R1_AUTO_IMPORT (OFF par défaut), le workflow appris est assaini (sanitize_workflow_dict) puis importé en DB VWB rejouable via le pont idempotent (import_core_workflow_to_db), dans un app-context VWB lazy mutualisé (vwb_db). NON bloquant : un échec n'interrompt jamais la finalisation. Rend l'appris rejouable sans geste manuel (R1). Tests : câblage du seam + gating du flag + non-régression. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3066,6 +3066,8 @@ class StreamProcessor:
|
||||
saved_path = self._persist_workflow(workflow, session_id, machine_id=machine_id)
|
||||
# Stocker le machine_id dans le workflow pour le filtrage
|
||||
workflow._machine_id = machine_id
|
||||
# R1 : import auto en DB VWB (rejouable) — gated RPA_R1_AUTO_IMPORT, non bloquant.
|
||||
self._maybe_import_to_vwb(workflow, session_id, machine_id)
|
||||
|
||||
# Récupérer les métadonnées applicatives de la session
|
||||
session_state = self.session_manager.get_session(session_id)
|
||||
@@ -4444,6 +4446,45 @@ class StreamProcessor:
|
||||
logger.error(f"Erreur sauvegarde workflow {session_id}: {e}")
|
||||
return None
|
||||
|
||||
def _import_workflow_to_vwb(self, workflow, session_id: str, machine_id: str) -> Dict[str, Any]:
|
||||
"""Importer le workflow appris dans la DB VWB rejouable (Maillon A / R1).
|
||||
|
||||
Rend l'appris rejouable sans geste manuel, de façon idempotente (fusion
|
||||
par signature de trajectoire). Suppose un app-context VWB actif fournissant
|
||||
``db.session`` (créé par l'appelant côté worker).
|
||||
"""
|
||||
from .pii_sanitizer import sanitize_workflow_dict
|
||||
from services.learned_workflow_bridge import import_core_workflow_to_db
|
||||
from db.models import db
|
||||
# Assainir la PII (cibles OCR `by_text`, noms) avant dépôt en DB VWB.
|
||||
core_dict = sanitize_workflow_dict(workflow.to_dict())
|
||||
return import_core_workflow_to_db(
|
||||
core_dict,
|
||||
machine_id=machine_id,
|
||||
source_session_id=session_id,
|
||||
db_session=db.session,
|
||||
)
|
||||
|
||||
def _vwb_app_context(self):
|
||||
"""Couplage worker→DB VWB mutualisé (un seul pont, cf. vwb_db).
|
||||
|
||||
Délègue au helper module ``vwb_db.vwb_app_context`` partagé entre R1 et
|
||||
l'extraction métier — pas de duplication de l'app Flask/init_app.
|
||||
"""
|
||||
from .vwb_db import vwb_app_context
|
||||
return vwb_app_context()
|
||||
|
||||
def _maybe_import_to_vwb(self, workflow, session_id: str, machine_id: str) -> None:
|
||||
"""Import auto de l'appris en DB VWB, gated par RPA_R1_AUTO_IMPORT (OFF
|
||||
par défaut) et NON bloquant : un échec ne casse jamais la finalisation."""
|
||||
if os.environ.get("RPA_R1_AUTO_IMPORT", "false").lower() not in ("true", "1", "yes"):
|
||||
return
|
||||
try:
|
||||
with self._vwb_app_context():
|
||||
self._import_workflow_to_vwb(workflow, session_id, machine_id)
|
||||
except Exception as e:
|
||||
logger.warning("[R1] import VWB auto échoué (non bloquant): %s", e)
|
||||
|
||||
def _build_raw_session_fallback(self, session, raw_dict):
|
||||
"""Construire un RawSession manuellement si from_dict échoue."""
|
||||
from core.models.raw_session import RawSession, Event, Screenshot, RawWindowContext
|
||||
|
||||
Reference in New Issue
Block a user