camel-ai 0.2.71a3__py3-none-any.whl → 0.2.71a5__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.

Files changed (39) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +1482 -134
  3. camel/agents/repo_agent.py +2 -1
  4. camel/benchmarks/browsecomp.py +6 -6
  5. camel/interpreters/docker_interpreter.py +3 -2
  6. camel/loaders/base_loader.py +85 -0
  7. camel/logger.py +1 -1
  8. camel/messages/base.py +12 -1
  9. camel/models/azure_openai_model.py +96 -7
  10. camel/models/base_model.py +68 -10
  11. camel/models/deepseek_model.py +5 -0
  12. camel/models/gemini_model.py +5 -0
  13. camel/models/litellm_model.py +48 -16
  14. camel/models/model_manager.py +24 -6
  15. camel/models/openai_compatible_model.py +109 -5
  16. camel/models/openai_model.py +117 -8
  17. camel/societies/workforce/prompts.py +68 -5
  18. camel/societies/workforce/role_playing_worker.py +1 -0
  19. camel/societies/workforce/single_agent_worker.py +1 -0
  20. camel/societies/workforce/utils.py +67 -2
  21. camel/societies/workforce/workforce.py +412 -67
  22. camel/societies/workforce/workforce_logger.py +0 -8
  23. camel/tasks/task.py +2 -0
  24. camel/toolkits/__init__.py +7 -2
  25. camel/toolkits/craw4ai_toolkit.py +2 -2
  26. camel/toolkits/file_write_toolkit.py +526 -121
  27. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +9 -3
  28. camel/toolkits/hybrid_browser_toolkit/unified_analyzer.js +31 -8
  29. camel/toolkits/message_agent_toolkit.py +608 -0
  30. camel/toolkits/note_taking_toolkit.py +90 -0
  31. camel/toolkits/openai_image_toolkit.py +292 -0
  32. camel/toolkits/slack_toolkit.py +4 -4
  33. camel/toolkits/terminal_toolkit.py +223 -73
  34. camel/utils/mcp_client.py +37 -1
  35. {camel_ai-0.2.71a3.dist-info → camel_ai-0.2.71a5.dist-info}/METADATA +48 -7
  36. {camel_ai-0.2.71a3.dist-info → camel_ai-0.2.71a5.dist-info}/RECORD +38 -35
  37. camel/toolkits/dalle_toolkit.py +0 -175
  38. {camel_ai-0.2.71a3.dist-info → camel_ai-0.2.71a5.dist-info}/WHEEL +0 -0
  39. {camel_ai-0.2.71a3.dist-info → camel_ai-0.2.71a5.dist-info}/licenses/LICENSE +0 -0
@@ -134,7 +134,14 @@ class TerminalToolkit(BaseToolkit):
134
134
  logger.info(f"Terminal output will be redirected to: {self.log_file}")
135
135
 
136
136
  def file_update(output: str):
137
+ import sys
138
+
137
139
  try:
140
+ # For macOS/Linux file-based mode, also write to stdout
141
+ # to provide real-time feedback in the user's terminal.
142
+ sys.stdout.write(output)
143
+ sys.stdout.flush()
144
+
138
145
  # Initialize file on first write
139
146
  if not self._file_initialized:
140
147
  with open(self.log_file, "w") as f:
@@ -147,9 +154,6 @@ class TerminalToolkit(BaseToolkit):
147
154
  # Directly append to the end of the file
148
155
  with open(self.log_file, "a") as f:
149
156
  f.write(output)
150
- # If the output does not end with a newline, add one
151
- if output and not output.endswith('\n'):
152
- f.write('\n')
153
157
  # Ensure the agent also receives the output
154
158
  self.agent_queue.put(output)
155
159
  except Exception as e:
@@ -334,17 +338,24 @@ class TerminalToolkit(BaseToolkit):
334
338
  def file_find_in_content(
335
339
  self, file: str, regex: str, sudo: bool = False
336
340
  ) -> str:
337
- r"""Search for matching text within file content.
341
+ r"""Search for text within a file's content using a regular expression.
342
+
343
+ This function is useful for finding specific patterns or lines of text
344
+ within a given file. It uses `grep` on Unix-like systems and `findstr`
345
+ on Windows.
338
346
 
339
347
  Args:
