swarms 7.6.0__py3-none-any.whl → 7.6.2__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.
@@ -0,0 +1,226 @@
1
+ import json
2
+ import random
3
+ from swarms.structs.agent import Agent
4
+ from typing import List
5
+ from swarms.structs.conversation import Conversation
6
+ from swarms.utils.history_output_formatter import (
7
+ history_output_formatter,
8
+ )
9
+ from swarms.utils.any_to_str import any_to_str
10
+
11
+ tools = [
12
+ {
13
+ "type": "function",
14
+ "function": {
15
+ "name": "select_agent",
16
+ "description": "Analyzes the input task and selects the most appropriate agent configuration, outputting both the agent name and the formatted response.",
17
+ "parameters": {
18
+ "type": "object",
19
+ "properties": {
20
+ "respond_or_no_respond": {
21
+ "type": "boolean",
22
+ "description": "Whether the agent should respond to the response or not.",
23
+ },
24
+ "reasoning": {
25
+ "type": "string",
26
+ "description": "The reasoning behind the selection of the agent and response.",
27
+ },
28
+ "agent_name": {
29
+ "type": "string",
30
+ "description": "The name of the selected agent that is most appropriate for handling the given task.",
31
+ },
32
+ "response": {
33
+ "type": "string",
34
+ "description": "A clear and structured description of the response for the next agent.",
35
+ },
36
+ },
37
+ "required": [
38
+ "reasoning",
39
+ "agent_name",
40
+ "response",
41
+ "respond_or_no_respond",
42
+ ],
43
+ },
44
+ },
45
+ },
46
+ ]
47
+
48
+
49
+ class DynamicConversationalSwarm:
50
+ def __init__(
51
+ self,
52
+ name: str = "Dynamic Conversational Swarm",
53
+ description: str = "A swarm that uses a dynamic conversational model to solve complex tasks.",
54
+ agents: List[Agent] = [],
55
+ max_loops: int = 1,
56
+ output_type: str = "list",
57
+ *args,
58
+ **kwargs,
59
+ ):
60
+ self.name = name
61
+ self.description = description
62
+ self.agents = agents
63
+ self.max_loops = max_loops
64
+ self.output_type = output_type
65
+
66
+ self.conversation = Conversation()
67
+
68
+ # Agents in the chat
69
+ agents_in_chat = self.get_agents_info()
70
+ self.conversation.add(
71
+ role="Conversation Log", content=agents_in_chat
72
+ )
73
+
74
+ self.inject_tools()
75
+
76
+ # Inject tools into the agents
77
+ def inject_tools(self):
78
+ for agent in self.agents:
79
+ agent.tools_list_dictionary = tools
80
+
81
+ def parse_json_into_dict(self, json_str: str) -> dict:
82
+ try:
83
+ return json.loads(json_str)
84
+ except json.JSONDecodeError:
85
+ raise ValueError("Invalid JSON string")
86
+
87
+ def find_agent_by_name(self, agent_name: str) -> Agent:
88
+ for agent in self.agents:
89
+ if agent.name == agent_name:
90
+ return agent
91
+ raise ValueError(f"Agent with name {agent_name} not found")
92
+
93
+ def run_agent(self, agent_name: str, task: str) -> str:
94
+ agent = self.find_agent_by_name(agent_name)
95
+ return agent.run(task)
96
+
97
+ def fetch_random_agent_name(self) -> str:
98
+ return random.choice(self.agents).agent_name
99
+
100
+ def run(self, task: str) -> str:
101
+ """
102
+ Run the dynamic conversational swarm for a specified number of loops.
103
+ Each agent has access to the full conversation history.
104
+
105
+ Args:
106
+ task (str): The initial task/prompt to process
107
+
108
+ Returns:
109
+ str: The final response after all loops are complete
110
+ """
111
+ self.conversation.add(
112
+ role=f"{self.fetch_random_agent_name()}", content=task
113
+ )
114
+
115
+ # for loop in range(self.max_loops):
116
+ # # Add loop marker to conversation for clarity
117
+ # self.conversation.add(
118
+ # role="System",
119
+ # content=f"=== Starting Loop {loop + 1}/{self.max_loops} ==="
120
+ # )
121
+
122
+ # # First agent interaction
123
+ # current_agent = self.randomly_select_agent()
124
+ # response = self.run_agent(current_agent.name, self.conversation.get_str())
125
+ # self.conversation.add(role=current_agent.name, content=any_to_str(response))
126
+
127
+ # try:
128
+ # # Parse response and get next agent
129
+ # response_dict = self.parse_json_into_dict(response)
130
+
131
+ # # Check if we should continue or end the loop
132
+ # if not response_dict.get("respond_or_no_respond", True):
133
+ # break
134
+
135
+ # # Get the task description for the next agent
136
+ # next_task = response_dict.get("task_description", self.conversation.get_str())
137
+
138
+ # # Run the next agent with the specific task description
139
+ # next_agent = self.find_agent_by_name(response_dict["agent_name"])
140
+ # next_response = self.run_agent(next_agent.name, next_task)
141
+
142
+ # # Add both the task description and response to the conversation
143
+ # self.conversation.add(
144
+ # role="System",
145
+ # content=f"Response from {response_dict['agent_name']}: {next_task}"
146
+ # )
147
+ # self.conversation.add(role=next_agent.name, content=any_to_str(next_response))
148
+
149
+ # except (ValueError, KeyError) as e:
150
+ # self.conversation.add(
151
+ # role="System",
152
+ # content=f"Error in loop {loop + 1}: {str(e)}"
153
+ # )
154
+ # break
155
+
156
+ # Run first agent
157
+ current_agent = self.randomly_select_agent()
158
+ response = self.run_agent(
159
+ current_agent.agent_name, self.conversation.get_str()
160
+ )
161
+ self.conversation.add(
162
+ role=current_agent.agent_name,
163
+ content=any_to_str(response),
164
+ )
165
+
166
+ # Convert to json
167
+ response_dict = self.parse_json_into_dict(response)
168
+
169
+ # Fetch task
170
+ respone_two = response_dict["response"]
171
+ agent_name = response_dict["agent_name"]
172
+
173
+ print(f"Response from {agent_name}: {respone_two}")
174
+
175
+ # Run next agent
176
+ next_response = self.run_agent(
177
+ agent_name, self.conversation.get_str()
178
+ )
179
+ self.conversation.add(
180
+ role=agent_name, content=any_to_str(next_response)
181
+ )
182
+
183
+ # # Get the next agent
184
+ # response_three = self.parse_json_into_dict(next_response)
185
+ # agent_name_three = response_three["agent_name"]
186
+ # respone_four = response_three["response"]
187
+
188
+ # print(f"Response from {agent_name_three}: {respone_four}")
189
+ # # Run the next agent
190
+ # next_response = self.run_agent(agent_name_three, self.conversation.get_str())
191
+ # self.conversation.add(role=agent_name_three, content=any_to_str(next_response))
192
+
193
+ # Format and return the final conversation history
194
+ return history_output_formatter(
195
+ self.conversation, type=self.output_type
196
+ )
197
+
198
+ def randomly_select_agent(self) -> Agent:
199
+ return random.choice(self.agents)
200
+
201
+ def get_agents_info(self) -> str:
202
+ """
203
+ Fetches and formats information about all available agents in the system.
204
+
205
+ Returns:
206
+ str: A formatted string containing names and descriptions of all agents.
207
+ """
208
+ if not self.agents:
209
+ return "No agents currently available in the system."
210
+
211
+ agents_info = [
212
+ "Agents In the System:",
213
+ "",
214
+ ] # Empty string for line spacing
215
+
216
+ for idx, agent in enumerate(self.agents, 1):
217
+ agents_info.extend(
218
+ [
219
+ f"[Agent {idx}]",
220
+ f"Name: {agent.name}",
221
+ f"Description: {agent.description}",
222
+ "", # Empty string for line spacing between agents
223
+ ]
224
+ )
225
+
226
+ return "\n".join(agents_info).strip()
@@ -8,7 +8,7 @@ from pydantic import BaseModel, Field
8
8
  from swarms.structs.agent import Agent
