camel-ai 0.2.73a4__py3-none-any.whl → 0.2.80a2__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 (173) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/_utils.py +38 -0
  3. camel/agents/chat_agent.py +2217 -519
  4. camel/agents/mcp_agent.py +30 -27
  5. camel/configs/__init__.py +15 -0
  6. camel/configs/aihubmix_config.py +88 -0
  7. camel/configs/amd_config.py +70 -0
  8. camel/configs/cometapi_config.py +104 -0
  9. camel/configs/minimax_config.py +93 -0
  10. camel/configs/nebius_config.py +103 -0
  11. camel/data_collectors/alpaca_collector.py +15 -6
  12. camel/datasets/base_generator.py +39 -10
  13. camel/environments/single_step.py +28 -3
  14. camel/environments/tic_tac_toe.py +1 -1
  15. camel/interpreters/__init__.py +2 -0
  16. camel/interpreters/docker/Dockerfile +3 -12
  17. camel/interpreters/e2b_interpreter.py +34 -1
  18. camel/interpreters/microsandbox_interpreter.py +395 -0
  19. camel/loaders/__init__.py +11 -2
  20. camel/loaders/chunkr_reader.py +9 -0
  21. camel/memories/agent_memories.py +48 -4
  22. camel/memories/base.py +26 -0
  23. camel/memories/blocks/chat_history_block.py +122 -4
  24. camel/memories/context_creators/score_based.py +25 -384
  25. camel/memories/records.py +88 -8
  26. camel/messages/base.py +153 -34
  27. camel/models/__init__.py +10 -0
  28. camel/models/aihubmix_model.py +83 -0
  29. camel/models/aiml_model.py +1 -16
  30. camel/models/amd_model.py +101 -0
  31. camel/models/anthropic_model.py +6 -19
  32. camel/models/aws_bedrock_model.py +2 -33
  33. camel/models/azure_openai_model.py +114 -89
  34. camel/models/base_audio_model.py +3 -1
  35. camel/models/base_model.py +32 -14
  36. camel/models/cohere_model.py +1 -16
  37. camel/models/cometapi_model.py +83 -0
  38. camel/models/crynux_model.py +1 -16
  39. camel/models/deepseek_model.py +1 -16
  40. camel/models/fish_audio_model.py +6 -0
  41. camel/models/gemini_model.py +36 -18
  42. camel/models/groq_model.py +1 -17
  43. camel/models/internlm_model.py +1 -16
  44. camel/models/litellm_model.py +1 -16
  45. camel/models/lmstudio_model.py +1 -17
  46. camel/models/minimax_model.py +83 -0
  47. camel/models/mistral_model.py +1 -16
  48. camel/models/model_factory.py +27 -1
  49. camel/models/modelscope_model.py +1 -16
  50. camel/models/moonshot_model.py +105 -24
  51. camel/models/nebius_model.py +83 -0
  52. camel/models/nemotron_model.py +0 -5
  53. camel/models/netmind_model.py +1 -16
  54. camel/models/novita_model.py +1 -16
  55. camel/models/nvidia_model.py +1 -16
  56. camel/models/ollama_model.py +4 -19
  57. camel/models/openai_compatible_model.py +62 -41
  58. camel/models/openai_model.py +62 -57
  59. camel/models/openrouter_model.py +1 -17
  60. camel/models/ppio_model.py +1 -16
  61. camel/models/qianfan_model.py +1 -16
  62. camel/models/qwen_model.py +1 -16
  63. camel/models/reka_model.py +1 -16
  64. camel/models/samba_model.py +34 -47
  65. camel/models/sglang_model.py +64 -31
  66. camel/models/siliconflow_model.py +1 -16
  67. camel/models/stub_model.py +0 -4
  68. camel/models/togetherai_model.py +1 -16
  69. camel/models/vllm_model.py +1 -16
  70. camel/models/volcano_model.py +0 -17
  71. camel/models/watsonx_model.py +1 -16
  72. camel/models/yi_model.py +1 -16
  73. camel/models/zhipuai_model.py +60 -16
  74. camel/parsers/__init__.py +18 -0
  75. camel/parsers/mcp_tool_call_parser.py +176 -0
  76. camel/retrievers/auto_retriever.py +1 -0
  77. camel/runtimes/daytona_runtime.py +11 -12
  78. camel/societies/__init__.py +2 -0
  79. camel/societies/workforce/__init__.py +2 -0
  80. camel/societies/workforce/events.py +122 -0
  81. camel/societies/workforce/prompts.py +146 -66
  82. camel/societies/workforce/role_playing_worker.py +15 -11
  83. camel/societies/workforce/single_agent_worker.py +302 -65
  84. camel/societies/workforce/structured_output_handler.py +30 -18
  85. camel/societies/workforce/task_channel.py +163 -27
  86. camel/societies/workforce/utils.py +107 -13
  87. camel/societies/workforce/workflow_memory_manager.py +772 -0
  88. camel/societies/workforce/workforce.py +1949 -579
  89. camel/societies/workforce/workforce_callback.py +74 -0
  90. camel/societies/workforce/workforce_logger.py +168 -145
  91. camel/societies/workforce/workforce_metrics.py +33 -0
  92. camel/storages/key_value_storages/json.py +15 -2
  93. camel/storages/key_value_storages/mem0_cloud.py +48 -47
  94. camel/storages/object_storages/google_cloud.py +1 -1
  95. camel/storages/vectordb_storages/oceanbase.py +13 -13
  96. camel/storages/vectordb_storages/qdrant.py +3 -3
  97. camel/storages/vectordb_storages/tidb.py +8 -6
  98. camel/tasks/task.py +4 -3
  99. camel/toolkits/__init__.py +20 -7
  100. camel/toolkits/aci_toolkit.py +45 -0
  101. camel/toolkits/base.py +6 -4
  102. camel/toolkits/code_execution.py +28 -1
  103. camel/toolkits/context_summarizer_toolkit.py +684 -0
  104. camel/toolkits/dappier_toolkit.py +5 -1
  105. camel/toolkits/dingtalk.py +1135 -0
  106. camel/toolkits/edgeone_pages_mcp_toolkit.py +11 -31
  107. camel/toolkits/excel_toolkit.py +1 -1
  108. camel/toolkits/{file_write_toolkit.py → file_toolkit.py} +430 -36
  109. camel/toolkits/function_tool.py +13 -3
  110. camel/toolkits/github_toolkit.py +104 -17
  111. camel/toolkits/gmail_toolkit.py +1839 -0
  112. camel/toolkits/google_calendar_toolkit.py +38 -4
  113. camel/toolkits/google_drive_mcp_toolkit.py +12 -31
  114. camel/toolkits/hybrid_browser_toolkit/config_loader.py +15 -0
  115. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +77 -8
  116. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +884 -88
  117. camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
  118. camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +5 -612
  119. camel/toolkits/hybrid_browser_toolkit/ts/package.json +0 -1
  120. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +959 -89
  121. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +9 -2
  122. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +281 -213
  123. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  124. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
  125. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  126. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +23 -3
  127. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +72 -7
  128. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +582 -132
  129. camel/toolkits/hybrid_browser_toolkit_py/actions.py +158 -0
  130. camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +55 -8
  131. camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +43 -0
  132. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +321 -8
  133. camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +10 -4
  134. camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +45 -4
  135. camel/toolkits/{openai_image_toolkit.py → image_generation_toolkit.py} +151 -53
  136. camel/toolkits/klavis_toolkit.py +5 -1
  137. camel/toolkits/markitdown_toolkit.py +27 -1
  138. camel/toolkits/math_toolkit.py +64 -10
  139. camel/toolkits/mcp_toolkit.py +366 -71
  140. camel/toolkits/memory_toolkit.py +5 -1
  141. camel/toolkits/message_integration.py +18 -13
  142. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  143. camel/toolkits/note_taking_toolkit.py +19 -10
  144. camel/toolkits/notion_mcp_toolkit.py +16 -26
  145. camel/toolkits/openbb_toolkit.py +5 -1
  146. camel/toolkits/origene_mcp_toolkit.py +8 -49
  147. camel/toolkits/playwright_mcp_toolkit.py +12 -31
  148. camel/toolkits/resend_toolkit.py +168 -0
  149. camel/toolkits/search_toolkit.py +264 -91
  150. camel/toolkits/slack_toolkit.py +64 -10
  151. camel/toolkits/terminal_toolkit/__init__.py +18 -0
  152. camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
  153. camel/toolkits/terminal_toolkit/utils.py +532 -0
  154. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  155. camel/toolkits/video_analysis_toolkit.py +17 -11
  156. camel/toolkits/wechat_official_toolkit.py +483 -0
  157. camel/toolkits/zapier_toolkit.py +5 -1
  158. camel/types/__init__.py +2 -2
  159. camel/types/enums.py +274 -7
  160. camel/types/openai_types.py +2 -2
  161. camel/types/unified_model_type.py +15 -0
  162. camel/utils/commons.py +36 -5
  163. camel/utils/constants.py +3 -0
  164. camel/utils/context_utils.py +1003 -0
  165. camel/utils/mcp.py +138 -4
  166. camel/utils/token_counting.py +43 -20
  167. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +223 -83
  168. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +170 -141
  169. camel/loaders/pandas_reader.py +0 -368
  170. camel/toolkits/openai_agent_toolkit.py +0 -135
  171. camel/toolkits/terminal_toolkit.py +0 -1550
  172. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
  173. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,195 @@
