camel-ai 0.2.60__py3-none-any.whl → 0.2.61__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.

@@ -11,8 +11,6 @@
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
-
16
14
  import re
17
15
  from datetime import datetime
18
16
  from pathlib import Path
@@ -21,7 +19,7 @@ from typing import List, Optional, Union
21
19
  from camel.logger import get_logger
22
20
  from camel.toolkits.base import BaseToolkit
23
21
  from camel.toolkits.function_tool import FunctionTool
24
- from camel.utils import MCPServer
22
+ from camel.utils import MCPServer, dependencies_required
25
23
 
26
24
  logger = get_logger(__name__)
27
25
 
@@ -148,40 +146,83 @@ class FileWriteToolkit(BaseToolkit):
148
146
  document.save(str(file_path))
149
147
  logger.debug(f"Wrote DOCX to {file_path} with default formatting")
150
148
 
151
- def _write_pdf_file(self, file_path: Path, content: str, **kwargs) -> None:
149
+ @dependencies_required('pylatex', 'fpdf')
150
+ def _write_pdf_file(
151
+ self, file_path: Path, content: str, use_latex: bool = False
152
+ ) -> None:
152
153
  r"""Write text content to a PDF file with default formatting.
153
154
 
154
155
  Args:
155
156
  file_path (Path): The target file path.
156
157
  content (str): The text content to write.
158
+ use_latex (bool): Whether to use LaTeX for rendering. (requires
159
+ LaTeX toolchain). If False, uses FPDF for simpler PDF
160
+ generation. (default: :obj: `False`)
157
161
 
158
162
  Raises:
159
- RuntimeError: If the 'fpdf' library is not installed.
163
+ RuntimeError: If the 'pylatex' or 'fpdf' library is not installed
164
+ when use_latex=True.
160
165
  """
161
- from fpdf import FPDF
162
-
163
- # Use default formatting values
164
- font_family = 'Arial'
165
- font_size = 12
166
- font_style = ''
167
- line_height = 10
168
- margin = 10
169
-
170
- pdf = FPDF()
171
- pdf.set_margins(margin, margin, margin)
172
-
173
- pdf.add_page()
174
- pdf.set_font(font_family, style=font_style, size=font_size)
175
-
176
- # Split content into paragraphs and add them
177
- for para in content.split('\n'):
178
- if para.strip(): # Skip empty paragraphs
179
- pdf.multi_cell(0, line_height, para)
180
- else:
181
- pdf.ln(line_height) # Add empty line
166
+ if use_latex:
167
+ from pylatex import (
168
+ Command,
169
+ Document,
170
+ Math,
171
+ Section,
172
+ )
173
+ from pylatex.utils import (
174
+ NoEscape,
175
+ )
182
176
 
183
- pdf.output(str(file_path))
184
- logger.debug(f"Wrote PDF to {file_path} with custom formatting")
177
+ doc = Document(documentclass="article")
178
+ doc.packages.append(Command('usepackage', 'amsmath'))
179
+
180
+ with doc.create(Section('Generated Content')):
181
+ for line in content.split('\n'):
182
+ # Remove leading whitespace
183
+ stripped_line = line.strip()
184
+ # Check if the line is intended as a standalone math
185
+ # expression
186
+ if (
187
+ stripped_line.startswith('$')
188
+ and stripped_line.endswith('$')
189
+ and len(stripped_line) > 1
190
+ ):
191
+ # Extract content between the '$' delimiters
192
+ math_data = stripped_line[1:-1]
193
+ doc.append(Math(data=math_data))
194
+ else:
195
+ doc.append(NoEscape(line))
196
+ doc.append(NoEscape(r'\par'))
197
+
198
+ doc.generate_pdf(str(file_path), clean_tex=False)
199
+
200
+ logger.info(f"Wrote PDF (with LaTeX) to {file_path}")
201
+ else:
202
+ from fpdf import FPDF
203
+
204
+ # Use default formatting values
205
+ font_family = 'Arial'
206
+ font_size = 12
207
+ font_style = ''
208
+ line_height = 10
209
+ margin = 10
210
+
211
+ pdf = FPDF()
212
+ pdf.set_margins(margin, margin, margin)
213
+
214
+ pdf.add_page()
215
+ pdf.set_font(font_family, style=font_style, size=font_size)
216
+
217
+ # Split content into paragraphs and add them
218
+ for para in content.split('\n'):
219
+ if para.strip(): # Skip empty paragraphs
220
+ pdf.multi_cell(0, line_height, para)
221
+ else:
222
+ pdf.ln(line_height) # Add empty line
223
+
224
+ pdf.output(str(file_path))
225
+ logger.debug(f"Wrote PDF to {file_path} with custom formatting")
185
226
 
