swarms 7.7.8__py3-none-any.whl → 7.8.0__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.
Files changed (51) hide show
  1. swarms/__init__.py +0 -1
  2. swarms/agents/cort_agent.py +206 -0
  3. swarms/agents/react_agent.py +173 -0
  4. swarms/agents/self_agent_builder.py +40 -0
  5. swarms/communication/base_communication.py +290 -0
  6. swarms/communication/duckdb_wrap.py +369 -72
  7. swarms/communication/pulsar_struct.py +691 -0
  8. swarms/communication/redis_wrap.py +1362 -0
  9. swarms/communication/sqlite_wrap.py +547 -44
  10. swarms/prompts/agent_self_builder_prompt.py +103 -0
  11. swarms/prompts/safety_prompt.py +50 -0
  12. swarms/schemas/__init__.py +6 -1
  13. swarms/schemas/agent_class_schema.py +91 -0
  14. swarms/schemas/agent_mcp_errors.py +18 -0
  15. swarms/schemas/agent_tool_schema.py +13 -0
  16. swarms/schemas/llm_agent_schema.py +92 -0
  17. swarms/schemas/mcp_schemas.py +43 -0
  18. swarms/structs/__init__.py +4 -0
  19. swarms/structs/agent.py +315 -267
  20. swarms/structs/aop.py +3 -1
  21. swarms/structs/batch_agent_execution.py +64 -0
  22. swarms/structs/conversation.py +261 -57
  23. swarms/structs/council_judge.py +542 -0
  24. swarms/structs/deep_research_swarm.py +19 -22
  25. swarms/structs/long_agent.py +424 -0
  26. swarms/structs/ma_utils.py +11 -8
  27. swarms/structs/malt.py +30 -28
  28. swarms/structs/multi_model_gpu_manager.py +1 -1
  29. swarms/structs/output_types.py +1 -1
  30. swarms/structs/swarm_router.py +70 -15
  31. swarms/tools/__init__.py +12 -0
  32. swarms/tools/base_tool.py +2840 -264
  33. swarms/tools/create_agent_tool.py +104 -0
  34. swarms/tools/mcp_client_call.py +504 -0
  35. swarms/tools/py_func_to_openai_func_str.py +45 -7
  36. swarms/tools/pydantic_to_json.py +10 -27
  37. swarms/utils/audio_processing.py +343 -0
  38. swarms/utils/history_output_formatter.py +5 -5
  39. swarms/utils/index.py +226 -0
  40. swarms/utils/litellm_wrapper.py +65 -67
  41. swarms/utils/try_except_wrapper.py +2 -2
  42. swarms/utils/xml_utils.py +42 -0
  43. {swarms-7.7.8.dist-info → swarms-7.8.0.dist-info}/METADATA +5 -4
  44. {swarms-7.7.8.dist-info → swarms-7.8.0.dist-info}/RECORD +47 -30
  45. {swarms-7.7.8.dist-info → swarms-7.8.0.dist-info}/WHEEL +1 -1
  46. swarms/client/__init__.py +0 -15
  47. swarms/client/main.py +0 -407
  48. swarms/tools/mcp_client.py +0 -246
  49. swarms/tools/mcp_integration.py +0 -340
  50. {swarms-7.7.8.dist-info → swarms-7.8.0.dist-info}/LICENSE +0 -0
  51. {swarms-7.7.8.dist-info → swarms-7.8.0.dist-info}/entry_points.txt +0 -0
@@ -1,15 +1,19 @@
1
1
  import sqlite3
2
2
  import json
3
3
  import datetime
4
- from typing import List, Optional, Union, Dict
4
+ from typing import List, Optional, Union, Dict, Any
5
5
  from pathlib import Path
6
6
  import threading
7
7
  from contextlib import contextmanager
8
8
  import logging
9
- from dataclasses import dataclass
10
- from enum import Enum
11
9
  import uuid
12
10
  import yaml
11
+ from swarms.communication.base_communication import (
12
+ BaseCommunication,
13
+ Message,
14
+ MessageType,
15
+ )
16
+ from typing import Callable
13
17
 
14
18
  try:
15
19
  from loguru import logger
@@ -19,32 +23,7 @@ except ImportError:
19
23
  LOGURU_AVAILABLE = False
20
24
 
21
25
 
