Skip to content

Commit e16f409

Browse files
committed
Add blocking wait-until-vanish (wait_until_gone / image / text)
1 parent e3c5042 commit e16f409

15 files changed

Lines changed: 335 additions & 8 deletions

File tree

README/WHATS_NEW_zh-CN.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# 本次更新 — AutoControl
22

3+
## 本次更新 (2026-06-23) — 等待消失(阻塞式 vanish 等待)
4+
5+
阻塞直到转圈圈 / toast / 对话框消失。完整参考:[`docs/source/Zh/doc/new_features/v118_features_doc.rst`](../docs/source/Zh/doc/new_features/v118_features_doc.rst)
6+
7+
- **`wait_until_gone` / `wait_until_image_gone` / `wait_until_text_gone`**(`AC_wait_image_gone``AC_wait_text_gone`):`wait_for_image`/`wait_for_text` 只阻塞到某物*出现*,`observer` 则以异步回调在消失时触发——先前没有*阻塞式*的「等到此图像/文本消失再继续」。通用的 `wait_until_gone` 接受任意谓词(可无头测试);图像/文本辅助函数从定位函数建立。`gone_for_s` 可消抖。返回 `WaitOutcome`。纯标准库。
8+
39
## 本次更新 (2026-06-23) — 清空再输入字段
410

511
可靠地设定文本字段的值(Playwright 的 `fill` 惯用法)。完整参考:[`docs/source/Zh/doc/new_features/v117_features_doc.rst`](../docs/source/Zh/doc/new_features/v117_features_doc.rst)

README/WHATS_NEW_zh-TW.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# 本次更新 — AutoControl
22

3+
## 本次更新 (2026-06-23) — 等待消失(阻塞式 vanish 等待)
4+
5+
阻塞直到轉圈圈 / toast / 對話框消失。完整參考:[`docs/source/Zh/doc/new_features/v118_features_doc.rst`](../docs/source/Zh/doc/new_features/v118_features_doc.rst)
6+
7+
- **`wait_until_gone` / `wait_until_image_gone` / `wait_until_text_gone`**(`AC_wait_image_gone``AC_wait_text_gone`):`wait_for_image`/`wait_for_text` 只阻塞到某物*出現*,`observer` 則以非同步回呼在消失時觸發——先前沒有*阻塞式*的「等到此影像/文字消失再繼續」。通用的 `wait_until_gone` 接受任意述詞(可無頭測試);影像/文字輔助函式從定位函式建立。`gone_for_s` 可消抖。回傳 `WaitOutcome`。純標準函式庫。
8+
39
## 本次更新 (2026-06-23) — 清空再輸入欄位
410

511
可靠地設定文字欄位的值(Playwright 的 `fill` 慣用法)。完整參考:[`docs/source/Zh/doc/new_features/v117_features_doc.rst`](../docs/source/Zh/doc/new_features/v117_features_doc.rst)

WHATS_NEW.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# What's New — AutoControl
22

3+
## What's new (2026-06-23) — Wait Until Gone (Blocking Vanish Waits)
4+
5+
Block until a spinner / toast / dialog disappears. Full reference: [`docs/source/Eng/doc/new_features/v118_features_doc.rst`](docs/source/Eng/doc/new_features/v118_features_doc.rst).
6+
7+
- **`wait_until_gone` / `wait_until_image_gone` / `wait_until_text_gone`** (`AC_wait_image_gone`, `AC_wait_text_gone`): `wait_for_image`/`wait_for_text` only block until something *appears*, and `observer` fires async callbacks on vanish — there was no *blocking* "wait until this image/text disappears then continue" call. The generic `wait_until_gone` takes any predicate (headless-testable); the image/text helpers build it from the locate functions. `gone_for_s` debounces flicker. Returns a `WaitOutcome`. Pure-stdlib.
8+
39
## What's new (2026-06-23) — Clear-Then-Type Field Entry
410

