camel-ai 0.2.11__py3-none-any.whl → 0.2.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of camel-ai might be problematic. Click here for more details.

Files changed (55) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +13 -1
  3. camel/benchmarks/__init__.py +18 -0
  4. camel/benchmarks/base.py +152 -0
  5. camel/benchmarks/gaia.py +478 -0
  6. camel/configs/__init__.py +3 -0
  7. camel/configs/ollama_config.py +4 -2
  8. camel/configs/sglang_config.py +71 -0
  9. camel/data_collector/__init__.py +19 -0
  10. camel/data_collector/alpaca_collector.py +127 -0
  11. camel/data_collector/base.py +211 -0
  12. camel/data_collector/sharegpt_collector.py +205 -0
  13. camel/datahubs/__init__.py +23 -0
  14. camel/datahubs/base.py +136 -0
  15. camel/datahubs/huggingface.py +433 -0
  16. camel/datahubs/models.py +22 -0
  17. camel/interpreters/__init__.py +2 -0
  18. camel/interpreters/e2b_interpreter.py +136 -0
  19. camel/loaders/__init__.py +3 -1
  20. camel/loaders/base_io.py +41 -41
  21. camel/messages/__init__.py +2 -0
  22. camel/models/__init__.py +2 -0
  23. camel/models/anthropic_model.py +14 -4
  24. camel/models/base_model.py +28 -0
  25. camel/models/groq_model.py +1 -1
  26. camel/models/model_factory.py +3 -0
  27. camel/models/ollama_model.py +12 -0
  28. camel/models/openai_model.py +0 -26
  29. camel/models/reward/__init__.py +22 -0
  30. camel/models/reward/base_reward_model.py +58 -0
  31. camel/models/reward/evaluator.py +63 -0
  32. camel/models/reward/nemotron_model.py +112 -0
  33. camel/models/sglang_model.py +225 -0
  34. camel/models/vllm_model.py +1 -1
  35. camel/personas/persona_hub.py +2 -2
  36. camel/schemas/openai_converter.py +2 -2
  37. camel/societies/workforce/role_playing_worker.py +2 -2
  38. camel/societies/workforce/single_agent_worker.py +2 -2
  39. camel/societies/workforce/workforce.py +3 -3
  40. camel/storages/object_storages/amazon_s3.py +2 -2
  41. camel/storages/object_storages/azure_blob.py +2 -2
  42. camel/storages/object_storages/google_cloud.py +2 -2
  43. camel/toolkits/__init__.py +2 -0
  44. camel/toolkits/code_execution.py +5 -1
  45. camel/toolkits/function_tool.py +41 -0
  46. camel/toolkits/math_toolkit.py +47 -16
  47. camel/toolkits/search_toolkit.py +154 -2
  48. camel/toolkits/stripe_toolkit.py +273 -0
  49. camel/types/__init__.py +2 -0
  50. camel/types/enums.py +27 -2
  51. camel/utils/token_counting.py +22 -10
  52. {camel_ai-0.2.11.dist-info → camel_ai-0.2.12.dist-info}/METADATA +13 -6
  53. {camel_ai-0.2.11.dist-info → camel_ai-0.2.12.dist-info}/RECORD +55 -36
  54. {camel_ai-0.2.11.dist-info → camel_ai-0.2.12.dist-info}/LICENSE +0 -0
  55. {camel_ai-0.2.11.dist-info → camel_ai-0.2.12.dist-info}/WHEEL +0 -0