340
- file (str): Absolute path of the file to search within.
341
- regex (str): Regular expression pattern to match.
342
- sudo (bool, optional): Whether to use sudo privileges. Defaults to
343
- False. Note: Using sudo requires the process to have
344
- appropriate permissions.
348
+ file (str): The absolute path of the file to search within.
349
+ regex (str): The regular expression pattern to match.
350
+ sudo (bool, optional): Whether to use sudo privileges for the
351
+ search. Defaults to False. Note: Using sudo requires the
352
+ process to have appropriate permissions.
353
+ (default: :obj:`False`)
345
354
 
346
355
  Returns:
347
- str: Matching content found in the file.
356
+ str: The matching content found in the file. If no matches are
357
+ found, an empty string is returned. Returns an error message
358
+ if the file does not exist or another error occurs.
348
359
  """
349
360
 
350
361
  if not os.path.exists(file):
@@ -376,14 +387,21 @@ class TerminalToolkit(BaseToolkit):
376
387
  return f"Error: {e!s}"
377
388
 
378
389
  def file_find_by_name(self, path: str, glob: str) -> str:
379
- r"""Find files by name pattern in specified directory.
390
+ r"""Find files by name in a specified directory using a glob pattern.
391
+
392
+ This function recursively searches for files matching a given name or
393
+ pattern within a directory. It uses `find` on Unix-like systems and
394
+ `dir` on Windows.
380
395
 
381
396
  Args:
382
- path (str): Absolute path of directory to search.
383
- glob (str): Filename pattern using glob syntax wildcards.
397
+ path (str): The absolute path of the directory to search in.
398
+ glob (str): The filename pattern to search for, using glob syntax
399
+ (e.g., "*.py", "data*").
384
400
 
385
401
  Returns:
386
- str: List of files matching the pattern.
402
+ str: A newline-separated string containing the paths of the files
403
+ that match the pattern. Returns an error message if the
404
+ directory does not exist or another error occurs.
387
405
  """
388
406
  if not os.path.exists(path):
389
407
  return f"Directory not found: {path}"
@@ -649,18 +667,37 @@ class TerminalToolkit(BaseToolkit):
649
667
 
650
668
  return True, command
651
669
 
652
- def shell_exec(self, id: str, command: str) -> str:
653
- r"""Execute commands. This can be used to execute various commands,
654
- such as writing code, executing code, and running commands.
670
+ def shell_exec(
671
+ self, id: str, command: str, interactive: bool = False
672
+ ) -> str:
673
+ r"""Executes a shell command in a specified session.
674
+
675
+ This function creates and manages shell sessions to execute commands,
676
+ simulating a real terminal. It can run commands in both non-interactive
677
+ (capturing output) and interactive modes. Each session is identified by
678
+ a unique ID. If a session with the given ID does not exist, it will be
679
+ created.
655
680
 
656
681
  Args:
657
- id (str): Unique identifier of the target shell session.
658
- command (str): Shell command to execute.
682
+ id (str): A unique identifier for the shell session. This is used
683
+ to manage multiple concurrent shell processes.
684
+ command (str): The shell command to be executed.
685
+ interactive (bool, optional): If `True`, the command runs in
686
+ interactive mode, connecting it to the terminal's standard
687
+ input. This is useful for commands that require user input,
688
+ like `ssh`. Defaults to `False`. Interactive mode is only
689
+ supported on macOS and Linux. (default: :obj:`False`)
659
690
 
660
691
  Returns:
661
- str: Output of the command execution or error message.
692
+ str: The standard output and standard error from the command. If an
693
+ error occurs during execution, a descriptive error message is
694
+ returned.
695
+
696
+ Note:
697
+ When `interactive` is set to `True`, this function may block if the
698
+ command requires input. In safe mode, some commands that are
699
+ considered dangerous are restricted.
662
700
  """
663
- # Command execution must be within the working directory
664
701
  error_msg = self._enforce_working_dir_for_execution(self.working_dir)
665
702
  if error_msg:
666
703
  return error_msg
@@ -673,7 +710,6 @@ class TerminalToolkit(BaseToolkit):
673
710
  return f"Command rejected: {sanitized_command}"
674
711
  command = sanitized_command
675
712
 
676
- # If the session does not exist, create a new session
677
713
  if id not in self.shell_sessions:
678
714
  self.shell_sessions[id] = {
679
715
  "process": None,
@@ -682,7 +718,6 @@ class TerminalToolkit(BaseToolkit):
682
718
  }
683
719
 
684
720
  try:
685
- # First, log the command to be executed
686
721
  self._update_terminal_output(f"\n$ {command}\n")
687
722
 
688
723
  if command.startswith('python') or command.startswith('pip'):
@@ -706,42 +741,130 @@ class TerminalToolkit(BaseToolkit):
706
741
  elif command.startswith('pip'):
707
742
  command = command.replace('pip', pip_path, 1)
708
743
 
709
- proc = subprocess.Popen(
710
- command,
711
- shell=True,
712
- cwd=self.working_dir,
713
- stdout=subprocess.PIPE,
714
- stderr=subprocess.PIPE,
715
- stdin=subprocess.PIPE,
716
- text=True,
717
- bufsize=1,
718
- universal_newlines=True,
719
- env=os.environ.copy(),
720
- )
744
+ if not interactive:
745
+ proc = subprocess.Popen(
746
+ command,
747
+ shell=True,
748
+ cwd=self.working_dir,
749
+ stdout=subprocess.PIPE,
750
+ stderr=subprocess.PIPE,
751
+ stdin=subprocess.PIPE,
752
+ text=True,
753
+ bufsize=1,
754
+ universal_newlines=True,
755
+ env=os.environ.copy(),
756
+ )
757
+
758
+ self.shell_sessions[id]["process"] = proc
759
+ self.shell_sessions[id]["running"] = True
760
+ stdout, stderr = proc.communicate()
761
+ output = stdout or ""
762
+ if stderr:
763
+ output += f"\nStderr Output:\n{stderr}"
764
+ self.shell_sessions[id]["output"] = output
765
+ self._update_terminal_output(output + "\n")
766
+ return output
767
+
768
+ # Interactive mode with real-time streaming via PTY
769
+ if self.os_type not in ['Darwin', 'Linux']:
770
+ return (
771
+ "Interactive mode is not supported on "
772
+ f"{self.os_type} due to PTY limitations."
773
+ )
774
+
775
+ import pty
776
+ import select
777
+ import sys
778
+ import termios
779
+ import tty
780
+
781
+ # Fork a new process with a PTY
782
+ pid, master_fd = pty.fork()
783
+
784
+ if pid == 0: # Child process
785
+ # Execute the command in the child process
786
+ try:
787
+ import shlex
788
+
789
+ parts = shlex.split(command)
790
+ if not parts:
791
+ logger.error("Error: Empty command")
792
+ os._exit(1)
793
+
794
+ os.chdir(self.working_dir)
795
+ os.execvp(parts[0], parts)
796
+ except (ValueError, IndexError, OSError) as e:
797
+ logger.error(f"Command execution error: {e}")
798
+ os._exit(127)
799
+ except Exception as e:
800
+ logger.error(f"Unexpected error: {e}")
801
+ os._exit(1)
721
802
 
722
- # Store the process and mark it as running
723
- self.shell_sessions[id]["process"] = proc
803
+ # Parent process
804
+ self.shell_sessions[id]["process_id"] = pid
724
805
  self.shell_sessions[id]["running"] = True
806
+ output_lines: List[str] = []
807
+ original_settings = termios.tcgetattr(sys.stdin)
725
808
 
726
- # Get output
727
- stdout, stderr = proc.communicate()
809
+ try:
810
+ tty.setraw(sys.stdin.fileno())
728
811
 
729
- output = stdout or ""
730
- if stderr:
731
- output += f"\nStderr Output:\n{stderr}"
812
+ while True:
813
+ # Check if the child process has exited
814
+ try:
815
+ wait_pid, status = os.waitpid(pid, os.WNOHANG)
816
+ if wait_pid == pid:
817
+ self.shell_sessions[id]["running"] = False
818
+ break
819
+ except OSError:
820
+ # Process already reaped
821
+ self.shell_sessions[id]["running"] = False
822
+ break
823
+
824
+ # Use select to wait for I/O on stdin or master PTY
825
+ r, _, _ = select.select(
826
+ [sys.stdin, master_fd], [], [], 0.1
827
+ )
732
828
 
733
- # Update session information and terminal
734
- self.shell_sessions[id]["output"] = output
735
- self._update_terminal_output(output + "\n")
829
+ if master_fd in r:
830
+ try:
831
+ data = os.read(master_fd, 1024)
832
+ if not data:
833
+ break
834
+ decoded_data = data.decode(
835
+ 'utf-8', errors='replace'
836
+ )
837
+ # Echo to user's terminal and log
838
+ self._update_terminal_output(decoded_data)
839
+ output_lines.append(decoded_data)
840
+ except OSError:
841
+ break # PTY has been closed
736
842
 
737
- return output
843
+ if sys.stdin in r:
844
+ try:
845
+ user_input = os.read(sys.stdin.fileno(), 1024)
846
+ if not user_input:
847
+ break
848
+ os.write(master_fd, user_input)
849
+ except OSError:
850
+ break
851
+
852
+ finally:
853
+ if original_settings is not None:
854
+ termios.tcsetattr(
855
+ sys.stdin, termios.TCSADRAIN, original_settings
856
+ )
857
+ if master_fd:
858
+ os.close(master_fd)
859
+
860
+ final_output = "".join(output_lines)
861
+ self.shell_sessions[id]["output"] = final_output
862
+ return final_output
738
863
 
739
864
  except Exception as e:
740
865
  error_msg = f"Command execution error: {e!s}"
741
866
  logger.error(error_msg)
742
867
  self._update_terminal_output(f"\nError: {error_msg}\n")
743
-
744
- # More detailed error information
745
868
  import traceback
746
869
 
747
870
  detailed_error = traceback.format_exc()
@@ -751,13 +874,19 @@ class TerminalToolkit(BaseToolkit):
751
874
  )
752
875
 
753
876
  def shell_view(self, id: str) -> str:
754
- r"""View the content of a specified shell session.
877
+ r"""View the full output history of a specified shell session.
878
+
879
+ Retrieves the accumulated output (both stdout and stderr) generated by
880
+ commands in the specified session since its creation. This is useful
881
+ for checking the complete history of a session, especially after a
882
+ command has finished execution.
755
883
 
756
884
  Args:
757
- id (str): Unique identifier of the target shell session.
885
+ id (str): The unique identifier of the shell session to view.
758
886
 
759
887
  Returns:
760
- str: Current output content of the shell session.
888
+ str: The complete output history of the shell session. Returns an
889
+ error message if the session is not found.
761
890
  """
