camel-ai 0.2.76a0__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 (30) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +8 -1
  3. camel/memories/__init__.py +2 -1
  4. camel/memories/agent_memories.py +3 -1
  5. camel/memories/blocks/chat_history_block.py +17 -2
  6. camel/societies/workforce/single_agent_worker.py +44 -38
  7. camel/storages/object_storages/google_cloud.py +1 -1
  8. camel/toolkits/__init__.py +9 -2
  9. camel/toolkits/aci_toolkit.py +45 -0
  10. camel/toolkits/context_summarizer_toolkit.py +683 -0
  11. camel/toolkits/{file_write_toolkit.py → file_toolkit.py} +194 -34
  12. camel/toolkits/hybrid_browser_toolkit/config_loader.py +4 -0
  13. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +7 -2
  14. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +62 -45
  15. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +489 -60
  16. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +5 -2
  17. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +72 -12
  18. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +2 -14
  19. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +1 -0
  20. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +196 -60
  21. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +4 -4
  22. camel/toolkits/markitdown_toolkit.py +27 -1
  23. camel/toolkits/note_taking_toolkit.py +18 -8
  24. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  25. camel/toolkits/wechat_official_toolkit.py +483 -0
  26. camel/utils/context_utils.py +395 -0
  27. {camel_ai-0.2.76a0.dist-info → camel_ai-0.2.76a1.dist-info}/METADATA +2 -1
  28. {camel_ai-0.2.76a0.dist-info → camel_ai-0.2.76a1.dist-info}/RECORD +30 -26
  29. {camel_ai-0.2.76a0.dist-info → camel_ai-0.2.76a1.dist-info}/WHEEL +0 -0
  30. {camel_ai-0.2.76a0.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,12 +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,
89
87
  log_dir: Optional[str] = None,
90
88
  session_id: Optional[str] = None,
91
- default_start_url: str = "https://google.com/",
89
+ default_start_url: Optional[str] = None,
92
90
  default_timeout: Optional[int] = None,
93
91
  short_timeout: Optional[int] = None,
94
92
  navigation_timeout: Optional[int] = None,
@@ -99,6 +97,7 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
99
97
  viewport_limit: bool = False,
100
98
  connect_over_cdp: bool = False,
101
99
  cdp_url: Optional[str] = None,
100
+ cdp_keep_current_page: bool = False,
102
101
  full_visual_mode: bool = False,
103
102
  ) -> None:
104
103
  r"""Initialize the HybridBrowserToolkit.
@@ -147,6 +146,8 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
147
146
  cdp_url (Optional[str]): WebSocket endpoint URL for CDP
148
147
  connection (e.g., 'ws://localhost:9222/devtools/browser/...').
149
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.
150
151
  full_visual_mode (bool): When True, browser actions like click,
151
152
  browser_open, visit_page, etc. will not return snapshots.
152
153
  Defaults to False.
@@ -154,7 +155,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
154
155
  super().__init__()
155
156
  RegisteredAgentToolkit.__init__(self)
156
157
 
157
- # Initialize configuration loader
158
158
  self.config_loader = ConfigLoader.from_kwargs(
159
159
  headless=headless,
160
160
  user_data_dir=user_data_dir,
@@ -175,13 +175,24 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
175
175
  enabled_tools=enabled_tools,
176
176
  connect_over_cdp=connect_over_cdp,
177
177
  cdp_url=cdp_url,
178
+ cdp_keep_current_page=cdp_keep_current_page,
178
179
  full_visual_mode=full_visual_mode,
179
180
  )
180
181
 
181
- # Legacy attribute access for backward compatibility
182
182
  browser_config = self.config_loader.get_browser_config()
183
183
  toolkit_config = self.config_loader.get_toolkit_config()
184
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
+
185
196
  self._headless = browser_config.headless
186
197
  self._user_data_dir = browser_config.user_data_dir
187
198
  self._stealth = browser_config.stealth
@@ -193,7 +204,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
193
204
  self._viewport_limit = browser_config.viewport_limit
194
205
  self._full_visual_mode = browser_config.full_visual_mode
195
206
 
196
- # Store timeout configuration for backward compatibility
197
207
  self._default_timeout = browser_config.default_timeout
198
208
  self._short_timeout = browser_config.short_timeout
199
209
  self._navigation_timeout = browser_config.navigation_timeout
@@ -204,11 +214,9 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
204
214
  browser_config.dom_content_loaded_timeout
205
215
  )
206
216
 
207
- # Configure enabled tools
208
217
  if enabled_tools is None:
209
218
  self.enabled_tools = self.DEFAULT_TOOLS.copy()
210
219
  else:
211
- # Validate enabled tools
212
220
  invalid_tools = [
213
221
  tool for tool in enabled_tools if tool not in self.ALL_TOOLS
214
222
  ]
@@ -221,7 +229,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
221
229
 
222
230
  logger.info(f"Enabled tools: {self.enabled_tools}")
223
231
 
224
- # Initialize WebSocket wrapper
225
232
  self._ws_wrapper: Optional[WebSocketBrowserWrapper] = None
226
233
  self._ws_config = self.config_loader.to_ws_config()
227
234
 
@@ -248,13 +255,29 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
248
255
 
249
256
  import asyncio
250
257
 
258
+ is_cdp = (
259
+ self._ws_config.get('connectOverCdp', False)
260
+ if hasattr(self, '_ws_config')
261
+ else False
262
+ )
263
+
251
264
  try:
252
265
  loop = asyncio.get_event_loop()
253
266
  if not loop.is_closed() and not loop.is_running():
254
267
  try:
255
- loop.run_until_complete(
256
- asyncio.wait_for(self.browser_close(), timeout=2.0)
257
- )
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
+ )
258
281
  except asyncio.TimeoutError:
259
282
  pass
260
283
  except (RuntimeError, ImportError):
@@ -277,8 +300,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
277
300
  """Get the cache directory."""
278
301
  return self._cache_dir
279
302
 
280
- # Public API Methods
281
-
282
303
  async def browser_open(self) -> Dict[str, Any]:
283
304
  r"""Starts a new browser session. This must be the first browser