1
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
+
15
+ import os
16
+ from typing import Any, Dict, List, Optional
17
+
18
+ from camel.toolkits import BaseToolkit, FunctionTool
19
+
20
+ from .mcp_toolkit import MCPToolkit
21
+
22
+
23
+ class MinimaxMCPToolkit(BaseToolkit):
24
+ r"""MinimaxMCPToolkit provides an interface for interacting with
25
+ MiniMax AI services using the MiniMax MCP server.
26
+
27
+ This toolkit enables access to MiniMax's multimedia generation
28
+ capabilities including text-to-audio, voice cloning, video generation,
29
+ image generation, music generation, and voice design.
30
+
31
+ This toolkit can be used as an async context manager for automatic
32
+ connection management:
33
+
34
+ # Using explicit API key
35
+ async with MinimaxMCPToolkit(api_key="your-key") as toolkit:
36
+ tools = toolkit.get_tools()
37
+ # Toolkit is automatically disconnected when exiting
38
+
39
+ # Using environment variables (recommended for security)
40
+ # Set MINIMAX_API_KEY=your-key in environment
41
+ async with MinimaxMCPToolkit() as toolkit:
42
+ tools = toolkit.get_tools()
43
+
44
+ Environment Variables:
45
+ MINIMAX_API_KEY: MiniMax API key for authentication
46
+ MINIMAX_API_HOST: API host URL (default: https://api.minimax.io)
47
+ MINIMAX_MCP_BASE_PATH: Base path for output files
48
+
49
+ Attributes:
50
+ timeout (Optional[float]): Connection timeout in seconds.
51
+ (default: :obj:`None`)
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ api_key: Optional[str] = None,
57
+ api_host: str = "https://api.minimax.io",
58
+ base_path: Optional[str] = None,
59
+ timeout: Optional[float] = None,
60
+ ) -> None:
61
+ r"""Initializes the MinimaxMCPToolkit.
62
+
63
+ Args:
64
+ api_key (Optional[str]): MiniMax API key for authentication.
65
+ If None, will attempt to read from MINIMAX_API_KEY
66
+ environment variable. (default: :obj:`None`)
67
+ api_host (str): MiniMax API host URL. Can be either
68
+ "https://api.minimax.io" (global) or
69
+ "https://api.minimaxi.com" (mainland China).
70
+ Can also be read from MINIMAX_API_HOST environment variable.
71
+ (default: :obj:`"https://api.minimax.io"`)
72
+ base_path (Optional[str]): Base path for output files.
73
+ If None, uses current working directory. Can also be read
74
+ from MINIMAX_MCP_BASE_PATH environment variable.
75
+ (default: :obj:`None`)
76
+ timeout (Optional[float]): Connection timeout in seconds.
77
+ (default: :obj:`None`)
78
+ """
79
+ super().__init__(timeout=timeout)
80
+
81
+ # Read API key from parameter or environment variable
82
+ if api_key is None:
83
+ api_key = os.getenv("MINIMAX_API_KEY")
84
+
85
+ if not api_key:
86
+ raise ValueError(
87
+ "api_key must be provided either as a parameter or through "
88
+ "the MINIMAX_API_KEY environment variable"
89
+ )
90
+
91
+ # Read API host from environment variable if not overridden
92
+ env_api_host = os.getenv("MINIMAX_API_HOST")
93
+ if env_api_host:
94
+ api_host = env_api_host
95
+
96
+ # Read base path from environment variable if not provided
97
+ if base_path is None:
98
+ base_path = os.getenv("MINIMAX_MCP_BASE_PATH")
99
+
100
+ # Set up environment variables for the MCP server
101
+ env = {
102
+ "MINIMAX_API_KEY": api_key,
103
+ "MINIMAX_API_HOST": api_host,
104
+ }
105
+
106
+ if base_path:
107
+ env["MINIMAX_MCP_BASE_PATH"] = base_path
108
+
109
+ self._mcp_toolkit = MCPToolkit(
110
+ config_dict={
111
+ "mcpServers": {
112
+ "minimax": {
113
+ "command": "uvx",
114
+ "args": ["minimax-mcp", "-y"],
115
+ "env": env,
116
+ }
117
+ }
118
+ },
119
+ timeout=timeout,
120
+ )
121
+
122
+ async def connect(self):
123
+ r"""Explicitly connect to the MiniMax MCP server."""
124
+ await self._mcp_toolkit.connect()
125
+
126
+ async def disconnect(self):
127
+ r"""Explicitly disconnect from the MiniMax MCP server."""
128
+ await self._mcp_toolkit.disconnect()
129
+
130
+ @property
131
+ def is_connected(self) -> bool:
132
+ r"""Check if the toolkit is connected to the MCP server.
133
+
134
+ Returns:
135
+ bool: True if connected, False otherwise.
136
+ """
137
+ return self._mcp_toolkit.is_connected
138
+
139
+ async def __aenter__(self) -> "MinimaxMCPToolkit":
140
+ r"""Async context manager entry point.
141
+
142
+ Returns:
143
+ MinimaxMCPToolkit: The connected toolkit instance.
144
+
145
+ Example:
146
+ async with MinimaxMCPToolkit(api_key="your-key") as toolkit:
147
+ tools = toolkit.get_tools()
148
+ """
149
+ await self.connect()
150
+ return self
151
+
152
+ async def __aexit__(self, _exc_type, _exc_val, _exc_tb) -> None:
153
+ r"""Async context manager exit point.
154
+
155
+ Automatically disconnects from the MiniMax MCP server.
156
+ """
157
+ await self.disconnect()
158
+
159
+ def get_tools(self) -> List[FunctionTool]:
160
+ r"""Returns a list of tools provided by the MiniMax MCP server.
161
+
162
+ This includes tools for:
163
+ - Text-to-audio conversion
164
+ - Voice cloning
165
+ - Video generation
166
+ - Image generation
167
+ - Music generation
168
+ - Voice design
169
+
170
+ Returns:
171
+ List[FunctionTool]: List of available MiniMax AI tools.
172
+ """
173
+ return self._mcp_toolkit.get_tools()
174
+
175
+ def get_text_tools(self) -> str:
176
+ r"""Returns a string containing the descriptions of the tools.
177
+
178
+ Returns:
179
+ str: A string containing the descriptions of all MiniMax tools.
180
+ """
181
+ return self._mcp_toolkit.get_text_tools()
182
+
183
+ async def call_tool(
184
+ self, tool_name: str, tool_args: Dict[str, Any]
185
+ ) -> Any:
186
+ r"""Call a MiniMax tool by name.
187
+
188
+ Args:
189
+ tool_name (str): Name of the tool to call.
190
+ tool_args (Dict[str, Any]): Arguments to pass to the tool.
191
+
192
+ Returns:
193
+ Any: The result of the tool call.
194
+ """
195
+ return await self._mcp_toolkit.call_tool(tool_name, tool_args)
@@ -138,34 +138,43 @@ class NoteTakingToolkit(BaseToolkit):
138
138
  self.registry.append(note_name)
139
139
  self._save_registry()
140
140
 
141
- def create_note(self, note_name: str, content: str = "") -> str:
141
+ def create_note(
142
+ self, note_name: str, content: str, overwrite: bool = False
143
+ ) -> str:
142
144
  r"""Creates a new note with a unique name.
