From b19c4fec4e04b730abf9090b07d60ae4e5b7d8d8 Mon Sep 17 00:00:00 2001 From: Athena Date: Fri, 14 Aug 2026 22:31:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20feat(core):=20maref=20=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E5=BA=93/sidecar/loop=20=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🤖 自动改进 PR — 来自 RSI 进化循环 ### 改进类型 code ### 描述 提交 39e95a9f: feat(core): maref 核心库/sidecar/loop 增强 ### 指标变化 无指标数据 ### 变更文件 - `src/maref/__init__.py` - `src/maref/__main__.py` - `src/maref/agent_card_config.py` - `src/maref/browser/page_adapter.py` - `src/maref/desktop/accessibility_parser.py` - `src/maref/desktop/browser_controller.py` - `src/maref/loop/reflection_buffer.py` - `src/maref/loop/rollout_executor.py` - `src/maref/loop/security_audit_evaluator.py` - `src/maref/loop/skill_persist. --- src/maref/desktop/accessibility_parser.py | 60 +++++++++++------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/maref/desktop/accessibility_parser.py b/src/maref/desktop/accessibility_parser.py index abafe754..986b8af8 100644 --- a/src/maref/desktop/accessibility_parser.py +++ b/src/maref/desktop/accessibility_parser.py @@ -128,11 +128,14 @@ } return; } - var title = String(el.title()); - var desc = String(el.description()); - var value = String(el.value()); - var pos = el.position(); - var size = el.size(); + // 单属性容错:某些 AXUIElement 不支持 title/position 等,抛错不应丢整棵子树。 + var title = ""; var desc = ""; var value = ""; + try { title = String(el.title()); } catch(e) {} + try { desc = String(el.description()); } catch(e) {} + try { value = String(el.value()); } catch(e) {} + var pos = [0, 0]; var size = [0, 0]; + try { pos = el.position(); } catch(e) {} + try { size = el.size(); } catch(e) {} var enabled = true; try { enabled = el.enabled(); } catch(e) {} var focused = false; @@ -210,7 +213,6 @@ def check_permissions(self) -> bool: return False try: import ApplicationServices - trusted = ApplicationServices.AXIsProcessTrusted() self._permission_granted = bool(trusted) return self._permission_granted @@ -244,10 +246,11 @@ def parse( ScreenParseResult with real UI elements from the Accessibility tree. """ if not self._initialized: - raise RuntimeError("AccessibilityParser not initialized. Call initialize() first.") + raise RuntimeError( + "AccessibilityParser not initialized. Call initialize() first." + ) import time - t0 = time.time() raw_json = self._run_jxa(target_app) @@ -261,7 +264,6 @@ def parse( if width <= 0 or height <= 0: try: import Quartz - main_display = Quartz.CGMainDisplayID() width = int(Quartz.CGDisplayPixelsWide(main_display)) height = int(Quartz.CGDisplayPixelsHigh(main_display)) @@ -295,22 +297,20 @@ def parse( continue interactions = _ROLE_INTERACTIONS.get(role, []) elem_id = f"ax_{role}_{x}_{y}_{w}_{h}" - elements.append( - ParsedUIElement( - element_type=element_type, - bbox=BoundingBox(x=x, y=y, width=w, height=h), - text=title, - confidence=1.0, - interaction_types=interactions, - element_id=elem_id, - attributes={ - "ax_role": role, - "enabled": is_enabled, - "focused": item.get("focused", False), - "source": "accessibility_api", - }, - ) - ) + elements.append(ParsedUIElement( + element_type=element_type, + bbox=BoundingBox(x=x, y=y, width=w, height=h), + text=title, + confidence=1.0, + interaction_types=interactions, + element_id=elem_id, + attributes={ + "ax_role": role, + "enabled": is_enabled, + "focused": item.get("focused", False), + "source": "accessibility_api", + }, + )) elapsed = (time.time() - t0) * 1000 return ScreenParseResult( @@ -324,14 +324,12 @@ def parse( def _run_jxa(self, target_app: str) -> str: """Execute JXA script and return JSON element array.""" - sanitized_app = re.sub(r"[^a-zA-Z0-9\- ]", "", target_app) + sanitized_app = re.sub(r'[^a-zA-Z0-9\- ]', '', target_app) script = _JXA_GET_ELEMENTS % (sanitized_app, self._max_depth) try: result = subprocess.run( ["osascript", "-l", "JavaScript", "-e", script], - capture_output=True, - text=True, - timeout=15, + capture_output=True, text=True, timeout=15, ) if result.returncode == 0: return result.stdout.strip() @@ -343,7 +341,9 @@ def _run_jxa(self, target_app: str) -> str: def benchmark(self, num_runs: int = 3) -> dict[str, Any]: """Run a quick benchmark: avg latency and element count.""" if not self._initialized: - raise RuntimeError("AccessibilityParser not initialized. Call initialize() first.") + raise RuntimeError( + "AccessibilityParser not initialized. Call initialize() first." + ) latencies: list[float] = [] counts: list[int] = [] for _ in range(num_runs):