feat: prepare 2.2.0 with UI and execution fixes

Add dark theme, richer Markdown and readable plugin results.
Improve Android input evidence, response integrity and diagnostics.
Unify lifecycle, guidance receipts and evidence sources across clients.
Keep direct action dispatch without an added AI quota approval layer.
Align version metadata at 2.2.0 and bundle Helper 1.2.2.

Validation: 3063 backend tests before the version bump; 44 after.
Frontend: 317 tests and production build passed.
This commit is contained in:
chenmingxuan committed 2026-10-26 00:44:13 +08:00
1 parent 83bcfd54d5
commit fac4ccb760
146 files changed
+5689 -2033

No files matched your search

+18 -4
View File
@@ -18,6 +18,7 @@ import re
from typing import Any
from artemis.utils.coordinates import parse_swipe_parameters
from artemis.utils.input_state import input_state
from PIL import Image, ImageDraw, ImageFont
@@ -287,13 +288,14 @@ def format_minimal_list_with_points(
for node in fused_xml:
text = node.get("text") or node.get("content-desc") or ""
value_evidence = input_state(node)
bounds_str = node.get("bounds")
bounds = parse_bounds(bounds_str)
ocr_elements = node.get("ocr_elements")
registered = False
if ocr_elements:
if ocr_elements and not value_evidence:
for ocr in ocr_elements:
ocr_bounds = parse_bounds(ocr.get("bounds"))
if ocr_bounds:
@@ -363,13 +365,14 @@ def format_minimal_list_with_elements(
for node in fused_xml:
text = node.get("text") or node.get("content-desc") or ""
value_evidence = input_state(node)
bounds_str = node.get("bounds")
bounds = parse_bounds(bounds_str)
ocr_elements = node.get("ocr_elements")
registered = False
if ocr_elements:
if ocr_elements and not value_evidence:
for ocr in ocr_elements:
ocr_bounds = parse_bounds(ocr.get("bounds"))
if ocr_bounds:
@@ -401,9 +404,15 @@ def format_minimal_list_with_elements(
# An empty input field carries no text but usually a hint ("Search settings");
# a rejected one carries an error ("Password too short"). Both come from the
# accessibility helper's dump and are exactly what the agent needs to see.
hint = str(node.get("hint") or "").strip()
hint = str(value_evidence.get("hint") or node.get("hint") or "").strip()
error = str(node.get("error") or "").strip()
shown = text.strip() or hint
if value_evidence.get("showing_hint") is True:
text = ""
shown = text.strip() or hint or ("(empty input)" if value_evidence else "")
if value_evidence:
# OCR describes pixels, including placeholders. It cannot replace
# the editable node's value evidence or its hit-test bounds.
registered = False
if not registered and shown and bounds:
left, top, right, bottom = bounds
cx, cy = get_center_coordinates(left, top, right, bottom)
@@ -415,6 +424,10 @@ def format_minimal_list_with_elements(
line = f"[{idx}] {kind}: '{shown}' | Bounds: {norm_bounds}"
if error:
line += f" | Error: '{error}'"
if value_evidence:
line += f" | Editable: true | Value: {value_evidence['input_value_state']}"
if value_evidence.get("focused") is not None:
line += f" | Focused: {str(value_evidence['focused']).lower()}"
lines.append(line)
items_bounds.append((idx, (left, top, right, bottom)))
@@ -431,6 +444,7 @@ def format_minimal_list_with_elements(
element["is_hint"] = True
if error:
element["error"] = error
element.update(value_evidence)
elements.append(element)
labels.append(str(idx))
added_items.append((shown, cx, cy))