feat: self-healing element recovery engine#4732
feat: self-healing element recovery engine#4732factspark23-hash wants to merge 3 commits intobrowser-use:mainfrom
Conversation
When element lookups fail (e.g., DOM changed after navigation or dynamic update), the auto-heal engine attempts recovery using multiple strategies: 1. Text content match — find element with same visible text 2. Accessibility label match — aria-label, placeholder, title, alt 3. Role/tag fallback — same tag type in similar structural position How it works: - Elements are fingerprinted BEFORE interaction (click/input) - When lookup fails, recovery strategies are attempted automatically - Healing stats are tracked for observability - New 'heal_stats' action shows recovery statistics Changes: - browser_use/dom/auto_heal.py — Self-healing engine (new module) - browser_use/tools/service.py — Integrated into click and input actions - tests/test_auto_heal.py — 10 tests covering all core functionality Inspired by Agent-OS auto-heal engine, adapted for browser-use's CDP-based architecture.
|
|
There was a problem hiding this comment.
4 issues found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="browser_use/dom/auto_heal.py">
<violation number="1" location="browser_use/dom/auto_heal.py:151">
P2: A11y recovery selectors interpolate raw attribute values without escaping, so special characters can break `querySelector` and silently disable this healing strategy.</violation>
<violation number="2" location="browser_use/dom/auto_heal.py:240">
P2: Structural fingerprint fields (parent_tag, sibling_index) are never captured, so the role/structure healing strategy cannot perform structural disambiguation and degrades to fallback selection.</violation>
<violation number="3" location="browser_use/dom/auto_heal.py:316">
P1: Healing is gated on `backendNodeId`, but recovery JS reads it from DOM nodes (`el.backendNodeId`) without any demonstrated runtime annotation path, causing likely false healing failures.</violation>
<violation number="4" location="browser_use/dom/auto_heal.py:348">
P1: `page.evaluate` is called with a single list argument while JS expects multiple positional parameters, causing heal strategies to receive wrong argument types and fail.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| for strategy_name, strategy_fn, args in strategies: | ||
| try: | ||
| result = await strategy_fn(*args) | ||
| if result and result.get('backendNodeId'): |
There was a problem hiding this comment.
P1: Healing is gated on backendNodeId, but recovery JS reads it from DOM nodes (el.backendNodeId) without any demonstrated runtime annotation path, causing likely false healing failures.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At browser_use/dom/auto_heal.py, line 316:
<comment>Healing is gated on `backendNodeId`, but recovery JS reads it from DOM nodes (`el.backendNodeId`) without any demonstrated runtime annotation path, causing likely false healing failures.</comment>
<file context>
@@ -0,0 +1,388 @@
+ for strategy_name, strategy_fn, args in strategies:
+ try:
+ result = await strategy_fn(*args)
+ if result and result.get('backendNodeId'):
+ fp.healed_count += 1
+ fp.last_healed_via = strategy_name
</file context>
| classes = [] | ||
| data_attrs = {} | ||
| tag = '' | ||
| parent_tag = '' |
There was a problem hiding this comment.
P2: Structural fingerprint fields (parent_tag, sibling_index) are never captured, so the role/structure healing strategy cannot perform structural disambiguation and degrades to fallback selection.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At browser_use/dom/auto_heal.py, line 240:
<comment>Structural fingerprint fields (parent_tag, sibling_index) are never captured, so the role/structure healing strategy cannot perform structural disambiguation and degrades to fallback selection.</comment>
<file context>
@@ -0,0 +1,388 @@
+ classes = []
+ data_attrs = {}
+ tag = ''
+ parent_tag = ''
+ sibling_index = 0
+
</file context>
There was a problem hiding this comment.
P2: A11y recovery selectors interpolate raw attribute values without escaping, so special characters can break querySelector and silently disable this healing strategy.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At browser_use/dom/auto_heal.py, line 151:
<comment>A11y recovery selectors interpolate raw attribute values without escaping, so special characters can break `querySelector` and silently disable this healing strategy.</comment>
<file context>
@@ -0,0 +1,388 @@
+ _FIND_BY_A11Y_JS = """
+ (ariaLabel, placeholder, title, alt) => {
+ const selectors = [];
+ if (ariaLabel) selectors.push(`[aria-label="${ariaLabel}"]`);
+ if (placeholder) selectors.push(`[placeholder="${placeholder}"]`);
+ if (title) selectors.push(`[title="${title}"]`);
</file context>
- Replace browser_session.current_page with get_or_create_cdp_session() - Update auto_heal.py to use CDP Runtime.evaluate instead of page.evaluate() - Update tests to mock CDP sessions instead of Playwright pages - Fixes code-style and type-checker CI failures
…to-heal EnhancedSnapshotNode does not have 'name' or 'role' attributes. These belong to EnhancedAXNode (accessed via node.ax_node). This fixes the 'EnhancedSnapshotNode object has no attribute name' error that caused test_dom_serializer and test_ax_name_matching CI failures.

What
Add a self-healing element recovery engine that automatically recovers when element lookups fail due to DOM changes.
Why
One of the most common failure modes in browser automation is elements becoming stale or disappearing after page navigation, AJAX updates, or dynamic content changes. Currently, when an element index lookup fails, the agent gets an error and must manually retry with a refreshed browser state.
This PR adds automatic recovery — the engine fingerprints elements before interaction and attempts multiple recovery strategies when lookups fail.
How
Recovery Strategies (in priority order):
aria-label,placeholder,title, oraltattributesFlow:
New action:
heal_stats— Shows self-healing statistics (attempts, successes, failures, success rate)Changes
browser_use/dom/auto_heal.pybrowser_use/tools/service.pyclickandinputactionstests/test_auto_heal.pyTesting
Tests cover:
Design Decisions
Summary by cubic
Adds a self-healing element recovery engine that auto-recovers missing elements after DOM changes and plugs into click/input flows. Uses a CDP session with
Runtime.evaluateand adds aheal_statsaction for visibility.New Features
heal_statsaction reports attempts, successes, failures, success rate, and stored fingerprints; 10 tests cover core behavior.Bug Fixes
get_or_create_cdp_session()andRuntime.evaluatefor reliable healing.ax_nodefor element name/role instead ofsnapshot_nodeto fix attribute errors and restore CI stability.Written for commit e5a9c16. Summary will update on new commits.