swarms 7.8.4__py3-none-any.whl → 7.8.8__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 (58) 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/prompt.py +0 -3
  13. swarms/schemas/agent_completion_response.py +71 -0
  14. swarms/schemas/agent_rag_schema.py +7 -0
  15. swarms/schemas/conversation_schema.py +9 -0
  16. swarms/schemas/llm_agent_schema.py +99 -81
  17. swarms/schemas/swarms_api_schemas.py +164 -0
  18. swarms/structs/__init__.py +14 -11
  19. swarms/structs/agent.py +219 -199
  20. swarms/structs/agent_rag_handler.py +685 -0
  21. swarms/structs/base_swarm.py +2 -1
  22. swarms/structs/conversation.py +608 -87
  23. swarms/structs/csv_to_agent.py +153 -100
  24. swarms/structs/deep_research_swarm.py +197 -193
  25. swarms/structs/dynamic_conversational_swarm.py +18 -7
  26. swarms/structs/hiearchical_swarm.py +1 -1
  27. swarms/structs/hybrid_hiearchical_peer_swarm.py +2 -18
  28. swarms/structs/image_batch_processor.py +261 -0
  29. swarms/structs/interactive_groupchat.py +356 -0
  30. swarms/structs/ma_blocks.py +75 -0
  31. swarms/structs/majority_voting.py +1 -1
  32. swarms/structs/mixture_of_agents.py +1 -1
  33. swarms/structs/multi_agent_router.py +3 -2
  34. swarms/structs/rearrange.py +3 -3
  35. swarms/structs/sequential_workflow.py +3 -3
  36. swarms/structs/swarm_matcher.py +500 -411
  37. swarms/structs/swarm_router.py +15 -97
  38. swarms/structs/swarming_architectures.py +1 -1
  39. swarms/tools/mcp_client_call.py +3 -0
  40. swarms/utils/__init__.py +10 -2
  41. swarms/utils/check_all_model_max_tokens.py +43 -0
  42. swarms/utils/generate_keys.py +0 -27
  43. swarms/utils/history_output_formatter.py +5 -20
  44. swarms/utils/litellm_wrapper.py +208 -60
  45. swarms/utils/output_types.py +24 -0
  46. swarms/utils/vllm_wrapper.py +5 -6
  47. swarms/utils/xml_utils.py +37 -2
  48. {swarms-7.8.4.dist-info → swarms-7.8.8.dist-info}/METADATA +31 -55
  49. {swarms-7.8.4.dist-info → swarms-7.8.8.dist-info}/RECORD +53 -48
  50. swarms/structs/multi_agent_collab.py +0 -242
  51. swarms/structs/output_types.py +0 -6
  52. swarms/utils/markdown_message.py +0 -21
  53. swarms/utils/visualizer.py +0 -510
  54. swarms/utils/wrapper_clusterop.py +0 -127
  55. /swarms/{tools → schemas}/tool_schema_base_model.py +0 -0
  56. {swarms-7.8.4.dist-info → swarms-7.8.8.dist-info}/LICENSE +0 -0
  57. {swarms-7.8.4.dist-info → swarms-7.8.8.dist-info}/WHEEL +0 -0
  58. {swarms-7.8.4.dist-info → swarms-7.8.8.dist-info}/entry_points.txt +0 -0
@@ -1,8 +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
- from pydantic import BaseModel, Field
5
- from tenacity import retry, stop_after_attempt, wait_exponential
5
+ import numpy as np
6
+ from pydantic import BaseModel, Field, field_validator
7
+ from pydantic.v1 import validator
8
+ from litellm import embedding
6
9
 
7
10
  from swarms.utils.auto_download_check_packages import (
8
11
  auto_check_and_download_package,
@@ -20,18 +23,75 @@ class SwarmType(BaseModel):
20
23
  )
21
24
 
22
25
 
26
+ api_key = os.getenv("OPENAI_API_KEY")
27
+
28
+
23
29
  class SwarmMatcherConfig(BaseModel):