143
145
 
144
146
  This function will create a new file for your note.
145
- You must provide a `note_name` that does not already exist. If you want
146
- to add content to an existing note, use the `append_note` function
147
- instead.
147
+ By default, you must provide a `note_name` that does not already exist.
148
+ If you want to add content to an existing note, use the `append_note`
149
+ function instead. If you want to overwrite an existing note, set
150
+ `overwrite=True`.
148
151
 
149
152
  Args:
150
153
  note_name (str): The name for your new note (without the .md
151
- extension). This name must be unique.
152
- content (str, optional): The initial content to write in the note.
153
- If not provided, an empty note will be created. Defaults to "".
154
+ extension). This name must be unique unless overwrite is True.
155
+ content (str): The initial content to write in the note.
156
+ overwrite (bool): Whether to overwrite an existing note.
157
+ Defaults to False.
154
158
 
155
159
  Returns:
156
160
  str: A message confirming the creation of the note or an error if
157
- the note name is not valid or already exists.
161
+ the note name is not valid or already exists
162
+ (when overwrite=False).
158
163
  """
159
164
  try:
160
165
  note_path = self.working_directory / f"{note_name}.md"
166
+ existed_before = note_path.exists()
161
167
 
162
- if note_path.exists():
168
+ if existed_before and not overwrite:
163
169
  return f"Error: Note '{note_name}.md' already exists."
164
170
 
165
171
  note_path.write_text(content, encoding="utf-8")
166
172
  self._register_note(note_name)
167
173
 
168
- return f"Note '{note_name}.md' successfully created."
174
+ if existed_before and overwrite:
175
+ return f"Note '{note_name}.md' successfully overwritten."
176
+ else:
177
+ return f"Note '{note_name}.md' successfully created."
169
178
  except Exception as e:
170
179
  return f"Error creating note: {e}"
171
180
 
@@ -14,12 +14,12 @@
14
14
 
15
15
  from typing import Any, ClassVar, Dict, List, Optional, Set
16
16
 
17
- from camel.toolkits import BaseToolkit, FunctionTool
17
+ from camel.toolkits import FunctionTool
18
18
 
19
19
  from .mcp_toolkit import MCPToolkit
20
20
 
21
21
 
22
- class NotionMCPToolkit(BaseToolkit):
22
+ class NotionMCPToolkit(MCPToolkit):
23
23
  r"""NotionMCPToolkit provides an interface for interacting with Notion
