@@ -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