284
305
  action.
@@ -299,7 +320,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
299
320
  ws_wrapper = await self._get_ws_wrapper()
300
321
  result = await ws_wrapper.open_browser(self._default_start_url)
301
322
 
302
- # Add tab information
303
323
  tab_info = await ws_wrapper.get_tab_info()
304
324
  result.update(
305
325
  {
@@ -344,6 +364,31 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
344
364
  logger.error(f"Failed to close browser: {e}")
345
365
  return f"Error closing browser: {e}"
346
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
+
347
392
  async def browser_visit_page(self, url: str) -> Dict[str, Any]:
348
393
  r"""Opens a URL in a new browser tab and switches to it.
349
394
 
@@ -363,7 +408,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
363
408
  ws_wrapper = await self._get_ws_wrapper()
364
409
  result = await ws_wrapper.visit_page(url)
365
410
 
366
- # Add tab information
367
411
  tab_info = await ws_wrapper.get_tab_info()
368
412
  result.update(
369
413
  {
@@ -409,7 +453,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
409
453
  ws_wrapper = await self._get_ws_wrapper()
410
454
  result = await ws_wrapper.back()
411
455
 
412
- # Add tab information
413
456
  tab_info = await ws_wrapper.get_tab_info()
414
457
  result.update(
415
458
  {
@@ -455,7 +498,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
455
498
  ws_wrapper = await self._get_ws_wrapper()
456
499
  result = await ws_wrapper.forward()
457
500
 
458
- # Add tab information
459
501
  tab_info = await ws_wrapper.get_tab_info()
460
502
  result.update(
461
503
  {
@@ -547,19 +589,14 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
547
589
  ws_wrapper = await self._get_ws_wrapper()
548
590
  result = await ws_wrapper.get_som_screenshot()
549
591
 
550
- # Initialize result text
551
592
  result_text = result.text
552
593
  file_path = None
553
594
 
554
- # Save screenshot to cache directory if images are available
555
595
  if result.images:
556
- # Ensure cache directory exists (use absolute path)
557
596
  cache_dir = os.path.abspath(self._cache_dir)
558
597
  os.makedirs(cache_dir, exist_ok=True)
559
598
 
560
- # Get current page URL for filename
561
599
  try:
562
- # Try to get the current page URL from the wrapper
563
600
  page_info = await ws_wrapper.get_tab_info()
564
601
  current_tab = next(
565
602
  (tab for tab in page_info if tab.get('is_current')),
@@ -569,7 +606,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
569
606
  except Exception:
570
607
  url = 'unknown'
571
608
 
572
- # Generate filename
573
609
  parsed_url = urllib.parse.urlparse(url)
574
610
  url_name = sanitize_filename(
575
611
  str(parsed_url.path) or 'homepage', max_length=241
@@ -579,24 +615,19 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
579
615
  cache_dir, f"{url_name}_{timestamp}_som.png"
580
616
  )
581
617
 
582
- # Extract base64 data and save to file
583
618
  for _, image_data in enumerate(result.images):
584
619
  if image_data.startswith('data:image/png;base64,'):
585
- # Remove data URL prefix
586
620
  base64_data = image_data.split(',', 1)[1]
587
621
 
588
- # Decode and save
589
622
  image_bytes = base64.b64decode(base64_data)
590
623
  with open(file_path, 'wb') as f:
591
624
  f.write(image_bytes)
592
625
 
593
626
  logger.info(f"Screenshot saved to: {file_path}")
594
627
 
595
- # Update result text to include file path
596
628
  result_text += f" (saved to: {file_path})"
597
629
  break
598
630
 
599
- # Analyze image if requested and agent is registered
600
631
  if read_image and file_path:
601
632
  if self.agent is None:
602
633
  logger.error(
@@ -611,7 +642,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
611
642
  )
612
643
  else:
613
644
  try:
614
- # Load the image and create a message
615
645
  from PIL import Image
616
646
 
617
647
  img = Image.open(file_path)
@@ -622,7 +652,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
622
652
  image_list=[img],
623
653
  )
624
654
 
625
- # Get agent's analysis
626
655
  response = await self.agent.astep(message)
627
656
  agent_response = response.msgs[0].content
628
657
  result_text += f". Agent analysis: {agent_response}"
@@ -656,7 +685,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
656
685
  ws_wrapper = await self._get_ws_wrapper()
657
686
  result = await ws_wrapper.click(ref)
658
687
 
659
- # Add tab information
660
688
  tab_info = await ws_wrapper.get_tab_info()
661
689
 
662
690
  response = {
@@ -729,10 +757,8 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
729
757
  try:
730
758
  ws_wrapper = await self._get_ws_wrapper()
731
759
 
732
- # Handle single input mode (backward compatibility)
733
760
  if ref is not None and text is not None:
734
761
  result = await ws_wrapper.type(ref, text)
735
- # Handle multiple inputs mode
736
762
  elif inputs is not None:
737
763
  result = await ws_wrapper.type_multiple(inputs)
738
764
  else:
@@ -741,7 +767,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
741
767
  "or 'inputs' for multiple inputs"
742
768
  )
743
769
 
744
- # Add tab information
745
770
  tab_info = await ws_wrapper.get_tab_info()
746
771
  result.update(
747
772
  {
@@ -790,7 +815,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
790
815
  ws_wrapper = await self._get_ws_wrapper()
791
816
  result = await ws_wrapper.select(ref, value)
792
817
 
793
- # Add tab information
794
818
  tab_info = await ws_wrapper.get_tab_info()
795
819
  result.update(
796
820
  {
@@ -839,7 +863,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
839
863
  ws_wrapper = await self._get_ws_wrapper()
840
864
  result = await ws_wrapper.scroll(direction, amount)
841
865
 
842
- # Add tab information
843
866
  tab_info = await ws_wrapper.get_tab_info()
844
867
  result.update(
845
868
  {
@@ -887,7 +910,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
887
910
  ws_wrapper = await self._get_ws_wrapper()
888
911
  result = await ws_wrapper.enter()
889
912
 
890
- # Add tab information
891
913
  tab_info = await ws_wrapper.get_tab_info()
892
914
  result.update(
893
915
  {
@@ -939,7 +961,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
939
961
  ws_wrapper = await self._get_ws_wrapper()
940
962
  result = await ws_wrapper.mouse_control(control, x, y)
941
963
 
942
- # Add tab information
943
964
  tab_info = await ws_wrapper.get_tab_info()
944
965
  result.update(
945
966
  {
@@ -988,7 +1009,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
988
1009
  ws_wrapper = await self._get_ws_wrapper()
989
1010
  result = await ws_wrapper.mouse_drag(from_ref, to_ref)
990
1011
 
991
- # Add tab information
992
1012
  tab_info = await ws_wrapper.get_tab_info()
993
1013
  result.update(
994
1014
  {
@@ -1037,7 +1057,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
1037
1057
  ws_wrapper = await self._get_ws_wrapper()
1038
1058
  result = await ws_wrapper.press_key(keys)
1039
1059
 
1040
- # Add tab information
1041
1060
  tab_info = await ws_wrapper.get_tab_info()
1042
1061
  result.update(
1043
1062
  {
@@ -1086,7 +1105,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
1086
1105
  ws_wrapper = await self._get_ws_wrapper()
1087
1106
  result = await ws_wrapper.switch_tab(tab_id)
1088
1107
 
1089
- # Add tab information
1090
1108
  tab_info = await ws_wrapper.get_tab_info()
1091
1109
  result.update(
1092
1110
  {
@@ -1136,7 +1154,6 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
1136
1154
  ws_wrapper = await self._get_ws_wrapper()
1137
1155
  result = await ws_wrapper.close_tab(tab_id)
1138
1156
 
1139
- # Add tab information
1140
1157
  tab_info = await ws_wrapper.get_tab_info()
1141
1158
  result.update(
1142
1159
  {
@@ -1415,7 +1432,7 @@ class HybridBrowserToolkit(BaseToolkit, RegisteredAgentToolkit):
1415
1432
  "browser_select": self.browser_select,
1416
1433
  "browser_scroll": self.browser_scroll,
1417
1434
  "browser_enter": self.browser_enter,
1418
- "browser_mouse_click": self.browser_mouse_control,
1435
+ "browser_mouse_control": self.browser_mouse_control,
1419
1436
  "browser_mouse_drag": self.browser_mouse_drag,
1420
1437
  "browser_press_key": self.browser_press_key,
1421
1438
  "browser_wait_user": self.browser_wait_user,