optexity-browser-use 0.9.5__py3-none-any.whl → 0.9.5.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1361,14 +1361,14 @@ class BrowserSession(BaseModel):
1361
1361
  # SecurityWatchdog only handles security policy enforcement
1362
1362
  self._security_watchdog.attach_to_session()
1363
1363
 
1364
- # Initialize AboutBlankWatchdog (handles about:blank pages and DVD loading animation on first load)
1365
- AboutBlankWatchdog.model_rebuild()
1366
- self._aboutblank_watchdog = AboutBlankWatchdog(event_bus=self.event_bus, browser_session=self)
1367
- # self.event_bus.on(BrowserStopEvent, self._aboutblank_watchdog.on_BrowserStopEvent)
1368
- # self.event_bus.on(BrowserStoppedEvent, self._aboutblank_watchdog.on_BrowserStoppedEvent)
1369
- # self.event_bus.on(TabCreatedEvent, self._aboutblank_watchdog.on_TabCreatedEvent)
1370
- # self.event_bus.on(TabClosedEvent, self._aboutblank_watchdog.on_TabClosedEvent)
1371
- self._aboutblank_watchdog.attach_to_session()
1364
+ # # Initialize AboutBlankWatchdog (handles about:blank pages and DVD loading animation on first load)
1365
+ # AboutBlankWatchdog.model_rebuild()
1366
+ # self._aboutblank_watchdog = AboutBlankWatchdog(event_bus=self.event_bus, browser_session=self)
1367
+ # # self.event_bus.on(BrowserStopEvent, self._aboutblank_watchdog.on_BrowserStopEvent)
1368
+ # # self.event_bus.on(BrowserStoppedEvent, self._aboutblank_watchdog.on_BrowserStoppedEvent)
1369
+ # # self.event_bus.on(TabCreatedEvent, self._aboutblank_watchdog.on_TabCreatedEvent)
1370
+ # # self.event_bus.on(TabClosedEvent, self._aboutblank_watchdog.on_TabClosedEvent)
1371
+ # self._aboutblank_watchdog.attach_to_session()
1372
1372
 
1373
1373
  # Initialize PopupsWatchdog (handles accepting and dismissing JS dialogs, alerts, confirm, onbeforeunload, etc.)
1374
1374
  PopupsWatchdog.model_rebuild()
@@ -792,19 +792,22 @@ class DOMTreeSerializer:
792
792
  return False
793
793
 
794
794
  @staticmethod
795
- def serialize_tree(node: SimplifiedNode | None, include_attributes: list[str], depth: int = 0) -> str:
795
+ def serialize_tree(node: SimplifiedNode | None, include_attributes: list[str], depth: int = 0, remove_empty_nodes: bool = False) -> tuple[list[str], bool]:
796
796
  """Serialize the optimized tree to string format."""
797
797
  if not node:
798
- return ''
798
+ return [], False
799
+
800
+ is_empty_node = False
799
801
 
800
802
  # Skip rendering excluded nodes, but process their children
801
803
  if hasattr(node, 'excluded_by_parent') and node.excluded_by_parent:
802
804
  formatted_text = []
803
805
  for child in node.children:
804
- child_text = DOMTreeSerializer.serialize_tree(child, include_attributes, depth)
806
+ child_formatted_text, child_is_interactive = DOMTreeSerializer.serialize_tree(child, include_attributes, depth, remove_empty_nodes)
807
+ child_text = '\n'.join(child_formatted_text)
805
808
  if child_text:
806
809
  formatted_text.append(child_text)
807
- return '\n'.join(formatted_text)
810
+ return formatted_text, node.is_interactive
808
811
 
809
812
  formatted_text = []
810
813
  depth_str = depth * '\t'
@@ -814,10 +817,11 @@ class DOMTreeSerializer:
814
817
  # Skip displaying nodes marked as should_display=False
815
818
  if not node.should_display:
816
819
  for child in node.children:
817
- child_text = DOMTreeSerializer.serialize_tree(child, include_attributes, depth)
820
+ child_formatted_text, child_is_interactive = DOMTreeSerializer.serialize_tree(child, include_attributes, depth, remove_empty_nodes)
821
+ child_text = '\n'.join(child_formatted_text)
818
822
  if child_text:
819
823
  formatted_text.append(child_text)