24
- model_name: str = "sentence-transformers/all-MiniLM-L6-v2"
25
- embedding_dim: int = (
26
- 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
27
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
28
80
 
29
81
 
30
82
  class SwarmMatcher:
31
83
  """
32
- A class for matching tasks to swarm types based on their descriptions.
33
- It utilizes a transformer model to generate embeddings for task and swarm type descriptions,
34
- 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
35
95
  """
36
96
 
37
97
  def __init__(self, config: SwarmMatcherConfig):
@@ -39,15 +99,35 @@ class SwarmMatcher:
39
99
  Initializes the SwarmMatcher with a configuration.
40
100
 
41
101
  Args:
42
- 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
43
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
44
120
 
121
+ def _setup_dependencies(self):
122
+ """Set up required dependencies for the SwarmMatcher."""
45
123
  try:
124
+ import numpy as np
46
125
  import torch
47
126
  except ImportError:
48
127
  auto_check_and_download_package(
49
128
  "torch", package_manager="pip", upgrade=True
50
129
  )
130
+ import numpy as np
51
131
  import torch
52
132
 
53
133
  try:
@@ -59,65 +139,279 @@ class SwarmMatcher:
59
139
  import transformers
60
140
 
61
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."""
62
191
  try:
63
- self.config = config
64
- self.tokenizer = (
65
- transformers.AutoTokenizer.from_pretrained(
66
- 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"
67
201
  )
68
- )
69
- self.model = transformers.AutoModel.from_pretrained(
70
- config.model_name
71
- )
72
- self.swarm_types: List[SwarmType] = []
73
- 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
74
227
  except Exception as e:
75
- logger.error(f"Error initializing SwarmMatcher: {str(e)}")
228
+ logger.error(f"Error getting OpenAI embedding: {str(e)}")
76
229
  raise
77
230
 
78
- @retry(
79
- stop=stop_after_attempt(3),
80
- wait=wait_exponential(multiplier=1, min=4, max=10),
81
- )
82
- def get_embedding(self, text: str):
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
+ )
275
+ raise
276
+
277
+ def get_embedding(self, text: str) -> np.ndarray:
83
278
  """
84
279
  Generates an embedding for a given text using the configured model.
85
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
+
86
284
  Args:
87
- text (str): The text for which to generate an embedding.
285
+ text (str): The text for which to generate an embedding
88
286
 
89
287
  Returns:
90
- 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
91
292
  """
293
+ # Check cache first
294
+ cached_embedding = self._get_cached_embedding(text)
295
+ if cached_embedding is not None:
296
+ return cached_embedding
92
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,38 +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.
143
- """
144
- import numpy as np
439
+ Tuple[str, float]: A tuple containing:
440
+ - The name of the best matching swarm type
441
+ - The similarity score (between 0 and 1)
145
442
 
443
+ Raises:
444
+ Exception: If matching process fails
445
+ """
146
446
  logger.debug(f"Finding best match for task: {task[:50]}...")
147
447
  try:
148
448
  task_embedding = self.get_embedding(task)
149
449
  best_match = None
150
450
  best_score = -float("inf")
151
- for swarm_type in self.swarm_types:
152
- score = np.dot(
153
- 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}"
154
469
  )
155
- if score > best_score:
156
- best_score = score
157
- best_match = swarm_type
470
+
158
471
  logger.info(
159
472
  f"Best match for task: {best_match.name} (score: {best_score})"
160
473
  )
161
- return best_match.name, float(best_score)
474
+ return best_match.name, best_score
162
475
  except Exception as e:
163
476
  logger.error(
164
477
  f"Error finding best match for task: {str(e)}"
165
478
  )
166
479
  raise
167
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
+
168
528
  def auto_select_swarm(self, task: str) -> str:
169
529
  """
170
530
  Automatically selects the best swarm type for a given task based on their descriptions.
@@ -226,56 +586,86 @@ class SwarmMatcher:
226
586
  logger.error(f"Error loading swarm types: {str(e)}")
227
587
  raise
228
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
+
229
657
 
230
- def initialize_swarm_types(matcher: SwarmMatcher):
231
- logger.debug("Initializing swarm types")
232
- swarm_types = [
233
- SwarmType(
234
- name="AgentRearrange",
235
- 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",
236
- ),
237
- SwarmType(
238
- name="MixtureOfAgents",
239
- 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",
240
- ),
241
- SwarmType(
242
- name="SpreadSheetSwarm",
243
- 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",
244
- ),
245
- SwarmType(
246
- name="SequentialWorkflow",
247
- 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",
248
- ),
249
- SwarmType(
250
- name="ConcurrentWorkflow",
251
- 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",
252
- ),
253
- # SwarmType(
254
- # name="HierarchicalSwarm",
255
- # 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",
256
- # ),
257
- # SwarmType(
258
- # name="AdaptiveSwarm",
259
- # 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",
260
- # ),
261
- # SwarmType(
262
- # name="ConsensusSwarm",
263
- # 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",
264
- # ),
265
- ]
266
-
267
- for swarm_type in swarm_types:
268
- matcher.add_swarm_type(swarm_type)
269
- logger.debug("Swarm types initialized")
270
-
271
-
272
- def swarm_matcher(task: str, *args, **kwargs):
658
+ def swarm_matcher(task: Union[str, List[str]], *args, **kwargs):
273
659
  """
274
660
  Runs the SwarmMatcher example with predefined tasks and swarm types.
275
661
  """
662
+ if isinstance(task, list):
663
+ task = "".join(task)
664
+ else:
665
+ task = task
666
+
276
667
  config = SwarmMatcherConfig()
277
668
  matcher = SwarmMatcher(config)
278
- initialize_swarm_types(matcher)
279
669
 
280
670
  # matcher.save_swarm_types(f"swarm_logs/{uuid4().hex}.json")
281
671
 
@@ -286,319 +676,18 @@ def swarm_matcher(task: str, *args, **kwargs):
286
676
  return swarm_type
287
677
 
288
678
 
289
- # from typing import List, Tuple, Dict
290
- # from pydantic import BaseModel, Field
291
- # from loguru import logger
292
- # from uuid import uuid4
293
- # import chromadb
294
- # import json
295
- # from tenacity import retry, stop_after_attempt, wait_exponential
296
-
297
-
298
- # class SwarmType(BaseModel):
299
- # """A swarm type with its name, description and optional metadata"""
300
-
301
- # id: str = Field(default_factory=lambda: str(uuid4()))
302
- # name: str
303
- # description: str
304
- # metadata: Dict = Field(default_factory=dict)
305
-
306
-
307
- # class SwarmMatcherConfig(BaseModel):
308
- # """Configuration for the SwarmMatcher"""
309
-
310
- # collection_name: str = "swarm_types"
311
- # distance_metric: str = "cosine" # or "l2" or "ip"
312
- # embedding_function: str = (
313
- # "sentence-transformers/all-mpnet-base-v2" # Better model than MiniLM
314
- # )
315
- # persist_directory: str = "./chroma_db"
316
-
317
-
318
- # class SwarmMatcher:
319
- # """
320
- # An improved swarm matcher that uses ChromaDB for better vector similarity search.
321
- # Features:
322
- # - Persistent storage of embeddings
323
- # - Better vector similarity search with multiple distance metrics
324
- # - Improved embedding model
325
- # - Metadata filtering capabilities
326
- # - Batch operations support
327
- # """
328
-
329
- # def __init__(self, config: SwarmMatcherConfig):
330
- # """Initialize the improved swarm matcher"""
331
- # logger.add("swarm_matcher.log", rotation="100 MB")
332
- # self.config = config
333
-
334
- # # Initialize ChromaDB client with persistence
335
- # self.chroma_client = chromadb.Client()
336
-
337
- # # Get or create collection
338
- # try:
339
- # self.collection = self.chroma_client.get_collection(
340
- # name=config.collection_name,
341
- # )
342
- # except ValueError:
343
- # self.collection = self.chroma_client.create_collection(
344
- # name=config.collection_name,
345
- # metadata={"hnsw:space": config.distance_metric},
346
- # )
347
-
348
- # logger.info(
349
- # f"Initialized SwarmMatcher with collection '{config.collection_name}'"
350
- # )
351
-
352
- # def add_swarm_type(self, swarm_type: SwarmType) -> None:
353
- # """Add a single swarm type to the collection"""
354
- # try:
355
- # self.collection.add(
356
- # ids=[swarm_type.id],
357
- # documents=[swarm_type.description],
358
- # metadatas=[
359
- # {"name": swarm_type.name, **swarm_type.metadata}
360
- # ],
361
- # )
362
- # logger.info(f"Added swarm type: {swarm_type.name}")
363
- # except Exception as e:
364
- # logger.error(
365
- # f"Error adding swarm type {swarm_type.name}: {str(e)}"
366
- # )
367
- # raise
368
-
369
- # def add_swarm_types(self, swarm_types: List[SwarmType]) -> None:
370
- # """Add multiple swarm types in batch"""
371
- # try:
372
- # self.collection.add(
373
- # ids=[st.id for st in swarm_types],
374
- # documents=[st.description for st in swarm_types],
375
- # metadatas=[
376
- # {"name": st.name, **st.metadata}
377
- # for st in swarm_types
378
- # ],
379
- # )
380
- # logger.info(f"Added {len(swarm_types)} swarm types")
381
- # except Exception as e:
382
- # logger.error(
383
- # f"Error adding swarm types in batch: {str(e)}"
384
- # )
385
- # raise
386
-
387
- # @retry(
388
- # stop=stop_after_attempt(3),
389
- # wait=wait_exponential(multiplier=1, min=4, max=10),
390
- # )
391
- # def find_best_matches(
392
- # self,
393
- # task: str,
394
- # n_results: int = 3,
395
- # score_threshold: float = 0.7,
396
- # ) -> List[Tuple[str, float]]:
397
- # """
398
- # Find the best matching swarm types for a given task
399
- # Returns multiple matches with their scores
400
- # """
401
- # try:
402
- # results = self.collection.query(
403
- # query_texts=[task],
404
- # n_results=n_results,
405
- # include=["metadatas", "distances"],
406
- # )
407
-
408
- # matches = []
409
- # for metadata, distance in zip(
410
- # results["metadatas"][0], results["distances"][0]
411
- # ):
412
- # # Convert distance to similarity score (1 - normalized_distance)
413
- # score = 1 - (
414
- # distance / 2
415
- # ) # Normalize cosine distance to [0,1]
416
- # if score >= score_threshold:
417
- # matches.append((metadata["name"], score))
418
-
419
- # logger.info(f"Found {len(matches)} matches for task")
420
- # return matches
421
-
422
- # except Exception as e:
423
- # logger.error(f"Error finding matches for task: {str(e)}")
424
- # raise
425
-
426
- # def auto_select_swarm(self, task: str) -> str:
427
- # """
428
- # Automatically select the best swarm type for a task
429
- # Returns only the top match
430
- # """
431
- # matches = self.find_best_matches(task, n_results=1)
432
- # if not matches:
433
- # logger.warning("No suitable matches found for task")
434
- # return "SequentialWorkflow" # Default fallback
435
-
436
- # best_match, score = matches[0]
437
- # logger.info(
438
- # f"Selected swarm type '{best_match}' with confidence {score:.3f}"
439
- # )
440
- # return best_match
441
-
442
- # def run_multiple(self, tasks: List[str]) -> List[str]:
443
- # """Process multiple tasks in batch"""
444
- # return [self.auto_select_swarm(task) for task in tasks]
445
-
446
- # def save_swarm_types(self, filename: str) -> None:
447
- # """Export swarm types to JSON"""
448
- # try:
449
- # all_data = self.collection.get(
450
- # include=["metadatas", "documents"]
451
- # )
452
- # swarm_types = [
453
- # SwarmType(
454
- # id=id_,
455
- # name=metadata["name"],
456
- # description=document,
457
- # metadata={
458
- # k: v
459
- # for k, v in metadata.items()
460
- # if k != "name"
461
- # },
462
- # )
463
- # for id_, metadata, document in zip(
464
- # all_data["ids"],
465
- # all_data["metadatas"],
466
- # all_data["documents"],
467
- # )
468
- # ]
469
-
470
- # with open(filename, "w") as f:
471
- # json.dump(
472
- # [st.dict() for st in swarm_types], f, indent=2
473
- # )
474
- # logger.info(f"Saved swarm types to {filename}")
475
- # except Exception as e:
476
- # logger.error(f"Error saving swarm types: {str(e)}")
477
- # raise
478
-
479
- # def load_swarm_types(self, filename: str) -> None:
480
- # """Import swarm types from JSON"""
481
- # try:
482
- # with open(filename, "r") as f:
483
- # swarm_types_data = json.load(f)
484
- # swarm_types = [SwarmType(**st) for st in swarm_types_data]
485
- # self.add_swarm_types(swarm_types)
486
- # logger.info(f"Loaded swarm types from {filename}")
487
- # except Exception as e:
488
- # logger.error(f"Error loading swarm types: {str(e)}")
489
- # raise
490
-
491
-
492
- # def initialize_default_swarm_types(matcher: SwarmMatcher) -> None:
493
- # """Initialize the matcher with default swarm types"""
494
- # swarm_types = [
495
- # SwarmType(
496
- # name="AgentRearrange",
497
- # description="""
498
- # Optimize agent order and rearrange flow for multi-step tasks, ensuring efficient task allocation
499
- # and minimizing bottlenecks. Specialized in orchestration, coordination, pipeline optimization,
500
- # task scheduling, resource allocation, workflow management, agent organization, and process optimization.
501
- # Best for tasks requiring complex agent interactions and workflow optimization.
502
- # """,
503
- # metadata={
504
- # "category": "optimization",
505
- # "complexity": "high",
506
- # },
507
- # ),
508
- # SwarmType(
509
- # name="MixtureOfAgents",
510
- # description="""
511
- # Combine diverse expert agents for comprehensive analysis, fostering a collaborative approach
512
- # to problem-solving and leveraging individual strengths. Focuses on multi-agent systems,
513
- # expert collaboration, distributed intelligence, collective problem solving, agent specialization,
514
- # team coordination, hybrid approaches, and knowledge synthesis. Ideal for complex problems
515
- # requiring multiple areas of expertise.
516
- # """,
517
- # metadata={
518
- # "category": "collaboration",
519
- # "complexity": "high",
520
- # },
521
- # ),
522
- # SwarmType(
523
- # name="SpreadSheetSwarm",
524
- # description="""
525
- # Collaborative data processing and analysis in a spreadsheet-like environment, facilitating
526
- # real-time data sharing and visualization. Specializes in data analysis, tabular processing,
527
- # collaborative editing, data transformation, spreadsheet operations, data visualization,
528
- # real-time collaboration, and structured data handling. Perfect for data-intensive tasks
529
- # requiring structured analysis.
530
- # """,
531
- # metadata={
532
- # "category": "data_processing",
533
- # "complexity": "medium",
534
- # },
535
- # ),
536
- # SwarmType(
537
- # name="SequentialWorkflow",
538
- # description="""
539
- # Execute tasks in a step-by-step, sequential process workflow, ensuring a logical and methodical
540
- # approach to task execution. Focuses on linear processing, waterfall methodology, step-by-step
541
- # execution, ordered tasks, sequential operations, process flow, systematic approach, and staged
542
- # execution. Best for tasks requiring strict order and dependencies.
543
- # """,
544
- # metadata={"category": "workflow", "complexity": "low"},
545
- # ),
546
- # SwarmType(
547
- # name="ConcurrentWorkflow",
548
- # description="""
549
- # Process multiple tasks or data sources concurrently in parallel, maximizing productivity
550
- # and reducing processing time. Specializes in parallel processing, multi-threading,
551
- # asynchronous execution, distributed computing, concurrent operations, simultaneous tasks,
552
- # parallel workflows, and scalable processing. Ideal for independent tasks that can be
553
- # processed simultaneously.
554
- # """,
555
- # metadata={"category": "workflow", "complexity": "medium"},
556
- # ),
557
- # ]
558
-
559
- # matcher.add_swarm_types(swarm_types)
560
- # logger.info("Initialized default swarm types")
561
-
562
-
563
- # def create_swarm_matcher(
564
- # persist_dir: str = "./chroma_db",
565
- # collection_name: str = "swarm_types",
566
- # ) -> SwarmMatcher:
567
- # """Convenience function to create and initialize a swarm matcher"""
679
+ # # Example usage
680
+ # if __name__ == "__main__":
681
+ # # Create configuration
568
682
  # config = SwarmMatcherConfig(
569
- # 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,
570
686
  # )
687
+
688
+ # # Initialize matcher
571
689
  # matcher = SwarmMatcher(config)
572
- # initialize_default_swarm_types(matcher)
573
- # return matcher
574
690
 
691
+ # task = "I need to concurrently run 1000 tasks"
575
692
 
576
- # # Example usage
577
- # def swarm_matcher(task: str) -> str:
578
- # # Create and initialize matcher
579
- # matcher = create_swarm_matcher()
580
-
581
- # swarm_type = matcher.auto_select_swarm(task)
582
- # print(f"Task: {task}\nSelected Swarm: {swarm_type}\n")
583
-
584
- # return swarm_type
585
-
586
-
587
- # # # Example usage
588
- # # if __name__ == "__main__":
589
- # # # Create and initialize matcher
590
- # # matcher = create_swarm_matcher()
591
-
592
- # # # Example tasks
593
- # # tasks = [
594
- # # "Analyze this spreadsheet of sales data and create visualizations",
595
- # # "Coordinate multiple AI agents to solve a complex problem",
596
- # # "Process these tasks one after another in a specific order",
597
- # # "Write multiple blog posts about the latest advancements in swarm intelligence all at once",
598
- # # "Write a blog post about the latest advancements in swarm intelligence",
599
- # # ]
600
-
601
- # # # Process tasks
602
- # # for task in tasks:
603
- # # swarm_type = matcher.auto_select_swarm(task)
604
- # # print(f"Task: {task}\nSelected Swarm: {swarm_type}\n")
693
+ # print(matcher.auto_select_swarm(task))