762
891
  if id not in self.shell_sessions:
763
892
  return f"Shell session not found: {id}"
@@ -788,16 +917,22 @@ class TerminalToolkit(BaseToolkit):
788
917
  return f"Error: {e!s}"
789
918
 
790
919
  def shell_wait(self, id: str, seconds: Optional[int] = None) -> str:
791
- r"""Wait for the running process in a specified shell session to
792
- return.
920
+ r"""Wait for a command to finish in a specified shell session.
921
+
922
+ Blocks execution and waits for the running process in a shell session
923
+ to complete. This is useful for ensuring a long-running command has
924
+ finished before proceeding.
793
925
 
794
926
  Args:
795
- id (str): Unique identifier of the target shell session.
796
- seconds (Optional[int], optional): Wait duration in seconds.
797
- If None, wait indefinitely. Defaults to None.
927
+ id (str): The unique identifier of the target shell session.
928
+ seconds (Optional[int], optional): The maximum time to wait, in
929
+ seconds. If `None`, it waits indefinitely.
930
+ (default: :obj:`None`)
798
931
 
799
932
  Returns:
800
- str: Final output content after waiting.
933
+ str: A message indicating that the process has completed, including
934
+ the final output. If the process times out, it returns a
935
+ timeout message.
801
936
  """
802
937
  if id not in self.shell_sessions:
803
938
  return f"Shell session not found: {id}"
@@ -857,13 +992,20 @@ class TerminalToolkit(BaseToolkit):
857
992
  ) -> str:
858
993
  r"""Write input to a running process in a specified shell session.
859
994
 
995
+ Sends a string of text to the standard input of a running process.
996
+ This is useful for interacting with commands that require input. This
997
+ function cannot be used with a command that was started in
998
+ interactive mode.
999
+
860
1000
  Args:
861
- id (str): Unique identifier of the target shell session.
862
- input (str): Input content to write to the process.
863
- press_enter (bool): Whether to press Enter key after input.
1001
+ id (str): The unique identifier of the target shell session.
1002
+ input (str): The text to write to the process's stdin.
1003
+ press_enter (bool): If `True`, a newline character (`\n`) is
1004
+ appended to the input, simulating pressing the Enter key.
864
1005
 
865
1006
  Returns:
866
- str: Status message indicating whether the input was sent.
1007
+ str: A status message indicating whether the input was sent, or an
1008
+ error message if the operation fails.
867
1009
  """
868
1010
  if id not in self.shell_sessions:
869
1011
  return f"Shell session not found: {id}"
@@ -899,11 +1041,17 @@ class TerminalToolkit(BaseToolkit):
899
1041
  def shell_kill_process(self, id: str) -> str:
900
1042
  r"""Terminate a running process in a specified shell session.
901
1043
 
1044
+ Forcibly stops a command that is currently running in a shell session.
1045
+ This is useful for ending processes that are stuck, running too long,
1046
+ or need to be cancelled.
1047
+
902
1048
  Args:
903
- id (str): Unique identifier of the target shell session.
1049
+ id (str): The unique identifier of the shell session containing the
1050
+ process to be terminated.
904
1051
 
905
1052
  Returns:
906
- str: Status message indicating whether the process was terminated.
1053
+ str: A status message indicating that the process has been
1054
+ terminated, or an error message if the operation fails.
907
1055
  """
908
1056
  if id not in self.shell_sessions:
909
1057
  return f"Shell session not found: {id}"
@@ -939,22 +1087,24 @@ class TerminalToolkit(BaseToolkit):
939
1087
  return f"Error killing process: {e!s}"
940
1088
 
941
1089
  def ask_user_for_help(self, id: str) -> str:
942
- r"""Pauses agent execution to ask a human for help in the terminal.
1090
+ r"""Pause the agent and ask a human for help with a command.
943
1091
 
944
- This function should be called when an agent is stuck or needs
945
- assistance with a task that requires manual intervention (e.g.,
946
- solving a CAPTCHA or complex debugging). The human will take over the
947
- specified terminal session to execute commands and then return control
948
- to the agent.
1092
+ This function should be used when the agent is stuck and requires
1093
+ manual intervention, such as solving a CAPTCHA or debugging a complex
1094
+ issue. It pauses the agent's execution and allows a human to take
1095
+ control of a specified shell session. The human can execute one
1096
+ command to resolve the issue, and then control is returned to the
1097
+ agent.
949
1098
 
950
1099
  Args:
951
- id (str): Identifier of the shell session for the human to
952
- interact with. If the session does not yet exist, it will be
953
- created automatically.
1100
+ id (str): The identifier of the shell session for the human to
1101
+ interact with. If the session does not exist, it will be
1102
+ created.
954
1103
 
955
1104
  Returns:
956
1105
  str: A status message indicating that the human has finished,
957
- including the number of commands executed.
1106
+ including the number of commands executed. If the takeover
1107
+ times out or fails, an error message is returned.
958
1108
  """
959
1109
  # Input validation
960
1110
  if not id or not isinstance(id, str):
camel/utils/mcp_client.py CHANGED
@@ -113,7 +113,11 @@ class ServerConfig(BaseModel):
113
113
  # Advanced options
114
114
  sse_read_timeout: float = 300.0 # 5 minutes
115
115
  terminate_on_close: bool = True
116
- # For HTTP URLs, prefer SSE over StreamableHTTP
116
+
117
+ # New transport type parameter
118
+ type: Optional[str] = None
119
+
120
+ # Legacy parameter for backward compatibility
117
121
  prefer_sse: bool = False
118
122
 
119
123
  @model_validator(mode='after')
@@ -128,11 +132,43 @@ class ServerConfig(BaseModel):
128
132
  if self.command and self.url:
129
133
  raise ValueError("Cannot specify both 'command' and 'url'")
130
134
 
