swarms 7.6.1__py3-none-any.whl → 7.6.4__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 +1 -0
- swarms/agents/__init__.py +4 -5
- swarms/agents/flexion_agent.py +2 -1
- swarms/agents/reasoning_agents.py +10 -0
- swarms/client/__init__.py +15 -0
- swarms/prompts/multi_agent_collab_prompt.py +313 -0
- swarms/structs/__init__.py +10 -17
- swarms/structs/agent.py +178 -262
- swarms/structs/base_swarm.py +0 -7
- swarms/structs/concurrent_workflow.py +2 -2
- swarms/structs/conversation.py +16 -2
- swarms/structs/de_hallucination_swarm.py +8 -4
- swarms/structs/dynamic_conversational_swarm.py +226 -0
- swarms/structs/groupchat.py +80 -84
- swarms/structs/hiearchical_swarm.py +1 -1
- swarms/structs/hybrid_hiearchical_peer_swarm.py +256 -0
- swarms/structs/majority_voting.py +1 -1
- swarms/structs/mixture_of_agents.py +1 -1
- swarms/structs/multi_agent_exec.py +63 -139
- swarms/structs/multi_agent_orchestrator.py +1 -1
- swarms/structs/output_types.py +3 -0
- swarms/structs/rearrange.py +66 -205
- swarms/structs/sequential_workflow.py +34 -47
- swarms/structs/swarm_router.py +3 -2
- swarms/telemetry/bootup.py +19 -38
- swarms/telemetry/main.py +62 -22
- swarms/tools/tool_schema_base_model.py +57 -0
- swarms/utils/auto_download_check_packages.py +2 -2
- swarms/utils/disable_logging.py +0 -17
- swarms/utils/history_output_formatter.py +8 -3
- swarms/utils/litellm_wrapper.py +117 -1
- {swarms-7.6.1.dist-info → swarms-7.6.4.dist-info}/METADATA +1 -5
- {swarms-7.6.1.dist-info → swarms-7.6.4.dist-info}/RECORD +37 -37
- swarms/structs/agent_security.py +0 -318
- swarms/structs/airflow_swarm.py +0 -430
- swarms/structs/output_type.py +0 -18
- swarms/utils/agent_ops_check.py +0 -26
- swarms/utils/pandas_utils.py +0 -92
- /swarms/{structs/swarms_api.py → client/main.py} +0 -0
- {swarms-7.6.1.dist-info → swarms-7.6.4.dist-info}/LICENSE +0 -0
- {swarms-7.6.1.dist-info → swarms-7.6.4.dist-info}/WHEEL +0 -0
- {swarms-7.6.1.dist-info → swarms-7.6.4.dist-info}/entry_points.txt +0 -0
swarms/structs/agent_security.py
DELETED
@@ -1,318 +0,0 @@
|
|
1
|
-
import base64
|
2
|
-
import json
|
3
|
-
import uuid
|
4
|
-
from datetime import datetime
|
5
|
-
from dataclasses import dataclass
|
6
|
-
from typing import Optional, Union, Dict, List
|
7
|
-
|
8
|
-
from cryptography.fernet import Fernet
|
9
|
-
from cryptography.hazmat.primitives import hashes, serialization
|
10
|
-
from cryptography.hazmat.primitives.asymmetric import padding, rsa
|
11
|
-
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
12
|
-
|
13
|
-
|
14
|
-
@dataclass
|
15
|
-
class EncryptedMessage:
|
16
|
-
"""Structure for encrypted messages between agents"""
|
17
|
-
|
18
|
-
sender_id: str
|
19
|
-
receiver_id: str
|
20
|
-
encrypted_content: bytes
|
21
|
-
timestamp: float
|
22
|
-
message_id: str
|
23
|
-
session_id: str
|
24
|
-
|
25
|
-
|
26
|
-
class EncryptionSession:
|
27
|
-
"""Represents an encrypted communication session between agents"""
|
28
|
-
|
29
|
-
def __init__(
|
30
|
-
self,
|
31
|
-
session_id: str,
|
32
|
-
agent_ids: List[str],
|
33
|
-
encrypted_keys: Dict[str, bytes],
|
34
|
-
created_at: datetime,
|
35
|
-
):
|
36
|
-
self.session_id = session_id
|
37
|
-
self.agent_ids = agent_ids
|
38
|
-
self.encrypted_keys = encrypted_keys
|
39
|
-
self.created_at = created_at
|
40
|
-
|
41
|
-
|
42
|
-
class AgentEncryption:
|
43
|
-
"""
|
44
|
-
Handles encryption for agent data both at rest and in transit.
|
45
|
-
Supports both symmetric (for data at rest) and asymmetric (for data in transit) encryption.
|
46
|
-
Also supports secure multi-agent communication.
|
47
|
-
"""
|
48
|
-
|
49
|
-
def __init__(
|
50
|
-
self,
|
51
|
-
agent_id: Optional[str] = None,
|
52
|
-
encryption_key: Optional[str] = None,
|
53
|
-
enable_transit_encryption: bool = False,
|
54
|
-
enable_rest_encryption: bool = False,
|
55
|
-
enable_multi_agent: bool = False,
|
56
|
-
):
|
57
|
-
self.agent_id = agent_id or str(uuid.uuid4())
|
58
|
-
self.enable_transit_encryption = enable_transit_encryption
|
59
|
-
self.enable_rest_encryption = enable_rest_encryption
|
60
|
-
self.enable_multi_agent = enable_multi_agent
|
61
|
-
|
62
|
-
# Multi-agent communication storage
|
63
|
-
self.sessions: Dict[str, EncryptionSession] = {}
|
64
|
-
self.known_agents: Dict[str, "AgentEncryption"] = {}
|
65
|
-
|
66
|
-
if enable_rest_encryption:
|
67
|
-
# Initialize encryption for data at rest
|
68
|
-
if encryption_key:
|
69
|
-
self.encryption_key = base64.urlsafe_b64encode(
|
70
|
-
PBKDF2HMAC(
|
71
|
-
algorithm=hashes.SHA256(),
|
72
|
-
length=32,
|
73
|
-
salt=f"agent_{self.agent_id}".encode(), # Unique salt per agent
|
74
|
-
iterations=100000,
|
75
|
-
).derive(encryption_key.encode())
|
76
|
-
)
|
77
|
-
else:
|
78
|
-
self.encryption_key = Fernet.generate_key()
|
79
|
-
|
80
|
-
self.cipher_suite = Fernet(self.encryption_key)
|
81
|
-
|
82
|
-
if enable_transit_encryption or enable_multi_agent:
|
83
|
-
# Generate RSA key pair for transit encryption
|
84
|
-
self.private_key = rsa.generate_private_key(
|
85
|
-
public_exponent=65537, key_size=2048
|
86
|
-
)
|
87
|
-
self.public_key = self.private_key.public_key()
|
88
|
-
|
89
|
-
def register_agent(
|
90
|
-
self, agent_id: str, agent_encryption: "AgentEncryption"
|
91
|
-
) -> None:
|
92
|
-
"""Register another agent for secure communication"""
|
93
|
-
if not self.enable_multi_agent:
|
94
|
-
raise ValueError("Multi-agent support is not enabled")
|
95
|
-
self.known_agents[agent_id] = agent_encryption
|
96
|
-
|
97
|
-
def create_session(self, agent_ids: List[str]) -> str:
|
98
|
-
"""Create a new encrypted session between multiple agents"""
|
99
|
-
if not self.enable_multi_agent:
|
100
|
-
raise ValueError("Multi-agent support is not enabled")
|
101
|
-
|
102
|
-
session_id = str(uuid.uuid4())
|
103
|
-
|
104
|
-
# Generate a shared session key
|
105
|
-
session_key = Fernet.generate_key()
|
106
|
-
|
107
|
-
# Create encrypted copies of the session key for each agent
|
108
|
-
encrypted_keys = {}
|
109
|
-
for agent_id in agent_ids:
|
110
|
-
if (
|
111
|
-
agent_id not in self.known_agents
|
112
|
-
and agent_id != self.agent_id
|
113
|
-
):
|
114
|
-
raise ValueError(f"Agent {agent_id} not registered")
|
115
|
-
|
116
|
-
if agent_id == self.agent_id:
|
117
|
-
agent_public_key = self.public_key
|
118
|
-
else:
|
119
|
-
agent_public_key = self.known_agents[
|
120
|
-
agent_id
|
121
|
-
].public_key
|
122
|
-
|
123
|
-
encrypted_key = agent_public_key.encrypt(
|
124
|
-
session_key,
|
125
|
-
padding.OAEP(
|
126
|
-
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
127
|
-
algorithm=hashes.SHA256(),
|
128
|
-
label=None,
|
129
|
-
),
|
130
|
-
)
|
131
|
-
encrypted_keys[agent_id] = encrypted_key
|
132
|
-
|
133
|
-
# Store session information
|
134
|
-
self.sessions[session_id] = EncryptionSession(
|
135
|
-
session_id=session_id,
|
136
|
-
agent_ids=agent_ids,
|
137
|
-
encrypted_keys=encrypted_keys,
|
138
|
-
created_at=datetime.now(),
|
139
|
-
)
|
140
|
-
|
141
|
-
return session_id
|
142
|
-
|
143
|
-
def encrypt_message(
|
144
|
-
self,
|
145
|
-
content: Union[str, dict],
|
146
|
-
receiver_id: str,
|
147
|
-
session_id: str,
|
148
|
-
) -> EncryptedMessage:
|
149
|
-
"""Encrypt a message for another agent within a session"""
|
150
|
-
if not self.enable_multi_agent:
|
151
|
-
raise ValueError("Multi-agent support is not enabled")
|
152
|
-
|
153
|
-
if session_id not in self.sessions:
|
154
|
-
raise ValueError("Invalid session ID")
|
155
|
-
|
156
|
-
session = self.sessions[session_id]
|
157
|
-
if (
|
158
|
-
self.agent_id not in session.agent_ids
|
159
|
-
or receiver_id not in session.agent_ids
|
160
|
-
):
|
161
|
-
raise ValueError("Sender or receiver not in session")
|
162
|
-
|
163
|
-
# Serialize content if it's a dictionary
|
164
|
-
if isinstance(content, dict):
|
165
|
-
content = json.dumps(content)
|
166
|
-
|
167
|
-
# Get the session key
|
168
|
-
encrypted_session_key = session.encrypted_keys[self.agent_id]
|
169
|
-
session_key = self.decrypt_session_key(encrypted_session_key)
|
170
|
-
|
171
|
-
# Create Fernet cipher with session key
|
172
|
-
cipher = Fernet(session_key)
|
173
|
-
|
174
|
-
# Encrypt the message
|
175
|
-
encrypted_content = cipher.encrypt(content.encode())
|
176
|
-
|
177
|
-
return EncryptedMessage(
|
178
|
-
sender_id=self.agent_id,
|
179
|
-
receiver_id=receiver_id,
|
180
|
-
encrypted_content=encrypted_content,
|
181
|
-
timestamp=datetime.now().timestamp(),
|
182
|
-
message_id=str(uuid.uuid4()),
|
183
|
-
session_id=session_id,
|
184
|
-
)
|
185
|
-
|
186
|
-
def decrypt_message(
|
187
|
-
self, message: EncryptedMessage
|
188
|
-
) -> Union[str, dict]:
|
189
|
-
"""Decrypt a message from another agent"""
|
190
|
-
if not self.enable_multi_agent:
|
191
|
-
raise ValueError("Multi-agent support is not enabled")
|
192
|
-
|
193
|
-
if message.session_id not in self.sessions:
|
194
|
-
raise ValueError("Invalid session ID")
|
195
|
-
|
196
|
-
if self.agent_id != message.receiver_id:
|
197
|
-
raise ValueError("Message not intended for this agent")
|
198
|
-
|
199
|
-
session = self.sessions[message.session_id]
|
200
|
-
|
201
|
-
# Get the session key
|
202
|
-
encrypted_session_key = session.encrypted_keys[self.agent_id]
|
203
|
-
session_key = self.decrypt_session_key(encrypted_session_key)
|
204
|
-
|
205
|
-
# Create Fernet cipher with session key
|
206
|
-
cipher = Fernet(session_key)
|
207
|
-
|
208
|
-
# Decrypt the message
|
209
|
-
decrypted_content = cipher.decrypt(
|
210
|
-
message.encrypted_content
|
211
|
-
).decode()
|
212
|
-
|
213
|
-
# Try to parse as JSON
|
214
|
-
try:
|
215
|
-
return json.loads(decrypted_content)
|
216
|
-
except json.JSONDecodeError:
|
217
|
-
return decrypted_content
|
218
|
-
|
219
|
-
def decrypt_session_key(self, encrypted_key: bytes) -> bytes:
|
220
|
-
"""Decrypt a session key using the agent's private key"""
|
221
|
-
return self.private_key.decrypt(
|
222
|
-
encrypted_key,
|
223
|
-
padding.OAEP(
|
224
|
-
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
225
|
-
algorithm=hashes.SHA256(),
|
226
|
-
label=None,
|
227
|
-
),
|
228
|
-
)
|
229
|
-
|
230
|
-
# Original methods preserved below
|
231
|
-
def encrypt_at_rest(self, data: Union[str, dict, bytes]) -> bytes:
|
232
|
-
"""Encrypts data for storage"""
|
233
|
-
if not self.enable_rest_encryption:
|
234
|
-
return (
|
235
|
-
data
|
236
|
-
if isinstance(data, bytes)
|
237
|
-
else str(data).encode()
|
238
|
-
)
|
239
|
-
|
240
|
-
if isinstance(data, dict):
|
241
|
-
data = json.dumps(data)
|
242
|
-
if isinstance(data, str):
|
243
|
-
data = data.encode()
|
244
|
-
|
245
|
-
return self.cipher_suite.encrypt(data)
|
246
|
-
|
247
|
-
def decrypt_at_rest(
|
248
|
-
self, encrypted_data: bytes
|
249
|
-
) -> Union[str, dict]:
|
250
|
-
"""Decrypts stored data"""
|
251
|
-
if not self.enable_rest_encryption:
|
252
|
-
return encrypted_data.decode()
|
253
|
-
|
254
|
-
decrypted_data = self.cipher_suite.decrypt(encrypted_data)
|
255
|
-
|
256
|
-
try:
|
257
|
-
return json.loads(decrypted_data)
|
258
|
-
except json.JSONDecodeError:
|
259
|
-
return decrypted_data.decode()
|
260
|
-
|
261
|
-
def encrypt_for_transit(self, data: Union[str, dict]) -> bytes:
|
262
|
-
"""Encrypts data for transmission"""
|
263
|
-
if not self.enable_transit_encryption:
|
264
|
-
return str(data).encode()
|
265
|
-
|
266
|
-
if isinstance(data, dict):
|
267
|
-
data = json.dumps(data)
|
268
|
-
|
269
|
-
return self.public_key.encrypt(
|
270
|
-
data.encode(),
|
271
|
-
padding.OAEP(
|
272
|
-
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
273
|
-
algorithm=hashes.SHA256(),
|
274
|
-
label=None,
|
275
|
-
),
|
276
|
-
)
|
277
|
-
|
278
|
-
def decrypt_from_transit(
|
279
|
-
self, data: Union[bytes, str]
|
280
|
-
) -> Union[str, dict]:
|
281
|
-
"""Decrypts received data, handling both encrypted and unencrypted inputs"""
|
282
|
-
if not self.enable_transit_encryption:
|
283
|
-
return data.decode() if isinstance(data, bytes) else data
|
284
|
-
|
285
|
-
try:
|
286
|
-
if isinstance(data, bytes) and len(data) == 256:
|
287
|
-
decrypted_data = self.private_key.decrypt(
|
288
|
-
data,
|
289
|
-
padding.OAEP(
|
290
|
-
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
291
|
-
algorithm=hashes.SHA256(),
|
292
|
-
label=None,
|
293
|
-
),
|
294
|
-
).decode()
|
295
|
-
else:
|
296
|
-
return (
|
297
|
-
data.decode() if isinstance(data, bytes) else data
|
298
|
-
)
|
299
|
-
|
300
|
-
try:
|
301
|
-
return json.loads(decrypted_data)
|
302
|
-
except json.JSONDecodeError:
|
303
|
-
return decrypted_data
|
304
|
-
except ValueError:
|
305
|
-
return data.decode() if isinstance(data, bytes) else data
|
306
|
-
|
307
|
-
def get_public_key_pem(self) -> bytes:
|
308
|
-
"""Returns the public key in PEM format for sharing"""
|
309
|
-
if (
|
310
|
-
not self.enable_transit_encryption
|
311
|
-
and not self.enable_multi_agent
|
312
|
-
):
|
313
|
-
return b""
|
314
|
-
|
315
|
-
return self.public_key.public_bytes(
|
316
|
-
encoding=serialization.Encoding.PEM,
|
317
|
-
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
318
|
-
)
|