swarms 7.7.7__py3-none-any.whl → 7.7.9__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.
- swarms/__init__.py +0 -1
- swarms/agents/cort_agent.py +206 -0
- swarms/agents/react_agent.py +173 -0
- swarms/communication/base_communication.py +290 -0
- swarms/communication/duckdb_wrap.py +369 -72
- swarms/communication/pulsar_struct.py +691 -0
- swarms/communication/redis_wrap.py +1362 -0
- swarms/communication/sqlite_wrap.py +547 -44
- swarms/prompts/safety_prompt.py +50 -0
- swarms/structs/agent.py +13 -8
- swarms/structs/concurrent_workflow.py +56 -242
- swarms/structs/conversation.py +228 -38
- swarms/structs/council_judge.py +456 -0
- swarms/structs/deep_research_swarm.py +19 -22
- swarms/structs/malt.py +30 -28
- swarms/structs/multi_model_gpu_manager.py +1 -1
- swarms/structs/output_types.py +1 -1
- swarms/structs/swarm_router.py +2 -2
- swarms/tools/mcp_client.py +1 -1
- swarms/tools/py_func_to_openai_func_str.py +2 -2
- swarms/utils/history_output_formatter.py +5 -5
- swarms/utils/try_except_wrapper.py +2 -2
- swarms/utils/xml_utils.py +42 -0
- {swarms-7.7.7.dist-info → swarms-7.7.9.dist-info}/METADATA +4 -3
- {swarms-7.7.7.dist-info → swarms-7.7.9.dist-info}/RECORD +28 -22
- {swarms-7.7.7.dist-info → swarms-7.7.9.dist-info}/WHEEL +1 -1
- swarms/client/__init__.py +0 -15
- swarms/client/main.py +0 -407
- {swarms-7.7.7.dist-info → swarms-7.7.9.dist-info}/LICENSE +0 -0
- {swarms-7.7.7.dist-info → swarms-7.7.9.dist-info}/entry_points.txt +0 -0
swarms/structs/conversation.py
CHANGED
@@ -1,20 +1,39 @@
|
|
1
1
|
import datetime
|
2
|
+
import hashlib
|
2
3
|
import json
|
3
|
-
|
4
|
+
import os
|
4
5
|
import threading
|
5
|
-
import
|
6
|
+
import uuid
|
7
|
+
from typing import (
|
8
|
+
TYPE_CHECKING,
|
9
|
+
Any,
|
10
|
+
Dict,
|
11
|
+
List,
|
12
|
+
Optional,
|
13
|
+
Union,
|
14
|
+
Literal,
|
15
|
+
)
|
6
16
|
|
7
17
|
import yaml
|
18
|
+
|
8
19
|
from swarms.structs.base_structure import BaseStructure
|
9
|
-
from typing import TYPE_CHECKING
|
10
20
|
from swarms.utils.any_to_str import any_to_str
|
11
21
|
from swarms.utils.formatter import formatter
|
12
22
|
from swarms.utils.litellm_tokenizer import count_tokens
|
13
23
|
|
14
24
|
if TYPE_CHECKING:
|
15
|
-
from swarms.structs.agent import
|
16
|
-
|
17
|
-
|
25
|
+
from swarms.structs.agent import Agent
|
26
|
+
|
27
|
+
from loguru import logger
|
28
|
+
|
29
|
+
|
30
|
+
def generate_conversation_id():
|
31
|
+
"""Generate a unique conversation ID."""
|
32
|
+
return str(uuid.uuid4())
|
33
|
+
|
34
|
+
|
35
|
+
# Define available providers
|
36
|
+
providers = Literal["mem0", "in-memory"]
|
18
37
|
|
19
38
|
|
20
39
|
class Conversation(BaseStructure):
|
@@ -41,10 +60,13 @@ class Conversation(BaseStructure):
|
|
41
60
|
cache_enabled (bool): Flag to enable prompt caching.
|
42
61
|
cache_stats (dict): Statistics about cache usage.
|
43
62
|
cache_lock (threading.Lock): Lock for thread-safe cache operations.
|
63
|
+
conversations_dir (str): Directory to store cached conversations.
|
44
64
|
"""
|
45
65
|
|
46
66
|
def __init__(
|
47
67
|
self,
|
68
|
+
id: str = generate_conversation_id(),
|
69
|
+
name: str = None,
|
48
70
|
system_prompt: Optional[str] = None,
|
49
71
|
time_enabled: bool = False,
|
50
72
|
autosave: bool = False,
|
@@ -59,29 +81,16 @@ class Conversation(BaseStructure):
|
|
59
81
|
save_as_json_bool: bool = False,
|
60
82
|
token_count: bool = True,
|
61
83
|
cache_enabled: bool = True,
|
84
|
+
conversations_dir: Optional[str] = None,
|
85
|
+
provider: providers = "in-memory",
|
62
86
|
*args,
|
63
87
|
**kwargs,
|
64
88
|
):
|
65
|
-
"""
|
66
|
-
Initializes the Conversation object with the provided parameters.
|
67
|
-
|
68
|
-
Args:
|
69
|
-
system_prompt (Optional[str]): The system prompt for the conversation.
|
70
|
-
time_enabled (bool): Flag to enable time tracking for messages.
|
71
|
-
autosave (bool): Flag to enable automatic saving of conversation history.
|
72
|
-
save_filepath (str): File path for saving the conversation history.
|
73
|
-
tokenizer (Any): Tokenizer for counting tokens in messages.
|
74
|
-
context_length (int): Maximum number of tokens allowed in the conversation history.
|
75
|
-
rules (str): Rules for the conversation.
|
76
|
-
custom_rules_prompt (str): Custom prompt for rules.
|
77
|
-
user (str): The user identifier for messages.
|
78
|
-
auto_save (bool): Flag to enable auto-saving of conversation history.
|
79
|
-
save_as_yaml (bool): Flag to save conversation history as YAML.
|
80
|
-
save_as_json_bool (bool): Flag to save conversation history as JSON.
|
81
|
-
token_count (bool): Flag to enable token counting for messages.
|
82
|
-
cache_enabled (bool): Flag to enable prompt caching.
|
83
|
-
"""
|
84
89
|
super().__init__()
|
90
|
+
|
91
|
+
# Initialize all attributes first
|
92
|
+
self.id = id
|
93
|
+
self.name = name or id
|
85
94
|
self.system_prompt = system_prompt
|
86
95
|
self.time_enabled = time_enabled
|
87
96
|
self.autosave = autosave
|
@@ -97,6 +106,7 @@ class Conversation(BaseStructure):
|
|
97
106
|
self.save_as_json_bool = save_as_json_bool
|
98
107
|
self.token_count = token_count
|
99
108
|
self.cache_enabled = cache_enabled
|
109
|
+
self.provider = provider
|
100
110
|
self.cache_stats = {
|
101
111
|
"hits": 0,
|
102
112
|
"misses": 0,
|
@@ -104,20 +114,70 @@ class Conversation(BaseStructure):
|
|
104
114
|
"total_tokens": 0,
|
105
115
|
}
|
106
116
|
self.cache_lock = threading.Lock()
|
117
|
+
self.conversations_dir = conversations_dir
|
118
|
+
|
119
|
+
self.setup()
|
120
|
+
|
121
|
+
def setup(self):
|
122
|
+
# Set up conversations directory
|
123
|
+
self.conversations_dir = (
|
124
|
+
self.conversations_dir
|
125
|
+
or os.path.join(
|
126
|
+
os.path.expanduser("~"), ".swarms", "conversations"
|
127
|
+
)
|
128
|
+
)
|
129
|
+
os.makedirs(self.conversations_dir, exist_ok=True)
|
130
|
+
|
131
|
+
# Try to load existing conversation if it exists
|
132
|
+
conversation_file = os.path.join(
|
133
|
+
self.conversations_dir, f"{self.name}.json"
|
134
|
+
)
|
135
|
+
if os.path.exists(conversation_file):
|
136
|
+
with open(conversation_file, "r") as f:
|
137
|
+
saved_data = json.load(f)
|
138
|
+
# Update attributes from saved data
|
139
|
+
for key, value in saved_data.get(
|
140
|
+
"metadata", {}
|
141
|
+
).items():
|
142
|
+
if hasattr(self, key):
|
143
|
+
setattr(self, key, value)
|
144
|
+
self.conversation_history = saved_data.get(
|
145
|
+
"history", []
|
146
|
+
)
|
147
|
+
else:
|
148
|
+
# If system prompt is not None, add it to the conversation history
|
149
|
+
if self.system_prompt is not None:
|
150
|
+
self.add("System", self.system_prompt)
|
107
151
|
|
108
|
-
|
109
|
-
|
110
|
-
self.add("System", self.system_prompt)
|
152
|
+
if self.rules is not None:
|
153
|
+
self.add(self.user or "User", self.rules)
|
111
154
|
|
112
|
-
|
113
|
-
|
155
|
+
if self.custom_rules_prompt is not None:
|
156
|
+
self.add(
|
157
|
+
self.user or "User", self.custom_rules_prompt
|
158
|
+
)
|
114
159
|
|
115
|
-
|
116
|
-
self.
|
160
|
+
# If tokenizer then truncate
|
161
|
+
if self.tokenizer is not None:
|
162
|
+
self.truncate_memory_with_tokenizer()
|
117
163
|
|
118
|
-
|
119
|
-
|
120
|
-
|
164
|
+
def mem0_provider(self):
|
165
|
+
try:
|
166
|
+
from mem0 import AsyncMemory
|
167
|
+
except ImportError:
|
168
|
+
logger.warning(
|
169
|
+
"mem0ai is not installed. Please install it to use the Conversation class."
|
170
|
+
)
|
171
|
+
return None
|
172
|
+
|
173
|
+
try:
|
174
|
+
memory = AsyncMemory()
|
175
|
+
return memory
|
176
|
+
except Exception as e:
|
177
|
+
logger.error(
|
178
|
+
f"Failed to initialize AsyncMemory: {str(e)}"
|
179
|
+
)
|
180
|
+
return None
|
121
181
|
|
122
182
|
def _generate_cache_key(
|
123
183
|
self, content: Union[str, dict, list]
|
@@ -174,7 +234,46 @@ class Conversation(BaseStructure):
|
|
174
234
|
self.cache_stats["cached_tokens"] += token_count
|
175
235
|
self.cache_stats["total_tokens"] += token_count
|
176
236
|
|
177
|
-
def
|
237
|
+
def _save_to_cache(self):
|
238
|
+
"""Save the current conversation state to the cache directory."""
|
239
|
+
if not self.conversations_dir:
|
240
|
+
return
|
241
|
+
|
242
|
+
conversation_file = os.path.join(
|
243
|
+
self.conversations_dir, f"{self.name}.json"
|
244
|
+
)
|
245
|
+
|
246
|
+
# Prepare metadata
|
247
|
+
metadata = {
|
248
|
+
"id": self.id,
|
249
|
+
"name": self.name,
|
250
|
+
"system_prompt": self.system_prompt,
|
251
|
+
"time_enabled": self.time_enabled,
|
252
|
+
"autosave": self.autosave,
|
253
|
+
"save_filepath": self.save_filepath,
|
254
|
+
"context_length": self.context_length,
|
255
|
+
"rules": self.rules,
|
256
|
+
"custom_rules_prompt": self.custom_rules_prompt,
|
257
|
+
"user": self.user,
|
258
|
+
"auto_save": self.auto_save,
|
259
|
+
"save_as_yaml": self.save_as_yaml,
|
260
|
+
"save_as_json_bool": self.save_as_json_bool,
|
261
|
+
"token_count": self.token_count,
|
262
|
+
"cache_enabled": self.cache_enabled,
|
263
|
+
}
|
264
|
+
|
265
|
+
# Prepare data to save
|
266
|
+
save_data = {
|
267
|
+
"metadata": metadata,
|
268
|
+
"history": self.conversation_history,
|
269
|
+
"cache_stats": self.cache_stats,
|
270
|
+
}
|
271
|
+
|
272
|
+
# Save to file
|
273
|
+
with open(conversation_file, "w") as f:
|
274
|
+
json.dump(save_data, f, indent=4)
|
275
|
+
|
276
|
+
def add_in_memory(
|
178
277
|
self,
|
179
278
|
role: str,
|
180
279
|
content: Union[str, dict, list],
|
@@ -210,7 +309,7 @@ class Conversation(BaseStructure):
|
|
210
309
|
else:
|
211
310
|
message["cached"] = False
|
212
311
|
|
213
|
-
# Add
|
312
|
+
# Add message to appropriate backend
|
214
313
|
self.conversation_history.append(message)
|
215
314
|
|
216
315
|
if self.token_count is True and not message.get(
|
@@ -218,6 +317,41 @@ class Conversation(BaseStructure):
|
|
218
317
|
):
|
219
318
|
self._count_tokens(content, message)
|
220
319
|
|
320
|
+
# Save to cache after adding message
|
321
|
+
self._save_to_cache()
|
322
|
+
|
323
|
+
def add_mem0(
|
324
|
+
self,
|
325
|
+
role: str,
|
326
|
+
content: Union[str, dict, list],
|
327
|
+
metadata: Optional[dict] = None,
|
328
|
+
):
|
329
|
+
"""Add a message to the conversation history using the Mem0 provider."""
|
330
|
+
if self.provider == "mem0":
|
331
|
+
memory = self.mem0_provider()
|
332
|
+
memory.add(
|
333
|
+
messages=content,
|
334
|
+
agent_id=role,
|
335
|
+
run_id=self.id,
|
336
|
+
metadata=metadata,
|
337
|
+
)
|
338
|
+
|
339
|
+
def add(
|
340
|
+
self,
|
341
|
+
role: str,
|
342
|
+
content: Union[str, dict, list],
|
343
|
+
metadata: Optional[dict] = None,
|
344
|
+
):
|
345
|
+
"""Add a message to the conversation history."""
|
346
|
+
if self.provider == "in-memory":
|
347
|
+
self.add_in_memory(role, content)
|
348
|
+
elif self.provider == "mem0":
|
349
|
+
self.add_mem0(
|
350
|
+
role=role, content=content, metadata=metadata
|
351
|
+
)
|
352
|
+
else:
|
353
|
+
raise ValueError(f"Invalid provider: {self.provider}")
|
354
|
+
|
221
355
|
def add_multiple_messages(
|
222
356
|
self, roles: List[str], contents: List[Union[str, dict, list]]
|
223
357
|
):
|
@@ -256,6 +390,7 @@ class Conversation(BaseStructure):
|
|
256
390
|
index (str): Index of the message to delete.
|
257
391
|
"""
|
258
392
|
self.conversation_history.pop(index)
|
393
|
+
self._save_to_cache()
|
259
394
|
|
260
395
|
def update(self, index: str, role, content):
|
261
396
|
"""Update a message in the conversation history.
|
@@ -269,6 +404,7 @@ class Conversation(BaseStructure):
|
|
269
404
|
"role": role,
|
270
405
|
"content": content,
|
271
406
|
}
|
407
|
+
self._save_to_cache()
|
272
408
|
|
273
409
|
def query(self, index: str):
|
274
410
|
"""Query a message in the conversation history.
|
@@ -450,6 +586,7 @@ class Conversation(BaseStructure):
|
|
450
586
|
def clear(self):
|
451
587
|
"""Clear the conversation history."""
|
452
588
|
self.conversation_history = []
|
589
|
+
self._save_to_cache()
|
453
590
|
|
454
591
|
def to_json(self):
|
455
592
|
"""Convert the conversation history to a JSON string.
|
@@ -508,7 +645,13 @@ class Conversation(BaseStructure):
|
|
508
645
|
Returns:
|
509
646
|
str: The last message formatted as 'role: content'.
|
510
647
|
"""
|
511
|
-
|
648
|
+
if self.provider == "mem0":
|
649
|
+
memory = self.mem0_provider()
|
650
|
+
return memory.get_all(run_id=self.id)
|
651
|
+
elif self.provider == "in-memory":
|
652
|
+
return f"{self.conversation_history[-1]['role']}: {self.conversation_history[-1]['content']}"
|
653
|
+
else:
|
654
|
+
raise ValueError(f"Invalid provider: {self.provider}")
|
512
655
|
|
513
656
|
def return_messages_as_list(self):
|
514
657
|
"""Return the conversation messages as a list of formatted strings.
|
@@ -629,6 +772,53 @@ class Conversation(BaseStructure):
|
|
629
772
|
),
|
630
773
|
}
|
631
774
|
|
775
|
+
@classmethod
|
776
|
+
def load_conversation(
|
777
|
+
cls, name: str, conversations_dir: Optional[str] = None
|
778
|
+
) -> "Conversation":
|
779
|
+
"""Load a conversation from the cache by name.
|
780
|
+
|
781
|
+
Args:
|
782
|
+
name (str): Name of the conversation to load
|
783
|
+
conversations_dir (Optional[str]): Directory containing cached conversations
|
784
|
+
|
785
|
+
Returns:
|
786
|
+
Conversation: The loaded conversation object
|
787
|
+
"""
|
788
|
+
return cls(name=name, conversations_dir=conversations_dir)
|
789
|
+
|
790
|
+
@classmethod
|
791
|
+
def list_cached_conversations(
|
792
|
+
cls, conversations_dir: Optional[str] = None
|
793
|
+
) -> List[str]:
|
794
|
+
"""List all cached conversations.
|
795
|
+
|
796
|
+
Args:
|
797
|
+
conversations_dir (Optional[str]): Directory containing cached conversations
|
798
|
+
|
799
|
+
Returns:
|
800
|
+
List[str]: List of conversation names (without .json extension)
|
801
|
+
"""
|
802
|
+
if conversations_dir is None:
|
803
|
+
conversations_dir = os.path.join(
|
804
|
+
os.path.expanduser("~"), ".swarms", "conversations"
|
805
|
+
)
|
806
|
+
|
807
|
+
if not os.path.exists(conversations_dir):
|
808
|
+
return []
|
809
|
+
|
810
|
+
conversations = []
|
811
|
+
for file in os.listdir(conversations_dir):
|
812
|
+
if file.endswith(".json"):
|
813
|
+
conversations.append(
|
814
|
+
file[:-5]
|
815
|
+
) # Remove .json extension
|
816
|
+
return conversations
|
817
|
+
|
818
|
+
def clear_memory(self):
|
819
|
+
"""Clear the memory of the conversation."""
|
820
|
+
self.conversation_history = []
|
821
|
+
|
632
822
|
|
633
823
|
# # Example usage
|
634
824
|
# # conversation = Conversation()
|