Skip to content

Commit e8b5088

Browse files
authored
Merge pull request #379 from Integration-Automation/feat/action-effect-batch
Add action_effect: classify did-my-click-do-anything with attribution
2 parents bfed3bc + bce4bfc commit e8b5088

15 files changed

Lines changed: 398 additions & 0 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-24) — 动作效果分类(我的点击有没有效果?)
4+
5+
告诉代理点击有没有效果——以及是否发生在它瞄准之处。完整参考:[`docs/source/Zh/doc/new_features/v167_features_doc.rst`](../docs/source/Zh/doc/new_features/v167_features_doc.rst)
6+
7+
- **`classify_effect` / `effect_near_point` / `is_no_op`**(`AC_classify_effect``AC_effect_near_point`):`screen_state`/`element_diff` 报告变了什么却不归因到动作;`loop_guard` 要重复 N 次才标记 no-op。本功能比对前后观测,并依动作目标点在*第一步*就分类结果为 `no_op` / `changed_near_target` / `changed_elsewhere`(意外对话框)/ `changed`,返回含变化中心与原因的 `EffectVerdict`。重用 `element_diff.match_elements` + `observation_delta` 的字段变更检查。纯标准库;不导入 `PySide6`
8+
39
## 本次更新 (2026-06-24) — 表单字段关联(多方向)+ 复选框状态
410

511
即使值在下方或右对齐也能把标签与值配对,并读取复选框状态。完整参考:[`docs/source/Zh/doc/new_features/v166_features_doc.rst`](../docs/source/Zh/doc/new_features/v166_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-24) — 動作效果分類(我的點擊有沒有效果?)
4+
5+
告訴代理點擊有沒有效果——以及是否發生在它瞄準之處。完整參考:[`docs/source/Zh/doc/new_features/v167_features_doc.rst`](../docs/source/Zh/doc/new_features/v167_features_doc.rst)
6+
7+
- **`classify_effect` / `effect_near_point` / `is_no_op`**(`AC_classify_effect``AC_effect_near_point`):`screen_state`/`element_diff` 回報變了什麼卻不歸因到動作;`loop_guard` 要重複 N 次才標記 no-op。本功能比對前後觀測,並依動作目標點在*第一步*就分類結果為 `no_op` / `changed_near_target` / `changed_elsewhere`(意外對話框)/ `changed`,回傳含變化中心與原因的 `EffectVerdict`。重用 `element_diff.match_elements` + `observation_delta` 的欄位變更檢查。純標準函式庫;不匯入 `PySide6`
8+
39
## 本次更新 (2026-06-24) — 表單欄位關聯(多方向)+ 核取方塊狀態
410

511
即使值在下方或右對齊也能把標籤與值配對,並讀取核取方塊狀態。完整參考:[`docs/source/Zh/doc/new_features/v166_features_doc.rst`](../docs/source/Zh/doc/new_features/v166_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-24) — Action-Effect Classification (Did My Click Do Anything?)
4+
5+
Tell an agent whether a click did anything — and whether it happened where it aimed. Full reference: [`docs/source/Eng/doc/new_features/v167_features_doc.rst`](docs/source/Eng/doc/new_features/v167_features_doc.rst).
6+
7+
- **`classify_effect` / `effect_near_point` / `is_no_op`** (`AC_classify_effect`, `AC_effect_near_point`): `screen_state`/`element_diff` report what changed but never tie it to the action; `loop_guard` only flags a no-op after N repeats. This diffs the before/after observation and, given the action's target point, classifies the result on the *first* step as `no_op` / `changed_near_target` / `changed_elsewhere` (a surprise dialog) / `changed`, returning an `EffectVerdict` with the changed centres and a reason. Reuses `element_diff.match_elements` + `observation_delta`'s field-change check. Pure-stdlib; no `PySide6`.
8+
39
## What's new (2026-06-24) — Form Field Association (Multi-Direction) + Checkbox State
410

