20
20
ActionResult ,
21
21
AgentHistoryList ,
22
22
AgentOutput ,
23
+ AgentHistory ,
23
24
)
24
25
from browser_use .browser .browser import Browser
25
26
from browser_use .browser .context import BrowserContext
27
+ from browser_use .browser .views import BrowserStateHistory
26
28
from browser_use .controller .service import Controller
27
29
from browser_use .telemetry .views import (
28
30
AgentEndTelemetryEvent ,
34
36
from langchain_core .messages import (
35
37
BaseMessage ,
36
38
)
39
+ from src .utils .agent_state import AgentState
37
40
38
41
from .custom_massage_manager import CustomMassageManager
39
42
from .custom_views import CustomAgentOutput , CustomAgentStepInfo
@@ -72,6 +75,7 @@ def __init__(
72
75
max_error_length : int = 400 ,
73
76
max_actions_per_step : int = 10 ,
74
77
tool_call_in_content : bool = True ,
78
+ agent_state : AgentState = None ,
75
79
):
76
80
super ().__init__ (
77
81
task = task ,
@@ -92,6 +96,7 @@ def __init__(
92
96
tool_call_in_content = tool_call_in_content ,
93
97
)
94
98
self .add_infos = add_infos
99
+ self .agent_state = agent_state
95
100
self .message_manager = CustomMassageManager (
96
101
llm = self .llm ,
97
102
task = self .task ,
@@ -367,9 +372,21 @@ async def run(self, max_steps: int = 100) -> AgentHistoryList:
367
372
)
368
373
369
374
for step in range (max_steps ):
375
+ # 1) Check if stop requested
376
+ if self .agent_state and self .agent_state .is_stop_requested ():
377
+ logger .info ("🛑 Stop requested by user" )
378
+ self ._create_stop_history_item ()
379
+ break
380
+
381
+ # 2) Store last valid state before step
382
+ if self .browser_context and self .agent_state :
383
+ state = await self .browser_context .get_state (use_vision = self .use_vision )
384
+ self .agent_state .set_last_valid_state (state )
385
+
370
386
if self ._too_many_failures ():
371
387
break
372
388
389
+ # 3) Do the step
373
390
await self .step (step_info )
374
391
375
392
if self .history .is_done ():
@@ -403,3 +420,61 @@ async def run(self, max_steps: int = 100) -> AgentHistoryList:
403
420
404
421
if self .generate_gif :
405
422
self .create_history_gif ()
423
+
424
+ def _create_stop_history_item (self ):
425
+ """Create a history item for when the agent is stopped."""
426
+ try :
427
+ # Attempt to retrieve the last valid state from agent_state
428
+ state = None
429
+ if self .agent_state :
430
+ last_state = self .agent_state .get_last_valid_state ()
431
+ if last_state :
432
+ # Convert to BrowserStateHistory
433
+ state = BrowserStateHistory (
434
+ url = getattr (last_state , 'url' , "" ),
435
+ title = getattr (last_state , 'title' , "" ),
436
+ tabs = getattr (last_state , 'tabs' , []),
437
+ interacted_element = [None ],
438
+ screenshot = getattr (last_state , 'screenshot' , None )
439
+ )
440
+ else :
441
+ state = self ._create_empty_state ()
442
+ else :
443
+ state = self ._create_empty_state ()
444
+
445
+ # Create a final item in the agent history indicating done
446
+ stop_history = AgentHistory (
447
+ model_output = None ,
448
+ state = state ,
449
+ result = [ActionResult (extracted_content = None , error = None , is_done = True )]
450
+ )
451
+ self .history .history .append (stop_history )
452
+
453
+ except Exception as e :
454
+ logger .error (f"Error creating stop history item: { e } " )
455
+ # Create empty state as fallback
456
+ state = self ._create_empty_state ()
457
+ stop_history = AgentHistory (
458
+ model_output = None ,
459
+ state = state ,
460
+ result = [ActionResult (extracted_content = None , error = None , is_done = True )]
461
+ )
462
+ self .history .history .append (stop_history )
463
+
464
+ def _convert_to_browser_state_history (self , browser_state ):
465
+ return BrowserStateHistory (
466
+ url = getattr (browser_state , 'url' , "" ),
467
+ title = getattr (browser_state , 'title' , "" ),
468
+ tabs = getattr (browser_state , 'tabs' , []),
469
+ interacted_element = [None ],
470
+ screenshot = getattr (browser_state , 'screenshot' , None )
471
+ )
472
+
473
+ def _create_empty_state (self ):
474
+ return BrowserStateHistory (
475
+ url = "" ,
476
+ title = "" ,
477
+ tabs = [],
478
+ interacted_element = [None ],
479
+ screenshot = None
480
+ )
0 commit comments