@@ -0,0 +1,433 @@
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
+ import json
15
+ import os
16
+ import tempfile
17
+ from typing import Any, List, Optional
18
+
19
+ from camel.datahubs.base import BaseDatasetManager
20
+ from camel.datahubs.models import Record
21
+ from camel.logger import get_logger
22
+ from camel.types import HuggingFaceRepoType
23
+ from camel.utils import api_keys_required, dependencies_required
24
+
25
+ logger = get_logger(__name__)
26
+
27
+
28
+ class HuggingFaceDatasetManager(BaseDatasetManager):
29
+ r"""A dataset manager for Hugging Face datasets. This class provides
30
+ methods to create, add, update, delete, and list records in a dataset on
31
+ the Hugging Face Hub.
32
+
33
+ Args:
34
+ token (str): The Hugging Face API token. If not provided, the token
35
+ will be read from the environment variable `HUGGING_FACE_TOKEN`.
36
+ """
37
+
38
+ @api_keys_required("HUGGING_FACE_TOKEN")
39
+ @dependencies_required('huggingface_hub')
40
+ def __init__(self, token: Optional[str] = None):
41
+ from huggingface_hub import HfApi
42
+
43
+ self._api_key = token or os.getenv("HUGGING_FACE_TOKEN")
44
+ self.api = HfApi(token=self._api_key)
45
+
46
+ def create_dataset_card(
47
+ self,
48
+ dataset_name: str,
49
+ description: str,
50
+ license: Optional[str] = None,
51
+ version: Optional[str] = None,
52
+ tags: Optional[List[str]] = None,
53
+ authors: Optional[List[str]] = None,
54
+ size_category: Optional[List[str]] = None,
55
+ language: Optional[List[str]] = None,
56
+ task_categories: Optional[List[str]] = None,
57
+ content: Optional[str] = None,
58
+ ) -> None:
59
+ r"""Creates and uploads a dataset card to the Hugging Face Hub in YAML
60
+ format.
61
+
62
+ Args:
63
+ dataset_name (str): The name of the dataset.
64
+ description (str): A description of the dataset.
65
+ license (str): The license of the dataset. (default: :obj:`None`)
66
+ version (str): The version of the dataset. (default: :obj:`None`)
67
+ tags (list): A list of tags for the dataset.(default: :obj:`None`)
68
+ authors (list): A list of authors of the dataset. (default:
69
+ :obj:`None`)
70
+ size_category (list): A size category for the dataset. (default:
71
+ :obj:`None`)
72
+ language (list): A list of languages the dataset is in. (default:
73
+ :obj:`None`)
74
+ task_categories (list): A list of task categories. (default:
75
+ :obj:`None`)
76
+ content (str): Custom markdown content that the user wants to add
77
+ to the dataset card. (default: :obj:`None`)
78
+ """
79
+ import yaml
80
+
81
+ metadata = {
82
+ "license": license,
83
+ "authors": authors,
84
+ "task_categories": task_categories,
85
+ "language": language,
86
+ "tags": tags,
87
+ "pretty_name": dataset_name,
88
+ "size_categories": size_category,
89
+ "version": version,
90
+ "description": description,
91
+ }
92
+
93
+ # Remove keys with None values
94
+ metadata = {k: v for k, v in metadata.items() if v}
95
+
96
+ card_content = (
97
+ "---\n"
98
+ + yaml.dump(metadata, default_flow_style=False, allow_unicode=True)
99
+ + "\n---"
100
+ )
101
+
102
+ if content:
103
+ card_content += f"\n\n# Additional Information\n{content}\n"
104
+
105
+ self._upload_file(
106
+ file_content=card_content,
107
+ dataset_name=dataset_name,
108
+ filepath="README.md",
109
+ file_type="md",
110
+ )
111
+
112
+ def create_dataset(
113
+ self, name: str, private: bool = False, **kwargs: Any
114
+ ) -> str:
115
+ r"""Creates a new dataset on the Hugging Face Hub.
116
+
117
+ Args:
118
+ name (str): The name of the dataset.
119
+ private (bool): Whether the dataset should be private. defaults to
120
+ False.
121
+ kwargs (Any): Additional keyword arguments.
122
+
123
+ Returns:
124
+ str: The URL of the created dataset.
125
+ """
126
+ from huggingface_hub.errors import RepositoryNotFoundError
127
+
128
+ try:
129
+ self.api.repo_info(
130
+ repo_id=name,
131
+ repo_type=HuggingFaceRepoType.DATASET.value,
132
+ **kwargs,
133
+ )
134
+ except RepositoryNotFoundError:
135
+ self.api.create_repo(
136
+ repo_id=name,
137
+ repo_type=HuggingFaceRepoType.DATASET.value,
138
+ private=private,
139
+ )
140
+
141
+ return f"https://huggingface.co/datasets/{name}"
142
+
143
+ def list_datasets(
144
+ self, username: str, limit: int = 100, **kwargs: Any
145
+ ) -> List[str]:
146
+ r"""Lists all datasets for the current user.
147
+
148
+ Args:
149
+ username (str): The username of the user whose datasets to list.
150
+ limit (int): The maximum number of datasets to list.
151
+ (default: :obj:`100`)
152
+ kwargs (Any): Additional keyword arguments.
153
+
154
+ Returns:
155
+ List[str]: A list of dataset ids.
156
+ """
157
+ try:
158
+ return [
159
+ dataset.id
160
+ for dataset in self.api.list_datasets(
161
+ author=username, limit=limit, **kwargs
162
+ )
163
+ ]
164
+ except Exception as e:
165
+ logger.error(f"Error listing datasets: {e}")
166
+ return []
167
+
168
+ def delete_dataset(self, dataset_name: str, **kwargs: Any) -> None:
169
+ r"""Deletes a dataset from the Hugging Face Hub.
170
+
171
+ Args:
172
+ dataset_name (str): The name of the dataset to delete.
173
+ kwargs (Any): Additional keyword arguments.
174
+ """
175
+ try:
176
+ self.api.delete_repo(
177
+ repo_id=dataset_name,
178
+ repo_type=HuggingFaceRepoType.DATASET.value,
179
+ **kwargs,
180
+ )
181
+ logger.info(f"Dataset '{dataset_name}' deleted successfully.")
182
+ except Exception as e:
183
+ logger.error(f"Error deleting dataset '{dataset_name}': {e}")
184
+ raise
185
+
186
+ def add_records(
187
+ self,
188
+ dataset_name: str,
189
+ records: List[Record],
190
+ filepath: str = "records/records.json",
191
+ **kwargs: Any,
192
+ ) -> None:
193
+ r"""Adds records to a dataset on the Hugging Face Hub.
194
+
195
+ Args:
196
+ dataset_name (str): The name of the dataset.
197
+ records (List[Record]): A list of records to add to the dataset.
198
+ filepath (str): The path to the file containing the records.
199
+ kwargs (Any): Additional keyword arguments.
200
+
201
+ Raises:
202
+ ValueError: If the dataset already has a records file.
203
+ """
204
+ existing_records = self._download_records(
205
+ dataset_name=dataset_name, filepath=filepath, **kwargs
206
+ )
207
+
208
+ if existing_records:
209
+ raise ValueError(
210
+ f"Dataset '{filepath}' already exists. "
211
+ f"Use `update_records` to modify."
212
+ )
213
+
214
+ self._upload_records(
215
+ records=records,
216
+ dataset_name=dataset_name,
217
+ filepath=filepath,
218
+ **kwargs,
219
+ )
220
+
221
+ def update_records(
222
+ self,
223
+ dataset_name: str,
224
+ records: List[Record],
225
+ filepath: str = "records/records.json",
226
+ **kwargs: Any,
227
+ ) -> None:
228
+ r"""Updates records in a dataset on the Hugging Face Hub.
229
+
230
+ Args:
231
+ dataset_name (str): The name of the dataset.
232
+ records (List[Record]): A list of records to update in the dataset.
233
+ filepath (str): The path to the file containing the records.
234
+ kwargs (Any): Additional keyword arguments.
235
+
236
+ Raises:
237
+ ValueError: If the dataset does not have an existing file to update
238
+ records in.
239
+ """
240
+ existing_records = self._download_records(
241
+ dataset_name=dataset_name, filepath=filepath, **kwargs
242
+ )
243
+
244
+ if not existing_records:
245
+ logger.warning(
246
+ f"Dataset '{dataset_name}' does not have existing "
247
+ "records. Adding new records."
248
+ )
249
+ self._upload_records(
250
+ records=records,
251
+ dataset_name=dataset_name,
252
+ filepath=filepath,
253
+ **kwargs,
254
+ )
255
+ return
256
+
257
+ old_dict = {record.id: record for record in existing_records}
258
+ new_dict = {record.id: record for record in records}
259
+ merged_dict = old_dict.copy()
260
+ merged_dict.update(new_dict)
261
+
262
+ self._upload_records(
263
+ records=list(merged_dict.values()),
264
+ dataset_name=dataset_name,
265
+ filepath=filepath,
266
+ **kwargs,
267
+ )
268
+
269
+ def delete_record(
270
+ self,
271
+ dataset_name: str,
272
+ record_id: str,
273
+ filepath: str = "records/records.json",
274
+ **kwargs: Any,
275
+ ) -> None:
276
+ r"""Deletes a record from the dataset.
277
+
278
+ Args:
279
+ dataset_name (str): The name of the dataset.
280
+ record_id (str): The ID of the record to delete.
281
+ filepath (str): The path to the file containing the records.
282
+ kwargs (Any): Additional keyword arguments.
283
+
284
+ Raises:
285
+ ValueError: If the dataset does not have an existing file to delete
286
+ records from.
287
+ """
288
+ existing_records = self._download_records(
289
+ dataset_name=dataset_name, filepath=filepath, **kwargs
290
+ )
291
+
292
+ if not existing_records:
293
+ raise ValueError(
294
+ f"Dataset '{dataset_name}' does not have an existing file to "
295
+ f"delete records from."
296
+ )
297
+
298
+ filtered_records = [
299
+ record for record in existing_records if record.id != record_id
300
+ ]
301
+
302
+ self._upload_records(
303
+ records=filtered_records,
304
+ dataset_name=dataset_name,
305
+ filepath=filepath,
306
+ **kwargs,
307
+ )
308
+
309
+ def list_records(
310
+ self,
311
+ dataset_name: str,
312
+ filepath: str = "records/records.json",
313
+ **kwargs: Any,
314
+ ) -> List[Record]:
315
+ r"""Lists all records in a dataset.
316
+
317
+ Args:
318
+ dataset_name (str): The name of the dataset.
319
+ filepath (str): The path to the file containing the records.
320
+ kwargs (Any): Additional keyword arguments.
321
+
322
+ Returns:
323
+ List[Record]: A list of records in the dataset.
324
+ """
325
+ return self._download_records(
326
+ dataset_name=dataset_name, filepath=filepath, **kwargs
327
+ )
328
+
329
+ def _download_records(
330
+ self, dataset_name: str, filepath: str, **kwargs: Any
331
+ ) -> List[Record]:
332
+ from huggingface_hub import hf_hub_download
333
+ from huggingface_hub.errors import EntryNotFoundError
334
+
335
+ try:
336
+ downloaded_file_path = hf_hub_download(
337
+ repo_id=dataset_name,
338
+ filename=filepath,
339
+ repo_type=HuggingFaceRepoType.DATASET.value,
340
+ token=self._api_key,
341
+ **kwargs,
342
+ )
343
+
344
+ with open(downloaded_file_path, "r") as f:
345
+ records_data = json.load(f)
346
+
347
+ return [Record(**record) for record in records_data]
348
+ except EntryNotFoundError:
349
+ logger.info(f"No records found for dataset '{dataset_name}'.")
350
+ return []
351
+ except Exception as e:
352
+ logger.error(f"Error downloading or processing records: {e}")
353
+ raise e
354
+
355
+ def _upload_records(
356
+ self,
357
+ records: List[Record],
358
+ dataset_name: str,
359
+ filepath: str,
360
+ **kwargs: Any,
361
+ ):
362
+ with tempfile.NamedTemporaryFile(
363
+ delete=False, mode="w", newline="", encoding="utf-8"
364
+ ) as f:
365
+ json.dump([record.model_dump() for record in records], f)
366
+ temp_file_path = f.name
367
+
368
+ try:
369
+ self.api.upload_file(
370
+ path_or_fileobj=temp_file_path,
371
+ path_in_repo=filepath,
372
+ repo_id=dataset_name,
373
+ repo_type=HuggingFaceRepoType.DATASET.value,
374
+ **kwargs,
375
+ )
376
+ except Exception as e:
377
+ logger.error(f"Error uploading records file: {e}")
378
+ raise
379
+ finally:
380
+ if os.path.exists(temp_file_path):
381
+ os.remove(temp_file_path)
382
+
383
+ def _upload_file(
384
+ self,
385
+ file_content: str,
386
+ dataset_name: str,
387
+ filepath: str,
388
+ file_type: str = "json",
389
+ **kwargs: Any,
390
+ ):
391
+ with tempfile.NamedTemporaryFile(
392
+ mode="w", delete=False, suffix=f".{file_type}"
393
+ ) as f:
394
+ if file_type == "json":
395
+ if isinstance(file_content, str):
396
+ try:
397
+ json_content = json.loads(file_content)
398
+ except json.JSONDecodeError:
399
+ raise ValueError(
400
+ "Invalid JSON string provided for file_content."
401
+ )
402
+ else:
403
+ try:
404
+ json.dumps(file_content)
405
+ json_content = file_content
406
+ except (TypeError, ValueError):
407
+ raise ValueError(
408
+ "file_content is not JSON serializable."
409
+ )
410
+
411
+ json.dump(json_content, f)
412
+ elif file_type == "md" or file_type == "txt":
413
+ f.write(file_content)
414
+ else:
415
+ raise ValueError(f"Unsupported file type: {file_type}")
416
+
417
+ temp_file_path = f.name
418
+
419
+ try:
420
+ self.api.upload_file(
421
+ path_or_fileobj=temp_file_path,
422
+ path_in_repo=filepath,
423
+ repo_id=dataset_name,
424
+ repo_type=HuggingFaceRepoType.DATASET.value,
425
+ **kwargs,
426
+ )
427
+ logger.info(f"File uploaded successfully: {filepath}")
428
+ except Exception as e:
429
+ logger.error(f"Error uploading file: {e}")
430
+ raise
431
+
432
+ if os.path.exists(temp_file_path):
433
+ os.remove(temp_file_path)
@@ -0,0 +1,22 @@
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
+ from typing import Any, Dict, Optional
15
+
16
+ from pydantic import BaseModel
17
+
18
+
19
+ class Record(BaseModel):
20
+ id: Optional[str] = None
21
+ metadata: Optional[Dict[str, Any]] = None
22
+ content: Dict[str, Any]
@@ -14,6 +14,7 @@
14
14
 
