feat(android): add state conditions and measured gesture feedback
Add optional ensure_state, gesture region and final value feedback shared by Flash and Pro. Preserve completed inputs when verification fails and stop repeated ineffective strategies. Regenerate pinned tool schemas for the new optional arguments.
This commit is contained in:
1 parent
6a69a595ef
commit
4ea7939d9c
20 files changed
+2779
-33
No files matched your search
@@ -158,10 +158,10 @@ async def _pause(deadline: float, interval: float) -> None:
|
||||
|
||||
def _condition(request: WaitUntilRequest, node: dict) -> bool:
|
||||
state = request.state
|
||||
if state == "text":
|
||||
if node.get("password") is True or not isinstance(node.get("text"), str):
|
||||
if state in {"text", "content_desc"}:
|
||||
if node.get("password") is True or not isinstance(node.get(state), str):
|
||||
raise ValueError("An exact readable native text value is required.")
|
||||
return node["text"] == request.expected_text
|
||||
return node[state] == request.expected_text
|
||||
if state == "value":
|
||||
native_range = _range(node)
|
||||
if native_range is None or request.expected_value is None:
|
||||
@@ -268,6 +268,23 @@ async def _control(request: ControlActionRequest, native: NativeCaller) -> dict:
|
||||
if not inspection["success"]:
|
||||
return _result("control_action", inspection)
|
||||
node = inspection["node"]
|
||||
condition = None
|
||||
if request.ensure_state is not None:
|
||||
condition = WaitUntilRequest(
|
||||
selector=request.selector,
|
||||
timeout_ms=request.verify_timeout_ms,
|
||||
**request.ensure_state.model_dump(),
|
||||
)
|
||||
try:
|
||||
satisfied = _condition(condition, node)
|
||||
except ValueError as exc:
|
||||
return _result(
|
||||
"control_action", _failure("INVALID_STATE", str(exc)), preflight=inspection
|
||||
)
|
||||
if satisfied:
|
||||
return _result(
|
||||
"control_action", inspection, skipped=True, verification="condition_satisfied"
|
||||
)
|
||||
invalid = _write_guard(node, request.action, request.expected_token)
|
||||
if invalid is None and request.action == "set_progress":
|
||||
native_range = _range(node)
|
||||
@@ -284,9 +301,30 @@ async def _control(request: ControlActionRequest, native: NativeCaller) -> dict:
|
||||
)
|
||||
if invalid is not None:
|
||||
return _result("control_action", invalid, preflight=inspection, node_before=node)
|
||||
args = request.model_dump(mode="json", exclude_none=True)
|
||||
args = request.model_dump(
|
||||
mode="json", exclude_none=True, exclude={"ensure_state", "verify_timeout_ms"}
|
||||
)
|
||||
args["expected_token"] = node["token"]
|
||||
receipt = await _call(native, "control_action", args)
|
||||
if receipt["success"] and condition is not None:
|
||||
verification = await _wait(condition, native)
|
||||
outcome = dict(receipt)
|
||||
if not verification["success"]:
|
||||
outcome.update(
|
||||
success=False,
|
||||
code=verification["code"],
|
||||
error="The input completed, but its requested state was not verified. Do not toggle again blindly.",
|
||||
)
|
||||
return _result(
|
||||
"control_action",
|
||||
outcome,
|
||||
native_receipt=receipt,
|
||||
preflight=inspection,
|
||||
postcondition=verification,
|
||||
node_before=node,
|
||||
node_after=verification.get("node"),
|
||||
verification="condition_satisfied" if verification["success"] else "condition_not_met",
|
||||
)
|
||||
return _result(
|
||||
"control_action",
|
||||
receipt,
|
||||
|
||||
Reference in new issue
Block a user