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,335 @@
1
+ """Storage state watchdog for managing browser cookies and storage persistence."""
2
+
3
+ import asyncio
4
+ import json
5
+ import os
6
+ from pathlib import Path
7
+ from typing import Any, ClassVar
8
+
9
+ from bubus import BaseEvent
10
+ from cdp_use.cdp.network import Cookie
11
+ from pydantic import Field, PrivateAttr
12
+
13
+ from browser_use.browser.events import (
14
+ BrowserConnectedEvent,
15
+ BrowserStopEvent,
16
+ LoadStorageStateEvent,
17
+ SaveStorageStateEvent,
18
+ StorageStateLoadedEvent,
19
+ StorageStateSavedEvent,
20
+ )
21
+ from browser_use.browser.watchdog_base import BaseWatchdog
22
+
23
+
24
+ class StorageStateWatchdog(BaseWatchdog):
25
+ """Monitors and persists browser storage state including cookies and localStorage."""
26
+
27
+ # Event contracts
28
+ LISTENS_TO: ClassVar[list[type[BaseEvent]]] = [
29
+ BrowserConnectedEvent,
30
+ BrowserStopEvent,
31
+ SaveStorageStateEvent,
32
+ LoadStorageStateEvent,
33
+ ]
34
+ EMITS: ClassVar[list[type[BaseEvent]]] = [
35
+ StorageStateSavedEvent,
36
+ StorageStateLoadedEvent,
37
+ ]
38
+
39
+ # Configuration
40
+ auto_save_interval: float = Field(default=30.0) # Auto-save every 30 seconds
41
+ save_on_change: bool = Field(default=True) # Save immediately when cookies change
42
+
43
+ # Private state
44
+ _monitoring_task: asyncio.Task | None = PrivateAttr(default=None)
45
+ _last_cookie_state: list[dict] = PrivateAttr(default_factory=list)
46
+ _save_lock: asyncio.Lock = PrivateAttr(default_factory=asyncio.Lock)
47
+
48
+ async def on_BrowserConnectedEvent(self, event: BrowserConnectedEvent) -> None:
49
+ """Start monitoring when browser starts."""
50
+ self.logger.debug('[StorageStateWatchdog] 🍪 Initializing auth/cookies sync <-> with storage_state.json file')
51
+
52
+ # Start monitoring
53
+ await self._start_monitoring()
54
+
55
+ # Automatically load storage state after browser start
56
+ await self.event_bus.dispatch(LoadStorageStateEvent())
57
+
58
+ async def on_BrowserStopEvent(self, event: BrowserStopEvent) -> None:
59
+ """Stop monitoring when browser stops."""
60
+ self.logger.debug('[StorageStateWatchdog] Stopping storage_state monitoring')
61
+ await self._stop_monitoring()
62
+
63
+ async def on_SaveStorageStateEvent(self, event: SaveStorageStateEvent) -> None:
64
+ """Handle storage state save request."""
65
+ # Use provided path or fall back to profile default
66
+ path = event.path
67
+ if path is None:
68
+ # Use profile default path if available
69
+ if self.browser_session.browser_profile.storage_state:
70
+ path = str(self.browser_session.browser_profile.storage_state)
71
+ else:
72
+ path = None # Skip saving if no path available
73
+ await self._save_storage_state(path)
74
+
75
+ async def on_LoadStorageStateEvent(self, event: LoadStorageStateEvent) -> None:
76
+ """Handle storage state load request."""
77
+ # Use provided path or fall back to profile default
78
+ path = event.path
79
+ if path is None:
80
+ # Use profile default path if available
81
+ if self.browser_session.browser_profile.storage_state:
82
+ path = str(self.browser_session.browser_profile.storage_state)
83
+ else:
84
+ path = None # Skip loading if no path available
85
+ await self._load_storage_state(path)
86
+
87
+ async def _start_monitoring(self) -> None:
88
+ """Start the monitoring task."""
89
+ if self._monitoring_task and not self._monitoring_task.done():
90
+ return
91
+
92
+ assert self.browser_session.cdp_client is not None
93
+
94
+ self._monitoring_task = asyncio.create_task(self._monitor_storage_changes())
95
+ # self.logger'[StorageStateWatchdog] Started storage monitoring task')
96
+
97
+ async def _stop_monitoring(self) -> None:
98
+ """Stop the monitoring task."""
99
+ if self._monitoring_task and not self._monitoring_task.done():
100
+ self._monitoring_task.cancel()
101
+ try:
102
+ await self._monitoring_task
103
+ except asyncio.CancelledError:
104
+ pass
105
+ # self.logger.debug('[StorageStateWatchdog] Stopped storage monitoring task')
106
+
107
+ async def _check_for_cookie_changes_cdp(self, event: dict) -> None:
108
+ """Check if a CDP network event indicates cookie changes.
109
+
110
+ This would be called by Network.responseReceivedExtraInfo events
111
+ if we set up CDP event listeners.
112
+ """
113
+ try:
114
+ # Check for Set-Cookie headers in the response
115
+ headers = event.get('headers', {})
116
+ if 'set-cookie' in headers or 'Set-Cookie' in headers:
117
+ self.logger.debug('[StorageStateWatchdog] Cookie change detected via CDP')
118
+
119
+ # If save on change is enabled, trigger save immediately
120
+ if self.save_on_change:
121
+ await self._save_storage_state()
122
+ except Exception as e:
123
+ self.logger.warning(f'[StorageStateWatchdog] Error checking for cookie changes: {e}')
124
+
125
+ async def _monitor_storage_changes(self) -> None:
126
+ """Periodically check for storage changes and auto-save."""
127
+ while True:
128
+ try:
129
+ await asyncio.sleep(self.auto_save_interval)
130
+
131
+ # Check if cookies have changed
132
+ if await self._have_cookies_changed():
133
+ self.logger.debug('[StorageStateWatchdog] Detected changes to sync with storage_state.json')
134
+ await self._save_storage_state()
135
+
136
+ except asyncio.CancelledError:
137
+ break
138
+ except Exception as e:
139
+ self.logger.error(f'[StorageStateWatchdog] Error in monitoring loop: {e}')
140
+
141
+ async def _have_cookies_changed(self) -> bool:
142
+ """Check if cookies have changed since last save."""
143
+ if not self.browser_session.cdp_client:
144
+ return False
145
+
146
+ try:
147
+ # Get current cookies using CDP
148
+ current_cookies = await self.browser_session._cdp_get_cookies()
149
+
150
+ # Convert to comparable format, using .get() for optional fields
151
+ current_cookie_set = {
152
+ (c.get('name', ''), c.get('domain', ''), c.get('path', '')): c.get('value', '') for c in current_cookies
153
+ }
154
+
155
+ last_cookie_set = {
156
+ (c.get('name', ''), c.get('domain', ''), c.get('path', '')): c.get('value', '') for c in self._last_cookie_state
157
+ }
158
+
159
+ return current_cookie_set != last_cookie_set
160
+ except Exception as e:
161
+ self.logger.debug(f'[StorageStateWatchdog] Error comparing cookies: {e}')
162
+ return False
163
+
164
+ async def _save_storage_state(self, path: str | None = None) -> None:
165
+ """Save browser storage state to file."""
166
+ async with self._save_lock:
167
+ # Check if CDP client is available
168
+ assert await self.browser_session.get_or_create_cdp_session(target_id=None)
169
+
170
+ save_path = path or self.browser_session.browser_profile.storage_state
171
+ if not save_path:
172
+ return
173
+
174
+ # Skip saving if the storage state is already a dict (indicates it was loaded from memory)
175
+ # We only save to file if it started as a file path
176
+ if isinstance(save_path, dict):
177
+ self.logger.debug('[StorageStateWatchdog] Storage state is already a dict, skipping file save')
178
+ return
179
+
180
+ try:
181
+ # Get current storage state using CDP
182
+ storage_state = await self.browser_session._cdp_get_storage_state()
183
+
184
+ # Update our last known state
185
+ self._last_cookie_state = storage_state.get('cookies', []).copy()
186
+
187
+ # Convert path to Path object
188
+ json_path = Path(save_path).expanduser().resolve()
189
+ json_path.parent.mkdir(parents=True, exist_ok=True)
190
+
191
+ # Merge with existing state if file exists
192
+ merged_state = storage_state
193
+ if json_path.exists():
194
+ try:
195
+ existing_state = json.loads(json_path.read_text())
196
+ merged_state = self._merge_storage_states(existing_state, dict(storage_state))
197
+ except Exception as e:
198
+ self.logger.error(f'[StorageStateWatchdog] Failed to merge with existing state: {e}')
199
+
200
+ # Write atomically
201
+ temp_path = json_path.with_suffix('.json.tmp')
202
+ temp_path.write_text(json.dumps(merged_state, indent=4))
203
+
204
+ # Backup existing file
205
+ if json_path.exists():
206
+ backup_path = json_path.with_suffix('.json.bak')
207
+ json_path.replace(backup_path)
208
+
209
+ # Move temp to final
210
+ temp_path.replace(json_path)
211
+
212
+ # Emit success event
213
+ self.event_bus.dispatch(
214
+ StorageStateSavedEvent(
215
+ path=str(json_path),
216
+ cookies_count=len(merged_state.get('cookies', [])),
217
+ origins_count=len(merged_state.get('origins', [])),
218
+ )
219
+ )
220
+
221
+ self.logger.debug(
222
+ f'[StorageStateWatchdog] Saved storage state to {json_path} '
223
+ f'({len(merged_state.get("cookies", []))} cookies, '
224
+ f'{len(merged_state.get("origins", []))} origins)'
225
+ )
226
+
227
+ except Exception as e:
228
+ self.logger.error(f'[StorageStateWatchdog] Failed to save storage state: {e}')
229
+
230
+ async def _load_storage_state(self, path: str | None = None) -> None:
231
+ """Load browser storage state from file."""
232
+ if not self.browser_session.cdp_client:
233
+ self.logger.warning('[StorageStateWatchdog] No CDP client available for loading')
234
+ return
235
+
236
+ load_path = path or self.browser_session.browser_profile.storage_state
237
+ if not load_path or not os.path.exists(str(load_path)):
238
+ return
239
+
240
+ try:
241
+ # Read the storage state file asynchronously
242
+ import anyio
243
+
244
+ content = await anyio.Path(str(load_path)).read_text()
245
+ storage = json.loads(content)
246
+
247
+ # Apply cookies if present
248
+ if 'cookies' in storage and storage['cookies']:
249
+ await self.browser_session._cdp_set_cookies(storage['cookies'])
250
+ self._last_cookie_state = storage['cookies'].copy()
251
+ self.logger.debug(f'[StorageStateWatchdog] Added {len(storage["cookies"])} cookies from storage state')
252
+
253
+ # Apply origins (localStorage/sessionStorage) if present
254
+ if 'origins' in storage and storage['origins']:
255
+ for origin in storage['origins']:
256
+ if 'localStorage' in origin:
257
+ for item in origin['localStorage']:
258
+ script = f"""
259
+ window.localStorage.setItem({json.dumps(item['name'])}, {json.dumps(item['value'])});
260
+ """
261
+ await self.browser_session._cdp_add_init_script(script)
262
+ if 'sessionStorage' in origin:
263
+ for item in origin['sessionStorage']:
264
+ script = f"""
265
+ window.sessionStorage.setItem({json.dumps(item['name'])}, {json.dumps(item['value'])});
266
+ """
267
+ await self.browser_session._cdp_add_init_script(script)
268
+ self.logger.debug(
269
+ f'[StorageStateWatchdog] Applied localStorage/sessionStorage from {len(storage["origins"])} origins'
270
+ )
271
+
272
+ self.event_bus.dispatch(
273
+ StorageStateLoadedEvent(
274
+ path=str(load_path),
275
+ cookies_count=len(storage.get('cookies', [])),
276
+ origins_count=len(storage.get('origins', [])),
277
+ )
278
+ )
279
+
280
+ self.logger.debug(f'[StorageStateWatchdog] Loaded storage state from: {load_path}')
281
+
282
+ except Exception as e:
283
+ self.logger.error(f'[StorageStateWatchdog] Failed to load storage state: {e}')
284
+
285
+ @staticmethod
286
+ def _merge_storage_states(existing: dict[str, Any], new: dict[str, Any]) -> dict[str, Any]:
287
+ """Merge two storage states, with new values taking precedence."""
288
+ merged = existing.copy()
289
+
290
+ # Merge cookies
291
+ existing_cookies = {(c['name'], c['domain'], c['path']): c for c in existing.get('cookies', [])}
292
+
293
+ for cookie in new.get('cookies', []):
294
+ key = (cookie['name'], cookie['domain'], cookie['path'])
295
+ existing_cookies[key] = cookie
296
+
297
+ merged['cookies'] = list(existing_cookies.values())
298
+
299
+ # Merge origins
300
+ existing_origins = {origin['origin']: origin for origin in existing.get('origins', [])}
301
+
302
+ for origin in new.get('origins', []):
303
+ existing_origins[origin['origin']] = origin
304
+
305
+ merged['origins'] = list(existing_origins.values())
306
+
307
+ return merged
308
+
309
+ async def get_current_cookies(self) -> list[dict[str, Any]]:
310
+ """Get current cookies using CDP."""
311
+ if not self.browser_session.cdp_client:
312
+ return []
313
+
314
+ try:
315
+ cookies = await self.browser_session._cdp_get_cookies()
316
+ # Cookie is a TypedDict, cast to dict for compatibility
317
+ return [dict(cookie) for cookie in cookies]
318
+ except Exception as e:
319
+ self.logger.error(f'[StorageStateWatchdog] Failed to get cookies: {e}')
320
+ return []
321
+
322
+ async def add_cookies(self, cookies: list[dict[str, Any]]) -> None:
323
+ """Add cookies using CDP."""
324
+ if not self.browser_session.cdp_client:
325
+ self.logger.warning('[StorageStateWatchdog] No CDP client available for adding cookies')
326
+ return
327
+
328
+ try:
329
+ # Convert dicts to Cookie objects
330
+ cookie_objects = [Cookie(**cookie_dict) if isinstance(cookie_dict, dict) else cookie_dict for cookie_dict in cookies]
331
+ # Set cookies using CDP
332
+ await self.browser_session._cdp_set_cookies(cookie_objects)
333
+ self.logger.debug(f'[StorageStateWatchdog] Added {len(cookies)} cookies')
334
+ except Exception as e:
335
+ self.logger.error(f'[StorageStateWatchdog] Failed to add cookies: {e}')