camel-ai 0.2.69a4__py3-none-any.whl → 0.2.69a7__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 +220 -7
- camel/interpreters/internal_python_interpreter.py +51 -2
- camel/memories/context_creators/score_based.py +11 -6
- camel/messages/base.py +2 -2
- camel/models/base_model.py +91 -2
- camel/societies/workforce/workforce.py +214 -22
- camel/storages/__init__.py +2 -0
- camel/storages/vectordb_storages/__init__.py +2 -0
- camel/storages/vectordb_storages/chroma.py +731 -0
- camel/tasks/task.py +30 -2
- camel/toolkits/__init__.py +8 -1
- camel/toolkits/craw4ai_toolkit.py +73 -0
- camel/toolkits/edgeone_pages_mcp_toolkit.py +69 -0
- camel/toolkits/excel_toolkit.py +814 -69
- camel/toolkits/google_drive_mcp_toolkit.py +73 -0
- camel/toolkits/markitdown_toolkit.py +78 -0
- camel/toolkits/mcp_toolkit.py +31 -1
- camel/toolkits/non_visual_browser_toolkit/browser_non_visual_toolkit.py +91 -57
- camel/types/enums.py +6 -6
- {camel_ai-0.2.69a4.dist-info → camel_ai-0.2.69a7.dist-info}/METADATA +5 -6
- {camel_ai-0.2.69a4.dist-info → camel_ai-0.2.69a7.dist-info}/RECORD +24 -19
- {camel_ai-0.2.69a4.dist-info → camel_ai-0.2.69a7.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.69a4.dist-info → camel_ai-0.2.69a7.dist-info}/licenses/LICENSE +0 -0
|
@@ -19,7 +19,7 @@ import time
|
|
|
19
19
|
import uuid
|
|
20
20
|
from collections import deque
|
|
21
21
|
from enum import Enum
|
|
22
|
-
from typing import Any, Coroutine, Deque, Dict, List, Optional
|
|
22
|
+
from typing import Any, Coroutine, Deque, Dict, List, Optional, Set, Tuple
|
|
23
23
|
|
|
24
24
|
from colorama import Fore
|
|
25
25
|
|
|
@@ -37,6 +37,7 @@ from camel.societies.workforce.role_playing_worker import RolePlayingWorker
|
|
|
37
37
|
from camel.societies.workforce.single_agent_worker import SingleAgentWorker
|
|
38
38
|
from camel.societies.workforce.task_channel import TaskChannel
|
|
39
39
|
from camel.societies.workforce.utils import (
|
|
40
|
+
TaskAssignment,
|
|
40
41
|
TaskAssignResult,
|
|
41
42
|
WorkerConf,
|
|
42
43
|
check_if_running,
|
|
@@ -1164,22 +1165,30 @@ class Workforce(BaseNode):
|
|
|
1164
1165
|
)
|
|
1165
1166
|
return info
|
|
1166
1167
|
|
|
1167
|
-
def
|
|
1168
|
-
|
|
1169
|
-
|
|
1168
|
+
def _get_valid_worker_ids(self) -> set:
|
|
1169
|
+
r"""Get all valid worker IDs from child nodes.
|
|
1170
|
+
|
|
1171
|
+
Returns:
|
|
1172
|
+
set: Set of valid worker IDs that can be assigned tasks.
|
|
1173
|
+
"""
|
|
1174
|
+
valid_worker_ids = {child.node_id for child in self._children}
|
|
1175
|
+
return valid_worker_ids
|
|
1176
|
+
|
|
1177
|
+
def _call_coordinator_for_assignment(
|
|
1178
|
+
self, tasks: List[Task], invalid_ids: Optional[List[str]] = None
|
|
1170
1179
|
) -> TaskAssignResult:
|
|
1171
|
-
r"""
|
|
1180
|
+
r"""Call coordinator agent to assign tasks with optional validation
|
|
1181
|
+
feedback in the case of invalid worker IDs.
|
|
1172
1182
|
|
|
1173
|
-
|
|
1174
|
-
tasks (List[Task]):
|
|
1183
|
+
Args:
|
|
1184
|
+
tasks (List[Task]): Tasks to assign.
|
|
1185
|
+
invalid_ids (List[str], optional): Invalid worker IDs from previous
|
|
1186
|
+
attempt (if any).
|
|
1175
1187
|
|
|
1176
1188
|
Returns:
|
|
1177
|
-
TaskAssignResult: Assignment result
|
|
1178
|
-
with their dependencies.
|
|
1189
|
+
TaskAssignResult: Assignment result from coordinator.
|
|
1179
1190
|
"""
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
# Format tasks information for the prompt
|
|
1191
|
+
# format tasks information for the prompt
|
|
1183
1192
|
tasks_info = ""
|
|
1184
1193
|
for task in tasks:
|
|
1185
1194
|
tasks_info += f"Task ID: {task.id}\n"
|
|
@@ -1188,29 +1197,212 @@ class Workforce(BaseNode):
|
|
|
1188
1197
|
tasks_info += f"Additional Info: {task.additional_info}\n"
|
|
1189
1198
|
tasks_info += "---\n"
|
|
1190
1199
|
|
|
1191
|
-
prompt =
|
|
1192
|
-
|
|
1193
|
-
|
|
1200
|
+
prompt = str(
|
|
1201
|
+
ASSIGN_TASK_PROMPT.format(
|
|
1202
|
+
tasks_info=tasks_info,
|
|
1203
|
+
child_nodes_info=self._get_child_nodes_info(),
|
|
1204
|
+
)
|
|
1194
1205
|
)
|
|
1195
1206
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1207
|
+
# add feedback if this is a retry
|
|
1208
|
+
if invalid_ids:
|
|
1209
|
+
valid_worker_ids = list(self._get_valid_worker_ids())
|
|
1210
|
+
feedback = (
|
|
1211
|
+
f"VALIDATION ERROR: The following worker IDs are invalid: "
|
|
1212
|
+
f"{invalid_ids}. "
|
|
1213
|
+
f"VALID WORKER IDS: {valid_worker_ids}. "
|
|
1214
|
+
f"Please reassign ONLY the above tasks using these valid IDs."
|
|
1215
|
+
)
|
|
1216
|
+
prompt = prompt + f"\n\n{feedback}"
|
|
1200
1217
|
|
|
1201
1218
|
response = self.coordinator_agent.step(
|
|
1202
1219
|
prompt, response_format=TaskAssignResult
|
|
1203
1220
|
)
|
|
1221
|
+
|
|
1204
1222
|
if response.msg is None or response.msg.content is None:
|
|
1205
1223
|
logger.error(
|
|
1206
1224
|
"Coordinator agent returned empty response for task assignment"
|
|
1207
1225
|
)
|
|
1208
|
-
# Return empty result as fallback
|
|
1209
1226
|
return TaskAssignResult(assignments=[])
|
|
1210
1227
|
|
|
1211
1228
|
result_dict = json.loads(response.msg.content, parse_int=str)
|
|
1212
|
-
|
|
1213
|
-
|
|
1229
|
+
return TaskAssignResult(**result_dict)
|
|
1230
|
+
|
|
1231
|
+
def _validate_assignments(
|
|
1232
|
+
self, assignments: List[TaskAssignment], valid_ids: Set[str]
|
|
1233
|
+
) -> Tuple[List[TaskAssignment], List[TaskAssignment]]:
|
|
1234
|
+
r"""Validate task assignments against valid worker IDs.
|
|
1235
|
+
|
|
1236
|
+
Args:
|
|
1237
|
+
assignments (List[TaskAssignment]): Assignments to validate.
|
|
1238
|
+
valid_ids (Set[str]): Set of valid worker IDs.
|
|
1239
|
+
|
|
1240
|
+
Returns:
|
|
1241
|
+
Tuple[List[TaskAssignment], List[TaskAssignment]]:
|
|
1242
|
+
(valid_assignments, invalid_assignments)
|
|
1243
|
+
"""
|
|
1244
|
+
valid_assignments: List[TaskAssignment] = []
|
|
1245
|
+
invalid_assignments: List[TaskAssignment] = []
|
|
1246
|
+
|
|
1247
|
+
for assignment in assignments:
|
|
1248
|
+
if assignment.assignee_id in valid_ids:
|
|
1249
|
+
valid_assignments.append(assignment)
|
|
1250
|
+
else:
|
|
1251
|
+
invalid_assignments.append(assignment)
|
|
1252
|
+
|
|
1253
|
+
return valid_assignments, invalid_assignments
|
|
1254
|
+
|
|
1255
|
+
def _handle_task_assignment_fallbacks(self, tasks: List[Task]) -> List:
|
|
1256
|
+
r"""Create new workers for unassigned tasks as fallback.
|
|
1257
|
+
|
|
1258
|
+
Args:
|
|
1259
|
+
tasks (List[Task]): Tasks that need new workers.
|
|
1260
|
+
|
|
1261
|
+
Returns:
|
|
1262
|
+
List[TaskAssignment]: Assignments for newly created workers.
|
|
1263
|
+
"""
|
|
1264
|
+
fallback_assignments = []
|
|
1265
|
+
|
|
1266
|
+
for task in tasks:
|
|
1267
|
+
logger.info(f"Creating new worker for unassigned task {task.id}")
|
|
1268
|
+
new_worker = self._create_worker_node_for_task(task)
|
|
1269
|
+
|
|
1270
|
+
assignment = TaskAssignment(
|
|
1271
|
+
task_id=task.id,
|
|
1272
|
+
assignee_id=new_worker.node_id,
|
|
1273
|
+
dependencies=[],
|
|
1274
|
+
)
|
|
1275
|
+
fallback_assignments.append(assignment)
|
|
1276
|
+
|
|
1277
|
+
return fallback_assignments
|
|
1278
|
+
|
|
1279
|
+
def _handle_assignment_retry_and_fallback(
|
|
1280
|
+
self,
|
|
1281
|
+
invalid_assignments: List[TaskAssignment],
|
|
1282
|
+
tasks: List[Task],
|
|
1283
|
+
valid_worker_ids: Set[str],
|
|
1284
|
+
) -> List[TaskAssignment]:
|
|
1285
|
+
r"""Called if Coordinator agent fails to assign tasks to valid worker
|
|
1286
|
+
IDs. Handles retry assignment and fallback worker creation for invalid
|
|
1287
|
+
assignments.
|
|
1288
|
+
|
|
1289
|
+
Args:
|
|
1290
|
+
invalid_assignments (List[TaskAssignment]): Invalid assignments to
|
|
1291
|
+
retry.
|
|
1292
|
+
tasks (List[Task]): Original tasks list for task lookup.
|
|
1293
|
+
valid_worker_ids (set): Set of valid worker IDs.
|
|
1294
|
+
|
|
1295
|
+
Returns:
|
|
1296
|
+
List[TaskAssignment]: Final assignments for the invalid tasks.
|
|
1297
|
+
"""
|
|
1298
|
+
invalid_ids = [a.assignee_id for a in invalid_assignments]
|
|
1299
|
+
invalid_tasks = [
|
|
1300
|
+
task
|
|
1301
|
+
for task in tasks
|
|
1302
|
+
if any(a.task_id == task.id for a in invalid_assignments)
|
|
1303
|
+
]
|
|
1304
|
+
|
|
1305
|
+
# handle cases where coordinator returned no assignments at all
|
|
1306
|
+
if not invalid_assignments:
|
|
1307
|
+
invalid_tasks = tasks # all tasks need assignment
|
|
1308
|
+
logger.warning(
|
|
1309
|
+
f"Coordinator returned no assignments. "
|
|
1310
|
+
f"Retrying assignment for all {len(invalid_tasks)} tasks."
|
|
1311
|
+
)
|
|
1312
|
+
else:
|
|
1313
|
+
logger.warning(
|
|
1314
|
+
f"Invalid worker IDs detected: {invalid_ids}. "
|
|
1315
|
+
f"Retrying assignment for {len(invalid_tasks)} tasks."
|
|
1316
|
+
)
|
|
1317
|
+
|
|
1318
|
+
# retry assignment with feedback
|
|
1319
|
+
retry_result = self._call_coordinator_for_assignment(
|
|
1320
|
+
invalid_tasks, invalid_ids
|
|
1321
|
+
)
|
|
1322
|
+
final_assignments = []
|
|
1323
|
+
|
|
1324
|
+
if retry_result.assignments:
|
|
1325
|
+
retry_valid, retry_invalid = self._validate_assignments(
|
|
1326
|
+
retry_result.assignments, valid_worker_ids
|
|
1327
|
+
)
|
|
1328
|
+
final_assignments.extend(retry_valid)
|
|
1329
|
+
|
|
1330
|
+
# collect tasks that are still unassigned for fallback
|
|
1331
|
+
if retry_invalid:
|
|
1332
|
+
unassigned_tasks = [
|
|
1333
|
+
task
|
|
1334
|
+
for task in invalid_tasks
|
|
1335
|
+
if any(a.task_id == task.id for a in retry_invalid)
|
|
1336
|
+
]
|
|
1337
|
+
else:
|
|
1338
|
+
unassigned_tasks = []
|
|
1339
|
+
else:
|
|
1340
|
+
# retry failed completely, all invalid tasks need fallback
|
|
1341
|
+
logger.warning("Retry assignment failed")
|
|
1342
|
+
unassigned_tasks = invalid_tasks
|
|
1343
|
+
|
|
1344
|
+
# handle fallback for any remaining unassigned tasks
|
|
1345
|
+
if unassigned_tasks:
|
|
1346
|
+
logger.warning(
|
|
1347
|
+
f"Creating fallback workers for {len(unassigned_tasks)} "
|
|
1348
|
+
f"unassigned tasks"
|
|
1349
|
+
)
|
|
1350
|
+
fallback_assignments = self._handle_task_assignment_fallbacks(
|
|
1351
|
+
unassigned_tasks
|
|
1352
|
+
)
|
|
1353
|
+
final_assignments.extend(fallback_assignments)
|
|
1354
|
+
|
|
1355
|
+
return final_assignments
|
|
1356
|
+
|
|
1357
|
+
def _find_assignee(
|
|
1358
|
+
self,
|
|
1359
|
+
tasks: List[Task],
|
|
1360
|
+
) -> TaskAssignResult:
|
|
1361
|
+
r"""Assigns multiple tasks to worker nodes with the best capabilities.
|
|
1362
|
+
|
|
1363
|
+
Parameters:
|
|
1364
|
+
tasks (List[Task]): The tasks to be assigned.
|
|
1365
|
+
|
|
1366
|
+
Returns:
|
|
1367
|
+
TaskAssignResult: Assignment result containing task assignments
|
|
1368
|
+
with their dependencies.
|
|
1369
|
+
"""
|
|
1370
|
+
self.coordinator_agent.reset()
|
|
1371
|
+
valid_worker_ids = self._get_valid_worker_ids()
|
|
1372
|
+
|
|
1373
|
+
logger.debug(
|
|
1374
|
+
f"Sending batch assignment request to coordinator "
|
|
1375
|
+
f"for {len(tasks)} tasks."
|
|
1376
|
+
)
|
|
1377
|
+
|
|
1378
|
+
assignment_result = self._call_coordinator_for_assignment(tasks)
|
|
1379
|
+
|
|
1380
|
+
# validate assignments
|
|
1381
|
+
valid_assignments, invalid_assignments = self._validate_assignments(
|
|
1382
|
+
assignment_result.assignments, valid_worker_ids
|
|
1383
|
+
)
|
|
1384
|
+
|
|
1385
|
+
# check if we have assignments for all tasks
|
|
1386
|
+
assigned_task_ids = {
|
|
1387
|
+
a.task_id for a in valid_assignments + invalid_assignments
|
|
1388
|
+
}
|
|
1389
|
+
unassigned_tasks = [t for t in tasks if t.id not in assigned_task_ids]
|
|
1390
|
+
|
|
1391
|
+
# if all assignments are valid and all tasks are assigned, return early
|
|
1392
|
+
if not invalid_assignments and not unassigned_tasks:
|
|
1393
|
+
return TaskAssignResult(assignments=valid_assignments)
|
|
1394
|
+
|
|
1395
|
+
# handle retry and fallback for
|
|
1396
|
+
# invalid assignments and unassigned tasks
|
|
1397
|
+
all_problem_assignments = invalid_assignments
|
|
1398
|
+
retry_and_fallback_assignments = (
|
|
1399
|
+
self._handle_assignment_retry_and_fallback(
|
|
1400
|
+
all_problem_assignments, tasks, valid_worker_ids
|
|
1401
|
+
)
|
|
1402
|
+
)
|
|
1403
|
+
valid_assignments.extend(retry_and_fallback_assignments)
|
|
1404
|
+
|
|
1405
|
+
return TaskAssignResult(assignments=valid_assignments)
|
|
1214
1406
|
|
|
1215
1407
|
async def _post_task(self, task: Task, assignee_id: str) -> None:
|
|
1216
1408
|
# Record the start time when a task is posted
|
camel/storages/__init__.py
CHANGED
|
@@ -26,6 +26,7 @@ from .vectordb_storages.base import (
|
|
|
26
26
|
VectorDBQueryResult,
|
|
27
27
|
VectorRecord,
|
|
28
28
|
)
|
|
29
|
+
from .vectordb_storages.chroma import ChromaStorage
|
|
29
30
|
from .vectordb_storages.faiss import FaissStorage
|
|
30
31
|
from .vectordb_storages.milvus import MilvusStorage
|
|
31
32
|
from .vectordb_storages.oceanbase import OceanBaseStorage
|
|
@@ -52,4 +53,5 @@ __all__ = [
|
|
|
52
53
|
'Mem0Storage',
|
|
53
54
|
'OceanBaseStorage',
|
|
54
55
|
'WeaviateStorage',
|
|
56
|
+
'ChromaStorage',
|
|
55
57
|
]
|
|
@@ -19,6 +19,7 @@ from .base import (
|
|
|
19
19
|
VectorDBStatus,
|
|
20
20
|
VectorRecord,
|
|
21
21
|
)
|
|
22
|
+
from .chroma import ChromaStorage
|
|
22
23
|
from .faiss import FaissStorage
|
|
23
24
|
from .milvus import MilvusStorage
|
|
24
25
|
from .oceanbase import OceanBaseStorage
|
|
@@ -30,6 +31,7 @@ __all__ = [
|
|
|
30
31
|
'BaseVectorStorage',
|
|
31
32
|
'VectorDBQuery',
|
|
32
33
|
'VectorDBQueryResult',
|
|
34
|
+
'ChromaStorage',
|
|
33
35
|
'QdrantStorage',
|
|
34
36
|
'MilvusStorage',
|
|
35
37
|
"TiDBStorage",
|