camel-ai 0.2.76a4__py3-none-any.whl → 0.2.76a5__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 +276 -21
- camel/configs/__init__.py +3 -0
- camel/configs/cometapi_config.py +104 -0
- camel/interpreters/docker/Dockerfile +3 -12
- camel/memories/blocks/chat_history_block.py +4 -1
- camel/memories/records.py +52 -8
- camel/messages/base.py +1 -1
- camel/models/__init__.py +2 -0
- camel/models/cometapi_model.py +83 -0
- camel/models/model_factory.py +2 -0
- camel/retrievers/auto_retriever.py +1 -0
- camel/societies/workforce/workforce.py +9 -7
- camel/storages/key_value_storages/json.py +15 -2
- camel/storages/vectordb_storages/tidb.py +8 -6
- camel/toolkits/__init__.py +4 -0
- camel/toolkits/dingtalk.py +1135 -0
- camel/toolkits/edgeone_pages_mcp_toolkit.py +11 -31
- camel/toolkits/google_drive_mcp_toolkit.py +12 -31
- camel/toolkits/message_integration.py +3 -0
- camel/toolkits/notion_mcp_toolkit.py +16 -26
- 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/terminal_toolkit/__init__.py +18 -0
- camel/toolkits/terminal_toolkit/terminal_toolkit.py +909 -0
- camel/toolkits/terminal_toolkit/utils.py +580 -0
- camel/types/enums.py +109 -0
- camel/types/unified_model_type.py +5 -0
- camel/utils/commons.py +2 -0
- {camel_ai-0.2.76a4.dist-info → camel_ai-0.2.76a5.dist-info}/METADATA +25 -6
- {camel_ai-0.2.76a4.dist-info → camel_ai-0.2.76a5.dist-info}/RECORD +34 -28
- camel/toolkits/terminal_toolkit.py +0 -1798
- {camel_ai-0.2.76a4.dist-info → camel_ai-0.2.76a5.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.76a4.dist-info → camel_ai-0.2.76a5.dist-info}/licenses/LICENSE +0 -0
camel/memories/records.py
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
# Enables postponed evaluation of annotations (for string-based type hints)
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
+
import inspect
|
|
18
19
|
import time
|
|
19
|
-
from dataclasses import asdict
|
|
20
20
|
from typing import Any, ClassVar, Dict
|
|
21
21
|
from uuid import UUID, uuid4
|
|
22
22
|
|
|
@@ -63,6 +63,20 @@ class MemoryRecord(BaseModel):
|
|
|
63
63
|
"FunctionCallingMessage": FunctionCallingMessage,
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
# Cache for constructor parameters (performance optimization)
|
|
67
|
+
_constructor_params_cache: ClassVar[Dict[str, set]] = {}
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def _get_constructor_params(cls, message_cls) -> set:
|
|
71
|
+
"""Get constructor parameters for a message class with caching."""
|
|
72
|
+
cls_name = message_cls.__name__
|
|
73
|
+
if cls_name not in cls._constructor_params_cache:
|
|
74
|
+
sig = inspect.signature(message_cls.__init__)
|
|
75
|
+
cls._constructor_params_cache[cls_name] = set(
|
|
76
|
+
sig.parameters.keys()
|
|
77
|
+
) - {'self'}
|
|
78
|
+
return cls._constructor_params_cache[cls_name]
|
|
79
|
+
|
|
66
80
|
@classmethod
|
|
67
81
|
def from_dict(cls, record_dict: Dict[str, Any]) -> "MemoryRecord":
|
|
68
82
|
r"""Reconstruct a :obj:`MemoryRecord` from the input dict.
|
|
@@ -70,14 +84,42 @@ class MemoryRecord(BaseModel):
|
|
|
70
84
|
Args:
|
|
71
85
|
record_dict(Dict[str, Any]): A dict generated by :meth:`to_dict`.
|
|
72
86
|
"""
|
|
87
|
+
from camel.types import OpenAIBackendRole, RoleType
|
|
88
|
+
|
|
73
89
|
message_cls = cls._MESSAGE_TYPES[record_dict["message"]["__class__"]]
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
90
|
+
data = record_dict["message"].copy()
|
|
91
|
+
data.pop("__class__")
|
|
92
|
+
|
|
93
|
+
# Convert role_type string to enum
|
|
94
|
+
if "role_type" in data and isinstance(data["role_type"], str):
|
|
95
|
+
data["role_type"] = RoleType(data["role_type"])
|
|
96
|
+
|
|
97
|
+
# Get valid constructor parameters (cached)
|
|
98
|
+
valid_params = cls._get_constructor_params(message_cls)
|
|
99
|
+
|
|
100
|
+
# Separate constructor args from extra fields
|
|
101
|
+
kwargs = {k: v for k, v in data.items() if k in valid_params}
|
|
102
|
+
extra_fields = {k: v for k, v in data.items() if k not in valid_params}
|
|
103
|
+
|
|
104
|
+
# Handle meta_dict properly: merge existing meta_dict with extra fields
|
|
105
|
+
existing_meta = kwargs.get("meta_dict", {}) or {}
|
|
106
|
+
if extra_fields:
|
|
107
|
+
# Extra fields take precedence, but preserve existing meta_dict
|
|
108
|
+
# structure
|
|
109
|
+
merged_meta = {**existing_meta, **extra_fields}
|
|
110
|
+
kwargs["meta_dict"] = merged_meta
|
|
111
|
+
elif not existing_meta:
|
|
112
|
+
kwargs["meta_dict"] = None
|
|
113
|
+
|
|
114
|
+
# Convert role_at_backend
|
|
115
|
+
role_at_backend = record_dict["role_at_backend"]
|
|
116
|
+
if isinstance(role_at_backend, str):
|
|
117
|
+
role_at_backend = OpenAIBackendRole(role_at_backend)
|
|
118
|
+
|
|
77
119
|
return cls(
|
|
78
120
|
uuid=UUID(record_dict["uuid"]),
|
|
79
|
-
message=
|
|
80
|
-
role_at_backend=
|
|
121
|
+
message=message_cls(**kwargs),
|
|
122
|
+
role_at_backend=role_at_backend,
|
|
81
123
|
extra_info=record_dict["extra_info"],
|
|
82
124
|
timestamp=record_dict["timestamp"],
|
|
83
125
|
agent_id=record_dict["agent_id"],
|
|
@@ -91,9 +133,11 @@ class MemoryRecord(BaseModel):
|
|
|
91
133
|
"uuid": str(self.uuid),
|
|
92
134
|
"message": {
|
|
93
135
|
"__class__": self.message.__class__.__name__,
|
|
94
|
-
**
|
|
136
|
+
**self.message.to_dict(),
|
|
95
137
|
},
|
|
96
|
-
"role_at_backend": self.role_at_backend
|
|
138
|
+
"role_at_backend": self.role_at_backend.value
|
|
139
|
+
if hasattr(self.role_at_backend, "value")
|
|
140
|
+
else self.role_at_backend,
|
|
97
141
|
"extra_info": self.extra_info,
|
|
98
142
|
"timestamp": self.timestamp,
|
|
99
143
|
"agent_id": self.agent_id,
|
camel/messages/base.py
CHANGED
camel/models/__init__.py
CHANGED
|
@@ -19,6 +19,7 @@ from .azure_openai_model import AzureOpenAIModel
|
|
|
19
19
|
from .base_audio_model import BaseAudioModel
|
|
20
20
|
from .base_model import BaseModelBackend
|
|
21
21
|
from .cohere_model import CohereModel
|
|
22
|
+
from .cometapi_model import CometAPIModel
|
|
22
23
|
from .crynux_model import CrynuxModel
|
|
23
24
|
from .deepseek_model import DeepSeekModel
|
|
24
25
|
from .fish_audio_model import FishAudioModel
|
|
@@ -69,6 +70,7 @@ __all__ = [
|
|
|
69
70
|
'StubModel',
|
|
70
71
|
'ZhipuAIModel',
|
|
71
72
|
'CohereModel',
|
|
73
|
+
'CometAPIModel',
|
|
72
74
|
'ModelFactory',
|
|
73
75
|
'ModelManager',
|
|
74
76
|
'LiteLLMModel',
|
|
@@ -0,0 +1,83 @@
|
|
|
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 os
|
|
15
|
+
from typing import Any, Dict, Optional, Union
|
|
16
|
+
|
|
17
|
+
from camel.configs import CometAPIConfig
|
|
18
|
+
from camel.models.openai_compatible_model import OpenAICompatibleModel
|
|
19
|
+
from camel.types import ModelType
|
|
20
|
+
from camel.utils import (
|
|
21
|
+
BaseTokenCounter,
|
|
22
|
+
api_keys_required,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CometAPIModel(OpenAICompatibleModel):
|
|
27
|
+
r"""LLM API served by CometAPI in a unified OpenAICompatibleModel
|
|
28
|
+
interface.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
model_type (Union[ModelType, str]): Model for which a backend is
|
|
32
|
+
created.
|
|
33
|
+
model_config_dict (Optional[Dict[str, Any]], optional): A dictionary
|
|
34
|
+
that will be fed into:obj:`openai.ChatCompletion.create()`.
|
|
35
|
+
If:obj:`None`, :obj:`CometAPIConfig().as_dict()` will be used.
|
|
36
|
+
(default: :obj:`None`)
|
|
37
|
+
api_key (Optional[str], optional): The API key for authenticating
|
|
38
|
+
with the CometAPI service. (default: :obj:`None`).
|
|
39
|
+
url (Optional[str], optional): The url to the CometAPI service.
|
|
40
|
+
(default: :obj:`None`)
|
|
41
|
+
token_counter (Optional[BaseTokenCounter], optional): Token counter to
|
|
42
|
+
use for the model. If not provided, :obj:`OpenAITokenCounter(
|
|
43
|
+
ModelType.GPT_4O_MINI)` will be used.
|
|
44
|
+
(default: :obj:`None`)
|
|
45
|
+
timeout (Optional[float], optional): The timeout value in seconds for
|
|
46
|
+
API calls. If not provided, will fall back to the MODEL_TIMEOUT
|
|
47
|
+
environment variable or default to 180 seconds.
|
|
48
|
+
(default: :obj:`None`)
|
|
49
|
+
max_retries (int, optional): Maximum number of retries for API calls.
|
|
50
|
+
(default: :obj:`3`)
|
|
51
|
+
**kwargs (Any): Additional arguments to pass to the client
|
|
52
|
+
initialization.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
@api_keys_required([("api_key", "COMETAPI_KEY")])
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
model_type: Union[ModelType, str],
|
|
59
|
+
model_config_dict: Optional[Dict[str, Any]] = None,
|
|
60
|
+
api_key: Optional[str] = None,
|
|
61
|
+
url: Optional[str] = None,
|
|
62
|
+
token_counter: Optional[BaseTokenCounter] = None,
|
|
63
|
+
timeout: Optional[float] = None,
|
|
64
|
+
max_retries: int = 3,
|
|
65
|
+
**kwargs: Any,
|
|
66
|
+
) -> None:
|
|
67
|
+
if model_config_dict is None:
|
|
68
|
+
model_config_dict = CometAPIConfig().as_dict()
|
|
69
|
+
api_key = api_key or os.environ.get("COMETAPI_KEY")
|
|
70
|
+
url = url or os.environ.get(
|
|
71
|
+
"COMETAPI_API_BASE_URL", "https://api.cometapi.com/v1"
|
|
72
|
+
)
|
|
73
|
+
timeout = timeout or float(os.environ.get("MODEL_TIMEOUT", 180))
|
|
74
|
+
super().__init__(
|
|
75
|
+
model_type=model_type,
|
|
76
|
+
model_config_dict=model_config_dict,
|
|
77
|
+
api_key=api_key,
|
|
78
|
+
url=url,
|
|
79
|
+
token_counter=token_counter,
|
|
80
|
+
timeout=timeout,
|
|
81
|
+
max_retries=max_retries,
|
|
82
|
+
**kwargs,
|
|
83
|
+
)
|
camel/models/model_factory.py
CHANGED
|
@@ -22,6 +22,7 @@ from camel.models.aws_bedrock_model import AWSBedrockModel
|
|
|
22
22
|
from camel.models.azure_openai_model import AzureOpenAIModel
|
|
23
23
|
from camel.models.base_model import BaseModelBackend
|
|
24
24
|
from camel.models.cohere_model import CohereModel
|
|
25
|
+
from camel.models.cometapi_model import CometAPIModel
|
|
25
26
|
from camel.models.crynux_model import CrynuxModel
|
|
26
27
|
from camel.models.deepseek_model import DeepSeekModel
|
|
27
28
|
from camel.models.gemini_model import GeminiModel
|
|
@@ -86,6 +87,7 @@ class ModelFactory:
|
|
|
86
87
|
ModelPlatformType.AZURE: AzureOpenAIModel,
|
|
87
88
|
ModelPlatformType.ANTHROPIC: AnthropicModel,
|
|
88
89
|
ModelPlatformType.GROQ: GroqModel,
|
|
90
|
+
ModelPlatformType.COMETAPI: CometAPIModel,
|
|
89
91
|
ModelPlatformType.NEBIUS: NebiusModel,
|
|
90
92
|
ModelPlatformType.LMSTUDIO: LMStudioModel,
|
|
91
93
|
ModelPlatformType.OPENROUTER: OpenRouterModel,
|
|
@@ -97,6 +97,7 @@ class AutoRetriever:
|
|
|
97
97
|
"URL (database url) and API key required for TiDB storage "
|
|
98
98
|
"are not provided. Format: "
|
|
99
99
|
"mysql+pymysql://<username>:<password>@<host>:4000/test"
|
|
100
|
+
"You can get the database url from https://tidbcloud.com/console/clusters"
|
|
100
101
|
)
|
|
101
102
|
return TiDBStorage(
|
|
102
103
|
vector_dim=self.embedding_model.get_output_dim(),
|
|
@@ -23,6 +23,7 @@ from collections import deque
|
|
|
23
23
|
from enum import Enum
|
|
24
24
|
from typing import (
|
|
25
25
|
Any,
|
|
26
|
+
Callable,
|
|
26
27
|
Coroutine,
|
|
27
28
|
Deque,
|
|
28
29
|
Dict,
|
|
@@ -32,6 +33,7 @@ from typing import (
|
|
|
32
33
|
Set,
|
|
33
34
|
Tuple,
|
|
34
35
|
Union,
|
|
36
|
+
cast,
|
|
35
37
|
)
|
|
36
38
|
|
|
37
39
|
from colorama import Fore
|
|
@@ -71,6 +73,7 @@ from camel.tasks.task import (
|
|
|
71
73
|
)
|
|
72
74
|
from camel.toolkits import (
|
|
73
75
|
CodeExecutionToolkit,
|
|
76
|
+
FunctionTool,
|
|
74
77
|
SearchToolkit,
|
|
75
78
|
TaskPlanningToolkit,
|
|
76
79
|
ThinkingToolkit,
|
|
@@ -345,10 +348,7 @@ class Workforce(BaseNode):
|
|
|
345
348
|
None,
|
|
346
349
|
),
|
|
347
350
|
output_language=coordinator_agent.output_language,
|
|
348
|
-
tools=
|
|
349
|
-
tool.func
|
|
350
|
-
for tool in coordinator_agent._internal_tools.values()
|
|
351
|
-
],
|
|
351
|
+
tools=list(coordinator_agent._internal_tools.values()),
|
|
352
352
|
external_tools=[
|
|
353
353
|
schema
|
|
354
354
|
for schema in coordinator_agent._external_tool_schemas.values() # noqa: E501
|
|
@@ -398,9 +398,11 @@ class Workforce(BaseNode):
|
|
|
398
398
|
|
|
399
399
|
# Since ChatAgent constructor uses a dictionary with
|
|
400
400
|
# function names as keys, we don't need to manually deduplicate.
|
|
401
|
-
combined_tools =
|
|
402
|
-
|
|
403
|
-
|
|
401
|
+
combined_tools: List[Union[FunctionTool, Callable]] = cast(
|
|
402
|
+
List[Union[FunctionTool, Callable]],
|
|
403
|
+
list(task_agent._internal_tools.values())
|
|
404
|
+
+ task_planning_tools,
|
|
405
|
+
)
|
|
404
406
|
|
|
405
407
|
# Create a new agent with the provided agent's configuration
|
|
406
408
|
# but with the combined system message and tools
|
|
@@ -17,6 +17,8 @@ from enum import EnumMeta
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from typing import Any, ClassVar, Dict, List, Optional
|
|
19
19
|
|
|
20
|
+
from pydantic import BaseModel
|
|
21
|
+
|
|
20
22
|
from camel.storages.key_value_storages import BaseKeyValueStorage
|
|
21
23
|
from camel.types import (
|
|
22
24
|
ModelType,
|
|
@@ -27,8 +29,13 @@ from camel.types import (
|
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
class CamelJSONEncoder(json.JSONEncoder):
|
|
30
|
-
r"""A custom JSON encoder for serializing
|
|
31
|
-
|
|
32
|
+
r"""A custom JSON encoder for serializing CAMEL-specific types.
|
|
33
|
+
|
|
34
|
+
Handles serialization of:
|
|
35
|
+
- Enumerated types (RoleType, TaskType, ModelType, OpenAIBackendRole)
|
|
36
|
+
- Pydantic BaseModel objects (from structured outputs)
|
|
37
|
+
|
|
38
|
+
Ensures these types can be stored in and retrieved from JSON format.
|
|
32
39
|
"""
|
|
33
40
|
|
|
34
41
|
CAMEL_ENUMS: ClassVar[Dict[str, EnumMeta]] = {
|
|
@@ -39,8 +46,14 @@ class CamelJSONEncoder(json.JSONEncoder):
|
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
def default(self, obj) -> Any:
|
|
49
|
+
# Handle CAMEL enum types
|
|
42
50
|
if type(obj) in self.CAMEL_ENUMS.values():
|
|
43
51
|
return {"__enum__": str(obj)}
|
|
52
|
+
|
|
53
|
+
# Handle Pydantic BaseModel objects (e.g., from structured outputs)
|
|
54
|
+
if isinstance(obj, BaseModel):
|
|
55
|
+
return obj.model_dump()
|
|
56
|
+
|
|
44
57
|
# Let the base class default method raise the TypeError
|
|
45
58
|
return json.JSONEncoder.default(self, obj)
|
|
46
59
|
|
|
@@ -44,7 +44,7 @@ class TiDBStorage(BaseVectorStorage):
|
|
|
44
44
|
r"""An implementation of the `BaseVectorStorage` for interacting with TiDB.
|
|
45
45
|
|
|
46
46
|
The detailed information about TiDB is available at:
|
|
47
|
-
`TiDB Vector Search <https://
|
|
47
|
+
`TiDB Vector Search <https://pingcap.com/ai>`_
|
|
48
48
|
|
|
49
49
|
Args:
|
|
50
50
|
vector_dim (int): The dimension of storing vectors.
|
|
@@ -107,10 +107,10 @@ class TiDBStorage(BaseVectorStorage):
|
|
|
107
107
|
)
|
|
108
108
|
|
|
109
109
|
def _get_table_model(self, collection_name: str) -> Any:
|
|
110
|
+
from pytidb.datatype import JSON
|
|
110
111
|
from pytidb.schema import Field, TableModel, VectorField
|
|
111
|
-
from sqlalchemy import JSON
|
|
112
112
|
|
|
113
|
-
class
|
|
113
|
+
class VectorDBRecordBase(TableModel, table=False):
|
|
114
114
|
id: Optional[str] = Field(None, primary_key=True)
|
|
115
115
|
vector: list[float] = VectorField(self.vector_dim)
|
|
116
116
|
payload: Optional[dict[str, Any]] = Field(None, sa_type=JSON)
|
|
@@ -119,7 +119,7 @@ class TiDBStorage(BaseVectorStorage):
|
|
|
119
119
|
# class names.
|
|
120
120
|
return type(
|
|
121
121
|
f"VectorDBRecord_{collection_name}",
|
|
122
|
-
(
|
|
122
|
+
(VectorDBRecordBase,),
|
|
123
123
|
{"__tablename__": collection_name},
|
|
124
124
|
table=True,
|
|
125
125
|
)
|
|
@@ -128,8 +128,9 @@ class TiDBStorage(BaseVectorStorage):
|
|
|
128
128
|
r"""Opens an existing table or creates a new table in TiDB."""
|
|
129
129
|
table = self._client.open_table(self.collection_name)
|
|
130
130
|
if table is None:
|
|
131
|
+
table_model = self._get_table_model(self.collection_name)
|
|
131
132
|
table = self._client.create_table(
|
|
132
|
-
schema=
|
|
133
|
+
schema=table_model, if_exists="skip"
|
|
133
134
|
)
|
|
134
135
|
return table
|
|
135
136
|
|
|
@@ -166,6 +167,7 @@ class TiDBStorage(BaseVectorStorage):
|
|
|
166
167
|
table.
|
|
167
168
|
"""
|
|
168
169
|
vector_count = self._table.rows()
|
|
170
|
+
|
|
169
171
|
# Get vector dimension from table schema
|
|
170
172
|
columns = self._table.columns()
|
|
171
173
|
dim_value = None
|
|
@@ -303,7 +305,7 @@ class TiDBStorage(BaseVectorStorage):
|
|
|
303
305
|
for row in rows:
|
|
304
306
|
query_results.append(
|
|
305
307
|
VectorDBQueryResult.create(
|
|
306
|
-
similarity=float(row['
|
|
308
|
+
similarity=float(row['_score']),
|
|
307
309
|
id=str(row['id']),
|
|
308
310
|
payload=row['payload'],
|
|
309
311
|
vector=row['vector'],
|
camel/toolkits/__init__.py
CHANGED
|
@@ -41,6 +41,7 @@ from .arxiv_toolkit import ArxivToolkit
|
|
|
41
41
|
from .slack_toolkit import SlackToolkit
|
|
42
42
|
from .whatsapp_toolkit import WhatsAppToolkit
|
|
43
43
|
from .wechat_official_toolkit import WeChatOfficialToolkit
|
|
44
|
+
from .dingtalk import DingtalkToolkit
|
|
44
45
|
from .twitter_toolkit import TwitterToolkit
|
|
45
46
|
from .open_api_toolkit import OpenAPIToolkit
|
|
46
47
|
from .retrieval_toolkit import RetrievalToolkit
|
|
@@ -76,6 +77,7 @@ from .klavis_toolkit import KlavisToolkit
|
|
|
76
77
|
from .aci_toolkit import ACIToolkit
|
|
77
78
|
from .origene_mcp_toolkit import OrigeneToolkit
|
|
78
79
|
from .playwright_mcp_toolkit import PlaywrightMCPToolkit
|
|
80
|
+
from .resend_toolkit import ResendToolkit
|
|
79
81
|
from .wolfram_alpha_toolkit import WolframAlphaToolkit
|
|
80
82
|
from .task_planning_toolkit import TaskPlanningToolkit
|
|
81
83
|
from .hybrid_browser_toolkit import HybridBrowserToolkit
|
|
@@ -107,6 +109,7 @@ __all__ = [
|
|
|
107
109
|
'SlackToolkit',
|
|
108
110
|
'WhatsAppToolkit',
|
|
109
111
|
'WeChatOfficialToolkit',
|
|
112
|
+
'DingtalkToolkit',
|
|
110
113
|
'ImageGenToolkit',
|
|
111
114
|
'TwitterToolkit',
|
|
112
115
|
'WeatherToolkit',
|
|
@@ -155,6 +158,7 @@ __all__ = [
|
|
|
155
158
|
'KlavisToolkit',
|
|
156
159
|
'ACIToolkit',
|
|
157
160
|
'PlaywrightMCPToolkit',
|
|
161
|
+
'ResendToolkit',
|
|
158
162
|
'WolframAlphaToolkit',
|
|
159
163
|
'BohriumToolkit',
|
|
160
164
|
'OpenAIImageToolkit', # Backward compatibility
|