24
24
  through the Model Context Protocol (MCP).
25
25
 
@@ -75,31 +75,21 @@ class NotionMCPToolkit(BaseToolkit):
75
75
  timeout (Optional[float]): Connection timeout in seconds.
76
76
  (default: :obj:`None`)
77
77
  """
78
- super().__init__(timeout=timeout)
79
-
80
- self._mcp_toolkit = MCPToolkit(
81
- config_dict={
82
- "mcpServers": {
83
- "notionMCP": {
84
- "command": "npx",
85
- "args": [
86
- "-y",
87
- "mcp-remote",
88
- "https://mcp.notion.com/mcp",
89
- ],
90
- }
78
+ config_dict = {
79
+ "mcpServers": {
80
+ "notionMCP": {
81
+ "command": "npx",
82
+ "args": [
83
+ "-y",
84
+ "mcp-remote",
85
+ "https://mcp.notion.com/mcp",
86
+ ],
91
87
  }
92
- },
93
- timeout=timeout,
94
- )
95
-
96
- async def connect(self):
97
- r"""Explicitly connect to the Notion MCP server."""
98
- await self._mcp_toolkit.connect()
88
+ }
89
+ }
99
90
 
100
- async def disconnect(self):
101
- r"""Explicitly disconnect from the Notion MCP server."""
102
- await self._mcp_toolkit.disconnect()
91
+ # Initialize parent MCPToolkit with Notion configuration
92
+ super().__init__(config_dict=config_dict, timeout=timeout)
103
93
 
104
94
  def get_tools(self) -> List[FunctionTool]:
105
95
  r"""Returns a list of tools provided by the NotionMCPToolkit.