511
Pair form labels with values even when the value is below or right-aligned, and read checkbox state. Full reference: [`docs/source/Eng/doc/new_features/v166_features_doc.rst`](docs/source/Eng/doc/new_features/v166_features_doc.rst).
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
Action-Effect Classification (Did My Click Do Anything?)
2+
========================================================
3+
4+
After an agent clicks, the crucial question is "did that do anything, and was it the *right*
5+
thing?" — but nothing answered it on the *first* step. ``screen_state.diff_snapshots`` and
6+
``element_diff`` report what changed but never tie the change back to the action;
7+
``loop_guard`` only flags a no-op after the same digest repeats N times (so the agent loops
8+
2–8 times first); ``actionability`` is purely a *pre*-action gate. ``action_effect`` closes the
9+
loop: it diffs the before/after observation and, given the action's target point, classifies
10+
the result so an agent can react immediately.
11+
12+
The verdict is one of ``no_op`` (nothing changed), ``changed_near_target`` (the change happened
13+
where we acted — a button depressed), ``changed_elsewhere`` (a surprise dialog popped somewhere
14+
else), or ``changed`` (something changed but the action carried no point to attribute to).
15+
16+
Pure-stdlib over element dicts + the action record; reuses ``element_diff.match_elements`` for
17+
the overlap join and ``observation_delta``'s field-change check. Fully deterministic and
18+
unit-testable with no device. Imports no ``PySide6``.
19+
20+
Headless API
21+
------------
22+
23+
.. code-block:: python
24+
25+
from je_auto_control import classify_effect, effect_near_point, is_no_op
26+
27+
verdict = classify_effect(before_elements, after_elements,
28+
{"type": "click", "x": 480, "y": 260})
29+
if verdict.effect == "no_op":
30+
retry_or_repair()
31+
elif verdict.effect == "changed_elsewhere":
32+
handle_unexpected_dialog()
33+
34+
if is_no_op(before_elements, after_elements):
35+
...
36+
37+
``classify_effect`` returns an ``EffectVerdict`` (``effect`` / ``changed_near_target`` /
38+
``changed_count`` / ``changed_centers`` / ``reason``). ``effect_near_point`` answers whether any
39+
change landed within ``radius`` of an arbitrary point; ``is_no_op`` is the boolean shortcut.
40+
41+
Executor commands
42+
-----------------
43+
44+
``AC_classify_effect`` (``before`` / ``after`` / ``action`` / ``radius`` →
45+
``{effect, changed_near_target, changed_count, changed_centers, reason}``) and
46+
``AC_effect_near_point`` (``before`` / ``after`` / ``point`` / ``radius`` → ``{near}``). They
47+
are exposed as the MCP tools ``ac_classify_effect`` / ``ac_effect_near_point`` (read-only) and
48+
as the Script Builder commands **Classify Action Effect** / **Effect Near Point?** under
49+
**Native UI**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ Comprehensive guides for all AutoControl features.
189189
doc/new_features/v164_features_doc
190190
doc/new_features/v165_features_doc
191191
doc/new_features/v166_features_doc
192+
doc/new_features/v167_features_doc
192193
doc/ocr_backends/ocr_backends_doc
193194
doc/observability/observability_doc
194195
doc/operations_layer/operations_layer_doc
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
動作效果分類(我的點擊有沒有效果?)
2+
====================================
3+
4+
代理點擊後最關鍵的問題是「這有沒有效果,而且是*正確的*效果嗎?」——但在*第一步*就回答這個
5+
問題的功能並不存在。``screen_state.diff_snapshots`` 與 ``element_diff`` 回報變了什麼,卻從不
6+
把變化歸因回該動作;``loop_guard`` 只在相同摘要重複 N 次後才標記 no-op(因此代理會先空轉
7+
2–8 次);``actionability`` 純粹是*動作前*的閘門。``action_effect`` 補上這個迴圈:比對前後
8+
觀測,並依動作的目標點分類結果,讓代理能立即反應。
9+
10+
判定為下列之一:``no_op``(無變化)、``changed_near_target``(變化發生在我們動作之處——按鈕被
11+
按下)、``changed_elsewhere``(別處彈出意外對話框)、或 ``changed``(有變化但動作沒有可歸因的
12+
座標點)。
13+
14+
純標準函式庫,作用於元素字典 + 動作記錄;重用 ``element_diff.match_elements`` 做重疊配對與
15+
``observation_delta`` 的欄位變更檢查。完全確定性、可在無裝置下單元測試。不匯入 ``PySide6``。
16+
17+
無頭 API
18+
--------
19+
20+
.. code-block:: python
21+
22+
from je_auto_control import classify_effect, effect_near_point, is_no_op
23+
24+
verdict = classify_effect(before_elements, after_elements,
25+
{"type": "click", "x": 480, "y": 260})
26+
if verdict.effect == "no_op":
27+
retry_or_repair()
28+
elif verdict.effect == "changed_elsewhere":
29+
handle_unexpected_dialog()
30+
31+
if is_no_op(before_elements, after_elements):
32+
...
33+
34+
``classify_effect`` 回傳 ``EffectVerdict``(``effect`` / ``changed_near_target`` /
35+
``changed_count`` / ``changed_centers`` / ``reason``)。``effect_near_point`` 回答任一變化是否
36+
落在任意點的 ``radius`` 內;``is_no_op`` 是布林捷徑。
37+
38+
執行器指令
39+
----------
40+
41+
``AC_classify_effect``(``before`` / ``after`` / ``action`` / ``radius`` →
42+
``{effect, changed_near_target, changed_count, changed_centers, reason}``)與
43+
``AC_effect_near_point``(``before`` / ``after`` / ``point`` / ``radius`` → ``{near}``)。
44+
兩者以 MCP 工具 ``ac_classify_effect`` / ``ac_effect_near_point``(唯讀)及 Script Builder 指令
45+
**Classify Action Effect** / **Effect Near Point?**(位於 **Native UI** 分類下)形式提供。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ AutoControl 所有功能的完整使用指南。
189189
doc/new_features/v164_features_doc
190190
doc/new_features/v165_features_doc
191191
doc/new_features/v166_features_doc
192+
doc/new_features/v167_features_doc
192193
doc/ocr_backends/ocr_backends_doc
193194
doc/observability/observability_doc
194195
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,10 @@
311311
from je_auto_control.utils.form_fields import (
312312
associate_fields, checkbox_state, match_labels_to_widgets,
313313
)
314+
# Classify whether an action did anything (target-local attribution)
315+
from je_auto_control.utils.action_effect import (
316+
EffectVerdict, classify_effect, effect_near_point, is_no_op,
317+
)
314318
# Locate on-screen regions by colour (mask + connected components)
315319
from je_auto_control.utils.color_region import (
316320
find_color_region, find_color_regions,
@@ -1245,6 +1249,10 @@ def start_autocontrol_gui(*args, **kwargs):
12451249
"associate_fields",
12461250
"match_labels_to_widgets",
12471251
"checkbox_state",
1252+
"EffectVerdict",
1253+
"classify_effect",
1254+
"effect_near_point",
1255+
"is_no_op",
12481256
"find_color_region",
12491257
"find_color_regions",
12501258
"ssim_compare",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3142,6 +3142,31 @@ def _add_set_of_marks_specs(specs: List[CommandSpec]) -> None:
31423142
),
31433143
description="Token-budgeted '+/~/-' summary of what changed between frames.",
31443144
))
3145+
specs.append(CommandSpec(
3146+
"AC_classify_effect", "Native UI", "Classify Action Effect",
3147+
fields=(
3148+
FieldSpec("before", FieldType.STRING,
3149+
placeholder='[{"role":"button","name":"OK","x":0,"y":0}]'),
3150+
FieldSpec("after", FieldType.STRING,
3151+
placeholder='[{"role":"button","name":"OK","x":0,"y":0}]'),
3152+
FieldSpec("action", FieldType.STRING,
3153+
placeholder='{"type":"click","x":50,"y":50}'),
3154+
FieldSpec("radius", FieldType.INT, optional=True, default=64),
3155+
),
3156+
description="Did the action change the screen near its target? (no_op/…).",
3157+
))
3158+
specs.append(CommandSpec(
3159+
"AC_effect_near_point", "Native UI", "Effect Near Point?",
3160+
fields=(
3161+
FieldSpec("before", FieldType.STRING,
3162+
placeholder='[{"role":"button","x":0,"y":0}]'),
3163+
FieldSpec("after", FieldType.STRING,
3164+
placeholder='[{"role":"button","x":0,"y":0}]'),
3165+
FieldSpec("point", FieldType.STRING, placeholder="[50, 50]"),
3166+
FieldSpec("radius", FieldType.INT, optional=True, default=64),
3167+
),
3168+
description="Did any before/after change land within radius of a point?",
3169+
))
31453170
specs.append(CommandSpec(
31463171
"AC_validate_action", "Native UI", "Validate / Snap Action",
31473172
fields=(
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Classify whether an action did anything, with target-local attribution."""
2+
from je_auto_control.utils.action_effect.action_effect import (
3+
EffectVerdict, classify_effect, effect_near_point, is_no_op,
4+
)
5+
6+
__all__ = ["EffectVerdict", "classify_effect", "effect_near_point", "is_no_op"]

0 commit comments

Comments
 (0)