camel-ai 0.2.78__py3-none-any.whl → 0.2.79a0__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.

@@ -0,0 +1,74 @@
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
+ from abc import ABC, abstractmethod
17
+
18
+ from .events import (
19
+ AllTasksCompletedEvent,
20
+ TaskAssignedEvent,
21
+ TaskCompletedEvent,
22
+ TaskCreatedEvent,
23
+ TaskDecomposedEvent,
24
+ TaskFailedEvent,
25
+ TaskStartedEvent,
26
+ WorkerCreatedEvent,
27
+ WorkerDeletedEvent,
28
+ )
29
+
30
+
31
+ class WorkforceCallback(ABC):
32
+ r"""Interface for recording workforce lifecycle events.
33
+
34
+ Implementations should persist or stream events as appropriate.
35
+ """
36
+
37
+ @abstractmethod
38
+ def log_task_created(
39
+ self,
40
+ event: TaskCreatedEvent,
41
+ ) -> None:
42
+ pass
43
+
44
+ @abstractmethod
45
+ def log_task_decomposed(self, event: TaskDecomposedEvent) -> None:
46
+ pass
47
+
48
+ @abstractmethod
49
+ def log_task_assigned(self, event: TaskAssignedEvent) -> None:
50
+ pass
51
+
52
+ @abstractmethod
53
+ def log_task_started(self, event: TaskStartedEvent) -> None:
54
+ pass
55
+
56
+ @abstractmethod
57
+ def log_task_completed(self, event: TaskCompletedEvent) -> None:
58
+ pass
59
+
60
+ @abstractmethod
61
+ def log_task_failed(self, event: TaskFailedEvent) -> None:
62
+ pass
63
+
64
+ @abstractmethod
65
+ def log_worker_created(self, event: WorkerCreatedEvent) -> None:
66
+ pass
67
+
68
+ @abstractmethod
69
+ def log_worker_deleted(self, event: WorkerDeletedEvent) -> None:
70
+ pass
71
+
72
+ @abstractmethod
73
+ def log_all_tasks_completed(self, event: AllTasksCompletedEvent) -> None:
74
+ pass
@@ -16,12 +16,26 @@ from datetime import datetime, timezone
16
16
  from typing import Any, Dict, List, Optional
17
17
 
18
18
  from camel.logger import get_logger
19
+ from camel.societies.workforce.events import (
20
+ AllTasksCompletedEvent,
21
+ QueueStatusEvent,
22
+ TaskAssignedEvent,
23
+ TaskCompletedEvent,
24
+ TaskCreatedEvent,
25
+ TaskDecomposedEvent,
26
+ TaskFailedEvent,
27
+ TaskStartedEvent,
28
+ WorkerCreatedEvent,
29
+ WorkerDeletedEvent,
30
+ )
31
+ from camel.societies.workforce.workforce_callback import WorkforceCallback
32
+ from camel.societies.workforce.workforce_metrics import WorkforceMetrics
19
33
  from camel.types.agents import ToolCallingRecord
20
34
 
21
35
  logger = get_logger(__name__)
22
36
 
23
37
 
24
- class WorkforceLogger:
38
+ class WorkforceLogger(WorkforceCallback, WorkforceMetrics):
25
39
  r"""Logs events and metrics for a Workforce instance."""
26
40
 
27
41
  def __init__(self, workforce_id: str):
@@ -55,195 +69,201 @@ class WorkforceLogger:
55
69
 
56
70
  def log_task_created(
57
71
  self,
58
- task_id: str,
59
- description: str,
60
- parent_task_id: Optional[str] = None,
61
- task_type: Optional[str] = None,
62
- metadata: Optional[Dict[str, Any]] = None,
72
+ event: TaskCreatedEvent,
63
73
  ) -> None:
64
74
  r"""Logs the creation of a new task."""