@@ -108,7 +98,7 @@ class NotionMCPToolkit(BaseToolkit):
108
98
  List[FunctionTool]: List of available tools.
109
99
  """
110
100
  all_tools = []
111
- for client in self._mcp_toolkit.clients:
101
+ for client in self.clients:
112
102
  try:
113
103
  original_build_schema = client._build_tool_schema
114
104
 
@@ -17,7 +17,11 @@ from typing import List, Literal, Optional
17
17
 
18
18
  from camel.toolkits.base import BaseToolkit
19
19
  from camel.toolkits.function_tool import FunctionTool
20
- from camel.utils import MCPServer, api_keys_required, dependencies_required
20
+ from camel.utils import (
21
+ MCPServer,
22
+ api_keys_required,
23
+ dependencies_required,
24
+ )
21
25
 
22
26
 
23
27
  @MCPServer()
@@ -12,12 +12,12 @@
12
12
  # limitations under the License.
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
 
15
- from typing import Dict, List, Optional
15
+ from typing import Dict, Optional
16
16
 
17
- from camel.toolkits import BaseToolkit, FunctionTool, MCPToolkit
17
+ from .mcp_toolkit import MCPToolkit
18
18
 
19
19
 
20
- class OrigeneToolkit(BaseToolkit):
20
+ class OrigeneToolkit(MCPToolkit):
21
21
  r"""OrigeneToolkit provides an interface for interacting with
