camel-ai 0.2.37__py3-none-any.whl → 0.2.39__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/chat_agent.py +4 -0
- camel/agents/repo_agent.py +2 -2
- camel/benchmarks/apibank.py +1 -1
- camel/benchmarks/apibench.py +1 -1
- camel/configs/__init__.py +3 -0
- camel/configs/modelscope_config.py +59 -0
- camel/datagen/evol_instruct/__init__.py +20 -0
- camel/datagen/evol_instruct/evol_instruct.py +424 -0
- camel/datagen/evol_instruct/scorer.py +166 -0
- camel/datagen/evol_instruct/templates.py +268 -0
- camel/datagen/self_improving_cot.py +1 -1
- camel/datasets/__init__.py +2 -0
- camel/datasets/base_generator.py +22 -9
- camel/datasets/few_shot_generator.py +2 -3
- camel/datasets/self_instruct_generator.py +415 -0
- camel/embeddings/openai_compatible_embedding.py +13 -5
- camel/environments/models.py +10 -4
- camel/environments/single_step.py +181 -41
- camel/interpreters/docker_interpreter.py +2 -2
- camel/interpreters/e2b_interpreter.py +1 -1
- camel/interpreters/internal_python_interpreter.py +1 -1
- camel/interpreters/subprocess_interpreter.py +1 -1
- camel/loaders/__init__.py +2 -2
- camel/loaders/{panda_reader.py → pandas_reader.py} +61 -30
- camel/loaders/unstructured_io.py +2 -1
- camel/memories/blocks/chat_history_block.py +1 -1
- camel/memories/context_creators/score_based.py +198 -67
- camel/models/__init__.py +2 -0
- camel/models/aiml_model.py +9 -3
- camel/models/anthropic_model.py +11 -3
- camel/models/azure_openai_model.py +9 -3
- camel/models/base_audio_model.py +6 -0
- camel/models/base_model.py +4 -0
- camel/models/deepseek_model.py +9 -3
- camel/models/gemini_model.py +9 -3
- camel/models/groq_model.py +9 -3
- camel/models/internlm_model.py +8 -2
- camel/models/model_factory.py +123 -0
- camel/models/modelscope_model.py +208 -0
- camel/models/moonshot_model.py +8 -2
- camel/models/nemotron_model.py +9 -3
- camel/models/nvidia_model.py +9 -3
- camel/models/ollama_model.py +9 -3
- camel/models/openai_audio_models.py +7 -5
- camel/models/openai_compatible_model.py +9 -3
- camel/models/openai_model.py +58 -5
- camel/models/openrouter_model.py +9 -3
- camel/models/qwen_model.py +9 -3
- camel/models/samba_model.py +9 -3
- camel/models/sglang_model.py +11 -4
- camel/models/siliconflow_model.py +8 -2
- camel/models/stub_model.py +2 -1
- camel/models/togetherai_model.py +11 -5
- camel/models/vllm_model.py +10 -4
- camel/models/yi_model.py +9 -3
- camel/models/zhipuai_model.py +11 -5
- camel/retrievers/auto_retriever.py +14 -0
- camel/retrievers/vector_retriever.py +1 -1
- camel/storages/__init__.py +2 -0
- camel/storages/graph_storages/neo4j_graph.py +1 -1
- camel/storages/vectordb_storages/__init__.py +2 -0
- camel/storages/vectordb_storages/base.py +2 -2
- camel/storages/vectordb_storages/milvus.py +2 -2
- camel/storages/vectordb_storages/qdrant.py +2 -2
- camel/storages/vectordb_storages/tidb.py +332 -0
- camel/tasks/task.py +2 -2
- camel/toolkits/__init__.py +9 -1
- camel/toolkits/arxiv_toolkit.py +2 -1
- camel/toolkits/ask_news_toolkit.py +11 -3
- camel/toolkits/audio_analysis_toolkit.py +2 -0
- camel/toolkits/base.py +3 -0
- camel/toolkits/browser_toolkit.py +84 -61
- camel/toolkits/code_execution.py +3 -1
- camel/toolkits/dappier_toolkit.py +2 -1
- camel/toolkits/data_commons_toolkit.py +2 -0
- camel/toolkits/excel_toolkit.py +2 -0
- camel/toolkits/file_write_toolkit.py +2 -0
- camel/toolkits/github_toolkit.py +6 -4
- camel/toolkits/google_scholar_toolkit.py +2 -0
- camel/toolkits/human_toolkit.py +17 -1
- camel/toolkits/image_analysis_toolkit.py +2 -0
- camel/toolkits/linkedin_toolkit.py +2 -1
- camel/toolkits/math_toolkit.py +2 -0
- camel/toolkits/mcp_toolkit.py +42 -52
- camel/toolkits/meshy_toolkit.py +20 -2
- camel/toolkits/networkx_toolkit.py +2 -0
- camel/toolkits/notion_toolkit.py +7 -0
- camel/toolkits/openai_agent_toolkit.py +131 -0
- camel/toolkits/openbb_toolkit.py +2 -1
- camel/toolkits/pubmed_toolkit.py +2 -0
- camel/toolkits/reddit_toolkit.py +2 -1
- camel/toolkits/retrieval_toolkit.py +2 -1
- camel/toolkits/search_toolkit.py +2 -1
- camel/toolkits/searxng_toolkit.py +207 -0
- camel/toolkits/semantic_scholar_toolkit.py +2 -0
- camel/toolkits/slack_toolkit.py +2 -0
- camel/toolkits/stripe_toolkit.py +2 -1
- camel/toolkits/sympy_toolkit.py +2 -0
- camel/toolkits/terminal_toolkit.py +2 -0
- camel/toolkits/thinking_toolkit.py +168 -12
- camel/toolkits/twitter_toolkit.py +2 -1
- camel/toolkits/video_analysis_toolkit.py +2 -1
- camel/toolkits/video_download_toolkit.py +2 -1
- camel/toolkits/weather_toolkit.py +2 -0
- camel/toolkits/whatsapp_toolkit.py +2 -1
- camel/toolkits/zapier_toolkit.py +2 -1
- camel/types/enums.py +66 -0
- camel/types/unified_model_type.py +5 -0
- camel/utils/__init__.py +2 -0
- camel/utils/chunker/code_chunker.py +9 -9
- camel/utils/commons.py +50 -30
- camel/utils/constants.py +2 -2
- camel/utils/mcp.py +79 -0
- camel/verifiers/__init__.py +2 -0
- camel/verifiers/base.py +15 -15
- camel/verifiers/math_verifier.py +182 -0
- camel/verifiers/python_verifier.py +28 -28
- {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/METADATA +54 -4
- {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/RECORD +122 -110
- {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/licenses/LICENSE +0 -0
camel/types/enums.py
CHANGED
|
@@ -217,6 +217,29 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
217
217
|
AIML_MIXTRAL_8X7B = "mistralai/Mixtral-8x7B-Instruct-v0.1"
|
|
218
218
|
AIML_MISTRAL_7B_INSTRUCT = "mistralai/Mistral-7B-Instruct-v0.1"
|
|
219
219
|
|
|
220
|
+
# ModelScope models support tool calling
|
|
221
|
+
MODELSCOPE_QWEN_2_5_7B_INSTRUCT = "Qwen/Qwen2.5-7B-Instruct"
|
|
222
|
+
MODELSCOPE_QWEN_2_5_14B_INSTRUCT = "Qwen/Qwen2.5-14B-Instruct"
|
|
223
|
+
MODELSCOPE_QWEN_2_5_32B_INSTRUCT = "Qwen/Qwen2.5-32B-Instruct"
|
|
224
|
+
MODELSCOPE_QWEN_2_5_72B_INSTRUCT = "Qwen/Qwen2.5-72B-Instruct"
|
|
225
|
+
MODELSCOPE_QWEN_2_5_CODER_7B_INSTRUCT = "Qwen/Qwen2.5-Coder-7B-Instruct"
|
|
226
|
+
MODELSCOPE_QWEN_2_5_CODER_14B_INSTRUCT = "Qwen/Qwen2.5-Coder-14B-Instruct"
|
|
227
|
+
MODELSCOPE_QWEN_2_5_CODER_32B_INSTRUCT = "Qwen/Qwen2.5-Coder-32B-Instruct"
|
|
228
|
+
MODELSCOPE_QWQ_32B = "Qwen/QwQ-32B"
|
|
229
|
+
MODELSCOPE_QWQ_32B_PREVIEW = "Qwen/QwQ-32B-Preview"
|
|
230
|
+
MODELSCOPE_LLAMA_3_1_8B_INSTRUCT = (
|
|
231
|
+
"LLM-Research/Meta-Llama-3.1-8B-Instruct"
|
|
232
|
+
)
|
|
233
|
+
MODELSCOPE_LLAMA_3_1_70B_INSTRUCT = (
|
|
234
|
+
"LLM-Research/Meta-Llama-3.1-70B-Instruct"
|
|
235
|
+
)
|
|
236
|
+
MODELSCOPE_LLAMA_3_1_405B_INSTRUCT = (
|
|
237
|
+
"LLM-Research/Meta-Llama-3.1-405B-Instruct"
|
|
238
|
+
)
|
|
239
|
+
MODELSCOPE_LLAMA_3_3_70B_INSTRUCT = "LLM-Research/Llama-3.3-70B-Instruct"
|
|
240
|
+
MODELSCOPE_MINISTRAL_8B_INSTRUCT = "mistralai/Ministral-8B-Instruct-2410"
|
|
241
|
+
MODELSCOPE_DEEPSEEK_V3_0324 = "deepseek-ai/DeepSeek-V3-0324"
|
|
242
|
+
|
|
220
243
|
def __str__(self):
|
|
221
244
|
return self.value
|
|
222
245
|
|
|
@@ -263,6 +286,7 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
263
286
|
self.is_sglang,
|
|
264
287
|
self.is_moonshot,
|
|
265
288
|
self.is_siliconflow,
|
|
289
|
+
self.is_modelscope,
|
|
266
290
|
self.is_zhipuai,
|
|
267
291
|
self.is_aiml,
|
|
268
292
|
self.is_azure_openai,
|
|
@@ -515,6 +539,26 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
515
539
|
ModelType.INTERNLM2_PRO_CHAT,
|
|
516
540
|
}
|
|
517
541
|
|
|
542
|
+
@property
|
|
543
|
+
def is_modelscope(self) -> bool:
|
|
544
|
+
return self in {
|
|
545
|
+
ModelType.MODELSCOPE_QWEN_2_5_7B_INSTRUCT,
|
|
546
|
+
ModelType.MODELSCOPE_QWEN_2_5_14B_INSTRUCT,
|
|
547
|
+
ModelType.MODELSCOPE_QWEN_2_5_32B_INSTRUCT,
|
|
548
|
+
ModelType.MODELSCOPE_QWEN_2_5_72B_INSTRUCT,
|
|
549
|
+
ModelType.MODELSCOPE_QWEN_2_5_CODER_7B_INSTRUCT,
|
|
550
|
+
ModelType.MODELSCOPE_QWEN_2_5_CODER_14B_INSTRUCT,
|
|
551
|
+
ModelType.MODELSCOPE_QWEN_2_5_CODER_32B_INSTRUCT,
|
|
552
|
+
ModelType.MODELSCOPE_QWQ_32B,
|
|
553
|
+
ModelType.MODELSCOPE_QWQ_32B_PREVIEW,
|
|
554
|
+
ModelType.MODELSCOPE_LLAMA_3_1_8B_INSTRUCT,
|
|
555
|
+
ModelType.MODELSCOPE_LLAMA_3_1_70B_INSTRUCT,
|
|
556
|
+
ModelType.MODELSCOPE_LLAMA_3_1_405B_INSTRUCT,
|
|
557
|
+
ModelType.MODELSCOPE_LLAMA_3_3_70B_INSTRUCT,
|
|
558
|
+
ModelType.MODELSCOPE_MINISTRAL_8B_INSTRUCT,
|
|
559
|
+
ModelType.MODELSCOPE_DEEPSEEK_V3_0324,
|
|
560
|
+
}
|
|
561
|
+
|
|
518
562
|
@property
|
|
519
563
|
def is_moonshot(self) -> bool:
|
|
520
564
|
return self in {
|
|
@@ -638,6 +682,21 @@ class ModelType(UnifiedModelType, Enum):
|
|
|
638
682
|
ModelType.MOONSHOT_V1_32K,
|
|
639
683
|
ModelType.AIML_MIXTRAL_8X7B,
|
|
640
684
|
ModelType.AIML_MISTRAL_7B_INSTRUCT,
|
|
685
|
+
ModelType.MODELSCOPE_QWEN_2_5_7B_INSTRUCT,
|
|
686
|
+
ModelType.MODELSCOPE_QWEN_2_5_14B_INSTRUCT,
|
|
687
|
+
ModelType.MODELSCOPE_QWEN_2_5_32B_INSTRUCT,
|
|
688
|
+
ModelType.MODELSCOPE_QWEN_2_5_72B_INSTRUCT,
|
|
689
|
+
ModelType.MODELSCOPE_QWEN_2_5_CODER_7B_INSTRUCT,
|
|
690
|
+
ModelType.MODELSCOPE_QWEN_2_5_CODER_14B_INSTRUCT,
|
|
691
|
+
ModelType.MODELSCOPE_QWEN_2_5_CODER_32B_INSTRUCT,
|
|
692
|
+
ModelType.MODELSCOPE_QWQ_32B,
|
|
693
|
+
ModelType.MODELSCOPE_QWQ_32B_PREVIEW,
|
|
694
|
+
ModelType.MODELSCOPE_LLAMA_3_1_8B_INSTRUCT,
|
|
695
|
+
ModelType.MODELSCOPE_LLAMA_3_1_70B_INSTRUCT,
|
|
696
|
+
ModelType.MODELSCOPE_LLAMA_3_1_405B_INSTRUCT,
|
|
697
|
+
ModelType.MODELSCOPE_LLAMA_3_3_70B_INSTRUCT,
|
|
698
|
+
ModelType.MODELSCOPE_MINISTRAL_8B_INSTRUCT,
|
|
699
|
+
ModelType.MODELSCOPE_DEEPSEEK_V3_0324,
|
|
641
700
|
}:
|
|
642
701
|
return 32_768
|
|
643
702
|
elif self in {
|
|
@@ -882,6 +941,7 @@ class OpenAIVisionDetailType(Enum):
|
|
|
882
941
|
class StorageType(Enum):
|
|
883
942
|
MILVUS = "milvus"
|
|
884
943
|
QDRANT = "qdrant"
|
|
944
|
+
TIDB = "tidb"
|
|
885
945
|
|
|
886
946
|
|
|
887
947
|
class OpenAPIName(Enum):
|
|
@@ -921,6 +981,7 @@ class ModelPlatformType(Enum):
|
|
|
921
981
|
SGLANG = "sglang"
|
|
922
982
|
INTERNLM = "internlm"
|
|
923
983
|
MOONSHOT = "moonshot"
|
|
984
|
+
MODELSCOPE = "modelscope"
|
|
924
985
|
SILICONFLOW = "siliconflow"
|
|
925
986
|
AIML = "aiml"
|
|
926
987
|
VOLCANO = "volcano"
|
|
@@ -1049,6 +1110,11 @@ class ModelPlatformType(Enum):
|
|
|
1049
1110
|
r"""Returns whether this platform is Moonshot model."""
|
|
1050
1111
|
return self is ModelPlatformType.MOONSHOT
|
|
1051
1112
|
|
|
1113
|
+
@property
|
|
1114
|
+
def is_modelscope(self) -> bool:
|
|
1115
|
+
r"""Returns whether this platform is ModelScope model."""
|
|
1116
|
+
return self is ModelPlatformType.MODELSCOPE
|
|
1117
|
+
|
|
1052
1118
|
@property
|
|
1053
1119
|
def is_siliconflow(self) -> bool:
|
|
1054
1120
|
r"""Returns whether this platform is SiliconFlow."""
|
|
@@ -123,6 +123,11 @@ class UnifiedModelType(str):
|
|
|
123
123
|
r"""Returns whether the model is a InternLM model."""
|
|
124
124
|
return True
|
|
125
125
|
|
|
126
|
+
@property
|
|
127
|
+
def is_modelscope(self) -> bool:
|
|
128
|
+
r"""Returns whether the model is a ModelScope serverd model."""
|
|
129
|
+
return True
|
|
130
|
+
|
|
126
131
|
@property
|
|
127
132
|
def is_moonshot(self) -> bool:
|
|
128
133
|
r"""Returns whether this platform is Moonshot model."""
|
camel/utils/__init__.py
CHANGED
|
@@ -41,6 +41,7 @@ from .commons import (
|
|
|
41
41
|
)
|
|
42
42
|
from .constants import Constants
|
|
43
43
|
from .deduplication import DeduplicationResult, deduplicate_internally
|
|
44
|
+
from .mcp import MCPServer
|
|
44
45
|
from .response_format import get_pydantic_model
|
|
45
46
|
from .token_counting import (
|
|
46
47
|
AnthropicTokenCounter,
|
|
@@ -88,4 +89,5 @@ __all__ = [
|
|
|
88
89
|
"retry_on_error",
|
|
89
90
|
"BatchProcessor",
|
|
90
91
|
"with_timeout",
|
|
92
|
+
"MCPServer",
|
|
91
93
|
]
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import re
|
|
15
|
-
from typing import List, Optional
|
|
15
|
+
from typing import TYPE_CHECKING, List, Optional
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from unstructured.documents.elements import Element
|
|
18
19
|
|
|
19
20
|
from camel.utils import get_model_encoding
|
|
20
21
|
|
|
@@ -23,18 +24,15 @@ from .base import BaseChunker
|
|
|
23
24
|
|
|
24
25
|
class CodeChunker(BaseChunker):
|
|
25
26
|
r"""A class for chunking code or text while respecting structure
|
|
26
|
-
|
|
27
|
+
and token limits.
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
This class ensures that structured elements such as functions,
|
|
30
|
+
classes, and regions are not arbitrarily split across chunks.
|
|
31
|
+
It also handles oversized lines and Base64-encoded images.
|
|
31
32
|
|
|
32
33
|
Attributes:
|
|
33
34
|
chunk_size (int, optional): The maximum token size per chunk.
|
|
34
35
|
(default: :obj:`8192`)
|
|
35
|
-
token_counter (BaseTokenCounter, optional): The tokenizer used for
|
|
36
|
-
token counting, if `None`, OpenAITokenCounter will be used.
|
|
37
|
-
(default: :obj:`None`)
|
|
38
36
|
remove_image: (bool, optional): If the chunker should skip the images.
|
|
39
37
|
model_name (str, optional): The tokenizer model name used
|
|
40
38
|
for token counting. (default: :obj:`"cl100k_base"`)
|
|
@@ -108,6 +106,8 @@ class CodeChunker(BaseChunker):
|
|
|
108
106
|
Returns:
|
|
109
107
|
List[str]: A list of chunked text segments.
|
|
110
108
|
"""
|
|
109
|
+
from unstructured.documents.elements import Element, ElementMetadata
|
|
110
|
+
|
|
111
111
|
content_str = "\n".join(map(str, content))
|
|
112
112
|
chunks = []
|
|
113
113
|
current_chunk: list[str] = []
|
camel/utils/commons.py
CHANGED
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
+
import asyncio
|
|
14
15
|
import functools
|
|
15
16
|
import importlib
|
|
17
|
+
import inspect
|
|
16
18
|
import logging
|
|
17
19
|
import os
|
|
18
20
|
import platform
|
|
@@ -161,7 +163,7 @@ def get_task_list(task_response: str) -> List[str]:
|
|
|
161
163
|
|
|
162
164
|
|
|
163
165
|
def check_server_running(server_url: str) -> bool:
|
|
164
|
-
r"""Check whether the port
|
|
166
|
+
r"""Check whether the port referred by the URL to the server
|
|
165
167
|
is open.
|
|
166
168
|
|
|
167
169
|
Args:
|
|
@@ -978,36 +980,54 @@ def with_timeout(timeout=None):
|
|
|
978
980
|
"""
|
|
979
981
|
|
|
980
982
|
def decorator(func):
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
def target():
|
|
996
|
-
result_container.append(func(*args, **kwargs))
|
|
997
|
-
|
|
998
|
-
# Start the function in a new thread
|
|
999
|
-
thread = threading.Thread(target=target)
|
|
1000
|
-
thread.start()
|
|
1001
|
-
thread.join(effective_timeout)
|
|
1002
|
-
|
|
1003
|
-
# Check if the thread is still alive after the timeout
|
|
1004
|
-
if thread.is_alive():
|
|
1005
|
-
return (
|
|
1006
|
-
f"Function `{func.__name__}` execution timed out, "
|
|
1007
|
-
f"exceeded {effective_timeout} seconds."
|
|
983
|
+
if inspect.iscoroutinefunction(func):
|
|
984
|
+
|
|
985
|
+
@functools.wraps(func)
|
|
986
|
+
async def async_wrapper(*args, **kwargs):
|
|
987
|
+
eff_timeout = timeout
|
|
988
|
+
if eff_timeout is None and args:
|
|
989
|
+
eff_timeout = getattr(args[0], 'timeout', None)
|
|
990
|
+
|
|
991
|
+
if eff_timeout is None:
|
|
992
|
+
return await func(*args, **kwargs)
|
|
993
|
+
|
|
994
|
+
return await asyncio.wait_for(
|
|
995
|
+
func(*args, **kwargs), timeout=eff_timeout
|
|
1008
996
|
)
|
|
1009
|
-
|
|
1010
|
-
|
|
997
|
+
|
|
998
|
+
return async_wrapper
|
|
999
|
+
else:
|
|
1000
|
+
|
|
1001
|
+
@functools.wraps(func)
|
|
1002
|
+
def wrapper(*args, **kwargs):
|
|
1003
|
+
# Determine the effective timeout value
|
|
1004
|
+
effective_timeout = timeout
|
|
1005
|
+
if effective_timeout is None and args:
|
|
1006
|
+
effective_timeout = getattr(args[0], 'timeout', None)
|
|
1007
|
+
|
|
1008
|
+
# If no timeout value is provided, execute function normally
|
|
1009
|
+
if effective_timeout is None:
|
|
1010
|
+
return func(*args, **kwargs)
|
|
1011
|
+
|
|
1012
|
+
# Container to hold the result of the function call
|
|
1013
|
+
result_container = []
|
|
1014
|
+
|
|
1015
|
+
def target():
|
|
1016
|
+
result_container.append(func(*args, **kwargs))
|
|
1017
|
+
|
|
1018
|
+
# Start the function in a new thread
|
|
1019
|
+
thread = threading.Thread(target=target)
|
|
1020
|
+
thread.start()
|
|
1021
|
+
thread.join(effective_timeout)
|
|
1022
|
+
|
|
1023
|
+
# Check if the thread is still alive after the timeout
|
|
1024
|
+
if thread.is_alive():
|
|
1025
|
+
return (
|
|
1026
|
+
f"Function `{func.__name__}` execution timed out, "
|
|
1027
|
+
f"exceeded {effective_timeout} seconds."
|
|
1028
|
+
)
|
|
1029
|
+
else:
|
|
1030
|
+
return result_container[0]
|
|
1011
1031
|
|
|
1012
1032
|
return wrapper
|
|
1013
1033
|
|
camel/utils/constants.py
CHANGED
|
@@ -30,8 +30,8 @@ class Constants:
|
|
|
30
30
|
# Return response with json format
|
|
31
31
|
FUNC_NAME_FOR_STRUCTURED_OUTPUT = "return_json_response"
|
|
32
32
|
|
|
33
|
-
# Default top k
|
|
33
|
+
# Default top k value for RAG
|
|
34
34
|
DEFAULT_TOP_K_RESULTS = 1
|
|
35
35
|
|
|
36
|
-
# Default similarity threshold
|
|
36
|
+
# Default similarity threshold value for RAG
|
|
37
37
|
DEFAULT_SIMILARITY_THRESHOLD = 0.7
|
camel/utils/mcp.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
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 functools
|
|
15
|
+
import inspect
|
|
16
|
+
from typing import Any, Callable, Optional
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MCPServer:
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
function_names: Optional[list[str]] = None,
|
|
23
|
+
server_name: Optional[str] = None,
|
|
24
|
+
):
|
|
25
|
+
self.function_names = function_names
|
|
26
|
+
self.server_name = server_name
|
|
27
|
+
|
|
28
|
+
def make_wrapper(self, func: Callable[..., Any]) -> Callable[..., Any]:
|
|
29
|
+
if inspect.iscoroutinefunction(func):
|
|
30
|
+
|
|
31
|
+
@functools.wraps(func)
|
|
32
|
+
async def wrapper(*args, **kwargs):
|
|
33
|
+
return await func(*args, **kwargs)
|
|
34
|
+
else:
|
|
35
|
+
|
|
36
|
+
@functools.wraps(func)
|
|
37
|
+
def wrapper(*args, **kwargs):
|
|
38
|
+
return func(*args, **kwargs)
|
|
39
|
+
|
|
40
|
+
wrapper.__signature__ = inspect.signature(func) # type: ignore[attr-defined]
|
|
41
|
+
return wrapper
|
|
42
|
+
|
|
43
|
+
def __call__(self, cls):
|
|
44
|
+
from mcp.server.fastmcp import FastMCP
|
|
45
|
+
|
|
46
|
+
from camel.toolkits.base import BaseToolkit
|
|
47
|
+
|
|
48
|
+
original_init = cls.__init__
|
|
49
|
+
|
|
50
|
+
def new_init(instance, *args, **kwargs):
|
|
51
|
+
original_init(instance, *args, **kwargs)
|
|
52
|
+
self.server_name = self.server_name or cls.__name__
|
|
53
|
+
instance.mcp = FastMCP(self.server_name)
|
|
54
|
+
|
|
55
|
+
if not self.function_names and not isinstance(
|
|
56
|
+
instance, BaseToolkit
|
|
57
|
+
):
|
|
58
|
+
raise ValueError(
|
|
59
|
+
"Please specify function names or use BaseToolkit."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
function_names = self.function_names
|
|
63
|
+
if not function_names and isinstance(instance, BaseToolkit):
|
|
64
|
+
function_names = [
|
|
65
|
+
tool.get_function_name() for tool in instance.get_tools()
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
for name in function_names:
|
|
69
|
+
func = getattr(instance, name, None)
|
|
70
|
+
if func is None or not callable(func):
|
|
71
|
+
raise ValueError(
|
|
72
|
+
f"Method {name} not found in class {cls.__name} or "
|
|
73
|
+
"cannot be called."
|
|
74
|
+
)
|
|
75
|
+
wrapper = self.make_wrapper(func)
|
|
76
|
+
instance.mcp.tool(name=name)(wrapper)
|
|
77
|
+
|
|
78
|
+
cls.__init__ = new_init
|
|
79
|
+
return cls
|
camel/verifiers/__init__.py
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
from .base import BaseVerifier
|
|
15
|
+
from .math_verifier import MathVerifier
|
|
15
16
|
from .models import VerificationOutcome
|
|
16
17
|
from .python_verifier import PythonVerifier
|
|
17
18
|
|
|
@@ -19,4 +20,5 @@ __all__ = [
|
|
|
19
20
|
"BaseVerifier",
|
|
20
21
|
"VerificationOutcome",
|
|
21
22
|
"PythonVerifier",
|
|
23
|
+
"MathVerifier",
|
|
22
24
|
]
|
camel/verifiers/base.py
CHANGED
|
@@ -163,7 +163,7 @@ class BaseVerifier(ABC):
|
|
|
163
163
|
pass
|
|
164
164
|
|
|
165
165
|
async def verify(
|
|
166
|
-
self, solution: str,
|
|
166
|
+
self, solution: str, reference_answer: Optional[str]
|
|
167
167
|
) -> VerificationResult:
|
|
168
168
|
r"""Perform verification with full error handling.
|
|
169
169
|
|
|
@@ -174,7 +174,7 @@ class BaseVerifier(ABC):
|
|
|
174
174
|
|
|
175
175
|
Args:
|
|
176
176
|
solution (str): The generated response that needs verification.
|
|
177
|
-
|
|
177
|
+
reference_answer (Optional[str]): The expected correct answer to
|
|
178
178
|
compare against.
|
|
179
179
|
|
|
180
180
|
Returns:
|
|
@@ -215,13 +215,13 @@ class BaseVerifier(ABC):
|
|
|
215
215
|
verification_result = (
|
|
216
216
|
await asyncio.wait_for(
|
|
217
217
|
self._verify_implementation(
|
|
218
|
-
verifiable_solution,
|
|
218
|
+
verifiable_solution, reference_answer
|
|
219
219
|
),
|
|
220
220
|
timeout=self._timeout,
|
|
221
221
|
)
|
|
222
222
|
if self._timeout
|
|
223
223
|
else await self._verify_implementation(
|
|
224
|
-
verifiable_solution,
|
|
224
|
+
verifiable_solution, reference_answer
|
|
225
225
|
)
|
|
226
226
|
)
|
|
227
227
|
|
|
@@ -267,7 +267,7 @@ class BaseVerifier(ABC):
|
|
|
267
267
|
|
|
268
268
|
@abstractmethod
|
|
269
269
|
async def _verify_implementation(
|
|
270
|
-
self, solution: str,
|
|
270
|
+
self, solution: str, reference_answer: Optional[str]
|
|
271
271
|
) -> VerificationResult:
|
|
272
272
|
r"""Abstract method for verification logic.
|
|
273
273
|
|
|
@@ -276,7 +276,7 @@ class BaseVerifier(ABC):
|
|
|
276
276
|
|
|
277
277
|
Args:
|
|
278
278
|
solution (str): The generated response requiring verification.
|
|
279
|
-
|
|
279
|
+
reference_answer (Optional[str]): The expected reference output.
|
|
280
280
|
|
|
281
281
|
Returns:
|
|
282
282
|
VerificationResult: Contains verification status and details.
|
|
@@ -293,7 +293,7 @@ class BaseVerifier(ABC):
|
|
|
293
293
|
async def verify_batch(
|
|
294
294
|
self,
|
|
295
295
|
solutions: List[str],
|
|
296
|
-
|
|
296
|
+
reference_answers: List[Optional[str]],
|
|
297
297
|
raise_on_error: bool = False,
|
|
298
298
|
) -> List[VerificationResult]:
|
|
299
299
|
r"""Verify multiple solutions in parallel with controlled concurrency.
|
|
@@ -305,8 +305,8 @@ class BaseVerifier(ABC):
|
|
|
305
305
|
Args:
|
|
306
306
|
solutions (List[str]): A list of generated solutions to be
|
|
307
307
|
verified.
|
|
308
|
-
|
|
309
|
-
comparison. Each element corresponds to a solution.
|
|
308
|
+
reference_answers (List[Optional[str]]): A list of expected outputs
|
|
309
|
+
for comparison. Each element corresponds to a solution.
|
|
310
310
|
raise_on_error (bool, optional): If True, raises an exception if
|
|
311
311
|
any verification fails. (default: :obj:`False`)
|
|
312
312
|
|
|
@@ -337,13 +337,13 @@ class BaseVerifier(ABC):
|
|
|
337
337
|
semaphore = asyncio.Semaphore(max(1, max_workers))
|
|
338
338
|
|
|
339
339
|
async def _verify_with_semaphore(
|
|
340
|
-
solution: str,
|
|
340
|
+
solution: str, reference_answer: Optional[str]
|
|
341
341
|
) -> VerificationResult:
|
|
342
342
|
start_time = time.time()
|
|
343
343
|
try:
|
|
344
344
|
async with semaphore:
|
|
345
345
|
verification_result = await self.verify(
|
|
346
|
-
solution,
|
|
346
|
+
solution, reference_answer
|
|
347
347
|
)
|
|
348
348
|
processing_time = time.time() - start_time
|
|
349
349
|
success = (
|
|
@@ -368,12 +368,12 @@ class BaseVerifier(ABC):
|
|
|
368
368
|
all_results: List[VerificationResult] = []
|
|
369
369
|
for i in range(0, len(solutions), batch_size):
|
|
370
370
|
batch_solutions = solutions[i : i + batch_size]
|
|
371
|
-
|
|
371
|
+
batch_reference_answers = reference_answers[i : i + batch_size]
|
|
372
372
|
|
|
373
373
|
verification_tasks = [
|
|
374
|
-
_verify_with_semaphore(solution,
|
|
375
|
-
for solution,
|
|
376
|
-
batch_solutions,
|
|
374
|
+
_verify_with_semaphore(solution, reference_answer)
|
|
375
|
+
for solution, reference_answer in zip(
|
|
376
|
+
batch_solutions, batch_reference_answers
|
|
377
377
|
)
|
|
378
378
|
]
|
|
379
379
|
try:
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
# See the License for the specific language governing permissions and
|
|
12
|
+
# limitations under the License.
|
|
13
|
+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
+
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
from camel.extractors.base import BaseExtractor
|
|
18
|
+
from camel.logger import get_logger
|
|
19
|
+
from camel.verifiers import BaseVerifier
|
|
20
|
+
from camel.verifiers.models import VerificationOutcome, VerificationResult
|
|
21
|
+
|
|
22
|
+
logger = get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MathVerifier(BaseVerifier):
|
|
26
|
+
r"""Verifier for mathematical expressions using Math-Verify.
|
|
27
|
+
|
|
28
|
+
Features:
|
|
29
|
+
- Supports LaTeX and plain mathematical expressions
|
|
30
|
+
- Handles complex numbers, matrices, and sets
|
|
31
|
+
- Configurable precision for floating-point comparisons
|
|
32
|
+
- Optional LaTeX wrapping to ensure proper parsing and rendering
|
|
33
|
+
- Comprehensive error handling and logging
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
extractor: Optional[BaseExtractor] = None,
|
|
39
|
+
timeout: Optional[float] = 30.0,
|
|
40
|
+
float_rounding: int = 6,
|
|
41
|
+
numeric_precision: int = 15,
|
|
42
|
+
enable_wrapping: Optional[bool] = False,
|
|
43
|
+
**kwargs,
|
|
44
|
+
):
|
|
45
|
+
r"""Initializes the MathVerifier.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
extractor (Optional[BaseExtractor], optional): The extractor to use
|
|
49
|
+
for extracting code from the solution. (default: :obj:`None`)
|
|
50
|
+
timeout (Optional[float], optional): The execution timeout in
|
|
51
|
+
seconds. (default: :obj:`30.0`)
|
|
52
|
+
float_rounding (int, optional): The number of decimal places to
|
|
53
|
+
round floating-point numbers. (default: :obj:`6`)
|
|
54
|
+
numeric_precision (int, optional): The numeric precision for
|
|
55
|
+
floating-point comparisons. (default: :obj:`15`)
|
|
56
|
+
enable_wrapping (Optional[bool], optional): Whether to wrap LaTeX
|
|
57
|
+
expressions in math mode delimiters. (default: :obj:`False`)
|
|
58
|
+
"""
|
|
59
|
+
super().__init__(extractor=extractor, timeout=timeout, **kwargs)
|
|
60
|
+
self.float_rounding = float_rounding
|
|
61
|
+
self.numeric_precision = numeric_precision
|
|
62
|
+
self.enable_wrapping = enable_wrapping
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def _latex_wrapping(s: str) -> str:
|
|
66
|
+
r"""Wrap a LaTeX expression in math mode delimiters.
|
|
67
|
+
|
|
68
|
+
This function checks whether the input string is already in a LaTeX
|
|
69
|
+
math environment (e.g., $, \[, \begin{}, etc.). If not, it wraps the
|
|
70
|
+
expression in $$...$$ to ensure proper parsing and rendering as a
|
|
71
|
+
mathematical expression.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
s (str): The input LaTeX string.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
str: The LaTeX string wrapped in math mode if necessary.
|
|
78
|
+
"""
|
|
79
|
+
s_stripped = s.strip()
|
|
80
|
+
if (
|
|
81
|
+
not any(
|
|
82
|
+
s_stripped.startswith(prefix)
|
|
83
|
+
for prefix in ("$", "\\(", "\\[", "\\begin")
|
|
84
|
+
)
|
|
85
|
+
and "\\boxed" not in s_stripped
|
|
86
|
+
):
|
|
87
|
+
s = f"$$ {s_stripped} $$"
|
|
88
|
+
return s
|
|
89
|
+
|
|
90
|
+
async def _setup(self, **kwargs) -> None:
|
|
91
|
+
r"""No special setup needed for math verification."""
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
async def _cleanup(self) -> None:
|
|
95
|
+
r"""No cleanup needed for math verification."""
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
async def _verify_implementation(
|
|
99
|
+
self, solution: str, reference_answer: Optional[str]
|
|
100
|
+
) -> VerificationResult:
|
|
101
|
+
r"""Verify mathematical expressions using Math-Verify.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
solution: The solution to verify
|
|
105
|
+
reference_answer: The expected answer to compare against
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
VerificationResult containing the verification status and details
|
|
109
|
+
"""
|
|
110
|
+
from math_verify import parse, verify
|
|
111
|
+
from math_verify.parser import (
|
|
112
|
+
ExprExtractionConfig,
|
|
113
|
+
LatexExtractionConfig,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if reference_answer is None:
|
|
117
|
+
return VerificationResult(
|
|
118
|
+
status=VerificationOutcome.ERROR,
|
|
119
|
+
result="",
|
|
120
|
+
error_message=(
|
|
121
|
+
"Ground truth is required for " "mathematical verification"
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
# Apply LaTeX wrapping if enabled
|
|
127
|
+
if self.enable_wrapping:
|
|
128
|
+
solution = self._latex_wrapping(solution)
|
|
129
|
+
reference_answer = self._latex_wrapping(reference_answer)
|
|
130
|
+
logger.debug("Applied LaTeX wrapping")
|
|
131
|
+
|
|
132
|
+
# Parse both expressions with LaTeX and plain expression support
|
|
133
|
+
parsed_reference_answer = parse(
|
|
134
|
+
reference_answer,
|
|
135
|
+
extraction_config=[
|
|
136
|
+
LatexExtractionConfig(boxed_match_priority=0),
|
|
137
|
+
ExprExtractionConfig(),
|
|
138
|
+
],
|
|
139
|
+
)
|
|
140
|
+
parsed_solution = parse(
|
|
141
|
+
solution,
|
|
142
|
+
extraction_config=[
|
|
143
|
+
LatexExtractionConfig(),
|
|
144
|
+
ExprExtractionConfig(),
|
|
145
|
+
],
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if not parsed_reference_answer or not parsed_solution:
|
|
149
|
+
return VerificationResult(
|
|
150
|
+
status=VerificationOutcome.ERROR,
|
|
151
|
+
result="",
|
|
152
|
+
error_message="Failed to parse expressions",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
# Order matters! reference_answer must be first argument
|
|
156
|
+
is_correct = verify(
|
|
157
|
+
parsed_reference_answer,
|
|
158
|
+
parsed_solution,
|
|
159
|
+
float_rounding=self.float_rounding,
|
|
160
|
+
numeric_precision=self.numeric_precision,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if is_correct:
|
|
164
|
+
logger.debug("Mathematical verification succeeded")
|
|
165
|
+
return VerificationResult(
|
|
166
|
+
status=VerificationOutcome.SUCCESS, result=solution
|
|
167
|
+
)
|
|
168
|
+
else:
|
|
169
|
+
logger.debug("Mathematical verification failed")
|
|
170
|
+
return VerificationResult(
|
|
171
|
+
status=VerificationOutcome.FAILURE,
|
|
172
|
+
result=solution,
|
|
173
|
+
error_message="Solution does not match ground truth",
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
except Exception as error:
|
|
177
|
+
logger.error(f"Mathematical verification error: {error!s}")
|
|
178
|
+
return VerificationResult(
|
|
179
|
+
status=VerificationOutcome.ERROR,
|
|
180
|
+
result="",
|
|
181
|
+
error_message=f"Mathematical verification error: {error!s}",
|
|
182
|
+
)
|