optexity-browser-use 0.9.5__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.
Files changed (147) hide show
  1. browser_use/__init__.py +157 -0
  2. browser_use/actor/__init__.py +11 -0
  3. browser_use/actor/element.py +1175 -0
  4. browser_use/actor/mouse.py +134 -0
  5. browser_use/actor/page.py +561 -0
  6. browser_use/actor/playground/flights.py +41 -0
  7. browser_use/actor/playground/mixed_automation.py +54 -0
  8. browser_use/actor/playground/playground.py +236 -0
  9. browser_use/actor/utils.py +176 -0
  10. browser_use/agent/cloud_events.py +282 -0
  11. browser_use/agent/gif.py +424 -0
  12. browser_use/agent/judge.py +170 -0
  13. browser_use/agent/message_manager/service.py +473 -0
  14. browser_use/agent/message_manager/utils.py +52 -0
  15. browser_use/agent/message_manager/views.py +98 -0
  16. browser_use/agent/prompts.py +413 -0
  17. browser_use/agent/service.py +2316 -0
  18. browser_use/agent/system_prompt.md +185 -0
  19. browser_use/agent/system_prompt_flash.md +10 -0
  20. browser_use/agent/system_prompt_no_thinking.md +183 -0
  21. browser_use/agent/views.py +743 -0
  22. browser_use/browser/__init__.py +41 -0
  23. browser_use/browser/cloud/cloud.py +203 -0
  24. browser_use/browser/cloud/views.py +89 -0
  25. browser_use/browser/events.py +578 -0
  26. browser_use/browser/profile.py +1158 -0
  27. browser_use/browser/python_highlights.py +548 -0
  28. browser_use/browser/session.py +3225 -0
  29. browser_use/browser/session_manager.py +399 -0
  30. browser_use/browser/video_recorder.py +162 -0
  31. browser_use/browser/views.py +200 -0
  32. browser_use/browser/watchdog_base.py +260 -0
  33. browser_use/browser/watchdogs/__init__.py +0 -0
  34. browser_use/browser/watchdogs/aboutblank_watchdog.py +253 -0
  35. browser_use/browser/watchdogs/crash_watchdog.py +335 -0
  36. browser_use/browser/watchdogs/default_action_watchdog.py +2729 -0
  37. browser_use/browser/watchdogs/dom_watchdog.py +817 -0
  38. browser_use/browser/watchdogs/downloads_watchdog.py +1277 -0
  39. browser_use/browser/watchdogs/local_browser_watchdog.py +461 -0
  40. browser_use/browser/watchdogs/permissions_watchdog.py +43 -0
  41. browser_use/browser/watchdogs/popups_watchdog.py +143 -0
  42. browser_use/browser/watchdogs/recording_watchdog.py +126 -0
  43. browser_use/browser/watchdogs/screenshot_watchdog.py +62 -0
  44. browser_use/browser/watchdogs/security_watchdog.py +280 -0
  45. browser_use/browser/watchdogs/storage_state_watchdog.py +335 -0
  46. browser_use/cli.py +2359 -0
  47. browser_use/code_use/__init__.py +16 -0
  48. browser_use/code_use/formatting.py +192 -0
  49. browser_use/code_use/namespace.py +665 -0
  50. browser_use/code_use/notebook_export.py +276 -0
  51. browser_use/code_use/service.py +1340 -0
  52. browser_use/code_use/system_prompt.md +574 -0
  53. browser_use/code_use/utils.py +150 -0
  54. browser_use/code_use/views.py +171 -0
  55. browser_use/config.py +505 -0
  56. browser_use/controller/__init__.py +3 -0
  57. browser_use/dom/enhanced_snapshot.py +161 -0
  58. browser_use/dom/markdown_extractor.py +169 -0
  59. browser_use/dom/playground/extraction.py +312 -0
  60. browser_use/dom/playground/multi_act.py +32 -0
  61. browser_use/dom/serializer/clickable_elements.py +200 -0
  62. browser_use/dom/serializer/code_use_serializer.py +287 -0
  63. browser_use/dom/serializer/eval_serializer.py +478 -0
  64. browser_use/dom/serializer/html_serializer.py +212 -0
  65. browser_use/dom/serializer/paint_order.py +197 -0
  66. browser_use/dom/serializer/serializer.py +1170 -0
  67. browser_use/dom/service.py +825 -0
  68. browser_use/dom/utils.py +129 -0
  69. browser_use/dom/views.py +906 -0
  70. browser_use/exceptions.py +5 -0
  71. browser_use/filesystem/__init__.py +0 -0
  72. browser_use/filesystem/file_system.py +619 -0
  73. browser_use/init_cmd.py +376 -0
  74. browser_use/integrations/gmail/__init__.py +24 -0
  75. browser_use/integrations/gmail/actions.py +115 -0
  76. browser_use/integrations/gmail/service.py +225 -0
  77. browser_use/llm/__init__.py +155 -0
  78. browser_use/llm/anthropic/chat.py +242 -0
  79. browser_use/llm/anthropic/serializer.py +312 -0
  80. browser_use/llm/aws/__init__.py +36 -0
  81. browser_use/llm/aws/chat_anthropic.py +242 -0
  82. browser_use/llm/aws/chat_bedrock.py +289 -0
  83. browser_use/llm/aws/serializer.py +257 -0
  84. browser_use/llm/azure/chat.py +91 -0
  85. browser_use/llm/base.py +57 -0
  86. browser_use/llm/browser_use/__init__.py +3 -0
  87. browser_use/llm/browser_use/chat.py +201 -0
  88. browser_use/llm/cerebras/chat.py +193 -0
  89. browser_use/llm/cerebras/serializer.py +109 -0
  90. browser_use/llm/deepseek/chat.py +212 -0
  91. browser_use/llm/deepseek/serializer.py +109 -0
  92. browser_use/llm/exceptions.py +29 -0
  93. browser_use/llm/google/__init__.py +3 -0
  94. browser_use/llm/google/chat.py +542 -0
  95. browser_use/llm/google/serializer.py +120 -0
  96. browser_use/llm/groq/chat.py +229 -0
  97. browser_use/llm/groq/parser.py +158 -0
  98. browser_use/llm/groq/serializer.py +159 -0
  99. browser_use/llm/messages.py +238 -0
  100. browser_use/llm/models.py +271 -0
  101. browser_use/llm/oci_raw/__init__.py +10 -0
  102. browser_use/llm/oci_raw/chat.py +443 -0
  103. browser_use/llm/oci_raw/serializer.py +229 -0
  104. browser_use/llm/ollama/chat.py +97 -0
  105. browser_use/llm/ollama/serializer.py +143 -0
  106. browser_use/llm/openai/chat.py +264 -0
  107. browser_use/llm/openai/like.py +15 -0
  108. browser_use/llm/openai/serializer.py +165 -0
  109. browser_use/llm/openrouter/chat.py +211 -0
  110. browser_use/llm/openrouter/serializer.py +26 -0
  111. browser_use/llm/schema.py +176 -0
  112. browser_use/llm/views.py +48 -0
  113. browser_use/logging_config.py +330 -0
  114. browser_use/mcp/__init__.py +18 -0
  115. browser_use/mcp/__main__.py +12 -0
  116. browser_use/mcp/client.py +544 -0
  117. browser_use/mcp/controller.py +264 -0
  118. browser_use/mcp/server.py +1114 -0
  119. browser_use/observability.py +204 -0
  120. browser_use/py.typed +0 -0
  121. browser_use/sandbox/__init__.py +41 -0
  122. browser_use/sandbox/sandbox.py +637 -0
  123. browser_use/sandbox/views.py +132 -0
  124. browser_use/screenshots/__init__.py +1 -0
  125. browser_use/screenshots/service.py +52 -0
  126. browser_use/sync/__init__.py +6 -0
  127. browser_use/sync/auth.py +357 -0
  128. browser_use/sync/service.py +161 -0
  129. browser_use/telemetry/__init__.py +51 -0
  130. browser_use/telemetry/service.py +112 -0
  131. browser_use/telemetry/views.py +101 -0
  132. browser_use/tokens/__init__.py +0 -0
  133. browser_use/tokens/custom_pricing.py +24 -0
  134. browser_use/tokens/mappings.py +4 -0
  135. browser_use/tokens/service.py +580 -0
  136. browser_use/tokens/views.py +108 -0
  137. browser_use/tools/registry/service.py +572 -0
  138. browser_use/tools/registry/views.py +174 -0
  139. browser_use/tools/service.py +1675 -0
  140. browser_use/tools/utils.py +82 -0
  141. browser_use/tools/views.py +100 -0
  142. browser_use/utils.py +670 -0
  143. optexity_browser_use-0.9.5.dist-info/METADATA +344 -0
  144. optexity_browser_use-0.9.5.dist-info/RECORD +147 -0
  145. optexity_browser_use-0.9.5.dist-info/WHEEL +4 -0
  146. optexity_browser_use-0.9.5.dist-info/entry_points.txt +3 -0
  147. optexity_browser_use-0.9.5.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,330 @@
