camel-ai 0.2.50__py3-none-any.whl → 0.2.52__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.50'
17
+ __version__ = '0.2.52'
18
18
 
19
19
  __all__ = [
20
20
  '__version__',
@@ -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 random
16
17
  from typing import Any, Dict, List, Optional, Tuple, Union
17
18
 
@@ -58,6 +59,7 @@ class SingleStepEnv:
58
59
  self,
59
60
  dataset: Union[StaticDataset, BaseGenerator],
60
61
  verifier: BaseVerifier,
62
+ timeout: Optional[float] = 180.0,
61
63
  **kwargs,
62
64
  ) -> None:
63
65
  r"""Initialize the SingleStepEnv.
@@ -67,12 +69,15 @@ class SingleStepEnv:
67
69
  problems from.
68
70
  verifier (BaseVerifier): Verifier used to evaluate LLM responses
69
71
  against ground-truth answers.
72
+ timeout (Optional[float], optional): The execution timeout in
73
+ seconds. (default: :obj:`180.0`)
70
74
  **kwargs: Optional metadata or configuration values.
71
75
 
72
76
  Notes:
73
77
  This class assumes all interactions are single-step: one question,
74
78
  one LLM response, one reward.
75
79
  """
80
+ self._timeout = timeout
76
81
  self.dataset = dataset
77
82
  self.verifier = verifier
78
83
  self._metadata = kwargs
@@ -279,6 +284,7 @@ class SingleStepEnv:
279
284
  or if `reset()` has not been called.
280
285
  ValueError: If invalid action format, duplicate indices,
281
286
  or out-of-bounds indices are detected.
287
+ asyncio.TimeoutError: If the step execution exceeds the timeout.
282
288
  """
283
289
 
284
290
  if not self._is_setup:
@@ -307,18 +313,34 @@ class SingleStepEnv:
307
313
  f"total batch size ({self.current_batch_size})"
308
314
  )
309
315
 
310
- indices = [act.index for act in actions]
311
316
  proposed_solutions = [act.llm_response for act in actions]
312
- ground_truths: List[str] = []
313
- for idx in indices:
314
- ground_truths.append(self._states[idx].final_answer)
317
+ ground_truths: List[str] = [
318
+ self._states[idx].final_answer for idx in indices
319
+ ]
315
320
 
316
321
  try:
317
- verification_results = await self.verifier.verify_batch(
318
- solutions=proposed_solutions,
319
- reference_answers=ground_truths, # type: ignore [arg-type]
320
- raise_on_error=True,
322
+ verification_results = await asyncio.wait_for(
323
+ self.verifier.verify_batch(
324
+ solutions=proposed_solutions,
325
+ reference_answers=ground_truths, # type: ignore [arg-type]
326
+ raise_on_error=True,
327
+ ),
328
+ timeout=self._timeout,
329
+ )
330
+ except asyncio.TimeoutError as e:
331
+ logger.error(
332
+ f"Step verification timed out after {self._timeout}s: {e}"
321
333
  )
334
+ # Return timeout verification results
335
+ verification_results = [
336
+ VerificationResult(
337
+ result="",
338
+ status=VerificationOutcome.TIMEOUT,
339
+ error_message=f"Verification timed out "
340
+ f"after {self._timeout}s",
341
+ )
342
+ for _ in range(len(proposed_solutions))
343
+ ]
322
344
  except Exception as e:
323
345
  logger.error(f"Verification failed: {e}")
324
346
  # Return failed verification results with status=FAILURE
@@ -331,9 +353,55 @@ class SingleStepEnv:
331
353
  for _ in range(len(proposed_solutions))
332
354
  ]
333
355
 
334
- total_rewards, rewards_dicts = await self._compute_reward_batch(
335
- proposed_solutions, verification_results
336
- )
356
+ # Track which solutions have been processed and which have timed out
357
+ total_rewards = [0.0] * len(proposed_solutions)
358
+ rewards_dicts = [{"correctness": 0.0}] * len(proposed_solutions)
359
+
360
+ try:
361
+ # First try to compute all rewards with a timeout
362
+ computed_rewards, computed_rewards_dicts = await asyncio.wait_for(
363
+ self._compute_reward_batch(
364
+ proposed_solutions, verification_results
365
+ ),
366
+ timeout=self._timeout,
367
+ )
368
+ # If successful, use all the computed values
369
+ total_rewards = computed_rewards
370
+ rewards_dicts = computed_rewards_dicts
371
+ except asyncio.TimeoutError as e:
372
+ logger.error(
373
+ f"Reward computation timed out after {self._timeout}s: {e}"
374
+ )
375
+ # Try to compute rewards one by one to identify which ones time out
376
+ for i, (solution, result) in enumerate(
377
+ zip(proposed_solutions, verification_results)
378
+ ):
379
+ try:
380
+ individual_rewards = await asyncio.wait_for(
381
+ self._compute_custom_reward(solution, result),
382
+ timeout=self._timeout,
383
+ )
384
+ # If successful, calculate the reward for this solution
385
+ correctness_reward = (
386
+ self.ACCURACY_REWARD if result.status else 0.0
387
+ )
388
+ rewards_dict = {
389
+ "correctness": correctness_reward,
390
+ **individual_rewards,
391
+ }
392
+ total_rewards[i] = sum(rewards_dict.values())
393
+ rewards_dicts[i] = rewards_dict
394
+ except asyncio.TimeoutError:
395
+ logger.warning(
396
+ f"Reward computation for solution {i} timed out"
397
+ )
398
+ except Exception as e:
399
+ logger.warning(
400
+ f"Error computing reward for solution {i}: {e}"
401
+ )
402
+ except Exception as e:
403
+ logger.error(f"Reward computation failed: {e}")
404
+
337
405
  # Create and return step results in batch
338
406
  step_results = [
339
407
  StepResult(
@@ -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 Any, Dict, List, Optional, Type, Union
15
+ from typing import Any, Callable, Dict, List, Optional, Type, Union
16
16
 
17
17
  from openai import AsyncAzureOpenAI, AsyncStream, AzureOpenAI, Stream
18
18
  from pydantic import BaseModel
@@ -27,6 +27,8 @@ from camel.types import (
27
27
  )
28
28
  from camel.utils import BaseTokenCounter, OpenAITokenCounter
29
29
 
30
+ AzureADTokenProvider = Callable[[], str]
31
+
30
32
 
31
33
  class AzureOpenAIModel(BaseModelBackend):
32
34
  r"""Azure OpenAI API in a unified BaseModelBackend interface.
@@ -46,6 +48,12 @@ class AzureOpenAIModel(BaseModelBackend):
46
48
  (default: :obj:`None`)
47
49
  azure_deployment_name (Optional[str], optional): The deployment name
48
50
  you chose when you deployed an azure model. (default: :obj:`None`)
51
+ azure_ad_token (Optional[str], optional): Your Azure Active Directory
52
+ token, https://www.microsoft.com/en-us/security/business/
53
+ identity-access/microsoft-entra-id. (default: :obj:`None`)
54
+ azure_ad_token_provider (Optional[AzureADTokenProvider], optional): A
55
+ function that returns an Azure Active Directory token, will be
56
+ invoked on every request. (default: :obj:`None`)
49
57
  token_counter (Optional[BaseTokenCounter], optional): Token counter to
50
58
  use for the model. If not provided, :obj:`OpenAITokenCounter`
51
59
  will be used. (default: :obj:`None`)