186
227
  def _write_csv_file(
187
228
  self,
@@ -286,6 +327,7 @@ class FileWriteToolkit(BaseToolkit):
286
327
  content: Union[str, List[List[str]]],
287
328
  filename: str,
288
329
  encoding: Optional[str] = None,
330
+ use_latex: bool = False,
289
331
  ) -> str:
290
332
  r"""Write the given content to a file.
291
333
 
@@ -302,6 +344,9 @@ class FileWriteToolkit(BaseToolkit):
302
344
  supplied, it is resolved to self.output_dir.
303
345
  encoding (Optional[str]): The character encoding to use. (default:
304
346
  :obj: `None`)
347
+ use_latex (bool): For PDF files, whether to use LaTeX rendering
348
+ (True) or simple FPDF rendering (False). (default: :obj:
349
+ `False`)
305
350
 
306
351
  Returns:
307
352
  str: A message indicating success or error details.
@@ -326,7 +371,9 @@ class FileWriteToolkit(BaseToolkit):
326
371
  if extension in [".doc", ".docx"]:
327
372
  self._write_docx_file(file_path, str(content))
328
373
  elif extension == ".pdf":
329
- self._write_pdf_file(file_path, str(content))
374
+ self._write_pdf_file(
375
+ file_path, str(content), use_latex=use_latex
376
+ )
330
377
  elif extension == ".csv":
331
378
  self._write_csv_file(
332
379
  file_path, content, encoding=file_encoding
@@ -37,6 +37,7 @@ if TYPE_CHECKING:
37
37
 
38
38
  from camel.logger import get_logger
39
39
  from camel.toolkits import BaseToolkit, FunctionTool
40
+ from camel.utils.commons import run_async
40
41
 
41
42
  logger = get_logger(__name__)
42
43
 
@@ -220,6 +221,10 @@ class MCPClient(BaseToolkit):
220
221
  logger.error(f"Failed to connect to MCP server: {e}")
221
222
  raise e
222
223
 
224
+ def connect_sync(self):
225
+ r"""Synchronously connect to the MCP server."""
226
+ return run_async(self.connect)()
227
+
223
228
  async def disconnect(self):
224
229
  r"""Explicitly disconnect from the MCP server."""
225
230
  # If the server is not connected, do nothing
@@ -235,6 +240,10 @@ class MCPClient(BaseToolkit):
235
240
  self._exit_stack = AsyncExitStack()
236
241
  self._session = None
237
242
 
243
+ def disconnect_sync(self):
244
+ r"""Synchronously disconnect from the MCP server."""
245
+ return run_async(self.disconnect)()
246
+
238
247
  @asynccontextmanager
239
248
  async def connection(self):
240
249
  r"""Async context manager for establishing and managing the connection
@@ -254,6 +263,10 @@ class MCPClient(BaseToolkit):
254
263
  except Exception as e:
255
264
  logger.warning(f"Error: {e}")
256
265
 
266
+ def connection_sync(self):
267
+ r"""Synchronously connect to the MCP server."""
268
+ return run_async(self.connection)()
269
+
257
270
  async def list_mcp_tools(self) -> Union[str, "ListToolsResult"]:
