feat(executor): P1 DialogResolver serveur en fallback du catalog local
Léa avait déjà une infra pour les dialogs runtime (`_match_known_runtime_dialog` + `_handle_known_runtime_dialog`) mais avec un catalog local limité à 2 entrées. Le DialogResolver R2 côté serveur a 10 entrées centralisées. P1.MVP : `_try_dialog_resolver_server()` consulte l'endpoint `/api/v1/dialog/resolve` quand le catalog local n'a pas matché. La réponse `DialogResolution` est convertie en dialog_spec compatible avec `_handle_known_runtime_dialog` qui réutilise la cascade existante (serveur VLM grounding + template matching local). - Flag `RPA_DIALOG_RESOLVER_AGENT_ENABLED` (OFF par défaut) — rollback runtime - Auth Bearer via `_auth_headers()` existant - Timeout 3s, fail-safe sur exception/503/no-match → fallback humain intact - Zéro régression sur les chemins existants (le catalog local reste 1ère ligne) Tests unitaires en local (6/6 OK) : - flag OFF → None - serveur 503 → None - matched=False → None - policy=pause (UAC) → None - match auto + click_button → dialog_spec valide - exception réseau → None Tag rollback : rollback/pre-P1-2026-05-24_2105
This commit is contained in:
@@ -675,6 +675,68 @@ class ActionExecutorV1:
|
||||
)
|
||||
return None
|
||||
|
||||
def _try_dialog_resolver_server(
|
||||
self,
|
||||
current_title: str,
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""P1 : fallback DialogResolver serveur si catalog local pas de match.
|
||||
|
||||
Léa interroge l'endpoint ``/api/v1/dialog/resolve`` qui consulte
|
||||
le catalog centralisé (10 entrées vs 2 locales). Si match auto +
|
||||
action click_button, convertit le format ``DialogResolution`` en
|
||||
``dialog_spec`` compatible avec ``_handle_known_runtime_dialog``
|
||||
(réutilise la cascade serveur VLM + template existante).
|
||||
|
||||
Désactivé si ``RPA_DIALOG_RESOLVER_AGENT_ENABLED`` n'est pas
|
||||
positionné (flag agent séparé du flag serveur). Retour ``None``
|
||||
sur 503 (flag serveur OFF), pas de match, policy != auto, ou
|
||||
action incompatible.
|
||||
"""
|
||||
if os.environ.get("RPA_DIALOG_RESOLVER_AGENT_ENABLED", "").lower() not in (
|
||||
"1", "true", "yes", "on"
|
||||
):
|
||||
return None
|
||||
try:
|
||||
from ..config import SERVER_URL
|
||||
import requests as _requests
|
||||
if not SERVER_URL:
|
||||
return None
|
||||
resp = _requests.post(
|
||||
f"{SERVER_URL.rstrip('/')}/api/v1/dialog/resolve",
|
||||
json={"current_title": current_title, "evidence_texts": []},
|
||||
headers=self._auth_headers(),
|
||||
timeout=3,
|
||||
)
|
||||
if not resp.ok:
|
||||
return None
|
||||
data = resp.json()
|
||||
if not data.get("matched") or data.get("policy") != "auto":
|
||||
return None
|
||||
action = data.get("action") or {}
|
||||
if action.get("type") != "click_button":
|
||||
return None
|
||||
button_labels = action.get("fallback_button_labels") or []
|
||||
if action.get("button_label"):
|
||||
button_labels = [action["button_label"]] + [
|
||||
b for b in button_labels if b != action["button_label"]
|
||||
]
|
||||
button_labels = tuple(b for b in button_labels if b)
|
||||
if not button_labels:
|
||||
return None
|
||||
logger.info(
|
||||
f"[P1-DialogResolver] Match serveur: dialog={data.get('dialog_id')} "
|
||||
f"button_texts={button_labels}"
|
||||
)
|
||||
return {
|
||||
"id": f"server:{data.get('dialog_id')}",
|
||||
"title_patterns": (),
|
||||
"button_texts": button_labels,
|
||||
"skip_current_action_after_handle": True,
|
||||
}
|
||||
except Exception as exc:
|
||||
logger.warning(f"[P1-DialogResolver] échec: {exc}")
|
||||
return None
|
||||
|
||||
def _maybe_handle_runtime_dialog_before_pause(
|
||||
self,
|
||||
action: Dict[str, Any],
|
||||
@@ -691,6 +753,9 @@ class ActionExecutorV1:
|
||||
on applique le reflexe associe.
|
||||
"""
|
||||
dialog_spec = self._match_known_runtime_dialog(current_title)
|
||||
if not dialog_spec:
|
||||
# P1 : fallback DialogResolver serveur si catalog local pas de match
|
||||
dialog_spec = self._try_dialog_resolver_server(current_title)
|
||||
if not dialog_spec:
|
||||
return None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user