camel-ai 0.2.71a1__py3-none-any.whl → 0.2.71a2__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 +61 -3
- camel/messages/func_message.py +32 -5
- camel/societies/workforce/single_agent_worker.py +1 -5
- camel/societies/workforce/workforce.py +68 -8
- camel/tasks/task.py +2 -2
- camel/toolkits/craw4ai_toolkit.py +27 -7
- camel/toolkits/file_write_toolkit.py +110 -31
- camel/toolkits/human_toolkit.py +19 -14
- camel/toolkits/jina_reranker_toolkit.py +3 -4
- camel/toolkits/terminal_toolkit.py +189 -48
- camel/toolkits/video_download_toolkit.py +1 -2
- camel/utils/message_summarizer.py +148 -0
- {camel_ai-0.2.71a1.dist-info → camel_ai-0.2.71a2.dist-info}/METADATA +4 -4
- {camel_ai-0.2.71a1.dist-info → camel_ai-0.2.71a2.dist-info}/RECORD +17 -16
- {camel_ai-0.2.71a1.dist-info → camel_ai-0.2.71a2.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.71a1.dist-info → camel_ai-0.2.71a2.dist-info}/licenses/LICENSE +0 -0
camel/toolkits/human_toolkit.py
CHANGED
|
@@ -22,7 +22,12 @@ logger = logging.getLogger(__name__)
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class HumanToolkit(BaseToolkit):
|
|
25
|
-
r"""A class representing a toolkit for human interaction.
|
|
25
|
+
r"""A class representing a toolkit for human interaction.
|
|
26
|
+
|
|
27
|
+
Note:
|
|
28
|
+
This toolkit should be called to send a tidy message to the user to
|
|
29
|
+
keep them informed.
|
|
30
|
+
"""
|
|
26
31
|
|
|
27
32
|
def ask_human_via_console(self, question: str) -> str:
|
|
28
33
|
r"""Use this tool to ask a question to the user when you are stuck,
|
|
@@ -48,21 +53,21 @@ class HumanToolkit(BaseToolkit):
|
|
|
48
53
|
return reply
|
|
49
54
|
|
|
50
55
|
def send_message_to_user(self, message: str) -> None:
|
|
51
|
-
r"""Use this tool to send a message to the user
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
task.
|
|
56
|
+
r"""Use this tool to send a tidy message to the user in one short
|
|
57
|
+
sentence.
|
|
58
|
+
|
|
59
|
+
This one-way tool keeps the user informed about your progress,
|
|
60
|
+
decisions, or actions. It does not require a response.
|
|
61
|
+
You should use it to:
|
|
62
|
+
- Announce what you are about to do (e.g., "I will now search for
|
|
63
|
+
papers on GUI Agents.").
|
|
64
|
+
- Report the result of an action (e.g., "I have found 15 relevant
|
|
65
|
+
papers.").
|
|
66
|
+
- State a decision (e.g., "I will now analyze the top 10 papers.").
|
|
67
|
+
- Give a status update during a long-running task.
|
|
63
68
|
|
|
64
69
|
Args:
|
|
65
|
-
message (str): The
|
|
70
|
+
message (str): The tidy and informative message for the user.
|
|
66
71
|
"""
|
|
67
72
|
print(f"\nAgent Message:\n{message}")
|
|
68
73
|
logger.info(f"\nAgent Message:\n{message}")
|
|
@@ -34,7 +34,7 @@ class JinaRerankerToolkit(BaseToolkit):
|
|
|
34
34
|
def __init__(
|
|
35
35
|
self,
|
|
36
36
|
timeout: Optional[float] = None,
|
|
37
|
-
model_name:
|
|
37
|
+
model_name: str = "jinaai/jina-reranker-m0",
|
|
38
38
|
device: Optional[str] = None,
|
|
39
39
|
use_api: bool = True,
|
|
40
40
|
) -> None:
|
|
@@ -44,9 +44,8 @@ class JinaRerankerToolkit(BaseToolkit):
|
|
|
44
44
|
timeout (Optional[float]): The timeout value for API requests
|
|
45
45
|
in seconds. If None, no timeout is applied.
|
|
46
46
|
(default: :obj:`None`)
|
|
47
|
-
model_name (
|
|
48
|
-
|
|
49
|
-
(default: :obj:`None`)
|
|
47
|
+
model_name (str): The reranker model name.
|
|
48
|
+
(default: :obj:`"jinaai/jina-reranker-m0"`)
|
|
50
49
|
device (Optional[str]): Device to load the model on. If None,
|
|
51
50
|
will use CUDA if available, otherwise CPU.
|
|
52
51
|
Only effective when use_api=False.
|
|
@@ -84,6 +84,7 @@ class TerminalToolkit(BaseToolkit):
|
|
|
84
84
|
self._file_initialized = False
|
|
85
85
|
self.cloned_env_path = None
|
|
86
86
|
self.use_shell_mode = use_shell_mode
|
|
87
|
+
self._human_takeover_active = False
|
|
87
88
|
|
|
88
89
|
self.python_executable = sys.executable
|
|
89
90
|
self.is_macos = platform.system() == 'Darwin'
|
|
@@ -705,59 +706,35 @@ class TerminalToolkit(BaseToolkit):
|
|
|
705
706
|
elif command.startswith('pip'):
|
|
706
707
|
command = command.replace('pip', pip_path, 1)
|
|
707
708
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
output = process.stdout or ""
|
|
721
|
-
if process.stderr:
|
|
722
|
-
output += f"\nStderr Output:\n{process.stderr}"
|
|
723
|
-
|
|
724
|
-
# Update session information and terminal
|
|
725
|
-
self.shell_sessions[id]["output"] = output
|
|
726
|
-
self._update_terminal_output(output + "\n")
|
|
727
|
-
|
|
728
|
-
return output
|
|
729
|
-
|
|
730
|
-
else:
|
|
731
|
-
# Non-macOS systems use the Popen method
|
|
732
|
-
proc = subprocess.Popen(
|
|
733
|
-
command,
|
|
734
|
-
shell=True,
|
|
735
|
-
cwd=self.working_dir,
|
|
736
|
-
stdout=subprocess.PIPE,
|
|
737
|
-
stderr=subprocess.PIPE,
|
|
738
|
-
stdin=subprocess.PIPE,
|
|
739
|
-
text=True,
|
|
740
|
-
bufsize=1,
|
|
741
|
-
universal_newlines=True,
|
|
742
|
-
env=os.environ.copy(),
|
|
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
721
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
722
|
+
# Store the process and mark it as running
|
|
723
|
+
self.shell_sessions[id]["process"] = proc
|
|
724
|
+
self.shell_sessions[id]["running"] = True
|
|
748
725
|
|
|
749
|
-
|
|
750
|
-
|
|
726
|
+
# Get output
|
|
727
|
+
stdout, stderr = proc.communicate()
|
|
751
728
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
729
|
+
output = stdout or ""
|
|
730
|
+
if stderr:
|
|
731
|
+
output += f"\nStderr Output:\n{stderr}"
|
|
755
732
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
733
|
+
# Update session information and terminal
|
|
734
|
+
self.shell_sessions[id]["output"] = output
|
|
735
|
+
self._update_terminal_output(output + "\n")
|
|
759
736
|
|
|
760
|
-
|
|
737
|
+
return output
|
|
761
738
|
|
|
762
739
|
except Exception as e:
|
|
763
740
|
error_msg = f"Command execution error: {e!s}"
|
|
@@ -961,6 +938,169 @@ class TerminalToolkit(BaseToolkit):
|
|
|
961
938
|
logger.error(f"Error killing process: {e}")
|
|
962
939
|
return f"Error killing process: {e!s}"
|
|
963
940
|
|
|
941
|
+
def ask_user_for_help(self, id: str) -> str:
|
|
942
|
+
r"""Pauses agent execution to ask a human for help in the terminal.
|
|
943
|
+
|
|
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.
|
|
949
|
+
|
|
950
|
+
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.
|
|
954
|
+
|
|
955
|
+
Returns:
|
|
956
|
+
str: A status message indicating that the human has finished,
|
|
957
|
+
including the number of commands executed.
|
|
958
|
+
"""
|
|
959
|
+
# Input validation
|
|
960
|
+
if not id or not isinstance(id, str):
|
|
961
|
+
return "Error: Invalid session ID provided"
|
|
962
|
+
|
|
963
|
+
# Prevent concurrent human takeovers
|
|
964
|
+
if (
|
|
965
|
+
hasattr(self, '_human_takeover_active')
|
|
966
|
+
and self._human_takeover_active
|
|
967
|
+
):
|
|
968
|
+
return "Error: Human takeover already in progress"
|
|
969
|
+
|
|
970
|
+
try:
|
|
971
|
+
self._human_takeover_active = True
|
|
972
|
+
|
|
973
|
+
# Ensure the session exists so that the human can reuse it
|
|
974
|
+
if id not in self.shell_sessions:
|
|
975
|
+
self.shell_sessions[id] = {
|
|
976
|
+
"process": None,
|
|
977
|
+
"output": "",
|
|
978
|
+
"running": False,
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
command_count = 0
|
|
982
|
+
error_occurred = False
|
|
983
|
+
|
|
984
|
+
# Create clear banner message for user
|
|
985
|
+
takeover_banner = (
|
|
986
|
+
f"\n{'='*60}\n"
|
|
987
|
+
f"🤖 CAMEL Agent needs human help! Session: {id}\n"
|
|
988
|
+
f"📂 Working directory: {self.working_dir}\n"
|
|
989
|
+
f"{'='*60}\n"
|
|
990
|
+
f"💡 Type commands or '/exit' to return control to agent.\n"
|
|
991
|
+
f"{'='*60}\n"
|
|
992
|
+
)
|
|
993
|
+
|
|
994
|
+
# Print once to console for immediate visibility
|
|
995
|
+
print(takeover_banner, flush=True)
|
|
996
|
+
# Log for terminal output tracking
|
|
997
|
+
self._update_terminal_output(takeover_banner)
|
|
998
|
+
|
|
999
|
+
# Helper flag + event for coordination
|
|
1000
|
+
done_event = threading.Event()
|
|
1001
|
+
|
|
1002
|
+
def _human_loop() -> None:
|
|
1003
|
+
r"""Blocking loop that forwards human input to shell_exec."""
|
|
1004
|
+
nonlocal command_count, error_occurred
|
|
1005
|
+
try:
|
|
1006
|
+
while True:
|
|
1007
|
+
try:
|
|
1008
|
+
# Clear, descriptive prompt for user input
|
|
1009
|
+
user_cmd = input(f"🧑💻 [{id}]> ")
|
|
1010
|
+
if (
|
|
1011
|
+
user_cmd.strip()
|
|
1012
|
+
): # Only count non-empty commands
|
|
1013
|
+
command_count += 1
|
|
1014
|
+
except EOFError:
|
|
1015
|
+
# e.g. Ctrl_D / stdin closed, treat as exit.
|
|
1016
|
+
break
|
|
1017
|
+
except (KeyboardInterrupt, Exception) as e:
|
|
1018
|
+
logger.warning(
|
|
1019
|
+
f"Input error during human takeover: {e}"
|
|
1020
|
+
)
|
|
1021
|
+
error_occurred = True
|
|
1022
|
+
break
|
|
1023
|
+
|
|
1024
|
+
if user_cmd.strip() in {"/exit", "exit", "quit"}:
|
|
1025
|
+
break
|
|
1026
|
+
|
|
1027
|
+
try:
|
|
1028
|
+
exec_result = self.shell_exec(id, user_cmd)
|
|
1029
|
+
# Show the result immediately to the user
|
|
1030
|
+
if exec_result.strip():
|
|
1031
|
+
print(exec_result)
|
|
1032
|
+
logger.info(
|
|
1033
|
+
f"Human command executed: {user_cmd[:50]}..."
|
|
1034
|
+
)
|
|
1035
|
+
# Auto-exit after successful command
|
|
1036
|
+
break
|
|
1037
|
+
except Exception as e:
|
|
1038
|
+
error_msg = f"Error executing command: {e}"
|
|
1039
|
+
logger.error(f"Error executing human command: {e}")
|
|
1040
|
+
print(error_msg) # Show error to user immediately
|
|
1041
|
+
self._update_terminal_output(f"{error_msg}\n")
|
|
1042
|
+
error_occurred = True
|
|
1043
|
+
|
|
1044
|
+
except Exception as e:
|
|
1045
|
+
logger.error(f"Unexpected error in human loop: {e}")
|
|
1046
|
+
error_occurred = True
|
|
1047
|
+
finally:
|
|
1048
|
+
# Notify completion clearly
|
|
1049
|
+
finish_msg = (
|
|
1050
|
+
f"\n{'='*60}\n"
|
|
1051
|
+
f"✅ Human assistance completed! "
|
|
1052
|
+
f"Commands: {command_count}\n"
|
|
1053
|
+
f"🤖 Returning control to CAMEL agent...\n"
|
|
1054
|
+
f"{'='*60}\n"
|
|
1055
|
+
)
|
|
1056
|
+
print(finish_msg, flush=True)
|
|
1057
|
+
self._update_terminal_output(finish_msg)
|
|
1058
|
+
done_event.set()
|
|
1059
|
+
|
|
1060
|
+
# Start interactive thread (non-daemon for proper cleanup)
|
|
1061
|
+
thread = threading.Thread(target=_human_loop, daemon=False)
|
|
1062
|
+
thread.start()
|
|
1063
|
+
|
|
1064
|
+
# Block until human signals completion with timeout
|
|
1065
|
+
if done_event.wait(timeout=600): # 10 minutes timeout
|
|
1066
|
+
thread.join(timeout=10) # Give thread time to cleanup
|
|
1067
|
+
|
|
1068
|
+
# Generate detailed status message
|
|
1069
|
+
status = "completed successfully"
|
|
1070
|
+
if error_occurred:
|
|
1071
|
+
status = "completed with some errors"
|
|
1072
|
+
|
|
1073
|
+
result_msg = (
|
|
1074
|
+
f"Human assistance {status} for session '{id}'. "
|
|
1075
|
+
f"Total commands executed: {command_count}. "
|
|
1076
|
+
f"Working directory: {self.working_dir}"
|
|
1077
|
+
)
|
|
1078
|
+
logger.info(result_msg)
|
|
1079
|
+
return result_msg
|
|
1080
|
+
else:
|
|
1081
|
+
timeout_msg = (
|
|
1082
|
+
f"Human takeover for session '{id}' timed out after 10 "
|
|
1083
|
+
"minutes"
|
|
1084
|
+
)
|
|
1085
|
+
logger.warning(timeout_msg)
|
|
1086
|
+
return timeout_msg
|
|
1087
|
+
|
|
1088
|
+
except Exception as e:
|
|
1089
|
+
error_msg = f"Error during human takeover for session '{id}': {e}"
|
|
1090
|
+
logger.error(error_msg)
|
|
1091
|
+
# Notify user of the error clearly
|
|
1092
|
+
error_banner = (
|
|
1093
|
+
f"\n{'='*60}\n"
|
|
1094
|
+
f"❌ Error in human takeover! Session: {id}\n"
|
|
1095
|
+
f"❗ {e}\n"
|
|
1096
|
+
f"{'='*60}\n"
|
|
1097
|
+
)
|
|
1098
|
+
print(error_banner, flush=True)
|
|
1099
|
+
return error_msg
|
|
1100
|
+
finally:
|
|
1101
|
+
# Always reset the flag
|
|
1102
|
+
self._human_takeover_active = False
|
|
1103
|
+
|
|
964
1104
|
def __del__(self):
|
|
965
1105
|
r"""Clean up resources when the object is being destroyed.
|
|
966
1106
|
Terminates all running processes and closes any open file handles.
|
|
@@ -1042,4 +1182,5 @@ class TerminalToolkit(BaseToolkit):
|
|
|
1042
1182
|
FunctionTool(self.shell_wait),
|
|
1043
1183
|
FunctionTool(self.shell_write_to_process),
|
|
1044
1184
|
FunctionTool(self.shell_kill_process),
|
|
1185
|
+
FunctionTool(self.ask_user_for_help),
|
|
1045
1186
|
]
|
|
@@ -26,7 +26,7 @@ from PIL import Image
|
|
|
26
26
|
from camel.logger import get_logger
|
|
27
27
|
from camel.toolkits.base import BaseToolkit
|
|
28
28
|
from camel.toolkits.function_tool import FunctionTool
|
|
29
|
-
from camel.utils import
|
|
29
|
+
from camel.utils import dependencies_required
|
|
30
30
|
|
|
31
31
|
logger = get_logger(__name__)
|
|
32
32
|
|
|
@@ -57,7 +57,6 @@ def _capture_screenshot(video_file: str, timestamp: float) -> Image.Image:
|
|
|
57
57
|
return Image.open(io.BytesIO(out))
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
@MCPServer()
|
|
61
60
|
class VideoDownloaderToolkit(BaseToolkit):
|
|
62
61
|
r"""A class for downloading videos and optionally splitting them into
|
|
63
62
|
chunks.
|
|
@@ -0,0 +1,148 @@
|
|
|
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 typing import List, Optional
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel, Field
|
|
17
|
+
|
|
18
|
+
from camel.agents import ChatAgent
|
|
19
|
+
from camel.messages import BaseMessage
|
|
20
|
+
from camel.models import BaseModelBackend, ModelFactory
|
|
21
|
+
from camel.types import ModelPlatformType, ModelType
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MessageSummary(BaseModel):
|
|
25
|
+
r"""Schema for structured message summaries.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
summary (str): A brief, one-sentence summary of the conversation.
|
|
29
|
+
participants (List[str]): The roles of participants involved.
|
|
30
|
+
key_topics_and_entities (List[str]): Important topics, concepts, and
|
|
31
|
+
entities discussed.
|
|
32
|
+
decisions_and_outcomes (List[str]): Key decisions, conclusions, or
|
|
33
|
+
outcomes reached.
|
|
34
|
+
action_items (List[str]): A list of specific tasks or actions to be
|
|
35
|
+
taken, with assignees if mentioned.
|
|
36
|
+
progress_on_main_task (str): A summary of progress made on the
|
|
37
|
+
primary task.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
summary: str = Field(
|
|
41
|
+
description="A brief, one-sentence summary of the conversation."
|
|
42
|
+
)
|
|
43
|
+
participants: List[str] = Field(
|
|
44
|
+
description="The roles of participants involved."
|
|
45
|
+
)
|
|
46
|
+
key_topics_and_entities: List[str] = Field(
|
|
47
|
+
description="Important topics, concepts, and entities discussed."
|
|
48
|
+
)
|
|
49
|
+
decisions_and_outcomes: List[str] = Field(
|
|
50
|
+
description="Key decisions, conclusions, or outcomes reached."
|
|
51
|
+
)
|
|
52
|
+
action_items: List[str] = Field(
|
|
53
|
+
description=(
|
|
54
|
+
"A list of specific tasks or actions to be taken, with assignees "
|
|
55
|
+
"if mentioned."
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
progress_on_main_task: str = Field(
|
|
59
|
+
description="A summary of progress made on the primary task."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class MessageSummarizer:
|
|
64
|
+
r"""Utility class for generating structured summaries of chat messages.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
model_backend (Optional[BaseModelBackend], optional):
|
|
68
|
+
The model backend to use for summarization.
|
|
69
|
+
If not provided, a default model backend will be created.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(
|
|
73
|
+
self,
|
|
74
|
+
model_backend: Optional[BaseModelBackend] = None,
|
|
75
|
+
):
|
|
76
|
+
if model_backend is None:
|
|
77
|
+
self.model_backend = ModelFactory.create(
|
|
78
|
+
model_platform=ModelPlatformType.DEFAULT,
|
|
79
|
+
model_type=ModelType.GPT_4O_MINI,
|
|
80
|
+
)
|
|
81
|
+
else:
|
|
82
|
+
self.model_backend = model_backend
|
|
83
|
+
self.agent = ChatAgent(
|
|
84
|
+
BaseMessage.make_assistant_message(
|
|
85
|
+
role_name="Message Summarizer",
|
|
86
|
+
content=(
|
|
87
|
+
"You are an expert conversation summarizer. Your task is "
|
|
88
|
+
"to analyze chat messages and create a structured summary "
|
|
89
|
+
"in JSON format. The summary should capture:\n"
|
|
90
|
+
"- summary: A brief, one-sentence summary of the "
|
|
91
|
+
"conversation.\n"
|
|
92
|
+
"- participants: The roles of participants involved.\n"
|
|
93
|
+
"- key_topics_and_entities: Important topics, concepts, "
|
|
94
|
+
"and entities discussed.\n"
|
|
95
|
+
"- decisions_and_outcomes: Key decisions, conclusions, or "
|
|
96
|
+
"outcomes reached.\n"
|
|
97
|
+
"- action_items: A list of specific tasks or actions to "
|
|
98
|
+
"be taken, with assignees if mentioned.\n"
|
|
99
|
+
"- progress_on_main_task: A summary of progress made on "
|
|
100
|
+
"the primary task.\n\n"
|
|
101
|
+
"Your response must be a JSON object that strictly "
|
|
102
|
+
"adheres to this structure. Be concise and accurate."
|
|
103
|
+
),
|
|
104
|
+
),
|
|
105
|
+
model=self.model_backend,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
def summarize(self, messages: List[BaseMessage]) -> MessageSummary:
|
|
109
|
+
r"""Generate a structured summary of the provided messages.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
messages (List[BaseMessage]): List of messages to summarize.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
MessageSummary: Structured summary of the conversation.
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
ValueError: If the messages list is empty or if the model's
|
|
119
|
+
response cannot be parsed as valid JSON.
|
|
120
|
+
"""
|
|
121
|
+
if not messages:
|
|
122
|
+
raise ValueError("Cannot summarize an empty list of messages.")
|
|
123
|
+
|
|
124
|
+
# Construct prompt from messages
|
|
125
|
+
message_text = "\n".join(
|
|
126
|
+
f"{msg.role_name}: {msg.content}" for msg in messages
|
|
127
|
+
)
|
|
128
|
+
prompt = (
|
|
129
|
+
"Please analyze the following chat messages and generate a "
|
|
130
|
+
"structured summary.\n\n"
|
|
131
|
+
f"MESSAGES:\n\"\"\"\n{message_text}\n\"\"\"\n\n"
|
|
132
|
+
"Your response must be a JSON object that strictly adheres to the "
|
|
133
|
+
"required format."
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Get structured summary from model with forced JSON response
|
|
137
|
+
response = self.agent.step(prompt, response_format=MessageSummary)
|
|
138
|
+
|
|
139
|
+
if response.msg is None or response.msg.parsed is None:
|
|
140
|
+
raise ValueError(
|
|
141
|
+
"Failed to get a structured summary from the model."
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
summary = response.msg.parsed
|
|
145
|
+
if not isinstance(summary, MessageSummary):
|
|
146
|
+
raise ValueError("The parsed response is not a MessageSummary.")
|
|
147
|
+
|
|
148
|
+
return summary
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: camel-ai
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.71a2
|
|
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
|
|
@@ -54,7 +54,6 @@ Requires-Dist: ffmpeg-python<0.3,>=0.2.0; extra == 'all'
|
|
|
54
54
|
Requires-Dist: firecrawl-py<2,>=1.0.0; extra == 'all'
|
|
55
55
|
Requires-Dist: fish-audio-sdk<2025,>=2024.12.5; extra == 'all'
|
|
56
56
|
Requires-Dist: flask>=2.0; extra == 'all'
|
|
57
|
-
Requires-Dist: fpdf>=1.7.2; extra == 'all'
|
|
58
57
|
Requires-Dist: google-api-python-client==2.166.0; extra == 'all'
|
|
59
58
|
Requires-Dist: google-auth-httplib2==0.2.0; extra == 'all'
|
|
60
59
|
Requires-Dist: google-auth-oauthlib==1.2.1; extra == 'all'
|
|
@@ -99,6 +98,7 @@ Requires-Dist: pygithub<3,>=2.6.0; extra == 'all'
|
|
|
99
98
|
Requires-Dist: pylatex>=1.4.2; extra == 'all'
|
|
100
99
|
Requires-Dist: pymilvus<3,>=2.4.0; extra == 'all'
|
|
101
100
|
Requires-Dist: pymupdf<2,>=1.22.5; extra == 'all'
|
|
101
|
+
Requires-Dist: pymupdf>=1.26.1; extra == 'all'
|
|
102
102
|
Requires-Dist: pyobvector>=0.1.18; extra == 'all'
|
|
103
103
|
Requires-Dist: pyowm<4,>=3.3.0; extra == 'all'
|
|
104
104
|
Requires-Dist: pytelegrambotapi<5,>=4.18.0; extra == 'all'
|
|
@@ -206,7 +206,6 @@ Requires-Dist: chunkr-ai>=0.0.50; extra == 'document-tools'
|
|
|
206
206
|
Requires-Dist: crawl4ai>=0.3.745; extra == 'document-tools'
|
|
207
207
|
Requires-Dist: docx2txt<0.9,>=0.8; extra == 'document-tools'
|
|
208
208
|
Requires-Dist: docx>=0.2.4; extra == 'document-tools'
|
|
209
|
-
Requires-Dist: fpdf>=1.7.2; extra == 'document-tools'
|
|
210
209
|
Requires-Dist: markitdown==0.1.1; extra == 'document-tools'
|
|
211
210
|
Requires-Dist: numpy<=2.2,>=1.2; extra == 'document-tools'
|
|
212
211
|
Requires-Dist: openapi-spec-validator<0.8,>=0.7.1; extra == 'document-tools'
|
|
@@ -215,6 +214,7 @@ Requires-Dist: pandasai<3,>=2.3.0; extra == 'document-tools'
|
|
|
215
214
|
Requires-Dist: prance<24,>=23.6.21.0; extra == 'document-tools'
|
|
216
215
|
Requires-Dist: pylatex>=1.4.2; extra == 'document-tools'
|
|
217
216
|
Requires-Dist: pymupdf<2,>=1.22.5; extra == 'document-tools'
|
|
217
|
+
Requires-Dist: pymupdf>=1.26.1; extra == 'document-tools'
|
|
218
218
|
Requires-Dist: python-pptx>=1.0.2; extra == 'document-tools'
|
|
219
219
|
Requires-Dist: tabulate>=0.9.0; extra == 'document-tools'
|
|
220
220
|
Requires-Dist: unstructured==0.16.20; extra == 'document-tools'
|
|
@@ -254,7 +254,6 @@ Requires-Dist: docx>=0.2.4; extra == 'owl'
|
|
|
254
254
|
Requires-Dist: duckduckgo-search<7,>=6.3.5; extra == 'owl'
|
|
255
255
|
Requires-Dist: e2b-code-interpreter<2,>=1.0.3; extra == 'owl'
|
|
256
256
|
Requires-Dist: ffmpeg-python<0.3,>=0.2.0; extra == 'owl'
|
|
257
|
-
Requires-Dist: fpdf>=1.7.2; extra == 'owl'
|
|
258
257
|
Requires-Dist: html2text>=2024.2.26; extra == 'owl'
|
|
259
258
|
Requires-Dist: imageio[pyav]<3,>=2.34.2; extra == 'owl'
|
|
260
259
|
Requires-Dist: markitdown==0.1.1; extra == 'owl'
|
|
@@ -272,6 +271,7 @@ Requires-Dist: pyautogui<0.10,>=0.9.54; extra == 'owl'
|
|
|
272
271
|
Requires-Dist: pydub<0.26,>=0.25.1; extra == 'owl'
|
|
273
272
|
Requires-Dist: pylatex>=1.4.2; extra == 'owl'
|
|
274
273
|
Requires-Dist: pymupdf<2,>=1.22.5; extra == 'owl'
|
|
274
|
+
Requires-Dist: pymupdf>=1.26.1; extra == 'owl'
|
|
275
275
|
Requires-Dist: pytesseract>=0.3.13; extra == 'owl'
|
|
276
276
|
Requires-Dist: python-dotenv<2,>=1.0.0; extra == 'owl'
|
|
277
277
|
Requires-Dist: python-pptx>=1.0.2; extra == 'owl'
|