9
9
  from swarms.structs.base_swarm import BaseSwarm
10
10
  from swarms.structs.conversation import Conversation
11
- from swarms.structs.output_type import OutputType
11
+ from swarms.structs.output_types import OutputType
12
12
  from swarms.utils.formatter import formatter
13
13
 
14
14
  from swarms.utils.function_caller_model import OpenAIFunctionCaller
@@ -0,0 +1,273 @@
1
+ import os
2
+ from typing import List
3
+ from swarms.structs.agent import Agent
4
+ from swarms.structs.conversation import Conversation
5
+ from swarms.structs.swarm_router import SwarmRouter
6
+ from swarms.utils.history_output_formatter import (
7
+ history_output_formatter,
8
+ )
9
+ from concurrent.futures import ThreadPoolExecutor, as_completed
10
+ from typing import Union, Callable
11
+
12
+ tools = [
13
+ {
14
+ "type": "function",
15
+ "function": {
16
+ "name": "select_swarm",
17
+ "description": "Analyzes the input task and selects the most appropriate swarm configuration, outputting both the swarm name and the formatted task.",
18
+ "parameters": {
19
+ "type": "object",
20
+ "properties": {
21
+ "reasoning": {
22
+ "type": "string",
23
+ "description": "The reasoning behind the selection of the swarm and task description.",
24
+ },
25
+ "swarm_name": {
26
+ "type": "string",
27
+ "description": "The name of the selected swarm that is most appropriate for handling the given task.",
28
+ },
29
+ "task_description": {
30
+ "type": "string",
31
+ "description": "A clear and structured description of the task to be performed by the swarm.",
32
+ },
33
+ },
34
+ "required": [
35
+ "reasoning",
36
+ "swarm_name",
37
+ "task_description",
38
+ ],
39
+ },
40
+ },
41
+ },
42
+ ]
43
+
44
+ router_system_prompt = """
45
+ You are an intelligent Router Agent responsible for analyzing tasks and directing them to the most appropriate swarm in our system. Your role is critical in ensuring optimal task execution and resource utilization.
46
+
47
+ Key Responsibilities:
48
+ 1. Task Analysis:
49
+ - Carefully analyze the input task's requirements, complexity, and domain
50
+ - Identify key components and dependencies
51
+ - Determine the specialized skills needed for completion
52
+
53
+ 2. Swarm Selection Criteria:
54
+ - Match task requirements with swarm capabilities
55
+ - Consider swarm specializations and past performance
56
+ - Evaluate computational resources needed
57
+ - Account for task priority and time constraints
58
+
59
+ 3. Decision Making Framework:
60
+ - Use a systematic approach to evaluate all available swarms
61
+ - Consider load balancing across the system
62
+ - Factor in swarm availability and current workload
63
+ - Assess potential risks and failure points
64
+
65
+ 4. Output Requirements:
66
+ - Provide clear justification for swarm selection
67
+ - Structure the task description in a way that maximizes swarm efficiency
68
+ - Include any relevant context or constraints
69
+ - Ensure all critical information is preserved
70
+
71
+ Best Practices:
72
+ - Always prefer specialized swarms for domain-specific tasks
73
+ - Consider breaking complex tasks into subtasks when appropriate
74
+ - Maintain consistency in task formatting across different swarms
75
+ - Include error handling considerations in task descriptions
76
+
77
+ Your output must strictly follow the required format:
78
+ {
79
+ "swarm_name": "Name of the selected swarm",
80
+ "task_description": "Detailed and structured task description"
81
+ }
82
+
83
+ Remember: Your selection directly impacts the overall system performance and task completion success rate. Take all factors into account before making your final decision.
84
+ """
85
+
86
+
87
+ class HybridHierarchicalClusterSwarm:
88
+ """
89
+ A class representing a Hybrid Hierarchical-Cluster Swarm that routes tasks to appropriate swarms.
90
+
91
+ Attributes:
92
+ name (str): The name of the swarm.
93
+ description (str): A description of the swarm's functionality.
94
+ swarms (List[SwarmRouter]): A list of available swarm routers.
95
+ max_loops (int): The maximum number of loops for task processing.
96
+ output_type (str): The format of the output (e.g., list).
97
+ conversation (Conversation): An instance of the Conversation class to manage interactions.
98
+ router_agent (Agent): An instance of the Agent class responsible for routing tasks.
99
+ """
100
+
101
+ def __init__(
102
+ self,
103
+ name: str = "Hybrid Hierarchical-Cluster Swarm",
104
+ description: str = "A swarm that uses a hybrid hierarchical-peer model to solve complex tasks.",
105
+ swarms: List[Union[SwarmRouter, Callable]] = [],
106
+ max_loops: int = 1,
107
+ output_type: str = "list",
108
+ router_agent_model_name: str = "gpt-4o-mini",
109
+ *args,
110
+ **kwargs,
111
+ ):
112
+ self.name = name
113
+ self.description = description
114
+ self.swarms = swarms
115
+ self.max_loops = max_loops
116
+ self.output_type = output_type
117
+
118
+ self.conversation = Conversation()
119
+
120
+ self.router_agent = Agent(
121
+ agent_name="Router Agent",
122
+ agent_description="A router agent that routes tasks to the appropriate swarms.",
123
+ system_prompt=f"{router_system_prompt}\n\n{self.get_swarms_info()}",
124
+ tools_list_dictionary=tools,
125
+ model_name=router_agent_model_name,
126
+ max_loops=1,
127
+ )
128
+
129
+ def run(self, task: str, *args, **kwargs):
130
+ """
131
+ Runs the routing process for a given task.
132
+
133
+ Args:
134
+ task (str): The task to be processed by the swarm.
135
+
136
+ Returns:
137
+ str: The formatted history output of the conversation.
138
+
139
+ Raises:
140
+ ValueError: If the task is empty or invalid.
141
+ """
142
+ if not task:
143
+ raise ValueError("Task cannot be empty.")
144
+
145
+ self.conversation.add(role="User", content=task)
146
+
147
+ response = self.router_agent.run(task=task)
148
+
149
+ # Handle response whether it's a string or dictionary
150
+ if isinstance(response, str):
151
+ try:
152
+ import json
153
+
154
+ response = json.loads(response)
155
+ except json.JSONDecodeError:
156
+ raise ValueError(
157
+ "Invalid JSON response from router agent"
158
+ )
159
+
160
+ swarm_name = response.get("swarm_name")
161
+ task_description = response.get("task_description")
162
+
163
+ if not swarm_name or not task_description:
164
+ raise ValueError(
165
+ "Invalid response from router agent: missing swarm_name or task_description."
166
+ )
167
+
168
+ self.route_task(swarm_name, task_description)
169
+
170
+ return history_output_formatter(
171
+ self.conversation, self.output_type
172
+ )
173
+
174
+ def find_swarm_by_name(self, swarm_name: str):
175
+ """
176
+ Finds a swarm by its name.
177
+
178
+ Args:
179
+ swarm_name (str): The name of the swarm to find.
180
+
181
+ Returns:
182
+ SwarmRouter: The found swarm router, or None if not found.
183
+ """
184
+ for swarm in self.swarms:
185
+ if swarm.name == swarm_name:
186
+ return swarm
187
+ return None
188
+
189
+ def route_task(self, swarm_name: str, task_description: str):
190
+ """
191
+ Routes the task to the specified swarm.
192
+
193
+ Args:
194
+ swarm_name (str): The name of the swarm to route the task to.
195
+ task_description (str): The description of the task to be executed.
196
+
197
+ Raises:
198
+ ValueError: If the swarm is not found.
199
+ """
200
+ swarm = self.find_swarm_by_name(swarm_name)
201
+
202
+ if swarm:
203
+ output = swarm.run(task_description)
204
+ self.conversation.add(role=swarm.name, content=output)
205
+ else:
206
+ raise ValueError(f"Swarm '{swarm_name}' not found.")
207
+
208
+ def batched_run(self, tasks: List[str]):
209
+ """
210
+ Runs the routing process for a list of tasks in batches.
211
+
212
+ Args:
213
+ tasks (List[str]): A list of tasks to be processed by the swarm.
214
+
215
+ Returns:
216
+ List[str]: A list of formatted history outputs for each batch.
217
+
218
+ Raises:
219
+ ValueError: If the task list is empty or invalid.
220
+ """
221
+ if not tasks:
222
+ raise ValueError("Task list cannot be empty.")
223
+
224
+ max_workers = os.cpu_count() * 2
225
+
226
+ results = []
227
+
228
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
229
+ # Submit all tasks to the executor
230
+ future_to_task = {
231
+ executor.submit(self.run, task): task
232
+ for task in tasks
233
+ }
234
+
235
+ # Collect results as they complete
236
+ for future in as_completed(future_to_task):
237
+ try:
238
+ result = future.result()
239
+ results.append(result)
240
+ except Exception as e:
241
+ # Handle any errors that occurred during task execution
242
+ results.append(f"Error processing task: {str(e)}")
243
+
244
+ return results
245
+
246
+ def get_swarms_info(self) -> str:
247
+ """
248
+ Fetches and formats information about all available swarms in the system.
249
+
250
+ Returns:
251
+ str: A formatted string containing names and descriptions of all swarms.
252
+ """
253
+ if not self.swarms:
254
+ return "No swarms currently available in the system."
255
+
256
+ swarm_info = [
257
+ "Available Swarms:",
258
+ "",
259
+ ] # Empty string for line spacing
260
+
261
+ for idx, swarm in enumerate(self.swarms, 1):
262
+ swarm_info.extend(
263
+ [
264
+ f"[Swarm {idx}]",
265
+ f"Name: {swarm.name}",
266
+ f"Description: {swarm.description}",
267
+ f"Length of Agents: {len(swarm.agents)}",
268
+ f"Swarm Type: {swarm.swarm_type}",
269
+ "", # Empty string for line spacing between swarms
270
+ ]
271
+ )
272
+
273
+ return "\n".join(swarm_info).strip()
@@ -9,7 +9,7 @@ from typing import Any, Callable, List, Optional
9
9
  from swarms.structs.agent import Agent
