Skip to main content

gui-agent-interaction

Implements GUI agent interaction patterns (screen vision recognition, UI element detection, automated mouse/keyboard execution) for operating desktop and web applications without APIs.

Ir a la instalación

Datos de origen

Repositorio
paulpas/agent-skill-router
Última actividad en el origen
9 de junio de 2026 a las 00:45
Idioma detectado de SKILL.md
inglés
Estrellas
4
Forks
1

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
gui-agent-interaction
description
Implements GUI agent interaction patterns (screen vision recognition, UI element detection, automated mouse/keyboard execution) for operating desktop and web applications without APIs.
license
MIT
compatibility
opencode
archetypes
["tactical"]
anti_triggers
["API integration","REST endpoint","webhook automation"]
response_profile
{"verbosity":"medium","directive_strength":"high","abstraction_level":"operational"}
metadata
{"version":"1.0.0","domain":"agent","triggers":"gui agent, screen vision, UI automation, Project Mariner, desktop automation, how do i automate clicking buttons, visual agent, computer vision UI","role":"implementation","scope":"implementation","output-format":"code","related-skills":"tool-use-function-calling, coding-agent-frameworks, mcp-integration"}
# GUI Agent Interaction Pattern Implements screen-based interaction pipelines so AI agents can operate desktop and web applications by "seeing" rendered UI elements through computer vision and executing mouse/keyboard actions — no native APIs required. This skill applies the 5 Laws of Elegant Defense: Law 1 (Early Exit) for guard-clause-driven action validation, Law 2 (Parse at boundary) for screen state normalization, and Law 3 (Atomic Predictability) for immutable before/after state snapshots used in verification loops. This skill covers how to build agents that navigate graphical user interfaces end-to-end: capturing screenshots, detecting interactive elements via vision models, planning action sequences, executing them through OS-level input libraries, and verifying outcomes by comparing screen states before and after each step. ## TL;DR Checklist - [ ] Choose the right interaction layer — browser automation (Playwright/Selenium) for web, PyAutoGUI for desktop, or a hybrid pipeline - [ ] Implement screen capture with consistent resolution and color space (RGB, not RGBA) across all steps - [ ] Run UI element detection on every captured frame before planning any action - [ ] Execute actions through a typed execution engine that maps high-level intents to OS commands - [ ] Verify every action by capturing a post-action screenshot and diffing against expected state changes - [ ] Implement error recovery with timeout thresholds and fallback dialog classification - [ ] Log full interaction traces (screenshots, detected elements, actions taken) for replay debugging --- ## When to Use Use this skill when: - Automating legacy applications with no REST API or programmatic interface (e.g., internal enterprise web portals built with server-side rendering) - Interacting with desktop software where only GUI exposure exists (e.g., configuring a system administration tool on Windows/macOS/Linux) - Performing form-filling workflows across multiple disconnected web applications that lack integration points - Testing end-user experience of web or desktop applications by simulating real user interactions at the pixel level - Validating visual correctness of UI changes — comparing rendered screens before and after a deployment or style update - Building agents that must operate in environments where only screen-level access is permitted (air-gapped systems, restricted containers) ## When NOT to Use Avoid this skill for: - Applications with well-documented REST/GraphQL APIs — always prefer programmatic API calls over visual interaction (use `tool-use-function-calling` instead) - High-frequency trading or latency-sensitive automation where screen capture overhead introduces unacceptable delay (milliseconds matter — use exchange adapters directly) - Environments requiring pixel-perfect precision below 5-pixel tolerance (computer vision detection accuracy degrades with resolution; use DOM-based selectors when available) - Accessibility-compliance testing that requires semantic markup validation — screen-level interaction cannot verify ARIA attributes or screen reader output (use accessibility-in-ui-adjacent-code) --- ## Core Workflow ``` ┌─────────────┐ ┌──────────────────┐ ┌──────────────┐ ┌───────────────┐ │ Screen │───→│ UI Element │───→│ Action │───→│ State │ │ Capture │ │ Recognition │ │ Planning │ │ Verification │ │ (screenshot)│ │ (vision model → │ │ (LLM maps │ │ (before/after │ │ │ │ bounding boxes, │ │ intent → │ │ diff check) │ │ │ │ element types) │ │ OS commands)│ │ │ └─────────────┘ └──────────────────┘ └──────────────┘ └───────┬───────┘ │ ┌────────────▼────────┐ │ Error Recovery & │ │ Retry Loop │ └─────────────────────┘ ``` 1. **Capture Screen State** — Acquire a screenshot of the current visible UI surface at consistent resolution and color format: - Use browser automation APIs for web pages (Playwright's `screenshot()` or Selenium's `get_screenshot_as_file()`) - Use OS-level capture for desktop apps (mss for cross-platform, Quartz for macOS, GDI/DirectX for Windows) - Normalize to RGB format at a fixed resolution (1920x1080 minimum; scale smaller screens up consistently) **Checkpoint:** Every captured frame must be saved with a monotonic timestamp and stored alongside its element detection result. 2. **Detect UI Elements** — Run computer vision inference on the screenshot to identify all interactive elements with bounding boxes and classification labels: - Use a fine-tuned object detection model (YOLOv8, RT-DETR) trained on UI element taxonomies (buttons, inputs, links, menus, dialogs) - Alternatively use DOM scraping for web pages as a complementary ground-truth layer when JavaScript is available - Output structured element list: `[{"type": "button", "label": "Submit", "bbox": [x1, y1, x2, y2], "confidence": 0.94}]` **Checkpoint:** Element detection must return at least one actionable element per screen — empty detection triggers a re-capture with zoom adjustment. 3. **Plan Actions from Detected State** — Given the task goal and current element map, generate a sequence of atomic UI actions: - Feed the screenshot + element list + task description to an LLM that outputs structured action sequences - Each action must be typed (`click`, `type`, `scroll`, `drag`, `hover`, `right_click`) with concrete coordinates and optional text payload - Validate action feasibility before execution — e.g., cannot type into a non-editable element **Checkpoint:** Action sequence must be executable top-to-bottom without requiring human judgment mid-sequence. 4. **Execute Actions** — Map high-level actions to OS or browser commands through an execution engine: - Web: Playwright/Selenium locator-based actions (`.click()`, `.fill()`, `.select_option()`) or coordinate-based fallback - Desktop: PyAutoGUI functions (`pyautogui.click(x, y)`, `pyautogui.typewrite(text)`), optionally wrapped with safe guards - Include deliberate delays between actions (100–500ms default) to account for rendering and animation timing **Checkpoint:** Every executed action must log its type, target coordinates/selector, and execution duration. 5. **Verify State After Execution** — Capture a post-action screenshot and compare it against the expected outcome: - Use structural similarity (SSIM) or perceptual hash (pHash) to detect meaningful changes vs noise - Re-run element detection on the new frame to confirm the expected elements appeared/disappeared/changed state - If verification fails, classify the error type and route to the recovery handler **Checkpoint:** State verification must complete within a timeout window (default: 5 seconds) — stale screens indicate hung processes. 6. **Handle Errors and Recover** — When an action produces an unexpected screen state, classify and attempt recovery: - Detect common failure patterns: loading spinners, permission dialogs, connection errors, CAPTCHAs - Apply recovery strategies in priority order: retry (same action), cancel dialog → retry, wait for timeout → retry - After max retries exhausted, log the full interaction trace and raise a structured error with screenshot attachment **Checkpoint:** Recovery must never blindly loop — every retry path must have an independent success criterion. --- ## Implementation Patterns ### Pattern 1: Google Project Mariner Architecture (Full GUI Agent Pipeline) Google Project Mariner demonstrated that agents can navigate graphical interfaces by combining screen capture, element recognition, and action execution in a tight feedback loop. The core architecture chains three stages: vision-based UI understanding, LLM-driven action planning, and low-level command execution with verification. ```python import logging from dataclasses import dataclass, field from enum import Enum from typing import Any from datetime import datetime, timezone import time logger = logging.getLogger("gui.agent") class ActionType(Enum): """Atomic UI action types.""" CLICK = "click" DOUBLE_CLICK = "double_click" TYPE = "type" SCROLL_UP = "scroll_up" SCROLL_DOWN = "scroll_down" DRAG = "drag" HOVER = "hover" RIGHT_CLICK = "right_click" KEY_PRESS = "key_press" class ActionStatus(Enum): PENDING = "pending" EXECUTED = "executed" FAILED = "failed" RETRYING = "retrying" RECOVERED = "recovered" @dataclass class UIElement: """Detected interactive element on screen with bounding box.""" element_id: str element_type: str # "button", "input", "link", "menu", "dialog", "image" label: str # Visible text or accessible name bbox: tuple[int, int, int, int] # (x1, y1, x2, y2) in pixel coords confidence: float # Detection model confidence (0.0 – 1.0) @property def center(self) -> tuple[float, float]: """Return the geometric center of the bounding box.""" cx = (self.bbox[0] + self.bbox[2]) / 2 cy = (self.bbox[1] + self.bbox[3]) / 2 return (cx, cy) @property def width(self) -> int: return self.bbox[2] - self.bbox[0] @property def height(self) -> int: return self.bbox[3] - self.bbox[1] def contains_point(self, x: float, y: float) -> bool: """Check if a coordinate falls within this element's bounding box.""" return (self.bbox[0] <= x <= self.bbox[2] and self.bbox[1] <= y <= self.bbox[3]) @dataclass class ScreenState: """Immutable snapshot of a UI screen at a point in time.""" timestamp: str # ISO 8601 with UTC timezone screenshot_path: str # Path to saved PNG file width: int height: int elements: list[UIElement] = field(default_factory=list) metadata: dict[str, Any] = field(default_factory=dict) @dataclass class PlannedAction: """An action planned by the agent for a specific target element.""" action_type: ActionType target_element_id: str | None # Which element this targets coordinates: tuple[float, float] # (x, y) screen coordinates text_payload: str = "" # For TYPE actions delay_ms: int = 200 # Wait between actions in the sequence expected_state_change: str = "" # Description of what should happen after execution @dataclass class InteractionTrace: """Complete record of one agent interaction step.""" step_index: int before_state: ScreenState | None = None action: PlannedAction | None = None action_status: ActionStatus = ActionStatus.PENDING after_state: ScreenState | None = None error_message: str | None = None recovery_action: str | None = None duration_ms: float = 0.0 @property def is_complete(self) -> bool: return self.after_state is not None class GUIAgentPipeline: """Implements the Google Project Mariner pipeline for GUI agent interaction. Chains screen capture → element recognition → action planning → execution → state verification into a loop. Applies Law 2 (Parse at boundary) by normalizing all screen captures to a consistent format before passing to downstream stages, and Law 1 (Early Exit) by validating each stage's output before proceeding to the next. """ def __init__( self, vision_model: Any = None, executor: Any = None, verifier: Any = None, max_retries: int = 3, action_delay_ms: int = 200, verification_timeout_s: float = 5.0, ) -> None: self.vision_model = vision_model self.executor = executor self.verifier = verifier self.max_retries = max_retries self.action_delay_ms = action_delay_ms self.verification_timeout_s = verification_timeout_s self.trace: list[InteractionTrace] = [] def run(self, task_description: str) -> list[InteractionTrace]: """Execute a task on the target GUI by cycling through the interaction loop. Args: task_description: Natural language description of what the agent should accomplish. Returns: List of InteractionTraces recording each step's before/after state and outcome. """ step_index = 0 iteration = 0 max_iterations = 50 # Prevent infinite loops on stuck UIs while iteration < max_iterations: iteration += 1 trace = InteractionTrace(step_index=step_index) # Stage 1: Capture screen state trace.before_state = self._capture_screen() if not trace.before_state or not trace.before_state.elements: trace.error_message = "Screen capture returned no detectable elements" trace.action_status = ActionStatus.FAILED self.trace.append(trace) logger.error("Step %d: No elements detected on screen", step_index) break # Stage 2: Plan actions action_sequence = self._plan_actions( task_description, trace.before_state ) if not action_sequence: trace.error_message = "Action planner returned empty sequence" trace.action_status = ActionStatus.FAILED self.trace.append(trace) break # Stage 3-5: Execute each action with verification executed_any = False for action in action_sequence: result = self._execute_with_verification( action, trace.before_state, step_index ) if result.action_status == ActionStatus.FAILED and result.recovery_action: # Attempt recovery retry_result = self._attempt_recovery(result) if retry_result is not None: result = retry_result if result.action_status in (ActionStatus.EXECUTED, ActionStatus.RECOVERED): trace.before_state = result.after_state # Feed back into loop executed_any = True self.trace.append(result) step_index += 1 # Check if task is complete if not action_sequence or executed_any: trace.action_status = ActionStatus.EXECUTED self.trace.append(trace) break return self.trace def _capture_screen(self) -> ScreenState | None: """Capture current screen state with element detection.""" # Implementation depends on target environment (browser vs desktop) raise NotImplementedError("Subclass and implement for your target platform") def _plan_actions( self, task: str, state: ScreenState ) -> list[PlannedAction]: """Plan action sequence from task description and current element map.""" raise NotImplementedError("Subclass with LLM-powered planner") def _execute_with_verification( self, action: PlannedAction, before: ScreenState, step_idx: int, ) -> InteractionTrace: """Execute an action and verify its effect.""" trace = InteractionTrace(step_index=step_idx) trace.action = action trace.before_state = before start = time.time() try: trace.after_state = self._capture_screen() trace.action_status = ActionStatus.EXECUTED except Exception as e: trace.error_message = str(e) trace.action_status = ActionStatus.FAILED trace.duration_ms = (time.time() - start) * 1000 return trace def _attempt_recovery( self, failed_trace: InteractionTrace, ) -> InteractionTrace | None: """Attempt to recover from a failed action.""" raise NotImplementedError("Implement recovery strategies") ``` **BAD vs GOOD: Pipeline Design** ```python # ❌ BAD — No early exit on empty screen state; loops forever on hung UI class BrokenGUIAgent: def run(self, task): while True: # Never terminates screenshot = capture_screen() elements = detect_elements(screenshot) actions = plan(actions_for(task, elements)) execute(actions) # ✅ GOOD — Explicit max_iterations, guard clauses at every stage boundary, # immutable traces for replay debugging (Law 3: Atomic Predictability) class RobustGUIAgent: def run(self, task): for _ in range(50): # Hard cap prevents infinite loops state = self._capture_screen() if not state or not state.elements: break # Early exit: nothing actionable to do actions = self._plan_actions(task, state) if not actions: break ... ``` ### Pattern 2: UI Element Detection & Recognition System UI element detection maps raw pixel data into structured element catalogs that the action planner can reason about. For web applications, DOM-based detection is preferred (direct access to element properties, text content, and accessibility labels). For desktop apps without DOM exposure, computer vision models detect elements purely from screen pixels. ```python import base64 import io from dataclasses import dataclass, field try: from selenium.webdriver.common.by import By from selenium.webdriver.remote.webdriver import WebDriver SELENIUM_AVAILABLE = True except ImportError: SELENIUM_AVAILABLE = False @dataclass class DOMElementInfo: """Structured info extracted from a web page's DOM tree.""" element_id: str tag_name: str role: str | None # ARIA role (button, textbox, link, etc.) aria_label: str | None # Accessible label text_content: str # Visible text between tags is_visible: bool is_interactive: bool # Has click handler or is a form control rect: dict[str, int] # {"left", "top", "width", "height"} in viewport coords @property def center(self) -> tuple[float, float]: left = self.rect["left"] top = self.rect["top"] return (left + self.rect["width"] / 2, top + self.rect["height"] / 2) @dataclass class VisionElementInfo: """Structured info from a computer vision model detecting elements in pixels.""" element_id: str element_type: str # button, input_field, link, menu_item, dialog, icon label: str # Inferred text label from OCR or visual features bbox: tuple[int, int, int, int] # (x1, y1, x2, y2) absolute pixel coords confidence: float # Model detection confidence ocr_text: list[dict] = field(default_factory=list) # Raw OCR results near bbox class WebElementDetector: """Extracts structured element info from a browser page's DOM tree. This is the preferred detection method for web applications since it provides ground-truth accessibility information that vision models cannot reliably infer from pixels alone. """ INTERACTIVE_TAGS = {"a", "button", "input", "select", "textarea", "summary"} ATTRIBUTES_TO_EXTRACT = { "type", "name", "role", "aria-label", "aria-hidden", "disabled", "readonly", "placeholder", "value", } def __init__(self, driver: WebDriver) -> None: self.driver = driver def detect_all_interactive_elements(self) -> list[DOMElementInfo]: """Find all interactive elements on the current page. Uses JavaScript evaluation to extract element properties directly from the DOM, which is faster and more reliable than iterating through Selenium's find_element calls. """ script = """ (function() { const interactiveTags = %TAGS; const attrsToRead = %ATTRS; const results = []; // Get all elements, filter to interactive ones
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub