camel-ai 0.2.75a6__py3-none-any.whl → 0.2.76a1__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.

Potentially problematic release.


This version of camel-ai might be problematic. Click here for more details.

Files changed (52) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +159 -38
  3. camel/configs/__init__.py +3 -0
  4. camel/configs/amd_config.py +70 -0
  5. camel/interpreters/__init__.py +2 -0
  6. camel/interpreters/microsandbox_interpreter.py +395 -0
  7. camel/memories/__init__.py +2 -1
  8. camel/memories/agent_memories.py +3 -1
  9. camel/memories/blocks/chat_history_block.py +17 -2
  10. camel/models/__init__.py +2 -0
  11. camel/models/amd_model.py +101 -0
  12. camel/models/model_factory.py +2 -0
  13. camel/models/openai_model.py +0 -6
  14. camel/runtimes/daytona_runtime.py +11 -12
  15. camel/societies/workforce/single_agent_worker.py +44 -38
  16. camel/storages/object_storages/google_cloud.py +1 -1
  17. camel/toolkits/__init__.py +14 -5
  18. camel/toolkits/aci_toolkit.py +45 -0
  19. camel/toolkits/code_execution.py +28 -1
  20. camel/toolkits/context_summarizer_toolkit.py +683 -0
  21. camel/toolkits/{file_write_toolkit.py → file_toolkit.py} +194 -34
  22. camel/toolkits/function_tool.py +6 -1
  23. camel/toolkits/hybrid_browser_toolkit/config_loader.py +12 -0
  24. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +19 -2
  25. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +95 -59
  26. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +619 -95
  27. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +7 -2
  28. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +115 -219
  29. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  30. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
  31. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  32. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +1 -0
  33. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +39 -6
  34. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +401 -80
  35. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +9 -5
  36. camel/toolkits/{openai_image_toolkit.py → image_generation_toolkit.py} +98 -31
  37. camel/toolkits/markitdown_toolkit.py +27 -1
  38. camel/toolkits/mcp_toolkit.py +39 -14
  39. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  40. camel/toolkits/note_taking_toolkit.py +18 -8
  41. camel/toolkits/terminal_toolkit.py +12 -2
  42. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  43. camel/toolkits/video_analysis_toolkit.py +16 -10
  44. camel/toolkits/wechat_official_toolkit.py +483 -0
  45. camel/types/enums.py +11 -0
  46. camel/utils/commons.py +2 -0
  47. camel/utils/context_utils.py +395 -0
  48. camel/utils/mcp.py +136 -2
  49. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76a1.dist-info}/METADATA +6 -3
  50. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76a1.dist-info}/RECORD +52 -41
  51. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76a1.dist-info}/WHEEL +0 -0
  52. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76a1.dist-info}/licenses/LICENSE +0 -0
@@ -37,7 +37,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
37
37
  _snapshotForAI functionality for enhanced AI integration.
38
38
  """
39
39
 
40
- # Default tool list - core browser functionality
41
40
  DEFAULT_TOOLS: ClassVar[List[str]] = [
42
41
  "browser_open",
43
42
  "browser_close",
@@ -49,7 +48,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
49
48
  "browser_switch_tab",
50
49
  ]
51
50
 
52
- # All available tools
53
51
  ALL_TOOLS: ClassVar[List[str]] = [
54
52
  "browser_open",
55
53
  "browser_close",
@@ -83,11 +81,12 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
83
81
  user_data_dir: Optional[str] = None,
84
82
  stealth: bool = False,
85
83
  web_agent_model: Optional[BaseModelBackend] = None,
86
- cache_dir: str = "tmp/",
84
+ cache_dir: Optional[str] = None,
87
85
  enabled_tools: Optional[List[str]] = None,
88
86
  browser_log_to_file: bool = False,
87
+ log_dir: Optional[str] = None,
89
88
  session_id: Optional[str] = None,
90
- default_start_url: str = "https://google.com/",
89
+ default_start_url: Optional[str] = None,
91
90
  default_timeout: Optional[int] = None,
92
91
  short_timeout: Optional[int] = None,
93
92
  navigation_timeout: Optional[int] = None,
@@ -98,6 +97,8 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
98
97
  viewport_limit: bool = False,
99
98
  connect_over_cdp: bool = False,
100
99
  cdp_url: Optional[str] = None,
100
+ cdp_keep_current_page: bool = False,
101
+ full_visual_mode: bool = False,
101
102
  ) -> None:
102
103
  r"""Initialize the HybridBrowserToolkit.
103
104
 
@@ -115,6 +116,8 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
115
116
  Defaults to None.
116
117
  browser_log_to_file (bool): Whether to log browser actions to
117
118
  file. Defaults to False.
119
+ log_dir (Optional[str]): Custom directory path for log files.
120
+ If None, defaults to "browser_log". Defaults to None.
118
121
  session_id (Optional[str]): Session identifier. Defaults to None.
119
122
  default_start_url (str): Default URL to start with. Defaults
120
123
  to "https://google.com/".
@@ -143,11 +146,15 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
143
146
  cdp_url (Optional[str]): WebSocket endpoint URL for CDP
144
147
  connection (e.g., 'ws://localhost:9222/devtools/browser/...').
145
148
  Required when connect_over_cdp is True. Defaults to None.
149
+ cdp_keep_current_page (bool): When True and using CDP mode,
150
+ won't create new pages but use the existing one. Defaults to False.
151
+ full_visual_mode (bool): When True, browser actions like click,
152
+ browser_open, visit_page, etc. will not return snapshots.
153
+ Defaults to False.
146
154
  """
147
155
  super().__init__()
148
156
  RegisteredAgentToolkit.__init__(self)
149
157
 
150
- # Initialize configuration loader
151
158
  self.config_loader = ConfigLoader.from_kwargs(
152
159
  headless=headless,
153
160
  user_data_dir=user_data_dir,
@@ -163,16 +170,29 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
163
170
  viewport_limit=viewport_limit,
164
171
  cache_dir=cache_dir,
165
172
  browser_log_to_file=browser_log_to_file,
173
+ log_dir=log_dir,
166
174
  session_id=session_id,
167
175
  enabled_tools=enabled_tools,
168
176
  connect_over_cdp=connect_over_cdp,
169
177
  cdp_url=cdp_url,
178
+ cdp_keep_current_page=cdp_keep_current_page,
179
+ full_visual_mode=full_visual_mode,
170
180
  )
171
181
 
172
- # Legacy attribute access for backward compatibility
173
182
  browser_config = self.config_loader.get_browser_config()
174
183
  toolkit_config = self.config_loader.get_toolkit_config()
175
184
 
185
+ if (
186
+ browser_config.cdp_keep_current_page
187
+ and default_start_url is not None
188
+ ):
189
+ raise ValueError(
190
+ "Cannot use default_start_url with "
191
+ "cdp_keep_current_page=True. When cdp_keep_current_page "
192
+ "is True, the browser will keep the current page and not "
193
+ "navigate to any URL."
194
+ )
195
+
176
196
  self._headless = browser_config.headless
177
197
  self._user_data_dir = browser_config.user_data_dir
178
198
  self._stealth = browser_config.stealth
@@ -182,8 +202,8 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
182
202
  self._default_start_url = browser_config.default_start_url
183
203
  self._session_id = toolkit_config.session_id or "default"
184
204
  self._viewport_limit = browser_config.viewport_limit
205
+ self._full_visual_mode = browser_config.full_visual_mode
185
206
 
186
- # Store timeout configuration for backward compatibility
187
207
  self._default_timeout = browser_config.default_timeout
188
208
  self._short_timeout = browser_config.short_timeout
189
209
  self._navigation_timeout = browser_config.navigation_timeout
@@ -194,11 +214,9 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
194
214
  browser_config.dom_content_loaded_timeout
195
215
  )
196
216
 
197
- # Configure enabled tools
198
217
  if enabled_tools is None:
199
218
  self.enabled_tools = self.DEFAULT_TOOLS.copy()
200
219
  else:
201
- # Validate enabled tools
202
220
  invalid_tools = [
203
221
  tool for tool in enabled_tools if tool not in self.ALL_TOOLS
204
222
  ]
@@ -211,7 +229,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
211
229
 
212
230
  logger.info(f"Enabled tools: {self.enabled_tools}")
213
231
 
214
- # Initialize WebSocket wrapper
215
232
  self._ws_wrapper: Optional[WebSocketBrowserWrapper] = None
216
233
  self._ws_config = self.config_loader.to_ws_config()
217
234
 
@@ -238,13 +255,29 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
238
255
 
239
256
  import asyncio
240
257
 
258
+ is_cdp = (
259
+ self._ws_config.get('connectOverCdp', False)
260
+ if hasattr(self, '_ws_config')
261
+ else False
262
+ )
263
+
241
264
  try:
242
265
  loop = asyncio.get_event_loop()
243
266
  if not loop.is_closed() and not loop.is_running():
244
267
  try:
245
- loop.run_until_complete(
246
- asyncio.wait_for(self.browser_close(), timeout=2.0)
247
- )
268
+ if is_cdp:
269
+ # CDP: disconnect only
270
+ loop.run_until_complete(
271
+ asyncio.wait_for(
272
+ self.disconnect_websocket(), timeout=2.0
273
+ )
274
+ )
275
+ else:
276
+ loop.run_until_complete(
277
+ asyncio.wait_for(
278
+ self.browser_close(), timeout=2.0
279
+ )
280
+ )
248
281
  except asyncio.TimeoutError:
249
282
  pass
250
283
  except (RuntimeError, ImportError):
@@ -267,8 +300,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
267
300
  """Get the cache directory."""
268
301
  return self._cache_dir
269
302
 
270
- # Public API Methods
271
-
272
303
  async def browser_open(self) -> Dict[str, Any]:
273
304
  r"""Starts a new browser session. This must be the first browser
274
305
  action.
@@ -289,7 +320,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
289
320
  ws_wrapper = await self._get_ws_wrapper()
290
321
  result = await ws_wrapper.open_browser(self._default_start_url)
291
322
 
292
- # Add tab information
293
323
  tab_info = await ws_wrapper.get_tab_info()
294
324
  result.update(
295
325
  {
@@ -334,6 +364,31 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
334
364
  logger.error(f"Failed to close browser: {e}")
335
365
  return f"Error closing browser: {e}"
336
366
 
367
+ async def disconnect_websocket(self) -> str:
368
+ r"""Disconnects the WebSocket connection without closing the browser.
369
+
370
+ This is useful when using CDP mode where the browser should
371
+ remain open.
372
+
373
+ Returns:
374
+ str: A confirmation message.
375
+ """
376
+ try:
377
+ if self._ws_wrapper:
378
+ is_cdp = self._ws_config.get('connectOverCdp', False)
379
+
380
+ if is_cdp:
381
+ # CDP: disconnect only
382
+ await self._ws_wrapper.disconnect_only()
383
+ else:
384
+ await self._ws_wrapper.stop()
385
+
386
+ self._ws_wrapper = None
387
+ return "WebSocket disconnected."
388
+ except Exception as e:
389
+ logger.error(f"Failed to disconnect WebSocket: {e}")
390
+ return f"Error disconnecting WebSocket: {e}"
391
+
337
392
  async def browser_visit_page(self, url: str) -> Dict[str, Any]:
338
393
  r"""Opens a URL in a new browser tab and switches to it.
339
394
 
@@ -353,7 +408,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
353
408
  ws_wrapper = await self._get_ws_wrapper()
354
409
  result = await ws_wrapper.visit_page(url)
355
410
 
356
- # Add tab information
357
411
  tab_info = await ws_wrapper.get_tab_info()
358
412
  result.update(
359
413
  {
@@ -399,7 +453,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
399
453
  ws_wrapper = await self._get_ws_wrapper()
400
454
  result = await ws_wrapper.back()
401
455
 
402
- # Add tab information
403
456
  tab_info = await ws_wrapper.get_tab_info()
404
457
  result.update(
405
458
  {
@@ -445,7 +498,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
445
498
  ws_wrapper = await self._get_ws_wrapper()
446
499
  result = await ws_wrapper.forward()
447
500
 
448
- # Add tab information
449
501
  tab_info = await ws_wrapper.get_tab_info()
450
502
  result.update(
451
503
  {
@@ -537,19 +589,14 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
537
589
  ws_wrapper = await self._get_ws_wrapper()
538
590
  result = await ws_wrapper.get_som_screenshot()
539
591
 
540
- # Initialize result text
541
592
  result_text = result.text
542
593
  file_path = None
543
594
 
544
- # Save screenshot to cache directory if images are available
545
595
  if result.images:
546
- # Ensure cache directory exists (use absolute path)
547
596
  cache_dir = os.path.abspath(self._cache_dir)
548
597
  os.makedirs(cache_dir, exist_ok=True)
549
598
 
550
- # Get current page URL for filename
551
599
  try:
552
- # Try to get the current page URL from the wrapper
553
600
  page_info = await ws_wrapper.get_tab_info()
554
601
  current_tab = next(
555
602
  (tab for tab in page_info if tab.get('is_current')),
@@ -559,7 +606,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
559
606
  except Exception:
560
607
  url = 'unknown'
561
608
 
562
- # Generate filename
563
609
  parsed_url = urllib.parse.urlparse(url)
564
610
  url_name = sanitize_filename(
565
611
  str(parsed_url.path) or 'homepage', max_length=241
@@ -569,24 +615,19 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
569
615
  cache_dir, f"{url_name}_{timestamp}_som.png"
570
616
  )
571
617
 
572
- # Extract base64 data and save to file
573
618
  for _, image_data in enumerate(result.images):
574
619
  if image_data.startswith('data:image/png;base64,'):
575
- # Remove data URL prefix
576
620
  base64_data = image_data.split(',', 1)[1]
577
621
 
578
- # Decode and save
579
622
  image_bytes = base64.b64decode(base64_data)
580
623
  with open(file_path, 'wb') as f:
581
624
  f.write(image_bytes)
582
625
 
583
626
  logger.info(f"Screenshot saved to: {file_path}")
584
627
 
585
- # Update result text to include file path
586
628
  result_text += f" (saved to: {file_path})"
587
629
  break
588
630
 
589
- # Analyze image if requested and agent is registered
590
631
  if read_image and file_path:
591
632
  if self.agent is None:
592
633
  logger.error(
@@ -601,7 +642,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
601
642
  )
602
643
  else:
603
644
  try:
604
- # Load the image and create a message
605
645
  from PIL import Image
606
646
 
607
647
  img = Image.open(file_path)
@@ -612,7 +652,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
612
652
  image_list=[img],
613
653
  )
614
654
 
615
- # Get agent's analysis
616
655
  response = await self.agent.astep(message)
617
656
  agent_response = response.msgs[0].content
618
657
  result_text += f". Agent analysis: {agent_response}"
@@ -646,24 +685,30 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
646
685
  ws_wrapper = await self._get_ws_wrapper()
647
686
  result = await ws_wrapper.click(ref)
648
687
 
649
- # Add tab information
650
688
  tab_info = await ws_wrapper.get_tab_info()
651
- result.update(
652
- {
653
- "tabs": tab_info,
654
- "current_tab": next(
655
- (
656
- i
657
- for i, tab in enumerate(tab_info)
658
- if tab.get("is_current")
659
- ),
660
- 0,
689
+
690
+ response = {
691
+ "result": result.get("result", ""),
692
+ "snapshot": result.get("snapshot", ""),
693
+ "tabs": tab_info,
694
+ "current_tab": next(
695
+ (
696
+ i
697
+ for i, tab in enumerate(tab_info)
698
+ if tab.get("is_current")
661
699
  ),
662
- "total_tabs": len(tab_info),
663
- }
664
- )
700
+ 0,
701
+ ),
702
+ "total_tabs": len(tab_info),
703
+ }
665
704
 
666
- return result
705
+ if "newTabId" in result:
706
+ response["newTabId"] = result["newTabId"]
707
+
708
+ if "timing" in result:
709
+ response["timing"] = result["timing"]
710
+
711
+ return response
667
712
  except Exception as e:
668
713
  logger.error(f"Failed to click element: {e}")
669
714
  return {
@@ -712,10 +757,8 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
712
757
  try:
713
758
  ws_wrapper = await self._get_ws_wrapper()
714
759
 
715
- # Handle single input mode (backward compatibility)
716
760
  if ref is not None and text is not None:
717
761
  result = await ws_wrapper.type(ref, text)
718
- # Handle multiple inputs mode
719
762
  elif inputs is not None:
720
763
  result = await ws_wrapper.type_multiple(inputs)
721
764
  else:
@@ -724,7 +767,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
724
767
  "or 'inputs' for multiple inputs"
725
768
  )
726
769
 
727
- # Add tab information
728
770
  tab_info = await ws_wrapper.get_tab_info()
729
771
  result.update(
730
772
  {
@@ -773,7 +815,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
773
815
  ws_wrapper = await self._get_ws_wrapper()
774
816
  result = await ws_wrapper.select(ref, value)
775
817
 
776
- # Add tab information
777
818
  tab_info = await ws_wrapper.get_tab_info()
778
819
  result.update(
779
820
  {
@@ -822,7 +863,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
822
863
  ws_wrapper = await self._get_ws_wrapper()
823
864
  result = await ws_wrapper.scroll(direction, amount)
824
865
 
825
- # Add tab information
826
866
  tab_info = await ws_wrapper.get_tab_info()
827
867
  result.update(
828
868
  {
@@ -870,7 +910,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
870
910
  ws_wrapper = await self._get_ws_wrapper()
871
911
  result = await ws_wrapper.enter()
872
912
 
873
- # Add tab information
874
913
  tab_info = await ws_wrapper.get_tab_info()
875
914
  result.update(
876
915
  {
@@ -922,7 +961,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
922
961
  ws_wrapper = await self._get_ws_wrapper()
923
962
  result = await ws_wrapper.mouse_control(control, x, y)
924
963
 
925
- # Add tab information
926
964
  tab_info = await ws_wrapper.get_tab_info()
927
965
  result.update(
928
966
  {
@@ -971,7 +1009,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
971
1009
  ws_wrapper = await self._get_ws_wrapper()
972
1010
  result = await ws_wrapper.mouse_drag(from_ref, to_ref)
973
1011
 
974
- # Add tab information
975
1012
  tab_info = await ws_wrapper.get_tab_info()
976
1013
  result.update(
977
1014
  {
@@ -1020,7 +1057,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
1020
1057
  ws_wrapper = await self._get_ws_wrapper()
1021
1058
  result = await ws_wrapper.press_key(keys)
1022
1059
 
1023
- # Add tab information
1024
1060
  tab_info = await ws_wrapper.get_tab_info()
1025
1061
  result.update(
1026
1062
  {
@@ -1069,7 +1105,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
1069
1105
  ws_wrapper = await self._get_ws_wrapper()
1070
1106
  result = await ws_wrapper.switch_tab(tab_id)
1071
1107
 
1072
- # Add tab information
1073
1108
  tab_info = await ws_wrapper.get_tab_info()
1074
1109
  result.update(
1075
1110
  {
@@ -1119,7 +1154,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
1119
1154
  ws_wrapper = await self._get_ws_wrapper()
1120
1155
  result = await ws_wrapper.close_tab(tab_id)
1121
1156
 
1122
- # Add tab information
1123
1157
  tab_info = await ws_wrapper.get_tab_info()
1124
1158
  result.update(
1125
1159
  {
@@ -1377,6 +1411,8 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
1377
1411
  screenshot_timeout=self._screenshot_timeout,
1378
1412
  page_stability_timeout=self._page_stability_timeout,
1379
1413
  dom_content_loaded_timeout=self._dom_content_loaded_timeout,
1414
+ viewport_limit=self._viewport_limit,
1415
+ full_visual_mode=self._full_visual_mode,
1380
1416
  )
1381
1417
 
1382
1418
  def get_tools(self) -> List[FunctionTool]:
@@ -1396,7 +1432,7 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
1396
1432
  "browser_select": self.browser_select,
1397
1433
  "browser_scroll": self.browser_scroll,
1398
1434
  "browser_enter": self.browser_enter,
1399
- "browser_mouse_click": self.browser_mouse_control,
1435
+ "browser_mouse_control": self.browser_mouse_control,
1400
1436
  "browser_mouse_drag": self.browser_mouse_drag,
1401
1437
  "browser_press_key": self.browser_press_key,
1402
1438
  "browser_wait_user": self.browser_wait_user,