10
10
  from swarms.structs.conversation import Conversation
11
11
  from swarms.structs.multi_agent_exec import run_agents_concurrently
12
- from swarms.structs.output_type import OutputType
12
+ from swarms.structs.output_types import OutputType
13
13
  from swarms.utils.formatter import formatter
14
14
  from swarms.utils.loguru_logger import initialize_logger
15
15
 
@@ -11,7 +11,7 @@ from swarms.schemas.agent_step_schemas import ManySteps
11
11
  from swarms.prompts.ag_prompt import aggregator_system_prompt
12
12
  from swarms.utils.loguru_logger import initialize_logger
13
13
  import concurrent.futures
14
- from swarms.structs.output_type import OutputType
14
+ from swarms.structs.output_types import OutputType
15
15
  from swarms.structs.conversation import Conversation
16
16
 
17
17
  logger = initialize_logger(log_folder="mixture_of_agents")
@@ -18,7 +18,7 @@ from pydantic import BaseModel, Field
18
18
  from swarms.utils.function_caller_model import OpenAIFunctionCaller
19
19
  from swarms.structs.agent import Agent
20
20
  from swarms.structs.conversation import Conversation
21
- from swarms.structs.output_type import OutputType
21
+ from swarms.structs.output_types import OutputType
22
22
  from swarms.utils.any_to_str import any_to_str
