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
swarms/utils/index.py ADDED
@@ -0,0 +1,226 @@
1
+ def exists(val):
2
+ return val is not None
3
+
4
+
5
+ def format_dict_to_string(data: dict, indent_level=0, use_colon=True):
6
+ """
7
+ Recursively formats a dictionary into a multi-line string.
8
+
9
+ Args:
10
+ data (dict): The dictionary to format
11
+ indent_level (int): Current indentation level for nested structures
12
+ use_colon (bool): Whether to use "key: value" or "key value" format
13
+
14
+ Returns:
15
+ str: Formatted string representation of the dictionary
16
+ """
17
+ if not isinstance(data, dict):
18
+ return str(data)
19
+
20
+ lines = []
21
+ indent = " " * indent_level # 2 spaces per indentation level
22
+ separator = ": " if use_colon else " "
23
+
24
+ for key, value in data.items():
25
+ if isinstance(value, dict):
26
+ # Recursive case: nested dictionary
27
+ lines.append(f"{indent}{key}:")
28
+ nested_string = format_dict_to_string(
29
+ value, indent_level + 1, use_colon
30
+ )
31
+ lines.append(nested_string)
32
+ else:
33
+ # Base case: simple key-value pair
34
+ lines.append(f"{indent}{key}{separator}{value}")
35
+
36
+ return "\n".join(lines)
37
+
38
+
39
+ def format_data_structure(
40
+ data: any, indent_level: int = 0, max_depth: int = 10
41
+ ) -> str:
42
+ """
43
+ Fast formatter for any Python data structure into readable new-line format.
44
+
45
+ Args:
46
+ data: Any Python data structure to format
47
+ indent_level (int): Current indentation level for nested structures
48
+ max_depth (int): Maximum depth to prevent infinite recursion
49
+
50
+ Returns:
51
+ str: Formatted string representation with new lines
52
+ """
53
+ if indent_level >= max_depth:
54
+ return f"{' ' * indent_level}... (max depth reached)"
55
+
56
+ indent = " " * indent_level
57
+ data_type = type(data)
58
+
59
+ # Fast type checking using type() instead of isinstance() for speed
60
+ if data_type is dict:
61
+ if not data:
62
+ return f"{indent}{{}} (empty dict)"
63
+
64
+ lines = []
65
+ for key, value in data.items():
66
+ if type(value) in (dict, list, tuple, set):
67
+ lines.append(f"{indent}{key}:")
68
+ lines.append(
69
+ format_data_structure(
70
+ value, indent_level + 1, max_depth
71
+ )
72
+ )
73
+ else:
74
+ lines.append(f"{indent}{key}: {value}")
75
+ return "\n".join(lines)
76
+
77
+ elif data_type is list:
78
+ if not data:
79
+ return f"{indent}[] (empty list)"
80
+
81
+ lines = []
82
+ for i, item in enumerate(data):
83
+ if type(item) in (dict, list, tuple, set):
84
+ lines.append(f"{indent}[{i}]:")
85
+ lines.append(
86
+ format_data_structure(
87
+ item, indent_level + 1, max_depth
88
+ )
89
+ )
90
+ else:
91
+ lines.append(f"{indent}{item}")
92
+ return "\n".join(lines)
93
+
94
+ elif data_type is tuple:
95
+ if not data:
96
+ return f"{indent}() (empty tuple)"
97
+
98
+ lines = []
99
+ for i, item in enumerate(data):
100
+ if type(item) in (dict, list, tuple, set):
101
+ lines.append(f"{indent}({i}):")
102
+ lines.append(
103
+ format_data_structure(
104
+ item, indent_level + 1, max_depth
105
+ )
106
+ )
107
+ else:
108
+ lines.append(f"{indent}{item}")
109
+ return "\n".join(lines)
110
+
111
+ elif data_type is set:
112
+ if not data:
113
+ return f"{indent}set() (empty set)"
114
+
115
+ lines = []
116
+ for item in sorted(
117
+ data, key=str
118
+ ): # Sort for consistent output
119
+ if type(item) in (dict, list, tuple, set):
120
+ lines.append(f"{indent}set item:")
121
+ lines.append(
122
+ format_data_structure(
123
+ item, indent_level + 1, max_depth
124
+ )
125
+ )
126
+ else:
127
+ lines.append(f"{indent}{item}")
128
+ return "\n".join(lines)
129
+
130
+ elif data_type is str:
131
+ # Handle multi-line strings
132
+ if "\n" in data:
133
+ lines = data.split("\n")
134
+ return "\n".join(f"{indent}{line}" for line in lines)
135
+ return f"{indent}{data}"
136
+
137
+ elif data_type in (int, float, bool, type(None)):
138
+ return f"{indent}{data}"
139
+
140
+ else:
141
+ # Handle other types (custom objects, etc.)
142
+ if hasattr(data, "__dict__"):
143
+ # Object with attributes
144
+ lines = [f"{indent}{data_type.__name__} object:"]
145
+ for attr, value in data.__dict__.items():
146
+ if not attr.startswith(
147
+ "_"
148
+ ): # Skip private attributes
149
+ if type(value) in (dict, list, tuple, set):
150
+ lines.append(f"{indent} {attr}:")
151
+ lines.append(
152
+ format_data_structure(
153
+ value, indent_level + 2, max_depth
154
+ )
155
+ )
156
+ else:
157
+ lines.append(f"{indent} {attr}: {value}")
158
+ return "\n".join(lines)
159
+ else:
160
+ # Fallback for other types
161
+ return f"{indent}{data} ({data_type.__name__})"
162
+
163
+
164
+ # test_dict = {
165
+ # "name": "John",
166
+ # "age": 30,
167
+ # "address": {
168
+ # "street": "123 Main St",
169
+ # "city": "Anytown",
170
+ # "state": "CA",
171
+ # "zip": "12345"
172
+ # }
173
+ # }
174
+
175
+ # print(format_dict_to_string(test_dict))
176
+
177
+
178
+ # # Example usage of format_data_structure:
179
+ # if __name__ == "__main__":
180
+ # # Test different data structures
181
+
182
+ # # Dictionary
183
+ # test_dict = {
184
+ # "name": "John",
185
+ # "age": 30,
186
+ # "address": {
187
+ # "street": "123 Main St",
188
+ # "city": "Anytown"
189
+ # }
190
+ # }
191
+ # print("=== Dictionary ===")
192
+ # print(format_data_structure(test_dict))
193
+ # print()
194
+
195
+ # # List
196
+ # test_list = ["apple", "banana", {"nested": "dict"}, [1, 2, 3]]
197
+ # print("=== List ===")
198
+ # print(format_data_structure(test_list))
199
+ # print()
200
+
201
+ # # Tuple
202
+ # test_tuple = ("first", "second", {"key": "value"}, (1, 2))
203
+ # print("=== Tuple ===")
204
+ # print(format_data_structure(test_tuple))
205
+ # print()
206
+
207
+ # # Set
208
+ # test_set = {"apple", "banana", "cherry"}
209
+ # print("=== Set ===")
210
+ # print(format_data_structure(test_set))
211
+ # print()
212
+
213
+ # # Mixed complex structure
214
+ # complex_data = {
215
+ # "users": [
216
+ # {"name": "Alice", "scores": [95, 87, 92]},
217
+ # {"name": "Bob", "scores": [88, 91, 85]}
218
+ # ],
219
+ # "metadata": {
220
+ # "total_users": 2,
221
+ # "categories": ("students", "teachers"),
222
+ # "settings": {"debug": True, "version": "1.0"}
223
+ # }
224
+ # }
225
+ # print("=== Complex Structure ===")
226
+ # print(format_data_structure(complex_data))
@@ -1,3 +1,4 @@
1
+ from typing import Optional
1
2
  import base64
2
3
  import requests
3
4
 
@@ -6,25 +7,13 @@ from typing import List
6
7
 
7
8
  from loguru import logger
8
9
  import litellm
10
+ from pydantic import BaseModel
9
11
 
10
- try:
11
- from litellm import completion, acompletion
12
- except ImportError:
13
- import subprocess
14
- import sys
15
- import litellm
12
+ from litellm import completion, acompletion
16
13
 
17
- print("Installing litellm")
18
-
19
- subprocess.check_call(
20
- [sys.executable, "-m", "pip", "install", "-U", "litellm"]
21
- )
22
- print("litellm installed")
23
-
24
- from litellm import completion
25
-
26
- litellm.set_verbose = True
27
- litellm.ssl_verify = False
14
+ litellm.set_verbose = True
15
+ litellm.ssl_verify = False
16
+ # litellm._turn_on_debug()
28
17
 
29
18
 
30
19
  class LiteLLMException(Exception):
@@ -86,6 +75,9 @@ class LiteLLM:
86
75
  retries: int = 3,
87
76
  verbose: bool = False,
88
77
  caching: bool = False,
78
+ mcp_call: bool = False,
79
+ top_p: float = 1.0,
80
+ functions: List[dict] = None,
89
81
  *args,
90
82
  **kwargs,
91
83
  ):
@@ -110,6 +102,9 @@ class LiteLLM:
110
102
  self.tool_choice = tool_choice
111
103
  self.parallel_tool_calls = parallel_tool_calls
112
104
  self.caching = caching
105
+ self.mcp_call = mcp_call
106
+ self.top_p = top_p
107
+ self.functions = functions
113
108
  self.modalities = []