135
+ # Validate type if provided
136
+ if self.type is not None:
137
+ valid_types = {"stdio", "sse", "streamable_http", "websocket"}
138
+ if self.type not in valid_types:
139
+ raise ValueError(
140
+ f"Invalid type: "
141
+ f"'{self.type}'. "
142
+ f"Valid options: {valid_types}"
143
+ )
144
+
145
+ # Issue deprecation warning if prefer_sse is used
146
+ if self.prefer_sse and self.type is None:
147
+ import warnings
148
+
149
+ warnings.warn(
150
+ "The 'prefer_sse' parameter is deprecated. "
151
+ "Use 'type=\"sse\"' instead.",
152
+ DeprecationWarning,
153
+ stacklevel=2,
154
+ )
155
+
131
156
  return self
132
157
 
133
158
  @property
134
159
  def transport_type(self) -> TransportType:
135
160
  r"""Automatically detect transport type based on configuration."""
161
+ # Use explicit transport type if provided
162
+ if self.type is not None:
163
+ transport_map = {
164
+ "stdio": TransportType.STDIO,
165
+ "sse": TransportType.SSE,
166
+ "streamable_http": TransportType.STREAMABLE_HTTP,
167
+ "websocket": TransportType.WEBSOCKET,
168
+ }
169
+ return transport_map[self.type]
170
+
171
+ # If no type is provided, fall back to automatic detection
136
172
  if self.command:
137
173
  return TransportType.STDIO
138
174
  elif self.url:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: camel-ai
3
- Version: 0.2.71a3
3
+ Version: 0.2.71a5
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
@@ -15,7 +15,7 @@ Requires-Dist: docstring-parser<0.16,>=0.15
15
15
  Requires-Dist: httpx<1.0.0dev,>=0.28.0
16
16
  Requires-Dist: jsonschema<5,>=4
17
17
  Requires-Dist: mcp>=1.3.0
18
- Requires-Dist: openai<2,>=1.68.0
18
+ Requires-Dist: openai<2,>=1.86.0
19
19
  Requires-Dist: pillow<11.0.0,>=10.1.0
20
20
  Requires-Dist: psutil<6,>=5.9.8
21
21
  Requires-Dist: pydantic>=2.10.6
@@ -39,7 +39,7 @@ Requires-Dist: dappier<0.4,>=0.3.3; extra == 'all'
39
39
  Requires-Dist: datacommons-pandas<0.0.4,>=0.0.3; extra == 'all'
40
40
  Requires-Dist: datacommons<2,>=1.4.3; extra == 'all'
41
41
  Requires-Dist: datasets<4,>=3; extra == 'all'
42
- Requires-Dist: daytona-sdk>=0.20.0; extra == 'all'
42
+ Requires-Dist: daytona-sdk==0.20.0; extra == 'all'
43
43
  Requires-Dist: diffusers<0.26,>=0.25.0; extra == 'all'
44
44
  Requires-Dist: discord-py<3,>=2.3.2; extra == 'all'
45
45
  Requires-Dist: docker<8,>=7.1.0; extra == 'all'
@@ -98,7 +98,6 @@ Requires-Dist: pygithub<3,>=2.6.0; extra == 'all'
98
98
  Requires-Dist: pylatex>=1.4.2; extra == 'all'
99
99
  Requires-Dist: pymilvus<3,>=2.4.0; extra == 'all'
100
100
  Requires-Dist: pymupdf<2,>=1.22.5; extra == 'all'
101
- Requires-Dist: pymupdf>=1.26.1; extra == 'all'
102
101
  Requires-Dist: pyobvector>=0.1.18; extra == 'all'
103
102
  Requires-Dist: pyowm<4,>=3.3.0; extra == 'all'
104
103
  Requires-Dist: pytelegrambotapi<5,>=4.18.0; extra == 'all'
@@ -112,6 +111,7 @@ Requires-Dist: qdrant-client<2,>=1.9.0; extra == 'all'
112
111
  Requires-Dist: rank-bm25<0.3,>=0.2.2; extra == 'all'
113
112
  Requires-Dist: redis<6,>=5.0.6; extra == 'all'
114
113
  Requires-Dist: reka-api<4,>=3.0.8; extra == 'all'
114
+ Requires-Dist: reportlab>=4.4.2; extra == 'all'
115
115
  Requires-Dist: requests-oauthlib<2,>=1.3.1; extra == 'all'
116
116
  Requires-Dist: rlcard<1.3.0,>=1.0.0; extra == 'all'
117
117
  Requires-Dist: rouge<2,>=1.0.1; extra == 'all'
