camel-ai 0.2.44__py3-none-any.whl → 0.2.45__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.

camel/__init__.py CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  from camel.logger import disable_logging, enable_logging, set_log_level
16
16
 
17
- __version__ = '0.2.44'
17
+ __version__ = '0.2.45'
18
18
 
19
19
  __all__ = [
20
20
  '__version__',
@@ -44,7 +44,28 @@ except (ImportError, AttributeError):
44
44
 
45
45
 
46
46
  class CohereModel(BaseModelBackend):
47
- r"""Cohere API in a unified BaseModelBackend interface."""
47
+ r"""Cohere API in a unified BaseModelBackend interface.
48
+
49
+ Args:
50
+ model_type (Union[ModelType, str]): Model for which a backend is
51
+ created, one of Cohere series.
52
+ model_config_dict (Optional[Dict[str, Any]], optional): A dictionary
53
+ that will be fed into:obj:`cohere.ClientV2().chat()`. If
54
+ :obj:`None`, :obj:`CohereConfig().as_dict()` will be used.
55
+ (default: :obj:`None`)
56
+ api_key (Optional[str], optional): The API key for authenticating with
57
+ the Cohere service. (default: :obj:`None`)
58
+ url (Optional[str], optional): The url to the Cohere service.
59
+ (default: :obj:`None`)
60
+ token_counter (Optional[BaseTokenCounter], optional): Token counter to
61
+ use for the model. If not provided, :obj:`OpenAITokenCounter(
62
+ ModelType.GPT_4O_MINI)` will be used.
63
+ (default: :obj:`None`)
64
+ timeout (Optional[float], optional): The timeout value in seconds for
65
+ API calls. If not provided, will fall back to the MODEL_TIMEOUT
66
+ environment variable or default to 180 seconds.
67
+ (default: :obj:`None`)
68
+ """
48
69
 
49
70
  @api_keys_required(
50
71
  [
@@ -58,6 +79,7 @@ class CohereModel(BaseModelBackend):
58
79
  api_key: Optional[str] = None,
59
80
  url: Optional[str] = None,
60
81
  token_counter: Optional[BaseTokenCounter] = None,
82
+ timeout: Optional[float] = None,
61
83
  ):
62
84
  import cohere
63
85
 
@@ -66,11 +88,17 @@ class CohereModel(BaseModelBackend):
66
88
 
67
89
  api_key = api_key or os.environ.get("COHERE_API_KEY")
68
90
  url = url or os.environ.get("COHERE_API_BASE_URL")
91
+
92
+ timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
69
93
  super().__init__(
70
- model_type, model_config_dict, api_key, url, token_counter
94
+ model_type, model_config_dict, api_key, url, token_counter, timeout
95
+ )
96
+ self._client = cohere.ClientV2(
97
+ timeout=self._timeout, api_key=self._api_key
98
+ )
99
+ self._async_client = cohere.AsyncClientV2(
100
+ timeout=self._timeout, api_key=self._api_key
71
101
  )
72
- self._client = cohere.ClientV2(api_key=self._api_key)
73
- self._async_client = cohere.AsyncClientV2(api_key=self._api_key)
74
102
 
75
103
  def _to_openai_response(self, response: 'ChatResponse') -> ChatCompletion:
76
104
  if response.usage and response.usage.tokens:
@@ -11,6 +11,7 @@
11
11
  # See the License for the specific language governing permissions and
12
12
  # limitations under the License.
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
+ import os
14
15
  from typing import Any, Dict, List, Optional, Type, Union
15
16
 
16
17
  from pydantic import BaseModel
@@ -33,8 +34,8 @@ class LiteLLMModel(BaseModelBackend):
33
34
  model_type (Union[ModelType, str]): Model for which a backend is
34
35
  created, such as GPT-3.5-turbo, Claude-2, etc.
35
36
  model_config_dict (Optional[Dict[str, Any]], optional): A dictionary
36
- that will be fed into:obj:`openai.ChatCompletion.create()`.
37
- If:obj:`None`, :obj:`LiteLLMConfig().as_dict()` will be used.
37
+ that will be fed into:obj:`completion()`. If:obj:`None`,
38
+ :obj:`LiteLLMConfig().as_dict()` will be used.
38
39
  (default: :obj:`None`)
39
40
  api_key (Optional[str], optional): The API key for authenticating with
40
41
  the model service. (default: :obj:`None`)
@@ -43,6 +44,10 @@ class LiteLLMModel(BaseModelBackend):
43
44
  token_counter (Optional[BaseTokenCounter], optional): Token counter to
44
45
  use for the model. If not provided, :obj:`LiteLLMTokenCounter` will
45
46
  be used. (default: :obj:`None`)
47
+ timeout (Optional[float], optional): The timeout value in seconds for
48
+ API calls. If not provided, will fall back to the MODEL_TIMEOUT
49
+ environment variable or default to 180 seconds.
50
+ (default: :obj:`None`)
46
51
  """
47
52
 
48
53
  # NOTE: Currently stream mode is not supported.
@@ -55,14 +60,15 @@ class LiteLLMModel(BaseModelBackend):
55
60
  api_key: Optional[str] = None,
56
61
  url: Optional[str] = None,
57
62
  token_counter: Optional[BaseTokenCounter] = None,
63
+ timeout: Optional[float] = None,
58
64
  ) -> None:
59
65
  from litellm import completion
60
66
 
61
67
  if model_config_dict is None:
62
68
  model_config_dict = LiteLLMConfig().as_dict()
63
-
69
+ timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
64
70
  super().__init__(
65
- model_type, model_config_dict, api_key, url, token_counter
71
+ model_type, model_config_dict, api_key, url, token_counter, timeout
66
72
  )
67
73
  self.client = completion
68
74
 
@@ -127,6 +133,7 @@ class LiteLLMModel(BaseModelBackend):
127
133
  ChatCompletion
128
134
  """
129
135
  response = self.client(
136
+ timeout=self._timeout,
130
137
  api_key=self._api_key,
131
138
  base_url=self._url,
132
139
  model=self.model_type,
@@ -62,6 +62,10 @@ class MistralModel(BaseModelBackend):
62
62
  token_counter (Optional[BaseTokenCounter], optional): Token counter to
63
63
  use for the model. If not provided, :obj:`OpenAITokenCounter` will
64
64
  be used. (default: :obj:`None`)
65
+ timeout (Optional[float], optional): The timeout value in seconds for
66
+ API calls. If not provided, will fall back to the MODEL_TIMEOUT
67
+ environment variable or default to 180 seconds.
68
+ (default: :obj:`None`)
65
69
  """
66
70
 
67
71
  @api_keys_required(
@@ -77,6 +81,7 @@ class MistralModel(BaseModelBackend):
77
81
  api_key: Optional[str] = None,
78
82
  url: Optional[str] = None,
79
83
  token_counter: Optional[BaseTokenCounter] = None,
84
+ timeout: Optional[float] = None,
80
85
  ) -> None:
81
86
  from mistralai import Mistral
82
87
 
@@ -85,10 +90,17 @@ class MistralModel(BaseModelBackend):
85
90
 
86
91
  api_key = api_key or os.environ.get("MISTRAL_API_KEY")
87
92
  url = url or os.environ.get("MISTRAL_API_BASE_URL")
93
+ timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
88
94
  super().__init__(
89
- model_type, model_config_dict, api_key, url, token_counter
95
+ model_type, model_config_dict, api_key, url, token_counter, timeout
96
+ )
97
+ self._client = Mistral(
98
+ timeout_ms=int(self._timeout)
99
+ if self._timeout is not None
100
+ else None,
101
+ api_key=self._api_key,
102
+ server_url=self._url,
90
103
  )
91
- self._client = Mistral(api_key=self._api_key, server_url=self._url)
92
104
 
93
105
  def _to_openai_response(
94
106
  self, response: 'ChatCompletionResponse'
@@ -56,6 +56,10 @@ class RekaModel(BaseModelBackend):
56
56
  token_counter (Optional[BaseTokenCounter], optional): Token counter to
57
57
  use for the model. If not provided, :obj:`OpenAITokenCounter` will
58
58
  be used. (default: :obj:`None`)
59
+ timeout (Optional[float], optional): The timeout value in seconds for
60
+ API calls. If not provided, will fall back to the MODEL_TIMEOUT
61
+ environment variable or default to 180 seconds.
62
+ (default: :obj:`None`)
59
63
  """
60
64
 
61
65
  @api_keys_required(
@@ -71,6 +75,7 @@ class RekaModel(BaseModelBackend):
71
75
  api_key: Optional[str] = None,
72
76
  url: Optional[str] = None,
73
77
  token_counter: Optional[BaseTokenCounter] = None,
78
+ timeout: Optional[float] = None,
74
79
  ) -> None:
75
80
  from reka.client import AsyncReka, Reka
76
81
 
@@ -78,12 +83,15 @@ class RekaModel(BaseModelBackend):
78
83
  model_config_dict = RekaConfig().as_dict()
79
84
  api_key = api_key or os.environ.get("REKA_API_KEY")
80
85
  url = url or os.environ.get("REKA_API_BASE_URL")
86
+ timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
81
87
  super().__init__(
82
- model_type, model_config_dict, api_key, url, token_counter
88
+ model_type, model_config_dict, api_key, url, token_counter, timeout
89
+ )
90
+ self._client = Reka(
91
+ api_key=self._api_key, base_url=self._url, timeout=self._timeout
83
92
  )
84
- self._client = Reka(api_key=self._api_key, base_url=self._url)
85
93
  self._async_client = AsyncReka(
86
- api_key=self._api_key, base_url=self._url
94
+ api_key=self._api_key, base_url=self._url, timeout=self._timeout
87
95
  )
88
96
 
89
97
  def _convert_reka_to_openai_response(
@@ -41,6 +41,10 @@ class VolcanoModel(OpenAICompatibleModel):
41
41
  token_counter (Optional[BaseTokenCounter], optional): Token counter to
42
42
  use for the model. If not provided, :obj:`OpenAITokenCounter`
43
43
  will be used. (default: :obj:`None`)
44
+ timeout (Optional[float], optional): The timeout value in seconds for
45
+ API calls. If not provided, will fall back to the MODEL_TIMEOUT
46
+ environment variable or default to 180 seconds.
47
+ (default: :obj:`None`)
44
48
  """
45
49
 
46
50
  @api_keys_required(
@@ -55,6 +59,7 @@ class VolcanoModel(OpenAICompatibleModel):
55
59
  api_key: Optional[str] = None,
56
60
  url: Optional[str] = None,
57
61
  token_counter: Optional[BaseTokenCounter] = None,
62
+ timeout: Optional[float] = None,
58
63
  ) -> None:
59
64
  if model_config_dict is None:
60
65
  model_config_dict = {}
@@ -65,9 +70,9 @@ class VolcanoModel(OpenAICompatibleModel):
65
70
  or os.environ.get("VOLCANO_API_BASE_URL")
66
71
  or "https://ark.cn-beijing.volces.com/api/v3"
67
72
  )
68
-
73
+ timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
69
74
  super().__init__(
70
- model_type, model_config_dict, api_key, url, token_counter
75
+ model_type, model_config_dict, api_key, url, token_counter, timeout
71
76
  )
72
77
 
73
78
  @property
camel/runtime/__init__.py CHANGED
@@ -16,6 +16,7 @@ from .configs import TaskConfig
16
16
  from .docker_runtime import DockerRuntime
17
17
  from .llm_guard_runtime import LLMGuardRuntime
18
18
  from .remote_http_runtime import RemoteHttpRuntime
19
+ from .ubuntu_docker_runtime import UbuntuDockerRuntime
19
20
 
20
21
  # TODO: Add Celery Runtime to support distributed computing,
21
22
  # Rate Limiting, Load Balancing, etc.
@@ -26,4 +27,5 @@ __all__ = [
26
27
  "RemoteHttpRuntime",
27
28
  "LLMGuardRuntime",
28
29
  "TaskConfig",
30
+ "UbuntuDockerRuntime",
29
31
  ]
@@ -0,0 +1,340 @@
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 logging
16
+ import sys
17
+ import time
18
+ from pathlib import Path
19
+ from typing import Callable, List, Optional, Union
20
+
21
+ from camel.runtime.docker_runtime import DockerRuntime
22
+ from camel.toolkits import FunctionTool
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class UbuntuDockerRuntime(DockerRuntime):
28
+ r"""A specialized Docker runtime for Ubuntu-based environments.
29
+
30
+ This runtime includes specific configurations and setup for Ubuntu
31
+ containers, including proper Python path handling and environment setup.
32
+ It provides methods for executing Python files, managing the container
33
+ lifecycle, and handling file operations within the Ubuntu container.
34
+
35
+ Attributes:
36
+ python_path (str): Path to the Python interpreter in the container
37
+ docker_config (dict): Configuration dict for Docker container setup
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ image: str,
43
+ port: int = 0,
44
+ remove: bool = True,
45
+ python_path: str = "/usr/bin/python3",
46
+ **kwargs,
47
+ ):
48
+ r"""Initialize the Ubuntu Docker Runtime.
49
+
50
+ Args:
51
+ image (str): Docker image name to use
52
+ port (int, optional): Port to expose. Defaults to 0 (random port)
53
+ remove (bool, optional): Whether to remove container after use.
54
+ Defaults to True
55
+ python_path (str, optional): Path to Python interpreter.
56
+ Defaults to "/usr/bin/python3"
57
+ **kwargs: Additional arguments passed to DockerRuntime
58
+ """
59
+ super().__init__(image=image, port=port, remove=remove, **kwargs)
60
+
61
+ self.python_path = python_path
62
+ logger.info(
63
+ f"Initializing UbuntuDockerRuntime with python_path: {python_path}"
64
+ )
65
+
66
+ # Set default environment variables for Ubuntu
67
+ self.docker_config.setdefault("environment", {})
68
+ self.docker_config["environment"].update(
69
+ {
70
+ "PYTHON_PATH": python_path,
71
+ "PYTHON_EXECUTABLE": python_path,
72
+ "PATH": "/usr/local/bin:/usr/bin:/bin",
73
+ "PYTHONUNBUFFERED": "1",
74
+ }
75
+ )
76
+ logger.info(
77
+ f"Environment variables set: {self.docker_config['environment']}"
78
+ )
79
+
80
+ # Add default working directory
81
+ self.docker_config.setdefault("working_dir", "/app")
82
+
83
+ # Setup default volume mounts
84
+ self._setup_default_mounts()
85
+
86
+ def add(
87
+ self,
88
+ funcs: Union[FunctionTool, List[FunctionTool]],
89
+ entrypoint: str,
90
+ redirect_stdout: bool = False,
91
+ arguments: Optional[dict] = None,
92
+ ) -> "UbuntuDockerRuntime":
93
+ r"""Add functions to the runtime with Ubuntu-specific modifications.
94
+
95
+ Args:
96
+ funcs: Function(s) to add to the runtime
97
+ entrypoint: Entry point for function execution
98
+ redirect_stdout: Whether to redirect stdout
99
+ arguments: Optional arguments for function execution
100
+
101
+ Returns:
102
+ Self for method chaining
103
+ """
104
+ if not isinstance(funcs, list):
105
+ funcs = [funcs]
106
+
107
+ # Modify the code execution command to use python3
108
+ for func in funcs:
109
+ logger.info(f"Processing function: {func.get_function_name()}")
110
+ if hasattr(func, 'command'):
111
+ logger.info(f"Original command: {func.command}")
112
+ if isinstance(func.command, list):
113
+ if 'python' in func.command:
114
+ idx = func.command.index('python')
115
+ func.command[idx] = self.python_path
116
+ logger.info(f"Modified command: {func.command}")
117
+ else:
118
+ logger.info(
119
+ f"No command attribute found for function "
120
+ f"{func.get_function_name()}"
121
+ )
122
+
123
+ super().add(funcs, entrypoint, redirect_stdout, arguments)
124
+ return self
125
+
126
+ def _setup_default_mounts(self):
127
+ r"""Setup default volume mounts for the container.
128
+
129
+ This method can be extended to add Ubuntu-specific volume mounts.
130
+ """
131
+ pass
132
+
133
+ def build(self, time_out: int = 15) -> "UbuntuDockerRuntime":
134
+ r"""Build and initialize the Ubuntu container with proper setup.
135
+
136
+ Args:
137
+ time_out (int): Timeout in seconds for build operation
138
+
139
+ Returns:
140
+ Self for method chaining
141
+ """
142
+ logger.info("Starting container build...")
143
+
144
+ super().build(time_out=time_out)
145
+
146
+ if self.container:
147
+ logger.info("Container built successfully, verifying setup...")
148
+
149
+ # Verify Python installation
150
+ exit_code, output = self.container.exec_run(
151
+ [self.python_path, "--version"]
152
+ )
153
+ logger.info(f"Python version check result: {output.decode()}")
154
+ if exit_code != 0:
155
+ logger.error(
156
+ f"Python version check failed with exit code {exit_code}"
157
+ )
158
+ raise RuntimeError(
159
+ f"Python installation verification "
160
+ f"failed: {output.decode()}"
161
+ )
162
+
163
+ # Install required packages
164
+ logger.info("Installing required packages...")
165
+ exit_code, output = self.container.exec_run("apt-get update")
166
+ if exit_code != 0:
167
+ logger.error(
168
+ f"apt-get update failed with "
169
+ f"exit code {exit_code}: {output.decode()}"
170
+ )
171
+ raise RuntimeError(
172
+ f"Failed to update package lists: {output.decode()}"
173
+ )
174
+
175
+ exit_code, output = self.container.exec_run(
176
+ "apt-get install -y curl"
177
+ )
178
+ if exit_code != 0:
179
+ logger.error(
180
+ f"apt-get install curl failed with "
181
+ f"exit code {exit_code}: {output.decode()}"
182
+ )
183
+ raise RuntimeError(
184
+ f"Failed to install curl: {output.decode()}"
185
+ )
186
+
187
+ # Start API server with explicit Python path
188
+ logger.info("Starting API server...")
189
+ exec_result = self.container.exec_run(
190
+ [self.python_path, "/home/api.py"],
191
+ detach=True,
192
+ environment={
193
+ "PYTHONPATH": str(
194
+ Path(self.python_path).parent
195
+ / "lib/python3.10/site-packages"
196
+ ),
197
+ "PYTHON_EXECUTABLE": self.python_path,
198
+ },
199
+ )
200
+ logger.info("API server start result: %s", exec_result)
201
+
202
+ # Wait for API server to start
203
+ start_time = time.time()
204
+ while time.time() - start_time < 10:
205
+ try:
206
+ exit_code, curl_result = self.container.exec_run(
207
+ "curl -s -o /dev/null -w '%{http_code}' http://localhost:8000/docs"
208
+ )
209
+ status_code = curl_result.decode().strip()
210
+ if exit_code == 0 and status_code.startswith('2'):
211
+ logger.info(
212
+ f"API server is running "
213
+ f"(status code: {status_code})"
214
+ )
215
+ break
216
+ else:
217
+ logger.debug(
218
+ f"API server not ready yet (status: {status_code})"
219
+ )
220
+ except Exception as e:
221
+ logger.debug("Waiting for API server... %s", e)
222
+ time.sleep(0.5)
223
+ else:
224
+ logger.warning("API server may not be running properly")
225
+
226
+ return self
227
+
228
+ def exec_python_file(
229
+ self,
230
+ local_file_path: str,
231
+ container_path: Optional[str] = None,
232
+ args: Optional[List[str]] = None,
233
+ env: Optional[dict] = None,
234
+ callback: Optional[Callable[[str], None]] = None,
235
+ ) -> None:
236
+ r"""Execute a Python file inside the Docker container.
237
+
238
+ Args:
239
+ local_file_path: Path to the Python file on the local filesystem
240
+ container_path: Path where the file should be copied in the
241
+ container If None, the file will be copied to /tmp/
242
+ args: List of command-line arguments to pass to the Python script
243
+ env: Additional environment variables to set for the execution
244
+ callback: Optional function to process each line of output
245
+ If None, output is printed to stdout
246
+
247
+ Raises:
248
+ RuntimeError: If container is not running
249
+ FileNotFoundError: If Python file is not found
250
+ """
251
+ if not self.container:
252
+ raise RuntimeError("Container is not running. Call build() first.")
253
+
254
+ local_path = Path(local_file_path)
255
+ if not local_path.exists():
256
+ raise FileNotFoundError(f"Python file {local_file_path} not found")
257
+
258
+ # Determine where to put the file in the container
259
+ if container_path is None:
260
+ container_path = f"/tmp/{local_path.name}"
261
+
262
+ logger.info(
263
+ f"Copying {local_file_path} to container at {container_path}"
264
+ )
265
+
266
+ # Copy the file to the container
267
+ self.container.put_archive(
268
+ path=str(Path(container_path).parent),
269
+ data=self._create_archive_from_file(local_path),
270
+ )
271
+
272
+ # Prepare command
273
+ cmd = [self.python_path, container_path]
274
+ if args:
275
+ cmd.extend(args)
276
+
277
+ # Prepare environment
278
+ execution_env = {
279
+ "PYTHONPATH": "/usr/local/lib/python3.10/site-packages",
280
+ "PYTHON_EXECUTABLE": self.python_path,
281
+ }
282
+ execution_env["PYTHONPATH"] = str(
283
+ Path(self.python_path).parent / "lib/python3.10/site-packages"
284
+ )
285
+ if env:
286
+ execution_env.update(env)
287
+
288
+ logger.info(f"Executing Python file with command: {cmd}")
289
+
290
+ # Always use streaming output
291
+ exec_result = self.container.exec_run(
292
+ cmd,
293
+ environment=execution_env,
294
+ stream=True,
295
+ demux=True, # Separate stdout and stderr
296
+ )
297
+
298
+ # Handle output streams
299
+ try:
300
+ for stdout, stderr in exec_result[1]:
301
+ if stdout:
302
+ output = stdout.decode('utf-8')
303
+ if callback:
304
+ callback(output)
305
+ else:
306
+ print(output, end='')
307
+
308
+ if stderr:
309
+ error = stderr.decode('utf-8')
310
+ if callback:
311
+ callback(f"ERROR: {error}")
312
+ else:
313
+ print(f"ERROR: {error}", end='', file=sys.stderr)
314
+ except KeyboardInterrupt:
315
+ logger.info("Execution interrupted by user")
316
+ # Could add logic to stop container processes here
317
+ except Exception as e:
318
+ logger.error(f"Error during execution: {e}")
319
+ raise
320
+
321
+ def _create_archive_from_file(self, file_path: Union[str, Path]) -> bytes:
322
+ r"""Create a tar archive from a single file for docker.put_archive().
323
+
324
+ Args:
325
+ file_path: Path to the file to archive
326
+
327
+ Returns:
328
+ bytes: The tar archive as bytes
329
+ """
330
+ import io
331
+ import tarfile
332
+
333
+ file_path = Path(file_path)
334
+ tar_stream = io.BytesIO()
335
+
336
+ with tarfile.open(fileobj=tar_stream, mode='w') as tar:
337
+ tar.add(file_path, arcname=file_path.name)
338
+
339
+ tar_stream.seek(0)
340
+ return tar_stream.read()
@@ -83,29 +83,33 @@ def download_file(url: str, cache_dir: str) -> str:
83
83
 
84
84
  @MCPServer()
85
85
  class AudioAnalysisToolkit(BaseToolkit):
86
- r"""A toolkit for audio processing and analysis.
87
-
88
- This class provides methods for processing, transcribing, and extracting
89
- information from audio data, including direct question answering about
90
- audio content.
91
-
92
- Args:
93
- cache_dir (Optional[str]): Directory path for caching downloaded audio
94
- files. If not provided, 'tmp/' will be used. (default: :obj:`None`)
95
- transcribe_model (Optional[BaseAudioModel]): Model used for audio
96
- transcription. If not provided, OpenAIAudioModels will be used.
97
- (default: :obj:`None`)
98
- audio_reasoning_model (Optional[BaseModelBackend]): Model used for
99
- audio reasoning and question answering. If not provided, uses the
100
- default model from ChatAgent. (default: :obj:`None`)
101
- """
102
-
103
86
  def __init__(
104
87
  self,
105
88
  cache_dir: Optional[str] = None,
106
89
  transcribe_model: Optional[BaseAudioModel] = None,
107
90
  audio_reasoning_model: Optional[BaseModelBackend] = None,
91
+ timeout: Optional[float] = None,
108
92
  ):
93
+ r"""A toolkit for audio processing and analysis. This class provides
94
+ methods for processing, transcribing, and extracting information from
95
+ audio data, including direct question answering about audio content.
96
+
97
+ Args:
98
+ cache_dir (Optional[str]): Directory path for caching downloaded
99
+ audio files. If not provided, 'tmp/' will be used.
100
+ (default: :obj:`None`)
101
+ transcribe_model (Optional[BaseAudioModel]): Model used for audio
102
+ transcription. If not provided, OpenAIAudioModels will be used.
103
+ (default: :obj:`None`)
104
+ audio_reasoning_model (Optional[BaseModelBackend]): Model used for
105
+ audio reasoning and question answering.
106
+ If not provided, uses the default model from ChatAgent.
107
+ (default: :obj:`None`)
108
+ timeout (Optional[float]): The timeout value for API requests
109
+ in seconds. If None, no timeout is applied.
110
+ (default: :obj:`None`)
111
+ """
112
+ super().__init__(timeout=timeout)
109
113
  self.cache_dir = 'tmp/'
110
114
  if cache_dir:
111
115
  self.cache_dir = cache_dir
@@ -43,8 +43,9 @@ if TYPE_CHECKING:
43
43
  from camel.logger import get_logger
44
44
  from camel.messages import BaseMessage
45
45
  from camel.models import BaseModelBackend, ModelFactory
46
- from camel.toolkits import FunctionTool, VideoAnalysisToolkit
47
46
  from camel.toolkits.base import BaseToolkit
47
+ from camel.toolkits.function_tool import FunctionTool
48
+ from camel.toolkits.video_analysis_toolkit import VideoAnalysisToolkit
48
49
  from camel.types import ModelPlatformType, ModelType
49
50
  from camel.utils import dependencies_required, retry_on_error
50
51
 
@@ -22,13 +22,28 @@ from PIL import Image
22
22
 
23
23
  from camel.toolkits import FunctionTool
24
24
  from camel.toolkits.base import BaseToolkit
25
+ from camel.utils import MCPServer
25
26
 
26
27
 
28
+ @MCPServer()
27
29
  class DalleToolkit(BaseToolkit):
28
30
  r"""A class representing a toolkit for image generation using OpenAI's
29
31
  DALL-E model.
30
32
  """
31
33
 
34
+ def __init__(
35
+ self,
36
+ timeout: Optional[float] = None,
37
+ ):
38
+ r"""Initializes a new instance of the DalleToolkit class.
39
+
40
+ Args:
41
+ timeout (Optional[float]): The timeout value for API requests
42
+ in seconds. If None, no timeout is applied.
43
+ (default: :obj:`None`)
44
+ """
45
+ super().__init__(timeout=timeout)
46
+
32
47
  def base64_to_image(self, base64_string: str) -> Optional[Image.Image]:
33
48
  r"""Converts a base64 encoded string into a PIL Image object.
34
49
 
@@ -12,7 +12,7 @@
12
12
  # limitations under the License.
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
 
15
- from typing import List
15
+ from typing import List, Optional
16
16
 
17
17
  import pandas as pd
18
18
 
@@ -33,6 +33,19 @@ class ExcelToolkit(BaseToolkit):
33
33
  process excel files.
34
34
  """
35
35
 
36
+ def __init__(
37
+ self,
38
+ timeout: Optional[float] = None,
39
+ ):
40
+ r"""Initializes a new instance of the ExcelToolkit class.
41
+
42
+ Args:
43
+ timeout (Optional[float]): The timeout value for API requests
44
+ in seconds. If None, no timeout is applied.
45
+ (default: :obj:`None`)
46
+ """
47
+ super().__init__(timeout=timeout)
48
+
36
49
  def _convert_to_markdown(self, df: pd.DataFrame) -> str:
37
50
  r"""Convert DataFrame to Markdown format table.
38
51
 
@@ -36,7 +36,11 @@ class ImageAnalysisToolkit(BaseToolkit):
36
36
  The toolkit uses vision-capable language models to perform these tasks.
37
37
  """
38
38
 
39
- def __init__(self, model: Optional[BaseModelBackend] = None):
39
+ def __init__(
40
+ self,
41
+ model: Optional[BaseModelBackend] = None,
42
+ timeout: Optional[float] = None,
43
+ ):
40
44
  r"""Initialize the ImageAnalysisToolkit.
41
45
 
42
46
  Args:
@@ -45,7 +49,11 @@ class ImageAnalysisToolkit(BaseToolkit):
45
49
  images for tasks like image description and visual question
46
50
  answering. If None, a default model will be created using
47
51
  ModelFactory. (default: :obj:`None`)
52
+ timeout (Optional[float]): The timeout value for API requests
53
+ in seconds. If None, no timeout is applied.
54
+ (default: :obj:`None`)
48
55
  """
56
+ super().__init__(timeout=timeout)
49
57
  if model:
50
58
  self.model = model
51
59
  else:
@@ -314,6 +314,7 @@ class MCPClient(BaseToolkit):
314
314
  "type": "object",
315
315
  "properties": properties,
316
316
  "required": required,
317
+ "additionalProperties": False,
317
318
  }
318
319
 
319
320
  return {
@@ -322,6 +323,7 @@ class MCPClient(BaseToolkit):
322
323
  "name": mcp_tool.name,
323
324
  "description": mcp_tool.description
324
325
  or "No description provided.",
326
+ "strict": True,
325
327
  "parameters": parameters,
326
328
  },
327
329
  }
@@ -38,6 +38,7 @@ class NetworkXToolkit(BaseToolkit):
38
38
 
39
39
  def __init__(
40
40
  self,
41
+ timeout: Optional[float] = None,
41
42
  graph_type: Literal[
42
43
  'graph', 'digraph', 'multigraph', 'multidigraph'
43
44
  ] = 'graph',
@@ -53,7 +54,11 @@ class NetworkXToolkit(BaseToolkit):
53
54
  - 'multigraph': Undirected graph with parallel edges
54
55
  - 'multidigraph': Directed graph with parallel edges
55
56
  (default: :obj:`'graph'`)
57
+ timeout (Optional[float]): The timeout value for API requests
58
+ in seconds. If None, no timeout is applied.
59
+ (default: :obj:`None`)
56
60
  """
61
+ super().__init__(timeout=timeout)
57
62
  nx = self._get_nx()
58
63
  graph_types = {
59
64
  'graph': nx.Graph,
@@ -45,6 +45,7 @@ class OpenAIAgentToolkit(BaseToolkit):
45
45
  self,
46
46
  model: Optional[BaseModelBackend] = None,
47
47
  api_key: Optional[str] = None,
48
+ timeout: Optional[float] = None,
48
49
  ) -> None:
49
50
  r"""Initialize the OpenAI agent toolkit.
50
51
 
@@ -53,8 +54,11 @@ class OpenAIAgentToolkit(BaseToolkit):
53
54
  If None, defaults to gpt-4o-mini. (default: :obj:`None`)
54
55
  api_key (str): OpenAI API key. If not provided, will attempt to
55
56
  use OPENAI_API_KEY environment variable. (default: :obj:`None`)
57
+ timeout (Optional[float]): The timeout value for API requests
58
+ in seconds. If None, no timeout is applied.
59
+ (default: :obj:`None`)
56
60
  """
57
- super().__init__()
61
+ super().__init__(timeout=timeout)
58
62
  self.api_key = api_key or os.getenv("OPENAI_API_KEY")
59
63
  self.client = OpenAI(api_key=self.api_key)
60
64
  self.model = model or ModelFactory.create(
@@ -20,10 +20,12 @@ import requests
20
20
  from camel.logger import get_logger
21
21
  from camel.toolkits.base import BaseToolkit
22
22
  from camel.toolkits.function_tool import FunctionTool
23
+ from camel.utils import MCPServer
23
24
 
24
25
  logger = get_logger(__name__)
25
26
 
26
27
 
28
+ @MCPServer()
27
29
  class SearxNGToolkit(BaseToolkit):
28
30
  r"""A toolkit for performing web searches using SearxNG search engine.
29
31
 
@@ -42,6 +44,9 @@ class SearxNGToolkit(BaseToolkit):
42
44
  values are "day", "week", "month", "year". (default: :obj:`None`)
43
45
  safe_search (int, optional): Safe search level (0: None, 1: Moderate,
44
46
  2: Strict). (default: :obj:`1`)
47
+ timeout (Optional[float]): The timeout value for API requests
48
+ in seconds. If None, no timeout is applied.
49
+ (default: :obj:`None`)
45
50
 
46
51
  Raises:
47
52
  ValueError: If searxng_host is not a valid HTTP/HTTPS URL.
@@ -65,7 +70,9 @@ class SearxNGToolkit(BaseToolkit):
65
70
  categories: Optional[List[str]] = None,
66
71
  time_range: Optional[str] = None,
67
72
  safe_search: int = 1,
73
+ timeout: Optional[float] = None,
68
74
  ) -> None:
75
+ super().__init__(timeout=timeout)
69
76
  self._validate_searxng_host(searxng_host)
70
77
  self._validate_safe_search(safe_search)
71
78
  if time_range is not None:
@@ -15,7 +15,6 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import json
18
- import logging
19
18
  import os
20
19
  from typing import TYPE_CHECKING, List, Optional
21
20
 
@@ -27,9 +26,10 @@ if TYPE_CHECKING:
27
26
 
28
27
  from slack_sdk import WebClient
29
28
 
29
+ from camel.logger import get_logger
30
30
  from camel.toolkits import FunctionTool
31
31
 
32
- logger = logging.getLogger(__name__)
32
+ logger = get_logger(__name__)
33
33
 
34
34
 
35
35
  @MCPServer()
@@ -40,6 +40,19 @@ class SlackToolkit(BaseToolkit):
40
40
  channel, joining an existing channel, leaving a channel.
41
41
  """
42
42
 
43
+ def __init__(
44
+ self,
45
+ timeout: Optional[float] = None,
46
+ ):
47
+ r"""Initializes a new instance of the SlackToolkit class.
48
+
49
+ Args:
50
+ timeout (Optional[float]): The timeout value for API requests
51
+ in seconds. If None, no timeout is applied.
52
+ (default: :obj:`None`)
53
+ """
54
+ super().__init__(timeout=timeout)
55
+
43
56
  def _login_slack(
44
57
  self,
45
58
  slack_token: Optional[str] = None,
@@ -92,6 +92,9 @@ class VideoAnalysisToolkit(BaseToolkit):
92
92
  transcription using OpenAI's audio models. Requires a valid OpenAI
93
93
  API key. When disabled, video analysis will be based solely on
94
94
  visual content. (default: :obj:`False`)
95
+ timeout (Optional[float]): The timeout value for API requests
96
+ in seconds. If None, no timeout is applied.
97
+ (default: :obj:`None`)
95
98
  """
96
99
 
97
100
  @dependencies_required("ffmpeg", "scenedetect")
@@ -100,7 +103,9 @@ class VideoAnalysisToolkit(BaseToolkit):
100
103
  download_directory: Optional[str] = None,
101
104
  model: Optional[BaseModelBackend] = None,
102
105
  use_audio_transcription: bool = False,
106
+ timeout: Optional[float] = None,
103
107
  ) -> None:
