swarms 7.9.2__py3-none-any.whl → 7.9.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.
@@ -1,4 +1,13 @@
1
- from typing import List, Literal, Dict, Callable, Any
1
+ from typing import (
2
+ List,
3
+ Literal,
4
+ Dict,
5
+ Callable,
6
+ Any,
7
+ Tuple,
8
+ Hashable,
9
+ )
10
+
2
11
 
3
12
  from swarms.agents.consistency_agent import SelfConsistencyAgent
4
13
  from swarms.agents.flexion_agent import ReflexionAgent
@@ -10,6 +19,7 @@ from swarms.agents.reasoning_duo import ReasoningDuo
10
19
  from swarms.utils.output_types import OutputType
11
20
  from swarms.agents.agent_judge import AgentJudge
12
21
 
22
+
13
23
  agent_types = Literal[
14
24
  "reasoning-duo",
15
25
  "self-consistency",
@@ -27,6 +37,7 @@ class ReasoningAgentRouter:
27
37
  """
28
38
  A Reasoning Agent that can answer questions and assist with various tasks using different reasoning strategies.
29
39
 
40
+
30
41
  Attributes:
31
42
  agent_name (str): The name of the agent.
32
43
  description (str): A brief description of the agent's capabilities.
@@ -38,6 +49,9 @@ class ReasoningAgentRouter:
38
49
  output_type (OutputType): The format of the output (e.g., dict, list).
39
50
  """
40
51
 
52
+ # Class variable to store cached agent instances
53
+ _agent_cache: Dict[Tuple[Hashable, ...], Any] = {}
54
+
41
55
  def __init__(
42
56
  self,
43
57
  agent_name: str = "reasoning_agent",
@@ -63,16 +77,16 @@ class ReasoningAgentRouter:
63
77
  self.memory_capacity = memory_capacity
64
78
 
65
79
  # Added: Initialize the factory mapping dictionary
80
+
66
81
  self._initialize_agent_factories()
67
82
 
68
- # Added: Factory method initialization function
69
83
  def _initialize_agent_factories(self) -> None:
70
84
  """
71
85
  Initialize the agent factory mapping dictionary, mapping various agent types to their respective creation functions.
72
- This method replaces the original if-elif chain, making the code easier to maintain and extend.
86
+ This method replaces the original if-elif chain, making the code more maintainable and extensible.
73
87
  """
74
88
  self.agent_factories: Dict[str, Callable[[], Any]] = {
75
- # ReasoningDuo factory methods
89
+ # ReasoningDuo factory method
76
90
  "reasoning-duo": self._create_reasoning_duo,
77
91
  "reasoning-agent": self._create_reasoning_duo,
78
92
  # SelfConsistencyAgent factory methods
@@ -87,9 +101,30 @@ class ReasoningAgentRouter:
87
101
  "GKPAgent": self._create_gkp_agent,
88
102
  }
89
103
 
90
- # Added: Concrete factory methods for various agent types
104
+ def _get_cache_key(self) -> Tuple[Hashable, ...]:
105
+ """
106
+ Generate a unique key for cache lookup.
107
+ The key is based on all relevant configuration parameters of the agent.
108
+
109
+
110
+ Returns:
111
+ Tuple[Hashable, ...]: A hashable tuple to serve as the cache key
112
+ """
113
+ return (
114
+ self.swarm_type,
115
+ self.agent_name,
116
+ self.description,
117
+ self.model_name,
118
+ self.system_prompt,
119
+ self.max_loops,
120
+ self.num_samples,
121
+ self.output_type,
122
+ self.num_knowledge_items,
123
+ self.memory_capacity,
124
+ )
125
+
91
126
  def _create_reasoning_duo(self):
92
- """Creates an agent instance for ReasoningDuo type"""
127
+ """Create an agent instance for the ReasoningDuo type"""
93
128
  return ReasoningDuo(
94
129
  agent_name=self.agent_name,
95
130
  agent_description=self.description,
@@ -99,7 +134,7 @@ class ReasoningAgentRouter:
99
134
  )
100
135
 
101
136
  def _create_consistency_agent(self):
102
- """Creates an agent instance for SelfConsistencyAgent type"""
137
+ """Create an agent instance for the SelfConsistencyAgent type"""
103
138
  return SelfConsistencyAgent(
104
139
  agent_name=self.agent_name,
105
140
  description=self.description,
@@ -111,7 +146,7 @@ class ReasoningAgentRouter:
111
146
  )
112
147
 
113
148
  def _create_ire_agent(self):
114
- """Creates an agent instance for IREAgent type"""
149
+ """Create an agent instance for the IREAgent type"""
115
150
  return IREAgent(
116
151
  agent_name=self.agent_name,
117
152
  description=self.description,
@@ -123,7 +158,7 @@ class ReasoningAgentRouter:
123
158
  )
124
159
 
125
160
  def _create_agent_judge(self):
126
- """Creates an agent instance for AgentJudge type"""
161
+ """Create an agent instance for the AgentJudge type"""
127
162
  return AgentJudge(
128
163
  agent_name=self.agent_name,
129
164
  model_name=self.model_name,
@@ -132,7 +167,7 @@ class ReasoningAgentRouter:
132
167
  )
133
168
 
134
169
  def _create_reflexion_agent(self):
135
- """Creates an agent instance for ReflexionAgent type"""
170
+ """Create an agent instance for the ReflexionAgent type"""
136
171
  return ReflexionAgent(
137
172
  agent_name=self.agent_name,
138
173
  system_prompt=self.system_prompt,
@@ -141,7 +176,7 @@ class ReasoningAgentRouter:
141
176
  )
142
177
 
143
178
  def _create_gkp_agent(self):
144
- """Creates an agent instance for GKPAgent type"""
179
+ """Create an agent instance for the GKPAgent type"""
145
180
  return GKPAgent(
146
181
  agent_name=self.agent_name,
147
182
  model_name=self.model_name,
@@ -150,92 +185,42 @@ class ReasoningAgentRouter:
150
185
 
151
186
  def select_swarm(self):
152
187
  """
153
- Selects and initializes the appropriate reasoning swarm based on the specified swarm type.
188
+ Select and initialize the appropriate reasoning swarm based on the specified swarm type.
189
+ Uses a caching mechanism to return a cached instance if an agent with the same configuration already exists.
190
+
191
+
154
192
  Returns:
155
- An instance of the selected reasoning swarm.
156
- """
157
- # Commented out original if-elif chain implementation
158
- """
159
- if (
160
- self.swarm_type == "reasoning-duo"
161
- or self.swarm_type == "reasoning-agent"
162
- ):
163
- return ReasoningDuo(
164
- agent_name=self.agent_name,
165
- agent_description=self.description,
166
- model_name=[self.model_name, self.model_name],
167
- system_prompt=self.system_prompt,
168
- output_type=self.output_type,
169
- )
170
-
171
- elif (
172
- self.swarm_type == "self-consistency"
173
- or self.swarm_type == "consistency-agent"
174
- ):
175
- return SelfConsistencyAgent(
176
- agent_name=self.agent_name,
177
- description=self.description,
178
- model_name=self.model_name,
179
- system_prompt=self.system_prompt,
180
- max_loops=self.max_loops,
181
- num_samples=self.num_samples,
182
- output_type=self.output_type,
183
- )
184
-
185
- elif (
186
- self.swarm_type == "ire" or self.swarm_type == "ire-agent"
187
- ):
188
- return IREAgent(
189
- agent_name=self.agent_name,
190
- description=self.description,
191
- model_name=self.model_name,
192
- system_prompt=self.system_prompt,
193
- max_loops=self.max_loops,
194
- max_iterations=self.num_samples,
195
- output_type=self.output_type,
196
- )
197
-
198
- elif self.swarm_type == "AgentJudge":
199
- return AgentJudge(
200
- agent_name=self.agent_name,
201
- model_name=self.model_name,
202
- system_prompt=self.system_prompt,
203
- max_loops=self.max_loops,
204
- )
205
-
206
- elif self.swarm_type == "ReflexionAgent":
207
- return ReflexionAgent(
208
- agent_name=self.agent_name,
209
- system_prompt=self.system_prompt,
210
- model_name=self.model_name,
211
- max_loops=self.max_loops,
212
- )
213
-
214
- elif self.swarm_type == "GKPAgent":
215
- return GKPAgent(
216
- agent_name=self.agent_name,
217
- model_name=self.model_name,
218
- num_knowledge_items=self.num_knowledge_items,
219
- )
220
- else:
221
- raise ValueError(f"Invalid swarm type: {self.swarm_type}")
193
+ The selected reasoning swarm instance.
222
194
  """
223
195
 
224
- # Added: Implementation using factory pattern and dictionary mapping
196
+ # Generate cache key
197
+ cache_key = self._get_cache_key()
198
+
199
+ # Check if an instance with the same configuration already exists in the cache
200
+ if cache_key in self.__class__._agent_cache:
201
+ return self.__class__._agent_cache[cache_key]
202
+
225
203
  try:
226
- # Get the corresponding creation function from the factory dictionary and call it
227
- return self.agent_factories[self.swarm_type]()
204
+ # Use the factory method to create a new instance
205
+ agent = self.agent_factories[self.swarm_type]()
206
+
207
+ # Add the newly created instance to the cache
208
+ self.__class__._agent_cache[cache_key] = agent
209
+
210
+ return agent
228
211
  except KeyError:
229
- # Maintain the same error handling as the original code
212
+ # Keep the same error handling as the original code
230
213
  raise ValueError(f"Invalid swarm type: {self.swarm_type}")
231
214
 
232
215
  def run(self, task: str, *args, **kwargs):
233
216
  """
234
- Executes the selected swarm's reasoning process on the given task.
217
+ Execute the reasoning process of the selected swarm on a given task.
218
+
235
219
 
236
220
  Args:
237
221
  task (str): The task or question to be processed by the reasoning agent.
238
222
 
223
+
239
224
  Returns:
240
225
  The result of the reasoning process.
241
226
  """
@@ -244,15 +229,25 @@ class ReasoningAgentRouter:
244
229
 
245
230
  def batched_run(self, tasks: List[str], *args, **kwargs):
246
231
  """
247
- Executes the reasoning process on a batch of tasks.
232
+ Execute the reasoning process on a batch of tasks.
233
+
248
234
 
249
235
  Args:
250
- tasks (List[str]): A list of tasks to be processed.
236
+ tasks (List[str]): The list of tasks to process.
237
+
251
238
 
252
239
  Returns:
253
- List of results from the reasoning process for each task.
240
+ A list of reasoning process results for each task.
254
241
  """
255
242
  results = []
256
243
  for task in tasks:
257
244
  results.append(self.run(task, *args, **kwargs))
258
245
  return results
246
+
247
+ @classmethod
248
+ def clear_cache(cls):
249
+ """
250
+ Clear the agent instance cache.
251
+ Use this when you need to free memory or force the creation of new instances.
252
+ """
253
+ cls._agent_cache.clear()
swarms/structs/agent.py CHANGED
@@ -161,7 +161,6 @@ class AgentToolExecutionError(AgentError):
161
161
  pass
162
162
 
163
163
 
164
- # [FEAT][AGENT]
165
164
  class Agent:
166
165
  """
167
166
  Agent is the backbone to connect LLMs with tools and long term memory. Agent also provides the ability to
@@ -434,6 +433,7 @@ class Agent:
434
433
  output_raw_json_from_tool_call: bool = False,
435
434
  summarize_multiple_images: bool = False,
436
435
  tool_retry_attempts: int = 3,
436
+ speed_mode: str = "fast",
437
437
  *args,
438
438
  **kwargs,
439
439
  ):
@@ -574,6 +574,7 @@ class Agent:
574
574
  )
575
575
  self.summarize_multiple_images = summarize_multiple_images
576
576
  self.tool_retry_attempts = tool_retry_attempts
577
+ self.speed_mode = speed_mode
577
578
 
578
579
  # self.short_memory = self.short_memory_init()
579
580
 
@@ -1152,12 +1153,7 @@ class Agent:
1152
1153
  self.save()
1153
1154
 
1154
1155
  logger.error(
1155
- f"Attempt {attempt+1}/{self.max_retries}: Error generating response in loop {loop_count} for agent '{self.agent_name}': {str(e)} | "
1156
- f"Error type: {type(e).__name__}, Error details: {e.__dict__ if hasattr(e, '__dict__') else 'No additional details'} | "
1157
- f"Current task: '{task}', Agent state: max_loops={self.max_loops}, "
1158
- f"model={getattr(self.llm, 'model_name', 'unknown')}, "
1159
- f"temperature={getattr(self.llm, 'temperature', 'unknown')}"
1160
- f"{f' | Traceback: {e.__traceback__}' if hasattr(e, '__traceback__') else ''}"
1156
+ f"Attempt {attempt+1}/{self.retry_attempts}: Error generating response in loop {loop_count} for agent '{self.agent_name}': {str(e)} | "
1161
1157
  )
1162
1158
  attempt += 1
1163
1159
 
@@ -1237,6 +1233,192 @@ class Agent:
1237
1233
  except KeyboardInterrupt as error:
1238
1234
  self._handle_run_error(error)
1239
1235
 
1236
+ def _run_fast(
1237
+ self,
1238
+ task: Optional[Union[str, Any]] = None,
1239
+ img: Optional[str] = None,
1240
+ print_task: Optional[bool] = False,
1241
+ *args,
1242
+ **kwargs,
1243
+ ) -> Any:
1244
+ """
1245
+ run the agent
1246
+
1247
+ Args:
1248
+ task (str): The task to be performed.
1249
+ img (str): The image to be processed.
1250
+ is_last (bool): Indicates if this is the last task.
1251
+
1252
+ Returns:
1253
+ Any: The output of the agent.
1254
+ (string, list, json, dict, yaml, xml)
1255
+
1256
+ Examples:
1257
+ agent(task="What is the capital of France?")
1258
+ agent(task="What is the capital of France?", img="path/to/image.jpg")
1259
+ agent(task="What is the capital of France?", img="path/to/image.jpg", is_last=True)
1260
+ """
1261
+ try:
1262
+
1263
+ self.short_memory.add(role=self.user_name, content=task)
1264
+
1265
+ # Set the loop count
1266
+ loop_count = 0
1267
+
1268
+ # Clear the short memory
1269
+ response = None
1270
+
1271
+ # Query the long term memory first for the context
1272
+ if self.long_term_memory is not None:
1273
+ self.memory_query(task)
1274
+
1275
+ # Print the request
1276
+ if print_task is True:
1277
+ formatter.print_panel(
1278
+ content=f"\n User: {task}",
1279
+ title=f"Task Request for {self.agent_name}",
1280
+ )
1281
+
1282
+ while (
1283
+ self.max_loops == "auto"
1284
+ or loop_count < self.max_loops
1285
+ ):
1286
+ loop_count += 1
1287
+
1288
+ if self.max_loops >= 2:
1289
+ self.short_memory.add(
1290
+ role=self.agent_name,
1291
+ content=f"Current Internal Reasoning Loop: {loop_count}/{self.max_loops}",
1292
+ )
1293
+
1294
+ # If it is the final loop, then add the final loop message
1295
+ if loop_count >= 2 and loop_count == self.max_loops:
1296
+ self.short_memory.add(
1297
+ role=self.agent_name,
1298
+ content=f"🎉 Final Internal Reasoning Loop: {loop_count}/{self.max_loops} Prepare your comprehensive response.",
1299
+ )
1300
+
1301
+ # Dynamic temperature
1302
+ if self.dynamic_temperature_enabled is True:
1303
+ self.dynamic_temperature()
1304
+
1305
+ # Task prompt
1306
+ task_prompt = (
1307
+ self.short_memory.return_history_as_string()
1308
+ )
1309
+
1310
+ # Parameters
1311
+ attempt = 0
1312
+ success = False
1313
+ while attempt < self.retry_attempts and not success:
1314
+ try:
1315
+ if (
1316
+ self.long_term_memory is not None
1317
+ and self.rag_every_loop is True
1318
+ ):
1319
+ logger.info(
1320
+ "Querying RAG database for context..."
1321
+ )
1322
+ self.memory_query(task_prompt)
1323
+
1324
+ if img is not None:
1325
+ response = self.call_llm(
1326
+ task=task_prompt,
1327
+ img=img,
1328
+ current_loop=loop_count,
1329
+ *args,
1330
+ **kwargs,
1331
+ )
1332
+ else:
1333
+ response = self.call_llm(
1334
+ task=task_prompt,
1335
+ current_loop=loop_count,
1336
+ *args,
1337
+ **kwargs,
1338
+ )
1339
+
1340
+ # If streaming is enabled, then don't print the response
1341
+
1342
+ # Parse the response from the agent with the output type
1343
+ if exists(self.tools_list_dictionary):
1344
+ if isinstance(response, BaseModel):
1345
+ response = response.model_dump()
1346
+
1347
+ # Parse the response from the agent with the output type
1348
+ response = self.parse_llm_output(response)
1349
+
1350
+ self.short_memory.add(
1351
+ role=self.agent_name,
1352
+ content=response,
1353
+ )
1354
+
1355
+ # Print
1356
+ if self.print_on is True:
1357
+ if isinstance(response, list):
1358
+ self.pretty_print(
1359
+ f"Structured Output - Attempting Function Call Execution [{time.strftime('%H:%M:%S')}] \n\n {format_data_structure(response)} ",
1360
+ loop_count,
1361
+ )
1362
+ elif self.streaming_on is True:
1363
+ pass
1364
+ else:
1365
+ self.pretty_print(
1366
+ response, loop_count
1367
+ )
1368
+
1369
+ # Check and execute callable tools
1370
+ if exists(self.tools):
1371
+ self.tool_execution_retry(
1372
+ response, loop_count
1373
+ )
1374
+
1375
+ # Handle MCP tools
1376
+ if (
1377
+ exists(self.mcp_url)
1378
+ or exists(self.mcp_config)
1379
+ or exists(self.mcp_urls)
1380
+ ):
1381
+ # Only handle MCP tools if response is not None
1382
+ if response is not None:
1383
+ self.mcp_tool_handling(
1384
+ response=response,
1385
+ current_loop=loop_count,
1386
+ )
1387
+ else:
1388
+ logger.warning(
1389
+ f"LLM returned None response in loop {loop_count}, skipping MCP tool handling"
1390
+ )
1391
+
1392
+ success = True # Mark as successful to exit the retry loop
1393
+
1394
+ except Exception as e:
1395
+
1396
+ logger.error(
1397
+ f"Attempt {attempt+1}/{self.retry_attempts}: Error generating response in loop {loop_count} for agent '{self.agent_name}': {str(e)} | "
1398
+ )
1399
+ attempt += 1
1400
+
1401
+ if not success:
1402
+
1403
+ logger.error(
1404
+ "Failed to generate a valid response after"
1405
+ " retry attempts."
1406
+ )
1407
+ break # Exit the loop if all retry attempts fail
1408
+
1409
+ # log_agent_data(self.to_dict())
1410
+
1411
+ # Output formatting based on output_type
1412
+ return history_output_formatter(
1413
+ self.short_memory, type=self.output_type
1414
+ )
1415
+
1416
+ except Exception as error:
1417
+ self._handle_run_error(error)
1418
+
1419
+ except KeyboardInterrupt as error:
1420
+ self._handle_run_error(error)
1421
+
1240
1422
  def __handle_run_error(self, error: any):
1241
1423
  import traceback
1242
1424
 
@@ -2534,6 +2716,10 @@ class Agent:
2534
2716
  ValueError: If task is empty.
2535
2717
  """
2536
2718
 
2719
+ # Filter out is_last from kwargs if present
2720
+ if "is_last" in kwargs:
2721
+ del kwargs["is_last"]
2722
+
2537
2723
  try:
2538
2724
  # Set streaming parameter in LLM if streaming is enabled
2539
2725
  if self.streaming_on and hasattr(self.llm, "stream"):
@@ -2678,6 +2864,13 @@ class Agent:
2678
2864
  *args,
2679
2865
  **kwargs,
2680
2866
  )
2867
+ elif self.speed_mode == "fast":
2868
+ output = self._run_fast(
2869
+ task=task,
2870
+ img=img,
2871
+ *args,
2872
+ **kwargs,
2873
+ )
2681
2874
  else:
2682
2875
  output = self._run(
2683
2876
  task=task,