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.
- camel/__init__.py +1 -1
- camel/agents/_utils.py +38 -0
- camel/agents/chat_agent.py +2217 -519
- camel/agents/mcp_agent.py +30 -27
- camel/configs/__init__.py +15 -0
- camel/configs/aihubmix_config.py +88 -0
- camel/configs/amd_config.py +70 -0
- camel/configs/cometapi_config.py +104 -0
- camel/configs/minimax_config.py +93 -0
- camel/configs/nebius_config.py +103 -0
- camel/data_collectors/alpaca_collector.py +15 -6
- camel/datasets/base_generator.py +39 -10
- camel/environments/single_step.py +28 -3
- camel/environments/tic_tac_toe.py +1 -1
- camel/interpreters/__init__.py +2 -0
- camel/interpreters/docker/Dockerfile +3 -12
- camel/interpreters/e2b_interpreter.py +34 -1
- camel/interpreters/microsandbox_interpreter.py +395 -0
- camel/loaders/__init__.py +11 -2
- camel/loaders/chunkr_reader.py +9 -0
- camel/memories/agent_memories.py +48 -4
- camel/memories/base.py +26 -0
- camel/memories/blocks/chat_history_block.py +122 -4
- camel/memories/context_creators/score_based.py +25 -384
- camel/memories/records.py +88 -8
- camel/messages/base.py +153 -34
- camel/models/__init__.py +10 -0
- camel/models/aihubmix_model.py +83 -0
- camel/models/aiml_model.py +1 -16
- camel/models/amd_model.py +101 -0
- camel/models/anthropic_model.py +6 -19
- camel/models/aws_bedrock_model.py +2 -33
- camel/models/azure_openai_model.py +114 -89
- camel/models/base_audio_model.py +3 -1
- camel/models/base_model.py +32 -14
- camel/models/cohere_model.py +1 -16
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +1 -16
- camel/models/deepseek_model.py +1 -16
- camel/models/fish_audio_model.py +6 -0
- camel/models/gemini_model.py +36 -18
- camel/models/groq_model.py +1 -17
- camel/models/internlm_model.py +1 -16
- camel/models/litellm_model.py +1 -16
- camel/models/lmstudio_model.py +1 -17
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +1 -16
- camel/models/model_factory.py +27 -1
- camel/models/modelscope_model.py +1 -16
- camel/models/moonshot_model.py +105 -24
- camel/models/nebius_model.py +83 -0
- camel/models/nemotron_model.py +0 -5
- camel/models/netmind_model.py +1 -16
- camel/models/novita_model.py +1 -16
- camel/models/nvidia_model.py +1 -16
- camel/models/ollama_model.py +4 -19
- camel/models/openai_compatible_model.py +62 -41
- camel/models/openai_model.py +62 -57
- camel/models/openrouter_model.py +1 -17
- camel/models/ppio_model.py +1 -16
- camel/models/qianfan_model.py +1 -16
- camel/models/qwen_model.py +1 -16
- camel/models/reka_model.py +1 -16
- camel/models/samba_model.py +34 -47
- camel/models/sglang_model.py +64 -31
- camel/models/siliconflow_model.py +1 -16
- camel/models/stub_model.py +0 -4
- camel/models/togetherai_model.py +1 -16
- camel/models/vllm_model.py +1 -16
- camel/models/volcano_model.py +0 -17
- camel/models/watsonx_model.py +1 -16
- camel/models/yi_model.py +1 -16
- camel/models/zhipuai_model.py +60 -16
- camel/parsers/__init__.py +18 -0
- camel/parsers/mcp_tool_call_parser.py +176 -0
- camel/retrievers/auto_retriever.py +1 -0
- camel/runtimes/daytona_runtime.py +11 -12
- camel/societies/__init__.py +2 -0
- camel/societies/workforce/__init__.py +2 -0
- camel/societies/workforce/events.py +122 -0
- camel/societies/workforce/prompts.py +146 -66
- camel/societies/workforce/role_playing_worker.py +15 -11
- camel/societies/workforce/single_agent_worker.py +302 -65
- camel/societies/workforce/structured_output_handler.py +30 -18
- camel/societies/workforce/task_channel.py +163 -27
- camel/societies/workforce/utils.py +107 -13
- camel/societies/workforce/workflow_memory_manager.py +772 -0
- camel/societies/workforce/workforce.py +1949 -579
- camel/societies/workforce/workforce_callback.py +74 -0
- camel/societies/workforce/workforce_logger.py +168 -145
- camel/societies/workforce/workforce_metrics.py +33 -0
- camel/storages/key_value_storages/json.py +15 -2
- camel/storages/key_value_storages/mem0_cloud.py +48 -47
- camel/storages/object_storages/google_cloud.py +1 -1
- camel/storages/vectordb_storages/oceanbase.py +13 -13
- camel/storages/vectordb_storages/qdrant.py +3 -3
- camel/storages/vectordb_storages/tidb.py +8 -6
- camel/tasks/task.py +4 -3
- camel/toolkits/__init__.py +20 -7
- camel/toolkits/aci_toolkit.py +45 -0
- camel/toolkits/base.py +6 -4
- camel/toolkits/code_execution.py +28 -1
- camel/toolkits/context_summarizer_toolkit.py +684 -0
- camel/toolkits/dappier_toolkit.py +5 -1
- camel/toolkits/dingtalk.py +1135 -0
- camel/toolkits/edgeone_pages_mcp_toolkit.py +11 -31
- camel/toolkits/excel_toolkit.py +1 -1
- camel/toolkits/{file_write_toolkit.py → file_toolkit.py} +430 -36
- camel/toolkits/function_tool.py +13 -3
- camel/toolkits/github_toolkit.py +104 -17
- camel/toolkits/gmail_toolkit.py +1839 -0
- camel/toolkits/google_calendar_toolkit.py +38 -4
- camel/toolkits/google_drive_mcp_toolkit.py +12 -31
- camel/toolkits/hybrid_browser_toolkit/config_loader.py +15 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +77 -8
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +884 -88
- camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +5 -612
- camel/toolkits/hybrid_browser_toolkit/ts/package.json +0 -1
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +959 -89
- camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +9 -2
- camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +281 -213
- camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +23 -3
- camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +72 -7
- camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +582 -132
- camel/toolkits/hybrid_browser_toolkit_py/actions.py +158 -0
- camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +55 -8
- camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +43 -0
- camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +321 -8
- camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +10 -4
- camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +45 -4
- camel/toolkits/{openai_image_toolkit.py → image_generation_toolkit.py} +151 -53
- camel/toolkits/klavis_toolkit.py +5 -1
- camel/toolkits/markitdown_toolkit.py +27 -1
- camel/toolkits/math_toolkit.py +64 -10
- camel/toolkits/mcp_toolkit.py +366 -71
- camel/toolkits/memory_toolkit.py +5 -1
- camel/toolkits/message_integration.py +18 -13
- camel/toolkits/minimax_mcp_toolkit.py +195 -0
- camel/toolkits/note_taking_toolkit.py +19 -10
- camel/toolkits/notion_mcp_toolkit.py +16 -26
- camel/toolkits/openbb_toolkit.py +5 -1
- camel/toolkits/origene_mcp_toolkit.py +8 -49
- camel/toolkits/playwright_mcp_toolkit.py +12 -31
- camel/toolkits/resend_toolkit.py +168 -0
- camel/toolkits/search_toolkit.py +264 -91
- camel/toolkits/slack_toolkit.py +64 -10
- camel/toolkits/terminal_toolkit/__init__.py +18 -0
- camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
- camel/toolkits/terminal_toolkit/utils.py +532 -0
- camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
- camel/toolkits/video_analysis_toolkit.py +17 -11
- camel/toolkits/wechat_official_toolkit.py +483 -0
- camel/toolkits/zapier_toolkit.py +5 -1
- camel/types/__init__.py +2 -2
- camel/types/enums.py +274 -7
- camel/types/openai_types.py +2 -2
- camel/types/unified_model_type.py +15 -0
- camel/utils/commons.py +36 -5
- camel/utils/constants.py +3 -0
- camel/utils/context_utils.py +1003 -0
- camel/utils/mcp.py +138 -4
- camel/utils/token_counting.py +43 -20
- {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +223 -83
- {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +170 -141
- camel/loaders/pandas_reader.py +0 -368
- camel/toolkits/openai_agent_toolkit.py +0 -135
- camel/toolkits/terminal_toolkit.py +0 -1550
- {camel_ai-0.2.73a4.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
- {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
|
-
|
|
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[
|
|
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
|
|
camel/utils/token_counting.py
CHANGED
|
@@ -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 (
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
#
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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__(
|
|
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')
|