swarms 7.8.3__py3-none-any.whl → 7.8.7__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 (60) hide show
  1. swarms/agents/ape_agent.py +5 -22
  2. swarms/agents/consistency_agent.py +1 -1
  3. swarms/agents/i_agent.py +1 -1
  4. swarms/agents/reasoning_agents.py +99 -3
  5. swarms/agents/reasoning_duo.py +1 -1
  6. swarms/cli/main.py +1 -1
  7. swarms/communication/__init__.py +1 -0
  8. swarms/communication/duckdb_wrap.py +32 -2
  9. swarms/communication/pulsar_struct.py +45 -19
  10. swarms/communication/redis_wrap.py +56 -11
  11. swarms/communication/supabase_wrap.py +1659 -0
  12. swarms/prompts/agent_conversation_aggregator.py +38 -0
  13. swarms/prompts/prompt.py +0 -3
  14. swarms/schemas/agent_completion_response.py +71 -0
  15. swarms/schemas/agent_rag_schema.py +7 -0
  16. swarms/schemas/conversation_schema.py +9 -0
  17. swarms/schemas/llm_agent_schema.py +99 -81
  18. swarms/schemas/swarms_api_schemas.py +164 -0
  19. swarms/structs/__init__.py +15 -9
  20. swarms/structs/agent.py +219 -199
  21. swarms/structs/agent_rag_handler.py +685 -0
  22. swarms/structs/base_swarm.py +2 -1
  23. swarms/structs/conversation.py +832 -264
  24. swarms/structs/csv_to_agent.py +153 -100
  25. swarms/structs/deep_research_swarm.py +197 -193
  26. swarms/structs/dynamic_conversational_swarm.py +18 -7
  27. swarms/structs/hiearchical_swarm.py +1 -1
  28. swarms/structs/hybrid_hiearchical_peer_swarm.py +2 -18
  29. swarms/structs/image_batch_processor.py +261 -0
  30. swarms/structs/interactive_groupchat.py +356 -0
  31. swarms/structs/ma_blocks.py +159 -0
  32. swarms/structs/majority_voting.py +1 -1
  33. swarms/structs/mixture_of_agents.py +1 -1
  34. swarms/structs/multi_agent_exec.py +25 -26
  35. swarms/structs/multi_agent_router.py +3 -2
  36. swarms/structs/rearrange.py +3 -3
  37. swarms/structs/sequential_workflow.py +3 -3
  38. swarms/structs/swarm_matcher.py +499 -408
  39. swarms/structs/swarm_router.py +15 -97
  40. swarms/structs/swarming_architectures.py +1 -1
  41. swarms/tools/mcp_client_call.py +3 -0
  42. swarms/utils/__init__.py +10 -2
  43. swarms/utils/check_all_model_max_tokens.py +43 -0
  44. swarms/utils/generate_keys.py +0 -27
  45. swarms/utils/history_output_formatter.py +5 -20
  46. swarms/utils/litellm_wrapper.py +208 -60
  47. swarms/utils/output_types.py +24 -0
  48. swarms/utils/vllm_wrapper.py +14 -13
  49. swarms/utils/xml_utils.py +37 -2
  50. {swarms-7.8.3.dist-info → swarms-7.8.7.dist-info}/METADATA +31 -55
  51. {swarms-7.8.3.dist-info → swarms-7.8.7.dist-info}/RECORD +55 -48
  52. swarms/structs/multi_agent_collab.py +0 -242
  53. swarms/structs/output_types.py +0 -6
  54. swarms/utils/markdown_message.py +0 -21
  55. swarms/utils/visualizer.py +0 -510
  56. swarms/utils/wrapper_clusterop.py +0 -127
  57. /swarms/{tools → schemas}/tool_schema_base_model.py +0 -0
  58. {swarms-7.8.3.dist-info → swarms-7.8.7.dist-info}/LICENSE +0 -0
  59. {swarms-7.8.3.dist-info → swarms-7.8.7.dist-info}/WHEEL +0 -0
  60. {swarms-7.8.3.dist-info → swarms-7.8.7.dist-info}/entry_points.txt +0 -0
@@ -1,9 +1,11 @@
1
1
  import json
2
- from typing import List, Optional, Tuple
2
+ import os
3
+ from typing import Dict, List, Literal, Optional, Tuple, Union
3
4
 
4
5
  import numpy as np
5
- from pydantic import BaseModel, Field
6
- from tenacity import retry, stop_after_attempt, wait_exponential
6
+ from pydantic import BaseModel, Field, field_validator
7
+ from pydantic.v1 import validator
8
+ from litellm import embedding
7
9
 
8
10
  from swarms.utils.auto_download_check_packages import (
9
11
  auto_check_and_download_package,
@@ -21,18 +23,75 @@ class SwarmType(BaseModel):
21
23
  )
22
24
 
23
25
 
26
+ api_key = os.getenv("OPENAI_API_KEY")
27
+
28
+
24
29
  class SwarmMatcherConfig(BaseModel):
