camel-ai 0.2.5__py3-none-any.whl → 0.2.7__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 (49) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +114 -23
  3. camel/configs/__init__.py +6 -4
  4. camel/configs/base_config.py +21 -0
  5. camel/configs/gemini_config.py +17 -9
  6. camel/configs/qwen_config.py +91 -0
  7. camel/configs/samba_config.py +1 -38
  8. camel/configs/yi_config.py +58 -0
  9. camel/generators.py +93 -0
  10. camel/interpreters/docker_interpreter.py +5 -0
  11. camel/interpreters/ipython_interpreter.py +2 -1
  12. camel/loaders/__init__.py +2 -0
  13. camel/loaders/apify_reader.py +223 -0
  14. camel/memories/agent_memories.py +24 -1
  15. camel/messages/base.py +38 -0
  16. camel/models/__init__.py +4 -0
  17. camel/models/model_factory.py +6 -0
  18. camel/models/qwen_model.py +139 -0
  19. camel/models/samba_model.py +1 -1
  20. camel/models/yi_model.py +138 -0
  21. camel/prompts/image_craft.py +8 -0
  22. camel/prompts/video_description_prompt.py +8 -0
  23. camel/retrievers/vector_retriever.py +5 -1
  24. camel/societies/role_playing.py +29 -18
  25. camel/societies/workforce/base.py +7 -1
  26. camel/societies/workforce/task_channel.py +10 -0
  27. camel/societies/workforce/utils.py +6 -0
  28. camel/societies/workforce/worker.py +2 -0
  29. camel/storages/vectordb_storages/qdrant.py +147 -24
  30. camel/tasks/task.py +15 -0
  31. camel/terminators/base.py +4 -0
  32. camel/terminators/response_terminator.py +1 -0
  33. camel/terminators/token_limit_terminator.py +1 -0
  34. camel/toolkits/__init__.py +4 -1
  35. camel/toolkits/base.py +9 -0
  36. camel/toolkits/data_commons_toolkit.py +360 -0
  37. camel/toolkits/function_tool.py +174 -7
  38. camel/toolkits/github_toolkit.py +175 -176
  39. camel/toolkits/google_scholar_toolkit.py +36 -7
  40. camel/toolkits/notion_toolkit.py +279 -0
  41. camel/toolkits/search_toolkit.py +164 -36
  42. camel/types/enums.py +88 -0
  43. camel/types/unified_model_type.py +10 -0
  44. camel/utils/commons.py +2 -1
  45. camel/utils/constants.py +2 -0
  46. {camel_ai-0.2.5.dist-info → camel_ai-0.2.7.dist-info}/METADATA +129 -79
  47. {camel_ai-0.2.5.dist-info → camel_ai-0.2.7.dist-info}/RECORD +49 -42
  48. {camel_ai-0.2.5.dist-info → camel_ai-0.2.7.dist-info}/LICENSE +0 -0
  49. {camel_ai-0.2.5.dist-info → camel_ai-0.2.7.dist-info}/WHEEL +0 -0
@@ -11,8 +11,12 @@
11
11
  # See the License for the specific language governing permissions and
12
12
  # limitations under the License.
13
13
  # =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
14
+ import logging
14
15
  from datetime import datetime
15
- from typing import Any, Dict, List, Optional, Tuple, Union, cast
16
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union, cast
17
+
18
+ if TYPE_CHECKING:
19
+ from qdrant_client import QdrantClient
16
20
 
17
21
  from camel.storages.vectordb_storages import (
18
22
  BaseVectorStorage,
@@ -25,6 +29,7 @@ from camel.types import VectorDistance
25
29
  from camel.utils import dependencies_required
26
30
 
27
31
  _qdrant_local_client_map: Dict[str, Tuple[Any, int]] = {}
32
+ logger = logging.getLogger(__name__)
28
33
 
29
34
 
30
35
  class QdrantStorage(BaseVectorStorage):
@@ -107,7 +112,13 @@ class QdrantStorage(BaseVectorStorage):
107
112
  hasattr(self, "delete_collection_on_del")
108
113
  and self.delete_collection_on_del
109
114
  ):
110
- self._delete_collection(self.collection_name)
115
+ try:
116
+ self._delete_collection(self.collection_name)
117
+ except RuntimeError as e:
118
+ logger.error(
119
+ f"Failed to delete collection"
120
+ f" '{self.collection_name}': {e}"
121
+ )
111
122
 
112
123
  def _create_client(
113
124
  self,
@@ -244,6 +255,10 @@ class QdrantStorage(BaseVectorStorage):
244
255
  "config": collection_info.config,
245
256
  }
