camel-ai 0.2.58__py3-none-any.whl → 0.2.60__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 +126 -9
- camel/agents/critic_agent.py +73 -8
- camel/benchmarks/__init__.py +2 -0
- camel/benchmarks/browsecomp.py +854 -0
- camel/configs/cohere_config.py +1 -1
- camel/configs/mistral_config.py +1 -1
- camel/configs/openai_config.py +3 -0
- camel/configs/reka_config.py +1 -1
- camel/configs/samba_config.py +2 -2
- camel/datagen/cot_datagen.py +29 -34
- camel/embeddings/jina_embedding.py +8 -1
- camel/embeddings/sentence_transformers_embeddings.py +2 -2
- camel/embeddings/vlm_embedding.py +9 -2
- camel/human.py +14 -0
- camel/memories/records.py +3 -0
- camel/messages/base.py +15 -3
- camel/models/azure_openai_model.py +1 -0
- camel/models/model_factory.py +2 -2
- camel/retrievers/bm25_retriever.py +1 -2
- camel/retrievers/hybrid_retrival.py +2 -2
- camel/societies/role_playing.py +50 -0
- camel/societies/workforce/role_playing_worker.py +17 -8
- camel/societies/workforce/workforce.py +70 -14
- camel/storages/vectordb_storages/oceanbase.py +1 -2
- camel/toolkits/async_browser_toolkit.py +5 -1
- camel/toolkits/base.py +4 -2
- camel/toolkits/browser_toolkit.py +6 -3
- camel/toolkits/dalle_toolkit.py +4 -0
- camel/toolkits/excel_toolkit.py +11 -3
- camel/toolkits/github_toolkit.py +43 -25
- camel/toolkits/image_analysis_toolkit.py +3 -0
- camel/toolkits/jina_reranker_toolkit.py +194 -77
- camel/toolkits/mcp_toolkit.py +60 -16
- camel/toolkits/page_script.js +40 -28
- camel/toolkits/twitter_toolkit.py +6 -1
- camel/toolkits/video_analysis_toolkit.py +3 -0
- camel/toolkits/video_download_toolkit.py +3 -0
- camel/toolkits/wolfram_alpha_toolkit.py +46 -22
- camel/types/enums.py +14 -5
- {camel_ai-0.2.58.dist-info → camel_ai-0.2.60.dist-info}/METADATA +7 -9
- {camel_ai-0.2.58.dist-info → camel_ai-0.2.60.dist-info}/RECORD +44 -43
- {camel_ai-0.2.58.dist-info → camel_ai-0.2.60.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.58.dist-info → camel_ai-0.2.60.dist-info}/licenses/LICENSE +0 -0
camel/configs/cohere_config.py
CHANGED
camel/configs/mistral_config.py
CHANGED
camel/configs/openai_config.py
CHANGED
|
@@ -104,6 +104,8 @@ class ChatGPTConfig(BaseConfig):
|
|
|
104
104
|
parallel_tool_calls (bool, optional): A parameter specifying whether
|
|
105
105
|
the model should call tools in parallel or not.
|
|
106
106
|
(default: :obj:`None`)
|
|
107
|
+
extra_headers: Optional[Dict[str, str]]: Extra headers to use for the
|
|
108
|
+
model. (default: :obj:`None`)
|
|
107
109
|
"""
|
|
108
110
|
|
|
109
111
|
temperature: Optional[float] = None
|
|
@@ -120,6 +122,7 @@ class ChatGPTConfig(BaseConfig):
|
|
|
120
122
|
tool_choice: Optional[Union[Dict[str, str], str]] = None
|
|
121
123
|
reasoning_effort: Optional[str] = None
|
|
122
124
|
parallel_tool_calls: Optional[bool] = None
|
|
125
|
+
extra_headers: Optional[Dict[str, str]] = None
|
|
123
126
|
|
|
124
127
|
|
|
125
128
|
OPENAI_API_PARAMS = {param for param in ChatGPTConfig.model_fields.keys()}
|
camel/configs/reka_config.py
CHANGED
camel/configs/samba_config.py
CHANGED
|
@@ -65,7 +65,7 @@ class SambaVerseAPIConfig(BaseConfig):
|
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
SAMBA_VERSE_API_PARAMS = {
|
|
68
|
-
param for param in SambaVerseAPIConfig
|
|
68
|
+
param for param in SambaVerseAPIConfig.model_fields.keys()
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
|
|
@@ -160,5 +160,5 @@ class SambaCloudAPIConfig(BaseConfig):
|
|
|
160
160
|
|
|
161
161
|
|
|
162
162
|
SAMBA_CLOUD_API_PARAMS = {
|
|
163
|
-
param for param in SambaCloudAPIConfig
|
|
163
|
+
param for param in SambaCloudAPIConfig.model_fields.keys()
|
|
164
164
|
}
|
camel/datagen/cot_datagen.py
CHANGED
|
@@ -204,26 +204,23 @@ class CoTDataGenerator:
|
|
|
204
204
|
logger.info("Answer verification result: %s", is_correct)
|
|
205
205
|
return is_correct
|
|
206
206
|
|
|
207
|
-
def
|
|
207
|
+
def evaluate_partial_solution(
|
|
208
208
|
self, question: str, partial_solution: str = ""
|
|
209
209
|
) -> float:
|
|
210
|
-
r"""
|
|
210
|
+
r"""Evaluate the quality of a partial solution against the
|
|
211
|
+
golden answer.
|
|
211
212
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
scores
|
|
215
|
-
b. Expansion: Generate new solution steps using the generator agent
|
|
216
|
-
c. Simulation: Evaluate solution quality using similarity scores
|
|
217
|
-
d. Backpropagation: Update solution tree with new findings
|
|
213
|
+
This function generates a similarity score between the given partial
|
|
214
|
+
solution and the correct answer (golden answer).
|
|
218
215
|
|
|
219
216
|
Args:
|
|
220
|
-
question (str): The question
|
|
221
|
-
partial_solution (str): The
|
|
217
|
+
question (str): The question being solved.
|
|
218
|
+
partial_solution (str): The partial solution generated so far.
|
|
222
219
|
(default::obj:`""`)
|
|
223
220
|
|
|
224
221
|
Returns:
|
|
225
|
-
float:
|
|
226
|
-
solution
|
|
222
|
+
float: A similarity score between 0 and 1, indicating how close the
|
|
223
|
+
partial solution is to the golden answer.
|
|
227
224
|
"""
|
|
228
225
|
if question not in self.golden_answers:
|
|
229
226
|
raise ValueError(
|
|
@@ -293,10 +290,21 @@ class CoTDataGenerator:
|
|
|
293
290
|
r"""Solve a question using a multi-step approach.
|
|
294
291
|
|
|
295
292
|
The solution process follows these steps:
|
|
296
|
-
1. Try to solve directly - if correct, return the solution
|
|
297
|
-
2. If not correct,
|
|
298
|
-
|
|
299
|
-
|
|
293
|
+
1. Try to solve directly - if correct, return the solution.
|
|
294
|
+
2. If not correct, perform a search by iteratively generating
|
|
295
|
+
new solutions and evaluating their similarity scores to
|
|
296
|
+
find a good solution. The search process involves:
|
|
297
|
+
a. Generation: Generate new solution candidates using
|
|
298
|
+
the generator agent.
|
|
299
|
+
b. Evaluation: Score each solution candidate for similarity
|
|
300
|
+
to the golden answer.
|
|
301
|
+
c. Selection: Keep the best-scoring candidate found so far.
|
|
302
|
+
d. Early stopping: If a sufficiently high-scoring solution
|
|
303
|
+
is found (score > 0.9), stop early.
|
|
304
|
+
3. If the solution isn't perfect, use binary search to locate
|
|
305
|
+
errors.
|
|
306
|
+
4. Generate a new solution based on the correct part of the
|
|
307
|
+
initial solution.
|
|
300
308
|
|
|
301
309
|
Args:
|
|
302
310
|
question (str): The question to solve.
|
|
@@ -304,14 +312,14 @@ class CoTDataGenerator:
|
|
|
304
312
|
Returns:
|
|
305
313
|
str: The best solution found.
|
|
306
314
|
"""
|
|
315
|
+
|
|
307
316
|
# 1. Try direct solution first
|
|
308
317
|
solution = self.get_answer(question)
|
|
309
318
|
if self.verify_answer(question, solution):
|
|
310
319
|
logger.info("Initial solution is correct")
|
|
311
320
|
return solution
|
|
312
321
|
|
|
313
|
-
# 2. If direct solution fails,
|
|
314
|
-
# to find a solution with high similarity score
|
|
322
|
+
# 2. If direct solution fails, iteratively search for a better solution
|
|
315
323
|
best_solution = ""
|
|
316
324
|
best_score: float = 0.0
|
|
317
325
|
for i in range(self.search_limit):
|
|
@@ -319,23 +327,10 @@ class CoTDataGenerator:
|
|
|
319
327
|
current_solution = self.get_answer(question, best_solution)
|
|
320
328
|
|
|
321
329
|
# Evaluate solution similarity score
|
|
322
|
-
prompt = (
|
|
323
|
-
f"Please evaluate this solution and "
|
|
324
|
-
f"give a score between 0-1:\n"
|
|
325
|
-
f"Question: {question}\n"
|
|
326
|
-
f"Solution: {current_solution}\n"
|
|
327
|
-
f"Correct answer: {self.golden_answers.get(question, '')}\n"
|
|
328
|
-
f"Return a JSON object with a single field 'score' containing "
|
|
329
|
-
f"a float between 0 and 1, like this: {{'score': 0.85}}\n"
|
|
330
|
-
)
|
|
331
|
-
self.generator_agent.reset()
|
|
332
|
-
response = self.generator_agent.step(prompt)
|
|
333
330
|
try:
|
|
334
|
-
|
|
335
|
-
|
|
331
|
+
score = self.evaluate_partial_solution(
|
|
332
|
+
question, current_solution
|
|
336
333
|
)
|
|
337
|
-
agent_response = response.msgs[0].parsed.score # type: ignore [union-attr]
|
|
338
|
-
score = agent_response
|
|
339
334
|
|
|
340
335
|
# Exit early if we find a very good solution (score > 0.9)
|
|
341
336
|
if score > 0.9:
|
|
@@ -357,7 +352,7 @@ class CoTDataGenerator:
|
|
|
357
352
|
best_score,
|
|
358
353
|
)
|
|
359
354
|
except Exception as e:
|
|
360
|
-
logger.error("Error
|
|
355
|
+
logger.error("Error evaluating partial solution: %s", str(e))
|
|
361
356
|
continue
|
|
362
357
|
|
|
363
358
|
# 3. If the answer is not completely correct,
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
|
+
# Enables postponed evaluation of annotations (for string-based type hints)
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
15
18
|
import base64
|
|
16
19
|
import io
|
|
17
20
|
import os
|
|
@@ -104,6 +107,7 @@ class JinaEmbedding(BaseEmbedding[Union[str, Image.Image]]):
|
|
|
104
107
|
ValueError: If the input type is not supported.
|
|
105
108
|
RuntimeError: If the API request fails.
|
|
106
109
|
"""
|
|
110
|
+
|
|
107
111
|
input_data = []
|
|
108
112
|
for obj in objs:
|
|
109
113
|
if isinstance(obj, str):
|
|
@@ -111,7 +115,10 @@ class JinaEmbedding(BaseEmbedding[Union[str, Image.Image]]):
|
|
|
111
115
|
input_data.append({"text": obj})
|
|
112
116
|
else:
|
|
113
117
|
input_data.append(obj) # type: ignore[arg-type]
|
|
114
|
-
elif
|
|
118
|
+
elif (
|
|
119
|
+
obj.__class__.__module__ == "PIL.Image"
|
|
120
|
+
and obj.__class__.__name__ == "Image"
|
|
121
|
+
):
|
|
115
122
|
if self.model_type != EmbeddingModelType.JINA_CLIP_V2:
|
|
116
123
|
raise ValueError(
|
|
117
124
|
f"Model {self.model_type} does not support "
|
|
@@ -15,8 +15,6 @@ from __future__ import annotations
|
|
|
15
15
|
|
|
16
16
|
from typing import Any
|
|
17
17
|
|
|
18
|
-
from numpy import ndarray
|
|
19
|
-
|
|
20
18
|
from camel.embeddings.base import BaseEmbedding
|
|
21
19
|
|
|
22
20
|
|
|
@@ -61,6 +59,8 @@ class SentenceTransformerEncoder(BaseEmbedding[str]):
|
|
|
61
59
|
list[list[float]]: A list that represents the generated embedding
|
|
62
60
|
as a list of floating-point numbers.
|
|
63
61
|
"""
|
|
62
|
+
from numpy import ndarray
|
|
63
|
+
|
|
64
64
|
if not objs:
|
|
65
65
|
raise ValueError("Input text list is empty")
|
|
66
66
|
embeddings = self.model.encode(
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
+
|
|
15
|
+
# Enables postponed evaluation of annotations (for string-based type hints)
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
14
18
|
from typing import Any, List, Optional, Union
|
|
15
19
|
|
|
16
20
|
from PIL import Image
|
|
@@ -70,7 +74,7 @@ class VisionLanguageEmbedding(BaseEmbedding[Union[str, Image.Image]]):
|
|
|
70
74
|
def embed_list(
|
|
71
75
|
self, objs: List[Union[Image.Image, str]], **kwargs: Any
|
|
72
76
|
) -> List[List[float]]:
|
|
73
|
-
"""Generates embeddings for the given images or texts.
|
|
77
|
+
r"""Generates embeddings for the given images or texts.
|
|
74
78
|
|
|
75
79
|
Args:
|
|
76
80
|
objs (List[Image.Image|str]): The list of images or texts for
|
|
@@ -98,7 +102,10 @@ class VisionLanguageEmbedding(BaseEmbedding[Union[str, Image.Image]]):
|
|
|
98
102
|
|
|
99
103
|
result_list = []
|
|
100
104
|
for obj in objs:
|
|
101
|
-
if
|
|
105
|
+
if (
|
|
106
|
+
obj.__class__.__module__ == "PIL.Image"
|
|
107
|
+
and obj.__class__.__name__ == "Image"
|
|
108
|
+
):
|
|
102
109
|
image_input = self.processor(
|
|
103
110
|
images=obj,
|
|
104
111
|
return_tensors="pt",
|
camel/human.py
CHANGED
|
@@ -136,3 +136,17 @@ class Human:
|
|
|
136
136
|
content = self.parse_input(human_input)
|
|
137
137
|
message = meta_chat_message.create_new_instance(content)
|
|
138
138
|
return ChatAgentResponse(msgs=[message], terminated=False, info={})
|
|
139
|
+
|
|
140
|
+
def clone(self, with_memory: bool = False) -> 'Human':
|
|
141
|
+
r"""Creates a new instance of the Human class with the same
|
|
142
|
+
attributes.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
with_memory (bool): Flag indicating whether to include memory in
|
|
146
|
+
the cloned instance. Currently not used.
|
|
147
|
+
(default: :obj:`False`)
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Human: A new Human instance with the same name and logger_color.
|
|
151
|
+
"""
|
|
152
|
+
return Human(name=self.name, logger_color=self.logger_color)
|
camel/memories/records.py
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
|
+
# Enables postponed evaluation of annotations (for string-based type hints)
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
15
18
|
from dataclasses import asdict
|
|
16
19
|
from datetime import datetime, timezone
|
|
17
20
|
from typing import Any, ClassVar, Dict
|
camel/messages/base.py
CHANGED
|
@@ -11,13 +11,24 @@
|
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
+
|
|
15
|
+
# Enables postponed evaluation of annotations (for string-based type hints)
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
14
18
|
import base64
|
|
15
19
|
import io
|
|
16
20
|
import re
|
|
17
21
|
from dataclasses import dataclass
|
|
18
|
-
from typing import
|
|
22
|
+
from typing import (
|
|
23
|
+
Any,
|
|
24
|
+
Dict,
|
|
25
|
+
List,
|
|
26
|
+
Literal,
|
|
27
|
+
Optional,
|
|
28
|
+
Tuple,
|
|
29
|
+
Union,
|
|
30
|
+
)
|
|
19
31
|
|
|
20
|
-
import numpy as np
|
|
21
32
|
from PIL import Image
|
|
22
33
|
from pydantic import BaseModel
|
|
23
34
|
|
|
@@ -48,7 +59,7 @@ class BaseMessage:
|
|
|
48
59
|
role_name (str): The name of the user or assistant role.
|
|
49
60
|
role_type (RoleType): The type of role, either :obj:`RoleType.
|
|
50
61
|
ASSISTANT` or :obj:`RoleType.USER`.
|
|
51
|
-
meta_dict (Optional[Dict[str,
|
|
62
|
+
meta_dict (Optional[Dict[str, Any]]): Additional metadata dictionary
|
|
52
63
|
for the message.
|
|
53
64
|
content (str): The content of the message.
|
|
54
65
|
video_bytes (Optional[bytes]): Optional bytes of a video associated
|
|
@@ -457,6 +468,7 @@ class BaseMessage:
|
|
|
457
468
|
|
|
458
469
|
if self.video_bytes:
|
|
459
470
|
import imageio.v3 as iio
|
|
471
|
+
import numpy as np
|
|
460
472
|
|
|
461
473
|
base64Frames: List[str] = []
|
|
462
474
|
frame_count = 0
|
camel/models/model_factory.py
CHANGED
|
@@ -14,8 +14,6 @@
|
|
|
14
14
|
import json
|
|
15
15
|
from typing import ClassVar, Dict, Optional, Type, Union
|
|
16
16
|
|
|
17
|
-
import yaml
|
|
18
|
-
|
|
19
17
|
from camel.models.aiml_model import AIMLModel
|
|
20
18
|
from camel.models.anthropic_model import AnthropicModel
|
|
21
19
|
from camel.models.aws_bedrock_model import AWSBedrockModel
|
|
@@ -221,6 +219,8 @@ class ModelFactory:
|
|
|
221
219
|
|
|
222
220
|
@classmethod
|
|
223
221
|
def __load_yaml(cls, filepath: str) -> Dict:
|
|
222
|
+
import yaml
|
|
223
|
+
|
|
224
224
|
r"""Loads and parses a YAML file into a dictionary.
|
|
225
225
|
|
|
226
226
|
Args:
|
|
@@ -13,8 +13,6 @@
|
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
from typing import Any, Dict, List
|
|
15
15
|
|
|
16
|
-
import numpy as np
|
|
17
|
-
|
|
18
16
|
from camel.loaders import UnstructuredIO
|
|
19
17
|
from camel.retrievers import BaseRetriever
|
|
20
18
|
from camel.utils import dependencies_required
|
|
@@ -106,6 +104,7 @@ class BM25Retriever(BaseRetriever):
|
|
|
106
104
|
model has not been initialized by calling `process`
|
|
107
105
|
first.
|
|
108
106
|
"""
|
|
107
|
+
import numpy as np
|
|
109
108
|
|
|
110
109
|
if top_k <= 0:
|
|
111
110
|
raise ValueError("top_k must be a positive integer.")
|
|
@@ -13,8 +13,6 @@
|
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
from typing import Any, Collection, Dict, List, Optional, Sequence, Union
|
|
15
15
|
|
|
16
|
-
import numpy as np
|
|
17
|
-
|
|
18
16
|
from camel.embeddings import BaseEmbedding
|
|
19
17
|
from camel.retrievers import BaseRetriever, BM25Retriever, VectorRetriever
|
|
20
18
|
from camel.storages import BaseVectorStorage
|
|
@@ -96,6 +94,8 @@ class HybridRetriever(BaseRetriever):
|
|
|
96
94
|
https://medium.com/@devalshah1619/mathematical-intuition-behind-reciprocal-rank-fusion-rrf-explained-in-2-mins-002df0cc5e2a
|
|
97
95
|
https://colab.research.google.com/drive/1iwVJrN96fiyycxN1pBqWlEr_4EPiGdGy#scrollTo=0qh83qGV2dY8
|
|
98
96
|
"""
|
|
97
|
+
import numpy as np
|
|
98
|
+
|
|
99
99
|
text_to_id = {}
|
|
100
100
|
id_to_info = {}
|
|
101
101
|
current_id = 1
|
camel/societies/role_playing.py
CHANGED
|
@@ -120,6 +120,9 @@ class RolePlaying:
|
|
|
120
120
|
self.task_type = task_type
|
|
121
121
|
self.task_prompt = task_prompt
|
|
122
122
|
|
|
123
|
+
self.task_specify_agent_kwargs = task_specify_agent_kwargs
|
|
124
|
+
self.task_planner_agent_kwargs = task_planner_agent_kwargs
|
|
125
|
+
|
|
123
126
|
self.specified_task_prompt: Optional[TextPrompt] = None
|
|
124
127
|
self._init_specified_task_prompt(
|
|
125
128
|
assistant_role_name,
|
|
@@ -680,3 +683,50 @@ class RolePlaying:
|
|
|
680
683
|
info=user_response.info,
|
|
681
684
|
),
|
|
682
685
|
)
|
|
686
|
+
|
|
687
|
+
def clone(
|
|
688
|
+
self, task_prompt: str, with_memory: bool = False
|
|
689
|
+
) -> 'RolePlaying':
|
|
690
|
+
r"""Creates a new instance of RolePlaying with the same configuration.
|
|
691
|
+
|
|
692
|
+
Args:
|
|
693
|
+
task_prompt (str): The task prompt to be used by the new instance.
|
|
694
|
+
with_memory (bool, optional): Whether to copy the memory
|
|
695
|
+
(conversation history) to the new instance. If True, the new
|
|
696
|
+
instance will have the same conversation history. If False,
|
|
697
|
+
the new instance will have a fresh memory.
|
|
698
|
+
(default: :obj:`False`)
|
|
699
|
+
|
|
700
|
+
Returns:
|
|
701
|
+
RolePlaying: A new instance of RolePlaying with the same
|
|
702
|
+
configuration.
|
|
703
|
+
"""
|
|
704
|
+
|
|
705
|
+
new_instance = RolePlaying(
|
|
706
|
+
assistant_role_name=self.assistant_agent.role_name,
|
|
707
|
+
user_role_name=self.user_agent.role_name,
|
|
708
|
+
task_prompt=task_prompt,
|
|
709
|
+
with_task_specify=self.with_task_specify,
|
|
710
|
+
task_specify_agent_kwargs=self.task_specify_agent_kwargs,
|
|
711
|
+
with_task_planner=self.with_task_planner,
|
|
712
|
+
task_planner_agent_kwargs=self.task_planner_agent_kwargs,
|
|
713
|
+
with_critic_in_the_loop=False,
|
|
714
|
+
model=self.model,
|
|
715
|
+
task_type=self.task_type,
|
|
716
|
+
)
|
|
717
|
+
tmp_assistant_sys_msg = new_instance.assistant_sys_msg
|
|
718
|
+
new_instance.assistant_agent = self.assistant_agent.clone(with_memory)
|
|
719
|
+
new_instance.assistant_sys_msg = tmp_assistant_sys_msg
|
|
720
|
+
new_instance.assistant_agent._system_message = tmp_assistant_sys_msg
|
|
721
|
+
|
|
722
|
+
tmp_user_sys_msg = new_instance.user_sys_msg
|
|
723
|
+
new_instance.user_agent = self.user_agent.clone(with_memory)
|
|
724
|
+
new_instance.user_sys_msg = tmp_user_sys_msg
|
|
725
|
+
new_instance.user_agent._system_message = tmp_user_sys_msg
|
|
726
|
+
|
|
727
|
+
new_instance.with_critic_in_the_loop = self.with_critic_in_the_loop
|
|
728
|
+
new_instance.critic_sys_msg = self.critic_sys_msg
|
|
729
|
+
if self.critic:
|
|
730
|
+
new_instance.critic = self.critic.clone(with_memory)
|
|
731
|
+
|
|
732
|
+
return new_instance
|
|
@@ -38,14 +38,17 @@ class RolePlayingWorker(Worker):
|
|
|
38
38
|
description (str): Description of the node.
|
|
39
39
|
assistant_role_name (str): The role name of the assistant agent.
|
|
40
40
|
user_role_name (str): The role name of the user agent.
|
|
41
|
-
assistant_agent_kwargs (Optional[Dict]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
user_agent_kwargs (Optional[Dict]
|
|
41
|
+
assistant_agent_kwargs (Optional[Dict]): The keyword arguments to
|
|
42
|
+
initialize the assistant agent in the role playing, like the model
|
|
43
|
+
name, etc. (default: :obj:`None`)
|
|
44
|
+
user_agent_kwargs (Optional[Dict]): The keyword arguments to
|
|
45
45
|
initialize the user agent in the role playing, like the model name,
|
|
46
|
-
etc.
|
|
47
|
-
|
|
48
|
-
the
|
|
46
|
+
etc. (default: :obj:`None`)
|
|
47
|
+
summarize_agent_kwargs (Optional[Dict]): The keyword arguments to
|
|
48
|
+
initialize the summarize agent, like the model name, etc.
|
|
49
|
+
(default: :obj:`None`)
|
|
50
|
+
chat_turn_limit (int): The maximum number of chat turns in the role
|
|
51
|
+
playing. (default: :obj:`3`)
|
|
49
52
|
"""
|
|
50
53
|
|
|
51
54
|
def __init__(
|
|
@@ -55,9 +58,11 @@ class RolePlayingWorker(Worker):
|
|
|
55
58
|
user_role_name: str,
|
|
56
59
|
assistant_agent_kwargs: Optional[Dict] = None,
|
|
57
60
|
user_agent_kwargs: Optional[Dict] = None,
|
|
61
|
+
summarize_agent_kwargs: Optional[Dict] = None,
|
|
58
62
|
chat_turn_limit: int = 3,
|
|
59
63
|
) -> None:
|
|
60
64
|
super().__init__(description)
|
|
65
|
+
self.summarize_agent_kwargs = summarize_agent_kwargs
|
|
61
66
|
summ_sys_msg = BaseMessage.make_assistant_message(
|
|
62
67
|
role_name="Summarizer",
|
|
63
68
|
content="You are a good summarizer. You will be presented with "
|
|
@@ -65,7 +70,11 @@ class RolePlayingWorker(Worker):
|
|
|
65
70
|
"are trying to solve a task. Your job is summarizing the result "
|
|
66
71
|
"of the task based on the chat history.",
|
|
67
72
|
)
|
|
68
|
-
|
|
73
|
+
summarize_agent_dict = (
|
|
74
|
+
summarize_agent_kwargs if summarize_agent_kwargs else {}
|
|
75
|
+
)
|
|
76
|
+
summarize_agent_dict['system_message'] = summ_sys_msg
|
|
77
|
+
self.summarize_agent = ChatAgent(**summarize_agent_dict)
|
|
69
78
|
self.chat_turn_limit = chat_turn_limit
|
|
70
79
|
self.assistant_role_name = assistant_role_name
|
|
71
80
|
self.user_role_name = user_role_name
|
|
@@ -202,6 +202,7 @@ class Workforce(BaseNode):
|
|
|
202
202
|
user_role_name: str,
|
|
203
203
|
assistant_agent_kwargs: Optional[Dict] = None,
|
|
204
204
|
user_agent_kwargs: Optional[Dict] = None,
|
|
205
|
+
summarize_agent_kwargs: Optional[Dict] = None,
|
|
205
206
|
chat_turn_limit: int = 3,
|
|
206
207
|
) -> Workforce:
|
|
207
208
|
r"""Add a worker node to the workforce that uses `RolePlaying` system.
|
|
@@ -210,25 +211,29 @@ class Workforce(BaseNode):
|
|
|
210
211
|
description (str): Description of the node.
|
|
211
212
|
assistant_role_name (str): The role name of the assistant agent.
|
|
212
213
|
user_role_name (str): The role name of the user agent.
|
|
213
|
-
assistant_agent_kwargs (Optional[Dict]
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
user_agent_kwargs (Optional[Dict]
|
|
217
|
-
|
|
218
|
-
model name, etc.
|
|
219
|
-
|
|
220
|
-
|
|
214
|
+
assistant_agent_kwargs (Optional[Dict]): The keyword arguments to
|
|
215
|
+
initialize the assistant agent in the role playing, like the
|
|
216
|
+
model name, etc. (default: :obj:`None`)
|
|
217
|
+
user_agent_kwargs (Optional[Dict]): The keyword arguments to
|
|
218
|
+
initialize the user agent in the role playing, like the
|
|
219
|
+
model name, etc. (default: :obj:`None`)
|
|
220
|
+
summarize_agent_kwargs (Optional[Dict]): The keyword arguments to
|
|
221
|
+
initialize the summarize agent, like the model name, etc.
|
|
222
|
+
(default: :obj:`None`)
|
|
223
|
+
chat_turn_limit (int): The maximum number of chat turns in the
|
|
224
|
+
role playing. (default: :obj:`3`)
|
|
221
225
|
|
|
222
226
|
Returns:
|
|
223
227
|
Workforce: The workforce node itself.
|
|
224
228
|
"""
|
|
225
229
|
worker_node = RolePlayingWorker(
|
|
226
|
-
description,
|
|
227
|
-
assistant_role_name,
|
|
228
|
-
user_role_name,
|
|
229
|
-
assistant_agent_kwargs,
|
|
230
|
-
user_agent_kwargs,
|
|
231
|
-
|
|
230
|
+
description=description,
|
|
231
|
+
assistant_role_name=assistant_role_name,
|
|
232
|
+
user_role_name=user_role_name,
|
|
233
|
+
assistant_agent_kwargs=assistant_agent_kwargs,
|
|
234
|
+
user_agent_kwargs=user_agent_kwargs,
|
|
235
|
+
summarize_agent_kwargs=summarize_agent_kwargs,
|
|
236
|
+
chat_turn_limit=chat_turn_limit,
|
|
232
237
|
)
|
|
233
238
|
self._children.append(worker_node)
|
|
234
239
|
return self
|
|
@@ -501,3 +506,54 @@ class Workforce(BaseNode):
|
|
|
501
506
|
for child_task in self._child_listening_tasks:
|
|
502
507
|
child_task.cancel()
|
|
503
508
|
self._running = False
|
|
509
|
+
|
|
510
|
+
def clone(self, with_memory: bool = False) -> 'Workforce':
|
|
511
|
+
r"""Creates a new instance of Workforce with the same configuration.
|
|
512
|
+
|
|
513
|
+
Args:
|
|
514
|
+
with_memory (bool, optional): Whether to copy the memory
|
|
515
|
+
(conversation history) to the new instance. If True, the new
|
|
516
|
+
instance will have the same conversation history. If False,
|
|
517
|
+
the new instance will have a fresh memory.
|
|
518
|
+
(default: :obj:`False`)
|
|
519
|
+
|
|
520
|
+
Returns:
|
|
521
|
+
Workforce: A new instance of Workforce with the same configuration.
|
|
522
|
+
"""
|
|
523
|
+
|
|
524
|
+
# Create a new instance with the same configuration
|
|
525
|
+
new_instance = Workforce(
|
|
526
|
+
description=self.description,
|
|
527
|
+
coordinator_agent_kwargs={},
|
|
528
|
+
task_agent_kwargs={},
|
|
529
|
+
new_worker_agent_kwargs=self.new_worker_agent_kwargs,
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
new_instance.task_agent = self.task_agent.clone(with_memory)
|
|
533
|
+
new_instance.coordinator_agent = self.coordinator_agent.clone(
|
|
534
|
+
with_memory
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
for child in self._children:
|
|
538
|
+
if isinstance(child, SingleAgentWorker):
|
|
539
|
+
cloned_worker = child.worker.clone(with_memory)
|
|
540
|
+
new_instance.add_single_agent_worker(
|
|
541
|
+
child.description, cloned_worker
|
|
542
|
+
)
|
|
543
|
+
elif isinstance(child, RolePlayingWorker):
|
|
544
|
+
new_instance.add_role_playing_worker(
|
|
545
|
+
child.description,
|
|
546
|
+
child.assistant_role_name,
|
|
547
|
+
child.user_role_name,
|
|
548
|
+
child.assistant_agent_kwargs,
|
|
549
|
+
child.user_agent_kwargs,
|
|
550
|
+
child.summarize_agent_kwargs,
|
|
551
|
+
child.chat_turn_limit,
|
|
552
|
+
)
|
|
553
|
+
elif isinstance(child, Workforce):
|
|
554
|
+
new_instance.add_workforce(child.clone(with_memory))
|
|
555
|
+
else:
|
|
556
|
+
logger.warning(f"{type(child)} is not being cloned.")
|
|
557
|
+
continue
|
|
558
|
+
|
|
559
|
+
return new_instance
|
|
@@ -16,8 +16,6 @@ import json
|
|
|
16
16
|
import logging
|
|
17
17
|
from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional
|
|
18
18
|
|
|
19
|
-
from sqlalchemy import JSON, Column, Integer
|
|
20
|
-
|
|
21
19
|
if TYPE_CHECKING:
|
|
22
20
|
from pyobvector.client import ObVecClient
|
|
23
21
|
|
|
@@ -80,6 +78,7 @@ class OceanBaseStorage(BaseVectorStorage):
|
|
|
80
78
|
IndexParams,
|
|
81
79
|
)
|
|
82
80
|
from pyobvector.schema import VECTOR
|
|
81
|
+
from sqlalchemy import JSON, Column, Integer
|
|
83
82
|
|
|
84
83
|
self.vector_dim: int = vector_dim
|
|
85
84
|
self.table_name: str = table_name
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
+
|
|
15
|
+
# Enables postponed evaluation of annotations (for string-based type hints)
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
14
18
|
import asyncio
|
|
15
19
|
import datetime
|
|
16
20
|
import io
|
|
@@ -1336,7 +1340,7 @@ class AsyncBrowserToolkit(BaseToolkit):
|
|
|
1336
1340
|
|
|
1337
1341
|
def _initialize_agent(self) -> Tuple["ChatAgent", "ChatAgent"]:
|
|
1338
1342
|
r"""Initialize the agent."""
|
|
1339
|
-
from camel.agents import ChatAgent
|
|
1343
|
+
from camel.agents.chat_agent import ChatAgent
|
|
1340
1344
|
|
|
1341
1345
|
if self.web_agent_model is None:
|
|
1342
1346
|
web_agent_model = ModelFactory.create(
|
camel/toolkits/base.py
CHANGED
|
@@ -53,11 +53,13 @@ class BaseToolkit(metaclass=AgentOpsMeta):
|
|
|
53
53
|
"""
|
|
54
54
|
raise NotImplementedError("Subclasses must implement this method.")
|
|
55
55
|
|
|
56
|
-
def run_mcp_server(
|
|
56
|
+
def run_mcp_server(
|
|
57
|
+
self, mode: Literal["stdio", "sse", "streamable-http"]
|
|
58
|
+
) -> None:
|
|
57
59
|
r"""Run the MCP server in the specified mode.
|
|
58
60
|
|
|
59
61
|
Args:
|
|
60
|
-
mode (Literal["stdio", "sse"]): The mode to run
|
|
62
|
+
mode (Literal["stdio", "sse", "streamable-http"]): The mode to run
|
|
61
63
|
the MCP server in.
|
|
62
64
|
"""
|
|
63
65
|
self.mcp.run(mode)
|