camel-ai 0.2.35__py3-none-any.whl → 0.2.37__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 +1 -1
- camel/agents/__init__.py +2 -0
- camel/agents/repo_agent.py +579 -0
- camel/configs/__init__.py +3 -0
- camel/configs/aiml_config.py +20 -19
- camel/configs/anthropic_config.py +25 -27
- camel/configs/cohere_config.py +11 -10
- camel/configs/deepseek_config.py +16 -16
- camel/configs/gemini_config.py +8 -8
- camel/configs/groq_config.py +18 -19
- camel/configs/internlm_config.py +8 -8
- camel/configs/litellm_config.py +26 -24
- camel/configs/mistral_config.py +8 -8
- camel/configs/moonshot_config.py +11 -11
- camel/configs/nvidia_config.py +13 -13
- camel/configs/ollama_config.py +14 -15
- camel/configs/openai_config.py +3 -3
- camel/configs/openrouter_config.py +106 -0
- camel/configs/qwen_config.py +8 -8
- camel/configs/reka_config.py +12 -11
- camel/configs/samba_config.py +14 -14
- camel/configs/sglang_config.py +15 -16
- camel/configs/siliconflow_config.py +18 -17
- camel/configs/togetherai_config.py +18 -19
- camel/configs/vllm_config.py +18 -19
- camel/configs/yi_config.py +7 -8
- camel/configs/zhipuai_config.py +8 -9
- camel/datasets/few_shot_generator.py +2 -5
- camel/datasets/static_dataset.py +25 -23
- camel/environments/models.py +3 -0
- camel/environments/single_step.py +212 -132
- camel/extractors/__init__.py +16 -1
- camel/memories/agent_memories.py +2 -1
- camel/memories/blocks/chat_history_block.py +2 -1
- camel/models/__init__.py +2 -0
- camel/models/gemini_model.py +36 -0
- camel/models/groq_model.py +6 -3
- camel/models/model_factory.py +3 -0
- camel/models/openrouter_model.py +204 -0
- camel/storages/__init__.py +2 -0
- camel/storages/key_value_storages/__init__.py +2 -0
- camel/storages/key_value_storages/mem0_cloud.py +224 -0
- camel/storages/vectordb_storages/qdrant.py +3 -3
- camel/toolkits/__init__.py +2 -0
- camel/toolkits/browser_toolkit.py +43 -0
- camel/toolkits/code_execution.py +2 -1
- camel/toolkits/mcp_toolkit.py +30 -1
- camel/toolkits/thinking_toolkit.py +74 -0
- camel/types/enums.py +27 -0
- camel/types/unified_model_type.py +5 -0
- camel/utils/chunker/code_chunker.py +9 -15
- camel/verifiers/__init__.py +1 -2
- camel/verifiers/base.py +159 -99
- camel/verifiers/models.py +0 -12
- camel/verifiers/python_verifier.py +316 -60
- {camel_ai-0.2.35.dist-info → camel_ai-0.2.37.dist-info}/METADATA +54 -5
- {camel_ai-0.2.35.dist-info → camel_ai-0.2.37.dist-info}/RECORD +59 -54
- {camel_ai-0.2.35.dist-info → camel_ai-0.2.37.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.35.dist-info → camel_ai-0.2.37.dist-info}/licenses/LICENSE +0 -0
|
@@ -12,18 +12,21 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
|
+
import ast
|
|
15
16
|
import asyncio
|
|
16
17
|
import os
|
|
17
18
|
import shutil
|
|
18
19
|
import subprocess
|
|
20
|
+
import sys
|
|
19
21
|
import tempfile
|
|
20
22
|
import venv
|
|
21
|
-
from typing import List, Optional
|
|
23
|
+
from typing import List, Optional, Tuple
|
|
22
24
|
|
|
25
|
+
from camel.extractors.base import BaseExtractor
|
|
23
26
|
from camel.logger import get_logger
|
|
24
27
|
from camel.verifiers import BaseVerifier
|
|
25
28
|
|
|
26
|
-
from .models import VerificationOutcome, VerificationResult
|
|
29
|
+
from .models import VerificationOutcome, VerificationResult
|
|
27
30
|
|
|
28
31
|
logger = get_logger(__name__)
|
|
29
32
|
|
|
@@ -45,12 +48,16 @@ class PythonVerifier(BaseVerifier):
|
|
|
45
48
|
|
|
46
49
|
def __init__(
|
|
47
50
|
self,
|
|
51
|
+
extractor: Optional[BaseExtractor] = None,
|
|
48
52
|
timeout: Optional[float] = 30.0,
|
|
49
53
|
required_packages: Optional[List[str]] = None,
|
|
54
|
+
**kwargs,
|
|
50
55
|
):
|
|
51
56
|
r"""Initializes the PythonVerifier.
|
|
52
57
|
|
|
53
58
|
Args:
|
|
59
|
+
extractor (Optional[BaseExtractor], optional): The extractor to use
|
|
60
|
+
for extracting code from the solution. (default: :obj:`None`)
|
|
54
61
|
timeout (Optional[float], optional): The execution timeout in
|
|
55
62
|
seconds. (default: :obj:`30.0`)
|
|
56
63
|
required_packages (Optional[List[str]], optional): A list of
|
|
@@ -58,7 +65,7 @@ class PythonVerifier(BaseVerifier):
|
|
|
58
65
|
(default: :obj:`None`)
|
|
59
66
|
"""
|
|
60
67
|
# TODO: Use CAMEL's Interpreter to execute the code
|
|
61
|
-
super().__init__(timeout=timeout)
|
|
68
|
+
super().__init__(extractor=extractor, timeout=timeout, **kwargs)
|
|
62
69
|
self.venv_path: Optional[str] = None
|
|
63
70
|
self.required_packages = required_packages or []
|
|
64
71
|
|
|
@@ -67,25 +74,39 @@ class PythonVerifier(BaseVerifier):
|
|
|
67
74
|
else: # Unix-like systems
|
|
68
75
|
self.bin_dir = 'bin'
|
|
69
76
|
|
|
70
|
-
async def _setup(self) -> None:
|
|
71
|
-
r"""Set up a virtual environment
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
async def _setup(self, **kwargs) -> None:
|
|
78
|
+
r"""Set up a virtual environment and install required packages."""
|
|
79
|
+
uv = kwargs.get('uv', False)
|
|
80
|
+
if uv or self._is_uv_environment():
|
|
81
|
+
logger.info("[UV] Detected uv environment. Using uv for setup.")
|
|
82
|
+
self._setup_with_uv()
|
|
83
|
+
return
|
|
84
|
+
|
|
74
85
|
self.venv_path = tempfile.mkdtemp()
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
try:
|
|
87
|
+
venv.create(self.venv_path, with_pip=True)
|
|
88
|
+
logger.info(f"Virtual environment created at {self.venv_path}")
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.error(f"Failed to create virtual environment: {e}")
|
|
91
|
+
# Clean up resources before re-raising
|
|
92
|
+
if self.venv_path and os.path.exists(self.venv_path):
|
|
93
|
+
shutil.rmtree(self.venv_path)
|
|
94
|
+
self.venv_path = None
|
|
95
|
+
raise
|
|
77
96
|
|
|
78
97
|
venv_pip = os.path.join(self.venv_path, self.bin_dir, "pip")
|
|
79
98
|
|
|
80
99
|
if self.required_packages:
|
|
81
100
|
try:
|
|
101
|
+
# Add timeout to subprocess call
|
|
82
102
|
subprocess.run(
|
|
83
103
|
[venv_pip, "install", *self.required_packages],
|
|
84
104
|
check=True,
|
|
85
105
|
capture_output=True,
|
|
106
|
+
timeout=self._timeout,
|
|
86
107
|
)
|
|
87
108
|
logger.info(
|
|
88
|
-
"Installed required packages:"
|
|
109
|
+
"Installed required packages: "
|
|
89
110
|
f"{', '.join(self.required_packages)}"
|
|
90
111
|
)
|
|
91
112
|
except subprocess.CalledProcessError as e:
|
|
@@ -93,6 +114,97 @@ class PythonVerifier(BaseVerifier):
|
|
|
93
114
|
"Failed to install required packages: "
|
|
94
115
|
f"{e.stderr.decode().strip()}"
|
|
95
116
|
)
|
|
117
|
+
# Clean up resources before re-raising
|
|
118
|
+
if self.venv_path and os.path.exists(self.venv_path):
|
|
119
|
+
shutil.rmtree(self.venv_path)
|
|
120
|
+
self.venv_path = None
|
|
121
|
+
raise
|
|
122
|
+
except subprocess.TimeoutExpired:
|
|
123
|
+
logger.error(
|
|
124
|
+
f"Package installation timed out "
|
|
125
|
+
f"after {self._timeout} seconds"
|
|
126
|
+
)
|
|
127
|
+
if self.venv_path and os.path.exists(self.venv_path):
|
|
128
|
+
shutil.rmtree(self.venv_path)
|
|
129
|
+
self.venv_path = None
|
|
130
|
+
raise
|
|
131
|
+
|
|
132
|
+
def _is_uv_environment(self) -> bool:
|
|
133
|
+
r"""Detect whether the current Python runtime is managed by uv."""
|
|
134
|
+
return "UV_CACHE_DIR" in os.environ or "uv" in sys.executable
|
|
135
|
+
|
|
136
|
+
def _setup_with_uv(self) -> None:
|
|
137
|
+
r"""Create virtual environment and install packages using uv."""
|
|
138
|
+
self.venv_path = tempfile.mkdtemp()
|
|
139
|
+
try:
|
|
140
|
+
subprocess.run(
|
|
141
|
+
["uv", "venv", self.venv_path],
|
|
142
|
+
check=True,
|
|
143
|
+
capture_output=True,
|
|
144
|
+
timeout=self._timeout,
|
|
145
|
+
)
|
|
146
|
+
logger.info(
|
|
147
|
+
f"[UV] Virtual environment created at {self.venv_path}"
|
|
148
|
+
)
|
|
149
|
+
except subprocess.CalledProcessError as e:
|
|
150
|
+
logger.error(
|
|
151
|
+
"[UV] Failed to create virtual environment:\n"
|
|
152
|
+
f"{e.stderr.decode().strip()}"
|
|
153
|
+
)
|
|
154
|
+
# Clean up resources before re-raising
|
|
155
|
+
if self.venv_path and os.path.exists(self.venv_path):
|
|
156
|
+
shutil.rmtree(self.venv_path)
|
|
157
|
+
self.venv_path = None
|
|
158
|
+
raise
|
|
159
|
+
except subprocess.TimeoutExpired:
|
|
160
|
+
logger.error(
|
|
161
|
+
f"[UV] Virtual environment creation timed "
|
|
162
|
+
f"out after {self._timeout} seconds"
|
|
163
|
+
)
|
|
164
|
+
if self.venv_path and os.path.exists(self.venv_path):
|
|
165
|
+
shutil.rmtree(self.venv_path)
|
|
166
|
+
self.venv_path = None
|
|
167
|
+
raise
|
|
168
|
+
|
|
169
|
+
if self.required_packages:
|
|
170
|
+
venv_python = os.path.join(self.venv_path, self.bin_dir, "python")
|
|
171
|
+
try:
|
|
172
|
+
subprocess.run(
|
|
173
|
+
[
|
|
174
|
+
"uv",
|
|
175
|
+
"pip",
|
|
176
|
+
"install",
|
|
177
|
+
"--python",
|
|
178
|
+
venv_python,
|
|
179
|
+
*self.required_packages,
|
|
180
|
+
],
|
|
181
|
+
check=True,
|
|
182
|
+
capture_output=True,
|
|
183
|
+
timeout=self._timeout,
|
|
184
|
+
)
|
|
185
|
+
logger.info(
|
|
186
|
+
"[UV] Installed required packages via uv: "
|
|
187
|
+
f"{', '.join(self.required_packages)}"
|
|
188
|
+
)
|
|
189
|
+
except subprocess.CalledProcessError as e:
|
|
190
|
+
logger.error(
|
|
191
|
+
"[UV] Failed to install required packages via uv:\n"
|
|
192
|
+
f"{e.stderr.decode().strip()}"
|
|
193
|
+
)
|
|
194
|
+
# Clean up resources before re-raising
|
|
195
|
+
if self.venv_path and os.path.exists(self.venv_path):
|
|
196
|
+
shutil.rmtree(self.venv_path)
|
|
197
|
+
self.venv_path = None
|
|
198
|
+
raise
|
|
199
|
+
except subprocess.TimeoutExpired:
|
|
200
|
+
logger.error(
|
|
201
|
+
f"[UV] Package installation timed "
|
|
202
|
+
f"out after {self._timeout} seconds"
|
|
203
|
+
)
|
|
204
|
+
if self.venv_path and os.path.exists(self.venv_path):
|
|
205
|
+
shutil.rmtree(self.venv_path)
|
|
206
|
+
self.venv_path = None
|
|
207
|
+
raise
|
|
96
208
|
|
|
97
209
|
async def _cleanup(self) -> None:
|
|
98
210
|
r"""Clean up the virtual environment."""
|
|
@@ -102,25 +214,29 @@ class PythonVerifier(BaseVerifier):
|
|
|
102
214
|
self.venv_path = None
|
|
103
215
|
|
|
104
216
|
async def _verify_implementation(
|
|
105
|
-
self,
|
|
217
|
+
self, solution: str, ground_truth: Optional[str]
|
|
106
218
|
) -> VerificationResult:
|
|
107
|
-
r"""Executes the
|
|
108
|
-
|
|
219
|
+
r"""Executes the provided Python solution in an isolated environment
|
|
220
|
+
and verifies its output against an expected ground truth expression.
|
|
221
|
+
|
|
222
|
+
This method runs the solution in a subprocess inside a virtual
|
|
223
|
+
environment. The ground truth is assumed to be a pure Python
|
|
224
|
+
expression and is evaluated directly in the verifier process.
|
|
225
|
+
|
|
226
|
+
If both executions are successful, the actual output is compared
|
|
227
|
+
against the evaluated ground truth using semantic equality. If
|
|
228
|
+
evaluation fails, string comparison is used as a fallback.
|
|
109
229
|
|
|
110
230
|
Args:
|
|
111
|
-
|
|
112
|
-
|
|
231
|
+
solution (str): The Python code or expression to execute and
|
|
232
|
+
verify.
|
|
233
|
+
ground_truth (Optional[str]): The expected value as a Python
|
|
234
|
+
expression. If None, only execution success is verified.
|
|
113
235
|
|
|
114
236
|
Returns:
|
|
115
|
-
VerificationResult:
|
|
116
|
-
ERROR), execution output, error messages if any, and execution
|
|
117
|
-
duration.
|
|
118
|
-
|
|
119
|
-
Raises:
|
|
120
|
-
asyncio.TimeoutError: If execution exceeds the configured timeout.
|
|
121
|
-
Exception: Any unexpected errors during execution are caught and
|
|
122
|
-
converted to an ERROR verification result.
|
|
237
|
+
VerificationResult: Result of the verification process.
|
|
123
238
|
"""
|
|
239
|
+
# Check for virtual environment setup
|
|
124
240
|
if not self.venv_path:
|
|
125
241
|
return VerificationResult(
|
|
126
242
|
status=VerificationOutcome.ERROR,
|
|
@@ -128,9 +244,47 @@ class PythonVerifier(BaseVerifier):
|
|
|
128
244
|
error_message="Virtual environment is not set up.",
|
|
129
245
|
)
|
|
130
246
|
|
|
131
|
-
|
|
132
|
-
|
|
247
|
+
# If the solution is an expression, evaluate it directly
|
|
248
|
+
if self._is_expression(solution):
|
|
249
|
+
try:
|
|
250
|
+
sol_val = ast.literal_eval(solution)
|
|
251
|
+
except Exception as e:
|
|
252
|
+
return VerificationResult(
|
|
253
|
+
status=VerificationOutcome.ERROR,
|
|
254
|
+
result="",
|
|
255
|
+
error_message=f"Expression evaluation error: {e}",
|
|
256
|
+
)
|
|
133
257
|
|
|
258
|
+
if ground_truth is not None:
|
|
259
|
+
try:
|
|
260
|
+
gt_val = ast.literal_eval(ground_truth)
|
|
261
|
+
except Exception as e:
|
|
262
|
+
return VerificationResult(
|
|
263
|
+
status=VerificationOutcome.ERROR,
|
|
264
|
+
result="",
|
|
265
|
+
error_message=f"Ground truth evaluation error: {e}",
|
|
266
|
+
)
|
|
267
|
+
if sol_val == gt_val:
|
|
268
|
+
return VerificationResult(
|
|
269
|
+
status=VerificationOutcome.SUCCESS,
|
|
270
|
+
result=str(sol_val),
|
|
271
|
+
)
|
|
272
|
+
else:
|
|
273
|
+
return VerificationResult(
|
|
274
|
+
status=VerificationOutcome.FAILURE,
|
|
275
|
+
result=str(sol_val),
|
|
276
|
+
error_message="Output mismatch: "
|
|
277
|
+
f"{sol_val} != {gt_val}",
|
|
278
|
+
)
|
|
279
|
+
else:
|
|
280
|
+
return VerificationResult(
|
|
281
|
+
status=VerificationOutcome.SUCCESS,
|
|
282
|
+
result=str(sol_val),
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# Otherwise, run the code block,
|
|
286
|
+
# which should already include a print(...) in the end
|
|
287
|
+
venv_python = os.path.join(self.venv_path, self.bin_dir, "python")
|
|
134
288
|
if not os.path.exists(venv_python):
|
|
135
289
|
return VerificationResult(
|
|
136
290
|
status=VerificationOutcome.ERROR,
|
|
@@ -139,64 +293,166 @@ class PythonVerifier(BaseVerifier):
|
|
|
139
293
|
)
|
|
140
294
|
|
|
141
295
|
try:
|
|
142
|
-
|
|
143
|
-
venv_python
|
|
144
|
-
"-c",
|
|
145
|
-
script,
|
|
146
|
-
stdout=asyncio.subprocess.PIPE,
|
|
147
|
-
stderr=asyncio.subprocess.PIPE,
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
stdout, stderr = await asyncio.wait_for(
|
|
151
|
-
process.communicate(), timeout=self._timeout
|
|
296
|
+
sol_out, sol_err, sol_code = await self._run_code_block(
|
|
297
|
+
solution, venv_python
|
|
152
298
|
)
|
|
299
|
+
if sol_code != 0:
|
|
300
|
+
return VerificationResult(
|
|
301
|
+
status=VerificationOutcome.ERROR,
|
|
302
|
+
result=sol_out,
|
|
303
|
+
error_message=f"Solution code error:\n{sol_err}",
|
|
304
|
+
)
|
|
153
305
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
normalized_output = ' '.join(output_result.strip().split())
|
|
162
|
-
normalized_truth = ' '.join(
|
|
163
|
-
str(result.ground_truth).strip().split()
|
|
306
|
+
if ground_truth is not None:
|
|
307
|
+
try:
|
|
308
|
+
# First, try to evaluate the output as-is.
|
|
309
|
+
sol_val = ast.literal_eval(sol_out)
|
|
310
|
+
except Exception as e:
|
|
311
|
+
logger.warning(
|
|
312
|
+
f"Direct eval failed: {e}. Trying repr on output."
|
|
164
313
|
)
|
|
314
|
+
try:
|
|
315
|
+
# Try to convert sol_out to a literal
|
|
316
|
+
# by wrapping it with repr.
|
|
317
|
+
# FIXME: may be unnecessary
|
|
318
|
+
sol_val = ast.literal_eval(repr(sol_out))
|
|
319
|
+
except Exception as e2:
|
|
320
|
+
logger.warning(
|
|
321
|
+
f"repr eval also failed: {e2}."
|
|
322
|
+
"Falling back to string comparison."
|
|
323
|
+
)
|
|
324
|
+
sol_val = None
|
|
165
325
|
|
|
166
|
-
|
|
326
|
+
if sol_val is not None:
|
|
327
|
+
try:
|
|
328
|
+
gt_val = ast.literal_eval(ground_truth)
|
|
329
|
+
except Exception as e:
|
|
330
|
+
return VerificationResult(
|
|
331
|
+
status=VerificationOutcome.ERROR,
|
|
332
|
+
result="",
|
|
333
|
+
error_message="Ground truth evaluation error:"
|
|
334
|
+
f"{e}",
|
|
335
|
+
)
|
|
336
|
+
if sol_val == gt_val:
|
|
167
337
|
return VerificationResult(
|
|
168
338
|
status=VerificationOutcome.SUCCESS,
|
|
169
|
-
result=
|
|
339
|
+
result=sol_out,
|
|
170
340
|
)
|
|
171
341
|
else:
|
|
172
342
|
return VerificationResult(
|
|
173
343
|
status=VerificationOutcome.FAILURE,
|
|
174
|
-
|
|
175
|
-
|
|
344
|
+
result=sol_out,
|
|
345
|
+
error_message="Output mismatch: "
|
|
346
|
+
f"{sol_val} != {gt_val}",
|
|
176
347
|
)
|
|
177
348
|
else:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
349
|
+
# Fallback: string comparison
|
|
350
|
+
if sol_out.strip() == ground_truth.strip():
|
|
351
|
+
return VerificationResult(
|
|
352
|
+
status=VerificationOutcome.SUCCESS,
|
|
353
|
+
result=sol_out,
|
|
354
|
+
)
|
|
355
|
+
else:
|
|
356
|
+
return VerificationResult(
|
|
357
|
+
status=VerificationOutcome.FAILURE,
|
|
358
|
+
result=sol_out,
|
|
359
|
+
error_message="Fallback string mismatch: "
|
|
360
|
+
f"'{sol_out}' != '{ground_truth}'",
|
|
361
|
+
)
|
|
183
362
|
else:
|
|
184
363
|
return VerificationResult(
|
|
185
|
-
status=VerificationOutcome.
|
|
186
|
-
|
|
187
|
-
result=output_result,
|
|
364
|
+
status=VerificationOutcome.SUCCESS,
|
|
365
|
+
result=sol_out,
|
|
188
366
|
)
|
|
189
|
-
|
|
190
367
|
except asyncio.TimeoutError:
|
|
191
368
|
return VerificationResult(
|
|
192
369
|
status=VerificationOutcome.TIMEOUT,
|
|
193
370
|
result="",
|
|
194
371
|
error_message="Execution timed out.",
|
|
195
372
|
)
|
|
196
|
-
|
|
197
373
|
except Exception as e:
|
|
198
374
|
return VerificationResult(
|
|
199
375
|
status=VerificationOutcome.ERROR,
|
|
200
376
|
result="",
|
|
201
|
-
error_message=f"
|
|
377
|
+
error_message=f"Unexpected error: {e}",
|
|
202
378
|
)
|
|
379
|
+
|
|
380
|
+
async def _run_code_block(
|
|
381
|
+
self, code: str, venv_path: str
|
|
382
|
+
) -> Tuple[str, str, int]:
|
|
383
|
+
r"""Executes a block of Python code in the virtual environment.
|
|
384
|
+
|
|
385
|
+
The code is written to a temporary file, executed using the Python
|
|
386
|
+
interpreter from the specified virtual environment, and
|
|
387
|
+
its output and error streams are captured.
|
|
388
|
+
|
|
389
|
+
Args:
|
|
390
|
+
code (str): The Python code to execute.
|
|
391
|
+
venv_path (str): The path to the virtual environment's Python
|
|
392
|
+
binary.
|
|
393
|
+
|
|
394
|
+
Returns:
|
|
395
|
+
Tuple[str, str, int]: A tuple containing the stdout output,
|
|
396
|
+
stderr output, and return code from the executed script.
|
|
397
|
+
"""
|
|
398
|
+
# No longer checking for expressions since they're handled separately
|
|
399
|
+
with tempfile.NamedTemporaryFile(
|
|
400
|
+
"w+", suffix=".py", delete=False
|
|
401
|
+
) as tmp:
|
|
402
|
+
tmp.write(code)
|
|
403
|
+
tmp_path = tmp.name
|
|
404
|
+
|
|
405
|
+
proc = await asyncio.create_subprocess_exec(
|
|
406
|
+
venv_path,
|
|
407
|
+
tmp_path,
|
|
408
|
+
stdout=asyncio.subprocess.PIPE,
|
|
409
|
+
stderr=asyncio.subprocess.PIPE,
|
|
410
|
+
)
|
|
411
|
+
stdout, stderr = await asyncio.wait_for(
|
|
412
|
+
proc.communicate(), timeout=self._timeout
|
|
413
|
+
)
|
|
414
|
+
os.remove(tmp_path)
|
|
415
|
+
return (
|
|
416
|
+
stdout.decode().strip(),
|
|
417
|
+
stderr.decode().strip(),
|
|
418
|
+
proc.returncode if proc.returncode is not None else -1,
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
def _is_expression(self, code: str) -> bool:
|
|
422
|
+
r"""Determines whether a given string of code is a single expression.
|
|
423
|
+
|
|
424
|
+
This utility uses Python's AST module to parse the code and checks if
|
|
425
|
+
it consists of a single expression node.
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
code (str): The Python code to analyze.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
bool: True if the code is a single expression, False otherwise.
|
|
432
|
+
"""
|
|
433
|
+
# Skip empty or whitespace-only strings
|
|
434
|
+
if not code or code.isspace():
|
|
435
|
+
return False
|
|
436
|
+
|
|
437
|
+
try:
|
|
438
|
+
# First try parsing as an expression - this is more reliable than
|
|
439
|
+
# starting with literal_eval
|
|
440
|
+
tree = ast.parse(code.strip(), mode='eval')
|
|
441
|
+
# Check if it's a function call (like print()) - these should not
|
|
442
|
+
# be treated as expressions
|
|
443
|
+
if isinstance(tree.body, ast.Call):
|
|
444
|
+
return False
|
|
445
|
+
# If parsing succeeds in 'eval' mode and it's not a function call,
|
|
446
|
+
# it's a valid expression
|
|
447
|
+
return True
|
|
448
|
+
except SyntaxError:
|
|
449
|
+
# If parsing as expression fails, it's not a valid expression
|
|
450
|
+
return False
|
|
451
|
+
except Exception:
|
|
452
|
+
# For any other parsing errors, try literal_eval as fallback for
|
|
453
|
+
# simple literals
|
|
454
|
+
try:
|
|
455
|
+
ast.literal_eval(code)
|
|
456
|
+
return True
|
|
457
|
+
except Exception:
|
|
458
|
+
return False
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: camel-ai
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.37
|
|
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
|
|
@@ -58,6 +58,7 @@ Requires-Dist: jupyter-client<9,>=8.6.2; extra == 'all'
|
|
|
58
58
|
Requires-Dist: linkup-sdk<0.3,>=0.2.1; extra == 'all'
|
|
59
59
|
Requires-Dist: litellm<2,>=1.38.1; extra == 'all'
|
|
60
60
|
Requires-Dist: mcp>=1.3.0; extra == 'all'
|
|
61
|
+
Requires-Dist: mem0ai>=0.1.67; extra == 'all'
|
|
61
62
|
Requires-Dist: mistralai<2,>=1.1.0; extra == 'all'
|
|
62
63
|
Requires-Dist: mock<6,>=5; extra == 'all'
|
|
63
64
|
Requires-Dist: mypy<2,>=1.5.1; extra == 'all'
|
|
@@ -78,7 +79,7 @@ Requires-Dist: prance<24,>=23.6.21.0; extra == 'all'
|
|
|
78
79
|
Requires-Dist: praw<8,>=7.7.1; extra == 'all'
|
|
79
80
|
Requires-Dist: pre-commit<4,>=3; extra == 'all'
|
|
80
81
|
Requires-Dist: pydub<0.26,>=0.25.1; extra == 'all'
|
|
81
|
-
Requires-Dist: pygithub<3,>=2.
|
|
82
|
+
Requires-Dist: pygithub<3,>=2.6.0; extra == 'all'
|
|
82
83
|
Requires-Dist: pymilvus<3,>=2.4.0; extra == 'all'
|
|
83
84
|
Requires-Dist: pymupdf<2,>=1.22.5; extra == 'all'
|
|
84
85
|
Requires-Dist: pyowm<4,>=3.3.0; extra == 'all'
|
|
@@ -124,7 +125,7 @@ Provides-Extra: communication-tools
|
|
|
124
125
|
Requires-Dist: discord-py<3,>=2.3.2; extra == 'communication-tools'
|
|
125
126
|
Requires-Dist: notion-client<3,>=2.2.1; extra == 'communication-tools'
|
|
126
127
|
Requires-Dist: praw<8,>=7.7.1; extra == 'communication-tools'
|
|
127
|
-
Requires-Dist: pygithub<3,>=2.
|
|
128
|
+
Requires-Dist: pygithub<3,>=2.6.0; extra == 'communication-tools'
|
|
128
129
|
Requires-Dist: pytelegrambotapi<5,>=4.18.0; extra == 'communication-tools'
|
|
129
130
|
Requires-Dist: slack-bolt<2,>=1.20.1; extra == 'communication-tools'
|
|
130
131
|
Requires-Dist: slack-sdk<4,>=3.27.2; extra == 'communication-tools'
|
|
@@ -225,6 +226,7 @@ Provides-Extra: storage
|
|
|
225
226
|
Requires-Dist: azure-storage-blob<13,>=12.21.0; extra == 'storage'
|
|
226
227
|
Requires-Dist: botocore<2,>=1.35.3; extra == 'storage'
|
|
227
228
|
Requires-Dist: google-cloud-storage<3,>=2.18.0; extra == 'storage'
|
|
229
|
+
Requires-Dist: mem0ai>=0.1.73; extra == 'storage'
|
|
228
230
|
Requires-Dist: nebula3-python==3.8.2; extra == 'storage'
|
|
229
231
|
Requires-Dist: neo4j<6,>=5.18.0; extra == 'storage'
|
|
230
232
|
Requires-Dist: pymilvus<3,>=2.4.0; extra == 'storage'
|
|
@@ -443,9 +445,56 @@ Installing CAMEL is a breeze thanks to its availability on PyPI. Simply open you
|
|
|
443
445
|
pip install camel-ai
|
|
444
446
|
```
|
|
445
447
|
|
|
448
|
+
### Starting with ChatAgent
|
|
449
|
+
|
|
450
|
+
This example demonstrates how to create a `ChatAgent` using the CAMEL framework and perform a search query using DuckDuckGo.
|
|
451
|
+
|
|
452
|
+
1. **Install the tools package:**
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
pip install 'camel-ai[web_tools]'
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
2. **Set up your OpenAI API key:**
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
export OPENAI_API_KEY='your_openai_api_key'
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
3. **Run the following Python code:**
|
|
465
|
+
|
|
466
|
+
```python
|
|
467
|
+
from camel.models import ModelFactory
|
|
468
|
+
from camel.types import ModelPlatformType, ModelType
|
|
469
|
+
from camel.agents import ChatAgent
|
|
470
|
+
from camel.toolkits import SearchToolkit
|
|
471
|
+
|
|
472
|
+
model = ModelFactory.create(
|
|
473
|
+
model_platform=ModelPlatformType.OPENAI,
|
|
474
|
+
model_type=ModelType.GPT_4O,
|
|
475
|
+
model_config_dict={"temperature": 0.0},
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
search_tool = SearchToolkit().search_duckduckgo
|
|
479
|
+
|
|
480
|
+
agent = ChatAgent(model=model, tools=[search_tool])
|
|
481
|
+
|
|
482
|
+
response_1 = agent.step("What is CAMEL-AI?")
|
|
483
|
+
print(response_1.msgs[0].content)
|
|
484
|
+
# CAMEL-AI is the first LLM (Large Language Model) multi-agent framework
|
|
485
|
+
# and an open-source community focused on finding the scaling laws of agents.
|
|
486
|
+
# ...
|
|
487
|
+
|
|
488
|
+
response_2 = agent.step("What is the Github link to CAMEL framework?")
|
|
489
|
+
print(response_2.msgs[0].content)
|
|
490
|
+
# The GitHub link to the CAMEL framework is
|
|
491
|
+
# [https://github.com/camel-ai/camel](https://github.com/camel-ai/camel).
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
|
|
446
495
|
For more detailed instructions and additional configuration options, check out the [installation section](https://github.com/camel-ai/camel/blob/master/docs/get_started/installation.md).
|
|
447
496
|
|
|
448
|
-
After running, you can explore our CAMEL Tech Stack and Cookbooks at [
|
|
497
|
+
After running, you can explore our CAMEL Tech Stack and Cookbooks at [docs.camel-ai.org](https://docs.camel-ai.org) to build powerful multi-agent systems.
|
|
449
498
|
|
|
450
499
|
We provide a [](https://colab.research.google.com/drive/1AzP33O8rnMW__7ocWJhVBXjKziJXPtim?usp=sharing) demo showcasing a conversation between two ChatGPT agents playing roles as a python programmer and a stock trader collaborating on developing a trading bot for stock market.
|
|
451
500
|
|
|
@@ -503,7 +552,7 @@ We believe that studying these agents on a large scale offers valuable insights
|
|
|
503
552
|
</div>
|
|
504
553
|
|
|
505
554
|
<div align="center">
|
|
506
|
-
<a href="https://
|
|
555
|
+
<a href="https://agent-trust.camel-ai.org/">
|
|
507
556
|
<img src="docs/images/agent_trust.png" alt="Agent Trust">
|
|
508
557
|
</a>
|
|
509
558
|
</div>
|