25
- model_name: str = "sentence-transformers/all-MiniLM-L6-v2"
26
- embedding_dim: int = (
27
- 512 # Dimension of the sentence-transformers model
30
+ backend: Literal["local", "openai"] = "local"
31
+ model_name: str = (
32
+ "sentence-transformers/all-MiniLM-L6-v2" # For local embeddings
33
+ )
34
+ openai_model: str = (
35
+ "text-embedding-3-small" # Default to newer OpenAI model
36
+ )
37
+ embedding_dim: int = 512 # For local embeddings
38
+ openai_dimensions: Optional[int] = (
39
+ None # For OpenAI text-embedding-3-* models
28
40
  )
41
+ similarity_threshold: float = Field(default=0.5, ge=0.0, le=1.0)
42
+ cache_embeddings: bool = True
43
+ max_sequence_length: int = Field(default=512, ge=64, le=2048)
44
+ device: str = "cpu" # Only used for local embeddings
45
+ batch_size: int = Field(default=32, ge=1)
46
+ openai_api_key: Optional[str] = os.getenv("OPENAI_API_KEY")
47
+ metadata: Optional[Dict] = Field(
48
+ default_factory=dict
49
+ ) # For OpenAI embedding calls
50
+
51
+ class Config:
52
+ validate_assignment = True
53
+
54
+ @validator("openai_dimensions")
55
+ def validate_dimensions(cls, v, values):
56
+ if values.get("backend") == "openai":
57
+ if (
58
+ values.get("openai_model", "").startswith(
59
+ "text-embedding-3"
60
+ )
61
+ and v is None
62
+ ):
63
+ # Default to 1536 for text-embedding-3-small/large if not specified
64
+ return 1536
65
+ return v
66
+
67
+ @field_validator("openai_model")
68
+ def validate_model(cls, v, values):
69
+ if values.get("backend") == "openai":
70
+ valid_models = [
71
+ "text-embedding-3-small",
72
+ "text-embedding-3-large",
73
+ "text-embedding-ada-002",
74
+ ]
75
+ if v not in valid_models:
76
+ raise ValueError(
77
+ f"OpenAI model must be one of: {', '.join(valid_models)}"
78
+ )
79
+ return v
29
80
 
30
81
 
31
82
  class SwarmMatcher:
32
83
  """
33
- A class for matching tasks to swarm types based on their descriptions.
34
- It utilizes a transformer model to generate embeddings for task and swarm type descriptions,
35
- and then calculates the dot product to find the best match.
84
+ A class for matching tasks to swarm types based on their descriptions using semantic similarity.
85
+
86
+ This class uses transformer models to generate embeddings for both task descriptions and swarm type descriptions.
87
+ It then calculates similarity scores to find the most appropriate swarm type for a given task.
88
+
89
+ Features:
90
+ - Supports both local transformer models and OpenAI embeddings
91
+ - Implements embedding caching for improved performance
92
+ - Provides batch processing capabilities
93
+ - Includes retry mechanisms for API calls
94
+ - Supports saving/loading swarm type configurations
36
95
  """
37
96
 
38
97
  def __init__(self, config: SwarmMatcherConfig):
@@ -40,15 +99,35 @@ class SwarmMatcher:
40
99
  Initializes the SwarmMatcher with a configuration.
41
100
 
42
101
  Args:
43
- config (SwarmMatcherConfig): The configuration for the SwarmMatcher.
102
+ config (SwarmMatcherConfig): Configuration object specifying model settings,
103
+ similarity thresholds, and other parameters.
104
+
105
+ Raises:
106
+ ImportError: If required dependencies (torch, transformers) are not available
107
+ Exception: If model initialization fails
44
108
  """
109
+ try:
110
+ self.config = config
111
+ if self.config.backend == "local":
112
+ transformers = self._setup_dependencies()
113
+ self._setup_model_and_tokenizer(transformers)
114
+ self._initialize_state()
115
+ self.initialize_swarm_types()
116
+ logger.debug("SwarmMatcher initialized successfully")
117
+ except Exception as e:
118
+ logger.error(f"Error initializing SwarmMatcher: {str(e)}")
119
+ raise
45
120
 
121
+ def _setup_dependencies(self):
122
+ """Set up required dependencies for the SwarmMatcher."""
46
123
  try:
124
+ import numpy as np
47
125
  import torch
48
126
  except ImportError:
49
127
  auto_check_and_download_package(
50
128
  "torch", package_manager="pip", upgrade=True
51
129
  )
130
+ import numpy as np
52
131
  import torch
53
132
 
54
133
  try:
@@ -60,64 +139,279 @@ class SwarmMatcher:
60
139
  import transformers
61
140
 
62
141
  self.torch = torch
142
+ self.np = np
143
+ return transformers
144
+
145
+ def _setup_model_and_tokenizer(self, transformers):
146
+ """Initialize the model and tokenizer."""
147
+ self.device = self.torch.device(self.config.device)
148
+ self.tokenizer = transformers.AutoTokenizer.from_pretrained(
149
+ self.config.model_name
150
+ )
151
+ self.model = transformers.AutoModel.from_pretrained(
152
+ self.config.model_name
153
+ ).to(self.device)
154
+
155
+ def _initialize_state(self):
156
+ """Initialize internal state variables."""
157
+ self.swarm_types: List[SwarmType] = []
158
+ self._embedding_cache = (
159
+ {} if self.config.cache_embeddings else None
160
+ )
161
+
162
+ def _get_cached_embedding(
163
+ self, text: str
164
+ ) -> Optional[np.ndarray]:
165
+ """
166
+ Retrieves a cached embedding if available.
167
+
168
+ Args:
169
+ text (str): The text to look up in the cache
170
+
171
+ Returns:
172
+ Optional[np.ndarray]: The cached embedding if found, None otherwise
173
+ """
174
+ if self._embedding_cache is not None:
175
+ return self._embedding_cache.get(text)
176
+ return None
177
+
178
+ def _cache_embedding(self, text: str, embedding: np.ndarray):
179
+ """
180
+ Stores an embedding in the cache for future use.
181
+
182
+ Args:
183
+ text (str): The text associated with the embedding
184
+ embedding (np.ndarray): The embedding vector to cache
185
+ """
186
+ if self._embedding_cache is not None:
187
+ self._embedding_cache[text] = embedding
188
+
189
+ def _get_openai_embedding(self, text: str) -> np.ndarray:
190
+ """Get embedding using OpenAI's API via litellm."""
63
191
  try:
64
- self.config = config
65
- self.tokenizer = (
66
- transformers.AutoTokenizer.from_pretrained(
67
- config.model_name
192
+ params = {
193
+ "model": self.config.openai_model,
194
+ "input": [text],
195
+ }
196
+
197
+ # Add dimensions parameter for text-embedding-3-* models
198
+ if (
199
+ self.config.openai_model.startswith(
200
+ "text-embedding-3"
68
201
  )
69
- )
70
- self.model = transformers.AutoModel.from_pretrained(
71
- config.model_name
72
- )
73
- self.swarm_types: List[SwarmType] = []
74
- logger.debug("SwarmMatcher initialized successfully")
202
+ and self.config.openai_dimensions
203
+ ):
204
+ params["dimensions"] = self.config.openai_dimensions
205
+
206
+ response = embedding(**params)
207
+ response = response.model_dump()
208
+
209
+ # Handle the response format
210
+ if "data" in response and len(response["data"]) > 0:
211
+ embedding_data = response["data"][0]["embedding"]
212
+ else:
213
+ raise ValueError(
214
+ f"Unexpected response format from OpenAI API: {response}"
215
+ )
216
+
217
+ embedding_array = np.array(embedding_data)
218
+
219
+ # Log usage information if available
220
+ if "usage" in response:
221
+ logger.debug(
222
+ f"OpenAI API usage - Prompt tokens: {response['usage'].get('prompt_tokens', 'N/A')}, "
223
+ f"Total tokens: {response['usage'].get('total_tokens', 'N/A')}"
224
+ )
225
+
226
+ return embedding_array
75
227
  except Exception as e:
76
- logger.error(f"Error initializing SwarmMatcher: {str(e)}")
228
+ logger.error(f"Error getting OpenAI embedding: {str(e)}")
229
+ raise
230
+
231
+ def _get_openai_embeddings_batch(
232
+ self, texts: List[str]
233
+ ) -> np.ndarray:
234
+ """Get embeddings for a batch of texts using OpenAI's API via litellm."""
235
+ try:
236
+ params = {
237
+ "model": self.config.openai_model,
238
+ "input": texts,
239
+ }
240
+
241
+ # Add dimensions parameter for text-embedding-3-* models
242
+ if (
243
+ self.config.openai_model.startswith(
244
+ "text-embedding-3"
245
+ )
246
+ and self.config.openai_dimensions
247
+ ):
248
+ params["dimensions"] = self.config.openai_dimensions
249
+
250
+ response = embedding(**params)
251
+ response = response.model_dump()
252
+
253
+ # Handle the response format
254
+ if "data" in response:
255
+ embeddings = [
256
+ data["embedding"] for data in response["data"]
257
+ ]
258
+ else:
259
+ raise ValueError(
260
+ f"Unexpected response format from OpenAI API: {response}"
261
+ )
262
+
263
+ # Log usage information if available
264
+ if "usage" in response:
265
+ logger.debug(
266
+ f"Batch OpenAI API usage - Prompt tokens: {response['usage'].get('prompt_tokens', 'N/A')}, "
267
+ f"Total tokens: {response['usage'].get('total_tokens', 'N/A')}"
268
+ )
269
+
270
+ return np.array(embeddings)
271
+ except Exception as e:
272
+ logger.error(
273
+ f"Error getting OpenAI embeddings batch: {str(e)}"
274
+ )
77
275
  raise
78
276
 
79
- @retry(
80
- stop=stop_after_attempt(3),
81
- wait=wait_exponential(multiplier=1, min=4, max=10),
82
- )
83
277
  def get_embedding(self, text: str) -> np.ndarray:
84
278
  """
85
279
  Generates an embedding for a given text using the configured model.
86
280
 
281
+ This method first checks the cache for an existing embedding. If not found,
282
+ it generates a new embedding using either the local transformer model or OpenAI API.
283
+
87
284
  Args:
88
- text (str): The text for which to generate an embedding.
285
+ text (str): The text for which to generate an embedding
89
286
 
90
287
  Returns:
91
- np.ndarray: The embedding vector for the text.
288
+ np.ndarray: The embedding vector for the text
289
+
290
+ Raises:
291
+ Exception: If embedding generation fails
92
292
  """
293
+ # Check cache first
294
+ cached_embedding = self._get_cached_embedding(text)
295
+ if cached_embedding is not None:
296
+ return cached_embedding
297
+
93
298
  logger.debug(f"Getting embedding for text: {text[:50]}...")
94
299
  try:
95
- inputs = self.tokenizer(
96
- text,
97
- return_tensors="pt",
98
- padding=True,
99
- truncation=True,
100
- max_length=512,
101
- )
102
- with self.torch.no_grad():
103
- outputs = self.model(**inputs)
104
- embedding = (
105
- outputs.last_hidden_state.mean(dim=1)
106
- .squeeze()
107
- .numpy()
108
- )
300
+ if self.config.backend == "openai":
301
+ embedding = self._get_openai_embedding(text)
302
+ else:
303
+ inputs = self.tokenizer(
304
+ text,
305
+ return_tensors="pt",
306
+ padding=True,
307
+ truncation=True,
308
+ max_length=self.config.max_sequence_length,
309
+ )
310
+ # Move inputs to device
311
+ inputs = {
312
+ k: v.to(self.device) for k, v in inputs.items()
313
+ }
314
+
315
+ with self.torch.no_grad():
316
+ outputs = self.model(**inputs)
317
+ embedding = (
318
+ outputs.last_hidden_state.mean(dim=1)
319
+ .squeeze()
320
+ .cpu()
321
+ .numpy()
322
+ )
323
+
324
+ # Cache the embedding
325
+ self._cache_embedding(text, embedding)
326
+
109
327
  logger.debug("Embedding generated successfully")
110
328
  return embedding
111
329
  except Exception as e:
112
330
  logger.error(f"Error generating embedding: {str(e)}")
113
331
  raise
114
332
 
333
+ def get_embeddings_batch(self, texts: List[str]) -> np.ndarray:
334
+ """
335
+ Generate embeddings for multiple texts in batch for improved efficiency.
336
+
337
+ This method processes texts in batches, utilizing the cache where possible
338
+ and generating new embeddings only for uncached texts.
339
+
340
+ Args:
341
+ texts (List[str]): List of texts to generate embeddings for
342
+
343
+ Returns:
344
+ np.ndarray: Array of embeddings, one for each input text
345
+
346
+ Raises:
347
+ Exception: If batch processing fails
348
+ """
349
+ embeddings = []
350
+ batch_texts = []
351
+
352
+ for text in texts:
353
+ cached_embedding = self._get_cached_embedding(text)
354
+ if cached_embedding is not None:
355
+ embeddings.append(cached_embedding)
356
+ else:
357
+ batch_texts.append(text)
358
+
359
+ if batch_texts:
360
+ if self.config.backend == "openai":
361
+ batch_embeddings = self._get_openai_embeddings_batch(
362
+ batch_texts
363
+ )
364
+ for text, embedding in zip(
365
+ batch_texts, batch_embeddings
366
+ ):
367
+ self._cache_embedding(text, embedding)
368
+ embeddings.append(embedding)
369
+ else:
370
+ for i in range(
371
+ 0, len(batch_texts), self.config.batch_size
372
+ ):
373
+ batch = batch_texts[
374
+ i : i + self.config.batch_size
375
+ ]
376
+ inputs = self.tokenizer(
377
+ batch,
378
+ return_tensors="pt",
379
+ padding=True,
380
+ truncation=True,
381
+ max_length=self.config.max_sequence_length,
382
+ )
383
+ inputs = {
384
+ k: v.to(self.device)
385
+ for k, v in inputs.items()
386
+ }
387
+
388
+ with self.torch.no_grad():
389
+ outputs = self.model(**inputs)
390
+ batch_embeddings = (
391
+ outputs.last_hidden_state.mean(dim=1)
392
+ .cpu()
393
+ .numpy()
394
+ )
395
+
396
+ for text, embedding in zip(
397
+ batch, batch_embeddings
398
+ ):
399
+ self._cache_embedding(text, embedding)
400
+ embeddings.append(embedding)
401
+
402
+ return np.array(embeddings)
403
+
115
404
  def add_swarm_type(self, swarm_type: SwarmType):
116
405
  """
117
- Adds a swarm type to the list of swarm types, generating an embedding for its description.
406
+ Adds a swarm type to the matcher's registry.
407
+
408
+ Generates and stores an embedding for the swarm type's description.
118
409
 
119
410
  Args:
120
- swarm_type (SwarmType): The swarm type to add.
411
+ swarm_type (SwarmType): The swarm type to add
412
+
413
+ Raises:
414
+ Exception: If embedding generation or storage fails
121
415
  """
122
416
  logger.debug(f"Adding swarm type: {swarm_type.name}")
123
417
  try:
@@ -133,36 +427,104 @@ class SwarmMatcher:
133
427
 
134
428
  def find_best_match(self, task: str) -> Tuple[str, float]:
135
429
  """
136
- Finds the best match for a given task among the registered swarm types.
430
+ Finds the best matching swarm type for a given task.
431
+
432
+ Uses semantic similarity to compare the task against all registered swarm types
433
+ and returns the best match along with its confidence score.
137
434
 
138
435
  Args:
139
- task (str): The task for which to find the best match.
436
+ task (str): The task description to match
140
437
 
141
438
  Returns:
142
- Tuple[str, float]: A tuple containing the name of the best matching swarm type and the score.
439
+ Tuple[str, float]: A tuple containing:
440
+ - The name of the best matching swarm type
441
+ - The similarity score (between 0 and 1)
442
+
443
+ Raises:
444
+ Exception: If matching process fails
143
445
  """
144
446
  logger.debug(f"Finding best match for task: {task[:50]}...")
145
447
  try:
146
448
  task_embedding = self.get_embedding(task)
147
449
  best_match = None
148
450
  best_score = -float("inf")
149
- for swarm_type in self.swarm_types:
150
- score = np.dot(
151
- task_embedding, np.array(swarm_type.embedding)
451
+
452
+ # Get all swarm type embeddings in batch
453
+ swarm_descriptions = [
454
+ st.description for st in self.swarm_types
455
+ ]
456
+ swarm_embeddings = self.get_embeddings_batch(
457
+ swarm_descriptions
458
+ )
459
+
460
+ # Calculate similarity scores in batch
461
+ scores = np.dot(task_embedding, swarm_embeddings.T)
462
+ best_idx = np.argmax(scores)
463
+ best_score = float(scores[best_idx])
464
+ best_match = self.swarm_types[best_idx]
465
+
466
+ if best_score < self.config.similarity_threshold:
467
+ logger.warning(
468
+ f"Best match score {best_score} is below threshold {self.config.similarity_threshold}"
152
469
  )
153
- if score > best_score:
154
- best_score = score
155
- best_match = swarm_type
470
+
156
471
  logger.info(
157
472
  f"Best match for task: {best_match.name} (score: {best_score})"
158
473
  )
159
- return best_match.name, float(best_score)
474
+ return best_match.name, best_score
160
475
  except Exception as e:
161
476
  logger.error(
162
477
  f"Error finding best match for task: {str(e)}"
163
478
  )
164
479
  raise
165
480
 
481
+ def find_top_k_matches(
482
+ self, task: str, k: int = 3
483
+ ) -> List[Tuple[str, float]]:
484
+ """
485
+ Finds the top k matching swarm types for a given task.
486
+
487
+ Returns all matches that exceed the similarity threshold, sorted by score.
488
+
489
+ Args:
490
+ task (str): The task for which to find matches.
491
+ k (int): Number of top matches to return.
492
+
493
+ Returns:
494
+ List[Tuple[str, float]]: List of tuples containing swarm names and their scores.
495
+ """
496
+ logger.debug(
497
+ f"Finding top {k} matches for task: {task[:50]}..."
498
+ )
499
+ try:
500
+ task_embedding = self.get_embedding(task)
501
+ swarm_descriptions = [
502
+ st.description for st in self.swarm_types
503
+ ]
504
+ swarm_embeddings = self.get_embeddings_batch(
505
+ swarm_descriptions
506
+ )
507
+
508
+ # Calculate similarity scores in batch
509
+ scores = np.dot(task_embedding, swarm_embeddings.T)
510
+ top_k_indices = np.argsort(scores)[-k:][::-1]
511
+
512
+ results = []
513
+ for idx in top_k_indices:
514
+ score = float(scores[idx])
515
+ if score >= self.config.similarity_threshold:
516
+ results.append(
517
+ (self.swarm_types[idx].name, score)
518
+ )
519
+
520
+ logger.info(
521
+ f"Found {len(results)} matches above threshold"
522
+ )
523
+ return results
524
+ except Exception as e:
525
+ logger.error(f"Error finding top matches: {str(e)}")
526
+ raise
527
+
166
528
  def auto_select_swarm(self, task: str) -> str:
167
529
  """
168
530
  Automatically selects the best swarm type for a given task based on their descriptions.
@@ -224,56 +586,86 @@ class SwarmMatcher:
224
586
  logger.error(f"Error loading swarm types: {str(e)}")
225
587
  raise
226
588
 
589
+ def initialize_swarm_types(self):
590
+ logger.debug("Initializing swarm types")
591
+ swarm_types = [
592
+ SwarmType(
593
+ name="AgentRearrange",
594
+ description="Optimize agent order and rearrange flow for multi-step tasks, ensuring efficient task allocation and minimizing bottlenecks. Keywords: orchestration, coordination, pipeline optimization, task scheduling, resource allocation, workflow management, agent organization, process optimization",
595
+ ),
596
+ SwarmType(
597
+ name="MixtureOfAgents",
598
+ description="Combine diverse expert agents for comprehensive analysis, fostering a collaborative approach to problem-solving and leveraging individual strengths. Keywords: multi-agent system, expert collaboration, distributed intelligence, collective problem solving, agent specialization, team coordination, hybrid approaches, knowledge synthesis",
599
+ ),
600
+ SwarmType(
601
+ name="SpreadSheetSwarm",
602
+ description="Collaborative data processing and analysis in a spreadsheet-like environment, facilitating real-time data sharing and visualization. Keywords: data analysis, tabular processing, collaborative editing, data transformation, spreadsheet operations, data visualization, real-time collaboration, structured data",
603
+ ),
604
+ SwarmType(
605
+ name="SequentialWorkflow",
606
+ description="Execute tasks in a step-by-step, sequential process workflow, ensuring a logical and methodical approach to task execution. Keywords: linear processing, waterfall methodology, step-by-step execution, ordered tasks, sequential operations, process flow, systematic approach, staged execution",
607
+ ),
608
+ SwarmType(
609
+ name="ConcurrentWorkflow",
610
+ description="Process multiple tasks or data sources concurrently in parallel, maximizing productivity and reducing processing time. Keywords: parallel processing, multi-threading, asynchronous execution, distributed computing, concurrent operations, simultaneous tasks, parallel workflows, scalable processing",
611
+ ),
612
+ SwarmType(
613
+ name="HierarchicalSwarm",
614
+ description="Organize agents in a hierarchical structure with clear reporting lines and delegation of responsibilities. Keywords: management hierarchy, organizational structure, delegation, supervision, chain of command, tiered organization, structured coordination, leadership roles",
615
+ ),
616
+ SwarmType(
617
+ name="AdaptiveSwarm",
618
+ description="Dynamically adjust agent behavior and swarm configuration based on task requirements and performance feedback. Keywords: dynamic adaptation, self-optimization, feedback loops, learning systems, flexible configuration, responsive behavior, adaptive algorithms, real-time adjustment",
619
+ ),
620
+ SwarmType(
621
+ name="ConsensusSwarm",
622
+ description="Achieve group decisions through consensus mechanisms and voting protocols among multiple agents. Keywords: group decision making, voting systems, collective intelligence, agreement protocols, democratic processes, collaborative decisions, consensus building",
623
+ ),
624
+ SwarmType(
625
+ name="DeepResearchSwarm",
626
+ description="Conduct in-depth research and analysis by coordinating multiple agents to explore, synthesize, and validate information from various sources. Keywords: research methodology, information synthesis, data validation, comprehensive analysis, knowledge discovery, systematic investigation",
627
+ ),
628
+ SwarmType(
629
+ name="CouncilAsAJudge",
630
+ description="Evaluate and judge solutions or decisions through a council of expert agents acting as arbitrators. Keywords: evaluation, judgment, arbitration, expert assessment, quality control, decision validation, peer review, consensus building",
631
+ ),
632
+ SwarmType(
633
+ name="MALT",
634
+ description="Multi-Agent Language Tasks framework for coordinating language-based operations across multiple specialized agents. Keywords: language processing, task coordination, linguistic analysis, communication protocols, semantic understanding, natural language tasks",
635
+ ),
636
+ SwarmType(
637
+ name="GroupChat",
638
+ description="Enable dynamic multi-agent conversations and collaborative problem-solving through structured group discussions. Keywords: collaborative dialogue, group interaction, team communication, collective problem-solving, discussion facilitation, knowledge sharing",
639
+ ),
640
+ SwarmType(
641
+ name="MultiAgentRouter",
642
+ description="Intelligently route tasks and information between agents based on their specializations and current workload. Keywords: task distribution, load balancing, intelligent routing, agent specialization, workflow optimization, resource allocation",
643
+ ),
644
+ SwarmType(
645
+ name="MajorityVoting",
646
+ description="Make decisions through democratic voting mechanisms where multiple agents contribute their opinions and votes. Keywords: collective decision-making, democratic process, vote aggregation, opinion pooling, consensus building, collaborative choice",
647
+ ),
648
+ ]
649
+
650
+ try:
651
+ for swarm_type in swarm_types:
652
+ self.add_swarm_type(swarm_type)
653
+ except Exception as e:
654
+ logger.error(f"Error initializing swarm types: {str(e)}")
655
+ raise
656
+
227
657
 
228
- def initialize_swarm_types(matcher: SwarmMatcher):
229
- logger.debug("Initializing swarm types")
230
- swarm_types = [
231
- SwarmType(
232
- name="AgentRearrange",
233
- description="Optimize agent order and rearrange flow for multi-step tasks, ensuring efficient task allocation and minimizing bottlenecks. Keywords: orchestration, coordination, pipeline optimization, task scheduling, resource allocation, workflow management, agent organization, process optimization",
234
- ),
235
- SwarmType(
236
- name="MixtureOfAgents",
237
- description="Combine diverse expert agents for comprehensive analysis, fostering a collaborative approach to problem-solving and leveraging individual strengths. Keywords: multi-agent system, expert collaboration, distributed intelligence, collective problem solving, agent specialization, team coordination, hybrid approaches, knowledge synthesis",
238
- ),
239
- SwarmType(
240
- name="SpreadSheetSwarm",
241
- description="Collaborative data processing and analysis in a spreadsheet-like environment, facilitating real-time data sharing and visualization. Keywords: data analysis, tabular processing, collaborative editing, data transformation, spreadsheet operations, data visualization, real-time collaboration, structured data",
242
- ),
243
- SwarmType(
244
- name="SequentialWorkflow",
245
- description="Execute tasks in a step-by-step, sequential process workflow, ensuring a logical and methodical approach to task execution. Keywords: linear processing, waterfall methodology, step-by-step execution, ordered tasks, sequential operations, process flow, systematic approach, staged execution",
246
- ),
247
- SwarmType(
248
- name="ConcurrentWorkflow",
249
- description="Process multiple tasks or data sources concurrently in parallel, maximizing productivity and reducing processing time. Keywords: parallel processing, multi-threading, asynchronous execution, distributed computing, concurrent operations, simultaneous tasks, parallel workflows, scalable processing",
250
- ),
251
- # SwarmType(
252
- # name="HierarchicalSwarm",
253
- # description="Organize agents in a hierarchical structure with clear reporting lines and delegation of responsibilities. Keywords: management hierarchy, organizational structure, delegation, supervision, chain of command, tiered organization, structured coordination",
254
- # ),
255
- # SwarmType(
256
- # name="AdaptiveSwarm",
257
- # description="Dynamically adjust agent behavior and swarm configuration based on task requirements and performance feedback. Keywords: dynamic adaptation, self-optimization, feedback loops, learning systems, flexible configuration, responsive behavior, adaptive algorithms",
258
- # ),
259
- # SwarmType(
260
- # name="ConsensusSwarm",
261
- # description="Achieve group decisions through consensus mechanisms and voting protocols among multiple agents. Keywords: group decision making, voting systems, collective intelligence, agreement protocols, democratic processes, collaborative decisions",
262
- # ),
263
- ]
264
-
265
- for swarm_type in swarm_types:
266
- matcher.add_swarm_type(swarm_type)
267
- logger.debug("Swarm types initialized")
268
-
269
-
270
- def swarm_matcher(task: str, *args, **kwargs):
658
+ def swarm_matcher(task: Union[str, List[str]], *args, **kwargs):
271
659
  """
272
660
  Runs the SwarmMatcher example with predefined tasks and swarm types.
273
661
  """
662
+ if isinstance(task, list):
663
+ task = "".join(task)
664
+ else:
665
+ task = task
666
+
274
667
  config = SwarmMatcherConfig()
275
668
  matcher = SwarmMatcher(config)
276
- initialize_swarm_types(matcher)
277
669
 
278
670
  # matcher.save_swarm_types(f"swarm_logs/{uuid4().hex}.json")
279
671
 
@@ -284,319 +676,18 @@ def swarm_matcher(task: str, *args, **kwargs):
284
676
  return swarm_type
285
677
 
286
678
 
287
- # from typing import List, Tuple, Dict
288
- # from pydantic import BaseModel, Field
289
- # from loguru import logger
290
- # from uuid import uuid4
291
- # import chromadb
292
- # import json
293
- # from tenacity import retry, stop_after_attempt, wait_exponential
294
-
295
-
296
- # class SwarmType(BaseModel):
297
- # """A swarm type with its name, description and optional metadata"""
298
-
299
- # id: str = Field(default_factory=lambda: str(uuid4()))
300
- # name: str
301
- # description: str
302
- # metadata: Dict = Field(default_factory=dict)
303
-
304
-
305
- # class SwarmMatcherConfig(BaseModel):
306
- # """Configuration for the SwarmMatcher"""
307
-
308
- # collection_name: str = "swarm_types"
309
- # distance_metric: str = "cosine" # or "l2" or "ip"
310
- # embedding_function: str = (
311
- # "sentence-transformers/all-mpnet-base-v2" # Better model than MiniLM
312
- # )
313
- # persist_directory: str = "./chroma_db"
314
-
315
-
316
- # class SwarmMatcher:
317
- # """
318
- # An improved swarm matcher that uses ChromaDB for better vector similarity search.
319
- # Features:
320
- # - Persistent storage of embeddings
321
- # - Better vector similarity search with multiple distance metrics
322
- # - Improved embedding model
323
- # - Metadata filtering capabilities
324
- # - Batch operations support
325
- # """
326
-
327
- # def __init__(self, config: SwarmMatcherConfig):
328
- # """Initialize the improved swarm matcher"""
329
- # logger.add("swarm_matcher.log", rotation="100 MB")
330
- # self.config = config
331
-
332
- # # Initialize ChromaDB client with persistence
333
- # self.chroma_client = chromadb.Client()
334
-
335
- # # Get or create collection
336
- # try:
337
- # self.collection = self.chroma_client.get_collection(
338
- # name=config.collection_name,
339
- # )
340
- # except ValueError:
341
- # self.collection = self.chroma_client.create_collection(
342
- # name=config.collection_name,
343
- # metadata={"hnsw:space": config.distance_metric},
344
- # )
345
-
346
- # logger.info(
347
- # f"Initialized SwarmMatcher with collection '{config.collection_name}'"
348
- # )
349
-
350
- # def add_swarm_type(self, swarm_type: SwarmType) -> None:
351
- # """Add a single swarm type to the collection"""
352
- # try:
353
- # self.collection.add(
354
- # ids=[swarm_type.id],
355
- # documents=[swarm_type.description],
356
- # metadatas=[
357
- # {"name": swarm_type.name, **swarm_type.metadata}
358
- # ],
359
- # )
360
- # logger.info(f"Added swarm type: {swarm_type.name}")
361
- # except Exception as e:
362
- # logger.error(
363
- # f"Error adding swarm type {swarm_type.name}: {str(e)}"
364
- # )
365
- # raise
366
-
367
- # def add_swarm_types(self, swarm_types: List[SwarmType]) -> None:
368
- # """Add multiple swarm types in batch"""
369
- # try:
370
- # self.collection.add(
371
- # ids=[st.id for st in swarm_types],
372
- # documents=[st.description for st in swarm_types],
373
- # metadatas=[
374
- # {"name": st.name, **st.metadata}
375
- # for st in swarm_types
376
- # ],
377
- # )
378
- # logger.info(f"Added {len(swarm_types)} swarm types")
379
- # except Exception as e:
380
- # logger.error(
381
- # f"Error adding swarm types in batch: {str(e)}"
382
- # )
383
- # raise
384
-
385
- # @retry(
386
- # stop=stop_after_attempt(3),
387
- # wait=wait_exponential(multiplier=1, min=4, max=10),
388
- # )
389
- # def find_best_matches(
390
- # self,
391
- # task: str,
392
- # n_results: int = 3,
393
- # score_threshold: float = 0.7,
394
- # ) -> List[Tuple[str, float]]:
395
- # """
396
- # Find the best matching swarm types for a given task
397
- # Returns multiple matches with their scores
398
- # """
399
- # try:
400
- # results = self.collection.query(
401
- # query_texts=[task],
402
- # n_results=n_results,
403
- # include=["metadatas", "distances"],
404
- # )
405
-
406
- # matches = []
407
- # for metadata, distance in zip(
408
- # results["metadatas"][0], results["distances"][0]
409
- # ):
410
- # # Convert distance to similarity score (1 - normalized_distance)
411
- # score = 1 - (
412
- # distance / 2
413
- # ) # Normalize cosine distance to [0,1]
414
- # if score >= score_threshold:
415
- # matches.append((metadata["name"], score))
416
-
417
- # logger.info(f"Found {len(matches)} matches for task")
418
- # return matches
419
-
420
- # except Exception as e:
421
- # logger.error(f"Error finding matches for task: {str(e)}")
422
- # raise
423
-
424
- # def auto_select_swarm(self, task: str) -> str:
425
- # """
426
- # Automatically select the best swarm type for a task
427
- # Returns only the top match
428
- # """
429
- # matches = self.find_best_matches(task, n_results=1)
430
- # if not matches:
431
- # logger.warning("No suitable matches found for task")
432
- # return "SequentialWorkflow" # Default fallback
433
-
434
- # best_match, score = matches[0]
435
- # logger.info(
436
- # f"Selected swarm type '{best_match}' with confidence {score:.3f}"
437
- # )
438
- # return best_match
439
-
440
- # def run_multiple(self, tasks: List[str]) -> List[str]:
441
- # """Process multiple tasks in batch"""
442
- # return [self.auto_select_swarm(task) for task in tasks]
443
-
444
- # def save_swarm_types(self, filename: str) -> None:
445
- # """Export swarm types to JSON"""
446
- # try:
447
- # all_data = self.collection.get(
448
- # include=["metadatas", "documents"]
449
- # )
450
- # swarm_types = [
451
- # SwarmType(
452
- # id=id_,
453
- # name=metadata["name"],
454
- # description=document,
455
- # metadata={
456
- # k: v
457
- # for k, v in metadata.items()
458
- # if k != "name"
459
- # },
460
- # )
461
- # for id_, metadata, document in zip(
462
- # all_data["ids"],
463
- # all_data["metadatas"],
464
- # all_data["documents"],
465
- # )
466
- # ]
467
-
468
- # with open(filename, "w") as f:
469
- # json.dump(
470
- # [st.dict() for st in swarm_types], f, indent=2
471
- # )
472
- # logger.info(f"Saved swarm types to {filename}")
473
- # except Exception as e:
474
- # logger.error(f"Error saving swarm types: {str(e)}")
475
- # raise
476
-
477
- # def load_swarm_types(self, filename: str) -> None:
478
- # """Import swarm types from JSON"""
479
- # try:
480
- # with open(filename, "r") as f:
481
- # swarm_types_data = json.load(f)
482
- # swarm_types = [SwarmType(**st) for st in swarm_types_data]
483
- # self.add_swarm_types(swarm_types)
484
- # logger.info(f"Loaded swarm types from {filename}")
485
- # except Exception as e:
486
- # logger.error(f"Error loading swarm types: {str(e)}")
487
- # raise
488
-
489
-
490
- # def initialize_default_swarm_types(matcher: SwarmMatcher) -> None:
491
- # """Initialize the matcher with default swarm types"""
492
- # swarm_types = [
493
- # SwarmType(
494
- # name="AgentRearrange",
495
- # description="""
496
- # Optimize agent order and rearrange flow for multi-step tasks, ensuring efficient task allocation
497
- # and minimizing bottlenecks. Specialized in orchestration, coordination, pipeline optimization,
498
- # task scheduling, resource allocation, workflow management, agent organization, and process optimization.
499
- # Best for tasks requiring complex agent interactions and workflow optimization.
500
- # """,
501
- # metadata={
502
- # "category": "optimization",
503
- # "complexity": "high",
504
- # },
505
- # ),
506
- # SwarmType(
507
- # name="MixtureOfAgents",
508
- # description="""
509
- # Combine diverse expert agents for comprehensive analysis, fostering a collaborative approach
510
- # to problem-solving and leveraging individual strengths. Focuses on multi-agent systems,
511
- # expert collaboration, distributed intelligence, collective problem solving, agent specialization,
512
- # team coordination, hybrid approaches, and knowledge synthesis. Ideal for complex problems
513
- # requiring multiple areas of expertise.
514
- # """,
515
- # metadata={
516
- # "category": "collaboration",
517
- # "complexity": "high",
518
- # },
519
- # ),
520
- # SwarmType(
521
- # name="SpreadSheetSwarm",
522
- # description="""
523
- # Collaborative data processing and analysis in a spreadsheet-like environment, facilitating
524
- # real-time data sharing and visualization. Specializes in data analysis, tabular processing,
525
- # collaborative editing, data transformation, spreadsheet operations, data visualization,
526
- # real-time collaboration, and structured data handling. Perfect for data-intensive tasks
527
- # requiring structured analysis.
528
- # """,
529
- # metadata={
530
- # "category": "data_processing",
531
- # "complexity": "medium",
532
- # },
533
- # ),
534
- # SwarmType(
535
- # name="SequentialWorkflow",
536
- # description="""
537
- # Execute tasks in a step-by-step, sequential process workflow, ensuring a logical and methodical
538
- # approach to task execution. Focuses on linear processing, waterfall methodology, step-by-step
539
- # execution, ordered tasks, sequential operations, process flow, systematic approach, and staged
540
- # execution. Best for tasks requiring strict order and dependencies.
541
- # """,
542
- # metadata={"category": "workflow", "complexity": "low"},
543
- # ),
544
- # SwarmType(
545
- # name="ConcurrentWorkflow",
546
- # description="""
547
- # Process multiple tasks or data sources concurrently in parallel, maximizing productivity
548
- # and reducing processing time. Specializes in parallel processing, multi-threading,
549
- # asynchronous execution, distributed computing, concurrent operations, simultaneous tasks,
550
- # parallel workflows, and scalable processing. Ideal for independent tasks that can be
551
- # processed simultaneously.
552
- # """,
553
- # metadata={"category": "workflow", "complexity": "medium"},
554
- # ),
555
- # ]
556
-
557
- # matcher.add_swarm_types(swarm_types)
558
- # logger.info("Initialized default swarm types")
559
-
560
-
561
- # def create_swarm_matcher(
562
- # persist_dir: str = "./chroma_db",
563
- # collection_name: str = "swarm_types",
564
- # ) -> SwarmMatcher:
565
- # """Convenience function to create and initialize a swarm matcher"""
679
+ # # Example usage
680
+ # if __name__ == "__main__":
681
+ # # Create configuration
566
682
  # config = SwarmMatcherConfig(
567
- # persist_directory=persist_dir, collection_name=collection_name
683
+ # backend="openai", # Using local embeddings for this example
684
+ # similarity_threshold=0.6, # Increase threshold for more strict matching
685
+ # cache_embeddings=True,
568
686
  # )
687
+
688
+ # # Initialize matcher
569
689
  # matcher = SwarmMatcher(config)
570
- # initialize_default_swarm_types(matcher)
571
- # return matcher
572
690
 
691
+ # task = "I need to concurrently run 1000 tasks"
573
692
 
574
- # # Example usage
575
- # def swarm_matcher(task: str) -> str:
576
- # # Create and initialize matcher
577
- # matcher = create_swarm_matcher()
578
-
579
- # swarm_type = matcher.auto_select_swarm(task)
580
- # print(f"Task: {task}\nSelected Swarm: {swarm_type}\n")
581
-
582
- # return swarm_type
583
-
584
-
585
- # # # Example usage
586
- # # if __name__ == "__main__":
587
- # # # Create and initialize matcher
588
- # # matcher = create_swarm_matcher()
589
-
590
- # # # Example tasks
591
- # # tasks = [
592
- # # "Analyze this spreadsheet of sales data and create visualizations",
593
- # # "Coordinate multiple AI agents to solve a complex problem",
594
- # # "Process these tasks one after another in a specific order",
595
- # # "Write multiple blog posts about the latest advancements in swarm intelligence all at once",
596
- # # "Write a blog post about the latest advancements in swarm intelligence",
597
- # # ]
598
-
599
- # # # Process tasks
600
- # # for task in tasks:
601
- # # swarm_type = matcher.auto_select_swarm(task)
602
- # # print(f"Task: {task}\nSelected Swarm: {swarm_type}\n")
693
+ # print(matcher.auto_select_swarm(task))