258
271
  r"""Retrieves the list of available tools from the connected MCP
259
272
  server.
@@ -269,6 +282,11 @@ class MCPClient(BaseToolkit):
269
282
  logger.exception("Failed to list MCP tools")
270
283
  raise e
271
284
 
285
+ def list_mcp_tools_sync(self) -> Union[str, "ListToolsResult"]:
286
+ r"""Synchronously list the available tools from the connected MCP
287
+ server."""
288
+ return run_async(self.list_mcp_tools)()
289
+
272
290
  def generate_function_from_mcp_tool(self, mcp_tool: "Tool") -> Callable:
273
291
  r"""Dynamically generates a Python callable function corresponding to
274
292
  a given MCP tool.
@@ -390,6 +408,10 @@ class MCPClient(BaseToolkit):
390
408
 
391
409
  return dynamic_function
392
410
 
411
+ def generate_function_from_mcp_tool_sync(self, mcp_tool: "Tool") -> Any:
412
+ r"""Synchronously generate a function from an MCP tool."""
413
+ return run_async(self.generate_function_from_mcp_tool)(mcp_tool)
414
+
393
415
  def _build_tool_schema(self, mcp_tool: "Tool") -> Dict[str, Any]:
394
416
  input_schema = mcp_tool.inputSchema
395
417
  properties = input_schema.get("properties", {})
@@ -463,6 +485,10 @@ class MCPClient(BaseToolkit):
463
485
 
464
486
  return await self._session.call_tool(tool_name, tool_args)
465
487
 
488
+ def call_tool_sync(self, tool_name: str, tool_args: Dict[str, Any]) -> Any:
489
+ r"""Synchronously call a tool."""
490
+ return run_async(self.call_tool)(tool_name, tool_args)
491
+
466
492
  @property
467
493
  def session(self) -> Optional["ClientSession"]:
468
494
  return self._session
@@ -521,6 +547,21 @@ class MCPClient(BaseToolkit):
521
547
  logger.error(f"Failed to initialize MCPClient: {e}")
522
548
  raise RuntimeError(f"Failed to initialize MCPClient: {e}") from e
523
549
 
550
+ @classmethod
551
+ def create_sync(
552
+ self,
553
+ command_or_url: str,
554
+ args: Optional[List[str]] = None,
555
+ env: Optional[Dict[str, str]] = None,
556
+ timeout: Optional[float] = None,
557
+ headers: Optional[Dict[str, str]] = None,
558
+ mode: Optional[str] = None,
559
+ ) -> "MCPClient":
560
+ r"""Synchronously create and connect to the MCP server."""
561
+ return run_async(self.create)(
562
+ command_or_url, args, env, timeout, headers, mode
563
+ )
564
+
524
565
  async def __aenter__(self) -> "MCPClient":
525
566
  r"""Async context manager entry point. Automatically connects to the
526
567
  MCP server when used in an async with statement.
@@ -531,12 +572,35 @@ class MCPClient(BaseToolkit):
531
572
  await self.connect()
532
573
  return self
533
574
 
534
- async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
575
+ def __enter__(self) -> "MCPClient":
576
+ r"""Synchronously enter the async context manager."""
577
+ return run_async(self.__aenter__)()
578
+
579
+ async def __aexit__(self) -> None:
535
580
  r"""Async context manager exit point. Automatically disconnects from
536
581
  the MCP server when exiting an async with statement.
582
+
583
+ Returns:
584
+ None
537
585
  """
538
586
  await self.disconnect()
539
587
 
588
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
589
+ r"""Synchronously exit the async context manager.
590
+
591
+ Args:
592
+ exc_type (Optional[Type[Exception]]): The type of exception that
593
+ occurred during the execution of the with statement.
594
+ exc_val (Optional[Exception]): The exception that occurred during
595
+ the execution of the with statement.
596
+ exc_tb (Optional[TracebackType]): The traceback of the exception
597
+ that occurred during the execution of the with statement.
598
+
599
+ Returns:
600
+ None
601
+ """
602
+ return run_async(self.__aexit__)()
603
+
540
604
 
541
605
  class MCPToolkit(BaseToolkit):
542
606
  r"""MCPToolkit provides a unified interface for managing multiple