23
23
 
24
24
 
@@ -14,3 +14,6 @@ OutputType = Literal[
14
14
  "string",
15
15
  "str",
16
16
  ]
17
+
18
+ # Use the OutputType for type annotations
19
+ output_type: OutputType
@@ -15,7 +15,7 @@ from swarms.structs.base_swarm import BaseSwarm
15
15
  from swarms.utils.loguru_logger import initialize_logger
16
16
  from swarms.telemetry.main import log_agent_data
17
17
  from swarms.structs.conversation import Conversation
18
- from swarms.structs.output_type import OutputType
18
+ from swarms.structs.output_types import OutputType
19
19
 
20
20
  logger = initialize_logger(log_folder="rearrange")
21
21
 
@@ -1,7 +1,7 @@
1
1
  from typing import List, Optional
2
2
  from swarms.structs.agent import Agent
3
3
  from swarms.structs.rearrange import AgentRearrange
4
- from swarms.structs.output_type import OutputType
4
+ from swarms.structs.output_types import OutputType
5
5
  from concurrent.futures import ThreadPoolExecutor, as_completed
6
6
  from swarms.utils.loguru_logger import initialize_logger
7
7
 
@@ -18,9 +18,10 @@ from swarms.structs.rearrange import AgentRearrange
18
18
  from swarms.structs.sequential_workflow import SequentialWorkflow
