feat(vwb): execute wait for state
This commit is contained in:
@@ -28,6 +28,7 @@ from .vision_ui.focus_anchor import VWBFocusAnchorAction
|
||||
from .vision_ui.type_secret import VWBTypeSecretAction
|
||||
from .vision_ui.scroll_to_anchor import VWBScrollToAnchorAction
|
||||
from .vision_ui.extract_text import VWBExtractTextAction
|
||||
from .control.wait_for_state import VWBWaitForStateAction
|
||||
from .registry import (
|
||||
VWBActionRegistry,
|
||||
get_global_registry,
|
||||
@@ -50,6 +51,7 @@ __all__ = [
|
||||
'VWBTypeSecretAction',
|
||||
'VWBScrollToAnchorAction',
|
||||
'VWBExtractTextAction',
|
||||
'VWBWaitForStateAction',
|
||||
'VWBActionRegistry',
|
||||
'get_global_registry',
|
||||
'register_action',
|
||||
@@ -62,4 +64,4 @@ __all__ = [
|
||||
|
||||
__version__ = '1.1.0'
|
||||
__author__ = 'Dom, Alice, Kiro'
|
||||
__date__ = '10 janvier 2026'
|
||||
__date__ = '10 janvier 2026'
|
||||
|
||||
@@ -4,10 +4,13 @@ Auteur : Dom, Claude - 14 janvier 2026
|
||||
|
||||
Ce module contient les actions de contrôle de flux :
|
||||
- keyboard_shortcut : Raccourcis clavier
|
||||
- wait_for_state : Attente d'etat semantique
|
||||
"""
|
||||
|
||||
from .keyboard_shortcut import VWBKeyboardShortcutAction
|
||||
from .wait_for_state import VWBWaitForStateAction
|
||||
|
||||
__all__ = [
|
||||
'VWBKeyboardShortcutAction',
|
||||
'VWBWaitForStateAction',
|
||||
]
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
"""VWB action that waits for a semantic screen state."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from ..base_action import BaseVWBAction, VWBActionResult, VWBActionStatus
|
||||
from ...contracts.error import VWBErrorType, create_vwb_error
|
||||
from ...services.wait_for_state import wait_for_expected_state, StateProvider
|
||||
|
||||
|
||||
class VWBWaitForStateAction(BaseVWBAction):
|
||||
"""Wait until the foreground window/process matches an expected state."""
|
||||
|
||||
SUPPORTED_EVIDENCE = {"window_or_process"}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
action_id: str,
|
||||
parameters: Dict[str, Any],
|
||||
screen_capturer=None,
|
||||
state_provider: Optional[StateProvider] = None,
|
||||
):
|
||||
super().__init__(
|
||||
action_id=action_id,
|
||||
name="Attendre un etat",
|
||||
description="Attend un etat semantique d'ecran",
|
||||
parameters=parameters,
|
||||
screen_capturer=screen_capturer,
|
||||
)
|
||||
self.expected_state = parameters.get("expected_state") or {}
|
||||
self.timeout_ms = int(parameters.get("timeout_ms", 5000))
|
||||
self.poll_interval_ms = int(parameters.get("poll_interval_ms", 250))
|
||||
self.evidence_required = parameters.get(
|
||||
"evidence_required", "window_or_process"
|
||||
)
|
||||
self.state_provider = state_provider or parameters.get("_state_provider")
|
||||
|
||||
def validate_parameters(self) -> List[str]:
|
||||
errors: List[str] = []
|
||||
|
||||
if not isinstance(self.expected_state, dict) or not self.expected_state:
|
||||
errors.append("expected_state requis")
|
||||
|
||||
criteria = (
|
||||
"window_title_in",
|
||||
"window_title_contains",
|
||||
"process_active",
|
||||
)
|
||||
if isinstance(self.expected_state, dict) and not any(
|
||||
self.expected_state.get(key) for key in criteria
|
||||
):
|
||||
errors.append(
|
||||
"expected_state doit definir window_title_in, "
|
||||
"window_title_contains ou process_active"
|
||||
)
|
||||
|
||||
if self.timeout_ms < 100:
|
||||
errors.append("timeout_ms doit etre >= 100")
|
||||
if self.poll_interval_ms < 50:
|
||||
errors.append("poll_interval_ms doit etre >= 50")
|
||||
if self.evidence_required not in self.SUPPORTED_EVIDENCE:
|
||||
errors.append(
|
||||
f"evidence_required non supporte: {self.evidence_required}"
|
||||
)
|
||||
|
||||
return errors
|
||||
|
||||
def execute_core(self, step_id: str) -> VWBActionResult:
|
||||
start_time = datetime.now()
|
||||
wait_result = wait_for_expected_state(
|
||||
expected_state=self.expected_state,
|
||||
timeout_ms=self.timeout_ms,
|
||||
poll_interval_ms=self.poll_interval_ms,
|
||||
evidence_required=self.evidence_required,
|
||||
state_provider=self.state_provider,
|
||||
)
|
||||
end_time = datetime.now()
|
||||
execution_time = (end_time - start_time).total_seconds() * 1000
|
||||
output = wait_result.to_dict()
|
||||
|
||||
if wait_result.matched:
|
||||
return VWBActionResult(
|
||||
action_id=self.action_id,
|
||||
step_id=step_id,
|
||||
status=VWBActionStatus.SUCCESS,
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
execution_time_ms=execution_time,
|
||||
output_data=output,
|
||||
evidence_list=self.evidence_list.copy(),
|
||||
)
|
||||
|
||||
error = create_vwb_error(
|
||||
error_type=VWBErrorType.WAIT_TIMEOUT,
|
||||
message="Etat attendu non observe avant timeout",
|
||||
action_id=self.action_id,
|
||||
step_id=step_id,
|
||||
technical_details=output,
|
||||
execution_time_ms=execution_time,
|
||||
)
|
||||
return VWBActionResult(
|
||||
action_id=self.action_id,
|
||||
step_id=step_id,
|
||||
status=VWBActionStatus.TIMEOUT,
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
execution_time_ms=execution_time,
|
||||
output_data=output,
|
||||
evidence_list=self.evidence_list.copy(),
|
||||
error=error,
|
||||
)
|
||||
Reference in New Issue
Block a user