swarms 7.7.2__py3-none-any.whl → 7.7.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.
- swarms/prompts/ag_prompt.py +51 -19
- swarms/prompts/agent_system_prompts.py +13 -4
- swarms/prompts/multi_agent_collab_prompt.py +18 -0
- swarms/prompts/prompt.py +6 -10
- swarms/schemas/__init__.py +0 -3
- swarms/structs/__init__.py +2 -4
- swarms/structs/agent.py +201 -160
- swarms/structs/aop.py +8 -1
- swarms/structs/auto_swarm_builder.py +271 -210
- swarms/structs/conversation.py +22 -65
- swarms/structs/hiearchical_swarm.py +94 -123
- swarms/structs/hybrid_hiearchical_peer_swarm.py +1 -1
- swarms/structs/ma_utils.py +96 -0
- swarms/structs/mixture_of_agents.py +20 -103
- swarms/structs/multi_agent_router.py +32 -95
- swarms/structs/multi_model_gpu_manager.py +1447 -0
- swarms/structs/output_types.py +3 -16
- swarms/structs/stopping_conditions.py +30 -0
- swarms/structs/swarm_arange.py +18 -15
- swarms/structs/swarm_router.py +56 -4
- swarms/structs/swarming_architectures.py +576 -185
- swarms/telemetry/main.py +1 -7
- swarms/tools/mcp_client.py +209 -53
- swarms/tools/mcp_integration.py +1 -53
- swarms/utils/generate_keys.py +64 -0
- swarms/utils/history_output_formatter.py +2 -0
- {swarms-7.7.2.dist-info → swarms-7.7.4.dist-info}/METADATA +98 -263
- {swarms-7.7.2.dist-info → swarms-7.7.4.dist-info}/RECORD +31 -34
- swarms/schemas/agent_input_schema.py +0 -149
- swarms/structs/agents_available.py +0 -87
- swarms/structs/graph_swarm.py +0 -612
- swarms/structs/queue_swarm.py +0 -193
- swarms/structs/swarm_builder.py +0 -395
- swarms/structs/swarm_output_type.py +0 -23
- {swarms-7.7.2.dist-info → swarms-7.7.4.dist-info}/LICENSE +0 -0
- {swarms-7.7.2.dist-info → swarms-7.7.4.dist-info}/WHEEL +0 -0
- {swarms-7.7.2.dist-info → swarms-7.7.4.dist-info}/entry_points.txt +0 -0
swarms/structs/agent.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import concurrent.futures
|
2
1
|
import asyncio
|
3
2
|
import json
|
4
3
|
import logging
|
@@ -46,12 +45,7 @@ from swarms.structs.safe_loading import (
|
|
46
45
|
)
|
47
46
|
from swarms.telemetry.main import log_agent_data
|
48
47
|
from swarms.tools.base_tool import BaseTool
|
49
|
-
|
50
|
-
# from swarms.tools.mcp_integration import (
|
51
|
-
# MCPServerSseParams,
|
52
|
-
# batch_mcp_flow,
|
53
|
-
# mcp_flow_get_tool_schema,
|
54
|
-
# )
|
48
|
+
from swarms.tools.mcp_integration import MCPServerSseParams
|
55
49
|
from swarms.tools.tool_parse_exec import parse_and_execute_json
|
56
50
|
from swarms.utils.any_to_str import any_to_str
|
57
51
|
from swarms.utils.data_to_text import data_to_text
|
@@ -59,11 +53,18 @@ from swarms.utils.file_processing import create_file_in_folder
|
|
59
53
|
from swarms.utils.formatter import formatter
|
60
54
|
from swarms.utils.history_output_formatter import (
|
61
55
|
history_output_formatter,
|
62
|
-
HistoryOutputType,
|
63
56
|
)
|
64
57
|
from swarms.utils.litellm_tokenizer import count_tokens
|
65
58
|
from swarms.utils.litellm_wrapper import LiteLLM
|
66
59
|
from swarms.utils.pdf_to_text import pdf_to_text
|
60
|
+
from swarms.structs.output_types import OutputType
|
61
|
+
from swarms.utils.str_to_dict import str_to_dict
|
62
|
+
from swarms.tools.mcp_client import (
|
63
|
+
execute_mcp_tool,
|
64
|
+
list_tools_for_multiple_urls,
|
65
|
+
list_all,
|
66
|
+
find_and_execute_tool,
|
67
|
+
)
|
67
68
|
|
68
69
|
|
69
70
|
# Utils
|
@@ -335,7 +336,7 @@ class Agent:
|
|
335
336
|
# [Tools]
|
336
337
|
custom_tools_prompt: Optional[Callable] = None,
|
337
338
|
tool_schema: ToolUsageType = None,
|
338
|
-
output_type:
|
339
|
+
output_type: OutputType = "str-all-except-first",
|
339
340
|
function_calling_type: str = "json",
|
340
341
|
output_cleaner: Optional[Callable] = None,
|
341
342
|
function_calling_format_type: Optional[str] = "OpenAI",
|
@@ -392,7 +393,9 @@ class Agent:
|
|
392
393
|
role: agent_roles = "worker",
|
393
394
|
no_print: bool = False,
|
394
395
|
tools_list_dictionary: Optional[List[Dict[str, Any]]] = None,
|
395
|
-
|
396
|
+
mcp_servers: MCPServerSseParams = None,
|
397
|
+
mcp_url: str = None,
|
398
|
+
mcp_urls: List[str] = None,
|
396
399
|
*args,
|
397
400
|
**kwargs,
|
398
401
|
):
|
@@ -512,105 +515,93 @@ class Agent:
|
|
512
515
|
self.role = role
|
513
516
|
self.no_print = no_print
|
514
517
|
self.tools_list_dictionary = tools_list_dictionary
|
515
|
-
|
518
|
+
self.mcp_servers = mcp_servers
|
519
|
+
self.mcp_url = mcp_url
|
520
|
+
self.mcp_urls = mcp_urls
|
516
521
|
|
517
522
|
self._cached_llm = (
|
518
523
|
None # Add this line to cache the LLM instance
|
519
524
|
)
|
520
|
-
self._default_model = (
|
521
|
-
"gpt-4o-mini" # Move default model name here
|
522
|
-
)
|
523
525
|
|
526
|
+
self.short_memory = self.short_memory_init()
|
527
|
+
|
528
|
+
# Initialize the feedback
|
529
|
+
self.feedback = []
|
530
|
+
|
531
|
+
# self.init_handling()
|
532
|
+
# Define tasks as pairs of (function, condition)
|
533
|
+
# Each task will only run if its condition is True
|
534
|
+
self.setup_config()
|
535
|
+
|
536
|
+
if exists(self.docs_folder):
|
537
|
+
self.get_docs_from_doc_folders()
|
538
|
+
|
539
|
+
if exists(self.tools):
|
540
|
+
self.handle_tool_init()
|
541
|
+
|
542
|
+
if exists(self.tool_schema) or exists(self.list_base_models):
|
543
|
+
self.handle_tool_schema_ops()
|
544
|
+
|
545
|
+
if exists(self.sop) or exists(self.sop_list):
|
546
|
+
self.handle_sop_ops()
|
547
|
+
|
548
|
+
# Run sequential operations after all concurrent tasks are done
|
549
|
+
# self.agent_output = self.agent_output_model()
|
550
|
+
log_agent_data(self.to_dict())
|
551
|
+
|
552
|
+
if self.llm is None:
|
553
|
+
self.llm = self.llm_handling()
|
554
|
+
|
555
|
+
if self.mcp_url or self.mcp_servers is not None:
|
556
|
+
self.add_mcp_tools_to_memory()
|
557
|
+
|
558
|
+
def short_memory_init(self):
|
524
559
|
if (
|
525
560
|
self.agent_name is not None
|
526
561
|
or self.agent_description is not None
|
527
562
|
):
|
528
|
-
prompt = f"Your Name: {self.agent_name} \n\n Your Description: {self.agent_description} \n\n {system_prompt}"
|
563
|
+
prompt = f"\n Your Name: {self.agent_name} \n\n Your Description: {self.agent_description} \n\n {self.system_prompt}"
|
529
564
|
else:
|
530
|
-
prompt = system_prompt
|
565
|
+
prompt = self.system_prompt
|
531
566
|
|
532
567
|
# Initialize the short term memory
|
533
568
|
self.short_memory = Conversation(
|
534
569
|
system_prompt=prompt,
|
535
570
|
time_enabled=False,
|
536
|
-
user=user_name,
|
537
|
-
rules=rules,
|
571
|
+
user=self.user_name,
|
572
|
+
rules=self.rules,
|
538
573
|
token_count=False,
|
539
|
-
*args,
|
540
|
-
**kwargs,
|
541
|
-
)
|
542
|
-
|
543
|
-
# Initialize the feedback
|
544
|
-
self.feedback = []
|
545
|
-
|
546
|
-
# Initialize the executor
|
547
|
-
self.executor = ThreadPoolExecutor(
|
548
|
-
max_workers=executor_workers
|
549
574
|
)
|
550
575
|
|
551
|
-
self.
|
576
|
+
return self.short_memory
|
552
577
|
|
553
578
|
def init_handling(self):
|
554
579
|
# Define tasks as pairs of (function, condition)
|
555
580
|
# Each task will only run if its condition is True
|
556
|
-
|
557
|
-
(self.setup_config, True), # Always run setup_config
|
558
|
-
(
|
559
|
-
self.get_docs_from_doc_folders,
|
560
|
-
exists(self.docs_folder),
|
561
|
-
),
|
562
|
-
(self.handle_tool_init, True), # Always run tool init
|
563
|
-
(
|
564
|
-
self.handle_tool_schema_ops,
|
565
|
-
exists(self.tool_schema)
|
566
|
-
or exists(self.list_base_models),
|
567
|
-
),
|
568
|
-
(
|
569
|
-
self.handle_sop_ops,
|
570
|
-
exists(self.sop) or exists(self.sop_list),
|
571
|
-
),
|
572
|
-
]
|
573
|
-
|
574
|
-
# Filter out tasks whose conditions are False
|
575
|
-
filtered_tasks = [
|
576
|
-
task for task, condition in tasks if condition
|
577
|
-
]
|
578
|
-
|
579
|
-
# Execute all tasks concurrently
|
580
|
-
with concurrent.futures.ThreadPoolExecutor(
|
581
|
-
max_workers=os.cpu_count() * 4
|
582
|
-
) as executor:
|
583
|
-
# Map tasks to futures and collect results
|
584
|
-
results = {}
|
585
|
-
future_to_task = {
|
586
|
-
executor.submit(task): task.__name__
|
587
|
-
for task in filtered_tasks
|
588
|
-
}
|
581
|
+
self.setup_config()
|
589
582
|
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
except Exception as e:
|
602
|
-
results[task_name] = None
|
603
|
-
logging.error(
|
604
|
-
f"Task {task_name} failed with error: {e}"
|
605
|
-
)
|
583
|
+
if exists(self.docs_folder):
|
584
|
+
self.get_docs_from_doc_folders()
|
585
|
+
|
586
|
+
if exists(self.tools):
|
587
|
+
self.handle_tool_init()
|
588
|
+
|
589
|
+
if exists(self.tool_schema) or exists(self.list_base_models):
|
590
|
+
self.handle_tool_schema_ops()
|
591
|
+
|
592
|
+
if exists(self.sop) or exists(self.sop_list):
|
593
|
+
self.handle_sop_ops()
|
606
594
|
|
607
595
|
# Run sequential operations after all concurrent tasks are done
|
608
|
-
self.agent_output = self.agent_output_model()
|
596
|
+
# self.agent_output = self.agent_output_model()
|
609
597
|
log_agent_data(self.to_dict())
|
610
598
|
|
611
599
|
if self.llm is None:
|
612
600
|
self.llm = self.llm_handling()
|
613
601
|
|
602
|
+
if self.mcp_url or self.mcp_servers is not None:
|
603
|
+
self.add_mcp_tools_to_memory()
|
604
|
+
|
614
605
|
def agent_output_model(self):
|
615
606
|
# Many steps
|
616
607
|
id = agent_id()
|
@@ -637,10 +628,7 @@ class Agent:
|
|
637
628
|
return self._cached_llm
|
638
629
|
|
639
630
|
if self.model_name is None:
|
640
|
-
|
641
|
-
f"Model name is not provided, using {self._default_model}. You can configure any model from litellm if desired."
|
642
|
-
)
|
643
|
-
self.model_name = self._default_model
|
631
|
+
self.model_name = "gpt-4o-mini"
|
644
632
|
|
645
633
|
try:
|
646
634
|
# Simplify initialization logic
|
@@ -719,68 +707,122 @@ class Agent:
|
|
719
707
|
tool.__name__: tool for tool in self.tools
|
720
708
|
}
|
721
709
|
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
710
|
+
def add_mcp_tools_to_memory(self):
|
711
|
+
"""
|
712
|
+
Adds MCP tools to the agent's short-term memory.
|
713
|
+
|
714
|
+
This function checks for either a single MCP URL or multiple MCP URLs and adds the available tools
|
715
|
+
to the agent's memory. The tools are listed in JSON format.
|
716
|
+
|
717
|
+
Raises:
|
718
|
+
Exception: If there's an error accessing the MCP tools
|
719
|
+
"""
|
720
|
+
try:
|
721
|
+
if self.mcp_url is not None:
|
722
|
+
tools_available = list_all(
|
723
|
+
self.mcp_url, output_type="json"
|
724
|
+
)
|
725
|
+
self.short_memory.add(
|
726
|
+
role="Tools Available",
|
727
|
+
content=f"\n{tools_available}",
|
728
|
+
)
|
729
|
+
|
730
|
+
elif (
|
731
|
+
self.mcp_url is None
|
732
|
+
and self.mcp_urls is not None
|
733
|
+
and len(self.mcp_urls) > 1
|
734
|
+
):
|
735
|
+
tools_available = list_tools_for_multiple_urls(
|
736
|
+
urls=self.mcp_urls,
|
737
|
+
output_type="json",
|
738
|
+
)
|
739
|
+
|
740
|
+
self.short_memory.add(
|
741
|
+
role="Tools Available",
|
742
|
+
content=f"\n{tools_available}",
|
743
|
+
)
|
744
|
+
except Exception as e:
|
745
|
+
logger.error(f"Error adding MCP tools to memory: {e}")
|
746
|
+
raise e
|
747
|
+
|
748
|
+
def _single_mcp_tool_handling(self, response: any):
|
749
|
+
"""
|
750
|
+
Handles execution of a single MCP tool.
|
751
|
+
|
752
|
+
Args:
|
753
|
+
response (str): The tool response to process
|
754
|
+
|
755
|
+
Raises:
|
756
|
+
Exception: If there's an error executing the tool
|
757
|
+
"""
|
758
|
+
try:
|
759
|
+
if isinstance(response, dict):
|
760
|
+
result = response
|
761
|
+
print(type(result))
|
762
|
+
else:
|
763
|
+
result = str_to_dict(response)
|
764
|
+
print(type(result))
|
765
|
+
|
766
|
+
output = execute_mcp_tool(
|
767
|
+
url=self.mcp_url,
|
768
|
+
parameters=result,
|
769
|
+
)
|
770
|
+
|
771
|
+
self.short_memory.add(
|
772
|
+
role="Tool Executor", content=str(output)
|
773
|
+
)
|
774
|
+
except Exception as e:
|
775
|
+
logger.error(f"Error in single MCP tool handling: {e}")
|
776
|
+
raise e
|
777
|
+
|
778
|
+
def _multiple_mcp_tool_handling(self, response: any):
|
779
|
+
"""
|
780
|
+
Handles execution of multiple MCP tools.
|
781
|
+
|
782
|
+
Args:
|
783
|
+
response (any): The tool response to process
|
784
|
+
|
785
|
+
Raises:
|
786
|
+
Exception: If there's an error executing the tools
|
787
|
+
"""
|
788
|
+
try:
|
789
|
+
if isinstance(response, str):
|
790
|
+
response = str_to_dict(response)
|
791
|
+
|
792
|
+
execution = find_and_execute_tool(
|
793
|
+
self.mcp_urls,
|
794
|
+
response["name"],
|
795
|
+
parameters=response,
|
796
|
+
)
|
797
|
+
|
798
|
+
self.short_memory.add(
|
799
|
+
role="Tool Executor", content=str(execution)
|
800
|
+
)
|
801
|
+
except Exception as e:
|
802
|
+
logger.error(f"Error in multiple MCP tool handling: {e}")
|
803
|
+
raise e
|
804
|
+
|
805
|
+
def mcp_tool_handling(self, response: any):
|
806
|
+
"""
|
807
|
+
Main handler for MCP tool execution.
|
808
|
+
|
809
|
+
Args:
|
810
|
+
response (any): The tool response to process
|
811
|
+
|
812
|
+
Raises:
|
813
|
+
ValueError: If no MCP URL or MCP Servers are provided
|
814
|
+
Exception: If there's an error in tool handling
|
815
|
+
"""
|
816
|
+
try:
|
817
|
+
# if self.mcp_url is not None:
|
818
|
+
self._single_mcp_tool_handling(response)
|
819
|
+
# elif self.mcp_url is None and len(self.mcp_servers) > 1:
|
820
|
+
# self._multiple_mcp_tool_handling(response)
|
821
|
+
# else:
|
822
|
+
# raise ValueError("No MCP URL or MCP Servers provided")
|
823
|
+
except Exception as e:
|
824
|
+
logger.error(f"Error in mcp_tool_handling: {e}")
|
825
|
+
raise e
|
784
826
|
|
785
827
|
def setup_config(self):
|
786
828
|
# The max_loops will be set dynamically if the dynamic_loop
|
@@ -1095,6 +1137,15 @@ class Agent:
|
|
1095
1137
|
) as executor:
|
1096
1138
|
executor.map(lambda f: f(), update_tasks)
|
1097
1139
|
|
1140
|
+
####### MCP TOOL HANDLING #######
|
1141
|
+
if (
|
1142
|
+
self.mcp_servers
|
1143
|
+
and self.tools_list_dictionary is not None
|
1144
|
+
):
|
1145
|
+
self.mcp_tool_handling(response)
|
1146
|
+
|
1147
|
+
####### MCP TOOL HANDLING #######
|
1148
|
+
|
1098
1149
|
# Check and execute tools
|
1099
1150
|
if self.tools is not None:
|
1100
1151
|
out = self.parse_and_execute_tools(
|
@@ -1739,10 +1790,11 @@ class Agent:
|
|
1739
1790
|
)
|
1740
1791
|
|
1741
1792
|
# Reinitialize executor if needed
|
1742
|
-
if not hasattr(self, "executor") or self.executor is None:
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1793
|
+
# if not hasattr(self, "executor") or self.executor is None:
|
1794
|
+
with ThreadPoolExecutor(
|
1795
|
+
max_workers=os.cpu_count()
|
1796
|
+
) as executor:
|
1797
|
+
self.executor = executor
|
1746
1798
|
|
1747
1799
|
# # Reinitialize tool structure if needed
|
1748
1800
|
# if hasattr(self, 'tools') and (self.tools or getattr(self, 'list_base_models', None)):
|
@@ -2494,12 +2546,7 @@ class Agent:
|
|
2494
2546
|
self,
|
2495
2547
|
task: Optional[Union[str, Any]] = None,
|
2496
2548
|
img: Optional[str] = None,
|
2497
|
-
device: Optional[str] = "cpu", # gpu
|
2498
|
-
device_id: Optional[int] = 0,
|
2499
|
-
all_cores: Optional[bool] = True,
|
2500
2549
|
scheduled_run_date: Optional[datetime] = None,
|
2501
|
-
do_not_use_cluster_ops: Optional[bool] = True,
|
2502
|
-
all_gpus: Optional[bool] = False,
|
2503
2550
|
*args,
|
2504
2551
|
**kwargs,
|
2505
2552
|
) -> Any:
|
@@ -2539,7 +2586,6 @@ class Agent:
|
|
2539
2586
|
) # Sleep for a short period to avoid busy waiting
|
2540
2587
|
|
2541
2588
|
try:
|
2542
|
-
# If cluster ops disabled, run directly
|
2543
2589
|
output = self._run(
|
2544
2590
|
task=task,
|
2545
2591
|
img=img,
|
@@ -2549,11 +2595,6 @@ class Agent:
|
|
2549
2595
|
|
2550
2596
|
return output
|
2551
2597
|
|
2552
|
-
# if self.tools_list_dictionary is not None:
|
2553
|
-
# return str_to_dict(output)
|
2554
|
-
# else:
|
2555
|
-
# return output
|
2556
|
-
|
2557
2598
|
except ValueError as e:
|
2558
2599
|
self._handle_run_error(e)
|
2559
2600
|
|
swarms/structs/aop.py
CHANGED
@@ -27,6 +27,7 @@ class AOP:
|
|
27
27
|
name: Optional[str] = None,
|
28
28
|
description: Optional[str] = None,
|
29
29
|
url: Optional[str] = "http://localhost:8000/sse",
|
30
|
+
urls: Optional[list[str]] = None,
|
30
31
|
*args,
|
31
32
|
**kwargs,
|
32
33
|
):
|
@@ -44,7 +45,7 @@ class AOP:
|
|
44
45
|
self.name = name
|
45
46
|
self.description = description
|
46
47
|
self.url = url
|
47
|
-
|
48
|
+
self.urls = urls
|
48
49
|
self.tools = {}
|
49
50
|
self.swarms = {}
|
50
51
|
|
@@ -527,6 +528,12 @@ class AOP:
|
|
527
528
|
return tool
|
528
529
|
return None
|
529
530
|
|
531
|
+
def list_tools_for_multiple_urls(self):
|
532
|
+
out = []
|
533
|
+
for url in self.urls:
|
534
|
+
out.append(self.list_all(url))
|
535
|
+
return out
|
536
|
+
|
530
537
|
def search_if_tool_exists(self, name: str):
|
531
538
|
out = self.list_all()
|
532
539
|
for tool in out:
|