511
Reliably set a text field's value (the Playwright `fill` idiom). Full reference: [`docs/source/Eng/doc/new_features/v117_features_doc.rst`](docs/source/Eng/doc/new_features/v117_features_doc.rst).
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
Wait Until Gone (Blocking Vanish Waits)
2+
=======================================
3+
4+
``wait_for_image`` / ``wait_for_text`` block until something *appears*, and the
5+
``observer`` fires async callbacks on vanish — but there was no *blocking* "wait
6+
until this spinner / toast / dialog **disappears** then continue" call for an
7+
image or text. ``wait_until_window_closed`` covers windows only. This adds the
8+
missing vanish waits to the ``smart_waits`` family.
9+
10+
The generic :func:`wait_until_gone` takes any predicate, so its loop is
11+
headless-testable without a real screen; the image / text helpers build that
12+
predicate from the locate functions. Imports no ``PySide6``.
13+
14+
Headless API
15+
------------
16+
17+
.. code-block:: python
18+
19+
from je_auto_control import (
20+
wait_until_gone, wait_until_image_gone, wait_until_text_gone,
21+
)
22+
23+
# generic: wait until any predicate has been falsey
24+
wait_until_gone(lambda: spinner_is_visible(), timeout_s=15)
25+
26+
wait_until_image_gone("spinner.png", timeout_s=15) # image left the screen
27+
wait_until_text_gone("Loading...", timeout_s=15) # OCR text disappeared
28+
29+
Each returns a ``WaitOutcome`` (``succeeded`` / ``reason`` / ``elapsed_s`` /
30+
``samples_taken``) — the same result type as the other smart waits. ``gone_for_s``
31+
requires the target to stay absent for that long before succeeding (debounces a
32+
flickering element); ``poll_interval_s`` / ``timeout_s`` bound the loop.
33+
34+
Executor commands
35+
-----------------
36+
37+
``AC_wait_image_gone`` and ``AC_wait_text_gone`` take the target plus
38+
``timeout_s`` / ``poll_interval_s`` / ``gone_for_s`` (and ``detect_threshold`` for
39+
the image) and return the ``WaitOutcome`` dict. Both are exposed as MCP tools
40+
(``ac_wait_image_gone`` / ``ac_wait_text_gone``) and as Script Builder commands
41+
under **Flow**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ Comprehensive guides for all AutoControl features.
140140
doc/new_features/v115_features_doc
141141
doc/new_features/v116_features_doc
142142
doc/new_features/v117_features_doc
143+
doc/new_features/v118_features_doc
143144
doc/ocr_backends/ocr_backends_doc
144145
doc/observability/observability_doc
145146
doc/operations_layer/operations_layer_doc
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
等待消失(阻塞式 vanish 等待)
2+
==============================
3+
4+
``wait_for_image`` / ``wait_for_text`` 會阻塞直到某物*出現*,``observer`` 則以非同步回呼在消失時觸發——但先前
5+
沒有針對影像或文字的*阻塞式*「等到這個轉圈圈 / toast / 對話框**消失**再繼續」呼叫。``wait_until_window_closed``
6+
只涵蓋視窗。本功能為 ``smart_waits`` 家族補上缺少的 vanish 等待。
7+
8+
通用的 :func:`wait_until_gone` 接受任意述詞,因此其迴圈可在無真實螢幕下做無頭測試;影像 / 文字輔助函式則
9+
從定位函式建立該述詞。不匯入 ``PySide6``。
10+
11+
無頭 API
12+
--------
13+
14+
.. code-block:: python
15+
16+
from je_auto_control import (
17+
wait_until_gone, wait_until_image_gone, wait_until_text_gone,
18+
)
19+
20+
# 通用:等到任意述詞變為 falsey
21+
wait_until_gone(lambda: spinner_is_visible(), timeout_s=15)
22+
23+
wait_until_image_gone("spinner.png", timeout_s=15) # 影像離開螢幕
24+
wait_until_text_gone("Loading...", timeout_s=15) # OCR 文字消失
25+
26+
每個皆回傳 ``WaitOutcome``(``succeeded`` / ``reason`` / ``elapsed_s`` / ``samples_taken``)——與其他 smart
27+
waits 相同的結果型別。``gone_for_s`` 要求目標需持續缺席該段時間才算成功(可消抖閃爍的元素);
28+
``poll_interval_s`` / ``timeout_s`` 界定迴圈。
29+
30+
執行器命令
31+
----------
32+
33+
``AC_wait_image_gone`` 與 ``AC_wait_text_gone`` 接受目標以及 ``timeout_s`` / ``poll_interval_s`` /
34+
``gone_for_s``(影像另含 ``detect_threshold``),並回傳 ``WaitOutcome`` dict。兩者皆以 MCP 工具
35+
(``ac_wait_image_gone`` / ``ac_wait_text_gone``)以及 Script Builder 中 **Flow** 分類下的命令提供。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ AutoControl 所有功能的完整使用指南。
140140
doc/new_features/v115_features_doc
141141
doc/new_features/v116_features_doc
142142
doc/new_features/v117_features_doc
143+
doc/new_features/v118_features_doc
143144
doc/ocr_backends/ocr_backends_doc
144145
doc/observability/observability_doc
145146
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -605,8 +605,9 @@
605605
# Smart waits (frame-diff replacements for time.sleep)
606606
from je_auto_control.utils.smart_waits import (
607607
WaitOutcome, wait_until_clipboard_changes, wait_until_file,
608-
wait_until_pixel_changes, wait_until_port, wait_until_process,
609-
wait_until_region_idle, wait_until_screen_stable, wait_until_window_closed,
608+
wait_until_gone, wait_until_image_gone, wait_until_pixel_changes,
609+
wait_until_port, wait_until_process, wait_until_region_idle,
610+
wait_until_screen_stable, wait_until_text_gone, wait_until_window_closed,
610611
)
611612
# Visual regression (golden-image comparison)
612613
from je_auto_control.utils.visual_regression import (
@@ -1230,6 +1231,7 @@ def start_autocontrol_gui(*args, **kwargs):
12301231
"wait_until_region_idle", "wait_until_screen_stable",
12311232
"wait_until_clipboard_changes", "wait_until_window_closed",
12321233
"wait_until_file", "wait_until_port", "wait_until_process",
1234+
"wait_until_gone", "wait_until_image_gone", "wait_until_text_gone",
12331235
# Visual regression + state machine
12341236
"take_golden", "compare_to_golden", "image_difference",
12351237
"DiffResult", "MaskRegion",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,30 @@ def _add_flow_specs(specs: List[CommandSpec]) -> None:
443443
),
444444
description="Wait until the clipboard changes or matches target.",
445445
))
446+
specs.append(CommandSpec(
447+
"AC_wait_image_gone", "Flow", "Wait for Image to Vanish",
448+
fields=(
449+
FieldSpec("image", FieldType.STRING, placeholder="path/to/spinner.png"),
450+
FieldSpec("detect_threshold", FieldType.FLOAT, optional=True,
451+
default=1.0),
452+
FieldSpec("timeout_s", FieldType.FLOAT, optional=True, default=10.0),
453+
FieldSpec("poll_interval_s", FieldType.FLOAT, optional=True,
454+
default=0.2, min_value=0.01),
455+
FieldSpec("gone_for_s", FieldType.FLOAT, optional=True, default=0.0),
456+
),
457+
description="Block until an image (spinner/toast) leaves the screen.",
458+
))
459+
specs.append(CommandSpec(
460+
"AC_wait_text_gone", "Flow", "Wait for Text to Vanish",
461+
fields=(
462+
FieldSpec("text", FieldType.STRING, placeholder="Loading..."),
463+
FieldSpec("timeout_s", FieldType.FLOAT, optional=True, default=10.0),
464+
FieldSpec("poll_interval_s", FieldType.FLOAT, optional=True,
465+
default=0.2, min_value=0.01),
466+
FieldSpec("gone_for_s", FieldType.FLOAT, optional=True, default=0.0),
467+
),
468+
description="Block until on-screen text (OCR) disappears.",
469+
))
446470
specs.append(CommandSpec(
447471
"AC_loop", "Flow", "Loop (N times)",
448472
fields=(

je_auto_control/utils/executor/action_executor.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,29 @@ def _wait_clipboard_change(baseline: Optional[str] = None,
361361
).to_dict()
362362

363363

364+
def _wait_image_gone(image: Any, detect_threshold: float = 1.0,
365+
timeout_s: float = 10.0, poll_interval_s: float = 0.2,
366+
gone_for_s: float = 0.0) -> Dict[str, Any]:
367+
"""Executor adapter: wait until an image is no longer on screen."""
368+
from je_auto_control.utils.smart_waits import wait_until_image_gone
369+
return wait_until_image_gone(
370+
image, detect_threshold=float(detect_threshold),
371+
timeout_s=float(timeout_s), poll_interval_s=float(poll_interval_s),
372+
gone_for_s=float(gone_for_s),
373+
).to_dict()
374+
375+
376+
def _wait_text_gone(text: str, timeout_s: float = 10.0,
377+
poll_interval_s: float = 0.2,
378+
gone_for_s: float = 0.0) -> Dict[str, Any]:
379+
"""Executor adapter: wait until text is no longer on screen (OCR)."""
380+
from je_auto_control.utils.smart_waits import wait_until_text_gone
381+
return wait_until_text_gone(
382+
text, timeout_s=float(timeout_s),
383+
poll_interval_s=float(poll_interval_s), gone_for_s=float(gone_for_s),
384+
).to_dict()
385+
386+
364387
def _wait_window_closed(title: str, case_sensitive: bool = False,
365388
timeout_s: float = 10.0,
366389
poll_interval_s: float = 0.2) -> Dict[str, Any]:
@@ -4971,6 +4994,8 @@ def __init__(self):
49714994
"AC_wait_for_port": _wait_for_port,
49724995
"AC_wait_for_process": _wait_for_process,
49734996
"AC_wait_clipboard_change": _wait_clipboard_change,
4997+
"AC_wait_image_gone": _wait_image_gone,
4998+
"AC_wait_text_gone": _wait_text_gone,
49744999
"AC_wait_window_closed": _wait_window_closed,
49755000

49765001
# Cost telemetry (LLM token + USD tracking)

0 commit comments

Comments
 (0)