The action_wrapper now delegates to act() instead of calling registry.execute_action() directly.
This ensures:
- Consistent error handling (returns ActionResult with error, not raw exceptions)
- Consistent result normalization (always returns ActionResult)
- Full observability (Laminar spans, logging)
- Proper handling of BrowserError and TimeoutError
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added two convenience methods for finding element indices:
- get_index_by_id: Find element by its id attribute
- get_index_by_class: Find element by class name
These methods simplify common DOM element lookup patterns when
working with selector maps.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enable simpler, more ergonomic action calls in tests and direct usage:
- Old API: tools.act(NavigateActionModel(navigate=GoToUrlAction(...)), browser_session)
- New API: tools.navigate(url=..., browser_session=browser_session)
Implementation:
- Added __getattr__ method to Tools class that dynamically creates action wrappers
- Delegates to existing registry.execute_action() to avoid code duplication
- Works with all Tools subclasses (Tools, CodeAgentTools, custom subclasses)
- Works with custom registered actions
- Maintains full backward compatibility with existing act() API
Benefits:
- Significantly reduces boilerplate in tests
- More intuitive and Pythonic API
- All existing code continues to work unchanged
- No code duplication (delegates to registry)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes dropdown selections not persisting in Vue.js, React, and other
reactive frameworks. The issue was that only 'change' events were
dispatched, but Vue's v-model requires 'input' events to register changes.
**Root Cause:**
Dropdown selection handler only dispatched 'change' events, missing the
'input' event required by reactive frameworks.
**Solution:**
Enhanced event dispatching sequence in default_action_watchdog.py:
1. Focus element first
2. Set value and selected state
3. Dispatch 'input' event (critical for Vue v-model and React)
4. Dispatch 'change' event (standard for select elements)
5. Blur element for validation
**Tests:**
Added comprehensive integration tests in tests/ci/interaction/:
- test_dropdown_vue_submit.py: Vue.js 3 with v-model
- test_dropdown_react_submit.py: React 18 with controlled components
Both tests verify dropdown selections persist through the reactive
framework's state management and form submission works correctly.
Closes#3415🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This update adds functionality to the LocalBrowserWatchdog class to check for running Chrome/Chromium instances before launching a new browser. If any instances are detected, a RuntimeError is raised, providing users with instructions on how to close existing Chrome windows. This ensures exclusive control over Chrome for CDP debugging, preventing potential conflicts during browser automation.
Previously, done() calls inside if/else/elif blocks would only show a warning
but still execute, potentially causing tasks to never complete if the condition
wasn't met. This changes the behavior to raise a RuntimeError, forcing the LLM
to restructure code properly.
The proper pattern is:
```python
# Validate and set result variables
if condition:
result = "success"
else:
result = "failure"
# Then call done() unconditionally
await done(result, success=True)
```
Changes:
- Upgraded warning to RuntimeError in namespace.py
- Added comprehensive test suite with 5 test cases
- Tests cover if/else/elif blocks and verify standalone done() still works
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Change both the request URL and the returned CDP URL to 127.0.0.1 to be consistent with the binding of _find_free_port(), thereby avoiding connection issues caused by IPv4/IPv6 resolution differences.