camel-ai 0.2.73a4__py3-none-any.whl → 0.2.80a2__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.
Files changed (173) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/_utils.py +38 -0
  3. camel/agents/chat_agent.py +2217 -519
  4. camel/agents/mcp_agent.py +30 -27
  5. camel/configs/__init__.py +15 -0
  6. camel/configs/aihubmix_config.py +88 -0
  7. camel/configs/amd_config.py +70 -0
  8. camel/configs/cometapi_config.py +104 -0
  9. camel/configs/minimax_config.py +93 -0
  10. camel/configs/nebius_config.py +103 -0
  11. camel/data_collectors/alpaca_collector.py +15 -6
  12. camel/datasets/base_generator.py +39 -10
  13. camel/environments/single_step.py +28 -3
  14. camel/environments/tic_tac_toe.py +1 -1
  15. camel/interpreters/__init__.py +2 -0
  16. camel/interpreters/docker/Dockerfile +3 -12
  17. camel/interpreters/e2b_interpreter.py +34 -1
  18. camel/interpreters/microsandbox_interpreter.py +395 -0
  19. camel/loaders/__init__.py +11 -2
  20. camel/loaders/chunkr_reader.py +9 -0
  21. camel/memories/agent_memories.py +48 -4
  22. camel/memories/base.py +26 -0
  23. camel/memories/blocks/chat_history_block.py +122 -4
  24. camel/memories/context_creators/score_based.py +25 -384
  25. camel/memories/records.py +88 -8
  26. camel/messages/base.py +153 -34
  27. camel/models/__init__.py +10 -0
  28. camel/models/aihubmix_model.py +83 -0
  29. camel/models/aiml_model.py +1 -16
  30. camel/models/amd_model.py +101 -0
  31. camel/models/anthropic_model.py +6 -19
  32. camel/models/aws_bedrock_model.py +2 -33
  33. camel/models/azure_openai_model.py +114 -89
  34. camel/models/base_audio_model.py +3 -1
  35. camel/models/base_model.py +32 -14
  36. camel/models/cohere_model.py +1 -16
  37. camel/models/cometapi_model.py +83 -0
  38. camel/models/crynux_model.py +1 -16
  39. camel/models/deepseek_model.py +1 -16
  40. camel/models/fish_audio_model.py +6 -0
  41. camel/models/gemini_model.py +36 -18
  42. camel/models/groq_model.py +1 -17
  43. camel/models/internlm_model.py +1 -16
  44. camel/models/litellm_model.py +1 -16
  45. camel/models/lmstudio_model.py +1 -17
  46. camel/models/minimax_model.py +83 -0
  47. camel/models/mistral_model.py +1 -16
  48. camel/models/model_factory.py +27 -1
  49. camel/models/modelscope_model.py +1 -16
  50. camel/models/moonshot_model.py +105 -24
  51. camel/models/nebius_model.py +83 -0
  52. camel/models/nemotron_model.py +0 -5
  53. camel/models/netmind_model.py +1 -16
  54. camel/models/novita_model.py +1 -16
  55. camel/models/nvidia_model.py +1 -16
  56. camel/models/ollama_model.py +4 -19
  57. camel/models/openai_compatible_model.py +62 -41
  58. camel/models/openai_model.py +62 -57
  59. camel/models/openrouter_model.py +1 -17
  60. camel/models/ppio_model.py +1 -16
  61. camel/models/qianfan_model.py +1 -16
  62. camel/models/qwen_model.py +1 -16
  63. camel/models/reka_model.py +1 -16
  64. camel/models/samba_model.py +34 -47
  65. camel/models/sglang_model.py +64 -31
  66. camel/models/siliconflow_model.py +1 -16
  67. camel/models/stub_model.py +0 -4
  68. camel/models/togetherai_model.py +1 -16
  69. camel/models/vllm_model.py +1 -16
  70. camel/models/volcano_model.py +0 -17
  71. camel/models/watsonx_model.py +1 -16
  72. camel/models/yi_model.py +1 -16
  73. camel/models/zhipuai_model.py +60 -16
  74. camel/parsers/__init__.py +18 -0
  75. camel/parsers/mcp_tool_call_parser.py +176 -0
  76. camel/retrievers/auto_retriever.py +1 -0
  77. camel/runtimes/daytona_runtime.py +11 -12
  78. camel/societies/__init__.py +2 -0
  79. camel/societies/workforce/__init__.py +2 -0
  80. camel/societies/workforce/events.py +122 -0
  81. camel/societies/workforce/prompts.py +146 -66
  82. camel/societies/workforce/role_playing_worker.py +15 -11
  83. camel/societies/workforce/single_agent_worker.py +302 -65
  84. camel/societies/workforce/structured_output_handler.py +30 -18
  85. camel/societies/workforce/task_channel.py +163 -27
  86. camel/societies/workforce/utils.py +107 -13
  87. camel/societies/workforce/workflow_memory_manager.py +772 -0
  88. camel/societies/workforce/workforce.py +1949 -579
  89. camel/societies/workforce/workforce_callback.py +74 -0
  90. camel/societies/workforce/workforce_logger.py +168 -145
  91. camel/societies/workforce/workforce_metrics.py +33 -0
  92. camel/storages/key_value_storages/json.py +15 -2
  93. camel/storages/key_value_storages/mem0_cloud.py +48 -47
  94. camel/storages/object_storages/google_cloud.py +1 -1
  95. camel/storages/vectordb_storages/oceanbase.py +13 -13
  96. camel/storages/vectordb_storages/qdrant.py +3 -3
  97. camel/storages/vectordb_storages/tidb.py +8 -6
  98. camel/tasks/task.py +4 -3
  99. camel/toolkits/__init__.py +20 -7
  100. camel/toolkits/aci_toolkit.py +45 -0
  101. camel/toolkits/base.py +6 -4
  102. camel/toolkits/code_execution.py +28 -1
  103. camel/toolkits/context_summarizer_toolkit.py +684 -0
  104. camel/toolkits/dappier_toolkit.py +5 -1
  105. camel/toolkits/dingtalk.py +1135 -0
  106. camel/toolkits/edgeone_pages_mcp_toolkit.py +11 -31
  107. camel/toolkits/excel_toolkit.py +1 -1
  108. camel/toolkits/{file_write_toolkit.py → file_toolkit.py} +430 -36
  109. camel/toolkits/function_tool.py +13 -3
  110. camel/toolkits/github_toolkit.py +104 -17
  111. camel/toolkits/gmail_toolkit.py +1839 -0
  112. camel/toolkits/google_calendar_toolkit.py +38 -4
  113. camel/toolkits/google_drive_mcp_toolkit.py +12 -31
  114. camel/toolkits/hybrid_browser_toolkit/config_loader.py +15 -0
  115. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +77 -8
  116. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +884 -88
  117. camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
  118. camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +5 -612
  119. camel/toolkits/hybrid_browser_toolkit/ts/package.json +0 -1
  120. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +959 -89
  121. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +9 -2
  122. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +281 -213
  123. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  124. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
  125. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  126. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +23 -3
  127. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +72 -7
  128. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +582 -132
  129. camel/toolkits/hybrid_browser_toolkit_py/actions.py +158 -0
  130. camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +55 -8
  131. camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +43 -0
  132. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +321 -8
  133. camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +10 -4
  134. camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +45 -4
  135. camel/toolkits/{openai_image_toolkit.py → image_generation_toolkit.py} +151 -53
  136. camel/toolkits/klavis_toolkit.py +5 -1
  137. camel/toolkits/markitdown_toolkit.py +27 -1
  138. camel/toolkits/math_toolkit.py +64 -10
  139. camel/toolkits/mcp_toolkit.py +366 -71
  140. camel/toolkits/memory_toolkit.py +5 -1
  141. camel/toolkits/message_integration.py +18 -13
  142. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  143. camel/toolkits/note_taking_toolkit.py +19 -10
  144. camel/toolkits/notion_mcp_toolkit.py +16 -26
  145. camel/toolkits/openbb_toolkit.py +5 -1
  146. camel/toolkits/origene_mcp_toolkit.py +8 -49
  147. camel/toolkits/playwright_mcp_toolkit.py +12 -31
  148. camel/toolkits/resend_toolkit.py +168 -0
  149. camel/toolkits/search_toolkit.py +264 -91
  150. camel/toolkits/slack_toolkit.py +64 -10
  151. camel/toolkits/terminal_toolkit/__init__.py +18 -0
  152. camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
  153. camel/toolkits/terminal_toolkit/utils.py +532 -0
  154. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  155. camel/toolkits/video_analysis_toolkit.py +17 -11
  156. camel/toolkits/wechat_official_toolkit.py +483 -0
  157. camel/toolkits/zapier_toolkit.py +5 -1
  158. camel/types/__init__.py +2 -2
  159. camel/types/enums.py +274 -7
  160. camel/types/openai_types.py +2 -2
  161. camel/types/unified_model_type.py +15 -0
  162. camel/utils/commons.py +36 -5
  163. camel/utils/constants.py +3 -0
  164. camel/utils/context_utils.py +1003 -0
  165. camel/utils/mcp.py +138 -4
  166. camel/utils/token_counting.py +43 -20
  167. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +223 -83
  168. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +170 -141
  169. camel/loaders/pandas_reader.py +0 -368
  170. camel/toolkits/openai_agent_toolkit.py +0 -135
  171. camel/toolkits/terminal_toolkit.py +0 -1550
  172. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
  173. {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
camel/utils/mcp.py CHANGED
@@ -13,7 +13,121 @@
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
  import functools
15
15
  import inspect
16
- from typing import Any, Callable, Optional
16
+ import warnings
17
+ from typing import (
18
+ Any,
19
+ Callable,
20
+ List,
21
+ Optional,
22
+ Tuple,
23
+ Union,
24
+ get_args,
25
+ get_origin,
26
+ get_type_hints,
27
+ )
28
+
29
+ from pydantic import create_model
30
+ from pydantic.errors import PydanticSchemaGenerationError
31
+
32
+ from camel.logger import get_logger
33
+
34
+ logger = get_logger(__name__)
35
+
36
+
37
+ def _is_pydantic_serializable(type_annotation: Any) -> Tuple[bool, str]:
38
+ r"""Check if a type annotation is Pydantic serializable.
39
+
40
+ Args:
41
+ type_annotation: The type annotation to check
42
+
43
+ Returns:
44
+ Tuple[bool, str]: (is_serializable, error_message)
45
+ """
46
+ # Handle None type
47
+ if type_annotation is type(None) or type_annotation is None:
48
+ return True, ""
49
+
50
+ # Handle generic types (List, Dict, Optional, etc.)
51
+ origin = get_origin(type_annotation)
52
+ if origin is not None:
53
+ args = get_args(type_annotation)
54
+
55
+ # For Union types (including Optional), check all args
56
+ if origin is Union:
57
+ for arg in args:
58
+ is_serializable, error_msg = _is_pydantic_serializable(arg)
59
+ if not is_serializable:
60
+ return False, error_msg
61
+ return True, ""
62
+
63
+ # For List, Set, Tuple, etc., check the contained types
64
+ if origin in (list, set, tuple, frozenset):
65
+ for arg in args:
66
+ is_serializable, error_msg = _is_pydantic_serializable(arg)
67
+ if not is_serializable:
68
+ return False, error_msg
69
+ return True, ""
70
+
71
+ # For Dict, check both key and value types
72
+ if origin is dict:
73
+ for arg in args:
74
+ is_serializable, error_msg = _is_pydantic_serializable(arg)
75
+ if not is_serializable:
76
+ return False, error_msg
77
+ return True, ""
78
+
79
+ # Try to create a simple pydantic model with this type
80
+ try:
81
+ create_model("TestModel", test_field=(type_annotation, ...))
82
+ # If model creation succeeds, the type is serializable
83
+ return True, ""
84
+ except (PydanticSchemaGenerationError, TypeError, ValueError) as e:
85
+ error_msg = (
86
+ f"Type '{type_annotation}' is not Pydantic serializable. "
87
+ f"Consider using a custom serializable type or converting "
88
+ f"to bytes/base64. Error: {e!s}"
89
+ )
90
+ return False, error_msg
91
+
92
+
93
+ def _validate_function_types(func: Callable[..., Any]) -> List[str]:
94
+ r"""Validate function parameter and return types are Pydantic serializable.
95
+
96
+ Args:
97
+ func (Callable[..., Any]): The function to validate.
98
+
99
+ Returns:
100
+ List[str]: List of error messages for incompatible types.
101
+ """
102
+ errors = []
103
+
104
+ try:
105
+ type_hints = get_type_hints(func)
106
+ except (NameError, AttributeError) as e:
107
+ # If we can't get type hints, skip validation
108
+ logger.warning(f"Could not get type hints for {func.__name__}: {e}")
109
+ return []
110
+
111
+ # Check return type
112
+ return_type = type_hints.get('return', Any)
113
+ if return_type != Any:
114
+ is_serializable, error_msg = _is_pydantic_serializable(return_type)
115
+ if not is_serializable:
116
+ errors.append(f"Return type: {error_msg}")
117
+
118
+ # Check parameter types
119
+ sig = inspect.signature(func)
120
+ for param_name, _param in sig.parameters.items():
121
+ if param_name == 'self':
122
+ continue
123
+
124
+ param_type = type_hints.get(param_name, Any)
125
+ if param_type != Any:
126
+ is_serializable, error_msg = _is_pydantic_serializable(param_type)
127
+ if not is_serializable:
128
+ errors.append(f"Parameter '{param_name}': {error_msg}")
129
+
130
+ return errors
17
131
 
18
132
 
19
133
  class MCPServer:
@@ -55,7 +169,7 @@ class MCPServer:
55
169
 
56
170
  def __init__(
57
171
  self,
58
- function_names: Optional[list[str]] = None,
172
+ function_names: Optional[List[str]] = None,
59
173
  server_name: Optional[str] = None,
60
174
  ):
61
175
  self.function_names = function_names
@@ -106,11 +220,11 @@ class MCPServer:
106
220
  """
107
221
  from mcp.server.fastmcp import FastMCP
108
222
 
109
- from camel.toolkits.base import BaseToolkit
110
-
111
223
  original_init = cls.__init__
112
224
 
113
225
  def new_init(instance, *args, **kwargs):
226
+ from camel.toolkits.base import BaseToolkit
227
+
114
228
  original_init(instance, *args, **kwargs)
115
229
  self.server_name = self.server_name or cls.__name__
116
230
  instance.mcp = FastMCP(self.server_name)
@@ -135,6 +249,26 @@ class MCPServer:
135
249
  f"Method {name} not found in class {cls.__name__} or "
136
250
  "cannot be called."
137
251
  )
252
+
253
+ # Validate function types for Pydantic compatibility
254
+ type_errors = _validate_function_types(func)
255
+ if type_errors:
256
+ error_message = (
257
+ f"Method '{name}' in class '{cls.__name__}' has "
258
+ f"non-Pydantic-serializable types:\n"
259
+ + "\n".join(f" - {error}" for error in type_errors)
260
+ + "\n\nSuggestions:"
261
+ + "\n - Use standard Python types (str, int, float, bool, bytes)" # noqa: E501
262
+ + "\n - Convert complex objects to JSON strings or bytes" # noqa: E501
263
+ + "\n - Create custom Pydantic models for complex data" # noqa: E501
264
+ + "\n - Use base64 encoding for binary data like images" # noqa: E501
265
+ )
266
+
267
+ # For now, issue a warning instead of raising an error
268
+ # This allows gradual migration while alerting developers
269
+ warnings.warn(error_message, UserWarning, stacklevel=3)
270
+ logger.warning(error_message)
271
+
138
272
  wrapper = self.make_wrapper(func)
139
273
  instance.mcp.tool(name=name)(wrapper)
140
274
 
@@ -133,7 +133,11 @@ class OpenAITokenCounter(BaseTokenCounter):
133
133
  self.tokens_per_message = 4
134
134
  # If there's a name, the role is omitted
135
135
  self.tokens_per_name = -1
136
- elif ("gpt-3.5-turbo" in self.model) or ("gpt-4" in self.model):
136
+ elif (
137
+ ("gpt-3.5-turbo" in self.model)
138
+ or ("gpt-4" in self.model)
139
+ or ("gpt-5" in self.model)
140
+ ):
137
141
  self.tokens_per_message = 3
138
142
  self.tokens_per_name = 1
139
143
  elif (
@@ -191,24 +195,32 @@ class OpenAITokenCounter(BaseTokenCounter):
191
195
  image_str: str = item["image_url"]["url"]
192
196
  detail = item["image_url"]["detail"]
193
197
 
194
- image_prefix_format = "data:image/{};base64,"
195
- image_prefix: Optional[str] = None
196
- for image_type in list(OpenAIImageType):
197
- # Find the correct image format
198
- image_prefix = image_prefix_format.format(
199
- image_type.value
198
+ # Only count tokens for base64 encoded images
199
+ # For URLs, we cannot reliably determine token count without fetching the image
200
+ if image_str.startswith("data:image"):
201
+ # Base64 encoded image
202
+ image_prefix_format = "data:image/{};base64,"
203
+ image_prefix: Optional[str] = None
204
+ for image_type in list(OpenAIImageType):
205
+ # Find the correct image format
206
+ image_prefix = image_prefix_format.format(
207
+ image_type.value
208
+ )
209
+ if image_prefix in image_str:
210
+ break
211
+ assert isinstance(image_prefix, str)
212
+ encoded_image = image_str.split(image_prefix)[
213
+ 1
214
+ ]
215
+ image_bytes = BytesIO(
216
+ base64.b64decode(encoded_image)
200
217
  )
201
- if image_prefix in image_str:
202
- break
203
- assert isinstance(image_prefix, str)
204
- encoded_image = image_str.split(image_prefix)[1]
205
- image_bytes = BytesIO(
206
- base64.b64decode(encoded_image)
207
- )
208
- image = Image.open(image_bytes)
209
- num_tokens += self._count_tokens_from_image(
210
- image, OpenAIVisionDetailType(detail)
211
- )
218
+ image = Image.open(image_bytes)
219
+ num_tokens += self._count_tokens_from_image(
220
+ image, OpenAIVisionDetailType(detail)
221
+ )
222
+ # Note: For regular URLs, token count cannot be determined without fetching the image
223
+ # The actual token usage will be reported by the API response
212
224
  if key == "name":
213
225
  num_tokens += self.tokens_per_name
214
226
 
@@ -280,15 +292,26 @@ class OpenAITokenCounter(BaseTokenCounter):
280
292
 
281
293
  class AnthropicTokenCounter(BaseTokenCounter):
282
294
  @dependencies_required('anthropic')
283
- def __init__(self, model: str):
295
+ def __init__(
296
+ self,
297
+ model: str,
298
+ api_key: Optional[str] = None,
299
+ base_url: Optional[str] = None,
300
+ ):
284
301
  r"""Constructor for the token counter for Anthropic models.
285
302
 
286
303
  Args:
287
304
  model (str): The name of the Anthropic model being used.
305
+ api_key (Optional[str], optional): The API key for authenticating
306
+ with the Anthropic service. If not provided, it will use the
307
+ ANTHROPIC_API_KEY environment variable. (default: :obj:`None`)
308
+ base_url (Optional[str], optional): The URL of the Anthropic
309
+ service. If not provided, it will use the default Anthropic
310
+ URL. (default: :obj:`None`)
288
311
  """
289
312
  from anthropic import Anthropic
290
313
 
291
- self.client = Anthropic()
314
+ self.client = Anthropic(api_key=api_key, base_url=base_url)
292
315
  self.model = model
293
316
 
294
317
  @dependencies_required('anthropic')