@@ -68,6 +76,8 @@ class AzureOpenAIModel(BaseModelBackend):
68
76
  token_counter: Optional[BaseTokenCounter] = None,
69
77
  api_version: Optional[str] = None,
70
78
  azure_deployment_name: Optional[str] = None,
79
+ azure_ad_token_provider: Optional["AzureADTokenProvider"] = None,
80
+ azure_ad_token: Optional[str] = None,
71
81
  ) -> None:
72
82
  if model_config_dict is None:
73
83
  model_config_dict = ChatGPTConfig().as_dict()
@@ -79,15 +89,19 @@ class AzureOpenAIModel(BaseModelBackend):
79
89
  )
80
90
 
81
91
  self.api_version = api_version or os.environ.get("AZURE_API_VERSION")
82
- self.azure_deployment_name = azure_deployment_name or os.environ.get(
92
+ self._azure_deployment_name = azure_deployment_name or os.environ.get(
83
93
  "AZURE_DEPLOYMENT_NAME"
84
94
  )
95
+ self._azure_ad_token = azure_ad_token or os.environ.get(
96
+ "AZURE_AD_TOKEN"
97
+ )
98
+ self.azure_ad_token_provider = azure_ad_token_provider
85
99
  if self.api_version is None:
86
100
  raise ValueError(
87
101
  "Must provide either the `api_version` argument "
88
102
  "or `AZURE_API_VERSION` environment variable."
89
103
  )
90
- if self.azure_deployment_name is None:
104
+ if self._azure_deployment_name is None:
91
105
  raise ValueError(
92
106
  "Must provide either the `azure_deployment_name` argument "
93
107
  "or `AZURE_DEPLOYMENT_NAME` environment variable."
@@ -95,18 +109,22 @@ class AzureOpenAIModel(BaseModelBackend):
95
109
 
96
110
  self._client = AzureOpenAI(
97
111
  azure_endpoint=str(self._url),
98
- azure_deployment=self.azure_deployment_name,
112
+ azure_deployment=self._azure_deployment_name,
99
113
  api_version=self.api_version,
100
114
  api_key=self._api_key,
115
+ azure_ad_token=self._azure_ad_token,
116
+ azure_ad_token_provider=self.azure_ad_token_provider,
101
117
  timeout=self._timeout,
102
118
  max_retries=3,
103
119
  )
104
120
 
105
121
  self._async_client = AsyncAzureOpenAI(
106
122
  azure_endpoint=str(self._url),
107
- azure_deployment=self.azure_deployment_name,
123
+ azure_deployment=self._azure_deployment_name,
108
124
  api_version=self.api_version,
109
125
  api_key=self._api_key,
126
+ azure_ad_token=self._azure_ad_token,
127
+ azure_ad_token_provider=self.azure_ad_token_provider,
110
128
  timeout=self._timeout,
111
129
  max_retries=3,
112
130
  )
@@ -193,7 +211,7 @@ class AzureOpenAIModel(BaseModelBackend):
193
211
 
194
212
  return self._client.chat.completions.create(
195
213
  messages=messages,
196
- model=self.azure_deployment_name, # type:ignore[arg-type]
214
+ model=self._azure_deployment_name, # type:ignore[arg-type]
197
215
  **request_config,
198
216
  )
199
217
 
@@ -209,7 +227,7 @@ class AzureOpenAIModel(BaseModelBackend):
209
227
 
210
228
  return await self._async_client.chat.completions.create(
211
229
  messages=messages,
212
- model=self.azure_deployment_name, # type:ignore[arg-type]
230
+ model=self._azure_deployment_name, # type:ignore[arg-type]
213
231
  **request_config,
214
232
  )
215
233
 
@@ -232,7 +250,7 @@ class AzureOpenAIModel(BaseModelBackend):
232
250
 
233
251
  return self._client.beta.chat.completions.parse(
234
252
  messages=messages,
235
- model=self.azure_deployment_name, # type:ignore[arg-type]
253
+ model=self._azure_deployment_name, # type:ignore[arg-type]
236
254
  **request_config,
237
255
  )
238
256
 
@@ -255,7 +273,7 @@ class AzureOpenAIModel(BaseModelBackend):
255
273
 
256
274
  return await self._async_client.beta.chat.completions.parse(
257
275
  messages=messages,
258
- model=self.azure_deployment_name, # type:ignore[arg-type]
276
+ model=self._azure_deployment_name, # type:ignore[arg-type]
259
277
  **request_config,
260
278
  )
261
279
 
@@ -16,10 +16,13 @@ import subprocess
16
16
  from typing import Any, Dict, Optional, Union
17
17
 
18
18
  from camel.configs import OLLAMA_API_PARAMS, OllamaConfig
19
+ from camel.logger import get_logger
19
20
  from camel.models.openai_compatible_model import OpenAICompatibleModel
20
21
  from camel.types import ModelType
21
22
  from camel.utils import BaseTokenCounter
22
23
 
24
+ logger = get_logger(__name__)
25
+
23
26
 
24
27
  class OllamaModel(OpenAICompatibleModel):
25
28
  r"""Ollama service interface.
@@ -60,20 +63,22 @@ class OllamaModel(OpenAICompatibleModel):
60
63
  ) -> None:
61
64
  if model_config_dict is None:
62
65
  model_config_dict = OllamaConfig().as_dict()
63
- url = url or os.environ.get("OLLAMA_BASE_URL")
66
+ self._url = url or os.environ.get("OLLAMA_BASE_URL")
64
67
  timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
68
+ self._model_type = model_type
69
+
70
+ if not self._url:
71
+ self._start_server()
72
+
65
73
  super().__init__(
66
- model_type=model_type,
74
+ model_type=self._model_type,
67
75
  model_config_dict=model_config_dict,
68
- api_key=api_key,
69
- url=url,
76
+ api_key="Not_Used",
77
+ url=self._url,
70
78
  token_counter=token_counter,
71
79
  timeout=timeout,
72
80
  )
73
81
 
74
- if not self._url:
75
- self._start_server()
76
-
77
82
  def _start_server(self) -> None:
78
83
  r"""Starts the Ollama server in a subprocess."""
79
84
  try:
@@ -83,12 +88,12 @@ class OllamaModel(OpenAICompatibleModel):
83
88
  stderr=subprocess.PIPE,
84
89
  )
85
90
  self._url = "http://localhost:11434/v1"
86
- print(
91
+ logger.info(
87
92
  f"Ollama server started on {self._url} "
88
- f"for {self.model_type} model."
93
+ f"for {self._model_type} model."
89
94
  )
90
95
  except Exception as e:
91
- print(f"Failed to start Ollama server: {e}.")
96
+ logger.error(f"Failed to start Ollama server: {e}.")
92
97
 
93
98
  def check_model_config(self):
94
99
  r"""Check whether the model configuration contains any
@@ -16,10 +16,13 @@ import subprocess
16
16
  from typing import Any, Dict, Optional, Union
17
17
 
18
18
  from camel.configs import VLLM_API_PARAMS, VLLMConfig
19
+ from camel.logger import get_logger
19
20
  from camel.models.openai_compatible_model import OpenAICompatibleModel
20
21
  from camel.types import ModelType
21
22
  from camel.utils import BaseTokenCounter
22
23
 
24
+ logger = get_logger(__name__)
25
+
23
26
 
24
27
  # flake8: noqa: E501
25
28
  class VLLMModel(OpenAICompatibleModel):
@@ -62,18 +65,21 @@ class VLLMModel(OpenAICompatibleModel):
62
65
  ) -> None:
63
66
  if model_config_dict is None:
64
67
  model_config_dict = VLLMConfig().as_dict()
65
- url = url or os.environ.get("VLLM_BASE_URL")
68
+ self._url = url or os.environ.get("VLLM_BASE_URL")
66
69
  timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
70
+ self._model_type = model_type
71
+
72
+ if not self._url:
73
+ self._start_server()
74
+
67
75
  super().__init__(
68
- model_type=model_type,
76
+ model_type=self._model_type,
69
77
  model_config_dict=model_config_dict,
70
- api_key=api_key,
71
- url=url,
78
+ api_key="Not_Used",
79
+ url=self._url,
72
80
  token_counter=token_counter,
73
81
  timeout=timeout,
74
82
  )
75
- if not self._url:
76
- self._start_server()
77
83
 
78
84
  def _start_server(self) -> None:
79
85
  r"""Starts the vllm server in a subprocess."""
@@ -84,12 +90,12 @@ class VLLMModel(OpenAICompatibleModel):
84
90
  stderr=subprocess.PIPE,
85
91
  )
