camel-ai 0.2.52__py3-none-any.whl → 0.2.53__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/__init__.py +2 -0
- camel/agents/chat_agent.py +20 -0
- camel/agents/mcp_agent.py +233 -0
- camel/embeddings/__init__.py +2 -0
- camel/embeddings/gemini_embedding.py +115 -0
- camel/embeddings/openai_embedding.py +11 -11
- camel/embeddings/together_embedding.py +7 -7
- camel/models/model_factory.py +6 -0
- camel/responses/agent_responses.py +1 -4
- camel/societies/role_playing.py +12 -0
- camel/toolkits/__init__.py +2 -0
- camel/toolkits/aci_toolkit.py +456 -0
- camel/toolkits/function_tool.py +5 -3
- camel/toolkits/mcp_toolkit.py +44 -1
- camel/types/__init__.py +2 -0
- camel/types/enums.py +28 -0
- camel/utils/mcp.py +63 -0
- {camel_ai-0.2.52.dist-info → camel_ai-0.2.53.dist-info}/METADATA +6 -1
- {camel_ai-0.2.52.dist-info → camel_ai-0.2.53.dist-info}/RECORD +22 -19
- {camel_ai-0.2.52.dist-info → camel_ai-0.2.53.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.52.dist-info → camel_ai-0.2.53.dist-info}/licenses/LICENSE +0 -0
camel/__init__.py
CHANGED
camel/agents/__init__.py
CHANGED
|
@@ -16,6 +16,7 @@ from .chat_agent import ChatAgent
|
|
|
16
16
|
from .critic_agent import CriticAgent
|
|
17
17
|
from .embodied_agent import EmbodiedAgent
|
|
18
18
|
from .knowledge_graph_agent import KnowledgeGraphAgent
|
|
19
|
+
from .mcp_agent import MCPAgent
|
|
19
20
|
from .repo_agent import RepoAgent
|
|
20
21
|
from .role_assignment_agent import RoleAssignmentAgent
|
|
21
22
|
from .search_agent import SearchAgent
|
|
@@ -42,5 +43,6 @@ __all__ = [
|
|
|
42
43
|
'RoleAssignmentAgent',
|
|
43
44
|
'SearchAgent',
|
|
44
45
|
'KnowledgeGraphAgent',
|
|
46
|
+
'MCPAgent',
|
|
45
47
|
'RepoAgent',
|
|
46
48
|
]
|
camel/agents/chat_agent.py
CHANGED
|
@@ -16,6 +16,7 @@ from __future__ import annotations
|
|
|
16
16
|
import json
|
|
17
17
|
import logging
|
|
18
18
|
import textwrap
|
|
19
|
+
import threading
|
|
19
20
|
import uuid
|
|
20
21
|
from collections import defaultdict
|
|
21
22
|
from datetime import datetime
|
|
@@ -151,6 +152,9 @@ class ChatAgent(BaseAgent):
|
|
|
151
152
|
model calling at each step. (default: :obj:`False`)
|
|
152
153
|
agent_id (str, optional): The ID of the agent. If not provided, a
|
|
153
154
|
random UUID will be generated. (default: :obj:`None`)
|
|
155
|
+
stop_event (Optional[threading.Event], optional): Event to signal
|
|
156
|
+
termination of the agent's operation. When set, the agent will
|
|
157
|
+
terminate its execution. (default: :obj:`None`)
|
|
154
158
|
"""
|
|
155
159
|
|
|
156
160
|
def __init__(
|
|
@@ -182,6 +186,7 @@ class ChatAgent(BaseAgent):
|
|
|
182
186
|
scheduling_strategy: str = "round_robin",
|
|
183
187
|
single_iteration: bool = False,
|
|
184
188
|
agent_id: Optional[str] = None,
|
|
189
|
+
stop_event: Optional[threading.Event] = None,
|
|
185
190
|
) -> None:
|
|
186
191
|
# Resolve model backends and set up model manager
|
|
187
192
|
resolved_models = self._resolve_models(model)
|
|
@@ -252,6 +257,7 @@ class ChatAgent(BaseAgent):
|
|
|
252
257
|
self.terminated = False
|
|
253
258
|
self.response_terminators = response_terminators or []
|
|
254
259
|
self.single_iteration = single_iteration
|
|
260
|
+
self.stop_event = stop_event
|
|
255
261
|
|
|
256
262
|
def reset(self):
|
|
257
263
|
r"""Resets the :obj:`ChatAgent` to its initial state."""
|
|
@@ -757,6 +763,13 @@ class ChatAgent(BaseAgent):
|
|
|
757
763
|
self._get_full_tool_schemas(),
|
|
758
764
|
)
|
|
759
765
|
|
|
766
|
+
# Terminate Agent if stop_event is set
|
|
767
|
+
if self.stop_event and self.stop_event.is_set():
|
|
768
|
+
# Use the _step_token_exceed to terminate the agent with reason
|
|
769
|
+
return self._step_token_exceed(
|
|
770
|
+
num_tokens, tool_call_records, "termination_triggered"
|
|
771
|
+
)
|
|
772
|
+
|
|
760
773
|
if tool_call_requests := response.tool_call_requests:
|
|
761
774
|
# Process all tool calls
|
|
762
775
|
for tool_call_request in tool_call_requests:
|
|
@@ -849,6 +862,13 @@ class ChatAgent(BaseAgent):
|
|
|
849
862
|
self._get_full_tool_schemas(),
|
|
850
863
|
)
|
|
851
864
|
|
|
865
|
+
# Terminate Agent if stop_event is set
|
|
866
|
+
if self.stop_event and self.stop_event.is_set():
|
|
867
|
+
# Use the _step_token_exceed to terminate the agent with reason
|
|
868
|
+
return self._step_token_exceed(
|
|
869
|
+
num_tokens, tool_call_records, "termination_triggered"
|
|
870
|
+
)
|
|
871
|
+
|
|
852
872
|
if tool_call_requests := response.tool_call_requests:
|
|
853
873
|
# Process all tool calls
|
|
854
874
|
for tool_call_request in tool_call_requests:
|
|
@@ -0,0 +1,233 @@
|
|
|
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
|
+
|
|
15
|
+
import json
|
|
16
|
+
import re
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
from camel.agents import ChatAgent
|
|
20
|
+
from camel.logger import get_logger
|
|
21
|
+
from camel.messages import BaseMessage
|
|
22
|
+
from camel.models import BaseModelBackend
|
|
23
|
+
from camel.prompts import TextPrompt
|
|
24
|
+
from camel.responses import ChatAgentResponse
|
|
25
|
+
from camel.toolkits import MCPToolkit
|
|
26
|
+
from camel.types import RoleType
|
|
27
|
+
|
|
28
|
+
# AgentOps decorator setting
|
|
29
|
+
try:
|
|
30
|
+
import os
|
|
31
|
+
|
|
32
|
+
if os.getenv("AGENTOPS_API_KEY") is not None:
|
|
33
|
+
from agentops import track_agent
|
|
34
|
+
else:
|
|
35
|
+
raise ImportError
|
|
36
|
+
except (ImportError, AttributeError):
|
|
37
|
+
from camel.utils import track_agent
|
|
38
|
+
|
|
39
|
+
logger = get_logger(__name__)
|
|
40
|
+
|
|
41
|
+
SYS_MSG_CONTENT = """
|
|
42
|
+
You are a helpful assistant, and you prefer to use tools provided by the user
|
|
43
|
+
to solve problems.
|
|
44
|
+
Using a tool, you will tell the user `server_idx`, `tool_name` and
|
|
45
|
+
`tool_args` formatted in JSON as following:
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"server_idx": idx,
|
|
49
|
+
"tool_name": "tool_name",
|
|
50
|
+
"tool_args": {
|
|
51
|
+
"arg1": value1,
|
|
52
|
+
"arg2": value2,
|
|
53
|
+
...
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
For example:
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"server_idx": 0,
|
|
61
|
+
"tool_name": "multiply",
|
|
62
|
+
"tool_args": {"a": 5, "b": 50}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
Otherwise, you should respond to the user directly.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
TOOLS_PROMPT = """
|
|
70
|
+
## Available Tools:
|
|
71
|
+
|
|
72
|
+
{tools}
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
FINAL_RESPONSE_PROMPT = """
|
|
76
|
+
The result `{results}` is provided by tools you proposed.
|
|
77
|
+
Please answer me according to the result directly.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@track_agent(name="MCPAgent")
|
|
82
|
+
class MCPAgent(ChatAgent):
|
|
83
|
+
def __init__(
|
|
84
|
+
self,
|
|
85
|
+
config_path: str,
|
|
86
|
+
model: Optional[BaseModelBackend] = None,
|
|
87
|
+
function_calling_available: bool = False,
|
|
88
|
+
) -> None:
|
|
89
|
+
r"""A class for the MCP agent that assists using MCP tools.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
config_path (str): Path to the MCP configuration file.
|
|
93
|
+
model (Optional[BaseModelBackend]): Model backend for the agent.
|
|
94
|
+
(default: :obj:`None`)
|
|
95
|
+
function_calling_available (bool): Flag indicating whether the
|
|
96
|
+
model is equipped with the function calling ability.
|
|
97
|
+
(default: :obj:`False`)
|
|
98
|
+
"""
|
|
99
|
+
if function_calling_available:
|
|
100
|
+
sys_msg_content = "You are a helpful assistant, and you prefer "
|
|
101
|
+
"to use tools provided by the user to solve problems."
|
|
102
|
+
else:
|
|
103
|
+
sys_msg_content = SYS_MSG_CONTENT
|
|
104
|
+
|
|
105
|
+
system_message = BaseMessage(
|
|
106
|
+
role_name="MCPRouter",
|
|
107
|
+
role_type=RoleType.ASSISTANT,
|
|
108
|
+
meta_dict=None,
|
|
109
|
+
content=sys_msg_content,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
super().__init__(system_message, model=model)
|
|
113
|
+
|
|
114
|
+
self._mcp_toolkit = MCPToolkit(config_path=config_path)
|
|
115
|
+
self._function_calling_available = function_calling_available
|
|
116
|
+
self._text_tools = None
|
|
117
|
+
|
|
118
|
+
async def connect(self):
|
|
119
|
+
r"""Explicitly connect to all MCP servers."""
|
|
120
|
+
await self._mcp_toolkit.connect()
|
|
121
|
+
|
|
122
|
+
async def close(self):
|
|
123
|
+
r"""Explicitly disconnect from all MCP servers."""
|
|
124
|
+
await self._mcp_toolkit.disconnect()
|
|
125
|
+
|
|
126
|
+
def add_mcp_tools(self):
|
|
127
|
+
r"""Get the MCP tools and wrap into the models"""
|
|
128
|
+
|
|
129
|
+
if not self._mcp_toolkit.is_connected():
|
|
130
|
+
raise RuntimeError("The MCP server is not connected")
|
|
131
|
+
|
|
132
|
+
prompt = TextPrompt(TOOLS_PROMPT)
|
|
133
|
+
self._text_tools = prompt.format(
|
|
134
|
+
tools=self._mcp_toolkit.get_text_tools()
|
|
135
|
+
)
|
|
136
|
+
if self._function_calling_available:
|
|
137
|
+
tools = self._mcp_toolkit.get_tools()
|
|
138
|
+
for tool in tools:
|
|
139
|
+
self.add_tool(tool)
|
|
140
|
+
|
|
141
|
+
async def run(
|
|
142
|
+
self,
|
|
143
|
+
prompt: str,
|
|
144
|
+
) -> ChatAgentResponse:
|
|
145
|
+
r"""Run the agent to interact with the MCP tools.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
prompt (str): The user's input prompt or query to be processed by
|
|
149
|
+
the agent.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
ChatAgentResponse: The agent's response after processing the
|
|
153
|
+
prompt and potentially executing MCP tool calls.
|
|
154
|
+
|
|
155
|
+
Raises:
|
|
156
|
+
RuntimeError: If the MCP server is not connected when attempting
|
|
157
|
+
to run.
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
if not self._mcp_toolkit.is_connected():
|
|
161
|
+
raise RuntimeError("The MCP server is not connected")
|
|
162
|
+
|
|
163
|
+
if self._function_calling_available:
|
|
164
|
+
response = await self.astep(prompt)
|
|
165
|
+
return response
|
|
166
|
+
else:
|
|
167
|
+
task = f"## Task:\n {prompt}"
|
|
168
|
+
response = await self.astep(str(self._text_tools) + task)
|
|
169
|
+
content = response.msgs[0].content.lower()
|
|
170
|
+
|
|
171
|
+
tool_calls = []
|
|
172
|
+
while "```json" in content:
|
|
173
|
+
json_match = re.search(r'```json', content)
|
|
174
|
+
if not json_match:
|
|
175
|
+
break
|
|
176
|
+
json_start = json_match.span()[1]
|
|
177
|
+
|
|
178
|
+
end_match = re.search(r'```', content[json_start:])
|
|
179
|
+
if not end_match:
|
|
180
|
+
break
|
|
181
|
+
json_end = end_match.span()[0] + json_start
|
|
182
|
+
|
|
183
|
+
tool_json = content[json_start:json_end].strip('\n')
|
|
184
|
+
try:
|
|
185
|
+
tool_calls.append(json.loads(tool_json))
|
|
186
|
+
except json.JSONDecodeError:
|
|
187
|
+
logger.warning(f"Failed to parse JSON: {tool_json}")
|
|
188
|
+
continue
|
|
189
|
+
content = content[json_end:]
|
|
190
|
+
|
|
191
|
+
if not tool_calls:
|
|
192
|
+
return response
|
|
193
|
+
else:
|
|
194
|
+
tools_results = []
|
|
195
|
+
for tool_call in tool_calls:
|
|
196
|
+
server_idx = tool_call['server_idx']
|
|
197
|
+
tool_name = tool_call['tool_name']
|
|
198
|
+
tool_args = tool_call['tool_args']
|
|
199
|
+
server = self._mcp_toolkit.servers[server_idx]
|
|
200
|
+
result = await server.call_tool(tool_name, tool_args)
|
|
201
|
+
tools_results.append({tool_name: result.content[0].text})
|
|
202
|
+
results = json.dumps(tools_results)
|
|
203
|
+
final_prompt = TextPrompt(FINAL_RESPONSE_PROMPT).format(
|
|
204
|
+
results=results
|
|
205
|
+
)
|
|
206
|
+
response = await self.astep(final_prompt)
|
|
207
|
+
return response
|
|
208
|
+
|
|
209
|
+
@classmethod
|
|
210
|
+
async def create(
|
|
211
|
+
cls,
|
|
212
|
+
config_path: str,
|
|
213
|
+
model: Optional[BaseModelBackend] = None,
|
|
214
|
+
function_calling_available: bool = False,
|
|
215
|
+
) -> "MCPAgent":
|
|
216
|
+
r"""Factory method to create and initialize an MCPAgent.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
config_path (str): Path to the MCP configuration file that contains
|
|
220
|
+
server settings and other configuration parameters.
|
|
221
|
+
model (Optional[BaseModelBackend]): Model backend for the agent.
|
|
222
|
+
If None, the default model will be used. (default: :obj:`None`)
|
|
223
|
+
function_calling_available (bool): Flag indicating whether the
|
|
224
|
+
model is equipped with function calling ability. This affects
|
|
225
|
+
the system message content. (default: :obj:`False`)
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
MCPAgent: A fully initialized MCPAgent instance ready for use.
|
|
229
|
+
"""
|
|
230
|
+
agent = cls(config_path, model, function_calling_available)
|
|
231
|
+
await agent.connect()
|
|
232
|
+
agent.add_mcp_tools()
|
|
233
|
+
return agent
|
camel/embeddings/__init__.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
from .azure_embedding import AzureEmbedding
|
|
15
15
|
from .base import BaseEmbedding
|
|
16
|
+
from .gemini_embedding import GeminiEmbedding
|
|
16
17
|
from .jina_embedding import JinaEmbedding
|
|
17
18
|
from .mistral_embedding import MistralEmbedding
|
|
18
19
|
from .openai_compatible_embedding import OpenAICompatibleEmbedding
|
|
@@ -31,4 +32,5 @@ __all__ = [
|
|
|
31
32
|
"OpenAICompatibleEmbedding",
|
|
32
33
|
"JinaEmbedding",
|
|
33
34
|
"TogetherEmbedding",
|
|
35
|
+
"GeminiEmbedding",
|
|
34
36
|
]
|
|
@@ -0,0 +1,115 @@
|
|
|
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
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from typing import Any, Optional
|
|
18
|
+
|
|
19
|
+
from camel.embeddings.base import BaseEmbedding
|
|
20
|
+
from camel.types import EmbeddingModelType, GeminiEmbeddingTaskType
|
|
21
|
+
from camel.utils import api_keys_required
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GeminiEmbedding(BaseEmbedding[str]):
|
|
25
|
+
r"""Provides text embedding functionalities using Google's Gemini models.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
model_type (EmbeddingModelType, optional): The model type to be
|
|
29
|
+
used for text embeddings.
|
|
30
|
+
(default: :obj:`GEMINI_EMBEDDING_EXP`)
|
|
31
|
+
api_key (str, optional): The API key for authenticating with the
|
|
32
|
+
Gemini service. (default: :obj:`None`)
|
|
33
|
+
dimensions (int, optional): The text embedding output dimensions.
|
|
34
|
+
(default: :obj:`None`)
|
|
35
|
+
task_type (GeminiEmbeddingTaskType, optional): The task type for which
|
|
36
|
+
to optimize the embeddings. (default: :obj:`None`)
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
RuntimeError: If an unsupported model type is specified.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
@api_keys_required(
|
|
43
|
+
[
|
|
44
|
+
("api_key", 'GEMINI_API_KEY'),
|
|
45
|
+
]
|
|
46
|
+
)
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
model_type: EmbeddingModelType = (
|
|
50
|
+
EmbeddingModelType.GEMINI_EMBEDDING_EXP
|
|
51
|
+
),
|
|
52
|
+
api_key: Optional[str] = None,
|
|
53
|
+
dimensions: Optional[int] = None,
|
|
54
|
+
task_type: Optional[GeminiEmbeddingTaskType] = None,
|
|
55
|
+
) -> None:
|
|
56
|
+
from google import genai
|
|
57
|
+
|
|
58
|
+
if not model_type.is_gemini:
|
|
59
|
+
raise ValueError("Invalid Gemini embedding model type.")
|
|
60
|
+
|
|
61
|
+
self.model_type = model_type
|
|
62
|
+
if dimensions is None:
|
|
63
|
+
self.output_dim = model_type.output_dim
|
|
64
|
+
else:
|
|
65
|
+
assert isinstance(dimensions, int)
|
|
66
|
+
self.output_dim = dimensions
|
|
67
|
+
|
|
68
|
+
self._api_key = api_key or os.environ.get("GEMINI_API_KEY")
|
|
69
|
+
self._task_type = task_type
|
|
70
|
+
|
|
71
|
+
# Initialize Gemini client
|
|
72
|
+
self._client = genai.Client(api_key=self._api_key)
|
|
73
|
+
|
|
74
|
+
def embed_list(
|
|
75
|
+
self,
|
|
76
|
+
objs: list[str],
|
|
77
|
+
**kwargs: Any,
|
|
78
|
+
) -> list[list[float]]:
|
|
79
|
+
r"""Generates embeddings for the given texts.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
objs (list[str]): The texts for which to generate the embeddings.
|
|
83
|
+
**kwargs (Any): Extra kwargs passed to the embedding API.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
list[list[float]]: A list that represents the generated embedding
|
|
87
|
+
as a list of floating-point numbers.
|
|
88
|
+
"""
|
|
89
|
+
from google.genai import types
|
|
90
|
+
|
|
91
|
+
# Create embedding config if task_type is specified
|
|
92
|
+
embed_config = None
|
|
93
|
+
if self._task_type:
|
|
94
|
+
embed_config = types.EmbedContentConfig(
|
|
95
|
+
task_type=self._task_type.value
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Process each text separately since Gemini API
|
|
99
|
+
# expects single content item
|
|
100
|
+
responses = self._client.models.embed_content(
|
|
101
|
+
model=self.model_type.value,
|
|
102
|
+
contents=objs, # type: ignore[arg-type]
|
|
103
|
+
config=embed_config,
|
|
104
|
+
**kwargs,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return [response.values for response in responses.embeddings] # type: ignore[misc,union-attr]
|
|
108
|
+
|
|
109
|
+
def get_output_dim(self) -> int:
|
|
110
|
+
r"""Returns the output dimension of the embeddings.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
int: The dimensionality of the embedding for the current model.
|
|
114
|
+
"""
|
|
115
|
+
return self.output_dim
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
16
|
import os
|
|
17
|
-
from typing import Any
|
|
17
|
+
from typing import Any, Optional, Union
|
|
18
18
|
|
|
19
19
|
from openai import OpenAI
|
|
20
20
|
|
|
@@ -27,15 +27,15 @@ class OpenAIEmbedding(BaseEmbedding[str]):
|
|
|
27
27
|
r"""Provides text embedding functionalities using OpenAI's models.
|
|
28
28
|
|
|
29
29
|
Args:
|
|
30
|
-
model_type (EmbeddingModelType
|
|
31
|
-
|
|
30
|
+
model_type (EmbeddingModelType): The model type to be used for text
|
|
31
|
+
embeddings.
|
|
32
32
|
(default: :obj:`TEXT_EMBEDDING_3_SMALL`)
|
|
33
|
-
url (Optional[str]
|
|
33
|
+
url (Optional[str]): The url to the OpenAI service.
|
|
34
34
|
(default: :obj:`None`)
|
|
35
|
-
api_key (str
|
|
36
|
-
OpenAI service. (default: :obj:`None`)
|
|
37
|
-
dimensions (int,
|
|
38
|
-
(default: :obj:`NOT_GIVEN`)
|
|
35
|
+
api_key (Optional[str]): The API key for authenticating with
|
|
36
|
+
the OpenAI service. (default: :obj:`None`)
|
|
37
|
+
dimensions (Union[int, NotGiven]): The text embedding output
|
|
38
|
+
dimensions. (default: :obj:`NOT_GIVEN`)
|
|
39
39
|
|
|
40
40
|
Raises:
|
|
41
41
|
RuntimeError: If an unsupported model type is specified.
|
|
@@ -51,9 +51,9 @@ class OpenAIEmbedding(BaseEmbedding[str]):
|
|
|
51
51
|
model_type: EmbeddingModelType = (
|
|
52
52
|
EmbeddingModelType.TEXT_EMBEDDING_3_SMALL
|
|
53
53
|
),
|
|
54
|
-
url: str
|
|
55
|
-
api_key: str
|
|
56
|
-
dimensions: int
|
|
54
|
+
url: Optional[str] = None,
|
|
55
|
+
api_key: Optional[str] = None,
|
|
56
|
+
dimensions: Union[int, NotGiven] = NOT_GIVEN,
|
|
57
57
|
) -> None:
|
|
58
58
|
if not model_type.is_openai:
|
|
59
59
|
raise ValueError("Invalid OpenAI embedding model type.")
|
|
@@ -27,7 +27,7 @@ class TogetherEmbedding(BaseEmbedding[str]):
|
|
|
27
27
|
r"""Provides text embedding functionalities using Together AI's models.
|
|
28
28
|
|
|
29
29
|
Args:
|
|
30
|
-
|
|
30
|
+
model_type (str, optional): The model name to be used for text
|
|
31
31
|
embeddings.
|
|
32
32
|
(default: :obj:`togethercomputer/m2-bert-80M-8k-retrieval`)
|
|
33
33
|
api_key (str, optional): The API key for authenticating with the
|
|
@@ -44,17 +44,17 @@ class TogetherEmbedding(BaseEmbedding[str]):
|
|
|
44
44
|
@api_keys_required([("api_key", 'TOGETHER_API_KEY')])
|
|
45
45
|
def __init__(
|
|
46
46
|
self,
|
|
47
|
-
|
|
47
|
+
model_type: str = "togethercomputer/m2-bert-80M-8k-retrieval",
|
|
48
48
|
api_key: Optional[str] = None,
|
|
49
49
|
dimensions: Optional[int] = None,
|
|
50
50
|
) -> None:
|
|
51
|
-
if not isinstance(
|
|
51
|
+
if not isinstance(model_type, str) or not model_type.strip():
|
|
52
52
|
raise ValueError("Model name must be a non-empty string")
|
|
53
53
|
|
|
54
54
|
if dimensions is not None and dimensions <= 0:
|
|
55
55
|
raise ValueError("Dimensions must be a positive integer")
|
|
56
56
|
|
|
57
|
-
self.
|
|
57
|
+
self.model_type = model_type
|
|
58
58
|
self._api_key = api_key or os.environ.get("TOGETHER_API_KEY")
|
|
59
59
|
self.output_dim = dimensions
|
|
60
60
|
|
|
@@ -91,7 +91,7 @@ class TogetherEmbedding(BaseEmbedding[str]):
|
|
|
91
91
|
try:
|
|
92
92
|
response = self.client.embeddings.create(
|
|
93
93
|
input=objs,
|
|
94
|
-
model=self.
|
|
94
|
+
model=self.model_type,
|
|
95
95
|
**kwargs,
|
|
96
96
|
)
|
|
97
97
|
|
|
@@ -100,7 +100,7 @@ class TogetherEmbedding(BaseEmbedding[str]):
|
|
|
100
100
|
self.output_dim = len(response.data[0].embedding)
|
|
101
101
|
logger.debug(
|
|
102
102
|
f"Set output dimension to {self.output_dim} for model "
|
|
103
|
-
f"{self.
|
|
103
|
+
f"{self.model_type}"
|
|
104
104
|
)
|
|
105
105
|
|
|
106
106
|
return [data.embedding for data in response.data]
|
|
@@ -130,7 +130,7 @@ class TogetherEmbedding(BaseEmbedding[str]):
|
|
|
130
130
|
if self.output_dim is None:
|
|
131
131
|
raise ValueError(
|
|
132
132
|
"Failed to determine embedding dimension for model: "
|
|
133
|
-
f"{self.
|
|
133
|
+
f"{self.model_type}"
|
|
134
134
|
)
|
|
135
135
|
|
|
136
136
|
return self.output_dim
|
camel/models/model_factory.py
CHANGED
|
@@ -71,6 +71,7 @@ class ModelFactory:
|
|
|
71
71
|
api_key: Optional[str] = None,
|
|
72
72
|
url: Optional[str] = None,
|
|
73
73
|
timeout: Optional[float] = None,
|
|
74
|
+
**kwargs,
|
|
74
75
|
) -> BaseModelBackend:
|
|
75
76
|
r"""Creates an instance of `BaseModelBackend` of the specified type.
|
|
76
77
|
|
|
@@ -94,6 +95,10 @@ class ModelFactory:
|
|
|
94
95
|
(default: :obj:`None`)
|
|
95
96
|
timeout (Optional[float], optional): The timeout value in seconds
|
|
96
97
|
for API calls. (default: :obj:`None`)
|
|
98
|
+
**kwargs: Additional model-specific parameters that will be passed
|
|
99
|
+
to the model constructor. For example, Azure OpenAI models may
|
|
100
|
+
require `api_version`, `azure_deployment_name`,
|
|
101
|
+
`azure_ad_token_provider`, and `azure_ad_token`.
|
|
97
102
|
|
|
98
103
|
Returns:
|
|
99
104
|
BaseModelBackend: The initialized backend.
|
|
@@ -202,6 +207,7 @@ class ModelFactory:
|
|
|
202
207
|
url=url,
|
|
203
208
|
token_counter=token_counter,
|
|
204
209
|
timeout=timeout,
|
|
210
|
+
**kwargs,
|
|
205
211
|
)
|
|
206
212
|
|
|
207
213
|
@classmethod
|
camel/societies/role_playing.py
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import logging
|
|
15
|
+
import threading
|
|
15
16
|
from typing import Dict, List, Optional, Sequence, Tuple, Union
|
|
16
17
|
|
|
17
18
|
from camel.agents import (
|
|
@@ -77,6 +78,9 @@ class RolePlaying:
|
|
|
77
78
|
task specify meta dict with. (default: :obj:`None`)
|
|
78
79
|
output_language (str, optional): The language to be output by the
|
|
79
80
|
agents. (default: :obj:`None`)
|
|
81
|
+
stop_event (Optional[threading.Event], optional): Event to signal
|
|
82
|
+
termination of the agent's operation. When set, the agent will
|
|
83
|
+
terminate its execution. (default: :obj:`None`)
|
|
80
84
|
"""
|
|
81
85
|
|
|
82
86
|
def __init__(
|
|
@@ -101,6 +105,7 @@ class RolePlaying:
|
|
|
101
105
|
extend_sys_msg_meta_dicts: Optional[List[Dict]] = None,
|
|
102
106
|
extend_task_specify_meta_dict: Optional[Dict] = None,
|
|
103
107
|
output_language: Optional[str] = None,
|
|
108
|
+
stop_event: Optional[threading.Event] = None,
|
|
104
109
|
) -> None:
|
|
105
110
|
if model is not None:
|
|
106
111
|
logger.warning(
|
|
@@ -156,6 +161,7 @@ class RolePlaying:
|
|
|
156
161
|
assistant_agent_kwargs=assistant_agent_kwargs,
|
|
157
162
|
user_agent_kwargs=user_agent_kwargs,
|
|
158
163
|
output_language=output_language,
|
|
164
|
+
stop_event=stop_event,
|
|
159
165
|
)
|
|
160
166
|
self.critic: Optional[Union[CriticAgent, Human]] = None
|
|
161
167
|
self.critic_sys_msg: Optional[BaseMessage] = None
|
|
@@ -316,6 +322,7 @@ class RolePlaying:
|
|
|
316
322
|
assistant_agent_kwargs: Optional[Dict] = None,
|
|
317
323
|
user_agent_kwargs: Optional[Dict] = None,
|
|
318
324
|
output_language: Optional[str] = None,
|
|
325
|
+
stop_event: Optional[threading.Event] = None,
|
|
319
326
|
) -> None:
|
|
320
327
|
r"""Initialize assistant and user agents with their system messages.
|
|
321
328
|
|
|
@@ -330,6 +337,9 @@ class RolePlaying:
|
|
|
330
337
|
pass to the user agent. (default: :obj:`None`)
|
|
331
338
|
output_language (str, optional): The language to be output by the
|
|
332
339
|
agents. (default: :obj:`None`)
|
|
340
|
+
stop_event (Optional[threading.Event], optional): Event to signal
|
|
341
|
+
termination of the agent's operation. When set, the agent will
|
|
342
|
+
terminate its execution. (default: :obj:`None`)
|
|
333
343
|
"""
|
|
334
344
|
if self.model is not None:
|
|
335
345
|
if assistant_agent_kwargs is None:
|
|
@@ -344,6 +354,7 @@ class RolePlaying:
|
|
|
344
354
|
self.assistant_agent = ChatAgent(
|
|
345
355
|
init_assistant_sys_msg,
|
|
346
356
|
output_language=output_language,
|
|
357
|
+
stop_event=stop_event,
|
|
347
358
|
**(assistant_agent_kwargs or {}),
|
|
348
359
|
)
|
|
349
360
|
self.assistant_sys_msg = self.assistant_agent.system_message
|
|
@@ -351,6 +362,7 @@ class RolePlaying:
|
|
|
351
362
|
self.user_agent = ChatAgent(
|
|
352
363
|
init_user_sys_msg,
|
|
353
364
|
output_language=output_language,
|
|
365
|
+
stop_event=stop_event,
|
|
354
366
|
**(user_agent_kwargs or {}),
|
|
355
367
|
)
|
|
356
368
|
self.user_sys_msg = self.user_agent.system_message
|
camel/toolkits/__init__.py
CHANGED
|
@@ -69,6 +69,7 @@ from .openai_agent_toolkit import OpenAIAgentToolkit
|
|
|
69
69
|
from .searxng_toolkit import SearxNGToolkit
|
|
70
70
|
from .jina_reranker_toolkit import JinaRerankerToolkit
|
|
71
71
|
from .klavis_toolkit import KlavisToolkit
|
|
72
|
+
from .aci_toolkit import ACIToolkit
|
|
72
73
|
|
|
73
74
|
|
|
74
75
|
__all__ = [
|
|
@@ -126,4 +127,5 @@ __all__ = [
|
|
|
126
127
|
'SearxNGToolkit',
|
|
127
128
|
'JinaRerankerToolkit',
|
|
128
129
|
'KlavisToolkit',
|
|
130
|
+
'ACIToolkit',
|
|
129
131
|
]
|