22
- class MessageType(Enum):
23
- """Enum for different types of messages in the conversation."""
24
-
25
- SYSTEM = "system"
26
- USER = "user"
27
- ASSISTANT = "assistant"
28
- FUNCTION = "function"
29
- TOOL = "tool"
30
-
31
-
32
- @dataclass
33
- class Message:
34
- """Data class representing a message in the conversation."""
35
-
36
- role: str
37
- content: Union[str, dict, list]
38
- timestamp: Optional[str] = None
39
- message_type: Optional[MessageType] = None
40
- metadata: Optional[Dict] = None
41
- token_count: Optional[int] = None
42
-
43
- class Config:
44
- arbitrary_types_allowed = True
45
-
46
-
47
- class SQLiteConversation:
26
+ class SQLiteConversation(BaseCommunication):
48
27
  """
49
28
  A production-grade SQLite wrapper class for managing conversation history.
50
29
  This class provides persistent storage for conversations with various features
@@ -63,7 +42,21 @@ class SQLiteConversation:
63
42
 
64
43
  def __init__(
65
44
  self,
66
- db_path: str = "conversations.db",
45
+ system_prompt: Optional[str] = None,
46
+ time_enabled: bool = False,
47
+ autosave: bool = False,
48
+ save_filepath: str = None,
49
+ tokenizer: Any = None,
50
+ context_length: int = 8192,
51
+ rules: str = None,
52
+ custom_rules_prompt: str = None,
53
+ user: str = "User:",
54
+ auto_save: bool = True,
55
+ save_as_yaml: bool = True,
56
+ save_as_json_bool: bool = False,
57
+ token_count: bool = True,
58
+ cache_enabled: bool = True,
59
+ db_path: Union[str, Path] = None,
67
60
  table_name: str = "conversations",
68
61
  enable_timestamps: bool = True,
69
62
  enable_logging: bool = True,
@@ -72,19 +65,31 @@ class SQLiteConversation:
72
65
  connection_timeout: float = 5.0,
73
66
  **kwargs,
74
67
  ):
75
- """
76
- Initialize the SQLite conversation manager.
68
+ super().__init__(
69
+ system_prompt=system_prompt,
70
+ time_enabled=time_enabled,
71
+ autosave=autosave,
72
+ save_filepath=save_filepath,
73
+ tokenizer=tokenizer,
74
+ context_length=context_length,
75
+ rules=rules,
76
+ custom_rules_prompt=custom_rules_prompt,
77
+ user=user,
78
+ auto_save=auto_save,
79
+ save_as_yaml=save_as_yaml,
80
+ save_as_json_bool=save_as_json_bool,
81
+ token_count=token_count,
82
+ cache_enabled=cache_enabled,
83
+ )
77
84
 
