feat(vwb): log supervised competence verdicts
This commit is contained in:
@@ -49,6 +49,7 @@ def competence_yaml_to_vwb_preview(
|
||||
"review_status": "preview",
|
||||
"tags": ["lea", "competence", competence.learning_state],
|
||||
"competence_id": competence.id,
|
||||
"verdict_endpoint": f"/api/v1/lea/competences/{competence.id}/verdict",
|
||||
"learning_state": competence.learning_state,
|
||||
"source_path": competence.source_path,
|
||||
"readonly": True,
|
||||
@@ -120,6 +121,8 @@ def _method_to_vwb_step(
|
||||
"timeout_ms": int(params.get("timeout_ms", 5000)),
|
||||
"poll_interval_ms": int(params.get("poll_interval_ms", 250)),
|
||||
"evidence_required": params.get("evidence_required", "window_or_process"),
|
||||
"supervised_popup_detection": True,
|
||||
"popup_policy": "pause_only",
|
||||
**source_params,
|
||||
}
|
||||
return _step(
|
||||
@@ -185,6 +188,7 @@ def _pause_step(
|
||||
"message": message,
|
||||
"phase": phase,
|
||||
"verdict_required": verdict_required,
|
||||
"verdict_endpoint": f"/api/v1/lea/competences/{competence.id}/verdict",
|
||||
"competence_id": competence.id,
|
||||
"source": f"lea_competence:{competence.id}",
|
||||
"write_back_enabled": False,
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
"""Helpers for supervised popup detection without auto-resolution."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, Mapping, Optional
|
||||
|
||||
|
||||
def build_unexpected_popup_pause(
|
||||
detected_popup: Optional[Mapping[str, Any]],
|
||||
*,
|
||||
expected_state: Mapping[str, Any],
|
||||
competence_id: str = "",
|
||||
source_method_id: str = "",
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""Return a human-pause payload when a detected popup is not expected."""
|
||||
|
||||
if not detected_popup:
|
||||
return None
|
||||
|
||||
popup = dict(detected_popup)
|
||||
popup_title = _popup_title(popup)
|
||||
if popup_title and _title_is_expected(popup_title, expected_state):
|
||||
return None
|
||||
|
||||
competence_label = f" pour {competence_id}" if competence_id else ""
|
||||
title_label = popup_title or str(popup.get("pattern") or "popup inconnue")
|
||||
return {
|
||||
"needs_human": True,
|
||||
"pause_reason": "unexpected_popup",
|
||||
"message": (
|
||||
f"Popup inattendue detectee{competence_label}: '{title_label}'. "
|
||||
"Mode supervise: aucune resolution automatique n'est lancee."
|
||||
),
|
||||
"detected_popup": popup,
|
||||
"expected_state": dict(expected_state or {}),
|
||||
"competence_id": competence_id,
|
||||
"source_method_id": source_method_id,
|
||||
"auto_resolution": False,
|
||||
"write_back_enabled": False,
|
||||
}
|
||||
|
||||
|
||||
def _popup_title(popup: Mapping[str, Any]) -> str:
|
||||
for key in ("title", "window_title", "target", "pattern", "name"):
|
||||
value = popup.get(key)
|
||||
if isinstance(value, str) and value.strip():
|
||||
return value.strip()
|
||||
return ""
|
||||
|
||||
|
||||
def _title_is_expected(title: str, expected_state: Mapping[str, Any]) -> bool:
|
||||
normalized = _norm(title)
|
||||
exact = expected_state.get("window_title_in")
|
||||
if isinstance(exact, str):
|
||||
exact = [exact]
|
||||
if isinstance(exact, list) and any(_norm(candidate) == normalized for candidate in exact):
|
||||
return True
|
||||
|
||||
contains = expected_state.get("window_title_contains")
|
||||
if isinstance(contains, str):
|
||||
contains = [contains]
|
||||
if isinstance(contains, list) and any(_norm(candidate) in normalized for candidate in contains):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _norm(value: Any) -> str:
|
||||
return str(value or "").strip().casefold()
|
||||
Reference in New Issue
Block a user