820
- return '\n'.join(formatted_text)
824
+ return formatted_text, node.is_interactive
821
825
 
822
826
  # Special handling for SVG elements - show the tag but collapse children
823
827
  if node.original_node.tag_name.lower() == 'svg':
@@ -843,7 +847,7 @@ class DOMTreeSerializer:
843
847
  line += ' /> <!-- SVG content collapsed -->'
844
848
  formatted_text.append(line)
845
849
  # Don't process children for SVG
846
- return '\n'.join(formatted_text)
850
+ return formatted_text, node.is_interactive
847
851
 
848
852
  # Add element if clickable, scrollable, or iframe
849
853
  is_any_scrollable = node.original_node.is_actually_scrollable or node.original_node.is_scrollable
@@ -936,6 +940,14 @@ class DOMTreeSerializer:
936
940
  scroll_info_text = node.original_node.get_scroll_info_text()
937
941
  if scroll_info_text:
938
942
  line += f' ({scroll_info_text})'
943
+ else:
944
+ '''
945
+ We mark the node as empty if it has no attributes. like <button />.
946
+ But if it has some attributes, we don't mark it as empty. Like <button class="btn btn-primary">Login</button>.
947
+ We also don't touch scroll stuff as I do not know about that.
948
+ '''
949
+ if not attributes_html_str:
950
+ is_empty_node = True
939
951
 
940
952
  formatted_text.append(line)
941
953
 
@@ -950,7 +962,8 @@ class DOMTreeSerializer:
950
962
 
951
963
  # Process shadow DOM children
952
964
  for child in node.children:
953
- child_text = DOMTreeSerializer.serialize_tree(child, include_attributes, next_depth)
965
+ child_formatted_text, child_is_interactive = DOMTreeSerializer.serialize_tree(child, include_attributes, next_depth, remove_empty_nodes)
966
+ child_text = '\n'.join(child_formatted_text)
954
967
  if child_text:
955
968
  formatted_text.append(child_text)
956
969
 
@@ -972,13 +985,36 @@ class DOMTreeSerializer:
972
985
 
973
986
  # Process children (for non-shadow elements)
974
987
  if node.original_node.node_type != NodeType.DOCUMENT_FRAGMENT_NODE:
988
+ child_texts: list[str] = []
989
+ child_is_interactives: list[bool] = []
975
990
  for child in node.children:
976
- child_text = DOMTreeSerializer.serialize_tree(child, include_attributes, next_depth)
991
+ child_formatted_text, child_is_interactive = DOMTreeSerializer.serialize_tree(child, include_attributes, next_depth, remove_empty_nodes)
992
+ child_text = '\n'.join(child_formatted_text)
993
+ if child_text!='':
994
+ child_texts.append(child_text)
995
+ child_is_interactives.append(child_is_interactive)
996
+
997
+ if remove_empty_nodes and is_empty_node and depth >= 0:
998
+
999
+
1000
+ if len(child_texts) >= 1 and len(formatted_text) > 0:
1001
+ if all(child_is_interactives):
1002
+ formatted_text.pop()
1003
+
1004
+ '''
1005
+ bring all children one level up as this is the new level of child if they start with a tab
1006
+ '''
1007
+ if all([child_text.startswith('\t') for child_text in child_texts]):
1008
+ for i in range(len(child_texts)):
1009
+ temp = [a[1:] for a in child_texts[i].split("\n")]
1010
+ child_texts[i] = "\n".join(temp)
1011
+
1012
+ for child_text in child_texts:
977
1013
  if child_text:
978
1014
  formatted_text.append(child_text)
979
1015
 
980
- return '\n'.join(formatted_text)
981
-
1016
+ return formatted_text, node.is_interactive
1017
+
982
1018
  @staticmethod
983
1019
  def _build_attributes_string(node: EnhancedDOMTreeNode, include_attributes: list[str], text: str) -> str:
984
1020
  """Build the attributes string for an element."""
browser_use/dom/views.py CHANGED
@@ -817,6 +817,7 @@ class SerializedDOMState:
817
817
  def llm_representation(
818
818
  self,
819
819
  include_attributes: list[str] | None = None,
820
+ remove_empty_nodes: bool = False,
820
821
  ) -> str:
821
822
  """Kinda ugly, but leaving this as an internal method because include_attributes are a parameter on the agent, so we need to leave it as a 2 step process"""