@@ -127,6 +127,7 @@ Requires-Dist: sympy<2,>=1.13.3; extra == 'all'
127
127
  Requires-Dist: tabulate>=0.9.0; extra == 'all'
128
128
  Requires-Dist: tavily-python<0.6,>=0.5.0; extra == 'all'
129
129
  Requires-Dist: textblob<0.18,>=0.17.1; extra == 'all'
130
+ Requires-Dist: traceroot==0.0.3a2; extra == 'all'
130
131
  Requires-Dist: transformers<5,>=4; extra == 'all'
131
132
  Requires-Dist: tree-sitter-python<0.24,>=0.23.6; extra == 'all'
132
133
  Requires-Dist: tree-sitter<0.24,>=0.23.2; extra == 'all'
@@ -183,13 +184,14 @@ Requires-Dist: uv<0.8,>=0.7.0; extra == 'dev'
183
184
  Provides-Extra: dev-tools
184
185
  Requires-Dist: aci-sdk>=1.0.0b1; extra == 'dev-tools'
185
186
  Requires-Dist: agentops<0.4,>=0.3.21; extra == 'dev-tools'
186
- Requires-Dist: daytona-sdk>=0.20.0; extra == 'dev-tools'
187
+ Requires-Dist: daytona-sdk==0.20.0; extra == 'dev-tools'
187
188
  Requires-Dist: docker<8,>=7.1.0; extra == 'dev-tools'
188
189
  Requires-Dist: e2b-code-interpreter<2,>=1.0.3; extra == 'dev-tools'
189
190
  Requires-Dist: ipykernel<7,>=6.0.0; extra == 'dev-tools'
190
191
  Requires-Dist: jupyter-client<9,>=8.6.2; extra == 'dev-tools'
191
192
  Requires-Dist: langfuse>=2.60.5; extra == 'dev-tools'
192
193
  Requires-Dist: mcp>=1.3.0; extra == 'dev-tools'
194
+ Requires-Dist: traceroot==0.0.3a2; extra == 'dev-tools'
193
195
  Requires-Dist: tree-sitter-python<0.24,>=0.23.6; extra == 'dev-tools'
194
196
  Requires-Dist: tree-sitter<0.24,>=0.23.2; extra == 'dev-tools'
195
197
  Requires-Dist: typer>=0.15.2; extra == 'dev-tools'
@@ -214,8 +216,8 @@ Requires-Dist: pandasai<3,>=2.3.0; extra == 'document-tools'
214
216
  Requires-Dist: prance<24,>=23.6.21.0; extra == 'document-tools'
215
217
  Requires-Dist: pylatex>=1.4.2; extra == 'document-tools'
216
218
  Requires-Dist: pymupdf<2,>=1.22.5; extra == 'document-tools'
217
- Requires-Dist: pymupdf>=1.26.1; extra == 'document-tools'
218
219
  Requires-Dist: python-pptx>=1.0.2; extra == 'document-tools'
220
+ Requires-Dist: reportlab>=4.4.2; extra == 'document-tools'
219
221
  Requires-Dist: tabulate>=0.9.0; extra == 'document-tools'
220
222
  Requires-Dist: unstructured==0.16.20; extra == 'document-tools'
221
223
  Requires-Dist: xls2xlsx>=0.2.0; extra == 'document-tools'
@@ -272,10 +274,10 @@ Requires-Dist: pyautogui<0.10,>=0.9.54; extra == 'owl'
272
274
  Requires-Dist: pydub<0.26,>=0.25.1; extra == 'owl'
273
275
  Requires-Dist: pylatex>=1.4.2; extra == 'owl'
274
276
  Requires-Dist: pymupdf<2,>=1.22.5; extra == 'owl'
275
- Requires-Dist: pymupdf>=1.26.1; extra == 'owl'
276
277
  Requires-Dist: pytesseract>=0.3.13; extra == 'owl'
277
278
  Requires-Dist: python-dotenv<2,>=1.0.0; extra == 'owl'
278
279
  Requires-Dist: python-pptx>=1.0.2; extra == 'owl'
280
+ Requires-Dist: reportlab>=4.4.2; extra == 'owl'
279
281
  Requires-Dist: requests-oauthlib<2,>=1.3.1; extra == 'owl'
280
282
  Requires-Dist: rouge<2,>=1.0.1; extra == 'owl'