22
22
  Origene MCP server.
23
23
 
@@ -43,55 +43,14 @@ class OrigeneToolkit(BaseToolkit):
43
43
 
44
44
  Args:
45
45
  config_dict (Optional[Dict]): Configuration dictionary for MCP
46
- servers. If None, uses default configuration for chembl_mcp.
47
- (default: :obj:`None`)
46
+ servers. If None, raises ValueError as configuration is
47
+ required. (default: :obj:`None`)
48
48
  timeout (Optional[float]): Connection timeout in seconds.
49
49
  (default: :obj:`None`)
50
50
  """
51
- super().__init__(timeout=timeout)
52
-
53
- # Use default configuration if none provided
51
+ # Validate that config_dict is provided
54
52
  if config_dict is None:
55
53
  raise ValueError("config_dict must be provided")
56
54
 
57
- self._mcp_toolkit = MCPToolkit(
58
- config_dict=config_dict,
59
- timeout=timeout,
60
- )
61
-
62
- async def connect(self):
63
- r"""Explicitly connect to the Origene MCP server."""
64
- await self._mcp_toolkit.connect()
65
-
66
- async def disconnect(self):
67
- r"""Explicitly disconnect from the Origene MCP server."""
68
- await self._mcp_toolkit.disconnect()
69
-
70
- async def __aenter__(self) -> "OrigeneToolkit":
71
- r"""Async context manager entry point.
72
-
73
- Returns:
74
- OrigeneToolkit: The connected toolkit instance.
75
-
76
- Example:
77
- async with OrigeneToolkit(config_dict=config) as toolkit:
78
- tools = toolkit.get_tools()
79
- """
80
- await self.connect()
81
- return self
82
-
83
- async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
84
- r"""Async context manager exit point.
85
-
86
- Automatically disconnects from the Origene MCP server.
87
- """
88
- await self.disconnect()
89
- return None
90
-
91
- def get_tools(self) -> List[FunctionTool]:
92
- r"""Returns a list of tools provided by the Origene MCP server.
93
-
94
- Returns:
95
- List[FunctionTool]: List of available tools.
96
- """
97
- return self._mcp_toolkit.get_tools()
55
+ # Initialize parent MCPToolkit with provided configuration
56
+ super().__init__(config_dict=config_dict, timeout=timeout)
@@ -14,12 +14,10 @@
14
14
 
15
15
  from typing import List, Optional
16
16
 
17
- from camel.toolkits import BaseToolkit, FunctionTool
18
-
19
17
  from .mcp_toolkit import MCPToolkit
20
18
 
21
19
 
22
- class PlaywrightMCPToolkit(BaseToolkit):
20
+ class PlaywrightMCPToolkit(MCPToolkit):
23
21
  r"""PlaywrightMCPToolkit provides an interface for interacting with web