86
92
  self._url = "http://localhost:8000/v1"
87
- print(
93
+ logger.info(
88
94
  f"vllm server started on {self._url} "
89
- f"for {self.model_type} model."
95
+ f"for {self._model_type} model."
90
96
  )
91
97
  except Exception as e:
92
- print(f"Failed to start vllm server: {e}.")
98
+ logger.error(f"Failed to start vllm server: {e}.")
93
99
 
94
100
  def check_model_config(self):
95
101
  r"""Check whether the model configuration contains any
camel/runtime/__init__.py CHANGED
@@ -13,6 +13,7 @@
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
  from .base import BaseRuntime
15
15
  from .configs import TaskConfig
16
+ from .daytona_runtime import DaytonaRuntime
16
17
  from .docker_runtime import DockerRuntime
17
18
  from .llm_guard_runtime import LLMGuardRuntime
18
19
  from .remote_http_runtime import RemoteHttpRuntime
@@ -28,4 +29,5 @@ __all__ = [
28
29
  "LLMGuardRuntime",
29
30
  "TaskConfig",
30
31
  "UbuntuDockerRuntime",
32
+ "DaytonaRuntime",
31
33
  ]
@@ -0,0 +1,248 @@
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 inspect
16
+ import json
17
+ import os
18
+ from functools import wraps
19
+ from typing import Any, Dict, List, Optional, Union
20
+
21
+ from pydantic import BaseModel
22
+
23
+ from camel.logger import get_logger
24
+ from camel.runtime import BaseRuntime
25
+ from camel.toolkits.function_tool import FunctionTool
26
+
27
+ logger = get_logger(__name__)
28
+
29
+
30
+ class DaytonaRuntime(BaseRuntime):
31
+ r"""A runtime that executes functions in a Daytona sandbox environment.
32
+ Requires the Daytona server to be running and an API key configured.
33
+
34
+ Args:
35
+ api_key (Optional[str]): The Daytona API key for authentication. If not
36
+ provided, it will try to use the DAYTONA_API_KEY environment
37
+ variable. (default: :obj: `None`)
38
+ api_url (Optional[str]): The URL of the Daytona server. If not
39
+ provided, it will try to use the DAYTONA_API_URL environment
40
+ variable. If none is provided, it will use "http://localhost:8000".
41
+ (default: :obj: `None`)
42
+ language (Optional[str]): The programming language for the sandbox.
43
+ (default: :obj: `"python"`)
44
+ """
45
+
46
+ def __init__(
47
+ self,
48
+ api_key: Optional[str] = None,
49
+ api_url: Optional[str] = None,
50
+ language: Optional[str] = "python",
51
+ ):
52
+ from daytona_sdk import Daytona, DaytonaConfig
53
+
54
+ super().__init__()
55
+ self.api_key = api_key or os.environ.get('DAYTONA_API_KEY')
56
+ self.api_url = api_url or os.environ.get('DAYTONA_API_URL')
57
+ self.language = language
58
+ self.config = DaytonaConfig(api_key=self.api_key, api_url=self.api_url)
59
+ self.daytona = Daytona(self.config)
60
+ self.sandbox = None
61
+ self.entrypoint: Dict[str, str] = dict()
62
+
63
+ def build(self) -> "DaytonaRuntime":
64
+ r"""Create and start a Daytona sandbox.
65
+
66
+ Returns:
67
+ DaytonaRuntime: The current runtime.
68
+ """
69
+ from daytona_sdk import CreateSandboxParams
70
+
71
+ try:
72
+ params = CreateSandboxParams(language=self.language)
73
+ self.sandbox = self.daytona.create(params)
74
+ if self.sandbox is None:
75
+ raise RuntimeError("Failed to create sandbox.")
76
+ logger.info(f"Sandbox created with ID: {self.sandbox.id}")
77
+ except Exception as e:
78
+ logger.error(f"Failed to create sandbox: {e!s}")
79
+ raise RuntimeError(f"Daytona sandbox creation failed: {e!s}")
80
+ return self
81
+
82
+ def _cleanup(self):
83
+ r"""Clean up the sandbox when exiting."""
84
+ if self.sandbox:
85
+ try:
86
+ self.daytona.remove(self.sandbox)
87
+ logger.info(f"Sandbox {self.sandbox.id} removed")
88
+ self.sandbox = None
89
+ except Exception as e:
90
+ logger.error(f"Failed to remove sandbox: {e!s}")
91
+
92
+ def add(
93
+ self,
94
+ funcs: Union[FunctionTool, List[FunctionTool]],
95
+ entrypoint: str,
96
+ arguments: Optional[Dict[str, Any]] = None,
97
+ ) -> "DaytonaRuntime":
98
+ r"""Add a function or list of functions to the runtime.
99
+
100
+ Args:
101
+ funcs (Union[FunctionTool, List[FunctionTool]]): The function or
102
+ list of functions to add.
103
+ entrypoint (str): The entrypoint for the function.
104
+ arguments (Optional[Dict[str, Any]]): The arguments for the
105
+ function. (default: :obj: `None`)
106
+
107
+ Returns:
108
+ DaytonaRuntime: The current runtime.
109
+ """
110
+ if not isinstance(funcs, list):
111
+ funcs = [funcs]
112
+ if arguments is not None:
113
+ entrypoint += json.dumps(arguments, ensure_ascii=False)
114
+
115
+ def make_wrapper(inner_func, func_name, func_code):
116
+ r"""Creates a wrapper for a function to execute it in the
117
+ Daytona sandbox.
118
+
119
+ Args:
120
+ inner_func (Callable): The function to wrap.
121
+ func_name (str): The name of the function.
122
+ func_code (str): The source code of the function.
123
+
124
+ Returns:
125
+ Callable: A wrapped function that executes in the sandbox.
126
+ """
127
+
128
+ @wraps(inner_func)
129
+ def wrapper(*args, **kwargs):
130
+ if not self.sandbox:
131
+ raise RuntimeError(
132
+ "Sandbox not initialized. Call build() first."
133
+ )
134
+
135
+ try:
136
+ for key, value in kwargs.items():
137
+ if isinstance(value, BaseModel):
138
+ kwargs[key] = value.model_dump()
139
+ args_str = json.dumps(args, ensure_ascii=True)
140
+ kwargs_str = json.dumps(kwargs, ensure_ascii=True)
141
+ except (TypeError, ValueError) as e:
142
+ logger.error(f"Failed to serialize arguments: {e!s}")
143
+ return {"error": f"Argument serialization failed: {e!s}"}
144
+
145
+ # Upload function code to the sandbox
146
+ script_path = f"/home/daytona/{func_name}.py"
147
+ try:
148
+ self.sandbox.fs.upload_file(
149
+ script_path, func_code.encode()
150
+ )
151
+ except Exception as e:
152
+ logger.error(
153
+ f"Failed to upload function {func_name}: {e!s}"
154
+ )
155
+ return {"error": f"Upload failed: {e!s}"}
156
+
157
+ exec_code = (
158
+ f"import sys\n"
159
+ f"sys.path.append('/home/daytona')\n"
160
+ f"import json\n"
161
+ f"from {func_name} import {func_name}\n"
162
+ f"args = json.loads('{args_str}')\n"
163
+ f"kwargs = json.loads('{kwargs_str}')\n"
164
+ f"result = {func_name}(*args, **kwargs)\n"
165
+ f"print(json.dumps(result) if result is not "
166
+ f"None else 'null')"
167
+ )
168
+
169
+ # Execute the function in the sandbox
170
+ try:
171
+ response = self.sandbox.process.code_run(exec_code)
172
+ return (
173
+ json.loads(response.result)
174
+ if response.result
175
+ else None
176
+ )
177
+ except json.JSONDecodeError as e:
178
+ logger.error(
179
+ f"Failed to decode JSON response for {func_name}"
180
+ )
181
+ return {"error": f"JSON decoding failed: {e!s}"}
182
+ except Exception as e:
183
+ logger.error(
184
+ f"Failed to execute function {func_name}: {e!s}"
185
+ )
186
+ return {"error": f"Execution failed: {e!s}"}
187
+
188
+ return wrapper
189
+
190
+ for func in funcs:
191
+ inner_func = func.func
192
+ func_name = func.get_function_name()
193
+ func_code = inspect.getsource(inner_func).strip()
194
+
195
+ func.func = make_wrapper(inner_func, func_name, func_code)
196
+ self.tools_map[func_name] = func
197
+ self.entrypoint[func_name] = entrypoint
198
+
199
+ return self
200
+
201
+ def info(self) -> str:
202
+ r"""Get information about the current sandbox.
203
+
204
+ Returns:
205
+ str: Information about the sandbox.
206
+
207
+ Raises:
208
+ RuntimeError: If the sandbox is not initialized.
209
+ """
210
+ if self.sandbox is None:
211
+ raise RuntimeError("Failed to create sandbox.")
212
+ info = self.sandbox.info()
213
+ return (
214
+ f"Sandbox {info.name}:\n"
215
+ f"State: {info.state}\n"
216
+ f"Resources: {info.resources.cpu} CPU, {info.resources.memory} RAM"
217
+ )
218
+
219
+ def __del__(self):
220
+ r"""Clean up the sandbox when the object is deleted."""
221
+ if hasattr(self, 'sandbox'):
222
+ self._cleanup()
223
+
224
+ def stop(self) -> "DaytonaRuntime":
225
+ r"""Stop and remove the sandbox.
226
+
227
+ Returns:
228
+ DaytonaRuntime: The current runtime.
229
+ """
230
+ self._cleanup()
231
+ return self
232
+
233
+ def reset(self) -> "DaytonaRuntime":
234
+ r"""Reset the sandbox by stopping and rebuilding it.
235
+
236
+ Returns:
237
+ DaytonaRuntime: The current runtime.
238
+ """
239
+ return self.stop().build()
240
+
241
+ @property
242
+ def docs(self) -> str:
243
+ r"""Get the URL for the Daytona API documentation.
244
+
245
+ Returns:
246
+ str: The URL for the API documentation.
247
+ """
248
+ return "https://www.daytona.io/docs/python-sdk/daytona/"
@@ -68,6 +68,7 @@ from .pyautogui_toolkit import PyAutoGUIToolkit
68
68
  from .openai_agent_toolkit import OpenAIAgentToolkit
69
69
  from .searxng_toolkit import SearxNGToolkit
70
70
  from .jina_reranker_toolkit import JinaRerankerToolkit
71
+ from .klavis_toolkit import KlavisToolkit
71
72
 
72
73
 
73
74
  __all__ = [
@@ -124,4 +125,5 @@ __all__ = [
124
125
  'OpenAIAgentToolkit',
125
126
  'SearxNGToolkit',
126
127
  'JinaRerankerToolkit',
128
+ 'KlavisToolkit',
127
129
  ]
@@ -0,0 +1,228 @@
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
+ import requests
19
+
20
+ from camel.logger import get_logger
21
+ from camel.toolkits.base import BaseToolkit
22
+ from camel.toolkits.function_tool import FunctionTool
23
+ from camel.utils import MCPServer, api_keys_required, dependencies_required
24
+
25
+ logger = get_logger(__name__)
26
+
27
+
28
+ @MCPServer()
29
+ class KlavisToolkit(BaseToolkit):
30
+ r"""A class representing a toolkit for interacting with Klavis API.
31
+
32
+ This class provides methods for interacting with Klavis MCP server
33
+ instances, retrieving server information, managing tools, and handling
34
+ authentication.
35
+
36
+ Attributes:
37
+ api_key (str): The API key for authenticating with Klavis API.
38
+ base_url (str): The base URL for Klavis API endpoints.
39
+ timeout (Optional[float]): The timeout value for API requests
40
+ in seconds. If None, no timeout is applied.
41
+ (default: :obj:`None`)
42
+ """
43
+
44
+ @dependencies_required("requests")
45
+ @api_keys_required(
46
+ [
47
+ (None, "KLAVIS_API_KEY"),
48
+ ]
49
+ )
50
+ def __init__(self, timeout: Optional[float] = None) -> None:
51
+ r"""Initialize the KlavisToolkit with API client. The API key is
52
+ retrieved from environment variables.
53
+ """
54
+ super().__init__(timeout=timeout)
55
+ self.api_key = os.environ.get("KLAVIS_API_KEY")
56
+ self.base_url = "https://api.klavis.ai"
57
+
58
+ def _request(
59
+ self,
60
+ method: str,
61
+ endpoint: str,
62
+ payload: Optional[Dict[str, Any]] = None,
63
+ additional_headers: Optional[Dict[str, str]] = None,
64
+ ) -> Dict[str, Any]:
65
+ r"""Make an HTTP request to the Klavis API.
66
+
67
+ Args:
68
+ method (str): HTTP method (e.g., 'GET', 'POST', 'DELETE').
69
+ endpoint (str): API endpoint path.
70
+ payload (Optional[Dict[str, Any]]): JSON payload for POST
71
+ requests.
72
+ additional_headers (Optional[Dict[str, str]]): Additional
73
+ headers to include in the request.
74
+
75
+ Returns:
76
+ Dict[str, Any]: The JSON response from the API or an error
77
+ dict.
78
+ """
79
+ url = f"{self.base_url}{endpoint}"
80
+ headers = {
81
+ 'accept': 'application/json',
82
+ 'Authorization': f'Bearer {self.api_key}',
83
+ }
84
+ if additional_headers:
85
+ headers.update(additional_headers)
86
+
87
+ logger.debug(
88
+ f"Making {method} request to {url} with payload: {payload}"
89
+ )
90
+
91
+ try:
92
+ response = requests.request(
93
+ method,
94
+ url,
95
+ headers=headers,
96
+ json=payload,
97
+ timeout=self.timeout,
98
+ )
99
+ response.raise_for_status()
100
+ return response.json()
101
+ except requests.exceptions.RequestException as e:
102
+ logger.error(f"Request failed for {method} {endpoint}: {e!s}")
103
+ return {"error": f"Request failed: {e!s}"}
104
+ except ValueError:
105
+ logger.error(f"Response for {method} {endpoint} is not valid JSON")
106
+ return {"error": "Response is not valid JSON"}
107
+
108
+ def create_server_instance(
109
+ self, server_name: str, user_id: str, platform_name: str
110
+ ) -> Dict[str, Any]:
111
+ r"""Create a Server-Sent Events (SSE) URL for a specified MCP server.
112
+
113
+ Args:
114
+ server_name (str): The name of the target MCP server.
115
+ user_id (str): The ID for the user requesting the server URL.
116
+ platform_name (str): The name of the platform associated
117
+ with the user.
118
+
119
+ Returns:
120
+ Dict[str, Any]: Response containing the server instance details.
121
+ """
122
+ endpoint = "/mcp-server/instance/create"
123
+ payload = {
124
+ "serverName": server_name,
125
+ "userId": user_id,
126
+ "platformName": platform_name,
127
+ }
128
+ headers = {'Content-Type': 'application/json'}
129
+ return self._request(
130
+ 'POST', endpoint, payload=payload, additional_headers=headers
131
+ )
132
+
133
+ def get_server_instance(self, instance_id: str) -> Dict[str, Any]:
134
+ r"""Get details of a specific server connection instance.
135
+
136
+ Args:
137
+ instance_id (str): The ID of the connection instance whose status
138
+ is being checked.
139
+
140
+ Returns:
141
+ Dict[str, Any]: Details about the server instance.
142
+ """
143
+ endpoint = f"/mcp-server/instance/get/{instance_id}"
144
+ return self._request('GET', endpoint)
145
+
146
+ def delete_auth_data(self, instance_id: str) -> Dict[str, Any]:
147
+ r"""Delete authentication metadata for a specific server
148
+ connection instance.
149
+
150
+ Args:
151
+ instance_id (str): The ID of the connection instance to
152
+ delete auth for.
153
+
154
+ Returns:
155
+ Dict[str, Any]: Status response for the operation.
156
+ """
157
+ endpoint = f"/mcp-server/instance/delete-auth/{instance_id}"
158
+ return self._request('DELETE', endpoint)
159
+
160
+ def delete_server_instance(self, instance_id: str) -> Dict[str, Any]:
161
+ r"""Completely removes a server connection instance.
162
+
163
+ Args:
164
+ instance_id (str): The ID of the connection instance to delete.
165
+
166
+ Returns:
167
+ Dict[str, Any]: Status response for the operation.
168
+ """
169
+ endpoint = f"/mcp-server/instance/delete/{instance_id}"
170
+ return self._request('DELETE', endpoint)
171
+
172
+ def get_server_tools(self, server_name: str) -> Dict[str, Any]:
173
+ r"""Get list of tool names for a specific MCP server.
174
+
175
+ Args:
176
+ server_name (str): The name of the target MCP server.
177
+
178
+ Returns:
179
+ Dict[str, Any]: List of tools available for the specified server.
180
+ """
181
+ endpoint = f"/mcp-server/tools/{server_name}"
182
+ return self._request('GET', endpoint)
183
+
184
+ def get_all_servers(self) -> Dict[str, Any]:
185
+ r"""Get all MCP servers with their basic information.
186
+
187
+ Returns:
188
+ Dict[str, Any]: Information about all available MCP servers.
189
+ """
190
+ endpoint = "/mcp-server/servers"
191
+ return self._request('GET', endpoint)
192
+
193
+ def set_auth_token(
194
+ self, instance_id: str, auth_token: str
195
+ ) -> Dict[str, Any]:
196
+ r"""Sets an authentication token for a specific instance.
197
+
198
+ Args:
199
+ instance_id (str): The ID for the connection instance.
200
+ auth_token (str): The authentication token to save.
201
+
202
+ Returns:
203
+ Dict[str, Any]: Status response for the operation.
204
+ """
205
+ endpoint = "/mcp-server/instance/set-auth-token"
206
+ payload = {"instanceId": instance_id, "authToken": auth_token}
207
+ headers = {'Content-Type': 'application/json'}
208
+ return self._request(
209
+ 'POST', endpoint, payload=payload, additional_headers=headers
210
+ )
211
+
212
+ def get_tools(self) -> List[FunctionTool]:
213
+ r"""Returns a list of FunctionTool objects representing the functions
214
+ in the toolkit.
215
+
216
+ Returns:
217
+ List[FunctionTool]: A list of FunctionTool objects representing
218
+ the functions in the toolkit.
219
+ """
220
+ return [
221
+ FunctionTool(self.create_server_instance),
222
+ FunctionTool(self.get_server_instance),
223
+ FunctionTool(self.delete_auth_data),
224
+ FunctionTool(self.delete_server_instance),
225
+ FunctionTool(self.get_server_tools),
226
+ FunctionTool(self.get_all_servers),
227
+ FunctionTool(self.set_auth_token),
228
+ ]
@@ -60,6 +60,8 @@ class MCPClient(BaseToolkit):
60
60
  timeout (Optional[float]): Connection timeout. (default: :obj:`'None'`)
61
61
  headers (Dict[str, str]): Headers for the HTTP request.
62
62
  (default: :obj:`'None'`)
63
+ strict (Optional[bool]): Whether to enforce strict mode for the
64
+ function call. (default: :obj:`False`)
63
65
  """
64
66
 
65
67
  def __init__(
@@ -69,6 +71,7 @@ class MCPClient(BaseToolkit):
69
71
  env: Optional[Dict[str, str]] = None,
70
72
  timeout: Optional[float] = None,
71
73
  headers: Optional[Dict[str, str]] = None,
74
+ strict: Optional[bool] = False,
72
75
  ):
73
76
  from mcp import Tool
74
77
 
@@ -78,6 +81,7 @@ class MCPClient(BaseToolkit):
78
81
  self.args = args or []
79
82
  self.env = env or {}
80
83
  self.headers = headers or {}
84
+ self.strict = strict
81
85
 
82
86
  self._mcp_tools: List[Tool] = []
83
87
  self._session: Optional['ClientSession'] = None
@@ -317,13 +321,15 @@ class MCPClient(BaseToolkit):
317
321
  "additionalProperties": False,
318
322
  }
