camel-ai 0.2.75a6__py3-none-any.whl → 0.2.76__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 (97) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +1001 -205
  3. camel/agents/mcp_agent.py +30 -27
  4. camel/configs/__init__.py +6 -0
  5. camel/configs/amd_config.py +70 -0
  6. camel/configs/cometapi_config.py +104 -0
  7. camel/data_collectors/alpaca_collector.py +15 -6
  8. camel/environments/tic_tac_toe.py +1 -1
  9. camel/interpreters/__init__.py +2 -0
  10. camel/interpreters/docker/Dockerfile +3 -12
  11. camel/interpreters/microsandbox_interpreter.py +395 -0
  12. camel/loaders/__init__.py +11 -2
  13. camel/loaders/chunkr_reader.py +9 -0
  14. camel/memories/__init__.py +2 -1
  15. camel/memories/agent_memories.py +3 -1
  16. camel/memories/blocks/chat_history_block.py +21 -3
  17. camel/memories/records.py +88 -8
  18. camel/messages/base.py +127 -34
  19. camel/models/__init__.py +4 -0
  20. camel/models/amd_model.py +101 -0
  21. camel/models/azure_openai_model.py +0 -6
  22. camel/models/base_model.py +30 -0
  23. camel/models/cometapi_model.py +83 -0
  24. camel/models/model_factory.py +4 -0
  25. camel/models/openai_compatible_model.py +0 -6
  26. camel/models/openai_model.py +0 -6
  27. camel/models/zhipuai_model.py +61 -2
  28. camel/parsers/__init__.py +18 -0
  29. camel/parsers/mcp_tool_call_parser.py +176 -0
  30. camel/retrievers/auto_retriever.py +1 -0
  31. camel/runtimes/daytona_runtime.py +11 -12
  32. camel/societies/workforce/prompts.py +131 -50
  33. camel/societies/workforce/single_agent_worker.py +434 -49
  34. camel/societies/workforce/structured_output_handler.py +30 -18
  35. camel/societies/workforce/task_channel.py +43 -0
  36. camel/societies/workforce/utils.py +105 -12
  37. camel/societies/workforce/workforce.py +1322 -311
  38. camel/societies/workforce/workforce_logger.py +24 -5
  39. camel/storages/key_value_storages/json.py +15 -2
  40. camel/storages/object_storages/google_cloud.py +1 -1
  41. camel/storages/vectordb_storages/oceanbase.py +10 -11
  42. camel/storages/vectordb_storages/tidb.py +8 -6
  43. camel/tasks/task.py +4 -3
  44. camel/toolkits/__init__.py +18 -5
  45. camel/toolkits/aci_toolkit.py +45 -0
  46. camel/toolkits/code_execution.py +28 -1
  47. camel/toolkits/context_summarizer_toolkit.py +684 -0
  48. camel/toolkits/dingtalk.py +1135 -0
  49. camel/toolkits/edgeone_pages_mcp_toolkit.py +11 -31
  50. camel/toolkits/{file_write_toolkit.py → file_toolkit.py} +194 -34
  51. camel/toolkits/function_tool.py +6 -1
  52. camel/toolkits/google_drive_mcp_toolkit.py +12 -31
  53. camel/toolkits/hybrid_browser_toolkit/config_loader.py +12 -0
  54. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +79 -2
  55. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +95 -59
  56. camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
  57. camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +5 -612
  58. camel/toolkits/hybrid_browser_toolkit/ts/package.json +0 -1
  59. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +619 -95
  60. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +7 -2
  61. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +115 -219
  62. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  63. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
  64. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  65. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +1 -0
  66. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +39 -6
  67. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +405 -131
  68. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +9 -5
  69. camel/toolkits/{openai_image_toolkit.py → image_generation_toolkit.py} +98 -31
  70. camel/toolkits/markitdown_toolkit.py +27 -1
  71. camel/toolkits/mcp_toolkit.py +348 -348
  72. camel/toolkits/message_integration.py +3 -0
  73. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  74. camel/toolkits/note_taking_toolkit.py +18 -8
  75. camel/toolkits/notion_mcp_toolkit.py +16 -26
  76. camel/toolkits/origene_mcp_toolkit.py +8 -49
  77. camel/toolkits/playwright_mcp_toolkit.py +12 -31
  78. camel/toolkits/resend_toolkit.py +168 -0
  79. camel/toolkits/slack_toolkit.py +50 -1
  80. camel/toolkits/terminal_toolkit/__init__.py +18 -0
  81. camel/toolkits/terminal_toolkit/terminal_toolkit.py +924 -0
  82. camel/toolkits/terminal_toolkit/utils.py +532 -0
  83. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  84. camel/toolkits/video_analysis_toolkit.py +17 -11
  85. camel/toolkits/wechat_official_toolkit.py +483 -0
  86. camel/types/enums.py +124 -1
  87. camel/types/unified_model_type.py +5 -0
  88. camel/utils/commons.py +17 -0
  89. camel/utils/context_utils.py +804 -0
  90. camel/utils/mcp.py +136 -2
  91. camel/utils/token_counting.py +25 -17
  92. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76.dist-info}/METADATA +158 -59
  93. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76.dist-info}/RECORD +95 -76
  94. camel/loaders/pandas_reader.py +0 -368
  95. camel/toolkits/terminal_toolkit.py +0 -1788
  96. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76.dist-info}/WHEEL +0 -0
  97. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76.dist-info}/licenses/LICENSE +0 -0
