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,264 @@
1
+ """MCP (Model Context Protocol) tool wrapper for browser-use.
2
+
3
+ This module provides integration between MCP tools and browser-use's action registry system.
4
+ MCP tools are dynamically discovered and registered as browser-use actions.
5
+ """
6
+
7
+ import asyncio
8
+ import logging
9
+ from typing import Any
10
+
11
+ from pydantic import Field, create_model
12
+
13
+ from browser_use.agent.views import ActionResult
14
+ from browser_use.tools.registry.service import Registry
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ try:
19
+ from mcp import ClientSession, StdioServerParameters
20
+ from mcp.client.stdio import stdio_client
21
+ from mcp.types import TextContent, Tool
22
+
23
+ MCP_AVAILABLE = True
24
+ except ImportError:
25
+ MCP_AVAILABLE = False
26
+ logger.warning('MCP SDK not installed. Install with: pip install mcp')
27
+
28
+
29
+ class MCPToolWrapper:
30
+ """Wrapper to integrate MCP tools as browser-use actions."""
31
+
32
+ def __init__(self, registry: Registry, mcp_command: str, mcp_args: list[str] | None = None):
33
+ """Initialize MCP tool wrapper.
34
+
35
+ Args:
36
+ registry: Browser-use action registry to register MCP tools
37
+ mcp_command: Command to start MCP server (e.g., "npx")
38
+ mcp_args: Arguments for MCP command (e.g., ["@playwright/mcp@latest"])
39
+ """
40
+ if not MCP_AVAILABLE:
41
+ raise ImportError('MCP SDK not installed. Install with: pip install mcp')
42
+
43
+ self.registry = registry
44
+ self.mcp_command = mcp_command
45
+ self.mcp_args = mcp_args or []
46
+ self.session: ClientSession | None = None
47
+ self._tools: dict[str, Tool] = {}
48
+ self._registered_actions: set[str] = set()
49
+ self._shutdown_event = asyncio.Event()
50
+
51
+ async def connect(self):
52
+ """Connect to MCP server and discover available tools."""
53
+ if self.session:
54
+ return # Already connected
55
+
56
+ logger.info(f'🔌 Connecting to MCP server: {self.mcp_command} {" ".join(self.mcp_args)}')
57
+
58
+ # Create server parameters
59
+ server_params = StdioServerParameters(command=self.mcp_command, args=self.mcp_args, env=None)
60
+
61
+ # Connect to the MCP server
62
+ async with stdio_client(server_params) as (read, write):
63
+ async with ClientSession(read, write) as session:
64
+ self.session = session
65
+
66
+ # Initialize the connection
67
+ await session.initialize()
68
+
69
+ # Discover available tools
70
+ tools_response = await session.list_tools()
71
+ self._tools = {tool.name: tool for tool in tools_response.tools}
72
+
73
+ logger.info(f'📦 Discovered {len(self._tools)} MCP tools: {list(self._tools.keys())}')
74
+
75
+ # Register all discovered tools as actions
76
+ for tool_name, tool in self._tools.items():
77
+ self._register_tool_as_action(tool_name, tool)
78
+
79
+ # Keep session alive while tools are being used
80
+ await self._keep_session_alive()
81
+
82
+ async def _keep_session_alive(self):
83
+ """Keep the MCP session alive."""
84
+ # This will block until the session is closed
85
+ # In practice, you'd want to manage this lifecycle better
86
+ try:
87
+ await self._shutdown_event.wait()
88
+ except asyncio.CancelledError:
89
+ pass
90
+
91
+ def _register_tool_as_action(self, tool_name: str, tool: Tool):
92
+ """Register an MCP tool as a browser-use action.
93
+
94
+ Args:
95
+ tool_name: Name of the MCP tool
96
+ tool: MCP Tool object with schema information
97
+ """
98
+ if tool_name in self._registered_actions:
99
+ return # Already registered
100
+
101
+ # Parse tool parameters to create Pydantic model
102
+ param_fields = {}
103
+
104
+ if tool.inputSchema:
105
+ # MCP tools use JSON Schema for parameters
106
+ properties = tool.inputSchema.get('properties', {})
107
+ required = set(tool.inputSchema.get('required', []))
108
+
109
+ for param_name, param_schema in properties.items():
110
+ # Convert JSON Schema type to Python type
111
+ param_type = self._json_schema_to_python_type(param_schema)
112
+
113
+ # Determine if field is required
114
+ if param_name in required:
115
+ default = ... # Required field
116
+ else:
117
+ default = param_schema.get('default', None)
118
+
119
+ # Add field description if available
120
+ field_kwargs = {}
121
+ if 'description' in param_schema:
122
+ field_kwargs['description'] = param_schema['description']
123
+
124
+ param_fields[param_name] = (param_type, Field(default, **field_kwargs))
125
+
126
+ # Create Pydantic model for the tool parameters
127
+ param_model = create_model(f'{tool_name}_Params', **param_fields) if param_fields else None
128
+
129
+ # Determine if this is a browser-specific tool
130
+ is_browser_tool = tool_name.startswith('browser_')
131
+ domains = None
132
+ # Note: page_filter has been removed since we no longer use Page objects
133
+
134
+ # Create wrapper function for the MCP tool
135
+ async def mcp_action_wrapper(**kwargs):
136
+ """Wrapper function that calls the MCP tool."""
137
+ if not self.session:
138
+ raise RuntimeError(f'MCP session not connected for tool {tool_name}')
139
+
140
+ # Extract parameters (excluding special injected params)
141
+ special_params = {
142
+ 'page',
143
+ 'browser_session',
144
+ 'context',
145
+ 'page_extraction_llm',
146
+ 'file_system',
147
+ 'available_file_paths',
148
+ 'has_sensitive_data',
149
+ 'browser',
150
+ 'browser_context',
151
+ }
152
+
153
+ tool_params = {k: v for k, v in kwargs.items() if k not in special_params}
154
+
155
+ logger.debug(f'🔧 Calling MCP tool {tool_name} with params: {tool_params}')
156
+
157
+ try:
158
+ # Call the MCP tool
159
+ result = await self.session.call_tool(tool_name, tool_params)
160
+
161
+ # Convert MCP result to ActionResult
162
+ # MCP tools return results in various formats
163
+ if hasattr(result, 'content'):
164
+ # Handle structured content responses
165
+ if isinstance(result.content, list):
166
+ # Multiple content items
167
+ content_parts = []
168
+ for item in result.content:
169
+ if isinstance(item, TextContent):
170
+ content_parts.append(item.text) # type: ignore[reportAttributeAccessIssue]
171
+ else:
172
+ content_parts.append(str(item))
173
+ extracted_content = '\n'.join(content_parts)
174
+ else:
175
+ extracted_content = str(result.content)
176
+ else:
177
+ # Direct result
178
+ extracted_content = str(result)
179
+
180
+ return ActionResult(extracted_content=extracted_content)
181
+
182
+ except Exception as e:
183
+ logger.error(f'❌ MCP tool {tool_name} failed: {e}')
184
+ return ActionResult(extracted_content=f'MCP tool {tool_name} failed: {str(e)}', error=str(e))
185
+
186
+ # Set function name for better debugging
187
+ mcp_action_wrapper.__name__ = tool_name
188
+ mcp_action_wrapper.__qualname__ = f'mcp.{tool_name}'
189
+
190
+ # Register the action with browser-use
191
+ description = tool.description or f'MCP tool: {tool_name}'
192
+
193
+ # Use the decorator to register the action
194
+ decorated_wrapper = self.registry.action(description=description, param_model=param_model, domains=domains)(
195
+ mcp_action_wrapper
196
+ )
197
+
198
+ self._registered_actions.add(tool_name)
199
+ logger.info(f'✅ Registered MCP tool as action: {tool_name}')
200
+
201
+ async def disconnect(self):
202
+ """Disconnect from the MCP server and clean up resources."""
203
+ self._shutdown_event.set()
204
+ if self.session:
205
+ # Session cleanup will be handled by the context manager
206
+ self.session = None
207
+
208
+ def _json_schema_to_python_type(self, schema: dict) -> Any:
209
+ """Convert JSON Schema type to Python type.
210
+
211
+ Args:
212
+ schema: JSON Schema definition
213
+
214
+ Returns:
215
+ Python type corresponding to the schema
216
+ """
217
+ json_type = schema.get('type', 'string')
218
+
219
+ type_mapping = {
220
+ 'string': str,
221
+ 'number': float,
222
+ 'integer': int,
223
+ 'boolean': bool,
224
+ 'array': list,
225
+ 'object': dict,
226
+ }
227
+
228
+ base_type = type_mapping.get(json_type, str)
229
+
230
+ # Handle nullable types
231
+ if schema.get('nullable', False):
232
+ return base_type | None
233
+
234
+ return base_type
235
+
236
+
237
+ # Convenience function for easy integration
238
+ async def register_mcp_tools(registry: Registry, mcp_command: str, mcp_args: list[str] | None = None) -> MCPToolWrapper:
239
+ """Register MCP tools with a browser-use registry.
240
+
241
+ Args:
242
+ registry: Browser-use action registry
243
+ mcp_command: Command to start MCP server
244
+ mcp_args: Arguments for MCP command
245
+
246
+ Returns:
247
+ MCPToolWrapper instance (connected)
248
+
249
+ Example:
250
+ ```python
251
+ from browser_use import Tools
252
+ from browser_use.mcp.tools import register_mcp_tools
253
+
254
+ tools = Tools()
255
+
256
+ # Register Playwright MCP tools
257
+ mcp = await register_mcp_tools(tools.registry, 'npx', ['@playwright/mcp@latest', '--headless'])
258
+
259
+ # Now all MCP tools are available as browser-use actions
260
+ ```
261
+ """
262
+ wrapper = MCPToolWrapper(registry, mcp_command, mcp_args)
263
+ await wrapper.connect()
264
+ return wrapper