319
323
 
324
+ # Because certain parameters in MCP may include keywords that are not
325
+ # supported by OpenAI, it is essential to set "strict" to False.
320
326
  return {
321
327
  "type": "function",
322
328
  "function": {
323
329
  "name": mcp_tool.name,
324
330
  "description": mcp_tool.description
325
331
  or "No description provided.",
326
- "strict": True,
332
+ "strict": self.strict,
327
333
  "parameters": parameters,
328
334
  },
329
335
  }
@@ -363,6 +369,8 @@ class MCPToolkit(BaseToolkit):
363
369
  instances to manage.
364
370
  config_path (Optional[str]): Path to a JSON configuration file
365
371
  defining MCP servers.
372
+ strict (Optional[bool]): Whether to enforce strict mode for the
373
+ function call. (default: :obj:`False`)
366
374
 
367
375
  Note:
368
376
  Either `servers` or `config_path` must be provided. If both are
@@ -397,6 +405,7 @@ class MCPToolkit(BaseToolkit):
397
405
  self,
398
406
  servers: Optional[List[MCPClient]] = None,
399
407
  config_path: Optional[str] = None,
408
+ strict: Optional[bool] = False,
400
409
  ):
401
410
  super().__init__()
402
411
 
@@ -409,16 +418,22 @@ class MCPToolkit(BaseToolkit):
409
418
  self.servers: List[MCPClient] = servers or []