19
19
  from swarms.structs.spreadsheet_swarm import SpreadSheetSwarm
20
20
  from swarms.structs.swarm_matcher import swarm_matcher
21
- from swarms.structs.output_type import OutputType
21
+ from swarms.structs.output_types import OutputType
22
22
  from swarms.utils.loguru_logger import initialize_logger
23
23
  from swarms.structs.malt import MALT
24
+ from swarms.structs.deep_research_swarm import DeepResearchSwarm
24
25
 
25
26
  logger = initialize_logger(log_folder="swarm_router")
26
27
 
@@ -37,6 +38,7 @@ SwarmType = Literal[
37
38
  "auto",
38
39
  "MajorityVoting",
39
40
  "MALT",
41
+ "DeepResearchSwarm",
40
42
  ]
41
43
 
42
44
 
@@ -316,6 +318,15 @@ class SwarmRouter:
316
318
  preset_agents=True,
317
319
  )
318
320
 
321
+ elif self.swarm_type == "DeepResearchSwarm":
322
+ return DeepResearchSwarm(
323
+ name=self.name,
324
+ description=self.description,
325
+ agents=self.agents,
326
+ max_loops=self.max_loops,
327
+ output_type=self.output_type,
328
+ )
329
+
319
330
  elif self.swarm_type == "HiearchicalSwarm":