1
+ import logging
2
+ import os
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ from dotenv import load_dotenv
7
+
8
+ load_dotenv()
9
+
10
+ from browser_use.config import CONFIG
11
+
12
+
13
+ def addLoggingLevel(levelName, levelNum, methodName=None):
14
+ """
15
+ Comprehensively adds a new logging level to the `logging` module and the
16
+ currently configured logging class.
17
+
18
+ `levelName` becomes an attribute of the `logging` module with the value
19
+ `levelNum`. `methodName` becomes a convenience method for both `logging`
20
+ itself and the class returned by `logging.getLoggerClass()` (usually just
21
+ `logging.Logger`). If `methodName` is not specified, `levelName.lower()` is
22
+ used.
23
+
24
+ To avoid accidental clobberings of existing attributes, this method will
25
+ raise an `AttributeError` if the level name is already an attribute of the
26
+ `logging` module or if the method name is already present
27
+
28
+ Example
29
+ -------
30
+ >>> addLoggingLevel('TRACE', logging.DEBUG - 5)
31
+ >>> logging.getLogger(__name__).setLevel('TRACE')
32
+ >>> logging.getLogger(__name__).trace('that worked')
33
+ >>> logging.trace('so did this')
34
+ >>> logging.TRACE
35
+ 5
36
+
37
+ """
38
+ if not methodName:
39
+ methodName = levelName.lower()
40
+
41
+ if hasattr(logging, levelName):
42
+ raise AttributeError(f'{levelName} already defined in logging module')
43
+ if hasattr(logging, methodName):
44
+ raise AttributeError(f'{methodName} already defined in logging module')
45
+ if hasattr(logging.getLoggerClass(), methodName):
46
+ raise AttributeError(f'{methodName} already defined in logger class')
47
+
48
+ # This method was inspired by the answers to Stack Overflow post
49
+ # http://stackoverflow.com/q/2183233/2988730, especially
50
+ # http://stackoverflow.com/a/13638084/2988730
51
+ def logForLevel(self, message, *args, **kwargs):
52
+ if self.isEnabledFor(levelNum):
53
+ self._log(levelNum, message, args, **kwargs)
54
+
55
+ def logToRoot(message, *args, **kwargs):
56
+ logging.log(levelNum, message, *args, **kwargs)
57
+
58
+ logging.addLevelName(levelNum, levelName)
59
+ setattr(logging, levelName, levelNum)
60
+ setattr(logging.getLoggerClass(), methodName, logForLevel)
61
+ setattr(logging, methodName, logToRoot)
62
+
63
+
64
+ def setup_logging(stream=None, log_level=None, force_setup=False, debug_log_file=None, info_log_file=None):
65
+ """Setup logging configuration for browser-use.
66
+
67
+ Args:
68
+ stream: Output stream for logs (default: sys.stdout). Can be sys.stderr for MCP mode.
69
+ log_level: Override log level (default: uses CONFIG.BROWSER_USE_LOGGING_LEVEL)
70
+ force_setup: Force reconfiguration even if handlers already exist
71
+ debug_log_file: Path to log file for debug level logs only
72
+ info_log_file: Path to log file for info level logs only
73
+ """
74
+ # Try to add RESULT level, but ignore if it already exists
75
+ try:
76
+ addLoggingLevel('RESULT', 35) # This allows ERROR, FATAL and CRITICAL
77
+ except AttributeError:
78
+ pass # Level already exists, which is fine
79
+
80
+ log_type = log_level or CONFIG.BROWSER_USE_LOGGING_LEVEL
81
+
82
+ # Check if handlers are already set up
83
+ if logging.getLogger().hasHandlers() and not force_setup:
84
+ return logging.getLogger('browser_use')
85
+
86
+ # Clear existing handlers
87
+ root = logging.getLogger()
88
+ root.handlers = []
89
+
90
+ class BrowserUseFormatter(logging.Formatter):
91
+ def __init__(self, fmt, log_level):
92
+ super().__init__(fmt)
93
+ self.log_level = log_level
94
+
95
+ def format(self, record):
96
+ # Only clean up names in INFO mode, keep everything in DEBUG mode
97
+ if self.log_level > logging.DEBUG and isinstance(record.name, str) and record.name.startswith('browser_use.'):
98
+ # Extract clean component names from logger names
99
+ if 'Agent' in record.name:
100
+ record.name = 'Agent'
101
+ elif 'BrowserSession' in record.name:
102
+ record.name = 'BrowserSession'
103
+ elif 'tools' in record.name:
104
+ record.name = 'tools'
105
+ elif 'dom' in record.name:
106
+ record.name = 'dom'
107
+ elif record.name.startswith('browser_use.'):
108
+ # For other browser_use modules, use the last part
109
+ parts = record.name.split('.')
110
+ if len(parts) >= 2:
111
+ record.name = parts[-1]
112
+ return super().format(record)
113
+
114
+ # Setup single handler for all loggers
115
+ console = logging.StreamHandler(stream or sys.stdout)
116
+
117
+ # Determine the log level to use first
118
+ if log_type == 'result':
119
+ log_level = 35 # RESULT level value
120
+ elif log_type == 'debug':
121
+ log_level = logging.DEBUG
122
+ else:
123
+ log_level = logging.INFO
124
+
125
+ # adittional setLevel here to filter logs
126
+ if log_type == 'result':
127
+ console.setLevel('RESULT')
128
+ console.setFormatter(BrowserUseFormatter('%(message)s', log_level))
129
+ else:
130
+ console.setLevel(log_level) # Keep console at original log level (e.g., INFO)
131
+ console.setFormatter(BrowserUseFormatter('%(levelname)-8s [%(name)s] %(message)s', log_level))
132
+
133
+ # Configure root logger only
134
+ root.addHandler(console)
135
+
136
+ # Add file handlers if specified
137
+ file_handlers = []
138
+
139
+ # Create debug log file handler
140
+ if debug_log_file:
141
+ debug_handler = logging.FileHandler(debug_log_file, encoding='utf-8')
142
+ debug_handler.setLevel(logging.DEBUG)
143
+ debug_handler.setFormatter(BrowserUseFormatter('%(asctime)s - %(levelname)-8s [%(name)s] %(message)s', logging.DEBUG))
144
+ file_handlers.append(debug_handler)
145
+ root.addHandler(debug_handler)
146
+
147
+ # Create info log file handler
148
+ if info_log_file:
149
+ info_handler = logging.FileHandler(info_log_file, encoding='utf-8')
150
+ info_handler.setLevel(logging.INFO)
151
+ info_handler.setFormatter(BrowserUseFormatter('%(asctime)s - %(levelname)-8s [%(name)s] %(message)s', logging.INFO))
152
+ file_handlers.append(info_handler)
153
+ root.addHandler(info_handler)
154
+
155
+ # Configure root logger - use DEBUG if debug file logging is enabled
156
+ effective_log_level = logging.DEBUG if debug_log_file else log_level
157
+ root.setLevel(effective_log_level)
158
+
159
+ # Configure browser_use logger
160
+ browser_use_logger = logging.getLogger('browser_use')
161
+ browser_use_logger.propagate = False # Don't propagate to root logger
162
+ browser_use_logger.addHandler(console)
163
+ for handler in file_handlers:
164
+ browser_use_logger.addHandler(handler)
165
+ browser_use_logger.setLevel(effective_log_level)
166
+
167
+ # Configure bubus logger to allow INFO level logs
168
+ bubus_logger = logging.getLogger('bubus')
169
+ bubus_logger.propagate = False # Don't propagate to root logger
170
+ bubus_logger.addHandler(console)
171
+ for handler in file_handlers:
172
+ bubus_logger.addHandler(handler)
173
+ bubus_logger.setLevel(logging.INFO if log_type == 'result' else effective_log_level)
174
+
175
+ # Configure CDP logging using cdp_use's setup function
176
+ # This enables the formatted CDP output using CDP_LOGGING_LEVEL environment variable
177
+ # Convert CDP_LOGGING_LEVEL string to logging level
178
+ cdp_level_str = CONFIG.CDP_LOGGING_LEVEL.upper()
179
+ cdp_level = getattr(logging, cdp_level_str, logging.WARNING)
180
+
181
+ try:
182
+ from cdp_use.logging import setup_cdp_logging # type: ignore
183
+
184
+ # Use the CDP-specific logging level
185
+ setup_cdp_logging(
186
+ level=cdp_level,
187
+ stream=stream or sys.stdout,
188
+ format_string='%(levelname)-8s [%(name)s] %(message)s' if log_type != 'result' else '%(message)s',
189
+ )
190
+ except ImportError:
191
+ # If cdp_use doesn't have the new logging module, fall back to manual config
192
+ cdp_loggers = [
193
+ 'websockets.client',
194
+ 'cdp_use',
195
+ 'cdp_use.client',
196
+ 'cdp_use.cdp',
197
+ 'cdp_use.cdp.registry',
198
+ ]
199
+ for logger_name in cdp_loggers:
200
+ cdp_logger = logging.getLogger(logger_name)
201
+ cdp_logger.setLevel(cdp_level)
202
+ cdp_logger.addHandler(console)
203
+ cdp_logger.propagate = False
204
+
205
+ logger = logging.getLogger('browser_use')
206
+ # logger.debug('BrowserUse logging setup complete with level %s', log_type)
207
+
208
+ # Silence third-party loggers (but not CDP ones which we configured above)
209
+ third_party_loggers = [
210
+ 'WDM',
211
+ 'httpx',
212
+ 'selenium',
213
+ 'playwright',
214
+ 'urllib3',
215
+ 'asyncio',
216
+ 'langsmith',
217
+ 'langsmith.client',
218
+ 'openai',
219
+ 'httpcore',
220
+ 'charset_normalizer',
221
+ 'anthropic._base_client',
222
+ 'PIL.PngImagePlugin',
223
+ 'trafilatura.htmlprocessing',
224
+ 'trafilatura',
225
+ 'groq',
226
+ 'portalocker',
227
+ 'google_genai',
228
+ 'portalocker.utils',
229
+ 'websockets', # General websockets (but not websockets.client which we need)
230
+ ]
231
+ for logger_name in third_party_loggers:
232
+ third_party = logging.getLogger(logger_name)
233
+ third_party.setLevel(logging.ERROR)
234
+ third_party.propagate = False
235
+
236
+ return logger
237
+
238
+
239
+ class FIFOHandler(logging.Handler):
240
+ """Non-blocking handler that writes to a named pipe."""
241
+
242
+ def __init__(self, fifo_path: str):
243
+ super().__init__()
244
+ self.fifo_path = fifo_path
245
+ Path(fifo_path).parent.mkdir(parents=True, exist_ok=True)
246
+
247
+ # Create FIFO if it doesn't exist
248
+ if not os.path.exists(fifo_path):
249
+ os.mkfifo(fifo_path)
250
+
251
+ # Don't open the FIFO yet - will open on first write
252
+ self.fd = None
253
+
254
+ def emit(self, record):
255
+ try:
256
+ # Open FIFO on first write if not already open
257
+ if self.fd is None:
258
+ try:
259
+ self.fd = os.open(self.fifo_path, os.O_WRONLY | os.O_NONBLOCK)
260
+ except OSError:
261
+ # No reader connected yet, skip this message
262
+ return
263
+
264
+ msg = f'{self.format(record)}\n'.encode()
265
+ os.write(self.fd, msg)
266
+ except (OSError, BrokenPipeError):
267
+ # Reader disconnected, close and reset
268
+ if self.fd is not None:
269
+ try:
270
+ os.close(self.fd)
271
+ except Exception:
272
+ pass
273
+ self.fd = None
274
+
275
+ def close(self):
276
+ if hasattr(self, 'fd') and self.fd is not None:
277
+ try:
278
+ os.close(self.fd)
279
+ except Exception:
280
+ pass
281
+ super().close()
282
+
283
+
284
+ def setup_log_pipes(session_id: str, base_dir: str | None = None):
285
+ """Setup named pipes for log streaming.
286
+
287
+ Usage:
288
+ # In browser-use:
289
+ setup_log_pipes(session_id="abc123")
290
+
291
+ # In consumer process:
292
+ tail -f {temp_dir}/buagent.c123/agent.pipe
293
+ """
294
+ import tempfile
295
+
296
+ if base_dir is None:
297
+ base_dir = tempfile.gettempdir()
298
+
299
+ suffix = session_id[-4:]
300
+ pipe_dir = Path(base_dir) / f'buagent.{suffix}'
301
+
302
+ # Agent logs
303
+ agent_handler = FIFOHandler(str(pipe_dir / 'agent.pipe'))
304
+ agent_handler.setLevel(logging.DEBUG)
305
+ agent_handler.setFormatter(logging.Formatter('%(levelname)-8s [%(name)s] %(message)s'))
306
+ for name in ['browser_use.agent', 'browser_use.tools']:
307
+ logger = logging.getLogger(name)
308
+ logger.addHandler(agent_handler)
309
+ logger.setLevel(logging.DEBUG)
310
+ logger.propagate = True
311
+
312
+ # CDP logs
313
+ cdp_handler = FIFOHandler(str(pipe_dir / 'cdp.pipe'))
314
+ cdp_handler.setLevel(logging.DEBUG)
315
+ cdp_handler.setFormatter(logging.Formatter('%(levelname)-8s [%(name)s] %(message)s'))
316
+ for name in ['websockets.client', 'cdp_use.client']:
317
+ logger = logging.getLogger(name)
318
+ logger.addHandler(cdp_handler)
319
+ logger.setLevel(logging.DEBUG)
320
+ logger.propagate = True
321
+
322
+ # Event logs
323
+ event_handler = FIFOHandler(str(pipe_dir / 'events.pipe'))
324
+ event_handler.setLevel(logging.INFO)
325
+ event_handler.setFormatter(logging.Formatter('%(levelname)-8s [%(name)s] %(message)s'))
326
+ for name in ['bubus', 'browser_use.browser.session']:
327
+ logger = logging.getLogger(name)
328
+ logger.addHandler(event_handler)
329
+ logger.setLevel(logging.INFO) # Enable INFO for event bus
330
+ logger.propagate = True
@@ -0,0 +1,18 @@
1
+ """MCP (Model Context Protocol) support for browser-use.
2
+
3
+ This module provides integration with MCP servers and clients for browser automation.
4
+ """
5
+
6
+ from browser_use.mcp.client import MCPClient
7
+ from browser_use.mcp.controller import MCPToolWrapper
8
+
9
+ __all__ = ['MCPClient', 'MCPToolWrapper', 'BrowserUseServer'] # type: ignore
10
+
11
+
12
+ def __getattr__(name):
13
+ """Lazy import to avoid importing server module when only client is needed."""
14
+ if name == 'BrowserUseServer':
15
+ from browser_use.mcp.server import BrowserUseServer
16
+
17
+ return BrowserUseServer
18
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
@@ -0,0 +1,12 @@
1
+ """Entry point for running MCP server as a module.
2
+
3
+ Usage:
4
+ python -m browser_use.mcp
5
+ """
6
+
7
+ import asyncio
8
+
9
+ from browser_use.mcp.server import main
10
+
11
+ if __name__ == '__main__':
12
+ asyncio.run(main())