246
257
 
258
+ def close_client(self, **kwargs):
259
+ r"""Closes the client connection to the Qdrant storage."""
260
+ self._client.close(**kwargs)
261
+
247
262
  def add(
248
263
  self,
249
264
  records: List[VectorRecord],
@@ -273,36 +288,124 @@ class QdrantStorage(BaseVectorStorage):
273
288
  f"{op_info}."
274
289
  )
275
290
 
276
- def delete(
277
- self,
278
- ids: List[str],
279
- **kwargs: Any,
291
+ def update_payload(
292
+ self, ids: List[str], payload: Dict[str, Any], **kwargs: Any
280
293
  ) -> None:
281
- r"""Deletes a list of vectors identified by their IDs from the storage.
294
+ r"""Updates the payload of the vectors identified by their IDs.
282
295
 
283
296
  Args:
284
297
  ids (List[str]): List of unique identifiers for the vectors to be
285
- deleted.
298
+ updated.
299
+ payload (Dict[str, Any]): List of payloads to be updated.
286
300
  **kwargs (Any): Additional keyword arguments.
287
301
 
288
302
  Raises:
289
- RuntimeError: If there is an error during the deletion process.
303
+ RuntimeError: If there is an error during the update process.
290
304
  """
291
305
  from qdrant_client.http.models import PointIdsList, UpdateStatus
292
306
 
293
307
  points = cast(List[Union[str, int]], ids)
294
- op_info = self._client.delete(
308
+
309
+ op_info = self._client.set_payload(
295
310
  collection_name=self.collection_name,
296
- points_selector=PointIdsList(points=points),
297
- wait=True,
311
+ payload=payload,
312
+ points=PointIdsList(points=points),
298
313
  **kwargs,
299
314
  )
300
315
  if op_info.status != UpdateStatus.COMPLETED:
301
316
  raise RuntimeError(
302
- "Failed to delete vectors in Qdrant, operation info: "
317
+ "Failed to update payload in Qdrant, operation info: "
303
318
  f"{op_info}"
304
319
  )
305
320
 
321
+ def delete_collection(self) -> None:
322
+ r"""Deletes the entire collection in the Qdrant storage."""
323
+ self._delete_collection(self.collection_name)
324
+
325
+ def delete(
326
+ self,
327
+ ids: Optional[List[str]] = None,
328
+ payload_filter: Optional[Dict[str, Any]] = None,
329
+ **kwargs: Any,
330
+ ) -> None:
331
+ r"""Deletes points from the collection based on either IDs or payload
332
+ filters.
333
+
334
+ Args:
335
+ ids (Optional[List[str]], optional): List of unique identifiers
336
+ for the vectors to be deleted.
337
+ payload_filter (Optional[Dict[str, Any]], optional): A filter for
338
+ the payload to delete points matching specific conditions. If
339
+ `ids` is provided, `payload_filter` will be ignored unless both
340
+ are combined explicitly.
341
+ **kwargs (Any): Additional keyword arguments pass to `QdrantClient.
342
+ delete`.
343
+
344
+ Examples:
345
+ >>> # Delete points with IDs "1", "2", and "3"
346
+ >>> storage.delete(ids=["1", "2", "3"])
347
+ >>> # Delete points with payload filter
348
+ >>> storage.delete(payload_filter={"name": "Alice"})
349
+
350
+ Raises:
351
+ ValueError: If neither `ids` nor `payload_filter` is provided.
352
+ RuntimeError: If there is an error during the deletion process.
353
+
354
+ Notes:
355
+ - If `ids` is provided, the points with these IDs will be deleted
356
+ directly, and the `payload_filter` will be ignored.
357
+ - If `ids` is not provided but `payload_filter` is, then points
358
+ matching the `payload_filter` will be deleted.
359
+ """
360
+ from qdrant_client.http.models import (
361
+ Condition,
362
+ FieldCondition,
363
+ Filter,
364
+ MatchValue,
365
+ PointIdsList,
366
+ UpdateStatus,
367
+ )
368
+
369
+ if not ids and not payload_filter:
370
+ raise ValueError(
371
+ "You must provide either `ids` or `payload_filter` to delete "
372
+ "points."
373
+ )
374
+
375
+ if ids:
376
+ op_info = self._client.delete(
377
+ collection_name=self.collection_name,
378
+ points_selector=PointIdsList(
379
+ points=cast(List[Union[int, str]], ids)
380
+ ),
381
+ **kwargs,
382
+ )
383
+ if op_info.status != UpdateStatus.COMPLETED:
384
+ raise RuntimeError(
385
+ "Failed to delete vectors in Qdrant, operation info: "
386
+ f"{op_info}"
387
+ )
388
+
389
+ if payload_filter:
390
+ filter_conditions = [
391
+ FieldCondition(key=key, match=MatchValue(value=value))
392
+ for key, value in payload_filter.items()
393
+ ]
394
+
395
+ op_info = self._client.delete(
396
+ collection_name=self.collection_name,
397
+ points_selector=Filter(
398
+ must=cast(List[Condition], filter_conditions)
399
+ ),
400
+ **kwargs,
401
+ )
402
+
403
+ if op_info.status != UpdateStatus.COMPLETED:
404
+ raise RuntimeError(
405
+ "Failed to delete vectors in Qdrant, operation info: "
406
+ f"{op_info}"
407
+ )
408
+
306
409
  def status(self) -> VectorDBStatus:
307
410
  status = self._get_collection_info(self.collection_name)
308
411
  return VectorDBStatus(
@@ -313,6 +416,7 @@ class QdrantStorage(BaseVectorStorage):
313
416
  def query(
314
417
  self,
315
418
  query: VectorDBQuery,
419
+ filter_conditions: Optional[Dict[str, Any]] = None,
316
420
  **kwargs: Any,
317
421
  ) -> List[VectorDBQueryResult]:
318
422
  r"""Searches for similar vectors in the storage based on the provided
@@ -321,31 +425,50 @@ class QdrantStorage(BaseVectorStorage):
321
425
  Args:
322
426
  query (VectorDBQuery): The query object containing the search
323
427
  vector and the number of top similar vectors to retrieve.
428
+ filter_conditions (Optional[Dict[str, Any]], optional): A
429
+ dictionary specifying conditions to filter the query results.
324
430
  **kwargs (Any): Additional keyword arguments.
325
431
 
326
432
  Returns:
327
433
  List[VectorDBQueryResult]: A list of vectors retrieved from the
328
434
  storage based on similarity to the query vector.
329
435
  """
330
- # TODO: filter
436
+ from qdrant_client.http.models import (
437
+ Condition,
438
+ FieldCondition,
439
+ Filter,
440
+ MatchValue,
441
+ )
442
+
443
+ # Construct filter if filter_conditions is provided
444
+ search_filter = None
445
+ if filter_conditions:
446
+ must_conditions = [
447
+ FieldCondition(key=key, match=MatchValue(value=value))
448
+ for key, value in filter_conditions.items()
449
+ ]
450
+ search_filter = Filter(must=cast(List[Condition], must_conditions))
451
+
452
+ # Execute the search with optional filter
331
453
  search_result = self._client.search(
332
454
  collection_name=self.collection_name,
333
455
  query_vector=query.query_vector,
334
456
  with_payload=True,
335
457
  with_vectors=True,
336
458
  limit=query.top_k,
459
+ query_filter=search_filter,
337
460
  **kwargs,
338
461
  )
339
- query_results = []
340
- for point in search_result:
341
- query_results.append(
342
- VectorDBQueryResult.create(
343
- similarity=point.score,
344
- id=str(point.id),
345
- payload=point.payload,
346
- vector=point.vector, # type: ignore[arg-type]
347
- )
462
+
463
+ query_results = [
464
+ VectorDBQueryResult.create(
465
+ similarity=point.score,
466
+ id=str(point.id),
467
+ payload=point.payload,
468
+ vector=point.vector, # type: ignore[arg-type]
348
469
  )
470
+ for point in search_result
471
+ ]
349
472
 
350
473
  return query_results
351
474
 
@@ -363,6 +486,6 @@ class QdrantStorage(BaseVectorStorage):
363
486
  pass
364
487
 
365
488
  @property
366
- def client(self) -> Any:
489
+ def client(self) -> "QdrantClient":
367
490
  r"""Provides access to the underlying vector database client."""
368
491
  return self._client
camel/tasks/task.py CHANGED
@@ -130,6 +130,11 @@ class Task(BaseModel):
130
130
  self.set_state(TaskState.DONE)
131
131
 
132
132
  def set_id(self, id: str):
133
+ r"""Set the id of the task.
134
+
135
+ Args:
136
+ id (str): The id of the task.
137
+ """
133
138
  self.id = id
134
139
 
135
140
  def set_state(self, state: TaskState):
@@ -147,10 +152,20 @@ class Task(BaseModel):
147
152
  self.parent.set_state(state)
148
153
 
149
154
  def add_subtask(self, task: "Task"):
155
+ r"""Add a subtask to the current task.
156
+
157
+ Args:
158
+ task (Task): The subtask to be added.
159
+ """
150
160
  task.parent = self
151
161
  self.subtasks.append(task)
152
162
 
153
163
  def remove_subtask(self, id: str):
164
+ r"""Remove a subtask from the current task.
165
+
166
+ Args:
167
+ id (str): The id of the subtask to be removed.
168
+ """
154
169
  self.subtasks = [task for task in self.subtasks if task.id != id]
155
170
 
156
171
  def get_running_task(self) -> Optional["Task"]:
camel/terminators/base.py CHANGED
@@ -18,6 +18,8 @@ from camel.messages import BaseMessage
18
18
 
19
19
 
20
20
  class BaseTerminator(ABC):
21
+ r"""Base class for terminators."""
22
+
21
23
  def __init__(self, *args, **kwargs) -> None:
22
24
  self._terminated: bool = False
23
25
  self._termination_reason: Optional[str] = None
@@ -32,6 +34,8 @@ class BaseTerminator(ABC):
32
34
 
33
35
 
34
36
  class ResponseTerminator(BaseTerminator):
37
+ r"""A terminator that terminates the conversation based on the response."""
38
+
35
39
  @abstractmethod
36
40
  def is_terminated(
37
41
  self, messages: List[BaseMessage]
@@ -122,6 +122,7 @@ class ResponseWordsTerminator(ResponseTerminator):
122
122
  return self._terminated, self._termination_reason
123
123
 
124
124
  def reset(self):
125
+ r"""Reset the terminator."""
125
126
  self._terminated = False
126
127
  self._termination_reason = None
127
128
  self._word_count_dict = defaultdict(int)
@@ -53,5 +53,6 @@ class TokenLimitTerminator(BaseTerminator):
53
53
  return self._terminated, self._termination_reason
54
54
 
55
55
  def reset(self):
56
+ r"""Reset the terminator."""
56
57
  self._terminated = False
57
58
  self._termination_reason = None
@@ -17,10 +17,10 @@ from .function_tool import (
17
17
  OpenAIFunction,
18
18
  get_openai_function_schema,
19
19
  get_openai_tool_schema,
20
+ generate_docstring,
20
21
  )
21
22
  from .open_api_specs.security_config import openapi_security_config
22
23
 
23
-
24
24
  from .math_toolkit import MathToolkit, MATH_FUNCS
25
25
  from .search_toolkit import SearchToolkit, SEARCH_FUNCS
26
26
  from .weather_toolkit import WeatherToolkit, WEATHER_FUNCS
@@ -39,6 +39,7 @@ from .slack_toolkit import SlackToolkit
39
39
  from .twitter_toolkit import TwitterToolkit, TWITTER_FUNCS
40
40
  from .open_api_toolkit import OpenAPIToolkit
41
41
  from .retrieval_toolkit import RetrievalToolkit
42
+ from .notion_toolkit import NotionToolkit
42
43
 
43
44
  __all__ = [
44
45
  'BaseToolkit',
@@ -46,6 +47,7 @@ __all__ = [
46
47
  'OpenAIFunction',
47
48
  'get_openai_function_schema',
48
49
  'get_openai_tool_schema',
50
+ "generate_docstring",
49
51
  'openapi_security_config',
50
52
  'GithubToolkit',
51
53
  'MathToolkit',
@@ -63,6 +65,7 @@ __all__ = [
63
65
  'AskNewsToolkit',
64
66
  'AsyncAskNewsToolkit',
65
67
  'GoogleScholarToolkit',
68
+ 'NotionToolkit',
66
69
  'ArxivToolkit',
67
70
  'MATH_FUNCS',
68
71
  'SEARCH_FUNCS',
camel/toolkits/base.py CHANGED
@@ -19,5 +19,14 @@ from camel.utils import AgentOpsMeta
19
19
 
20
20
 
21
21
  class BaseToolkit(metaclass=AgentOpsMeta):
22
+ r"""Base class for toolkits."""
23
+
22
24
  def get_tools(self) -> List[FunctionTool]:
25
+ r"""Returns a list of FunctionTool objects representing the
26
+ functions in the toolkit.
27
+
28
+ Returns:
29
+ List[FunctionTool]: A list of FunctionTool objects
30
+ representing the functions in the toolkit.
31
+ """
23
32
  raise NotImplementedError("Subclasses must implement this method.")