410
419
 
411
420
  if config_path:
412
- self.servers.extend(self._load_servers_from_config(config_path))
421
+ self.servers.extend(
422
+ self._load_servers_from_config(config_path, strict)
423
+ )
413
424
 
414
425
  self._exit_stack = AsyncExitStack()
415
426
  self._connected = False
416
427
 
417
- def _load_servers_from_config(self, config_path: str) -> List[MCPClient]:
428
+ def _load_servers_from_config(
429
+ self, config_path: str, strict: Optional[bool] = False
430
+ ) -> List[MCPClient]:
418
431
  r"""Loads MCP server configurations from a JSON file.
419
432
 
420
433
  Args:
421
434
  config_path (str): Path to the JSON configuration file.
435
+ strict (bool): Whether to enforce strict mode for the
436
+ function call. (default: :obj:`False`)
422
437
 
423
438
  Returns:
424
439
  List[MCPClient]: List of configured MCPClient instances.
@@ -462,6 +477,7 @@ class MCPToolkit(BaseToolkit):
462
477
  args=cfg.get("args", []),
463
478
  env={**os.environ, **cfg.get("env", {})},
464
479
  timeout=cfg.get("timeout", None),
480
+ strict=strict,
465
481
  )
466
482
  all_servers.append(server)
467
483
 
camel/types/enums.py CHANGED
@@ -105,6 +105,7 @@ class ModelType(UnifiedModelType, Enum):
105
105
  TOGETHER_LLAMA_4_SCOUT = "meta-llama/Llama-4-Scout-17B-16E-Instruct"
106
106
 
107
107
  # PPIO platform models support tool calling
108
+ PPIO_DEEPSEEK_PROVER_V2_671B = "deepseek/deepseek-prover-v2-671b"
108
109
  PPIO_DEEPSEEK_R1_TURBO = "deepseek/deepseek-r1-turbo"
109
110
  PPIO_DEEPSEEK_V3_TURBO = "deepseek/deepseek-v3-turbo"
110
111
  PPIO_DEEPSEEK_R1_COMMUNITY = "deepseek/deepseek-r1/community"
@@ -716,6 +717,7 @@ class ModelType(UnifiedModelType, Enum):
716
717
  @property
717
718
  def is_ppio(self) -> bool:
718
719
  return self in {
720
+ ModelType.PPIO_DEEPSEEK_PROVER_V2_671B,
719
721
  ModelType.PPIO_DEEPSEEK_R1_TURBO,
720
722
  ModelType.PPIO_DEEPSEEK_V3_TURBO,
721
723
  ModelType.PPIO_DEEPSEEK_R1_COMMUNITY,
@@ -928,6 +930,7 @@ class ModelType(UnifiedModelType, Enum):
928
930
  }:
929
931
  return 14_336
930
932
  elif self in {
933
+ ModelType.PPIO_DEEPSEEK_PROVER_V2_671B,
931
934
  ModelType.NOVITA_DOLPHIN_MIXTRAL_8X22B,
932
935
  }:
933
936
  return 16_000
camel/utils/commons.py CHANGED
@@ -352,6 +352,8 @@ def api_keys_required(
352
352
  key_way = "https://platform.lingyiwanwu.com/docs"
353
353
  elif env_var_name == 'ZHIPUAI_API_KEY':
354
354
  key_way = "https://www.zhipuai.cn/"
355
+ elif env_var_name == 'KLAVIS_API_KEY':
356
+ key_way = "https://www.klavis.ai/docs"
355
357
 
356
358
  if missing_keys:
357
359
  raise ValueError(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: camel-ai
3
- Version: 0.2.50
3
+ Version: 0.2.52
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
@@ -36,6 +36,7 @@ Requires-Dist: dappier<0.4,>=0.3.3; extra == 'all'
36
36
  Requires-Dist: datacommons-pandas<0.0.4,>=0.0.3; extra == 'all'
37
37
  Requires-Dist: datacommons<2,>=1.4.3; extra == 'all'
38
38
  Requires-Dist: datasets<4,>=3; extra == 'all'
39
+ Requires-Dist: daytona-sdk==0.14.0; extra == 'all'
39
40
  Requires-Dist: diffusers<0.26,>=0.25.0; extra == 'all'
40
41
  Requires-Dist: discord-py<3,>=2.3.2; extra == 'all'
41
42
  Requires-Dist: docker<8,>=7.1.0; extra == 'all'
@@ -170,6 +171,7 @@ Requires-Dist: types-tqdm<5,>=4.66.0; extra == 'dev'
170
171
  Requires-Dist: uv==0.6.5; extra == 'dev'
171
172
  Provides-Extra: dev-tools
172
173
  Requires-Dist: agentops<0.4,>=0.3.21; extra == 'dev-tools'
174
+ Requires-Dist: daytona-sdk==0.14.0; extra == 'dev-tools'
173
175
  Requires-Dist: docker<8,>=7.1.0; extra == 'dev-tools'
174
176
  Requires-Dist: e2b-code-interpreter<2,>=1.0.3; extra == 'dev-tools'
175
177
  Requires-Dist: ipykernel<7,>=6.0.0; extra == 'dev-tools'
@@ -1,4 +1,4 @@
1
- camel/__init__.py,sha256=m9QPqmOwrIW6yXBMb1giOGlXCTU-o0GmvPQqmONLr2w,912
1
+ camel/__init__.py,sha256=4hOpc6x6mtK5OsacUZpZFBla8BA-4Ru7OKm_aTxLJso,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
@@ -114,7 +114,7 @@ camel/embeddings/vlm_embedding.py,sha256=HZFdcz1YzkFPzMj45_jaCVmDQJyccoXN561aLWl
114
114
  camel/environments/__init__.py,sha256=fwk74TJO5OaOhL5Pmiz6s6h77B_-DGav5m_HbfS1oUQ,1053
115
115
  camel/environments/models.py,sha256=jVcCyU7xObKoWPnkshmPqyyKi3AOiMVVtUZA-tWEYUU,4194
116
116
  camel/environments/multi_step.py,sha256=HPIH2W-iWsmtDLeN1gjxo7LoAnMQQZzdmfjhmRoBAxg,8534
117
- camel/environments/single_step.py,sha256=TxEVoQVqyGgBbb3OiyOSTEyJh7NqsJmrUOndJLrFWH4,20055
117
+ camel/environments/single_step.py,sha256=zrAXLOBGGKQFnGENasUnmFO_T-rjppGPK2CRBLGu7aQ,23019
118
118
  camel/environments/tic_tac_toe.py,sha256=axRDN9yUVH8PzACkD6zenWiQKFDaupGsQ7NmSvbJCIc,19080
119
119
  camel/extractors/__init__.py,sha256=lgtDl8zWvN826fJVKqRv05w556YZ-EdrHwdzKphywgA,1097
120
120
  camel/extractors/base.py,sha256=3jvuZpq27nlADDCX3GfubOpeb_zt-E9rzxF3x4lYm8s,10404
@@ -163,7 +163,7 @@ camel/models/_utils.py,sha256=hob1ehnS5xZitMCdYToHVgaTB55JnaP4_DSWnTEfVsg,2045
163
163
  camel/models/aiml_model.py,sha256=HO_jRvMN2WEVlZRc_UG-OoZ1hv8sEiO5j_7BBKuGlp0,3753
164
164
  camel/models/anthropic_model.py,sha256=0jilp8dBrk1JAP0dkw_YX21uL3_81ZGL0qmKZiAI2w0,4331
165
165
  camel/models/aws_bedrock_model.py,sha256=cpY66Wcwb-clNf0TCch9WI8au3_GGxHBYUd09rGQi_U,4353
166
- camel/models/azure_openai_model.py,sha256=psxSx1R9dCRw-jWy58lwhUjPFP01UrhCJ7sHeveu_fo,11057
166
+ camel/models/azure_openai_model.py,sha256=-_c4SjYOA-BM6n01FuaaQ8m_QucG8_DbV_zFozaesDg,12067
167
167
  camel/models/base_audio_model.py,sha256=_VUWh1L3rh8mldNvM5R6jBOKtvmTeBKJyRxAdPJmPlY,3324
168
168
  camel/models/base_model.py,sha256=eDeUlgH8iS0Stk6zommzqce4dfD4Qj51tvgXUs5ys4s,14474
169
169
  camel/models/cohere_model.py,sha256=OgRHxlPrei-NT5UVDFf6lVR88k6eKnmcZMyFj4XmONE,14880
@@ -183,7 +183,7 @@ camel/models/nemotron_model.py,sha256=APYCcpDMytZNsXFhdcLnO8bttc6pQWAo6e5h2VTJVw
183
183
  camel/models/netmind_model.py,sha256=EmyKBupEQlciI69ba_oF36RNT7EJYqGLtMJ_QVZPFaE,3959
184
184
  camel/models/novita_model.py,sha256=tU8RXsV-4wYmQhXcZkPXdlXRvLwsnj_pEJVSxnhXiXc,3921
185
185
  camel/models/nvidia_model.py,sha256=XkHBZJ94nkYB1j9AgyPsorYfvgO1Ys6S6_z3Qh3vrhM,3766
186
- camel/models/ollama_model.py,sha256=daPWcHSTt4Krre9Vy5_SWK1rNwWZb6Hk_7cH9PiM5xA,4275
186
+ camel/models/ollama_model.py,sha256=sc49XZT9KQeUWjvLqXn17kKa1jgAyAHiy2MHiUjQrzw,4416
187
187
  camel/models/openai_audio_models.py,sha256=BSixkXlc8xirQLl2qCla-g6_y9wDLnMZVHukHrhzw98,13344
188
188
  camel/models/openai_compatible_model.py,sha256=PmNMQKXMPk-4HYiDqn8dJ8cMH8ukl4MAPVtqWyWDnfY,10481
189
189
  camel/models/openai_model.py,sha256=atxW2N6xcA9kqGAE6moqKYZD3IxIxOjmKcQnBs7ff7w,12826
@@ -196,7 +196,7 @@ camel/models/sglang_model.py,sha256=GsRxh3yrOQRu5gJgPdES289vCiiUHoBvKw-YZ-iwlI0,
196
196
  camel/models/siliconflow_model.py,sha256=mdVcf-5N-ZWS5qGL2pq7TsAsvlhCXxL6jxavxeElFRw,4432
197
197
  camel/models/stub_model.py,sha256=JvjeEkXS7RMcR_UA_64a3T6S0QALUhOaMQs-aI7Etug,5955
198
198
  camel/models/togetherai_model.py,sha256=16q-0jsO5HIy9K0elSlR-aA9EDN5VhPXPGBG6cU1t1w,3937
199
- camel/models/vllm_model.py,sha256=vSgIuddQBvduDr5suh5jSG38ug7SCEFFHbERFrwcw8c,4351
199
+ camel/models/vllm_model.py,sha256=bB4-pkXnMD6aGXumCYpJY62JCWRMuK57kIpzYdK3mJQ,4493
200
200
  camel/models/volcano_model.py,sha256=Lsg0BDVPaP50vRNW0D37liEsa71RmvapBxN_JCcHe-4,3674
201
201
  camel/models/watsonx_model.py,sha256=2jIfx5dGBxxVqaZIUBTd01mtw_XuCUzqtcmKpubibME,9136
202
202
  camel/models/yi_model.py,sha256=hZ_LYZWYhDkjBA3UcDiY2sGPFH3jEbxHaRy6IMvLYZ4,3742
@@ -235,10 +235,11 @@ camel/retrievers/bm25_retriever.py,sha256=feQgn3dwnbQG8H7KSbFzjaFAw3KtKObfoyA6gm
235
235
  camel/retrievers/cohere_rerank_retriever.py,sha256=tzMS3HG4wD3gbIAVcHsC5fTbFxuiNrT4qJ10oJMJ0BA,4032
236
236
  camel/retrievers/hybrid_retrival.py,sha256=2ySeXnLunoBHarqssijjxn7bAQGypAXX6QdzxYstreM,9466
237
237
  camel/retrievers/vector_retriever.py,sha256=Fp6k7FkoeUXLiUokqsMIO74Dh2mJcmJP2TrCP-6Ekcc,11051
238
- camel/runtime/__init__.py,sha256=aMUmX2qBmO4wCVJp4pIjx2Zed88HcrUzimfJvnz9ZZg,1207
238
+ camel/runtime/__init__.py,sha256=bFbqDIST69V6LC_Oe5YBz-8qlUaJt4zWGFFT0ctiMLI,1273
239
239
  camel/runtime/api.py,sha256=JfkHqQ_Xs3ZNl4TXC_obV3Ymi21ltP1LAkXzBA3H_Lo,3227
240
240
  camel/runtime/base.py,sha256=KKBLO6PwWEWBXbYaVtO9JXqBT8110iYpMhgNSIxQvYQ,1512
241
241
  camel/runtime/configs.py,sha256=7swJ6shD5CAnQj16D_j1BWJjRDHLue8_BJcQ1-YiKJI,2431
242
+ camel/runtime/daytona_runtime.py,sha256=bhQyn1ZRNcDg-gDWOzjGszMl1keL90xnvLZ-EH--DaU,9165
242
243
  camel/runtime/docker_runtime.py,sha256=Q1eN4rWxDB4PF_G7nq64Rk7xhRZgAhNqmlxsu6YMdCg,13578
243
244
  camel/runtime/llm_guard_runtime.py,sha256=n8MImZsYLXCfr6LG6BFvlC75Al16GMJMvGp4vFsob6E,8101
244
245
  camel/runtime/remote_http_runtime.py,sha256=Emgz2xz4vbwCvErDk6Ni25aDA3EBXoPOQ7U70AgVg0w,6669
@@ -292,7 +293,7 @@ camel/terminators/__init__.py,sha256=t8uqrkUnXEOYMXQDgaBkMFJ0EXFKI0kmx4cUimli3Ls
292
293
  camel/terminators/base.py,sha256=xmJzERX7GdSXcxZjAHHODa0rOxRChMSRboDCNHWSscs,1511
293
294
  camel/terminators/response_terminator.py,sha256=n3G5KP6Oj7-7WlRN0yFcrtLpqAJKaKS0bmhrWlFfCgQ,4982
294
295
  camel/terminators/token_limit_terminator.py,sha256=YWv6ZR8R9yI2Qnf_3xES5bEE_O5bb2CxQ0EUXfMh34c,2118
295
- camel/toolkits/__init__.py,sha256=AQqFlCEzz9lb_eSgSNow0G9BXZyh5hD4vPaDJEz9w5I,4366
296
+ camel/toolkits/__init__.py,sha256=sGw0LKAG4WNVWL7NUYlQH0f0IE_gm2VMSPbkSLCJ-10,4429
296
297
  camel/toolkits/arxiv_toolkit.py,sha256=Bs2-K1yfmqhEhHoQ0j00KoI8LpOd8M3ApXcvI_-ApVw,6303
297
298
  camel/toolkits/ask_news_toolkit.py,sha256=WfWaqwEo1Apbil3-Rb5y65Ws43NU4rAFWZu5VHe4los,23448
298
299
  camel/toolkits/audio_analysis_toolkit.py,sha256=dnDtQJbztVBwBpamSyCfigPw2GBnDAfi3fOPgql4Y50,8941
@@ -312,9 +313,10 @@ camel/toolkits/google_scholar_toolkit.py,sha256=WQ9a0HQr0vro1Uo1m--alCUXvMmaHVKe
312
313
  camel/toolkits/human_toolkit.py,sha256=ZbhXPA0G3mQkcNW_jPwywReAft2pIJG0WkVXOG48s1w,2328
313
314
  camel/toolkits/image_analysis_toolkit.py,sha256=gnbX2by7_pxPpjUEY8bOj1tV-hGC3mwqEvQRMXyZ9TM,7535
314
315
  camel/toolkits/jina_reranker_toolkit.py,sha256=U-V9qZ7SKP3SPTh_0CsE7ZKNqS9jNkmKYsIN1Mk-vFY,8118
316
+ camel/toolkits/klavis_toolkit.py,sha256=L-OiGwgaIue8QiIijNlvGbgtwjGUszLqs9bVRW5md7c,8244
315
317
  camel/toolkits/linkedin_toolkit.py,sha256=wn4eXwYYlVA7doTna7k7WYhUqTBF83W79S-UJs_IQr0,8065
316
318
  camel/toolkits/math_toolkit.py,sha256=KdI8AJ9Dbq5cfWboAYJUYgSkmADMCO5eZ6yqYkWuiIQ,3686
317
- camel/toolkits/mcp_toolkit.py,sha256=4eweKFF3M9WOGroJCdsNBdyp8KUZJfaXLPGVYFu9kUQ,18275
319
+ camel/toolkits/mcp_toolkit.py,sha256=Vzw6ACr4z7Emzdobfw8diPB3Wd2G_SDfUKlJoS9lsxI,19024
318
320
  camel/toolkits/memory_toolkit.py,sha256=TeKYd5UMwgjVpuS2orb-ocFL13eUNKujvrFOruDCpm8,4436
319
321
  camel/toolkits/meshy_toolkit.py,sha256=NbgdOBD3FYLtZf-AfonIv6-Q8-8DW129jsaP1PqI2rs,7126
320
322
  camel/toolkits/mineru_toolkit.py,sha256=vRX9LholLNkpbJ6axfEN4pTG85aWb0PDmlVy3rAAXhg,6868
@@ -368,14 +370,14 @@ camel/toolkits/open_api_specs/web_scraper/openapi.yaml,sha256=u_WalQ01e8W1D27VnZ
368
370
  camel/toolkits/open_api_specs/web_scraper/paths/__init__.py,sha256=OKCZrQCDwaWtXIN_2rA9FSqEvgpQRieRoHh7Ek6N16A,702
369
371
  camel/toolkits/open_api_specs/web_scraper/paths/scraper.py,sha256=aWy1_ppV4NVVEZfnbN3tu9XA9yAPAC9bRStJ5JuXMRU,1117
370
372
  camel/types/__init__.py,sha256=VLWhAt857IFct3XepY5BNOIhyhDhfmODTezr9jhO_TI,2251
371
- camel/types/enums.py,sha256=dNrNNA1WIamFxNahGXCuKucZYd0rGLoZNx6ZllUXze8,56612
373
+ camel/types/enums.py,sha256=zisVc5hTqrbrwtH3lijzalP9zMI2pMW62-SIDizn8EQ,56786
372
374
  camel/types/openai_types.py,sha256=8ZFzLe-zGmKNPfuVZFzxlxAX98lGf18gtrPhOgMmzus,2104
373
375
  camel/types/unified_model_type.py,sha256=TpiUmJ3IuX8LNLtTUeUcVM7U82r4ClSq3ZQlNX3ODKs,5351
374
376
  camel/types/agents/__init__.py,sha256=cbvVkogPoZgcwZrgxLH6EtpGXk0kavF79nOic0Dc1vg,786
375
377
  camel/types/agents/tool_calling_record.py,sha256=qa-vLyKvYzWprRkFFl1928xaw9CnfacIebHaqM-oY3s,1814
376
378
  camel/utils/__init__.py,sha256=0rN9DFjUh7Gv6HIJBhm9edmLKecK-89j9q0TC4ABsZY,2737
377
379
  camel/utils/async_func.py,sha256=KqoktGSWjZBuAMQ2CV0X6FRgHGlzCKLfeaWvp-f1Qz8,1568
378
- camel/utils/commons.py,sha256=WnLInwlT3Cn-M2qhqI_GRX33A0uZaRnnRWvJ248JrrI,33587
380
+ camel/utils/commons.py,sha256=dzZ1zR2RIb6MCCSw_jfil36BGcVe0q4Jy2t2y2T2Vwg,33693
379
381
  camel/utils/constants.py,sha256=cqnxmpUeOwrtsR-tRO4bbOc6ZP19TLj7avjm3FONMJs,1410
380
382
  camel/utils/deduplication.py,sha256=UHikAtOW1TTDunf2t_wa2kFbmkrXWf7HfOKwLvwCxzo,8958
381
383
  camel/utils/filename.py,sha256=HYNc1wbSCgNR1CN21cwHxdAhpnsf5ySJ6jUDfeqOK20,2532
@@ -392,7 +394,7 @@ camel/verifiers/math_verifier.py,sha256=tA1D4S0sm8nsWISevxSN0hvSVtIUpqmJhzqfbuMo
392
394
  camel/verifiers/models.py,sha256=GdxYPr7UxNrR1577yW4kyroRcLGfd-H1GXgv8potDWU,2471
393
395
  camel/verifiers/physics_verifier.py,sha256=c1grrRddcrVN7szkxhv2QirwY9viIRSITWeWFF5HmLs,30187
394
396
  camel/verifiers/python_verifier.py,sha256=ogTz77wODfEcDN4tMVtiSkRQyoiZbHPY2fKybn59lHw,20558
395
- camel_ai-0.2.50.dist-info/METADATA,sha256=zXfL_GgIP8CyRTUax_ubD_fr7bAXVcpTl1R24A1yO0Q,43892
396
- camel_ai-0.2.50.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
397
- camel_ai-0.2.50.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
398
- camel_ai-0.2.50.dist-info/RECORD,,
397
+ camel_ai-0.2.52.dist-info/METADATA,sha256=MhuSMpOxRFCshNY5GspU1s-rIkuzPYzsRH921CgJoSA,44000
398
+ camel_ai-0.2.52.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
399
+ camel_ai-0.2.52.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
400
+ camel_ai-0.2.52.dist-info/RECORD,,