78
- Args:
79
- db_path (str): Path to the SQLite database file
80
- table_name (str): Name of the table to store conversations
81
- enable_timestamps (bool): Whether to track message timestamps
82
- enable_logging (bool): Whether to enable logging
83
- use_loguru (bool): Whether to use loguru for logging
84
- max_retries (int): Maximum number of retries for database operations
85
- connection_timeout (float): Timeout for database connections
86
- """
85
+ # Calculate default db_path if not provided
86
+ if db_path is None:
87
+ db_path = self.get_default_db_path("conversations.sqlite")
87
88
  self.db_path = Path(db_path)
89
+
90
+ # Ensure parent directory exists
91
+ self.db_path.parent.mkdir(parents=True, exist_ok=True)
92
+
88
93
  self.table_name = table_name
89
94
  self.enable_timestamps = enable_timestamps
90
95
  self.enable_logging = enable_logging
@@ -92,9 +97,7 @@ class SQLiteConversation:
92
97
  self.max_retries = max_retries
93
98
  self.connection_timeout = connection_timeout
94
99
  self._lock = threading.Lock()
95
- self.current_conversation_id = (
96
- self._generate_conversation_id()
97
- )
100
+ self.tokenizer = tokenizer
98
101
 
99
102
  # Setup logging
100
103
  if self.enable_logging:
@@ -112,6 +115,7 @@ class SQLiteConversation:
112
115
 
113
116
  # Initialize database
114
117
  self._init_db()
118
+ self.start_new_conversation()
115
119
 
116
120
  def _generate_conversation_id(self) -> str:
117
121
  """Generate a unique conversation ID using UUID and timestamp."""
@@ -811,3 +815,502 @@ class SQLiteConversation:
811
815
  "total_tokens": row["total_tokens"],
812
816
  "roles": self.count_messages_by_role(),
813
817
  }
818
+
819
+ def delete(self, index: str):
820
+ """Delete a message from the conversation history."""
821
+ with self._get_connection() as conn:
822
+ cursor = conn.cursor()
823
+ cursor.execute(
824
+ f"DELETE FROM {self.table_name} WHERE id = ? AND conversation_id = ?",
825
+ (index, self.current_conversation_id),
826
+ )
827
+ conn.commit()
828
+
829
+ def update(
830
+ self, index: str, role: str, content: Union[str, dict]
831
+ ):
832
+ """Update a message in the conversation history."""
833
+ if isinstance(content, (dict, list)):
834
+ content = json.dumps(content)
835
+
836
+ with self._get_connection() as conn:
837
+ cursor = conn.cursor()
838
+ cursor.execute(
839
+ f"""
840
+ UPDATE {self.table_name}
841
+ SET role = ?, content = ?
842
+ WHERE id = ? AND conversation_id = ?
843
+ """,
844
+ (role, content, index, self.current_conversation_id),
845
+ )
846
+ conn.commit()
847
+
848
+ def query(self, index: str) -> Dict:
849
+ """Query a message in the conversation history."""
850
+ with self._get_connection() as conn:
851
+ cursor = conn.cursor()
852
+ cursor.execute(
853
+ f"""
854
+ SELECT * FROM {self.table_name}
855
+ WHERE id = ? AND conversation_id = ?
856
+ """,
857
+ (index, self.current_conversation_id),
858
+ )
859
+ row = cursor.fetchone()
860
+
861
+ if not row:
862
+ return {}
863
+
864
+ content = row["content"]
865
+ try:
866
+ content = json.loads(content)
867
+ except json.JSONDecodeError:
868
+ pass
869
+
870
+ return {
871
+ "role": row["role"],
872
+ "content": content,
873
+ "timestamp": row["timestamp"],
874
+ "message_type": row["message_type"],
875
+ "metadata": (
876
+ json.loads(row["metadata"])
877
+ if row["metadata"]
878
+ else None
879
+ ),
880
+ "token_count": row["token_count"],
881
+ }
882
+
883
+ def search(self, keyword: str) -> List[Dict]:
884
+ """Search for messages containing a keyword."""
885
+ return self.search_messages(keyword)
886
+
887
+ def display_conversation(self, detailed: bool = False):
888
+ """Display the conversation history."""
889
+ print(self.get_str())
890
+
891
+ def export_conversation(self, filename: str):
892
+ """Export the conversation history to a file."""
893
+ self.save_as_json(filename)
894
+
895
+ def import_conversation(self, filename: str):
896
+ """Import a conversation history from a file."""
897
+ self.load_from_json(filename)
898
+
899
+ def return_history_as_string(self) -> str:
900
+ """Return the conversation history as a string."""
901
+ return self.get_str()
902
+
903
+ def clear(self):
904
+ """Clear the conversation history."""
905
+ with self._get_connection() as conn:
906
+ cursor = conn.cursor()
907
+ cursor.execute(
908
+ f"DELETE FROM {self.table_name} WHERE conversation_id = ?",
909
+ (self.current_conversation_id,),
910
+ )
911
+ conn.commit()
912
+
913
+ def get_conversation_timeline_dict(self) -> Dict[str, List[Dict]]:
914
+ """Get the conversation organized by timestamps."""
915
+ with self._get_connection() as conn:
916
+ cursor = conn.cursor()
917
+ cursor.execute(
918
+ f"""
919
+ SELECT
920
+ DATE(timestamp) as date,
921
+ role,
922
+ content,
923
+ timestamp,
924
+ message_type,
925
+ metadata,
926
+ token_count
927
+ FROM {self.table_name}
928
+ WHERE conversation_id = ?
929
+ ORDER BY timestamp ASC
930
+ """,
931
+ (self.current_conversation_id,),
932
+ )
933
+
934
+ timeline_dict = {}
935
+ for row in cursor.fetchall():
936
+ date = row["date"]
937
+ content = row["content"]
938
+ try:
939
+ content = json.loads(content)
940
+ except json.JSONDecodeError:
941
+ pass
942
+
943
+ message = {
944
+ "role": row["role"],
945
+ "content": content,
946
+ "timestamp": row["timestamp"],
947
+ "message_type": row["message_type"],
948
+ "metadata": (
949
+ json.loads(row["metadata"])
950
+ if row["metadata"]
951
+ else None
952
+ ),
953
+ "token_count": row["token_count"],
954
+ }
955
+
956
+ if date not in timeline_dict:
957
+ timeline_dict[date] = []
958
+ timeline_dict[date].append(message)
959
+
960
+ return timeline_dict
961
+
962
+ def truncate_memory_with_tokenizer(self):
963
+ """Truncate the conversation history based on token count."""
964
+ if not self.tokenizer:
965
+ return
966
+
967
+ with self._get_connection() as conn:
968
+ cursor = conn.cursor()
969
+ cursor.execute(
970
+ f"""
971
+ SELECT id, content, token_count
972
+ FROM {self.table_name}
973
+ WHERE conversation_id = ?
974
+ ORDER BY id ASC
975
+ """,
976
+ (self.current_conversation_id,),
977
+ )
978
+
979
+ total_tokens = 0
980
+ ids_to_keep = []
981
+
982
+ for row in cursor.fetchall():
983
+ token_count = row[
984
+ "token_count"
985
+ ] or self.tokenizer.count_tokens(row["content"])
986
+ if total_tokens + token_count <= self.context_length:
987
+ total_tokens += token_count
988
+ ids_to_keep.append(row["id"])
989
+ else:
990
+ break
991
+
992
+ if ids_to_keep:
993
+ ids_str = ",".join(map(str, ids_to_keep))
994
+ cursor.execute(
995
+ f"""
996
+ DELETE FROM {self.table_name}
997
+ WHERE conversation_id = ?
998
+ AND id NOT IN ({ids_str})
999
+ """,
1000
+ (self.current_conversation_id,),
1001
+ )
1002
+ conn.commit()
1003
+
1004
+ def get_conversation_metadata_dict(self) -> Dict:
1005
+ """Get detailed metadata about the conversation."""
1006
+ with self._get_connection() as conn:
1007
+ cursor = conn.cursor()
1008
+ # Get basic statistics
1009
+ stats = self.get_statistics()
1010
+
1011
+ # Get message type distribution
1012
+ cursor.execute(
1013
+ f"""
1014
+ SELECT message_type, COUNT(*) as count
1015
+ FROM {self.table_name}
1016
+ WHERE conversation_id = ?
1017
+ GROUP BY message_type
1018
+ """,
1019
+ (self.current_conversation_id,),
1020
+ )
1021
+ type_dist = cursor.fetchall()
1022
+
1023
+ # Get average tokens per message
1024
+ cursor.execute(
1025
+ f"""
1026
+ SELECT AVG(token_count) as avg_tokens
1027
+ FROM {self.table_name}
1028
+ WHERE conversation_id = ? AND token_count IS NOT NULL
1029
+ """,
1030
+ (self.current_conversation_id,),
1031
+ )
1032
+ avg_tokens = cursor.fetchone()
1033
+
1034
+ # Get message frequency by hour
1035
+ cursor.execute(
1036
+ f"""
1037
+ SELECT
1038
+ strftime('%H', timestamp) as hour,
1039
+ COUNT(*) as count
1040
+ FROM {self.table_name}
1041
+ WHERE conversation_id = ?
1042
+ GROUP BY hour
1043
+ ORDER BY hour
1044
+ """,
1045
+ (self.current_conversation_id,),
1046
+ )
1047
+ hourly_freq = cursor.fetchall()
1048
+
1049
+ return {
1050
+ "conversation_id": self.current_conversation_id,
1051
+ "basic_stats": stats,
1052
+ "message_type_distribution": {
1053
+ row["message_type"]: row["count"]
1054
+ for row in type_dist
1055
+ if row["message_type"]
1056
+ },
1057
+ "average_tokens_per_message": (
1058
+ avg_tokens["avg_tokens"]
1059
+ if avg_tokens["avg_tokens"] is not None
1060
+ else 0
1061
+ ),
1062
+ "hourly_message_frequency": {
1063
+ row["hour"]: row["count"] for row in hourly_freq
1064
+ },
1065
+ "role_distribution": self.count_messages_by_role(),
1066
+ }
1067
+
1068
+ def get_conversation_by_role_dict(self) -> Dict[str, List[Dict]]:
1069
+ """Get the conversation organized by roles."""
1070
+ with self._get_connection() as conn:
1071
+ cursor = conn.cursor()
1072
+ cursor.execute(
1073
+ f"""
1074
+ SELECT role, content, timestamp, message_type, metadata, token_count
1075
+ FROM {self.table_name}
1076
+ WHERE conversation_id = ?
1077
+ ORDER BY id ASC
1078
+ """,
1079
+ (self.current_conversation_id,),
1080
+ )
1081
+
1082
+ role_dict = {}
1083
+ for row in cursor.fetchall():
1084
+ role = row["role"]
1085
+ content = row["content"]
1086
+ try:
1087
+ content = json.loads(content)
1088
+ except json.JSONDecodeError:
1089
+ pass
1090
+
1091
+ message = {
1092
+ "content": content,
1093
+ "timestamp": row["timestamp"],
1094
+ "message_type": row["message_type"],
1095
+ "metadata": (
1096
+ json.loads(row["metadata"])
1097
+ if row["metadata"]
1098
+ else None
1099
+ ),
1100
+ "token_count": row["token_count"],
1101
+ }
1102
+
1103
+ if role not in role_dict:
1104
+ role_dict[role] = []
1105
+ role_dict[role].append(message)
1106
+
1107
+ return role_dict
1108
+
1109
+ def get_conversation_as_dict(self) -> Dict:
1110
+ """Get the entire conversation as a dictionary with messages and metadata."""
1111
+ messages = self.get_messages()
1112
+ stats = self.get_statistics()
1113
+
1114
+ return {
1115
+ "conversation_id": self.current_conversation_id,
1116
+ "messages": messages,
1117
+ "metadata": {
1118
+ "total_messages": stats["total_messages"],
1119
+ "unique_roles": stats["unique_roles"],
1120
+ "total_tokens": stats["total_tokens"],
1121
+ "first_message": stats["first_message"],
1122
+ "last_message": stats["last_message"],
1123
+ "roles": self.count_messages_by_role(),
1124
+ },
1125
+ }
1126
+
1127
+ def get_visible_messages(
1128
+ self, agent: Callable, turn: int
1129
+ ) -> List[Dict]:
1130
+ """
1131
+ Get the visible messages for a given agent and turn.
1132
+
1133
+ Args:
1134
+ agent (Agent): The agent.
1135
+ turn (int): The turn number.
1136
+
1137
+ Returns:
1138
+ List[Dict]: The list of visible messages.
1139
+ """
1140
+ with self._get_connection() as conn:
1141
+ cursor = conn.cursor()
1142
+ cursor.execute(
1143
+ f"""
1144
+ SELECT * FROM {self.table_name}
1145
+ WHERE conversation_id = ?
1146
+ AND json_extract(metadata, '$.turn') < ?
1147
+ ORDER BY id ASC
1148
+ """,
1149
+ (self.current_conversation_id, turn),
1150
+ )
1151
+
1152
+ visible_messages = []
1153
+ for row in cursor.fetchall():
1154
+ metadata = (
1155
+ json.loads(row["metadata"])
1156
+ if row["metadata"]
1157
+ else {}
1158
+ )
1159
+ visible_to = metadata.get("visible_to", "all")
1160
+
1161
+ if visible_to == "all" or (
1162
+ agent and agent.agent_name in visible_to
1163
+ ):
1164
+ content = row["content"]
1165
+ try:
1166
+ content = json.loads(content)
1167
+ except json.JSONDecodeError:
1168
+ pass
1169
+
1170
+ message = {
1171
+ "role": row["role"],
1172
+ "content": content,
1173
+ "visible_to": visible_to,
1174
+ "turn": metadata.get("turn"),
1175
+ }
1176
+ visible_messages.append(message)
1177
+
1178
+ return visible_messages
1179
+
1180
+ def return_messages_as_list(self) -> List[str]:
1181
+ """Return the conversation messages as a list of formatted strings.
1182
+
1183
+ Returns:
1184
+ list: List of messages formatted as 'role: content'.
1185
+ """
1186
+ with self._get_connection() as conn:
1187
+ cursor = conn.cursor()
1188
+ cursor.execute(
1189
+ f"""
1190
+ SELECT role, content FROM {self.table_name}
1191
+ WHERE conversation_id = ?
1192
+ ORDER BY id ASC
1193
+ """,
1194
+ (self.current_conversation_id,),
1195
+ )
1196
+
1197
+ return [
1198
+ f"{row['role']}: {json.loads(row['content']) if isinstance(row['content'], str) and row['content'].startswith('{') else row['content']}"
1199
+ for row in cursor.fetchall()
1200
+ ]
1201
+
1202
+ def return_messages_as_dictionary(self) -> List[Dict]:
1203
+ """Return the conversation messages as a list of dictionaries.
1204
+
1205
+ Returns:
1206
+ list: List of dictionaries containing role and content of each message.
1207
+ """
1208
+ with self._get_connection() as conn:
1209
+ cursor = conn.cursor()
1210
+ cursor.execute(
1211
+ f"""
1212
+ SELECT role, content FROM {self.table_name}
1213
+ WHERE conversation_id = ?
1214
+ ORDER BY id ASC
1215
+ """,
1216
+ (self.current_conversation_id,),
1217
+ )
1218
+
1219
+ messages = []
1220
+ for row in cursor.fetchall():
1221
+ content = row["content"]
1222
+ try:
1223
+ content = json.loads(content)
1224
+ except json.JSONDecodeError:
1225
+ pass
1226
+
1227
+ messages.append(
1228
+ {
1229
+ "role": row["role"],
1230
+ "content": content,
1231
+ }
1232
+ )
1233
+ return messages
1234
+
1235
+ def add_tool_output_to_agent(self, role: str, tool_output: dict):
1236
+ """Add a tool output to the conversation history.
1237
+
1238
+ Args:
1239
+ role (str): The role of the tool.
1240
+ tool_output (dict): The output from the tool to be added.
1241
+ """
1242
+ self.add(role, tool_output, message_type=MessageType.TOOL)
1243
+
1244
+ def get_final_message(self) -> str:
1245
+ """Return the final message from the conversation history.
1246
+
1247
+ Returns:
1248
+ str: The final message formatted as 'role: content'.
1249
+ """
1250
+ last_message = self.get_last_message()
1251
+ if not last_message:
1252
+ return ""
1253
+ return f"{last_message['role']}: {last_message['content']}"
1254
+
1255
+ def get_final_message_content(self) -> Union[str, dict]:
1256
+ """Return the content of the final message from the conversation history.
1257
+
1258
+ Returns:
1259
+ Union[str, dict]: The content of the final message.
1260
+ """
1261
+ last_message = self.get_last_message()
1262
+ if not last_message:
1263
+ return ""
1264
+ return last_message["content"]
1265
+
1266
+ def return_all_except_first(self) -> List[Dict]:
1267
+ """Return all messages except the first one.
1268
+
1269
+ Returns:
1270
+ list: List of messages except the first one.
1271
+ """
1272
+ with self._get_connection() as conn:
1273
+ cursor = conn.cursor()
1274
+ cursor.execute(
1275
+ f"""
1276
+ SELECT role, content, timestamp, message_type, metadata, token_count
1277
+ FROM {self.table_name}
1278
+ WHERE conversation_id = ?
1279
+ ORDER BY id ASC
1280
+ LIMIT -1 OFFSET 2
1281
+ """,
1282
+ (self.current_conversation_id,),
1283
+ )
1284
+
1285
+ messages = []
1286
+ for row in cursor.fetchall():
1287
+ content = row["content"]
1288
+ try:
1289
+ content = json.loads(content)
1290
+ except json.JSONDecodeError:
1291
+ pass
1292
+
1293
+ message = {
1294
+ "role": row["role"],
1295
+ "content": content,
1296
+ }
1297
+ if row["timestamp"]:
1298
+ message["timestamp"] = row["timestamp"]
1299
+ if row["message_type"]:
1300
+ message["message_type"] = row["message_type"]
1301
+ if row["metadata"]:
1302
+ message["metadata"] = json.loads(row["metadata"])
1303
+ if row["token_count"]:
1304
+ message["token_count"] = row["token_count"]
1305
+
1306
+ messages.append(message)
1307
+ return messages
1308
+
1309
+ def return_all_except_first_string(self) -> str:
1310
+ """Return all messages except the first one as a string.
1311
+
1312
+ Returns:
1313
+ str: All messages except the first one as a string.
1314
+ """
1315
+ messages = self.return_all_except_first()
1316
+ return "\n".join(f"{msg['content']}" for msg in messages)