15
15
  from .base import BaseInterpreter
16
16
  from .docker_interpreter import DockerInterpreter
17
+ from .e2b_interpreter import E2BInterpreter
17
18
  from .internal_python_interpreter import InternalPythonInterpreter
18
19
  from .interpreter_error import InterpreterError
19
20
  from .ipython_interpreter import JupyterKernelInterpreter
@@ -26,4 +27,5 @@ __all__ = [
26
27
  'SubprocessInterpreter',
27
28
  'DockerInterpreter',
28
29
  'JupyterKernelInterpreter',
30
+ 'E2BInterpreter',
29
31
  ]
@@ -0,0 +1,136 @@
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
+ import os
15
+ from typing import Any, ClassVar, Dict, List, Optional
16
+
17
+ from camel.interpreters.base import BaseInterpreter
18
+ from camel.interpreters.interpreter_error import InterpreterError
19
+ from camel.logger import get_logger
20
+ from camel.utils import api_keys_required
21
+
22
+ logger = get_logger(__name__)
23
+
24
+
25
+ class E2BInterpreter(BaseInterpreter):
26
+ r"""E2B Code Interpreter implementation.
27
+
28
+ Args:
29
+ require_confirm (bool, optional): If True, prompt user before running
30
+ code strings for security. (default: :obj:`True`)
31
+ """
32
+
33
+ _CODE_TYPE_MAPPING: ClassVar[Dict[str, Optional[str]]] = {
34
+ "python": None,
35
+ "py3": None,
36
+ "python3": None,
37
+ "py": None,
38
+ "shell": "bash",
39
+ "bash": "bash",
40
+ "sh": "bash",
41
+ "java": "java",
42
+ "javascript": "js",
43
+ "r": "r",
44
+ }
45
+
46
+ @api_keys_required("E2B_API_KEY")
47
+ def __init__(
48
+ self,
49
+ require_confirm: bool = True,
50
+ ) -> None:
51
+ from e2b_code_interpreter import Sandbox
52
+
53
+ self.require_confirm = require_confirm
54
+ self._sandbox = Sandbox(api_key=os.environ.get("E2B_API_KEY"))
55
+
56
+ def __del__(self) -> None:
57
+ r"""Destructor for the E2BInterpreter class.
58
+
59
+ This method ensures that the e2b sandbox is killed when the
60
+ interpreter is deleted.
61
+ """
62
+ if (
63
+ hasattr(self, '_sandbox')
64
+ and self._sandbox is not None
65
+ and self._sandbox.is_running()
66
+ ):
67
+ self._sandbox.kill()
68
+
69
+ def run(
70
+ self,
71
+ code: str,
72
+ code_type: str,
73
+ ) -> str:
74
+ r"""Executes the given code in the e2b sandbox.
75
+
76
+ Args:
77
+ code (str): The code string to execute.
78
+ code_type (str): The type of code to execute (e.g., 'python',
79
+ 'bash').
80
+
81
+ Returns:
82
+ str: The string representation of the output of the executed code.
83
+
84
+ Raises:
85
+ InterpreterError: If the `code_type` is not supported or if any
86
+ runtime error occurs during the execution of the code.
87
+ """
88
+ if code_type not in self._CODE_TYPE_MAPPING:
89
+ raise InterpreterError(
90
+ f"Unsupported code type {code_type}. "
91
+ f"`{self.__class__.__name__}` only supports "
92
+ f"{', '.join(list(self._CODE_TYPE_MAPPING.keys()))}."
93
+ )
94
+ # Print code for security checking
95
+ if self.require_confirm:
96
+ logger.info(
97
+ f"The following {code_type} code will run on your "
98
+ "e2b sandbox: {code}"
99
+ )
100
+ while True:
101
+ choice = input("Running code? [Y/n]:").lower()
102
+ if choice in ["y", "yes", "ye"]:
103
+ break
104
+ elif choice not in ["no", "n"]:
105
+ continue
106
+ raise InterpreterError(
107
+ "Execution halted: User opted not to run the code. "
108
+ "This choice stops the current operation and any "
109
+ "further code execution."
110
+ )
111
+
112
+ if self._CODE_TYPE_MAPPING[code_type] is None:
113
+ execution = self._sandbox.run_code(code)
114
+ else:
115
+ execution = self._sandbox.run_code(
116
+ code=code, language=self._CODE_TYPE_MAPPING[code_type]
117
+ )
118
+
119
+ if execution.text and execution.text.lower() != "none":
120
+ return execution.text
121
+
122
+ if execution.logs:
123
+ if execution.logs.stdout:
124
+ return ",".join(execution.logs.stdout)
125
+ elif execution.logs.stderr:
126
+ return ",".join(execution.logs.stderr)
127
+
128
+ return str(execution.error)
129
+
130
+ def supported_code_types(self) -> List[str]:
131
+ r"""Provides supported code types by the interpreter."""
132
+ return list(self._CODE_TYPE_MAPPING.keys())
133
+
134
+ def update_action_space(self, action_space: Dict[str, Any]) -> None:
135
+ r"""Updates action space for *python* interpreter"""
136
+ raise RuntimeError("E2B doesn't support " "`action_space`.")
camel/loaders/__init__.py CHANGED
@@ -13,7 +13,7 @@
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
 
15
15
  from .apify_reader import Apify
16
- from .base_io import File
16
+ from .base_io import File, create_file, create_file_from_raw_bytes
17
17
  from .chunkr_reader import ChunkrReader
18
18
  from .firecrawl_reader import Firecrawl
19
19
  from .jina_url_reader import JinaURLReader
@@ -21,6 +21,8 @@ from .unstructured_io import UnstructuredIO
21
21
 
22
22
  __all__ = [
23
23
  'File',
24
+ 'create_file',
25
+ 'create_file_from_raw_bytes',
24
26
  'UnstructuredIO',
25
27
  'JinaURLReader',
26
28
  'Firecrawl',