108
+ super().__init__(timeout=timeout)
104
109
  self._cleanup = download_directory is None
105
110
  self._temp_files: list[str] = [] # Track temporary files for cleanup
106
111
  self._use_audio_transcription = use_audio_transcription
@@ -12,7 +12,7 @@
12
12
  # limitations under the License.
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
  import os
15
- from typing import List, Literal
15
+ from typing import List, Literal, Optional
16
16
 
17
17
  from camel.toolkits.base import BaseToolkit
18
18
  from camel.toolkits.function_tool import FunctionTool
@@ -27,6 +27,19 @@ class WeatherToolkit(BaseToolkit):
27
27
  using the OpenWeatherMap API.
28
28
  """
29
29
 
30
+ def __init__(
31
+ self,
32
+ timeout: Optional[float] = None,
33
+ ):
34
+ r"""Initializes a new instance of the WeatherToolkit class.
35
+
36
+ Args:
37
+ timeout (Optional[float]): The timeout value for API requests
38
+ in seconds. If None, no timeout is applied.
39
+ (default: :obj:`None`)
40
+ """
41
+ super().__init__(timeout=timeout)
42
+
30
43
  def get_openweathermap_api_key(self) -> str:
31
44
  r"""Retrieve the OpenWeatherMap API key from environment variables.
