feat(verify): add compound action+verify flows
All checks were successful
python-syntax / syntax-check (push) Successful in 9s

This commit is contained in:
2026-05-01 16:26:57 +02:00
parent 02bf069425
commit c66779d929
4 changed files with 111 additions and 4 deletions

View File

@@ -278,6 +278,16 @@ class VisionStabilityRequest(BaseModel):
diff_threshold: float = Field(default=0.01, ge=0.0, le=1.0)
class VerifyActionRequest(BaseModel):
action: ActionRequest
condition: WaitTextCondition | WaitWindowCondition | WaitVisualCondition
retries: int = Field(default=0, ge=0, le=10)
timeout_ms: int = Field(default=5000, ge=0, le=120000)
poll_interval_ms: int = Field(default=250, ge=50, le=10000)
retry_delay_ms: int = Field(default=200, ge=0, le=60000)
stop_on_action_error: bool = True
def _auth(x_clickthrough_token: Optional[str] = Header(default=None)):
token = SETTINGS["token"]
@@ -1015,6 +1025,53 @@ def _measure_stability(req: VisionStabilityRequest, screen: int = 0) -> dict:
}
def _run_verified_action(req: VerifyActionRequest, screen: int = 0) -> dict:
attempts = []
for attempt in range(req.retries + 1):
action_ok = True
action_result = None
action_error = None
try:
action_result = _exec_action(req.action, screen)
except Exception as exc:
action_ok = False
action_error = str(exc)
if req.stop_on_action_error:
attempts.append(
{
"attempt": attempt,
"action_ok": action_ok,
"action_error": action_error,
"verification": None,
}
)
return {"success": False, "attempts": attempts, "final_attempt": attempt}
verification = _wait_for_condition(
WaitRequest(
condition=req.condition,
timeout_ms=req.timeout_ms,
poll_interval_ms=req.poll_interval_ms,
),
screen,
)
attempts.append(
{
"attempt": attempt,
"action_ok": action_ok,
"action_error": action_error,
"action_result": action_result,
"verification": verification,
}
)
if verification.get("satisfied"):
return {"success": True, "attempts": attempts, "final_attempt": attempt}
if attempt < req.retries and req.retry_delay_ms > 0:
time.sleep(req.retry_delay_ms / 1000.0)
return {"success": False, "attempts": attempts, "final_attempt": req.retries}
def _wait_for_condition(req: WaitRequest, screen: int = 0) -> dict:
condition = req.condition
deadline = time.time() + (req.timeout_ms / 1000.0)
@@ -1572,6 +1629,17 @@ def vision_stability(req: VisionStabilityRequest, screen: int = 0, _: None = Dep
}
@app.post("/action/verify")
def action_verify(req: VerifyActionRequest, screen: int = 0, _: None = Depends(_auth)):
result = _run_verified_action(req, screen)
return {
"ok": result.get("success", False),
"request_id": _request_id(),
"time_ms": _now_ms(),
"result": result,
}
@app.post("/ocr")
def ocr(req: OCRRequest, screen: int = 0, _: None = Depends(_auth)):
image, region, mon, displays, screen_selection, source = _capture_ocr_source(req, screen)