281
283
  Requires-Dist: scenedetect>=0.6.5.2; extra == 'owl'
@@ -753,6 +755,45 @@ Practical guides and tutorials for implementing specific functionalities in CAME
753
755
  | **[3 Ways to Ingest Data from Websites with Firecrawl](https://docs.camel-ai.org/cookbooks/data_processing/ingest_data_from_websites_with_Firecrawl.html)** | Explore three methods for extracting and processing data from websites using Firecrawl. |
754
756
  | **[Create AI Agents that work with your PDFs](https://docs.camel-ai.org/cookbooks/data_processing/agent_with_chunkr_for_pdf_parsing.html)** | Learn how to create AI agents that work with your PDFs using Chunkr and Mistral AI. |
755
757
 
758
+ <br>
759
+
760
+ ## Real-World Usecases
761
+
762
+ Real-world usecases demonstrating how CAMEL’s multi-agent framework enables real business value across infrastructure automation, productivity workflows, retrieval-augmented conversations, intelligent document/video analysis, and collaborative research.
763
+
764
+ ### 1 Infrastructure Automation
765
+
766
+ | Usecase | Description |
767
+ | :----------------------------------------------------------- | :----------------------------------------------------------- |
768
+ | **[ACI MCP](https://github.com/camel-ai/camel/tree/master/examples/usecases/aci_mcp)** | Real-world usecases demonstrating how CAMEL’s multi-agent framework enables real business value across infrastructure automation, productivity workflows, retrieval-augmented conversations, intelligent document/video analysis, and collaborative research. |
769
+ | **[Cloudflare MCP CAMEL](https://github.com/camel-ai/camel/tree/master/examples/usecases/cloudfare_mcp_camel)** | Intelligent agents manage Cloudflare resources dynamically, enabling scalable and efficient cloud security and performance tuning. |
770
+
771
+ ### 2 Productivity & Business Workflows
772
+
773
+ | Usecase | Description |
774
+ | :----------------------------------------------------------- | :----------------------------------------------------------- |
775
+ | **[Airbnb MCP](https://github.com/camel-ai/camel/tree/master/examples/usecases/airbnb_mcp)** | Coordinate agents to optimize and manage Airbnb listings and host operations. |
776
+ | **[PPTX Toolkit Usecase](https://github.com/camel-ai/camel/tree/master/examples/usecases/pptx_toolkit_usecase)** | Analyze PowerPoint documents and extract structured insights through multi-agent collaboration. |
777
+
778
+ ### 3 Retrieval-Augmented Multi-Agent Chat
779
+
780
+ | Usecase | Description |
781
+ | :----------------------------------------------------------- | :----------------------------------------------------------- |
782
+ | **[Chat with GitHub](https://github.com/camel-ai/camel/tree/master/examples/usecases/chat_with_github)** | Query and understand GitHub codebases through CAMEL agents leveraging RAG-style workflows, accelerating developer onboarding and codebase navigation. |
783
+ | **[Chat with YouTube](https://github.com/camel-ai/camel/tree/master/examples/usecases/chat_with_youtube)** | Conversational agents extract and summarize video transcripts, enabling faster content understanding and repurposing. |
784
+
785
+ ### 4 Video & Document Intelligence
786
+
787
+ | Usecase | Description |
788
+ | :----------------------------------------------------------- | :----------------------------------------------------------- |
789
+ | **[YouTube OCR](https://github.com/camel-ai/camel/tree/master/examples/usecases/youtube_ocr)** | Agents perform OCR on video screenshots to summarize visual content, supporting media monitoring and compliance. |
790
+ | **[Mistral OCR](https://github.com/camel-ai/camel/tree/master/examples/usecases/mistral_OCR)** | CAMEL agents use OCR with Mistral to analyze documents, reducing manual effort in document understanding workflows. |
791
+
792
+ ### 5 Research & Collaboration
793
+
794
+ | Usecase | Description |
795
+ | :----------------------------------------------------------- | :----------------------------------------------------------- |
796
+ | **[Multi-Agent Research Assistant](https://github.com/camel-ai/camel/tree/master/examples/usecases/multi_agent_research_assistant)** | Simulates a team of research agents collaborating on literature review, improving efficiency in exploratory analysis and reporting. |
756
797
 
757
798
  <br>
758
799