@@ -749,6 +813,10 @@ class MCPToolkit(BaseToolkit):
749
813
  logger.error(f"Failed to connect to one or more MCP servers: {e}")
750
814
  raise e
751
815
 
816
+ def connect_sync(self):
817
+ r"""Synchronously connect to all MCP servers."""
818
+ return run_async(self.connect)()
819
+
752
820
  async def disconnect(self):
753
821
  r"""Explicitly disconnect from all MCP servers."""
754
822
  if not self._connected:
@@ -758,6 +826,10 @@ class MCPToolkit(BaseToolkit):
758
826
  await server.disconnect()
759
827
  self._connected = False
760
828
 
829
+ def disconnect_sync(self):
830
+ r"""Synchronously disconnect from all MCP servers."""
831
+ return run_async(self.disconnect)()
832
+
761
833
  @asynccontextmanager
762
834
  async def connection(self) -> AsyncGenerator["MCPToolkit", None]:
763
835
  r"""Async context manager that simultaneously establishes connections
@@ -772,6 +844,10 @@ class MCPToolkit(BaseToolkit):
772
844
  finally:
773
845
  await self.disconnect()
774
846
 
847
+ def connection_sync(self):
848
+ r"""Synchronously connect to all MCP servers."""
849
+ return run_async(self.connection)()
850
+
775
851
  def is_connected(self) -> bool:
776
852
  r"""Checks if all the managed servers are connected.
777
853
 
@@ -117,7 +117,11 @@ class WolframAlphaToolkit(BaseToolkit):
117
117
 
118
118
  try:
119
119
  url = "https://www.wolframalpha.com/api/v1/llm-api"
120
- params = {"input": query, "appid": WOLFRAMALPHA_APP_ID}
120
+ params = {
121
+ "input": query,
122
+ "appid": WOLFRAMALPHA_APP_ID,
123
+ "format": "plaintext",
124
+ }
121
125
 
122
126
  response = requests.get(url, params=params)
123
127
  response.raise_for_status()
camel/types/enums.py CHANGED
@@ -56,6 +56,8 @@ class ModelType(UnifiedModelType, Enum):
56
56
  AWS_LLAMA_3_3_70B_INSTRUCT = "us.meta.llama3-3-70b-instruct-v1:0"
57
57
  AWS_LLAMA_3_2_90B_INSTRUCT = "us.meta.llama3-2-90b-instruct-v1:0"
58
58
  AWS_LLAMA_3_2_11B_INSTRUCT = "us.meta.llama3-2-11b-instruct-v1:0"
59
+ AWS_CLAUDE_SONNET_4 = "anthropic.claude-sonnet-4-20250514-v1:0"
60
+ AWS_CLAUDE_OPUS_4 = "anthropic.claude-opus-4-20250514-v1:0"
59
61
 
60
62
  GLM_4 = "glm-4"
61
63
  GLM_4V = "glm-4v"
@@ -145,13 +147,15 @@ class ModelType(UnifiedModelType, Enum):
145
147
  CLAUDE_2_0 = "claude-2.0"
146
148
  CLAUDE_INSTANT_1_2 = "claude-instant-1.2"
147
149
 
148
- # Claude3 models
150
+ # Claude models
149
151
  CLAUDE_3_OPUS = "claude-3-opus-latest"
150
152
  CLAUDE_3_SONNET = "claude-3-sonnet-20240229"
151
153
  CLAUDE_3_HAIKU = "claude-3-haiku-20240307"