65
75
  self._log_event(
66
- 'task_created',
67
- task_id=task_id,
68
- description=description,
69
- parent_task_id=parent_task_id,
70
- task_type=task_type,
71
- metadata=metadata or {},
76
+ event_type=event.event_type,
77
+ task_id=event.task_id,
78
+ description=event.description,
79
+ parent_task_id=event.parent_task_id,
80
+ task_type=event.task_type,
81
+ metadata=event.metadata or {},
72
82
  )
73
- self._task_hierarchy[task_id] = {
74
- 'parent': parent_task_id,
83
+ self._task_hierarchy[event.task_id] = {
84
+ 'parent': event.parent_task_id,
75
85
  'children': [],
76
86
  'status': 'created',
77
- 'description': description,
87
+ 'description': event.description,
78
88
  'assigned_to': None,
79
- **(metadata or {}),
89
+ **(event.metadata or {}),
80
90
  }
81
- if parent_task_id and parent_task_id in self._task_hierarchy:
82
- self._task_hierarchy[parent_task_id]['children'].append(task_id)
91
+ if (
92
+ event.parent_task_id
93
+ and event.parent_task_id in self._task_hierarchy
94
+ ):
95
+ self._task_hierarchy[event.parent_task_id]['children'].append(
96
+ event.task_id
97
+ )
83
98
 
84
99
  def log_task_decomposed(
85
100
  self,
86
- parent_task_id: str,
87
- subtask_ids: List[str],
88
- metadata: Optional[Dict[str, Any]] = None,
101
+ event: TaskDecomposedEvent,
89
102
  ) -> None:
90
103
  r"""Logs the decomposition of a task into subtasks."""
91
104
  self._log_event(
92
- 'task_decomposed',
93
- parent_task_id=parent_task_id,
94
- subtask_ids=subtask_ids,
95
- metadata=metadata or {},
105
+ event_type=event.event_type,
106
+ parent_task_id=event.parent_task_id,
107
+ subtask_ids=event.subtask_ids,
108
+ metadata=event.metadata or {},
96
109
  )
97
- if parent_task_id in self._task_hierarchy:
98
- self._task_hierarchy[parent_task_id]['status'] = "decomposed"
110
+ if event.parent_task_id in self._task_hierarchy:
111
+ self._task_hierarchy[event.parent_task_id]['status'] = "decomposed"
99
112
 
100
113
  def log_task_assigned(
101
114
  self,
102
- task_id: str,
103
- worker_id: str,
104
- queue_time_seconds: Optional[float] = None,
105
- dependencies: Optional[List[str]] = None,
106
- metadata: Optional[Dict[str, Any]] = None,
115
+ event: TaskAssignedEvent,
107
116
  ) -> None:
108
117
  r"""Logs the assignment of a task to a worker."""
109
118
  self._log_event(
110
- 'task_assigned',
111
- task_id=task_id,
112
- worker_id=worker_id,
113
- queue_time_seconds=queue_time_seconds,
114
- dependencies=dependencies or [],
115
- metadata=metadata or {},
119
+ event_type=event.event_type,
120
+ task_id=event.task_id,
121
+ worker_id=event.worker_id,
122
+ queue_time_seconds=event.queue_time_seconds,
123
+ dependencies=event.dependencies or [],
124
+ metadata=event.metadata or {},
116
125
  )
117
- if task_id in self._task_hierarchy:
118
- self._task_hierarchy[task_id]['status'] = 'assigned'
119
- self._task_hierarchy[task_id]['assigned_to'] = worker_id
120
- self._task_hierarchy[task_id]['dependencies'] = dependencies or []
121
- if worker_id in self._worker_information:
122
- self._worker_information[worker_id]['current_task_id'] = task_id
123
- self._worker_information[worker_id]['status'] = 'busy'
126
+ if event.task_id in self._task_hierarchy:
127
+ self._task_hierarchy[event.task_id]['status'] = 'assigned'
128
+ self._task_hierarchy[event.task_id]['assigned_to'] = (
129
+ event.worker_id
130
+ )
131
+ self._task_hierarchy[event.task_id]['dependencies'] = (
132
+ event.dependencies or []
133
+ )
134
+ if event.worker_id in self._worker_information:
135
+ self._worker_information[event.worker_id]['current_task_id'] = (
136
+ event.task_id
137
+ )
138
+ self._worker_information[event.worker_id]['status'] = 'busy'
124
139
 
125
140
  def log_task_started(
126
141
  self,
127
- task_id: str,
128
- worker_id: str,
129
- metadata: Optional[Dict[str, Any]] = None,
142
+ event: TaskStartedEvent,
130
143
  ) -> None:
131
144
  r"""Logs when a worker starts processing a task."""
132
145
  self._log_event(
133
- 'task_started',
134
- task_id=task_id,
135
- worker_id=worker_id,
136
- metadata=metadata or {},
146
+ event_type=event.event_type,
147
+ task_id=event.task_id,
148
+ worker_id=event.worker_id,
149
+ metadata=event.metadata or {},
137
150
  )
138
- if task_id in self._task_hierarchy:
139
- self._task_hierarchy[task_id]['status'] = 'processing'
151
+ if event.task_id in self._task_hierarchy:
152
+ self._task_hierarchy[event.task_id]['status'] = 'processing'
140
153
 
141
- def log_task_completed(
142
- self,
143
- task_id: str,
144
- worker_id: str,
145
- result_summary: Optional[str] = None,
146
- processing_time_seconds: Optional[float] = None,
147
- token_usage: Optional[Dict[str, int]] = None,
148
- metadata: Optional[Dict[str, Any]] = None,
149
- ) -> None:
154
+ def log_task_completed(self, event: TaskCompletedEvent) -> None:
150
155
  r"""Logs the successful completion of a task."""
151
156
  self._log_event(
152
- 'task_completed',
153
- task_id=task_id,
154
- worker_id=worker_id,
155
- result_summary=result_summary,
156
- processing_time_seconds=processing_time_seconds,
157
- token_usage=token_usage or {},
158
- metadata=metadata or {},
157
+ event_type=event.event_type,
158
+ task_id=event.task_id,
159
+ worker_id=event.worker_id,
160
+ result_summary=event.result_summary,
161
+ processing_time_seconds=event.processing_time_seconds,
162
+ token_usage=event.token_usage or {},
163
+ metadata=event.metadata or {},
159
164
  )
160
- if task_id in self._task_hierarchy:
161
- self._task_hierarchy[task_id]['status'] = 'completed'
162
- self._task_hierarchy[task_id]['assigned_to'] = None
165
+ if event.task_id in self._task_hierarchy:
166
+ self._task_hierarchy[event.task_id]['status'] = 'completed'
167
+ self._task_hierarchy[event.task_id]['assigned_to'] = None
163
168
  # Store processing time in task hierarchy for display in tree
164
- if processing_time_seconds is not None:
165
- self._task_hierarchy[task_id]['completion_time_seconds'] = (
166
- processing_time_seconds
167
- )
169
+ if event.processing_time_seconds is not None:
170
+ self._task_hierarchy[event.task_id][
171
+ 'completion_time_seconds'
172
+ ] = event.processing_time_seconds
168
173
  # Store token usage in task hierarchy for display in tree
169
- if token_usage is not None:
170
- self._task_hierarchy[task_id]['token_usage'] = token_usage
171
- if worker_id in self._worker_information:
172
- self._worker_information[worker_id]['current_task_id'] = None
173
- self._worker_information[worker_id]['status'] = 'idle'
174
- self._worker_information[worker_id]['tasks_completed'] = (
175
- self._worker_information[worker_id].get('tasks_completed', 0)
174
+ if event.token_usage is not None:
175
+ self._task_hierarchy[event.task_id]['token_usage'] = (
176
+ event.token_usage
177
+ )
178
+ if event.worker_id in self._worker_information:
179
+ self._worker_information[event.worker_id]['current_task_id'] = None
180
+ self._worker_information[event.worker_id]['status'] = 'idle'
181
+ self._worker_information[event.worker_id]['tasks_completed'] = (
182
+ self._worker_information[event.worker_id].get(
183
+ 'tasks_completed', 0
184
+ )
176
185
  + 1
177
186
  )
178
187
 
179
188
  def log_task_failed(
180
189
  self,
181
- task_id: str,
182
- error_message: str,
183
- worker_id: Optional[str] = None,
184
- metadata: Optional[Dict[str, Any]] = None,
190
+ event: TaskFailedEvent,
185
191
  ) -> None:
186
192
  r"""Logs the failure of a task."""
187
193
  self._log_event(
188
- 'task_failed',
189
- task_id=task_id,
190
- worker_id=worker_id,
191
- error_message=error_message,
192
- metadata=metadata or {},
194
+ event_type=event.event_type,
195
+ task_id=event.task_id,
196
+ worker_id=event.worker_id,
197
+ error_message=event.error_message,
198
+ metadata=event.metadata or {},
193
199
  )
194
- if task_id in self._task_hierarchy:
195
- self._task_hierarchy[task_id]['status'] = 'failed'
196
- self._task_hierarchy[task_id]['error'] = error_message
197
- self._task_hierarchy[task_id]['assigned_to'] = None
198
- if worker_id and worker_id in self._worker_information:
199
- self._worker_information[worker_id]['current_task_id'] = None
200
- self._worker_information[worker_id]['status'] = 'idle'
201
- self._worker_information[worker_id]['tasks_failed'] = (
202
- self._worker_information[worker_id].get('tasks_failed', 0) + 1
200
+ if event.task_id in self._task_hierarchy:
201
+ self._task_hierarchy[event.task_id]['status'] = 'failed'
202
+ self._task_hierarchy[event.task_id]['error'] = event.error_message
203
+ self._task_hierarchy[event.task_id]['assigned_to'] = None
204
+ if event.worker_id and event.worker_id in self._worker_information:
205
+ self._worker_information[event.worker_id]['current_task_id'] = None
206
+ self._worker_information[event.worker_id]['status'] = 'idle'
207
+ self._worker_information[event.worker_id]['tasks_failed'] = (
208
+ self._worker_information[event.worker_id].get(
209
+ 'tasks_failed', 0
210
+ )
211
+ + 1
203
212
  )
204
213
 
205
214
  def log_worker_created(
206
215
  self,
207
- worker_id: str,
208
- worker_type: str,
209
- role: str,
210
- metadata: Optional[Dict[str, Any]] = None,
216
+ event: WorkerCreatedEvent,
211
217
  ) -> None:
212
218
  r"""Logs the creation of a new worker."""
213
219
  self._log_event(
214
- 'worker_created',
215
- worker_id=worker_id,
216
- worker_type=worker_type,
217
- role=role,
218
- metadata=metadata or {},
220
+ event_type=event.event_type,
221
+ worker_id=event.worker_id,
222
+ worker_type=event.worker_type,
223
+ role=event.role,
224
+ metadata=event.metadata or {},
219
225
  )
220
- self._worker_information[worker_id] = {
221
- 'type': worker_type,
222
- 'role': role,
226
+ self._worker_information[event.worker_id] = {
227
+ 'type': event.worker_type,
228
+ 'role': event.role,
223
229
  'status': 'idle',
224
230
  'current_task_id': None,
225
231
  'tasks_completed': 0,
226
232
  'tasks_failed': 0,
227
- **(metadata or {}),
233
+ **(event.metadata or {}),
228
234
  }
229
235
 
230
236
  def log_worker_deleted(
231
237
  self,
232
- worker_id: str,
233
- reason: Optional[str] = None,
234
- metadata: Optional[Dict[str, Any]] = None,
238
+ event: WorkerDeletedEvent,
235
239
  ) -> None:
236
240
  r"""Logs the deletion of a worker."""
237
241
  self._log_event(
238
- 'worker_deleted',
239
- worker_id=worker_id,
240
- reason=reason,
241
- metadata=metadata or {},
242
+ event_type=event.event_type,
243
+ worker_id=event.worker_id,
244
+ reason=event.reason,
245
+ metadata=event.metadata or {},
242
246
  )
243
- if worker_id in self._worker_information:
244
- self._worker_information[worker_id]['status'] = 'deleted'
247
+ if event.worker_id in self._worker_information:
248
+ self._worker_information[event.worker_id]['status'] = 'deleted'
245
249
  # Or del self._worker_information[worker_id]
246
250
 
251
+ def log_queue_status(
252
+ self,
253
+ event: QueueStatusEvent,
254
+ ) -> None:
255
+ r"""Logs the status of a task queue."""
256
+ self._log_event(
257
+ event_type=event.event_type,
258
+ queue_name=event.queue_name,
259
+ length=event.length,
260
+ pending_task_ids=event.pending_task_ids or [],
261
+ metadata=event.metadata or {},
262
+ )
263
+
264
+ def log_all_tasks_completed(self, event: AllTasksCompletedEvent) -> None:
265
+ pass
266
+
247
267
  def reset_task_data(self) -> None:
248
268
  r"""Resets logs and data related to tasks, preserving worker
249
269
  information.
@@ -263,22 +283,6 @@ class WorkforceLogger:
263
283
  f"{self.workforce_id}"
264
284
  )
265
285
 
266
- def log_queue_status(
267
- self,
268
- queue_name: str,
269
- length: int,
270
- pending_task_ids: Optional[List[str]] = None,
271
- metadata: Optional[Dict[str, Any]] = None,
272
- ) -> None:
273
- r"""Logs the status of a task queue."""
274
- self._log_event(
275
- 'queue_status',
276
- queue_name=queue_name,
277
- length=length,
278
- pending_task_ids=pending_task_ids or [],
279
- metadata=metadata or {},
280
- )
281
-
282
286
  def dump_to_json(self, file_path: str) -> None:
283
287
  r"""Dumps all log entries to a JSON file.
284
288
 
@@ -0,0 +1,33 @@
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 abc import ABC, abstractmethod
15
+ from typing import Any, Dict
16
+
17
+
18
+ class WorkforceMetrics(ABC):
19
+ @abstractmethod
20
+ def reset_task_data(self) -> None:
21
+ pass
22
+
23
+ @abstractmethod
24
+ def dump_to_json(self, file_path: str) -> None:
25
+ pass
26
+
27
+ @abstractmethod
28
+ def get_ascii_tree_representation(self) -> str:
29
+ pass
30
+
31
+ @abstractmethod
32
+ def get_kpis(self) -> Dict[str, Any]:
33
+ pass
@@ -13,6 +13,7 @@
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
 
15
15
  import os
16
+ import re
16
17
  from datetime import datetime
17
18
  from pathlib import Path
18
19
  from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional
@@ -131,6 +132,10 @@ class ContextUtility:
131
132
  - Shared session management for workforce workflows
132
133
  """
133
134
 
135
+ # maximum filename length for workflow files (chosen for filesystem
136
+ # compatibility and readability)
137
+ MAX_WORKFLOW_FILENAME_LENGTH: ClassVar[int] = 50
138
+
134
139
  # Class variables for shared session management
135
140
  _shared_sessions: ClassVar[Dict[str, 'ContextUtility']] = {}
136
141
  _default_workforce_session: ClassVar[Optional['ContextUtility']] = None
@@ -191,6 +196,54 @@ class ContextUtility:
191
196
  timestamp = datetime.now().strftime('%Y%m%d_%H%M%S_%f')
192
197
  return f"session_{timestamp}"
193
198
 
199
+ @staticmethod
200
+ def sanitize_workflow_filename(
201
+ name: str,
202
+ max_length: Optional[int] = None,
203
+ ) -> str:
204
+ r"""Sanitize a name string for use as a workflow filename.
205
+
206
+ Converts the input string to a safe filename by:
207
+ - converting to lowercase
208
+ - replacing spaces with underscores
209
+ - removing special characters (keeping only alphanumeric and
210
+ underscores)
211
+ - truncating to maximum length if specified
212
+
213
+ Args:
214
+ name (str): The name string to sanitize (e.g., role_name or
215
+ task_title).
216
+ max_length (Optional[int]): Maximum length for the sanitized
217
+ filename. If None, uses MAX_WORKFLOW_FILENAME_LENGTH.
218
+ (default: :obj:`None`)
219
+
220
+ Returns:
221
+ str: Sanitized filename string suitable for filesystem use.
222
+ Returns "agent" if sanitization results in empty string.
223
+
224
+ Example:
225
+ >>> ContextUtility.sanitize_workflow_filename("Data Analyst!")
226
+ 'data_analyst'
227
+ >>> ContextUtility.sanitize_workflow_filename("Test@123", 5)
228
+ 'test1'
229
+ """
230
+ if max_length is None:
231
+ max_length = ContextUtility.MAX_WORKFLOW_FILENAME_LENGTH
232
+
233
+ # sanitize: lowercase, spaces to underscores, remove special chars
234
+ clean_name = name.lower().replace(" ", "_")
235
+ clean_name = re.sub(r'[^a-z0-9_]', '', clean_name)
236
+
237
+ # truncate if too long
238
+ if len(clean_name) > max_length:
239
+ clean_name = clean_name[:max_length]
240
+
241
+ # ensure it's not empty after sanitization
242
+ if not clean_name:
243
+ clean_name = "agent"
244
+
245
+ return clean_name
246
+
194
247
  # ========= GENERIC FILE MANAGEMENT METHODS =========
195
248
 
196
249
  def _ensure_directory_exists(self) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: camel-ai
3
- Version: 0.2.78
3
+ Version: 0.2.79a0
4
4
  Summary: Communicative Agents for AI Society Study
5
5
  Project-URL: Homepage, https://www.camel-ai.org/
6
6
  Project-URL: Repository, https://github.com/camel-ai/camel
@@ -9,7 +9,7 @@ Author: CAMEL-AI.org
9
9
  License-Expression: Apache-2.0
10
10
  License-File: LICENSE
11
11
  Keywords: ai-societies,artificial-intelligence,communicative-ai,cooperative-ai,deep-learning,large-language-models,multi-agent-systems,natural-language-processing
12
- Requires-Python: <3.13,>=3.10
12
+ Requires-Python: <3.15,>=3.10
13
13
  Requires-Dist: astor>=0.8.1
14
14
  Requires-Dist: colorama<0.5,>=0.4.6
15
15
  Requires-Dist: docstring-parser<0.18,>=0.17.0
@@ -72,7 +72,7 @@ Requires-Dist: jupyter-client<9,>=8.6.2; extra == 'all'
72
72
  Requires-Dist: langfuse>=2.60.5; extra == 'all'
73
73
  Requires-Dist: linkup-sdk<0.3,>=0.2.1; extra == 'all'
74
74
  Requires-Dist: litellm<2,>=1.38.1; extra == 'all'
75
- Requires-Dist: markitdown>=0.1.1; extra == 'all'
75
+ Requires-Dist: markitdown>=0.1.1; (python_version >= '3.13') and extra == 'all'
76
76
  Requires-Dist: math-verify<0.8,>=0.7.0; extra == 'all'
77
77
  Requires-Dist: mcp>=1.3.0; extra == 'all'
78
78
  Requires-Dist: mem0ai>=0.1.67; extra == 'all'
@@ -102,7 +102,7 @@ Requires-Dist: pygithub<3,>=2.6.0; extra == 'all'
102
102
  Requires-Dist: pylatex>=1.4.2; extra == 'all'
103
103
  Requires-Dist: pymilvus<3,>=2.4.0; extra == 'all'
104
104
  Requires-Dist: pymupdf<2,>=1.22.5; extra == 'all'
105
- Requires-Dist: pyobvector>=0.1.18; extra == 'all'
105
+ Requires-Dist: pyobvector>=0.1.18; (python_version < '3.13') and extra == 'all'
106
106
  Requires-Dist: pyowm<4,>=3.3.0; extra == 'all'
107
107
  Requires-Dist: pytelegrambotapi<5,>=4.18.0; extra == 'all'
108
108
  Requires-Dist: pytesseract>=0.3.13; extra == 'all'
@@ -143,7 +143,7 @@ Requires-Dist: types-pyyaml<7,>=6.0.12; extra == 'all'
143
143
  Requires-Dist: types-requests<3,>=2.31.0; extra == 'all'
144
144
  Requires-Dist: types-setuptools<70,>=69.2.0; extra == 'all'
145
145
  Requires-Dist: types-tqdm<5,>=4.66.0; extra == 'all'
146
- Requires-Dist: unstructured==0.16.20; extra == 'all'
146
+ Requires-Dist: unstructured==0.16.20; (python_version < '3.13') and extra == 'all'
147
147
  Requires-Dist: weaviate-client>=4.15.0; extra == 'all'
148
148
  Requires-Dist: websockets<15.1,>=13.0; extra == 'all'
149
149
  Requires-Dist: wikipedia<2,>=1; extra == 'all'
@@ -215,7 +215,7 @@ Requires-Dist: chunkr-ai<0.1.0,>=0.0.50; extra == 'document-tools'
215
215
  Requires-Dist: crawl4ai>=0.3.745; extra == 'document-tools'
216
216
  Requires-Dist: docx2txt<0.9,>=0.8; extra == 'document-tools'
217
217
  Requires-Dist: docx>=0.2.4; extra == 'document-tools'
218
- Requires-Dist: markitdown>=0.1.1; extra == 'document-tools'
218
+ Requires-Dist: markitdown>=0.1.1; (python_version >= '3.13') and extra == 'document-tools'
219
219
  Requires-Dist: numpy<=2.2,>=1.2; extra == 'document-tools'
220
220
  Requires-Dist: onnxruntime<=1.19.2; extra == 'document-tools'
221
221
  Requires-Dist: openapi-spec-validator<0.8,>=0.7.1; extra == 'document-tools'
@@ -226,7 +226,7 @@ Requires-Dist: pymupdf<2,>=1.22.5; extra == 'document-tools'
226
226
  Requires-Dist: python-pptx>=1.0.2; extra == 'document-tools'
227
227
  Requires-Dist: reportlab>=4.4.2; extra == 'document-tools'
228
228
  Requires-Dist: tabulate>=0.9.0; extra == 'document-tools'
229
- Requires-Dist: unstructured==0.16.20; extra == 'document-tools'
229
+ Requires-Dist: unstructured==0.16.20; (python_version < '3.13') and extra == 'document-tools'
230
230
  Requires-Dist: xls2xlsx>=0.2.0; extra == 'document-tools'
231
231
  Provides-Extra: eigent
232
232
  Requires-Dist: anthropic<0.50.0,>=0.47.0; extra == 'eigent'
@@ -238,7 +238,8 @@ Requires-Dist: google-api-python-client==2.166.0; extra == 'eigent'
238
238
  Requires-Dist: google-auth-httplib2==0.2.0; extra == 'eigent'
239
239
  Requires-Dist: google-auth-oauthlib==1.2.1; extra == 'eigent'
240
240
  Requires-Dist: imageio[pyav]<3,>=2.34.2; extra == 'eigent'
241
- Requires-Dist: markitdown[all]>=0.1.1; extra == 'eigent'
241
+ Requires-Dist: markitdown>=0.1.1; (python_version >= '3.13') and extra == 'eigent'
242
+ Requires-Dist: markitdown[all]>=0.1.1; (python_version < '3.13') and extra == 'eigent'
242
243
  Requires-Dist: mcp-server-fetch==2025.1.17; extra == 'eigent'
243
244
  Requires-Dist: mcp-simple-arxiv==0.2.2; extra == 'eigent'
244
245
  Requires-Dist: numpy<=2.2,>=1.2; extra == 'eigent'
@@ -297,7 +298,7 @@ Requires-Dist: exa-py<2,>=1.10.0; extra == 'owl'
297
298
  Requires-Dist: ffmpeg-python<0.3,>=0.2.0; extra == 'owl'
298
299
  Requires-Dist: html2text>=2024.2.26; extra == 'owl'
299
300
  Requires-Dist: imageio[pyav]<3,>=2.34.2; extra == 'owl'
300
- Requires-Dist: markitdown>=0.1.1; extra == 'owl'
301
+ Requires-Dist: markitdown>=0.1.1; (python_version >= '3.13') and extra == 'owl'
301
302
  Requires-Dist: mcp-server-fetch==2025.1.17; extra == 'owl'
302
303
  Requires-Dist: mcp-simple-arxiv==0.2.2; extra == 'owl'
303
304
  Requires-Dist: numpy<=2.2,>=1.2; extra == 'owl'
@@ -326,7 +327,7 @@ Requires-Dist: transformers<5,>=4; extra == 'owl'
326
327
  Requires-Dist: tree-sitter-python<0.24,>=0.23.6; extra == 'owl'
327
328
  Requires-Dist: tree-sitter<0.24,>=0.23.2; extra == 'owl'
328
329
  Requires-Dist: typer>=0.15.2; extra == 'owl'
329
- Requires-Dist: unstructured==0.16.20; extra == 'owl'
330
+ Requires-Dist: unstructured==0.16.20; (python_version < '3.13') and extra == 'owl'
330
331
  Requires-Dist: websockets<15.1,>=13.0; extra == 'owl'
331
332
  Requires-Dist: wikipedia<2,>=1; extra == 'owl'
332
333
  Requires-Dist: xls2xlsx>=0.2.0; extra == 'owl'
@@ -343,11 +344,11 @@ Requires-Dist: neo4j<6,>=5.18.0; extra == 'rag'
343
344
  Requires-Dist: numpy<=2.2,>=1.2; extra == 'rag'
344
345
  Requires-Dist: protobuf>=6.0.0; extra == 'rag'
345
346
  Requires-Dist: pymilvus<3,>=2.4.0; extra == 'rag'
346
- Requires-Dist: pyobvector>=0.1.18; extra == 'rag'
347
+ Requires-Dist: pyobvector>=0.1.18; (python_version < '3.13') and extra == 'rag'
347
348
  Requires-Dist: pytidb>=0.0.13; extra == 'rag'
348
349
  Requires-Dist: qdrant-client<2,>=1.9.0; extra == 'rag'
349
350
  Requires-Dist: rank-bm25<0.3,>=0.2.2; extra == 'rag'
350
- Requires-Dist: unstructured==0.16.20; extra == 'rag'
351
+ Requires-Dist: unstructured==0.16.20; (python_version < '3.13') and extra == 'rag'
351
352
  Requires-Dist: weaviate-client>=4.15.0; extra == 'rag'
352
353
  Provides-Extra: research-tools
353
354
  Requires-Dist: arxiv2text<0.2,>=0.1.14; extra == 'research-tools'
@@ -366,7 +367,7 @@ Requires-Dist: pgvector<0.3,>=0.2.4; extra == 'storage'
366
367
  Requires-Dist: protobuf>=6.0.0; extra == 'storage'
367
368
  Requires-Dist: psycopg[binary]<4,>=3.1.18; extra == 'storage'
368
369
  Requires-Dist: pymilvus<3,>=2.4.0; extra == 'storage'
369
- Requires-Dist: pyobvector>=0.1.18; extra == 'storage'
370
+ Requires-Dist: pyobvector>=0.1.18; (python_version < '3.13') and extra == 'storage'
370
371
  Requires-Dist: pytidb>=0.0.13; extra == 'storage'
371
372
  Requires-Dist: qdrant-client<2,>=1.9.0; extra == 'storage'
372
373
  Requires-Dist: redis<6,>=5.0.6; extra == 'storage'