swarms 7.8.9__py3-none-any.whl → 7.9.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.
@@ -1,17 +1,18 @@
1
- import asyncio
2
1
  import os
3
2
  from typing import List, Optional
4
3
 
5
4
 
6
5
  from swarms.structs.agent import Agent
7
6
  from swarms.prompts.ag_prompt import aggregator_system_prompt_main
7
+ from swarms.structs.ma_utils import list_all_agents
8
+ from swarms.utils.history_output_formatter import (
9
+ history_output_formatter,
10
+ )
8
11
  from swarms.utils.loguru_logger import initialize_logger
9
12
  import concurrent.futures
10
13
  from swarms.utils.output_types import OutputType
11
14
  from swarms.structs.conversation import Conversation
12
- from swarms.utils.history_output_formatter import (
13
- history_output_formatter,
14
- )
15
+
15
16
 
16
17
  logger = initialize_logger(log_folder="mixture_of_agents")
17
18
 
@@ -25,13 +26,13 @@ class MixtureOfAgents:
25
26
  self,
26
27
  name: str = "MixtureOfAgents",
27
28
  description: str = "A class to run a mixture of agents and aggregate their responses.",
28
- agents: List[Agent] = [],
29
+ agents: List[Agent] = None,
29
30
  aggregator_agent: Agent = None,
30
31
  aggregator_system_prompt: str = aggregator_system_prompt_main,
31
32
  layers: int = 3,
32
33
  max_loops: int = 1,
33
- return_str_on: bool = False,
34
- output_type: OutputType = "dict",
34
+ output_type: OutputType = "final",
35
+ aggregator_model_name: str = "claude-3-5-sonnet-20240620",
35
36
  ) -> None:
36
37
  """
37
38
  Initialize the Mixture of Agents class with agents and configuration.
@@ -48,16 +49,36 @@ class MixtureOfAgents:
48
49
  self.description = description
49
50
  self.agents = agents
50
51
  self.aggregator_agent = aggregator_agent
51
- self.aggregator_system_prompt = aggregator_system_prompt_main
52
+ self.aggregator_system_prompt = aggregator_system_prompt
52
53
  self.layers = layers
53
54
  self.max_loops = max_loops
54
- self.return_str_on = return_str_on
55
55
  self.output_type = output_type
56
+ self.aggregator_model_name = aggregator_model_name
57
+ self.aggregator_agent = self.aggregator_agent_setup()
56
58
 
57
59
  self.reliability_check()
58
60
 
59
61
  self.conversation = Conversation()
60
62
 
63
+ list_all_agents(
64
+ agents=self.agents,
65
+ conversation=self.conversation,
66
+ description=self.description,
67
+ name=self.name,
68
+ add_to_conversation=True,
69
+ )
70
+
71
+ def aggregator_agent_setup(self):
72
+ return Agent(
73
+ agent_name="Aggregator Agent",
74
+ description="An agent that aggregates the responses of the other agents.",
75
+ system_prompt=aggregator_system_prompt_main,
76
+ model_name=self.aggregator_model_name,
77
+ temperature=0.5,
78
+ max_loops=1,
79
+ output_type="str-all-except-first",
80
+ )
81
+
61
82
  def reliability_check(self) -> None:
62
83
  """
63
84
  Performs a reliability check on the Mixture of Agents class.
@@ -66,8 +87,8 @@ class MixtureOfAgents:
66
87
  "Checking the reliability of the Mixture of Agents class."
67
88
  )
68
89
 
69
- if not self.agents:
70
- raise ValueError("No reference agents provided.")
90
+ if len(self.agents) == 0:
91
+ raise ValueError("No agents provided.")
71
92
 
72
93
  if not self.aggregator_agent:
73
94
  raise ValueError("No aggregator agent provided.")
@@ -78,129 +99,83 @@ class MixtureOfAgents:
78
99
  if not self.layers:
79
100
  raise ValueError("No layers provided.")
80
101
 
81
- if self.layers < 1:
82
- raise ValueError("Layers must be greater than 0.")
83
-
84
102
  logger.info("Reliability check passed.")
85
103
  logger.info("Mixture of Agents class is ready for use.")
86
104
 