152
154
  CLAUDE_3_5_SONNET = "claude-3-5-sonnet-latest"
153
155
  CLAUDE_3_5_HAIKU = "claude-3-5-haiku-latest"
154
156
  CLAUDE_3_7_SONNET = "claude-3-7-sonnet-latest"
157
+ CLAUDE_SONNET_4 = "claude-sonnet-4-20250514"
158
+ CLAUDE_OPUS_4 = "claude-opus-4-20250514"
155
159
 
156
160
  # Netmind models
157
161
  NETMIND_LLAMA_4_MAVERICK_17B_128E_INSTRUCT = (
@@ -469,6 +473,8 @@ class ModelType(UnifiedModelType, Enum):
469
473
  ModelType.AWS_LLAMA_3_3_70B_INSTRUCT,
470
474
  ModelType.AWS_LLAMA_3_2_90B_INSTRUCT,
471
475
  ModelType.AWS_LLAMA_3_2_11B_INSTRUCT,
476
+ ModelType.AWS_CLAUDE_SONNET_4,
477
+ ModelType.AWS_CLAUDE_OPUS_4,
472
478
  }
473
479
 
474
480
  @property
@@ -530,6 +536,8 @@ class ModelType(UnifiedModelType, Enum):
530
536
  ModelType.CLAUDE_3_5_SONNET,
531
537
  ModelType.CLAUDE_3_5_HAIKU,
532
538
  ModelType.CLAUDE_3_7_SONNET,
539
+ ModelType.CLAUDE_SONNET_4,
540
+ ModelType.CLAUDE_OPUS_4,
533
541
  }
534
542
 
535
543
  @property
@@ -1162,11 +1170,15 @@ class ModelType(UnifiedModelType, Enum):
1162
1170
  ModelType.CLAUDE_3_5_SONNET,
1163
1171
  ModelType.CLAUDE_3_5_HAIKU,
1164
1172
  ModelType.CLAUDE_3_7_SONNET,
1173
+ ModelType.CLAUDE_SONNET_4,
1174
+ ModelType.CLAUDE_OPUS_4,
1165
1175
  ModelType.YI_MEDIUM_200K,
1166
1176
  ModelType.AWS_CLAUDE_3_5_SONNET,
1167
1177
  ModelType.AWS_CLAUDE_3_HAIKU,
1168
1178
  ModelType.AWS_CLAUDE_3_SONNET,
1169
1179
  ModelType.AWS_CLAUDE_3_7_SONNET,
1180
+ ModelType.AWS_CLAUDE_SONNET_4,
1181
+ ModelType.AWS_CLAUDE_OPUS_4,
1170
1182
  ModelType.O4_MINI,
1171
1183
  ModelType.O3,
1172
1184
  }:
camel/utils/__init__.py CHANGED
@@ -35,6 +35,7 @@ from .commons import (
35
35
  json_to_function_code,
36
36
  print_text_animated,
37
37
  retry_on_error,
38
+ run_async,
38
39
  text_extract_from_web,
39
40
  to_pascal,
40
41
  track_agent,
@@ -95,4 +96,5 @@ __all__ = [
95
96
  "model_from_json_schema",
96
97
  "sanitize_filename",
97
98
  "browser_toolkit_save_auth_cookie",
99
+ "run_async",
98
100
  ]
camel/utils/commons.py CHANGED
@@ -1103,3 +1103,30 @@ def browser_toolkit_save_auth_cookie(
1103
1103
  context.storage_state(path=cookie_json_path)
1104
1104
 
1105
1105
  browser.close() # Close the browser when finished
1106
+
1107
+
1108
+ def run_async(func: Callable[..., Any]) -> Callable[..., Any]:
1109
+ r"""Helper function to run async functions in synchronous context.
1110
+
1111
+ Args:
1112
+ func (Callable[..., Any]): The async function to wrap.
1113
+
1114
+ Returns:
1115
+ Callable[..., Any]: A synchronous wrapper for the async function.
1116
+ """
1117
+
1118
+ @wraps(func)
1119
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
1120
+ try:
1121
+ loop = asyncio.get_event_loop()
1122
+ except RuntimeError:
1123
+ loop = asyncio.new_event_loop()
1124
+ asyncio.set_event_loop(loop)
1125
+
1126
+ if loop.is_closed():
1127
+ loop = asyncio.new_event_loop()
1128
+ asyncio.set_event_loop(loop)
1129
+
1130
+ return loop.run_until_complete(func(*args, **kwargs))
1131
+
1132
+ return wrapper
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: camel-ai
3
- Version: 0.2.60
3
+ Version: 0.2.61
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
@@ -32,6 +32,7 @@ Requires-Dist: arxiv<3,>=2.1.3; extra == 'all'
32
32
  Requires-Dist: azure-storage-blob<13,>=12.21.0; extra == 'all'
33
33
  Requires-Dist: beautifulsoup4<5,>=4; extra == 'all'
34
34
  Requires-Dist: botocore<2,>=1.35.3; extra == 'all'
35
+ Requires-Dist: chunkr-ai>=0.0.50; extra == 'all'
35
36
  Requires-Dist: cohere<6,>=5.11.0; extra == 'all'
36
37
  Requires-Dist: crawl4ai>=0.3.745; extra == 'all'
37
38
  Requires-Dist: dappier<0.4,>=0.3.3; extra == 'all'
@@ -47,6 +48,7 @@ Requires-Dist: docx>=0.2.4; extra == 'all'
47
48
  Requires-Dist: duckduckgo-search<7,>=6.3.5; extra == 'all'
48
49
  Requires-Dist: e2b-code-interpreter<2,>=1.0.3; extra == 'all'
49
50
  Requires-Dist: exa-py<2,>=1.10.0; extra == 'all'
51
+ Requires-Dist: faiss-cpu<2,>=1.7.2; extra == 'all'
50
52
  Requires-Dist: fastapi>=0.115.11; extra == 'all'
51
53
  Requires-Dist: ffmpeg-python<0.3,>=0.2.0; extra == 'all'
52
54
  Requires-Dist: firecrawl-py<2,>=1.0.0; extra == 'all'
@@ -92,6 +94,7 @@ Requires-Dist: pre-commit<4,>=3; extra == 'all'
92
94
  Requires-Dist: pyautogui<0.10,>=0.9.54; extra == 'all'
93
95
  Requires-Dist: pydub<0.26,>=0.25.1; extra == 'all'
94
96
  Requires-Dist: pygithub<3,>=2.6.0; extra == 'all'
97
+ Requires-Dist: pylatex>=1.4.2; extra == 'all'
95
98
  Requires-Dist: pymilvus<3,>=2.4.0; extra == 'all'
96
99
  Requires-Dist: pymupdf<2,>=1.22.5; extra == 'all'
97
100
  Requires-Dist: pyobvector>=0.1.18; extra == 'all'
@@ -193,6 +196,7 @@ Requires-Dist: sphinx<8,>=7; extra == 'docs'
193
196
  Requires-Dist: sphinxext-rediraffe<0.3,>=0.2.7; extra == 'docs'
194
197
  Provides-Extra: document-tools
195
198
  Requires-Dist: beautifulsoup4<5,>=4; extra == 'document-tools'
199
+ Requires-Dist: chunkr-ai>=0.0.50; extra == 'document-tools'
196
200
  Requires-Dist: crawl4ai>=0.3.745; extra == 'document-tools'
197
201
  Requires-Dist: docx2txt<0.9,>=0.8; extra == 'document-tools'
198
202
  Requires-Dist: docx>=0.2.4; extra == 'document-tools'
@@ -203,6 +207,7 @@ Requires-Dist: openapi-spec-validator<0.8,>=0.7.1; extra == 'document-tools'
203
207
  Requires-Dist: openpyxl>=3.1.5; extra == 'document-tools'
204
208
  Requires-Dist: pandasai<3,>=2.3.0; extra == 'document-tools'
205
209
  Requires-Dist: prance<24,>=23.6.21.0; extra == 'document-tools'
210
+ Requires-Dist: pylatex>=1.4.2; extra == 'document-tools'
206
211
  Requires-Dist: pymupdf<2,>=1.22.5; extra == 'document-tools'
207
212
  Requires-Dist: tabulate>=0.9.0; extra == 'document-tools'
208
213
  Requires-Dist: unstructured==0.16.20; extra == 'document-tools'
@@ -235,6 +240,7 @@ Requires-Dist: aci-sdk>=1.0.0b1; extra == 'owl'
235
240
  Requires-Dist: anthropic<0.50.0,>=0.47.0; extra == 'owl'
236
241
  Requires-Dist: beautifulsoup4<5,>=4; extra == 'owl'
237
242
  Requires-Dist: chunkr-ai>=0.0.41; extra == 'owl'
243
+ Requires-Dist: chunkr-ai>=0.0.50; extra == 'owl'
238
244
  Requires-Dist: crawl4ai>=0.3.745; extra == 'owl'
239
245
  Requires-Dist: datasets<4,>=3; extra == 'owl'
240
246
  Requires-Dist: docx2txt<0.9,>=0.8; extra == 'owl'
@@ -259,6 +265,7 @@ Requires-Dist: playwright>=1.50.0; extra == 'owl'
259
265
  Requires-Dist: prance<24,>=23.6.21.0; extra == 'owl'
260
266
  Requires-Dist: pyautogui<0.10,>=0.9.54; extra == 'owl'
261
267
  Requires-Dist: pydub<0.26,>=0.25.1; extra == 'owl'
268
+ Requires-Dist: pylatex>=1.4.2; extra == 'owl'
262
269
  Requires-Dist: pymupdf<2,>=1.22.5; extra == 'owl'
263
270
  Requires-Dist: python-dotenv<2,>=1.0.0; extra == 'owl'
264
271
  Requires-Dist: requests-oauthlib<2,>=1.3.1; extra == 'owl'
@@ -277,8 +284,10 @@ Requires-Dist: wikipedia<2,>=1; extra == 'owl'
277
284
  Requires-Dist: xls2xlsx>=0.2.0; extra == 'owl'
278
285
  Requires-Dist: yt-dlp<2025,>=2024.11.4; extra == 'owl'
279
286
  Provides-Extra: rag
287
+ Requires-Dist: chunkr-ai>=0.0.50; extra == 'rag'
280
288
  Requires-Dist: cohere<6,>=5.11.0; extra == 'rag'
281
289
  Requires-Dist: crawl4ai>=0.3.745; extra == 'rag'
290
+ Requires-Dist: faiss-cpu<2,>=1.7.2; extra == 'rag'
282
291
  Requires-Dist: google-genai>=1.13.0; extra == 'rag'
283
292
  Requires-Dist: nebula3-python==3.8.2; extra == 'rag'
284
293
  Requires-Dist: neo4j<6,>=5.18.0; extra == 'rag'
@@ -298,6 +307,7 @@ Requires-Dist: scholarly[tor]==1.7.11; extra == 'research-tools'
298
307
  Provides-Extra: storage
299
308
  Requires-Dist: azure-storage-blob<13,>=12.21.0; extra == 'storage'
300
309
  Requires-Dist: botocore<2,>=1.35.3; extra == 'storage'
310
+ Requires-Dist: faiss-cpu<2,>=1.7.2; extra == 'storage'
301
311
  Requires-Dist: google-cloud-storage<3,>=2.18.0; extra == 'storage'
302
312
  Requires-Dist: mem0ai>=0.1.73; extra == 'storage'
303
313
  Requires-Dist: nebula3-python==3.8.2; extra == 'storage'