24
22
  browsers using the Playwright automation library through the Model Context
25
23
  Protocol (MCP).
@@ -51,33 +49,16 @@ class PlaywrightMCPToolkit(BaseToolkit):
51
49
  `["--cdp-endpoint=http://localhost:9222"]`.
52
50
  (default: :obj:`None`)
53
51
  """
54
- super().__init__(timeout=timeout)
55
-
56
- self._mcp_toolkit = MCPToolkit(
57
- config_dict={
58
- "mcpServers": {
59
- "playwright": {
60
- "command": "npx",
61
- "args": ["@playwright/mcp@latest"]
62
- + (additional_args or []),
63
- }
52
+ # Create config for Playwright MCP server
53
+ config_dict = {
54
+ "mcpServers": {
55
+ "playwright": {
56
+ "command": "npx",
57
+ "args": ["@playwright/mcp@latest"]
58
+ + (additional_args or []),
64
59
  }
65
- },
66
- timeout=timeout,
67
- )
68
-
69
- async def connect(self):
70
- r"""Explicitly connect to the Playwright MCP server."""
71
- await self._mcp_toolkit.connect()
60
+ }
61
+ }
72
62
 
73
- async def disconnect(self):
74
- r"""Explicitly disconnect from the Playwright MCP server."""
75
- await self._mcp_toolkit.disconnect()
76
-
77
- def get_tools(self) -> List[FunctionTool]:
78
- r"""Returns a list of tools provided by the PlaywrightMCPToolkit.
79
-
80
- Returns:
81
- List[FunctionTool]: List of available tools.
82
- """
83
- return self._mcp_toolkit.get_tools()
63
+ # Initialize parent MCPToolkit with Playwright configuration
64
+ super().__init__(config_dict=config_dict, timeout=timeout)
@@ -0,0 +1,168 @@
1
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
+
15
+ from typing import Dict, List, Optional, cast
16
+
17
+ from camel.toolkits.base import BaseToolkit
18
+ from camel.toolkits.function_tool import FunctionTool
19
+ from camel.utils import MCPServer, api_keys_required
20
+
21
+
22
+ @MCPServer()
23
+ class ResendToolkit(BaseToolkit):
24
+ r"""A toolkit for sending emails using the Resend API.
25
+
26
+ This toolkit provides functionality to send emails using Resend's
27
+ Python SDK.It supports sending both HTML and plain text emails,
28
+ with options for multiple recipients, CC, BCC, reply-to
29
+ addresses, and custom headers.
30
+
31
+ Notes:
32
+ To use this toolkit, you need to set the following environment
33
+ variable:
34
+ - RESEND_API_KEY: Your Resend API key. You can get one from
35
+ https://resend.com/api-keys
36
+
37
+ Example:
38
+ .. code-block:: python
39
+
40
+ from camel.toolkits import ResendToolkit
41
+
42
+ # Initialize the toolkit
43
+ toolkit = ResendToolkit()
44
+
45
+ # Get tools
46
+ tools = toolkit.get_tools()
47
+ """
48
+
49
+ @api_keys_required([(None, "RESEND_API_KEY")])
50
+ def send_email(
51
+ self,
52
+ to: List[str],
53
+ subject: str,
54
+ from_email: str,
55
+ html: Optional[str] = None,
56
+ text: Optional[str] = None,
57
+ cc: Optional[List[str]] = None,
58
+ bcc: Optional[List[str]] = None,
59
+ reply_to: Optional[str] = None,
60
+ tags: Optional[List[Dict[str, str]]] = None,
61
+ headers: Optional[Dict[str, str]] = None,
62
+ ) -> str:
63
+ r"""Send an email using the Resend API.
64
+
65
+ Args:
66
+ to (List[str]): List of recipient email addresses.
67
+ subject (str): The email subject line.
68
+ from_email (str): The sender email address. Must be from a verified
69
+ domain.
70
+ html (Optional[str]): The HTML content of the email. Either html or
71
+ text must be provided. (default: :obj:`None`)
72
+ text (Optional[str]): The plain text content of the email. Either
73
+ html or text must be provided. (default: :obj:`None`)
74
+ cc (Optional[List[str]]): List of CC recipient email addresses.
75
+ (default: :obj:`None`)
76
+ bcc (Optional[List[str]]): List of BCC recipient email addresses.
77
+ (default: :obj:`None`)
78
+ reply_to (Optional[str]): The reply-to email address.
79
+ (default: :obj:`None`)
80
+ tags (Optional[List[Dict[str, str]]]): List of tags to attach to
81
+ the email. Each tag should be a dict with 'name' and
82
+ 'value' keys. (default: :obj:`None`)
83
+ headers (Optional[Dict[str, str]]): Custom headers to include in
84
+ the email.(default: :obj:`None`)
85
+
86
+ Returns:
87
+ str: A success message with the email ID if sent successfully,
88
+ or an error message if the send failed.
89
+
90
+ Raises:
91
+ ValueError: If neither html nor text content is provided.
92
+
93
+ Example:
94
+ .. code-block:: python
95
+
96
+ toolkit = ResendToolkit()
97
+ result = toolkit.send_email(
98
+ to=["recipient@example.com"],
99
+ subject="Hello World",
100
+ from_email="sender@yourdomain.com",
101
+ html="<h1>Hello, World!</h1>",
102
+ text="Hello, World!"
103
+ )
104
+ """
105
+ import os
106
+
107
+ if not html and not text:
108
+ raise ValueError(
109
+ "Either 'html' or 'text' content must be provided"
110
+ )
111
+
112
+ try:
113
+ import resend
114
+ except ImportError:
115
+ raise ImportError(
116
+ "Please install the resend package first. "
117
+ "You can install it by running `pip install resend`."
118
+ )
119
+
120
+ # Set the API key
121
+ resend.api_key = os.getenv("RESEND_API_KEY")
122
+
123
+ # Prepare email parameters
124
+ params: resend.Emails.SendParams = {
125
+ "from": from_email,
126
+ "to": to,
127
+ "subject": subject,
128
+ }
129
+
130
+ # Add content
131
+ if html:
132
+ params["html"] = html
133
+ if text:
134
+ params["text"] = text
135
+
136
+ # Add optional parameters
137
+ if cc:
138
+ params["cc"] = cc
139
+ if bcc:
140
+ params["bcc"] = bcc
141
+ if reply_to:
142
+ params["reply_to"] = reply_to
143
+ if tags:
144
+ params["tags"] = cast('list[resend.emails._tag.Tag]', tags)
145
+ if headers:
146
+ params["headers"] = headers
147
+
148
+ try:
149
+ # Send the email
150
+ email = resend.Emails.send(params)
151
+ return (
152
+ f"Email sent successfully. "
153
+ f"Email ID: {email.get('id', 'Unknown')}"
154
+ )
155
+ except Exception as e:
156
+ return f"Failed to send email: {e!s}"
157
+
158
+ def get_tools(self) -> List[FunctionTool]:
159
+ r"""Returns a list of FunctionTool objects representing the
160
+ functions in the toolkit.
161
+
162
+ Returns:
163
+ List[FunctionTool]: A list of FunctionTool objects
164
+ representing the functions in the toolkit.
165
+ """
166
+ return [
167
+ FunctionTool(self.send_email),
168
+ ]