87
- def _get_final_system_prompt(
88
- self, system_prompt: str, results: List[str]
89
- ) -> str:
90
- """
91
- Constructs a system prompt for subsequent layers that includes previous responses.
105
+ def save_to_markdown_file(self, file_path: str = "moa.md"):
106
+ with open(file_path, "w") as f:
107
+ f.write(self.conversation.get_str())
92
108
 
93
- Args:
94
- system_prompt (str): The initial system prompt.
95
- results (List[str]): A list of previous responses.
96
-
97
- Returns:
98
- str: The final system prompt including previous responses.
99
- """
100
- return (
101
- system_prompt
102
- + "\n"
103
- + "\n".join(
104
- [
105
- f"{i+1}. {str(element)}"
106
- for i, element in enumerate(results)
107
- ]
108
- )
109
- )
110
-
111
- async def _run_agent_async(
109
+ def step(
112
110
  self,
113
- agent: Agent,
114
111
  task: str,
115
- prev_responses: Optional[List[str]] = None,
116
- ) -> str:
117
- """
118
- Asynchronous method to run a single agent.
112
+ img: Optional[str] = None,
113
+ imgs: Optional[List[str]] = None,
114
+ ):
115
+ # self.conversation.add(role="User", content=task)
119
116
 
120
- Args:
121
- agent (Agent): The agent to be run.
122
- task (str): The task for the agent.
123
- prev_responses (Optional[List[str]], optional): A list of previous responses. Defaults to None.
117
+ # Run agents concurrently
118
+ with concurrent.futures.ThreadPoolExecutor(
119
+ max_workers=os.cpu_count()
120
+ ) as executor:
121
+ # Submit all agent tasks and store with their index
122
+ future_to_agent = {
123
+ executor.submit(
124
+ agent.run, task=task, img=img, imgs=imgs
125
+ ): agent
126
+ for agent in self.agents
127
+ }
124
128
 
125
- Returns:
126
- str: The response from the agent.
127
- """
128
- # If there are previous responses, update the agent's system prompt
129
- if prev_responses:
130
- system_prompt_with_responses = (
131
- self._get_final_system_prompt(
132
- self.aggregator_system_prompt, prev_responses
133
- )
134
- )
135
- agent.system_prompt = system_prompt_with_responses
129
+ # Collect results and add to conversation in completion order
130
+ for future in concurrent.futures.as_completed(
131
+ future_to_agent
132
+ ):
133
+ agent = future_to_agent[future]
134
+ output = future.result()
135
+ self.conversation.add(role=agent.name, content=output)
136
136
 
137
- # Run the agent asynchronously
138
- response = await asyncio.to_thread(agent.run, task)
137
+ return self.conversation.get_str()
139
138
 
140
- self.conversation.add(agent.agent_name, response)
139
+ def _run(
140
+ self,
141
+ task: str,
142
+ img: Optional[str] = None,
143
+ imgs: Optional[List[str]] = None,
144
+ ):
141
145
 
142
- # Log the agent's response
143
- print(f"Agent {agent.agent_name} response: {response}")
144
- return response
146
+ self.conversation.add(role="User", content=task)
145
147
 
146
- async def _run_async(self, task: str) -> None:
147
- """
148
- Asynchronous method to run the Mixture of Agents process.
148
+ for i in range(self.layers):
149
+ out = self.step(
150
+ task=self.conversation.get_str(), img=img, imgs=imgs
151
+ )
152
+ task = out
149
153
 
150
- Args:
151
- task (str): The task for the mixture of agents.
152
- """
153
- # Gather initial responses from reference agents
154
- results: List[str] = await asyncio.gather(
155
- *[
156
- self._run_agent_async(agent, task)
157
- for agent in self.agents
158
- ]
154
+ out = self.aggregator_agent.run(
155
+ task=self.conversation.get_str()
159
156
  )
160
157
 
161
- # Process additional layers, if applicable
162
- for _ in range(1, self.layers - 1):
163
- results = await asyncio.gather(
164
- *[
165
- self._run_agent_async(
166
- agent, task, prev_responses=results
167
- )
168
- for agent in self.agents
169
- ]
170
- )
171
-
172
- # Perform final aggregation using the aggregator agent
173
- final_result = await self._run_agent_async(
174
- self.aggregator_agent, task, prev_responses=results
158
+ self.conversation.add(
159
+ role=self.aggregator_agent.agent_name, content=out
175
160
  )
176
161
 
177
- print(f"Final Aggregated Response: {final_result}")
162
+ out = history_output_formatter(
163
+ conversation=self.conversation, type=self.output_type
164
+ )
178
165
 
179
- def run(self, task: str) -> None:
180
- """
181
- Synchronous wrapper to run the async process.
166
+ return out
182
167
 
183
- Args:
184
- task (str): The task for the mixture of agents.
185
- """
168
+ def run(
169
+ self,
170
+ task: str,
171
+ img: Optional[str] = None,
172
+ imgs: Optional[List[str]] = None,
173
+ ):
186
174
  try:
187
- self.conversation.add("user", task)
188
-
189
- for _ in range(self.max_loops):
190
- # Add previous context to task if available
191
- prompt = f"History: {self.conversation.get_str()}\n\nTask: {task}"
192
-
193
- # Run async process
194
- asyncio.run(self._run_async(prompt))
195
-
196
- return history_output_formatter(
197
- conversation=self.conversation,
198
- type=self.output_type,
199
- )
200
-
175
+ return self._run(task=task, img=img, imgs=imgs)
201
176
  except Exception as e:
202
- logger.error(f"Error running mixture of agents: {str(e)}")
203
- raise e
177
+ logger.error(f"Error running Mixture of Agents: {e}")
178
+ return f"Error: {e}"
204
179
 
205
180
  def run_batched(self, tasks: List[str]) -> List[str]:
206
181
  """