114
109
  self._cached_messages = {} # Cache for prepared messages
115
110
  self.messages = [] # Initialize messages list
@@ -123,6 +118,23 @@ class LiteLLM:
123
118
  retries # Add retries for better reliability
124
119
  )
125
120
 
121
+ def output_for_tools(self, response: any):
122
+ if self.mcp_call is True:
123
+ out = response.choices[0].message.tool_calls[0].function
124
+ output = {
125
+ "function": {
126
+ "name": out.name,
127
+ "arguments": out.arguments,
128
+ }
129
+ }
130
+ return output
131
+ else:
132
+ out = response.choices[0].message.tool_calls
133
+
134
+ if isinstance(out, BaseModel):
135
+ out = out.model_dump()
136
+ return out
137
+
126
138
  def _prepare_messages(self, task: str) -> list:
127
139
  """
128
140
  Prepare the messages for the given task.
@@ -222,8 +234,8 @@ class LiteLLM:
222
234
  def run(
223
235
  self,
224
236
  task: str,
225
- audio: str = None,
226
- img: str = None,
237
+ audio: Optional[str] = None,
238
+ img: Optional[str] = None,
227
239
  *args,
228
240
  **kwargs,
229
241
  ):
@@ -250,38 +262,28 @@ class LiteLLM:
250
262
  self.handle_modalities(
251
263
  task=task, audio=audio, img=img
252
264
  )
253
- messages = (
254
- self.messages
255
- ) # Use modality-processed messages
256
-
257
- if (
258
- self.model_name == "openai/o4-mini"
259
- or self.model_name == "openai/o3-2025-04-16"
260
- ):
261
- # Prepare common completion parameters
262
- completion_params = {
263
- "model": self.model_name,
264
- "messages": messages,
265
- "stream": self.stream,
266
- # "temperature": self.temperature,
267
- "max_completion_tokens": self.max_tokens,
268
- "caching": self.caching,
269
- **kwargs,
270
- }
265
+ messages = self.messages
271
266
 
272
- else:
273
- # Prepare common completion parameters
274
- completion_params = {
275
- "model": self.model_name,
276
- "messages": messages,
277
- "stream": self.stream,
278
- "temperature": self.temperature,
279
- "max_tokens": self.max_tokens,
280
- "caching": self.caching,
281
- **kwargs,
282
- }
267
+ # Base completion parameters
268
+ completion_params = {
269
+ "model": self.model_name,
270
+ "messages": messages,
271
+ "stream": self.stream,
272
+ "max_tokens": self.max_tokens,
273
+ "caching": self.caching,
274
+ "temperature": self.temperature,
275
+ "top_p": self.top_p,
276
+ **kwargs,
277
+ }
283
278
 
284
- # Handle tool-based completion
279
+ # Add temperature for non-o4/o3 models
280
+ if self.model_name not in [
281
+ "openai/o4-mini",
282
+ "openai/o3-2025-04-16",
283
+ ]:
284
+ completion_params["temperature"] = self.temperature
285
+
286
+ # Add tools if specified
285
287
  if self.tools_list_dictionary is not None:
286
288
  completion_params.update(
287
289
  {
@@ -290,28 +292,24 @@ class LiteLLM:
290
292
  "parallel_tool_calls": self.parallel_tool_calls,
291
293
  }
292
294
  )
293
- response = completion(**completion_params)
294
- return (
295
- response.choices[0]
296
- .message.tool_calls[0]
297
- .function.arguments
298
- )
299
295
 
300
- # Handle modality-based completion
301
- if (
302
- self.modalities and len(self.modalities) > 1
303
- ): # More than just text
296
+ if self.functions is not None:
304
297
  completion_params.update(
305
- {"modalities": self.modalities}
298
+ {"functions": self.functions}
306
299
  )
307
- response = completion(**completion_params)
308
- return response.choices[0].message.content
309
300
 
310
- # Standard completion
311
- if self.stream:
312
- return completion(**completion_params)
301
+ # Add modalities if needed
302
+ if self.modalities and len(self.modalities) >= 2:
303
+ completion_params["modalities"] = self.modalities
304
+
305
+ # Make the completion call
306
+ response = completion(**completion_params)
307
+
308
+ # Handle tool-based response
309
+ if self.tools_list_dictionary is not None:
310
+ return self.output_for_tools(response)
313
311
  else:
314
- response = completion(**completion_params)
312
+ # Return standard response content
315
313
  return response.choices[0].message.content
316
314
 
317
315
  except LiteLLMException as error:
@@ -322,7 +320,7 @@ class LiteLLM:
322
320
  )
323
321
  import time
324
322
 
325
- time.sleep(2) # Add a small delay before retry
323
+ time.sleep(2)
326
324
  return self.run(task, audio, img, *args, **kwargs)
327
325
  raise error
328
326
 
@@ -21,7 +21,7 @@ def retry(
21
21
  """