32
45
 
@@ -13,7 +13,7 @@
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
 
15
15
  import os
16
- from typing import Any, Dict, List
16
+ from typing import Any, Dict, List, Optional
17
17
 
18
18
  import requests
19
19
 
@@ -33,6 +33,9 @@ class ZapierToolkit(BaseToolkit):
33
33
  Attributes:
34
34
  api_key (str): The API key for authenticating with Zapier's API.
35
35
  base_url (str): The base URL for Zapier's API endpoints.
36
+ timeout (Optional[float]): The timeout value for API requests
37
+ in seconds. If None, no timeout is applied.
38
+ (default: :obj:`None`)
36
39
  """
37
40
 
38
41
  @dependencies_required("requests")
@@ -41,7 +44,8 @@ class ZapierToolkit(BaseToolkit):
41
44
  (None, "ZAPIER_NLA_API_KEY"),
42
45
  ]
43
46
  )
44
- def __init__(self) -> None:
47
+ def __init__(self, timeout: Optional[float] = None) -> None:
48
+ super().__init__(timeout=timeout)
45
49
  r"""Initialize the ZapierToolkit with API client. The API key is
46
50
  retrieved from environment variables.
47
51
  """
camel/types/enums.py CHANGED
@@ -39,6 +39,9 @@ class ModelType(UnifiedModelType, Enum):
39
39
  O1_PREVIEW = "o1-preview"
40
40
  O1_MINI = "o1-mini"
41
41
  O3_MINI = "o3-mini"
42
+ GPT_4_1 = "gpt-4.1-2025-04-14"
43
+ GPT_4_1_MINI = "gpt-4.1-mini-2025-04-14"
44
+ GPT_4_1_NANO = "gpt-4.1-nano-2025-04-14"
42
45
 
43
46
  GLM_4 = "glm-4"
44
47
  GLM_4V = "glm-4v"
@@ -329,6 +332,9 @@ class ModelType(UnifiedModelType, Enum):
329
332
  ModelType.O1_MINI,
330
333
  ModelType.O3_MINI,
331
334
  ModelType.GPT_4_5_PREVIEW,
335
+ ModelType.GPT_4_1,
336
+ ModelType.GPT_4_1_MINI,
337
+ ModelType.GPT_4_1_NANO,
332
338
  }
333
339
 
334
340
  @property
@@ -857,6 +863,9 @@ class ModelType(UnifiedModelType, Enum):
857
863
  ModelType.GLM_4_LONG,
858
864
  ModelType.TOGETHER_LLAMA_4_MAVERICK,
859
865
  ModelType.OPENROUTER_LLAMA_4_MAVERICK,
866
+ ModelType.GPT_4_1,
867
+ ModelType.GPT_4_1_MINI,
868
+ ModelType.GPT_4_1_NANO,
860
869
  }:
861
870
  return 1_048_576
862
871
  elif self in {
camel/verifiers/base.py CHANGED
@@ -209,6 +209,20 @@ class BaseVerifier(ABC):
209
209
  )
210
210
 
211
211
  if not verifiable_solution:
212
+ attempt += 1
213
+ if attempt == self._max_retries:
214
+ return VerificationResult(
215
+ status=VerificationOutcome.ERROR,
216
+ result="",
217
+ error_message="Failed to extract verifiable solution",
218
+ duration=time.time() - start_time,
219
+ metadata={"attempt": attempt},
220
+ )
221
+ logger.warning(
222
+ f"Failed to extract verifiable solution on attempt "
223
+ f"{attempt}, retrying..."
224
+ )
225
+ await asyncio.sleep(self._retry_delay)
212
226
  continue
213
227
 
214
228
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: camel-ai
3
- Version: 0.2.44
3
+ Version: 0.2.45
4
4
  Summary: Communicative Agents for AI Society Study
5
5
  Project-URL: Homepage, https://www.camel-ai.org/
6
6
  Project-URL: Repository, https://github.com/camel-ai/camel
@@ -693,10 +693,10 @@ Practical guides and tutorials for implementing specific functionalities in CAME
693
693
  ### 3. Model Training & Data Generation
694
694
  | Cookbook | Description |
695
695
  |:---|:---|
696
- | **[Data Generation with CAMEL and Finetuning with Unsloth](https://docs.camel-ai.org/cookbooks/model_training/sft_data_generation_and_unsloth_finetuning_Qwen2_5_7B.html)** | Learn how to generate data with CAMEL and fine-tune models effectively with Unsloth. |
697
- | **[Data Gen with Real Function Calls and Hermes Format](https://docs.camel-ai.org/cookbooks/model_training/data_gen_with_real_function_calls_and_hermes_format.html)** | Explore how to generate data with real function calls and the Hermes format. |
698
- | **[CoT Data Generation and Upload Data to Huggingface](https://docs.camel-ai.org/cookbooks/model_training/cot_data_gen_upload_to_huggingface.html)** | Uncover how to generate CoT data with CAMEL and seamlessly upload it to Huggingface. |
699
- | **[CoT Data Generation and SFT Qwen with Unsolth](https://docs.camel-ai.org/cookbooks/model_training/cot_data_gen_sft_qwen_unsolth_upload_huggingface.html)** | Discover how to generate CoT data using CAMEL and SFT Qwen with Unsolth, and seamlessly upload your data and model to Huggingface. |
696
+ | **[Data Generation with CAMEL and Finetuning with Unsloth](https://docs.camel-ai.org/cookbooks/data_generation/sft_data_generation_and_unsloth_finetuning_Qwen2_5_7B.html)** | Learn how to generate data with CAMEL and fine-tune models effectively with Unsloth. |
697
+ | **[Data Gen with Real Function Calls and Hermes Format](https://docs.camel-ai.org/cookbooks/data_generation/data_gen_with_real_function_calls_and_hermes_format.html)** | Explore how to generate data with real function calls and the Hermes format. |
698
+ | **[CoT Data Generation and Upload Data to Huggingface](https://docs.camel-ai.org/cookbooks/data_generation/distill_math_reasoning_data_from_deepseek_r1.html)** | Uncover how to generate CoT data with CAMEL and seamlessly upload it to Huggingface. |
699
+ | **[CoT Data Generation and SFT Qwen with Unsolth](https://docs.camel-ai.org/cookbooks/data_generation/cot_data_gen_sft_qwen_unsolth_upload_huggingface.html)** | Discover how to generate CoT data using CAMEL and SFT Qwen with Unsolth, and seamlessly upload your data and model to Huggingface. |
700
700
 
701
701
  ### 4. Multi-Agent Systems & Applications
702
702
  | Cookbook | Description |
@@ -1,4 +1,4 @@
1
- camel/__init__.py,sha256=JoCVHktI2-iEIXH-BOJucMis7so3ZwAoYxghXz5a56Y,912
1
+ camel/__init__.py,sha256=zhU7RvDmL1FmYtkEqLee6cKHJgseNYLOUBS7g0P2klY,912
2
2
  camel/generators.py,sha256=JRqj9_m1PF4qT6UtybzTQ-KBT9MJQt18OAAYvQ_fr2o,13844
3
3
  camel/human.py,sha256=9X09UmxI2JqQnhrFfnZ3B9EzFmVfdSWQcjLWTIXKXe0,4962
4
4
  camel/logger.py,sha256=rZVeOVYuQ9RYJ5Tqyv0usqy0g4zaVEq4qSfZ9nd2640,5755
@@ -159,14 +159,14 @@ camel/models/anthropic_model.py,sha256=XQRisu4O1HEWL9q-mtF73S434PiZLxTUeDkKCNCD5
159
159
  camel/models/azure_openai_model.py,sha256=psxSx1R9dCRw-jWy58lwhUjPFP01UrhCJ7sHeveu_fo,11057
160
160
  camel/models/base_audio_model.py,sha256=_VUWh1L3rh8mldNvM5R6jBOKtvmTeBKJyRxAdPJmPlY,3324
161
161
  camel/models/base_model.py,sha256=eDeUlgH8iS0Stk6zommzqce4dfD4Qj51tvgXUs5ys4s,14474
162
- camel/models/cohere_model.py,sha256=Nl4i_mfm1Pok8243sSgUBwc8mB5HrHZQAeRdYGwQhFU,13556
162
+ camel/models/cohere_model.py,sha256=OgRHxlPrei-NT5UVDFf6lVR88k6eKnmcZMyFj4XmONE,14880
163
163
  camel/models/deepseek_model.py,sha256=Npi4-5f0pygQX9ZZttJyItZmUhHwNKNIMG3ZN7gciM4,10204
164
164
  camel/models/fish_audio_model.py,sha256=RCwORRIdCbjZXWWjjctpksPI2DnS0b68JjxunHBQ1xk,5981
165
165
  camel/models/gemini_model.py,sha256=OOH6k6lzP4ir_WJebHrKx5ABQcAZh5RZOgFMUia8iMc,12351
166
166
  camel/models/groq_model.py,sha256=Mods2h_OrPqJ0m37M8CwOtFZMgjPjvxOR74aHJfCSvw,7853
167
167
  camel/models/internlm_model.py,sha256=z6B8XXseqJ3ve3ZucT5kRVOG7GcH5Jcr6BZzeJ9NTYo,5994
168
- camel/models/litellm_model.py,sha256=xi4kDd0FKuznKtox8ArsB39u40ueOhcb-CpWv4bcbXw,5544
169
- camel/models/mistral_model.py,sha256=OB948fRVnXikVIDO3PqxV0zb_qpwwta0DIW1bbX3SYI,11666
168
+ camel/models/litellm_model.py,sha256=rlSt3EnBAAYyoIxq0_XTuRmRnc4RWvD2Z14yIrI_7uw,5942
169
+ camel/models/mistral_model.py,sha256=5FXI8wBIc_xU50NOJZh3gtn91ZNOlPVqKfGm-4aiRYQ,12179
170
170
  camel/models/model_factory.py,sha256=WS-Dm6SnU73-bAKsQexaCJL-QMMJZ1OEW-MLBAeOL6U,10897
171
171
  camel/models/model_manager.py,sha256=gfpL-WUxuTXgNeCkIVg8Y0zRvxMqRLX8JGt0XEAPQ8Y,9214
172
172
  camel/models/modelscope_model.py,sha256=U5ZrS1_6jrZe4ISUKDDHaUIPk1nJSY2z20AZnqiL7C0,7670
@@ -180,14 +180,14 @@ camel/models/openai_model.py,sha256=Ow8kHm7mL3vEYh8-5Ui0-JsPwIXjRP29HOFuf7Vfe0A,
180
180
  camel/models/openrouter_model.py,sha256=I-vqFFTRghBBR03Eox-4J7RHtHq_eaFld_SewVZgfgM,7949
181
181
  camel/models/ppio_model.py,sha256=oyQqTANwL9Ezhbb0Zzer-m5YlaOT62CDJ5byIn6KKJk,6736
182
182
  camel/models/qwen_model.py,sha256=WCIrEnZpuh37aZWzogcrDCKRRUa4EaFCClkFCx3TrOI,7456
183
- camel/models/reka_model.py,sha256=15DscZf3lbqsIzm6kzjzDrhblBt1_0xlphT4isuQMu0,10146
183
+ camel/models/reka_model.py,sha256=IWqbIEQwN0rzrCXFe85lgZQJ8mvTvcDm7ZjIaaX-36U,10586
184
184
  camel/models/samba_model.py,sha256=tfFqzvbZH3KF25zvnVyaUa3dgfMbfDfNlU-QXg9bdlw,22950
185
185
  camel/models/sglang_model.py,sha256=kdF-qShOH4j5lkuC2JEzUByuSoKtCFHdrIpAdbpR2Gg,14310
186
186
  camel/models/siliconflow_model.py,sha256=c40e0SQjHUNjr1ttJTTRTylRiNsPK_idP7Pa2iZr36g,6041
187
187
  camel/models/stub_model.py,sha256=JvjeEkXS7RMcR_UA_64a3T6S0QALUhOaMQs-aI7Etug,5955
188
188
  camel/models/togetherai_model.py,sha256=4wTLLlmoU0r5KR_8SaKUo7mtCljaw7bmA5YkCVZpZEw,9551
189
189
  camel/models/vllm_model.py,sha256=8fx9ezWGQ3R3sIUYQtWHgY0JbWXBVUj703USGhKjfd8,12278
190
- camel/models/volcano_model.py,sha256=inYDiKOfGvq8o3XW4KVQIrXiZOhXQfB4HfCHGCWHPKs,3792
190
+ camel/models/volcano_model.py,sha256=O56xeeDDGEm_EKDQH4-oPBT4JFIcxleifHO863DFUls,4163
191
191
  camel/models/yi_model.py,sha256=sg7qOzvWZlGeKmlvA4kvZSWwMxTBo0-qgvEVjBalXcE,6572
192
192
  camel/models/zhipuai_model.py,sha256=JtMOTDsJIteZBPdIAwkeyUoAoh3O0dseaqjikiwjIfM,6909
193
193
  camel/models/reward/__init__.py,sha256=MqPN6wXh7Y1SoeNoFlYaMG6xHzLG0CYsv_3kB2atIQk,984
@@ -224,13 +224,14 @@ camel/retrievers/bm25_retriever.py,sha256=feQgn3dwnbQG8H7KSbFzjaFAw3KtKObfoyA6gm
224
224
  camel/retrievers/cohere_rerank_retriever.py,sha256=tzMS3HG4wD3gbIAVcHsC5fTbFxuiNrT4qJ10oJMJ0BA,4032
225
225
  camel/retrievers/hybrid_retrival.py,sha256=2ySeXnLunoBHarqssijjxn7bAQGypAXX6QdzxYstreM,9466
226
226
  camel/retrievers/vector_retriever.py,sha256=Fp6k7FkoeUXLiUokqsMIO74Dh2mJcmJP2TrCP-6Ekcc,11051
227
- camel/runtime/__init__.py,sha256=QFxG8qYixImqSmC5bLXgT4_gkC5V8nq9dr9XlY4iZZM,1125
227
+ camel/runtime/__init__.py,sha256=aMUmX2qBmO4wCVJp4pIjx2Zed88HcrUzimfJvnz9ZZg,1207
228
228
  camel/runtime/api.py,sha256=JfkHqQ_Xs3ZNl4TXC_obV3Ymi21ltP1LAkXzBA3H_Lo,3227
229
229
  camel/runtime/base.py,sha256=KKBLO6PwWEWBXbYaVtO9JXqBT8110iYpMhgNSIxQvYQ,1512
230
230
  camel/runtime/configs.py,sha256=7swJ6shD5CAnQj16D_j1BWJjRDHLue8_BJcQ1-YiKJI,2431
231
231
  camel/runtime/docker_runtime.py,sha256=Q1eN4rWxDB4PF_G7nq64Rk7xhRZgAhNqmlxsu6YMdCg,13578
232
232
  camel/runtime/llm_guard_runtime.py,sha256=n8MImZsYLXCfr6LG6BFvlC75Al16GMJMvGp4vFsob6E,8101
233
233
  camel/runtime/remote_http_runtime.py,sha256=Emgz2xz4vbwCvErDk6Ni25aDA3EBXoPOQ7U70AgVg0w,6669
234
+ camel/runtime/ubuntu_docker_runtime.py,sha256=I6geuBMiDeX2kfpqJzY9IRLQOwUVd_iKGA90mKXtIRc,12466
234
235
  camel/runtime/utils/__init__.py,sha256=_4kT7j4gW9t5Zd_AbFa2mcHe8rpLB0tVlgAhQHxfwQQ,875
235
236
  camel/runtime/utils/function_risk_toolkit.py,sha256=0A9IN61JSziwKYB0AtCTZByXV9A3zWDRcNATG2V2dmA,2356
236
237
  camel/runtime/utils/ignore_risk_toolkit.py,sha256=kvLyF7EWEjXhlQJsmvA3JDB7An_LjtFjCaanNxOVaBE,2695
@@ -282,14 +283,14 @@ camel/terminators/token_limit_terminator.py,sha256=YWv6ZR8R9yI2Qnf_3xES5bEE_O5bb
282
283
  camel/toolkits/__init__.py,sha256=-wJqeptLP-lPSZtgEDAx8OSiCh0Av9A3iqW_KOA3HrA,4212
283
284
  camel/toolkits/arxiv_toolkit.py,sha256=Bs2-K1yfmqhEhHoQ0j00KoI8LpOd8M3ApXcvI_-ApVw,6303
284
285
  camel/toolkits/ask_news_toolkit.py,sha256=WfWaqwEo1Apbil3-Rb5y65Ws43NU4rAFWZu5VHe4los,23448
285
- camel/toolkits/audio_analysis_toolkit.py,sha256=-KH53iTzhHK-tqMlowy-HQGk9UBBOmWIUxcIFPudSDg,8599
286
+ camel/toolkits/audio_analysis_toolkit.py,sha256=dnDtQJbztVBwBpamSyCfigPw2GBnDAfi3fOPgql4Y50,8941
286
287
  camel/toolkits/base.py,sha256=4uuQ8peAvNNq-M0lOHVbIbMJiphlNCfQv7bfZ7LSKSI,2052
287
- camel/toolkits/browser_toolkit.py,sha256=QlOv1cD-QKV87Aub-7wxGOFXI5MzpCJPz9y80yqq72k,55776
288
+ camel/toolkits/browser_toolkit.py,sha256=8tWgquhspZarfkKk3O3l19DVQkcYJmf9Xn7Su_IVl3U,55839
288
289
  camel/toolkits/code_execution.py,sha256=6nI5wSBE6W8Ha05UfoPRoe7dtyszGUZ7W55_3HUgUoY,4626
289
- camel/toolkits/dalle_toolkit.py,sha256=Usmw3JiJErLQgWSB1qKq_bOACNwbUTQPFc_EsVzTrGo,5115
290
+ camel/toolkits/dalle_toolkit.py,sha256=pw5IzX9nNw8HaBllWrTYRtyQMbbCGE4f0JpZTizt8Co,5551
290
291
  camel/toolkits/dappier_toolkit.py,sha256=ewhXeeUj7e4DiTzuWDA-gHGhrLdyoZ4l9pbijvF3py0,8199
291
292
  camel/toolkits/data_commons_toolkit.py,sha256=aHZUSL1ACpnYGaf1rE2csVKTmXTmN8lMGRUBYhZ_YEk,14168
292
- camel/toolkits/excel_toolkit.py,sha256=P5CTI5kyuny-T0G4M3JuV_MjEG_rDFAu-rph1O3F37k,5955
293
+ camel/toolkits/excel_toolkit.py,sha256=SpmgLJWVFHaR8puDg4eTllGDc6SXzRt4U3QYgFTrLCM,6354
293
294
  camel/toolkits/file_write_toolkit.py,sha256=UiN5G7hX3dqSkktqvpMq0WhQQJW_fKbiPiOhUeuSWYU,14351
294
295
  camel/toolkits/function_tool.py,sha256=9I-7HHGf5TzdQDJce9xyz1tfrGZr5Os5iAopMK4p0XA,30325
295
296
  camel/toolkits/github_toolkit.py,sha256=x9QBsnZbLqAng4eGmnJrGxMSScrGzIA9yri9zAqfuwQ,12242
@@ -297,36 +298,36 @@ camel/toolkits/google_calendar_toolkit.py,sha256=E-sdgdbtNBs_CXbhht9t1dsVr4DsTr5
297
298
  camel/toolkits/google_maps_toolkit.py,sha256=WTnkURpGri9KcY5OwV7AJJHOzmpu5RNmYE1QCVqvwWM,12023
298
299
  camel/toolkits/google_scholar_toolkit.py,sha256=WQ9a0HQr0vro1Uo1m--alCUXvMmaHVKeQYqGCxXc2s8,7562
299
300
  camel/toolkits/human_toolkit.py,sha256=ZbhXPA0G3mQkcNW_jPwywReAft2pIJG0WkVXOG48s1w,2328
300
- camel/toolkits/image_analysis_toolkit.py,sha256=J0ArEFW0W8vt8JXMnFRwA1zwRjtkLE_vAMR-acv5MqE,7256
301
+ camel/toolkits/image_analysis_toolkit.py,sha256=gnbX2by7_pxPpjUEY8bOj1tV-hGC3mwqEvQRMXyZ9TM,7535
301
302
  camel/toolkits/linkedin_toolkit.py,sha256=wn4eXwYYlVA7doTna7k7WYhUqTBF83W79S-UJs_IQr0,8065
302
303
  camel/toolkits/math_toolkit.py,sha256=KdI8AJ9Dbq5cfWboAYJUYgSkmADMCO5eZ6yqYkWuiIQ,3686
303
- camel/toolkits/mcp_toolkit.py,sha256=p86I1x9UF75PRHsjBxYVm_X_Vy5lfmTMAWaDVhG8auA,18200
304
+ camel/toolkits/mcp_toolkit.py,sha256=4eweKFF3M9WOGroJCdsNBdyp8KUZJfaXLPGVYFu9kUQ,18275
304
305
  camel/toolkits/memory_toolkit.py,sha256=TeKYd5UMwgjVpuS2orb-ocFL13eUNKujvrFOruDCpm8,4436
305
306
  camel/toolkits/meshy_toolkit.py,sha256=NbgdOBD3FYLtZf-AfonIv6-Q8-8DW129jsaP1PqI2rs,7126
306
307
  camel/toolkits/mineru_toolkit.py,sha256=vRX9LholLNkpbJ6axfEN4pTG85aWb0PDmlVy3rAAXhg,6868
307
- camel/toolkits/networkx_toolkit.py,sha256=cCGm8kmQ2t1D0Oi9dcC4SexY9UMyqQ5jS95dA9TDLS8,8570
308
+ camel/toolkits/networkx_toolkit.py,sha256=C7pUCZTzzGkFyqdkrmhRKpAHmHWfLKeuzYHC_BHPtbk,8826
308
309
  camel/toolkits/notion_toolkit.py,sha256=jmmVWk_WazRNWnx4r9DAvhFTAL-n_ige0tb32UHJ_ik,9752
309
310
  camel/toolkits/open_api_toolkit.py,sha256=Venfq8JwTMQfzRzzB7AYmYUMEX35hW0BjIv_ozFMiNk,23316
310
- camel/toolkits/openai_agent_toolkit.py,sha256=tFaxRhtpi4Vjag3ydNVN5obb0CKGeqJzf9qqzKRIC9I,4467
311
+ camel/toolkits/openai_agent_toolkit.py,sha256=hT2ancdQigngAiY1LNnGJzZeiBDHUxrRGv6BdZTJizc,4696
311
312
  camel/toolkits/openbb_toolkit.py,sha256=8yBZL9E2iSgskosBQhD3pTP56oV6gerWpFjIJc_2UMo,28935
312
313
  camel/toolkits/page_script.js,sha256=gypbuQ_gn_oa3rQDoCN_q-kJ0jND1eSvY-30PufPZmQ,12613
313
314
  camel/toolkits/pubmed_toolkit.py,sha256=VGl8KeyWi7pjb2kEhFBLmpBlP9ezv8JyWRHtEVTQ6nQ,12227
314
315
  camel/toolkits/reddit_toolkit.py,sha256=x0XAT1zQJVNHUr1R1HwWCgIlkamU-kPmbfb_H1WIv-w,8036
315
316
  camel/toolkits/retrieval_toolkit.py,sha256=BKjEyOqW3cGEPTS5yHPYb-Qg795iNNPIs1wjowfuq3U,3825
316
317
  camel/toolkits/search_toolkit.py,sha256=7phtlC_5bmo8pFSUwGKiwNqKJuIpCvy1tdhrqIzpC0M,43767
317
- camel/toolkits/searxng_toolkit.py,sha256=h92gfk_0csRds68jrtQTaamy_EJK_lOeWxbL_FJQyAU,7365
318
+ camel/toolkits/searxng_toolkit.py,sha256=a2GtE4FGSrmaIVvX6Yide-abBYD1wsHqitnDlx9fdVg,7664
318
319
  camel/toolkits/semantic_scholar_toolkit.py,sha256=Rh7eA_YPxV5pvPIzhjjvpr3vtlaCniJicrqzkPWW9_I,11634
319
- camel/toolkits/slack_toolkit.py,sha256=F1Xn2_Jmnv-1SdBnCNg3MI3RGwjZ7ZDWiNZjFJJS6x8,10791
320
+ camel/toolkits/slack_toolkit.py,sha256=Nb3w-TbUmnUWEvHE9Hbf_wkpSepm_zKQj7m19UyoFio,11194
320
321
  camel/toolkits/stripe_toolkit.py,sha256=07swo5znGTnorafC1uYLKB4NRcJIOPOx19J7tkpLYWk,10102
321
322
  camel/toolkits/sympy_toolkit.py,sha256=dkzGp7C7Oy-qP1rVziEk_ZOPRb37d5LoI7JKCLiTEo4,33758
322
323
  camel/toolkits/terminal_toolkit.py,sha256=gupuTvNkwnFzcFwDB_irSJ9-dXRr8yEAsYq5ChEkkHg,37230
323
324
  camel/toolkits/thinking_toolkit.py,sha256=NyA6rDFG-WbCNt7NFODBTpqOIDtP6he6GhnZpPlA2To,8001
324
325
  camel/toolkits/twitter_toolkit.py,sha256=j14Hxpt4XTEOF6dWpGm6Ot_vkYT7WOiLrUa1d2JT05U,15850
325
- camel/toolkits/video_analysis_toolkit.py,sha256=EqZnut9p0W5bgF1YpdGoaRJFDLHM2Ls8i9ApTQz44tA,15088
326
+ camel/toolkits/video_analysis_toolkit.py,sha256=WUbZCuU9Fh5SCwUIep1rToWqp61bi8dXEn304oZgW9c,15340
326
327
  camel/toolkits/video_download_toolkit.py,sha256=DhAdGWdHHX_cu3a6IVSgyPnEzjTHQYAFQMAAN4yZwUw,7128
327
- camel/toolkits/weather_toolkit.py,sha256=uUD5GgmC4r1SvGlCT-RAPH0f-cJtCbcL0QGMZB_chLI,7012
328
+ camel/toolkits/weather_toolkit.py,sha256=fs9x9aC38Wsvni6A4PPpbRX6-aBnZiqs2Jix39yoULU,7413
328
329
  camel/toolkits/whatsapp_toolkit.py,sha256=udUQXkXyeWsmrUlOJZsGBhHtc_jhB05Axe_TchhibsU,5760
329
- camel/toolkits/zapier_toolkit.py,sha256=vokFqDBTwQfsP2EC1N38UEZQtaGjLkoIq49YOmkKYlE,6878
330
+ camel/toolkits/zapier_toolkit.py,sha256=A83y1UcfuopH7Fx82pORzypl1StbhBjB2HhyOqYa300,7124
330
331
  camel/toolkits/open_api_specs/security_config.py,sha256=ZVnBa_zEifaE_ao2xsvV5majuJHpn2Tn7feMDOnj-eo,898
331
332
  camel/toolkits/open_api_specs/biztoc/__init__.py,sha256=OKCZrQCDwaWtXIN_2rA9FSqEvgpQRieRoHh7Ek6N16A,702
332
333
  camel/toolkits/open_api_specs/biztoc/ai-plugin.json,sha256=IJinQbLv5MFPGFwdN7PbOhwArFVExSEZdJspe-mOBIo,866
@@ -353,7 +354,7 @@ camel/toolkits/open_api_specs/web_scraper/openapi.yaml,sha256=u_WalQ01e8W1D27VnZ
353
354
  camel/toolkits/open_api_specs/web_scraper/paths/__init__.py,sha256=OKCZrQCDwaWtXIN_2rA9FSqEvgpQRieRoHh7Ek6N16A,702
354
355
  camel/toolkits/open_api_specs/web_scraper/paths/scraper.py,sha256=aWy1_ppV4NVVEZfnbN3tu9XA9yAPAC9bRStJ5JuXMRU,1117
355
356
  camel/types/__init__.py,sha256=VLWhAt857IFct3XepY5BNOIhyhDhfmODTezr9jhO_TI,2251
356
- camel/types/enums.py,sha256=Hghw2BEWS3t8Fv8P0ADg7JnyVMeK8yxgWU3z1JGPF54,42288
357
+ camel/types/enums.py,sha256=G9KcZe_-f9G12DCz5fxPw2bBxI9eNnJnluirBYAKNk0,42619
357
358
  camel/types/openai_types.py,sha256=8ZFzLe-zGmKNPfuVZFzxlxAX98lGf18gtrPhOgMmzus,2104
358
359
  camel/types/unified_model_type.py,sha256=Mb6IOoom9C6Omksl48alJ4rYpR20__qgO7Omt6aosQI,4671
359
360
  camel/types/agents/__init__.py,sha256=cbvVkogPoZgcwZrgxLH6EtpGXk0kavF79nOic0Dc1vg,786
@@ -371,11 +372,11 @@ camel/utils/chunker/base.py,sha256=9CuqymFCRncyAdEST-IcRonB732YAPhusznqH-RES3E,9
371
372
  camel/utils/chunker/code_chunker.py,sha256=9h4rd39H9ngbOWAjd_12xt-EzVMh0e_fZnC4my8h_Jg,6823
372
373
  camel/utils/chunker/uio_chunker.py,sha256=ZvY4w50F3tE9k5ope52MEUrKv07VgjMpZ7u5CP6_OX8,2662
373
374
  camel/verifiers/__init__.py,sha256=bPIdYDVbZxY6szYuXh70Ng_A9kemhcqJDO_gj9Dn17w,961
374
- camel/verifiers/base.py,sha256=SQGZPP6p08q4Qmpr1vD-eb0UxBwkl1hpZSm19yV2wWo,14866
375
+ camel/verifiers/base.py,sha256=luvvEMCO_yH54zIUslPrcTDUFzrXU5ODn_1Ij054B3E,15523
375
376
  camel/verifiers/math_verifier.py,sha256=tA1D4S0sm8nsWISevxSN0hvSVtIUpqmJhzqfbuMo0y4,6875
376
377
  camel/verifiers/models.py,sha256=GdxYPr7UxNrR1577yW4kyroRcLGfd-H1GXgv8potDWU,2471
377
378
  camel/verifiers/python_verifier.py,sha256=qvNNYTlFyOMbIaDF2JNWELiIfj_phdV2JWRxPrghpT0,21528
378
- camel_ai-0.2.44.dist-info/METADATA,sha256=4mOoHcQgfILBlj1qh1AD5z2l_sLzPnAOpnHgYscRyZs,42902
379
- camel_ai-0.2.44.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
380
- camel_ai-0.2.44.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
381
- camel_ai-0.2.44.dist-info/RECORD,,
379
+ camel_ai-0.2.45.dist-info/METADATA,sha256=5FftSspcxfJ8fwvHDLzfWv9wpuJWOcD_FYPJzlgNytI,42916
380
+ camel_ai-0.2.45.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
381
+ camel_ai-0.2.45.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
382
+ camel_ai-0.2.45.dist-info/RECORD,,