320
331
  return HierarchicalSwarm(
321
332
  name=self.name,
@@ -142,7 +142,7 @@ class SwarmsAPIClient:
142
142
  def __init__(
143
143
  self,
144
144
  api_key: Optional[str] = None,
145
- base_url: str = "https://swarms-api-285321057562.us-east1.run.app",
145
+ base_url: str = "https://api.swarms.world",
146
146
  timeout: int = 30,
147
147
  max_retries: int = 3,
148
148
  format_type: Literal["pydantic", "json", "dict"] = "pydantic",
swarms/telemetry/main.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import hashlib
2
- import os
3
2
  import platform
4
3
  import socket
5
4
  import subprocess
@@ -279,12 +278,17 @@ def log_agent_data(data_dict: dict) -> dict | None:
279
278
  url = "https://swarms.world/api/get-agents/log-agents"
280
279
  headers = {
281
280
  "Content-Type": "application/json",
282
- "Authorization": os.getenv("SWARMS_API_KEY"),
281
+ "Authorization": "sk-33979fd9a4e8e6b670090e4900a33dbe7452a15ccc705745f4eca2a70c88ea24",
282
+ }
283
+
284
+ data_input = {
285
+ "data": data_dict,
286
+ "system_data": get_user_device_data(),
283
287
  }
284
288
 
285
289
  try:
286
290
  response = requests.post(
287
- url, json=data_dict, headers=headers, timeout=10
291
+ url, json=data_input, headers=headers, timeout=10
288
292
  )
289
293
  if (
290
294
  response.ok and response.text.strip()