822
823
  from browser_use.dom.serializer.serializer import DOMTreeSerializer
@@ -826,7 +827,21 @@ class SerializedDOMState:
826
827
 
827
828
  include_attributes = include_attributes or DEFAULT_INCLUDE_ATTRIBUTES
828
829
 
829
- return DOMTreeSerializer.serialize_tree(self._root, include_attributes)
830
+ formatted_text, is_interactive = DOMTreeSerializer.serialize_tree(self._root, include_attributes, remove_empty_nodes=remove_empty_nodes)
831
+ final_text = '\n'.join(formatted_text)
832
+ if remove_empty_nodes:
833
+ '''
834
+ remove extra tabs from the beginning of the lines
835
+ '''
836
+ formatted_text = final_text.split('\n')
837
+ for i in range(1,len(formatted_text)):
838
+ prev_tabs = len(formatted_text[i-1]) - len(formatted_text[i-1].lstrip('\t'))
839
+ curr_tabs = len(formatted_text[i]) - len(formatted_text[i].lstrip('\t'))
840
+ while curr_tabs - prev_tabs>1:
841
+ formatted_text[i] = formatted_text[i][1:]
842
+ curr_tabs = len(formatted_text[i]) - len(formatted_text[i].lstrip('\t'))
843
+ final_text = '\n'.join(formatted_text)
844
+ return final_text
830
845
 
831
846
  @observe_debug(ignore_input=True, ignore_output=True, name='eval_representation')