@@ -495,6 +495,11 @@ class WorkforceLogger:
495
495
 
496
496
  tasks_handled_by_worker: Dict[str, int] = {}
497
497
 
498
+ # Track unique task final states to avoid double-counting
499
+ task_final_states: Dict[
500
+ str, str
501
+ ] = {} # task_id -> 'completed' or 'failed'
502
+
498
503
  # Helper function to check if a task is the main task (has no parent)
499
504
  def is_main_task(task_id: str) -> bool:
500
505
  return (
@@ -528,7 +533,9 @@ class WorkforceLogger:
528
533
  elif event_type == 'task_completed':
529
534
  # Exclude main task from total count
530
535
  if not is_main_task(task_id):
531
- kpis['total_tasks_completed'] += 1
536
+ # Track final state - a completed task overwrites any
537
+ # previous failed state
538
+ task_final_states[task_id] = 'completed'
532
539
  # Count tasks handled by worker (only for non-main tasks)
533
540
  if 'worker_id' in entry and entry['worker_id'] is not None:
534
541
  worker_id = entry['worker_id']
@@ -550,7 +557,11 @@ class WorkforceLogger:
550
557
  elif event_type == 'task_failed':
551
558
  # Exclude main task from total count
552
559
  if not is_main_task(task_id):
553
- kpis['total_tasks_failed'] += 1
560
+ # Only track as failed if not already completed
561
+ # (in case of retries, the final completion overwrites
562
+ # failed state)
563
+ if task_final_states.get(task_id) != 'completed':
564
+ task_final_states[task_id] = 'failed'
554
565
  # Count tasks handled by worker (only for non-main tasks)
555
566
  if 'worker_id' in entry and entry['worker_id'] is not None:
556
567
  worker_id = entry['worker_id']
@@ -565,6 +576,14 @@ class WorkforceLogger:
565
576
  kpis['total_workforce_running_time_seconds'] = (
566
577
  last_timestamp - first_timestamp
567
578
  ).total_seconds()
579
+
580
+ # Count unique tasks by final state
581
+ for _task_id, state in task_final_states.items():
582
+ if state == 'completed':
583
+ kpis['total_tasks_completed'] += 1
584
+ elif state == 'failed':
585
+ kpis['total_tasks_failed'] += 1
586
+
568
587
  # Calculate worker utilization based on proportion of tasks handled
569
588
  total_tasks_processed_for_utilization = (
570
589
  kpis['total_tasks_completed'] + kpis['total_tasks_failed']
@@ -610,9 +629,9 @@ class WorkforceLogger:
610
629
 
611
630
  kpis['total_workers_created'] = len(self._worker_information)
612
631
 
613
- # Current pending tasks (simplified)
614
- kpis['current_pending_tasks'] = kpis['total_tasks_created'] - (
615
- kpis['total_tasks_completed'] + kpis['total_tasks_failed']
632
+ # Current pending tasks - tasks created but not yet completed or failed
633
+ kpis['current_pending_tasks'] = kpis['total_tasks_created'] - len(
634
+ task_final_states
616
635
  )
617
636
 
618
637
  return kpis
@@ -17,6 +17,8 @@ from enum import EnumMeta
17
17
  from pathlib import Path
18
18
  from typing import Any, ClassVar, Dict, List, Optional
19
19
 
20
+ from pydantic import BaseModel
21
+
20
22
  from camel.storages.key_value_storages import BaseKeyValueStorage
21
23
  from camel.types import (
22
24
  ModelType,
@@ -27,8 +29,13 @@ from camel.types import (
27
29
 
28
30
 
29
31
  class CamelJSONEncoder(json.JSONEncoder):
30
- r"""A custom JSON encoder for serializing specifically enumerated types.
31
- Ensures enumerated types can be stored in and retrieved from JSON format.
32
+ r"""A custom JSON encoder for serializing CAMEL-specific types.
33
+
34
+ Handles serialization of:
35
+ - Enumerated types (RoleType, TaskType, ModelType, OpenAIBackendRole)
36
+ - Pydantic BaseModel objects (from structured outputs)
37
+
38
+ Ensures these types can be stored in and retrieved from JSON format.
32
39
  """
33
40
 
34
41
  CAMEL_ENUMS: ClassVar[Dict[str, EnumMeta]] = {
@@ -39,8 +46,14 @@ class CamelJSONEncoder(json.JSONEncoder):
39
46
  }
40
47
 
41
48
  def default(self, obj) -> Any:
49
+ # Handle CAMEL enum types
42
50
  if type(obj) in self.CAMEL_ENUMS.values():
43
51
  return {"__enum__": str(obj)}
52
+
53
+ # Handle Pydantic BaseModel objects (e.g., from structured outputs)
54
+ if isinstance(obj, BaseModel):
55
+ return obj.model_dump()
56
+
44
57
  # Let the base class default method raise the TypeError
45
58
  return json.JSONEncoder.default(self, obj)
46
59
 
@@ -46,7 +46,7 @@ class GoogleCloudStorage(BaseObjectStorage):
46
46
  create_if_not_exists: bool = True,
47
47
  anonymous: bool = False,
48
48
  ) -> None:
49
- from google.cloud import storage
49
+ from google.cloud import storage # type: ignore[attr-defined]
50
50
 
51
51
  self.create_if_not_exists = create_if_not_exists
52
52
 
@@ -74,7 +74,6 @@ class OceanBaseStorage(BaseVectorStorage):
74
74
  ObVecClient,
75
75
  )
76
76
  from pyobvector.client.index_param import (
77
- IndexParam,
78
77
  IndexParams,
79
78
  )
80
79
  from pyobvector.schema import VECTOR
@@ -112,19 +111,19 @@ class OceanBaseStorage(BaseVectorStorage):
112
111
 
113
112
  # Create vector index
114
113
  index_params: IndexParams = IndexParams()
115
- index_params.add_index_param(
116
- IndexParam(
117
- index_name="embedding_idx",
118
- field_name="embedding",
119
- distance=self.distance,
120
- type="hnsw",
121
- m=16,
122
- ef_construction=256,
123
- )
114
+ index_params.add_index(
115
+ field_name="embedding",
116
+ index_type="hnsw",
117
+ index_name="embedding_idx",
118
+ distance=self.distance,
119
+ m=16,
120
+ ef_construction=256,
124
121
  )
125
122
 
123
+ # Get the first index parameter
124
+ first_index_param = next(iter(index_params))
126
125
  self._client.create_vidx_with_vec_index_param(
127
- table_name=self.table_name, vidx_param=index_params.params[0]
126
+ table_name=self.table_name, vidx_param=first_index_param
128
127
  )
129
128
 
130
129
  logger.info(f"Created table {self.table_name} with vector index")
@@ -44,7 +44,7 @@ class TiDBStorage(BaseVectorStorage):
44
44
  r"""An implementation of the `BaseVectorStorage` for interacting with TiDB.
45
45
 
46
46
  The detailed information about TiDB is available at:
47
- `TiDB Vector Search <https://ai.pingcap.com/>`_
47
+ `TiDB Vector Search <https://pingcap.com/ai>`_
48
48
 
49
49
  Args:
50
50
  vector_dim (int): The dimension of storing vectors.
@@ -107,10 +107,10 @@ class TiDBStorage(BaseVectorStorage):
107
107
  )
108
108
 
109
109
  def _get_table_model(self, collection_name: str) -> Any:
110
+ from pytidb.datatype import JSON
110
111
  from pytidb.schema import Field, TableModel, VectorField
111
- from sqlalchemy import JSON
112
112
 
113
- class VectorDBRecord(TableModel):
113
+ class VectorDBRecordBase(TableModel, table=False):
114
114
  id: Optional[str] = Field(None, primary_key=True)
115
115
  vector: list[float] = VectorField(self.vector_dim)
116
116
  payload: Optional[dict[str, Any]] = Field(None, sa_type=JSON)
@@ -119,7 +119,7 @@ class TiDBStorage(BaseVectorStorage):
119
119
  # class names.
120
120
  return type(
121
121
  f"VectorDBRecord_{collection_name}",
122
- (VectorDBRecord,),
122
+ (VectorDBRecordBase,),
123
123
  {"__tablename__": collection_name},
124
124
  table=True,
125
125
  )
@@ -128,8 +128,9 @@ class TiDBStorage(BaseVectorStorage):
128
128
  r"""Opens an existing table or creates a new table in TiDB."""
129
129
  table = self._client.open_table(self.collection_name)
130
130
  if table is None:
131
+ table_model = self._get_table_model(self.collection_name)
131
132
  table = self._client.create_table(
132
- schema=self._get_table_model(self.collection_name)
133
+ schema=table_model, if_exists="skip"
133
134
  )
134
135
  return table
135
136
 
@@ -166,6 +167,7 @@ class TiDBStorage(BaseVectorStorage):
166
167
  table.
167
168
  """
168
169
  vector_count = self._table.rows()
170
+
169
171
  # Get vector dimension from table schema
170
172
  columns = self._table.columns()
171
173
  dim_value = None
@@ -303,7 +305,7 @@ class TiDBStorage(BaseVectorStorage):
303
305
  for row in rows:
304
306
  query_results.append(
305
307
  VectorDBQueryResult.create(
306
- similarity=float(row['similarity_score']),
308
+ similarity=float(row['_score']),
307
309
  id=str(row['id']),
308
310
  payload=row['payload'],
309
311
  vector=row['vector'],
camel/tasks/task.py CHANGED
@@ -237,8 +237,9 @@ class Task(BaseModel):
237
237
  (default: :obj:`[]`)
238
238
  additional_info (Optional[Dict[str, Any]]): Additional information for
239
239
  the task. (default: :obj:`None`)
240
- image_list (Optional[List[Image.Image]]): Optional list of PIL Image
241
- objects associated with the task. (default: :obj:`None`)
240
+ image_list (Optional[List[Union[Image.Image, str]]]): Optional list
241
+ of PIL Image objects or image URLs (strings) associated with the
242
+ task. (default: :obj:`None`)
242
243
  image_detail (Literal["auto", "low", "high"]): Detail level of the
243
244
  images associated with the task. (default: :obj:`auto`)
244
245
  video_bytes (Optional[bytes]): Optional bytes of a video associated
@@ -271,7 +272,7 @@ class Task(BaseModel):
271
272
 
272
273
  additional_info: Optional[Dict[str, Any]] = None
273
274
 
274
- image_list: Optional[List[Image.Image]] = None
275
+ image_list: Optional[List[Union[Image.Image, str]]] = None
275
276
 
276
277
  image_detail: Literal["auto", "low", "high"] = "auto"
277
278
 
@@ -23,7 +23,7 @@ from .open_api_specs.security_config import openapi_security_config
23
23
  from .math_toolkit import MathToolkit
24
24
  from .search_toolkit import SearchToolkit
25
25
  from .weather_toolkit import WeatherToolkit
26
- from .openai_image_toolkit import OpenAIImageToolkit
26
+ from .image_generation_toolkit import ImageGenToolkit, OpenAIImageToolkit
27
27
  from .ask_news_toolkit import AskNewsToolkit, AsyncAskNewsToolkit
28
28
  from .linkedin_toolkit import LinkedInToolkit
29
29
  from .reddit_toolkit import RedditToolkit
@@ -40,6 +40,8 @@ from .google_calendar_toolkit import GoogleCalendarToolkit
40
40
  from .arxiv_toolkit import ArxivToolkit
41
41
  from .slack_toolkit import SlackToolkit
42
42
  from .whatsapp_toolkit import WhatsAppToolkit
43
+ from .wechat_official_toolkit import WeChatOfficialToolkit
44
+ from .dingtalk import DingtalkToolkit
43
45
  from .twitter_toolkit import TwitterToolkit
44
46
  from .open_api_toolkit import OpenAPIToolkit
45
47
  from .retrieval_toolkit import RetrievalToolkit
@@ -61,7 +63,7 @@ from .image_analysis_toolkit import ImageAnalysisToolkit
61
63
  from .mcp_toolkit import MCPToolkit
62
64
  from .browser_toolkit import BrowserToolkit
63
65
  from .async_browser_toolkit import AsyncBrowserToolkit
64
- from .file_write_toolkit import FileWriteToolkit
66
+ from .file_toolkit import FileToolkit, FileWriteToolkit
65
67
  from .pptx_toolkit import PPTXToolkit
66
68
  from .terminal_toolkit import TerminalToolkit
67
69
  from .pubmed_toolkit import PubMedToolkit
@@ -75,6 +77,7 @@ from .klavis_toolkit import KlavisToolkit
75
77
  from .aci_toolkit import ACIToolkit
76
78
  from .origene_mcp_toolkit import OrigeneToolkit
77
79
  from .playwright_mcp_toolkit import PlaywrightMCPToolkit
80
+ from .resend_toolkit import ResendToolkit
78
81
  from .wolfram_alpha_toolkit import WolframAlphaToolkit
79
82
  from .task_planning_toolkit import TaskPlanningToolkit
80
83
  from .hybrid_browser_toolkit import HybridBrowserToolkit
@@ -87,7 +90,10 @@ from .message_agent_toolkit import AgentCommunicationToolkit
87
90
  from .web_deploy_toolkit import WebDeployToolkit
88
91
  from .screenshot_toolkit import ScreenshotToolkit
89
92
  from .message_integration import ToolkitMessageIntegration
93
+ from .context_summarizer_toolkit import ContextSummarizerToolkit
90
94
  from .notion_mcp_toolkit import NotionMCPToolkit
95
+ from .vertex_ai_veo_toolkit import VertexAIVeoToolkit
96
+ from .minimax_mcp_toolkit import MinimaxMCPToolkit
91
97
 
92
98
  __all__ = [
93
99
  'BaseToolkit',
@@ -102,7 +108,9 @@ __all__ = [
102
108
  'SearchToolkit',
103
109
  'SlackToolkit',
104
110
  'WhatsAppToolkit',
105
- 'OpenAIImageToolkit',
111
+ 'WeChatOfficialToolkit',
112
+ 'DingtalkToolkit',
113
+ 'ImageGenToolkit',
106
114
  'TwitterToolkit',
107
115
  'WeatherToolkit',
108
116
  'RetrievalToolkit',
@@ -135,7 +143,8 @@ __all__ = [
135
143
  'ImageAnalysisToolkit',
136
144
  'BrowserToolkit',
137
145
  'AsyncBrowserToolkit',
138
- 'FileWriteToolkit',
146
+ 'FileToolkit',
147
+ 'FileWriteToolkit', # Deprecated, use FileToolkit instead
139
148
  'PPTXToolkit',
140
149
  'TerminalToolkit',
141
150
  'PubMedToolkit',
@@ -149,9 +158,10 @@ __all__ = [
149
158
  'KlavisToolkit',
150
159
  'ACIToolkit',
151
160
  'PlaywrightMCPToolkit',
161
+ 'ResendToolkit',
152
162
  'WolframAlphaToolkit',
153
163
  'BohriumToolkit',
154
- 'OpenAIImageToolkit',
164
+ 'OpenAIImageToolkit', # Backward compatibility
155
165
  'TaskPlanningToolkit',
156
166
  'HybridBrowserToolkit',
157
167
  'EdgeOnePagesMCPToolkit',
@@ -164,5 +174,8 @@ __all__ = [
164
174
  'ScreenshotToolkit',
165
175
  'RegisteredAgentToolkit',
166
176
  'ToolkitMessageIntegration',
177
+ 'ContextSummarizerToolkit',
167
178
  'NotionMCPToolkit',
179
+ 'VertexAIVeoToolkit',
180
+ 'MinimaxMCPToolkit',
168
181
  ]
@@ -12,6 +12,7 @@
12
12
  # limitations under the License.
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
 
15
+ import asyncio
15
16
  import os
16
17
  from typing import TYPE_CHECKING, Dict, List, Optional, Union
17
18
 
@@ -408,6 +409,38 @@ class ACIToolkit(BaseToolkit):
408
409
  )
409
410
  return result
410
411
 
412
+ async def aexecute_function(
413
+ self,
414
+ function_name: str,
415
+ function_arguments: Dict,
416
+ linked_account_owner_id: str,
417
+ allowed_apps_only: bool = False,
418
+ ) -> Dict:
419
+ r"""Execute a function call asynchronously.
420
+
421
+ Args:
422
+ function_name (str): Name of the function to execute.
423
+ function_arguments (Dict): Arguments to pass to the function.
424
+ linked_account_owner_id (str): To specify the end-user (account
425
+ owner) on behalf of whom you want to execute functions
426
+ You need to first link corresponding account with the same
427
+ owner id in the ACI dashboard (https://platform.aci.dev).
428
+ allowed_apps_only (bool): If true, only returns functions/apps
429
+ that are allowed to be used by the agent/accessor, identified
430
+ by the api key. (default: :obj:`False`)
431
+
432
+ Returns:
433
+ Dict: Result of the function execution
434
+ """
435
+ result = await asyncio.to_thread(
436
+ self.client.handle_function_call,
437
+ function_name,
438
+ function_arguments,
439
+ linked_account_owner_id,
440
+ allowed_apps_only,
441
+ )
442
+ return result
443
+
411
444
  def get_tools(self) -> List[FunctionTool]:
412
445
  r"""Get a list of tools (functions) available in the configured apps.
413
446
 
@@ -434,6 +467,8 @@ class ACIToolkit(BaseToolkit):
434
467
  FunctionTool(self.delete_linked_account),
435
468
  FunctionTool(self.function_definition),
436
469
  FunctionTool(self.search_function),
470
+ FunctionTool(self.execute_function),
471
+ FunctionTool(self.aexecute_function),
437
472
  ]
438
473
 
439
474
  for function in _all_function:
@@ -448,6 +483,16 @@ class ACIToolkit(BaseToolkit):
448
483
  linked_account_owner_id=self.linked_account_owner_id,
449
484
  )
450
485
 
486
+ async def async_dummy_func(*, schema=schema, **kwargs):
487
+ return await self.aexecute_function(
488
+ function_name=schema['function']['name'],
489
+ function_arguments=kwargs,
490
+ linked_account_owner_id=self.linked_account_owner_id,
491
+ )
492
+
493
+ # Add async_call method to the sync function for compatibility
494
+ dummy_func.async_call = async_dummy_func # type: ignore[attr-defined]
495
+
451
496
  tool = FunctionTool(
452
497
  func=dummy_func,
453
498
  openai_tool_schema=schema,
@@ -18,6 +18,7 @@ from camel.interpreters import (
18
18
  E2BInterpreter,
19
19
  InternalPythonInterpreter,
20
20
  JupyterKernelInterpreter,
21
+ MicrosandboxInterpreter,
21
22
  SubprocessInterpreter,
22
23
  )
23
24
  from camel.logger import get_logger
@@ -43,18 +44,31 @@ class CodeExecutionToolkit(BaseToolkit):
43
44
  (default: :obj:`None`)
44
45
  require_confirm (bool): Whether to require confirmation before
45
46
  executing code. (default: :obj:`False`)
47
+ timeout (Optional[float]): General timeout for toolkit operations.
48
+ (default: :obj:`None`)
49
+ microsandbox_config (Optional[dict]): Configuration for microsandbox
50
+ interpreter. Available keys: 'server_url', 'api_key',
51
+ 'namespace', 'sandbox_name', 'timeout'.
52
+ If None, uses default configuration. (default: :obj:`None`)
46
53
  """
47
54
 
48
55
  def __init__(
49
56
  self,
50
57
  sandbox: Literal[
51
- "internal_python", "jupyter", "docker", "subprocess", "e2b"
58
+ "internal_python",
59
+ "jupyter",
60
+ "docker",
61
+ "subprocess",
62
+ "e2b",
63
+ "microsandbox",
52
64
  ] = "subprocess",
53
65
  verbose: bool = False,
54
66
  unsafe_mode: bool = False,
55
67
  import_white_list: Optional[List[str]] = None,
56
68
  require_confirm: bool = False,
57
69
  timeout: Optional[float] = None,
70
+ # Microsandbox configuration dictionary
71
+ microsandbox_config: Optional[dict] = None,
58
72
  ) -> None:
59
73
  super().__init__(timeout=timeout)
60
74
  self.verbose = verbose
@@ -68,6 +82,7 @@ class CodeExecutionToolkit(BaseToolkit):
68
82
  DockerInterpreter,
69
83
  SubprocessInterpreter,
70
84
  E2BInterpreter,
85
+ MicrosandboxInterpreter,
71
86
  ]
72
87
 
73
88
  if sandbox == "internal_python":
@@ -95,6 +110,18 @@ class CodeExecutionToolkit(BaseToolkit):
95
110
  )
96
111
  elif sandbox == "e2b":
97
112
  self.interpreter = E2BInterpreter(require_confirm=require_confirm)
113
+ elif sandbox == "microsandbox":
114
+ # Extract parameters with proper types for microsandbox
115
+ config = microsandbox_config or {}
116
+
117
+ self.interpreter = MicrosandboxInterpreter(
118
+ require_confirm=require_confirm,
119
+ server_url=config.get("server_url"),
120
+ api_key=config.get("api_key"),
121
+ namespace=config.get("namespace", "default"),
122
+ sandbox_name=config.get("sandbox_name"),
123
+ timeout=config.get("timeout", 30),
124
+ )
98
125
  else:
99
126
  raise RuntimeError(
100
127
  f"The sandbox type `{sandbox}` is not supported."