@@ -35,40 +35,83 @@ def __init__(
3535 self .user_provided_instructions = user_provided_instructions
3636 self .self_heal = self_heal
3737
38- async def act (self , options : Union [ActOptions , ObserveResult ]) -> ActResult :
38+ async def act (
39+ self ,
40+ options_or_action : Union [ActOptions , ObserveResult , str , dict , None ] = None ,
41+ ** kwargs
42+ ) -> ActResult :
3943 """
4044 Perform an act based on an instruction.
4145 This method will observe the page and then perform the act on the first element returned.
46+
47+ Args:
48+ options_or_action: ActOptions, ObserveResult, action string, dict, or None
49+ **kwargs: Additional options to be merged
50+
51+ Returns:
52+ ActResult instance
4253 """
43- if "selector" in options and "method" in options :
44- options = ObserveResult ( ** options )
54+ # Handle ObserveResult case first (legacy compatibility)
55+ if isinstance ( options_or_action , ObserveResult ):
4556 return await self ._act_from_observe_result (
46- options , self .stagehand .dom_settle_timeout_ms
57+ options_or_action , self .stagehand .dom_settle_timeout_ms
58+ )
59+
60+ # Handle the new flexible parameter format
61+ options : Optional [ActOptions ] = None
62+ options_dict = {}
63+
64+ if isinstance (options_or_action , ActOptions ):
65+ options_dict = options_or_action .model_dump ()
66+ elif isinstance (options_or_action , dict ):
67+ # Check if it's actually an ObserveResult dict
68+ if "selector" in options_or_action and "method" in options_or_action :
69+ observe_result = ObserveResult (** options_or_action )
70+ return await self ._act_from_observe_result (
71+ observe_result , self .stagehand .dom_settle_timeout_ms
72+ )
73+ options_dict = options_or_action .copy ()
74+ elif isinstance (options_or_action , str ):
75+ options_dict ["action" ] = options_or_action
76+
77+ options_dict .update (kwargs )
78+
79+ # Validate options if we have any
80+ if options_dict :
81+ try :
82+ options = ActOptions (** options_dict )
83+ except Exception as e :
84+ self .logger .error (f"Invalid act options: { e } " )
85+ raise
86+
87+ if not options or not options .action :
88+ return ActResult (
89+ success = False ,
90+ message = "No action provided for act operation" ,
91+ action = "" ,
4792 )
4893
4994 # Start inference timer if available
5095 if hasattr (self .stagehand , "start_inference_timer" ):
5196 self .stagehand .start_inference_timer ()
5297
53- action_task = options .get ( " action" )
98+ action_task = options .action
5499 self .logger .info (
55100 f"Starting action for task: '{ action_task } '" ,
56101 category = "act" ,
57102 )
58103 prompt = build_act_observe_prompt (
59104 action = action_task ,
60105 supported_actions = list (method_handler_map .keys ()),
61- variables = options .get ( " variables" ) ,
106+ variables = options .variables ,
62107 )
63108
64109 observe_options_dict = {"instruction" : prompt }
65110 # Add other observe options from ActOptions if they exist
66- if options .get ("model_name" ):
67- observe_options_dict ["model_name" ] = options .get ("model_name" )
68- if options .get ("model_client_options" ):
69- observe_options_dict ["model_client_options" ] = options .get (
70- "model_client_options"
71- )
111+ if options .model_name :
112+ observe_options_dict ["model_name" ] = options .model_name
113+ if options .model_client_options :
114+ observe_options_dict ["model_client_options" ] = options .model_client_options
72115
73116 observe_options = ObserveOptions (** observe_options_dict )
74117
@@ -93,16 +136,16 @@ async def act(self, options: Union[ActOptions, ObserveResult]) -> ActResult:
93136 element_to_act_on = observe_results [0 ]
94137
95138 # Substitute variables in arguments
96- if options .get ( " variables" ) :
97- variables = options .get ( " variables" , {})
139+ if options .variables :
140+ variables = options .variables
98141 element_to_act_on .arguments = [
99142 str (arg ).replace (f"%{ key } %" , str (value ))
100143 for arg in (element_to_act_on .arguments or [])
101144 for key , value in variables .items ()
102145 ]
103146
104147 # domSettleTimeoutMs might come from options if specified for act
105- dom_settle_timeout_ms = options .get ( " dom_settle_timeout_ms" )
148+ dom_settle_timeout_ms = options .dom_settle_timeout_ms
106149
107150 try :
108151 await self ._perform_playwright_method (
0 commit comments