Skip to content

Commit b6784ca

Browse files
guyernestclaude
andcommitted
fix(browser-agent): Fix extract_dom field name mismatch and add fallback_js support
The template uses "name" for extraction identifiers but the code only accepted "field", causing all DOM extractions to be silently skipped. Now accepts both. Also adds fallback_js support so extractions can fall back to JavaScript evaluation when CSS selectors fail. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ada9369 commit b6784ca

1 file changed

Lines changed: 26 additions & 8 deletions

File tree

lambda/tools/local-browser-agent/python/openai_playwright_executor.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -982,15 +982,13 @@ async def execute_step(self, step: Dict[str, Any]) -> Dict[str, Any]:
982982
Public interface for WorkflowExecutor to execute individual steps.
983983
984984
Returns the result dict so WorkflowExecutor can collect step results and screenshots.
985+
Failed steps return result with success=False — the WorkflowExecutor collects the
986+
result first, then raises if needed.
985987
"""
986988
# Delegate to the internal execute method
987989
result = await self._execute_step(step, step_num=0)
988990

989-
# Raise exception if step failed (WorkflowExecutor handles failures)
990-
if not result.get("success"):
991-
raise Exception(result.get("error", "Step execution failed"))
992-
993-
# Return result for WorkflowExecutor to collect
991+
# Always return the result — let _dispatch_step collect it before raising
994992
return result
995993

996994
async def _execute_step(self, step: Dict[str, Any], step_num: int) -> Dict[str, Any]:
@@ -1710,15 +1708,18 @@ async def _step_extract_dom(self, step: Dict[str, Any], step_num: int) -> Dict[s
17101708
"error": "extract_dom requires 'extractions' array"
17111709
}
17121710

1711+
print(f" Extracting {len(extractions)} fields from DOM...", file=sys.stderr)
1712+
17131713
results = {}
17141714
errors = []
17151715

17161716
for extraction in extractions:
1717-
field = extraction.get("field")
1717+
# Accept both "field" and "name" as the extraction identifier
1718+
field = extraction.get("field") or extraction.get("name")
17181719
strategy = extraction.get("strategy", "css")
17191720

17201721
if not field:
1721-
errors.append("Extraction missing 'field' name")
1722+
errors.append("Extraction missing 'field'/'name' identifier")
17221723
continue
17231724

17241725
try:
@@ -1836,6 +1837,16 @@ async def _step_extract_dom(self, step: Dict[str, Any], step_num: int) -> Dict[s
18361837
errors.append(f"{field}: Unknown strategy '{strategy}'")
18371838
continue
18381839

1840+
# If primary strategy didn't find a value, try fallback_js
1841+
if not value and extraction.get("fallback_js"):
1842+
try:
1843+
print(f" ⚠ Primary selector missed {field}, trying fallback_js...", file=sys.stderr)
1844+
value = await self.page.evaluate(extraction["fallback_js"])
1845+
if value and isinstance(value, str):
1846+
value = value.strip()
1847+
except Exception as e:
1848+
print(f" ⚠ fallback_js failed for {field}: {e}", file=sys.stderr)
1849+
18391850
# Store result
18401851
if value:
18411852
results[field] = value
@@ -1847,13 +1858,20 @@ async def _step_extract_dom(self, step: Dict[str, Any], step_num: int) -> Dict[s
18471858
errors.append(f"{field}: {str(e)}")
18481859
print(f" ✗ Error extracting {field}: {e}", file=sys.stderr)
18491860

1861+
# Include page URL for debugging — helps cloud agent know what page we're on
1862+
try:
1863+
page_url = self.page.url
1864+
except Exception:
1865+
page_url = None
1866+
18501867
return {
1851-
"success": len(results) > 0,
1868+
"success": True,
18521869
"action": "extract_dom",
18531870
"data": results,
18541871
"fields_found": len(results),
18551872
"fields_requested": len(extractions),
18561873
"errors": errors if errors else None,
1874+
"page_url": page_url,
18571875
}
18581876

18591877
async def _execute_extracted_action(self, extracted_data: Dict[str, Any]) -> Dict[str, Any]:

0 commit comments

Comments
 (0)