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.

Files changed (122) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +4 -0
  3. camel/agents/repo_agent.py +2 -2
  4. camel/benchmarks/apibank.py +1 -1
  5. camel/benchmarks/apibench.py +1 -1
  6. camel/configs/__init__.py +3 -0
  7. camel/configs/modelscope_config.py +59 -0
  8. camel/datagen/evol_instruct/__init__.py +20 -0
  9. camel/datagen/evol_instruct/evol_instruct.py +424 -0
  10. camel/datagen/evol_instruct/scorer.py +166 -0
  11. camel/datagen/evol_instruct/templates.py +268 -0
  12. camel/datagen/self_improving_cot.py +1 -1
  13. camel/datasets/__init__.py +2 -0
  14. camel/datasets/base_generator.py +22 -9
  15. camel/datasets/few_shot_generator.py +2 -3
  16. camel/datasets/self_instruct_generator.py +415 -0
  17. camel/embeddings/openai_compatible_embedding.py +13 -5
  18. camel/environments/models.py +10 -4
  19. camel/environments/single_step.py +181 -41
  20. camel/interpreters/docker_interpreter.py +2 -2
  21. camel/interpreters/e2b_interpreter.py +1 -1
  22. camel/interpreters/internal_python_interpreter.py +1 -1
  23. camel/interpreters/subprocess_interpreter.py +1 -1
  24. camel/loaders/__init__.py +2 -2
  25. camel/loaders/{panda_reader.py → pandas_reader.py} +61 -30
  26. camel/loaders/unstructured_io.py +2 -1
  27. camel/memories/blocks/chat_history_block.py +1 -1
  28. camel/memories/context_creators/score_based.py +198 -67
  29. camel/models/__init__.py +2 -0
  30. camel/models/aiml_model.py +9 -3
  31. camel/models/anthropic_model.py +11 -3
  32. camel/models/azure_openai_model.py +9 -3
  33. camel/models/base_audio_model.py +6 -0
  34. camel/models/base_model.py +4 -0
  35. camel/models/deepseek_model.py +9 -3
  36. camel/models/gemini_model.py +9 -3
  37. camel/models/groq_model.py +9 -3
  38. camel/models/internlm_model.py +8 -2
  39. camel/models/model_factory.py +123 -0
  40. camel/models/modelscope_model.py +208 -0
  41. camel/models/moonshot_model.py +8 -2
  42. camel/models/nemotron_model.py +9 -3
  43. camel/models/nvidia_model.py +9 -3
  44. camel/models/ollama_model.py +9 -3
  45. camel/models/openai_audio_models.py +7 -5
  46. camel/models/openai_compatible_model.py +9 -3
  47. camel/models/openai_model.py +58 -5
  48. camel/models/openrouter_model.py +9 -3
  49. camel/models/qwen_model.py +9 -3
  50. camel/models/samba_model.py +9 -3
  51. camel/models/sglang_model.py +11 -4
  52. camel/models/siliconflow_model.py +8 -2
  53. camel/models/stub_model.py +2 -1
  54. camel/models/togetherai_model.py +11 -5
  55. camel/models/vllm_model.py +10 -4
  56. camel/models/yi_model.py +9 -3
  57. camel/models/zhipuai_model.py +11 -5
  58. camel/retrievers/auto_retriever.py +14 -0
  59. camel/retrievers/vector_retriever.py +1 -1
  60. camel/storages/__init__.py +2 -0
  61. camel/storages/graph_storages/neo4j_graph.py +1 -1
  62. camel/storages/vectordb_storages/__init__.py +2 -0
  63. camel/storages/vectordb_storages/base.py +2 -2
  64. camel/storages/vectordb_storages/milvus.py +2 -2
  65. camel/storages/vectordb_storages/qdrant.py +2 -2
  66. camel/storages/vectordb_storages/tidb.py +332 -0
  67. camel/tasks/task.py +2 -2
  68. camel/toolkits/__init__.py +9 -1
  69. camel/toolkits/arxiv_toolkit.py +2 -1
  70. camel/toolkits/ask_news_toolkit.py +11 -3
  71. camel/toolkits/audio_analysis_toolkit.py +2 -0
  72. camel/toolkits/base.py +3 -0
  73. camel/toolkits/browser_toolkit.py +84 -61
  74. camel/toolkits/code_execution.py +3 -1
  75. camel/toolkits/dappier_toolkit.py +2 -1
  76. camel/toolkits/data_commons_toolkit.py +2 -0
  77. camel/toolkits/excel_toolkit.py +2 -0
  78. camel/toolkits/file_write_toolkit.py +2 -0
  79. camel/toolkits/github_toolkit.py +6 -4
  80. camel/toolkits/google_scholar_toolkit.py +2 -0
  81. camel/toolkits/human_toolkit.py +17 -1
  82. camel/toolkits/image_analysis_toolkit.py +2 -0
  83. camel/toolkits/linkedin_toolkit.py +2 -1
  84. camel/toolkits/math_toolkit.py +2 -0
  85. camel/toolkits/mcp_toolkit.py +42 -52
  86. camel/toolkits/meshy_toolkit.py +20 -2
  87. camel/toolkits/networkx_toolkit.py +2 -0
  88. camel/toolkits/notion_toolkit.py +7 -0
  89. camel/toolkits/openai_agent_toolkit.py +131 -0
  90. camel/toolkits/openbb_toolkit.py +2 -1
  91. camel/toolkits/pubmed_toolkit.py +2 -0
  92. camel/toolkits/reddit_toolkit.py +2 -1
  93. camel/toolkits/retrieval_toolkit.py +2 -1
  94. camel/toolkits/search_toolkit.py +2 -1
  95. camel/toolkits/searxng_toolkit.py +207 -0
  96. camel/toolkits/semantic_scholar_toolkit.py +2 -0
  97. camel/toolkits/slack_toolkit.py +2 -0
  98. camel/toolkits/stripe_toolkit.py +2 -1
  99. camel/toolkits/sympy_toolkit.py +2 -0
  100. camel/toolkits/terminal_toolkit.py +2 -0
  101. camel/toolkits/thinking_toolkit.py +168 -12
  102. camel/toolkits/twitter_toolkit.py +2 -1
  103. camel/toolkits/video_analysis_toolkit.py +2 -1
  104. camel/toolkits/video_download_toolkit.py +2 -1
  105. camel/toolkits/weather_toolkit.py +2 -0
  106. camel/toolkits/whatsapp_toolkit.py +2 -1
  107. camel/toolkits/zapier_toolkit.py +2 -1
  108. camel/types/enums.py +66 -0
  109. camel/types/unified_model_type.py +5 -0
  110. camel/utils/__init__.py +2 -0
  111. camel/utils/chunker/code_chunker.py +9 -9
  112. camel/utils/commons.py +50 -30
  113. camel/utils/constants.py +2 -2
  114. camel/utils/mcp.py +79 -0
  115. camel/verifiers/__init__.py +2 -0
  116. camel/verifiers/base.py +15 -15
  117. camel/verifiers/math_verifier.py +182 -0
  118. camel/verifiers/python_verifier.py +28 -28
  119. {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/METADATA +54 -4
  120. {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/RECORD +122 -110
  121. {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/WHEEL +0 -0
  122. {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/licenses/LICENSE +0 -0
@@ -36,7 +36,7 @@ class MilvusStorage(BaseVectorStorage):
36
36
  `Milvus <https://milvus.io/docs/overview.md/>`_
37
37
 
38
38
  Args:
39
- vector_dim (int): The dimenstion of storing vectors.
39
+ vector_dim (int): The dimension of storing vectors.
40
40
  url_and_api_key (Tuple[str, str]): Tuple containing
41
41
  the URL and API key for connecting to a remote Milvus instance.
42
42
  URL maps to Milvus uri concept, typically "endpoint:port".
@@ -136,7 +136,7 @@ class MilvusStorage(BaseVectorStorage):
136
136
  schema.add_field(
137
137
  field_name="id",
138
138
  datatype=DataType.VARCHAR,
139
- descrition='A unique identifier for the vector',
139
+ description='A unique identifier for the vector',
140
140
  is_primary=True,
141
141
  max_length=65535,
142
142
  )
@@ -40,7 +40,7 @@ class QdrantStorage(BaseVectorStorage):
40
40
  `Qdrant <https://qdrant.tech/>`_
41
41
 
42
42
  Args:
43
- vector_dim (int): The dimenstion of storing vectors.
43
+ vector_dim (int): The dimension of storing vectors.
44
44
  collection_name (Optional[str], optional): Name for the collection in
45
45
  the Qdrant. If not provided, set it to the current time with iso
46
46
  format. (default: :obj:`None`)
@@ -218,7 +218,7 @@ class QdrantStorage(BaseVectorStorage):
218
218
  )
219
219
 
220
220
  def _collection_exists(self, collection_name: str) -> bool:
221
- r"""Returns wether the collection exists in the database"""
221
+ r"""Returns whether the collection exists in the database"""
222
222
  for c in self._client.get_collections().collections:
223
223
  if collection_name == c.name:
224
224
  return True
@@ -0,0 +1,332 @@
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 logging
16
+ import re
17
+ from datetime import datetime
18
+ from enum import Enum
19
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
20
+
21
+ from camel.storages.vectordb_storages import (
22
+ BaseVectorStorage,
23
+ VectorDBQuery,
24
+ VectorDBQueryResult,
25
+ VectorDBStatus,
26
+ VectorRecord,
27
+ )
28
+ from camel.utils import dependencies_required
29
+
30
+ if TYPE_CHECKING:
31
+ from pytidb import Table, TiDBClient
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ class EnumEncoder(json.JSONEncoder):
37
+ def default(self, obj):
38
+ if isinstance(obj, Enum):
39
+ return obj.value
40
+ return super().default(obj)
41
+
42
+
43
+ class TiDBStorage(BaseVectorStorage):
44
+ r"""An implementation of the `BaseVectorStorage` for interacting with TiDB.
45
+
46
+ The detailed information about TiDB is available at:
47
+ `TiDB Vector Search <https://ai.pingcap.com/>`_
48
+
49
+ Args:
50
+ vector_dim (int): The dimension of storing vectors.
51
+ url_and_api_key (Optional[Union[Tuple[str, str], str]]): A tuple
52
+ containing the database url and API key for connecting to a TiDB
53
+ cluster. The URL should be in the format:
54
+ "mysql+pymysql://<username>:<password>@<host>:<port>/<db_name>".
55
+ TiDB will not use the API Key, but retains the definition for
56
+ interface compatible.
57
+ collection_name (Optional[str]): Name of the collection.
58
+ The collection name will be used as the table name in TiDB. If not
59
+ provided, set it to the current time with iso format.
60
+ **kwargs (Any): Additional keyword arguments for initializing
61
+ TiDB connection.
62
+
63
+ Raises:
64
+ ImportError: If `pytidb` package is not installed.
65
+ """
66
+
67
+ @dependencies_required('pytidb')
68
+ def __init__(
69
+ self,
70
+ vector_dim: int,
71
+ collection_name: Optional[str] = None,
72
+ url_and_api_key: Optional[Union[Tuple[str, str], str]] = None,
73
+ **kwargs: Any,
74
+ ) -> None:
75
+ from pytidb import TiDBClient
76
+
77
+ self._client: TiDBClient
78
+ database_url = None
79
+ if isinstance(url_and_api_key, str):
80
+ database_url = url_and_api_key
81
+ elif isinstance(url_and_api_key, tuple):
82
+ database_url = url_and_api_key[0]
83
+ self._create_client(database_url, **kwargs)
84
+ self.vector_dim = vector_dim
85
+ self.collection_name = collection_name or self._generate_table_name()
86
+ self._table = self._open_and_create_table()
87
+ self._table_model = self._table.table_model
88
+ self._check_table()
89
+
90
+ def _create_client(
91
+ self,
92
+ database_url: Optional[str] = None,
93
+ **kwargs: Any,
94
+ ) -> None:
95
+ r"""Initializes the TiDB client with the provided connection details.
96
+
97
+ Args:
98
+ database_url (Optional[str]): The database connection string for
99
+ the TiDB server.
100
+ **kwargs: Additional keyword arguments passed to the TiDB client.
101
+ """
102
+ from pytidb import TiDBClient
103
+
104
+ self._client = TiDBClient.connect(
105
+ database_url,
106
+ **kwargs,
107
+ )
108
+
109
+ def _get_table_model(self, collection_name: str) -> Any:
110
+ from pytidb.schema import Field, TableModel, VectorField
111
+ from sqlalchemy import JSON
112
+
113
+ class VectorDBRecord(TableModel):
114
+ id: Optional[str] = Field(None, primary_key=True)
115
+ vector: list[float] = VectorField(self.vector_dim)
116
+ payload: Optional[dict[str, Any]] = Field(None, sa_type=JSON)
117
+
118
+ # Notice: Avoid repeated definition warnings by dynamically generating
119
+ # class names.
120
+ return type(
121
+ f"VectorDBRecord_{collection_name}",
122
+ (VectorDBRecord,),
123
+ {"__tablename__": collection_name},
124
+ table=True,
125
+ )
126
+
127
+ def _open_and_create_table(self) -> "Table[Any]":
128
+ r"""Opens an existing table or creates a new table in TiDB."""
129
+ table = self._client.open_table(self.collection_name)
130
+ if table is None:
131
+ table = self._client.create_table(
132
+ schema=self._get_table_model(self.collection_name)
133
+ )
134
+ return table
135
+
136
+ def _check_table(self):
137
+ r"""Ensuring the specified table matches the specified vector
138
+ dimensionality.
139
+ """
140
+ in_dim = self._get_table_info()["vector_dim"]
141
+ if in_dim != self.vector_dim:
142
+ raise ValueError(
143
+ "Vector dimension of the existing table "
144
+ f'"{self.collection_name}" ({in_dim}) is different from '
145
+ f"the given embedding dim ({self.vector_dim})."
146
+ )
147
+
148
+ def _generate_table_name(self) -> str:
149
+ r"""Generates a unique name for a new table based on the current
150
+ timestamp. TiDB table names can only contain alphanumeric
151
+ characters and underscores.
152
+
153
+ Returns:
154
+ str: A unique, valid table name.
155
+ """
156
+ timestamp = datetime.now().isoformat()
157
+ transformed_name = re.sub(r'[^a-zA-Z0-9_]', '_', timestamp)
158
+ valid_name = "vectors_" + transformed_name
159
+ return valid_name
160
+
161
+ def _get_table_info(self) -> Dict[str, Any]:
162
+ r"""Retrieves details of an existing table.
163
+
164
+ Returns:
165
+ Dict[str, Any]: A dictionary containing details about the
166
+ table.
167
+ """
168
+ vector_count = self._table.rows()
169
+ # Get vector dimension from table schema
170
+ columns = self._table.columns()
171
+ dim_value = None
172
+ for col in columns:
173
+ match = re.search(r'vector\((\d+)\)', col.column_type)
174
+ if match:
175
+ dim_value = int(match.group(1))
176
+ break
177
+
178
+ # If no vector column found, log a warning
179
+ if dim_value is None:
180
+ logger.warning(
181
+ f"No vector column found in table {self.collection_name}. "
182
+ "This may indicate an incompatible table schema."
183
+ )
184
+
185
+ return {
186
+ "vector_count": vector_count,
187
+ "vector_dim": dim_value,
188
+ }
189
+
190
+ def _validate_and_convert_vectors(
191
+ self, records: List[VectorRecord]
192
+ ) -> List[Any]:
193
+ r"""Validates and converts VectorRecord instances to VectorDBRecord
194
+ instances.
195
+
196
+ Args:
197
+ records (List[VectorRecord]): List of vector records to validate
198
+ and convert.
199
+
200
+ Returns:
201
+ List[VectorDBRecord]: A list of VectorDBRecord instances.
202
+ """
203
+ db_records = []
204
+ for record in records:
205
+ payload = record.payload
206
+ if isinstance(payload, str):
207
+ payload = json.loads(payload)
208
+ elif isinstance(payload, dict):
209
+ payload = json.loads(json.dumps(payload, cls=EnumEncoder))
210
+ else:
211
+ payload = None
212
+
213
+ db_records.append(
214
+ self._table_model(
215
+ id=record.id,
216
+ vector=record.vector,
217
+ payload=payload,
218
+ )
219
+ )
220
+ return db_records
221
+
222
+ def add(
223
+ self,
224
+ records: List[VectorRecord],
225
+ **kwargs,
226
+ ) -> None:
227
+ r"""Adds a list of vectors to the specified table.
228
+
229
+ Args:
230
+ records (List[VectorRecord]): List of vectors to be added.
231
+ **kwargs (Any): Additional keyword arguments pass to insert.
232
+
233
+ Raises:
234
+ RuntimeError: If there was an error in the addition process.
235
+ """
236
+
237
+ db_records = self._validate_and_convert_vectors(records)
238
+ if len(db_records) == 0:
239
+ return
240
+ self._table.bulk_insert(db_records)
241
+
242
+ logger.debug(
243
+ f"Successfully added vectors to TiDB table: {self.collection_name}"
244
+ )
245
+
246
+ def delete(
247
+ self,
248
+ ids: List[str],
249
+ **kwargs: Any,
250
+ ) -> None:
251
+ r"""Deletes a list of vectors identified by their IDs from the
252
+ storage.
253
+
254
+ Args:
255
+ ids (List[str]): List of unique identifiers for the vectors to be
256
+ deleted.
257
+ **kwargs (Any): Additional keyword arguments passed to delete.
258
+
259
+ Raises:
260
+ RuntimeError: If there is an error during the deletion process.
261
+ """
262
+ self._table.delete({"id": {"$in": ids}})
263
+ logger.debug(
264
+ f"Successfully deleted vectors from TiDB table "
265
+ f"<{self.collection_name}>"
266
+ )
267
+
268
+ def status(self) -> VectorDBStatus:
269
+ r"""Retrieves the current status of the TiDB table.
270
+
271
+ Returns:
272
+ VectorDBStatus: An object containing information about the
273
+ table's status.
274
+ """
275
+ status = self._get_table_info()
276
+ return VectorDBStatus(
277
+ vector_dim=status["vector_dim"],
278
+ vector_count=status["vector_count"],
279
+ )
280
+
281
+ def query(
282
+ self,
283
+ query: VectorDBQuery,
284
+ **kwargs: Any,
285
+ ) -> List[VectorDBQueryResult]:
286
+ r"""Searches for similar vectors in the storage based on the provided
287
+ query.
288
+
289
+ Args:
290
+ query (VectorDBQuery): The query object containing the search
291
+ vector and the number of top similar vectors to retrieve.
292
+ **kwargs (Any): Additional keyword arguments passed to search.
293
+
294
+ Returns:
295
+ List[VectorDBQueryResult]: A list of vectors retrieved from the
296
+ storage based on similarity to the query vector.
297
+ """
298
+ rows = (
299
+ self._table.search(query.query_vector).limit(query.top_k).to_list()
300
+ )
301
+
302
+ query_results = []
303
+ for row in rows:
304
+ query_results.append(
305
+ VectorDBQueryResult.create(
306
+ similarity=float(row['similarity_score']),
307
+ id=str(row['id']),
308
+ payload=row['payload'],
309
+ vector=row['vector'],
310
+ )
311
+ )
312
+ return query_results
313
+
314
+ def clear(self) -> None:
315
+ r"""Removes all vectors from the TiDB table. This method
316
+ deletes the existing table and then recreates it with the same
317
+ schema to effectively remove all stored vectors.
318
+ """
319
+ self._table.truncate()
320
+
321
+ def load(self) -> None:
322
+ r"""Load the collection hosted on cloud service."""
323
+ pass
324
+
325
+ @property
326
+ def client(self) -> "TiDBClient":
327
+ r"""Provides direct access to the TiDB client.
328
+
329
+ Returns:
330
+ Any: The TiDB client instance.
331
+ """
332
+ return self._client
camel/tasks/task.py CHANGED
@@ -178,7 +178,7 @@ class Task(BaseModel):
178
178
  return None
179
179
 
180
180
  def to_string(self, indent: str = "", state: bool = False) -> str:
181
- r"""Convert task to a sting.
181
+ r"""Convert task to a string.
182
182
 
183
183
  Args:
184
184
  indent (str): The ident for hierarchical tasks.
@@ -196,7 +196,7 @@ class Task(BaseModel):
196
196
  return _str
197
197
 
198
198
  def get_result(self, indent: str = "") -> str:
199
- r"""Get task result to a sting.
199
+ r"""Get task result to a string.
200
200
 
201
201
  Args:
202
202
  indent (str): The ident for hierarchical tasks.
@@ -37,6 +37,7 @@ from .github_toolkit import GithubToolkit
37
37
  from .google_scholar_toolkit import GoogleScholarToolkit
38
38
  from .arxiv_toolkit import ArxivToolkit
39
39
  from .slack_toolkit import SlackToolkit
40
+ from .whatsapp_toolkit import WhatsAppToolkit
40
41
  from .twitter_toolkit import TwitterToolkit
41
42
  from .open_api_toolkit import OpenAPIToolkit
42
43
  from .retrieval_toolkit import RetrievalToolkit
@@ -60,7 +61,11 @@ from .browser_toolkit import BrowserToolkit
60
61
  from .file_write_toolkit import FileWriteToolkit
61
62
  from .terminal_toolkit import TerminalToolkit
62
63
  from .pubmed_toolkit import PubMedToolkit
64
+ from .data_commons_toolkit import DataCommonsToolkit
63
65
  from .thinking_toolkit import ThinkingToolkit
66
+ from .openai_agent_toolkit import OpenAIAgentToolkit
67
+ from .searxng_toolkit import SearxNGToolkit
68
+
64
69
 
65
70
  __all__ = [
66
71
  'BaseToolkit',
@@ -74,6 +79,7 @@ __all__ = [
74
79
  'GoogleMapsToolkit',
75
80
  'SearchToolkit',
76
81
  'SlackToolkit',
82
+ 'WhatsAppToolkit',
77
83
  'DalleToolkit',
78
84
  'TwitterToolkit',
79
85
  'WeatherToolkit',
@@ -100,7 +106,6 @@ __all__ = [
100
106
  'MinerUToolkit',
101
107
  'MemoryToolkit',
102
108
  'MCPToolkit',
103
- 'MCPToolkitManager',
104
109
  'AudioAnalysisToolkit',
105
110
  'ExcelToolkit',
106
111
  'VideoAnalysisToolkit',
@@ -109,5 +114,8 @@ __all__ = [
109
114
  'FileWriteToolkit',
110
115
  'TerminalToolkit',
111
116
  'PubMedToolkit',
117
+ 'DataCommonsToolkit',
112
118
  'ThinkingToolkit',
119
+ 'OpenAIAgentToolkit',
120
+ 'SearxNGToolkit',
113
121
  ]
@@ -17,11 +17,12 @@ from typing import Dict, Generator, List, Optional
17
17
  from camel.logger import get_logger
18
18
  from camel.toolkits.base import BaseToolkit
19
19
  from camel.toolkits.function_tool import FunctionTool
20
- from camel.utils import dependencies_required
20
+ from camel.utils import MCPServer, dependencies_required
21
21
 
22
22
  logger = get_logger(__name__)
23
23
 
24
24
 
25
+ @MCPServer()
25
26
  class ArxivToolkit(BaseToolkit):
26
27
  r"""A toolkit for interacting with the arXiv API to search and download
27
28
  academic papers.
@@ -17,6 +17,7 @@ from typing import List, Literal, Optional, Tuple, Union
17
17
 
18
18
  from camel.toolkits import FunctionTool
19
19
  from camel.toolkits.base import BaseToolkit
20
+ from camel.utils import MCPServer, api_keys_required
20
21
 
21
22
 
22
23
  def _process_response(
@@ -55,6 +56,10 @@ def _process_response(
55
56
  raise ValueError(f"Invalid return_type: {return_type}")
56
57
 
57
58
 
59
+ @api_keys_required(
60
+ [(None, "ASKNEWS_CLIENT_ID"), (None, "ASKNEWS_CLIENT_SECRET")]
61
+ )
62
+ @MCPServer()
58
63
  class AskNewsToolkit(BaseToolkit):
59
64
  r"""A class representing a toolkit for interacting with the AskNews API.
60
65
 
@@ -62,7 +67,10 @@ class AskNewsToolkit(BaseToolkit):
62
67
  based on user queries using the AskNews API.
63
68
  """
64
69
 
65
- def __init__(self, timeout: Optional[float] = None):
70
+ def __init__(
71
+ self,
72
+ timeout: Optional[float] = None,
73
+ ):
66
74
  r"""Initialize the AskNewsToolkit with API clients.The API keys and
67
75
  credentials are retrieved from environment variables.
68
76
  """
@@ -152,7 +160,7 @@ class AskNewsToolkit(BaseToolkit):
152
160
  each update. (default: :obj:`10`)
153
161
 
154
162
  Returns:
155
- Unio[dict, str]: A dictionary containing the stories and their
163
+ Union[dict, str]: A dictionary containing the stories and their
156
164
  associated data, or error message if the process fails.
157
165
  """
158
166
  try:
@@ -446,7 +454,7 @@ class AsyncAskNewsToolkit(BaseToolkit):
446
454
  each update. (default: :obj:`10`)
447
455
 
448
456
  Returns:
449
- Unio[dict, str]: A dictionary containing the stories and their
457
+ Union[dict, str]: A dictionary containing the stories and their
450
458
  associated data, or error message if the process fails.
451
459
  """
452
460
  try:
@@ -23,6 +23,7 @@ from camel.messages import BaseMessage
23
23
  from camel.models import BaseAudioModel, BaseModelBackend, OpenAIAudioModels
24
24
  from camel.toolkits.base import BaseToolkit
25
25
  from camel.toolkits.function_tool import FunctionTool
26
+ from camel.utils import MCPServer
26
27
 
27
28
  logger = get_logger(__name__)
28
29
 
@@ -80,6 +81,7 @@ def download_file(url: str, cache_dir: str) -> str:
80
81
  return local_path
81
82
 
82
83
 
84
+ @MCPServer()
83
85
  class AudioAnalysisToolkit(BaseToolkit):
84
86
  r"""A toolkit for audio processing and analysis.
85
87
 
camel/toolkits/base.py CHANGED
@@ -25,6 +25,9 @@ class BaseToolkit(metaclass=AgentOpsMeta):
25
25
  timeout (Optional[float]): The timeout for the toolkit.
26
26
  """
27
27
 
28
+ from mcp.server import FastMCP
29
+
30
+ mcp: FastMCP
28
31
  timeout: Optional[float] = None
29
32
 
30
33
  def __init__(self, timeout: Optional[float] = None):