22
22
 
23
23
  def decorator_retry(
24
- func: Callable[..., Any]
24
+ func: Callable[..., Any],
25
25
  ) -> Callable[..., Any]:
26
26
  @wraps(func)
27
27
  def wrapper_retry(*args, **kwargs) -> Any:
@@ -48,7 +48,7 @@ def retry(
48
48
 
49
49
 
50
50
  def log_execution_time(
51
- func: Callable[..., Any]
51
+ func: Callable[..., Any],
52
52
  ) -> Callable[..., Any]:
53
53
  """
54
54
  A decorator that logs the execution time of a function.
@@ -0,0 +1,42 @@
1
+ import xml.etree.ElementTree as ET
2
+ from typing import Any
3
+
4
+
5
+ def dict_to_xml(tag: str, d: dict) -> ET.Element:
6
+ """Convert a dictionary to an XML Element."""
7
+ elem = ET.Element(tag)
8
+ for key, val in d.items():
9
+ child = ET.Element(str(key))
10
+ if isinstance(val, dict):
11
+ child.append(dict_to_xml(str(key), val))
12
+ elif isinstance(val, list):
13
+ for item in val:
14
+ if isinstance(item, dict):
15
+ child.append(dict_to_xml(str(key), item))
16
+ else:
17
+ item_elem = ET.Element("item")
18
+ item_elem.text = str(item)
19
+ child.append(item_elem)
20
+ else:
21
+ child.text = str(val)
22
+ elem.append(child)
23
+ return elem
24
+
25
+
26
+ def to_xml_string(data: Any, root_tag: str = "root") -> str:
27
+ """Convert a dict or list to an XML string."""
28
+ if isinstance(data, dict):
29
+ elem = dict_to_xml(root_tag, data)
30
+ elif isinstance(data, list):
31
+ elem = ET.Element(root_tag)
32
+ for item in data:
33
+ if isinstance(item, dict):
34
+ elem.append(dict_to_xml("item", item))
35
+ else:
36
+ item_elem = ET.Element("item")
37
+ item_elem.text = str(item)
38
+ elem.append(item_elem)
39
+ else:
40
+ elem = ET.Element(root_tag)
41
+ elem.text = str(data)
42
+ return ET.tostring(elem, encoding="unicode")
@@ -1,8 +1,7 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: swarms
3
- Version: 7.7.8
3
+ Version: 7.8.0
4
4
  Summary: Swarms - TGSC
5
- Home-page: https://github.com/kyegomez/swarms
6
5
  License: MIT
7
6
  Keywords: artificial intelligence,deep learning,optimizers,Prompt Engineering,swarms,agents,llms,transformers,multi-agent,swarms of agents,Enterprise-Grade Agents,Production-Grade Agents,Agents,Multi-Grade-Agents,Swarms,Transformers,LLMs,Prompt Engineering,Agents,Generative Agents,Generative AI,Agent Marketplace,Agent Store,quant,finance,algorithmic trading,portfolio optimization,risk management,financial modeling,machine learning for finance,natural language processing for finance
8
7
  Author: Kye Gomez
@@ -15,19 +14,20 @@ Classifier: Programming Language :: Python :: 3
15
14
  Classifier: Programming Language :: Python :: 3.10
16
15
  Classifier: Programming Language :: Python :: 3.11
17
16
  Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
18
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
19
  Requires-Dist: PyYAML
20
20
  Requires-Dist: aiofiles
21
21
  Requires-Dist: aiohttp
22
22
  Requires-Dist: asyncio (>=3.4.3,<4.0)
23
23
  Requires-Dist: docstring_parser (==0.16)
24
- Requires-Dist: fastmcp
25
24
  Requires-Dist: httpx
26
25
  Requires-Dist: litellm
27
26
  Requires-Dist: loguru
28
27
  Requires-Dist: mcp
29
28
  Requires-Dist: networkx
30
29
  Requires-Dist: numpy
30
+ Requires-Dist: numpydoc
31
31
  Requires-Dist: psutil
32
32
  Requires-Dist: pydantic
33
33
  Requires-Dist: pypdf (==5.1.0)
@@ -38,6 +38,7 @@ Requires-Dist: tenacity
38
38
  Requires-Dist: toml
39
39
  Requires-Dist: torch
40
40
  Project-URL: Documentation, https://docs.swarms.world
41
+ Project-URL: Homepage, https://github.com/kyegomez/swarms
41
42
  Project-URL: Repository, https://github.com/kyegomez/swarms
42
43
  Description-Content-Type: text/markdown
43
44