832
847
  def eval_representation(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: optexity-browser-use
3
- Version: 0.9.5
3
+ Version: 0.9.5.2
4
4
  Summary: Make websites accessible for AI agents
5
5
  Project-URL: Repository, https://github.com/browser-use/browser-use
6
6
  Author: Gregor Zunic
@@ -31,7 +31,7 @@ browser_use/browser/__init__.py,sha256=-MlstnQw2ulh9gNkl2o1FC_fXGwZWf-N-SVcycwia
31
31
  browser_use/browser/events.py,sha256=zdevl6XV1URi1l2oyK25PYnECp_5TCQujp4SJAYKGB0,18086
32
32
  browser_use/browser/profile.py,sha256=JpyLRupA31gQ52sBQUVoE-MkLEjl_0nruikZp0X31rI,47237
33
33
  browser_use/browser/python_highlights.py,sha256=l27_46HDphCB566hmOaY5-wLLHtQouBua8sjS4eUJo4,18151
34
- browser_use/browser/session.py,sha256=tnrQxIL2q6tpcc6lrV0yx1JJXEtRiRx9DmB7AhQZ39w,126115
34
+ browser_use/browser/session.py,sha256=-NInTkAjPSo0MJNfxwqB1S-foWHTAeBZrhGGhN2tAPA,126131
35
35
  browser_use/browser/session_manager.py,sha256=XKk7S1JgS_9FXBISqzecQV_KH3hfhan7yOAQnkvQRZY,15412
36
36
  browser_use/browser/video_recorder.py,sha256=N0swIzPd-2e08WQZ3ei5h5tbH1PQlmD_eNTIDAKjNSk,5360
37
37
  browser_use/browser/views.py,sha256=HwxjM1y8N3QRr3vW4xQVLWX6E9x0rbF7V72ST0rXgkQ,6317
@@ -64,7 +64,7 @@ browser_use/dom/enhanced_snapshot.py,sha256=HKpb49COP7i6E2xjSpw6troTcLO0L9Ge7lmM
64
64
  browser_use/dom/markdown_extractor.py,sha256=D8YXBTYAVQ9xOU_wQn8y5iUzdI2h8ysQ_l4BJK6D0-8,6470
65
65
  browser_use/dom/service.py,sha256=zNOMj9LfO7NWleHkrI73Z1LWfWOLZOWzA19YZVvJbPE,31575
66
66
  browser_use/dom/utils.py,sha256=jv5MN3kPkXhRYnvcyNmuMBNWjBu6yJ6oxwA31FdsIEw,4284
67
- browser_use/dom/views.py,sha256=FmFbSZGgipUjMXRPVpsWFFCR7dh2J6ZGyQ_uuRBFhHM,28599
67
+ browser_use/dom/views.py,sha256=Y3dgAAOV4aYvgQo022vPdSltzGOrX4ODGhQNQ83PaAA,29298
68
68
  browser_use/dom/playground/extraction.py,sha256=lXh5nSVW53UxnVvWlawDaI2xYWO6tTao-dK2JEuW32s,12558
69
69
  browser_use/dom/playground/multi_act.py,sha256=H-bQ1-bRPEeL9VmjIIKo0I_NDygRAD18kLIEM36mTRk,734
70
70
  browser_use/dom/serializer/clickable_elements.py,sha256=O-r0Ntyh-kBc86a_D7snw8VWLBuwQQaTBP8siU1yxPU,6564
@@ -72,7 +72,7 @@ browser_use/dom/serializer/code_use_serializer.py,sha256=KZPRBzGJ50Kb2hqUh4eykwZ
72
72
  browser_use/dom/serializer/eval_serializer.py,sha256=TbRmZcKDiD2ImUM16LBjtet-d2-_6yVlZpnDyUiGG3g,15097
73
73
  browser_use/dom/serializer/html_serializer.py,sha256=G2k9PyS1byraiBVmb-r0zRPU7zdDY_r_yaZg_gnOX1E,6032
74
74
  browser_use/dom/serializer/paint_order.py,sha256=NCirHXEt5CjrBSh9UT41x0yeJ9o1xmkh81fUDmTud24,5542
75
- browser_use/dom/serializer/serializer.py,sha256=gNu--eH6J7fN5vMAw1K00-6_cDcRUqNOIpW-TH8drr0,46041
75
+ browser_use/dom/serializer/serializer.py,sha256=UHdcz6od2IW-mk93iWqeJnbfbF9fhxGuowBqpQ2noas,47663
76
76
  browser_use/filesystem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
77
  browser_use/filesystem/file_system.py,sha256=Gq3eCYXghsMcnZcrFeRdVWfgi6jUIzEbYXgXhZ0PdDE,19513
78
78
  browser_use/integrations/gmail/__init__.py,sha256=zjQIPpFYRMdaBv87KQZ0-rsuq3eBzLk7RFhQYG7b33Q,1020
@@ -140,8 +140,8 @@ browser_use/tools/utils.py,sha256=xvKOaZW6Q83qo3QjeR31ZR6ed4_DfkrP7tZC_NOuLPo,29
140
140
  browser_use/tools/views.py,sha256=Oxfd1k7ka_P-qq0tc7pxxNlmsQJi5rmbqngrleTHquI,2920
141
141
  browser_use/tools/registry/service.py,sha256=aagu-WrnMv4t_3x0rY10qP4W0dL6OBxd7Z41_Ku9tiY,22696
142
142
  browser_use/tools/registry/views.py,sha256=4r3qysEE5UMER-G7PtU1j6RlsbKbUu6-1eGMN6xRG9A,5743
143
- optexity_browser_use-0.9.5.dist-info/METADATA,sha256=-B0m9j76aC3q9poVr2mbeWLv12yxzbD_ubL0YCB9zcg,11788
144
- optexity_browser_use-0.9.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
145
- optexity_browser_use-0.9.5.dist-info/entry_points.txt,sha256=NceUXLtKZs9AznxXL8P1rxVQVpF8jyk0x3SXZGhU1VE,87
146
- optexity_browser_use-0.9.5.dist-info/licenses/LICENSE,sha256=E1xXZxsO6VdmmwWgygDMBvZFSW01Hi5zKDLG4nbaml4,1069
147
- optexity_browser_use-0.9.5.dist-info/RECORD,,
143
+ optexity_browser_use-0.9.5.2.dist-info/METADATA,sha256=h9XtPkgrAMiNVQJ_hfTVaSdGhQ1jRIdAqi4QjB6Qj9c,11790
144
+ optexity_browser_use-0.9.5.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
145
+ optexity_browser_use-0.9.5.2.dist-info/entry_points.txt,sha256=NceUXLtKZs9AznxXL8P1rxVQVpF8jyk0x3SXZGhU1VE,87
146
+ optexity_browser_use-0.9.5.2.dist-info/licenses/LICENSE,sha256=E1xXZxsO6VdmmwWgygDMBvZFSW01Hi5zKDLG4nbaml4,1069
147
+ optexity_browser_use-0.9.5.2.dist-info/RECORD,,