swarms 7.8.7__py3-none-any.whl → 7.8.9__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/structs/agent.py CHANGED
@@ -72,8 +72,10 @@ from swarms.prompts.max_loop_prompt import generate_reasoning_prompt
72
72
  from swarms.prompts.safety_prompt import SAFETY_PROMPT
73
73
  from swarms.structs.ma_utils import set_random_models_for_agents
74
74
  from swarms.tools.mcp_client_call import (
75
+ execute_multiple_tools_on_multiple_mcp_servers_sync,
75
76
  execute_tool_call_simple,
76
77
  get_mcp_tools_sync,
78
+ get_tools_for_multiple_mcp_servers,
77
79
  )
78
80
  from swarms.schemas.mcp_schemas import (
79
81
  MCPConnection,
@@ -81,7 +83,6 @@ from swarms.schemas.mcp_schemas import (
81
83
  from swarms.utils.index import (
82
84
  exists,
83
85
  format_data_structure,
84
- format_dict_to_string,
85
86
  )
86
87
  from swarms.schemas.conversation_schema import ConversationSchema
87
88
  from swarms.utils.output_types import OutputType
@@ -417,7 +418,8 @@ class Agent:
417
418
  llm_base_url: Optional[str] = None,
418
419
  llm_api_key: Optional[str] = None,
419
420
  rag_config: Optional[RAGConfig] = None,
420
- no_tool_call_summary: bool = False,
421
+ tool_call_summary: bool = True,
422
+ output_raw_json_from_tool_call: bool = False,
421
423
  *args,
422
424
  **kwargs,
423
425
  ):
@@ -446,7 +448,10 @@ class Agent:
446
448
  self.system_prompt = system_prompt
447
449
  self.agent_name = agent_name
448
450
  self.agent_description = agent_description
449
- self.saved_state_path = f"{self.agent_name}_{generate_api_key(prefix='agent-')}_state.json"
451
+ # self.saved_state_path = f"{self.agent_name}_{generate_api_key(prefix='agent-')}_state.json"
452
+ self.saved_state_path = (
453
+ f"{generate_api_key(prefix='agent-')}_state.json"
454
+ )
450
455
  self.autosave = autosave
451
456
  self.response_filters = []
452
457
  self.self_healing_enabled = self_healing_enabled
@@ -549,7 +554,10 @@ class Agent:
549
554
  self.llm_base_url = llm_base_url
550
555
  self.llm_api_key = llm_api_key
551
556
  self.rag_config = rag_config
552
- self.no_tool_call_summary = no_tool_call_summary
557
+ self.tool_call_summary = tool_call_summary
558
+ self.output_raw_json_from_tool_call = (
559
+ output_raw_json_from_tool_call
560
+ )
553
561
 
554
562
  # self.short_memory = self.short_memory_init()
555
563
 
@@ -623,7 +631,7 @@ class Agent:
623
631
 
624
632
  self.short_memory.add(
625
633
  role=f"{self.agent_name}",
626
- content=f"Tools available: {format_data_structure(self.tools_list_dictionary)}",
634
+ content=self.tools_list_dictionary,
627
635
  )
628
636
 
629
637
  def short_memory_init(self):
@@ -692,6 +700,10 @@ class Agent:
692
700
 
693
701
  if exists(self.tools) and len(self.tools) >= 2:
694
702
  parallel_tool_calls = True
703
+ elif exists(self.mcp_url) or exists(self.mcp_urls):
704
+ parallel_tool_calls = True
705
+ elif exists(self.mcp_config):
706
+ parallel_tool_calls = True
695
707
  else:
696
708
  parallel_tool_calls = False
697
709
 
@@ -714,7 +726,7 @@ class Agent:
714
726
  parallel_tool_calls=parallel_tool_calls,
715
727
  )
716
728
 
717
- elif self.mcp_url is not None:
729
+ elif exists(self.mcp_url) or exists(self.mcp_urls):
718
730
  self.llm = LiteLLM(
719
731
  **common_args,
720
732
  tools_list_dictionary=self.add_mcp_tools_to_memory(),
@@ -752,15 +764,27 @@ class Agent:
752
764
  tools = get_mcp_tools_sync(server_path=self.mcp_url)
753
765
  elif exists(self.mcp_config):
754
766
  tools = get_mcp_tools_sync(connection=self.mcp_config)
755
- logger.info(f"Tools: {tools}")
767
+ # logger.info(f"Tools: {tools}")
768
+ elif exists(self.mcp_urls):
769
+ tools = get_tools_for_multiple_mcp_servers(
770
+ urls=self.mcp_urls,
771
+ output_type="str",
772
+ )
773
+ # print(f"Tools: {tools} for {self.mcp_urls}")
756
774
  else:
757
775
  raise AgentMCPConnectionError(
758
776
  "mcp_url must be either a string URL or MCPConnection object"
759
777
  )
760
- self.pretty_print(
761
- f"✨ [SYSTEM] Successfully integrated {len(tools)} MCP tools into agent: {self.agent_name} | Status: ONLINE | Time: {time.strftime('%H:%M:%S')} ✨",
762
- loop_count=0,
763
- )
778
+
779
+ if (
780
+ exists(self.mcp_url)
781
+ or exists(self.mcp_urls)
782
+ or exists(self.mcp_config)
783
+ ):
784
+ self.pretty_print(
785
+ f"✨ [SYSTEM] Successfully integrated {len(tools)} MCP tools into agent: {self.agent_name} | Status: ONLINE | Time: {time.strftime('%H:%M:%S')} ✨",
786
+ loop_count=0,
787
+ )
764
788
 
765
789
  return tools
766
790
  except AgentMCPConnectionError as e:
@@ -939,7 +963,7 @@ class Agent:
939
963
 
940
964
  self.short_memory.add(role=self.user_name, content=task)
941
965
 
942
- if self.plan_enabled:
966
+ if self.plan_enabled or self.planning_prompt is not None:
943
967
  self.plan(task)
944
968
 
945
969
  # Set the loop count
@@ -1006,55 +1030,51 @@ class Agent:
1006
1030
  )
1007
1031
  self.memory_query(task_prompt)
1008
1032
 
1009
- # # Generate response using LLM
1010
- # response_args = (
1011
- # (task_prompt, *args)
1012
- # if img is None
1013
- # else (task_prompt, img, *args)
1014
- # )
1015
-
1016
- # # Call the LLM
1017
- # response = self.call_llm(
1018
- # *response_args, **kwargs
1019
- # )
1020
-
1021
1033
  response = self.call_llm(
1022
1034
  task=task_prompt, img=img, *args, **kwargs
1023
1035
  )
1024
1036
 
1037
+ print(f"Response: {response}")
1038
+
1025
1039
  if exists(self.tools_list_dictionary):
1026
1040
  if isinstance(response, BaseModel):
1027
1041
  response = response.model_dump()
1028
1042
 
1029
- # # Convert to a str if the response is not a str
1030
- # if self.mcp_url is None or self.tools is None:
1043
+ # Parse the response from the agent with the output type
1031
1044
  response = self.parse_llm_output(response)
1032
1045
 
1033
1046
  self.short_memory.add(
1034
1047
  role=self.agent_name,
1035
- content=format_dict_to_string(response),
1048
+ content=response,
1036
1049
  )
1037
1050
 
1038
1051
  # Print
1039
1052
  self.pretty_print(response, loop_count)
1040
1053
 
1041
- # # Output Cleaner
1042
- # self.output_cleaner_op(response)
1043
-
1044
- # Check and execute tools
1054
+ # Check and execute callable tools
1045
1055
  if exists(self.tools):
1046
1056
 
1047
- self.execute_tools(
1048
- response=response,
1049
- loop_count=loop_count,
1050
- )
1057
+ if (
1058
+ self.output_raw_json_from_tool_call
1059
+ is True
1060
+ ):
1061
+ print(type(response))
1062
+ response = response
1063
+ else:
1064
+ self.execute_tools(
1065
+ response=response,
1066
+ loop_count=loop_count,
1067
+ )
1051
1068
 
1052
1069
  # Handle MCP tools
1053
- if exists(self.mcp_url) or exists(
1054
- self.mcp_config
1070
+ if (
1071
+ exists(self.mcp_url)
1072
+ or exists(self.mcp_config)
1073
+ or exists(self.mcp_urls)
1055
1074
  ):
1056
1075
  self.mcp_tool_handling(
1057
- response, loop_count
1076
+ response=response,
1077
+ current_loop=loop_count,
1058
1078
  )
1059
1079
 
1060
1080
  self.sentiment_and_evaluator(response)
@@ -1298,26 +1318,47 @@ class Agent:
1298
1318
 
1299
1319
  def plan(self, task: str, *args, **kwargs) -> None:
1300
1320
  """
1301
- Plan the task
1321
+ Create a strategic plan for executing the given task.
1322
+
1323
+ This method generates a step-by-step plan by combining the conversation
1324
+ history, planning prompt, and current task. The plan is then added to
1325
+ the agent's short-term memory for reference during execution.
1302
1326
 
1303
1327
  Args:
1304
- task (str): The task to plan
1328
+ task (str): The task to create a plan for
1329
+ *args: Additional positional arguments passed to the LLM
1330
+ **kwargs: Additional keyword arguments passed to the LLM
1331
+
1332
+ Returns:
1333
+ None: The plan is stored in memory rather than returned
1334
+
1335
+ Raises:
1336
+ Exception: If planning fails, the original exception is re-raised
1305
1337
  """
1306
1338
  try:
1307
- if exists(self.planning_prompt):
1308
- # Join the plan and the task
1309
- planning_prompt = f"{self.planning_prompt} {task}"
1310
- plan = self.llm(planning_prompt, *args, **kwargs)
1311
- logger.info(f"Plan: {plan}")
1339
+ # Get the current conversation history
1340
+ history = self.short_memory.get_str()
1312
1341
 
1313
- # Add the plan to the memory
1314
- self.short_memory.add(
1315
- role=self.agent_name, content=str(plan)
1342
+ # Construct the planning prompt by combining history, planning prompt, and task
1343
+ planning_prompt = (
1344
+ f"{history}\n\n{self.planning_prompt}\n\nTask: {task}"
1316
1345
  )
1317
1346
 
1347
+ # Generate the plan using the LLM
1348
+ plan = self.llm.run(task=planning_prompt, *args, **kwargs)
1349
+
1350
+ # Store the generated plan in short-term memory
1351
+ self.short_memory.add(role=self.agent_name, content=plan)
1352
+
1353
+ logger.info(
1354
+ f"Successfully created plan for task: {task[:50]}..."
1355
+ )
1318
1356
  return None
1357
+
1319
1358
  except Exception as error:
1320
- logger.error(f"Error planning task: {error}")
1359
+ logger.error(
1360
+ f"Failed to create plan for task '{task}': {error}"
1361
+ )
1321
1362
  raise error
1322
1363
 
1323
1364
  async def run_concurrent(self, task: str, *args, **kwargs):
@@ -1440,7 +1481,6 @@ class Agent:
1440
1481
  raise AgentInitializationError(
1441
1482
  f"Max tokens is set to {self.max_tokens}, but the model '{self.model_name}' only supports {get_max_tokens(self.model_name)} tokens. Please set max tokens to {get_max_tokens(self.model_name)} or less."
1442
1483
  )
1443
-
1444
1484
 
1445
1485
  if self.model_name not in model_list:
1446
1486
  logger.warning(
@@ -2664,7 +2704,7 @@ class Agent:
2664
2704
  ) # Convert other dicts to string
2665
2705
 
2666
2706
  elif isinstance(response, BaseModel):
2667
- out = response.model_dump()
2707
+ response = response.model_dump()
2668
2708
 
2669
2709
  # Handle List[BaseModel] responses
2670
2710
  elif (
@@ -2674,14 +2714,9 @@ class Agent:
2674
2714
  ):
2675
2715
  return [item.model_dump() for item in response]
2676
2716
 
2677
- elif isinstance(response, list):
2678
- out = format_data_structure(response)
2679
- else:
2680
- out = str(response)
2717
+ return response
2681
2718
 
2682
- return out
2683
-
2684
- except Exception as e:
2719
+ except AgentChatCompletionResponse as e:
2685
2720
  logger.error(f"Error parsing LLM output: {e}")
2686
2721
  raise ValueError(
2687
2722
  f"Failed to parse LLM output: {type(response)}"
@@ -2738,6 +2773,15 @@ class Agent:
2738
2773
  connection=self.mcp_config,
2739
2774
  )
2740
2775
  )
2776
+ elif exists(self.mcp_urls):
2777
+ tool_response = execute_multiple_tools_on_multiple_mcp_servers_sync(
2778
+ responses=response,
2779
+ urls=self.mcp_urls,
2780
+ output_type="json",
2781
+ )
2782
+ # tool_response = format_data_structure(tool_response)
2783
+
2784
+ print(f"Multiple MCP Tool Response: {tool_response}")
2741
2785
  else:
2742
2786
  raise AgentMCPConnectionError(
2743
2787
  "mcp_url must be either a string URL or MCPConnection object"
@@ -2745,7 +2789,7 @@ class Agent:
2745
2789
 
2746
2790
  # Get the text content from the tool response
2747
2791
  # execute_tool_call_simple returns a string directly, not an object with content attribute
2748
- text_content = f"MCP Tool Response: \n{json.dumps(tool_response, indent=2)}"
2792
+ text_content = f"MCP Tool Response: \n\n {json.dumps(tool_response, indent=2)}"
2749
2793
 
2750
2794
  if self.no_print is False:
2751
2795
  formatter.print_panel(
@@ -2818,7 +2862,7 @@ class Agent:
2818
2862
  # Now run the LLM again without tools - create a temporary LLM instance
2819
2863
  # instead of modifying the cached one
2820
2864
  # Create a temporary LLM instance without tools for the follow-up call
2821
- if self.no_tool_call_summary is False:
2865
+ if self.tool_call_summary is True:
2822
2866
  temp_llm = self.temp_llm_instance_for_tool_summary()
2823
2867
 
2824
2868
  tool_response = temp_llm.run(
@@ -1326,6 +1326,12 @@ class Conversation(BaseStructure):
1326
1326
  self.conversation_history[-1]["content"],
1327
1327
  )
1328
1328
 
1329
+ def return_list_final(self):
1330
+ """Return the final message as a list."""
1331
+ return [
1332
+ self.conversation_history[-1]["content"],
1333
+ ]
1334
+
1329
1335
  @classmethod
1330
1336
  def list_conversations(
1331
1337
  cls, conversations_dir: Optional[str] = None
@@ -104,9 +104,7 @@ class AgentValidator:
104
104
  model_name in model["model_name"]
105
105
  for model in model_list
106
106
  ):
107
- valid_models = [
108
- model["model_name"] for model in model_list
109
- ]
107
+ [model["model_name"] for model in model_list]
110
108
  raise AgentValidationError(
111
109
  "Invalid model name. Must be one of the supported litellm models",
112
110
  "model_name",
@@ -4,11 +4,9 @@ from swarms.telemetry.main import (
4
4
  get_cpu_info,
5
5
  get_machine_id,
6
6
  get_os_version,
7
- get_package_mismatches,
8
7
  get_pip_version,
9
8
  get_python_version,
10
9
  get_ram_info,
11
- get_swarms_verison,
12
10
  get_system_info,
13
11
  get_user_device_data,
14
12
  system_info,
@@ -21,11 +19,9 @@ __all__ = [
21
19
  "generate_unique_identifier",
22
20
  "get_python_version",
23
21
  "get_pip_version",
24
- "get_swarms_verison",
25
22
  "get_os_version",
26
23
  "get_cpu_info",
27
24
  "get_ram_info",
28
- "get_package_mismatches",
29
25
  "system_info",
30
26
  "get_user_device_data",
31
27
  ]
swarms/telemetry/main.py CHANGED
@@ -1,24 +1,16 @@
1
- import asyncio
2
-
3
-
1
+ import os
4
2
  import datetime
5
3
  import hashlib
6
4
  import platform
7
5
  import socket
8
6
  import subprocess
9
7
  import uuid
10
- from concurrent.futures import ThreadPoolExecutor
11
- from functools import lru_cache
12
- from threading import Lock
13
8
  from typing import Dict
14
9
 
15
- import aiohttp
16
10
  import pkg_resources
17
11
  import psutil
12
+ import requests
18
13
  import toml
19
- from requests import Session
20
- from requests.adapters import HTTPAdapter
21
- from urllib3.util.retry import Retry
22
14
 
23
15
 
24
16
  # Helper functions
@@ -263,134 +255,44 @@ def capture_system_data() -> Dict[str, str]:
263
255
  print(f"Failed to capture system data: {e}")
264
256
 
265
257
 
266
- # Global variables
267
- _session = None
268
- _session_lock = Lock()
269
- _executor = ThreadPoolExecutor(max_workers=10)
270
- _aiohttp_session = None
271
-
272
-
273
- def get_session() -> Session:
274
- """Thread-safe session getter with optimized connection pooling"""
275
- global _session
276
- if _session is None:
277
- with _session_lock:
278
- if _session is None: # Double-check pattern
279
- _session = Session()
280
- adapter = HTTPAdapter(
281
- pool_connections=1000, # Increased pool size
282
- pool_maxsize=1000, # Increased max size
283
- max_retries=Retry(
284
- total=3,
285
- backoff_factor=0.1,
286
- status_forcelist=[500, 502, 503, 504],
287
- ),
288
- pool_block=False, # Non-blocking pool
289
- )
290
- _session.mount("http://", adapter)
291
- _session.mount("https://", adapter)
292
- _session.headers.update(
293
- {
294
- "Content-Type": "application/json",
295
- "Authorization": "Bearer sk-33979fd9a4e8e6b670090e4900a33dbe7452a15ccc705745f4eca2a70c88ea24",
296
- "Connection": "keep-alive", # Enable keep-alive
297
- }
298
- )
299
- return _session
300
-
301
-
302
- @lru_cache(maxsize=2048, typed=True)
303
- def get_user_device_data_cached():
304
- """Cached version with increased cache size"""
305
- return get_user_device_data()
306
-
307
-
308
- async def get_aiohttp_session():
309
- """Get or create aiohttp session for async requests"""
310
- global _aiohttp_session
311
- if _aiohttp_session is None or _aiohttp_session.closed:
312
- timeout = aiohttp.ClientTimeout(total=10)
313
- connector = aiohttp.TCPConnector(
314
- limit=1000, # Connection limit
315
- ttl_dns_cache=300, # DNS cache TTL
316
- use_dns_cache=True, # Enable DNS caching
317
- keepalive_timeout=60, # Keep-alive timeout
318
- )
319
- _aiohttp_session = aiohttp.ClientSession(
320
- timeout=timeout,
321
- connector=connector,
322
- headers={
323
- "Content-Type": "application/json",
324
- "Authorization": "Bearer sk-33979fd9a4e8e6b670090e4900a33dbe7452a15ccc705745f4eca2a70c88ea24",
325
- },
326
- )
327
- return _aiohttp_session
328
-
329
-
330
- async def log_agent_data_async(data_dict: dict):
331
- """Asynchronous version of log_agent_data"""
258
+ def _log_agent_data(data_dict: dict):
259
+ """Simple function to log agent data using requests library"""
332
260
  if not data_dict:
333
- return None
261
+ return
334
262
 
335
263
  url = "https://swarms.world/api/get-agents/log-agents"
336
264
  payload = {
337
265
  "data": data_dict,
338
- "system_data": get_user_device_data_cached(),
266
+ "system_data": get_user_device_data(),
339
267
  "timestamp": datetime.datetime.now(
340
268
  datetime.timezone.utc
341
269
  ).isoformat(),
342
270
  }
343
271
 
344
- session = await get_aiohttp_session()
345
- try:
346
- async with session.post(url, json=payload) as response:
347
- if response.status == 200:
348
- return await response.json()
349
- except Exception:
350
- return None
351
-
352
-
353
- def _log_agent_data(data_dict: dict):
354
- """
355
- Enhanced log_agent_data with both sync and async capabilities
356
- """
357
- if not data_dict:
358
- return None
359
-
360
- # If running in an event loop, use async version
361
- try:
362
- loop = asyncio.get_event_loop()
363
- if loop.is_running():
364
- return asyncio.create_task(
365
- log_agent_data_async(data_dict)
366
- )
367
- except RuntimeError:
368
- pass
272
+ key = (
273
+ os.getenv("SWARMS_API_KEY")
274
+ or "Bearer sk-33979fd9a4e8e6b670090e4900a33dbe7452a15ccc705745f4eca2a70c88ea24"
275
+ )
369
276
 
370
- # Fallback to optimized sync version
371
- url = "https://swarms.world/api/get-agents/log-agents"
372
- payload = {
373
- "data": data_dict,
374
- "system_data": get_user_device_data_cached(),
375
- "timestamp": datetime.datetime.now(
376
- datetime.timezone.utc
377
- ).isoformat(),
277
+ headers = {
278
+ "Content-Type": "application/json",
279
+ "Authorization": key,
378
280
  }
379
281
 
380
282
  try:
381
- session = get_session()
382
- response = session.post(
383
- url,
384
- json=payload,
385
- timeout=10,
386
- stream=False, # Disable streaming for faster response
283
+ response = requests.post(
284
+ url, json=payload, headers=headers, timeout=10
387
285
  )
388
- if response.ok and response.text.strip():
389
- return response.json()
286
+ if response.status_code == 200:
287
+ return
390
288
  except Exception:
391
- return None
289
+ return
290
+
291
+ return
392
292
 
393
293
 
394
294
  def log_agent_data(data_dict: dict):
395
- """Log agent data"""
396
- pass
295
+ try:
296
+ _log_agent_data(data_dict)
297
+ except Exception:
298
+ pass
swarms/tools/__init__.py CHANGED
@@ -33,6 +33,11 @@ from swarms.tools.mcp_client_call import (
33
33
  get_tools_for_multiple_mcp_servers,
34
34
  get_mcp_tools_sync,
35
35
  aget_mcp_tools,
36
+ execute_multiple_tools_on_multiple_mcp_servers,
37
+ execute_multiple_tools_on_multiple_mcp_servers_sync,
38
+ _create_server_tool_mapping,
39
+ _create_server_tool_mapping_async,
40
+ _execute_tool_on_server,
36
41
  )
37
42
 
38
43
 
@@ -62,4 +67,9 @@ __all__ = [
62
67
  "get_tools_for_multiple_mcp_servers",
63
68
  "get_mcp_tools_sync",
64
69
  "aget_mcp_tools",
70
+ "execute_multiple_tools_on_multiple_mcp_servers",
71
+ "execute_multiple_tools_on_multiple_mcp_servers_sync",
72
+ "_create_server_tool_mapping",
73
+ "_create_server_tool_mapping_async",
74
+ "_execute_tool_on_server",
65
75
  ]
swarms/tools/base_tool.py CHANGED
@@ -2256,14 +2256,18 @@ class BaseTool(BaseModel):
2256
2256
  try:
2257
2257
  api_response = json.loads(api_response)
2258
2258
  except json.JSONDecodeError as e:
2259
- raise ToolValidationError(
2260
- f"Invalid JSON in API response: {e}"
2261
- ) from e
2259
+ self._log_if_verbose(
2260
+ "error",
2261
+ f"Failed to parse JSON from API response: {e}. Response: '{api_response[:100]}...'"
2262
+ )
2263
+ return []
2262
2264
 
2263
2265
  if not isinstance(api_response, dict):
2264
- raise ToolValidationError(
2265
- "API response must be a dictionary, JSON string, BaseModel, or list of tool calls"
2266
+ self._log_if_verbose(
2267
+ "warning",
2268
+ f"API response is not a dictionary (type: {type(api_response)}), returning empty list"
2266
2269
  )
2270
+ return []
2267
2271
 
2268
2272
  # Extract function calls from dictionary response
2269
2273
  function_calls = (
@@ -505,3 +505,511 @@ async def execute_tool_call_simple(
505
505
  *args,
506
506
  **kwargs,
507
507
  )
508
+
509
+
510
+ def _create_server_tool_mapping(
511
+ urls: List[str],
512
+ connections: List[MCPConnection] = None,
513
+ format: str = "openai",
514
+ ) -> Dict[str, Dict[str, Any]]:
515
+ """
516
+ Create a mapping of function names to server information for all MCP servers.
517
+
518
+ Args:
519
+ urls: List of server URLs
520
+ connections: Optional list of MCPConnection objects
521
+ format: Format to fetch tools in
522
+
523
+ Returns:
524
+ Dict mapping function names to server info (url, connection, tool)
525
+ """
526
+ server_tool_mapping = {}
527
+
528
+ for i, url in enumerate(urls):
529
+ connection = (
530
+ connections[i]
531
+ if connections and i < len(connections)
532
+ else None
533
+ )
534
+
535
+ try:
536
+ # Get tools for this server
537
+ tools = get_mcp_tools_sync(
538
+ server_path=url,
539
+ connection=connection,
540
+ format=format,
541
+ )
542
+
543
+ # Create mapping for each tool
544
+ for tool in tools:
545
+ if isinstance(tool, dict) and "function" in tool:
546
+ function_name = tool["function"]["name"]
547
+ server_tool_mapping[function_name] = {
548
+ "url": url,
549
+ "connection": connection,
550
+ "tool": tool,
551
+ "server_index": i,
552
+ }
553
+ elif hasattr(tool, "name"):
554
+ # Handle MCPTool objects
555
+ server_tool_mapping[tool.name] = {
556
+ "url": url,
557
+ "connection": connection,
558
+ "tool": tool,
559
+ "server_index": i,
560
+ }
561
+
562
+ except Exception as e:
563
+ logger.warning(
564
+ f"Failed to fetch tools from server {url}: {str(e)}"
565
+ )
566
+ continue
567
+
568
+ return server_tool_mapping
569
+
570
+
571
+ async def _create_server_tool_mapping_async(
572
+ urls: List[str],
573
+ connections: List[MCPConnection] = None,
574
+ format: str = "openai",
575
+ ) -> Dict[str, Dict[str, Any]]:
576
+ """
577
+ Async version: Create a mapping of function names to server information for all MCP servers.
578
+
579
+ Args:
580
+ urls: List of server URLs
581
+ connections: Optional list of MCPConnection objects
582
+ format: Format to fetch tools in
583
+
584
+ Returns:
585
+ Dict mapping function names to server info (url, connection, tool)
586
+ """
587
+ server_tool_mapping = {}
588
+
589
+ for i, url in enumerate(urls):
590
+ connection = (
591
+ connections[i]
592
+ if connections and i < len(connections)
593
+ else None
594
+ )
595
+
596
+ try:
597
+ # Get tools for this server using async function
598
+ tools = await aget_mcp_tools(
599
+ server_path=url,
600
+ connection=connection,
601
+ format=format,
602
+ )
603
+
604
+ # Create mapping for each tool
605
+ for tool in tools:
606
+ if isinstance(tool, dict) and "function" in tool:
607
+ function_name = tool["function"]["name"]
608
+ server_tool_mapping[function_name] = {
609
+ "url": url,
610
+ "connection": connection,
611
+ "tool": tool,
612
+ "server_index": i,
613
+ }
614
+ elif hasattr(tool, "name"):
615
+ # Handle MCPTool objects
616
+ server_tool_mapping[tool.name] = {
617
+ "url": url,
618
+ "connection": connection,
619
+ "tool": tool,
620
+ "server_index": i,
621
+ }
622
+
623
+ except Exception as e:
624
+ logger.warning(
625
+ f"Failed to fetch tools from server {url}: {str(e)}"
626
+ )
627
+ continue
628
+
629
+ return server_tool_mapping
630
+
631
+
632
+ async def _execute_tool_on_server(
633
+ tool_call: Dict[str, Any],
634
+ server_info: Dict[str, Any],
635
+ output_type: Literal["json", "dict", "str", "formatted"] = "str",
636
+ ) -> Dict[str, Any]:
637
+ """
638
+ Execute a single tool call on a specific server.
639
+
640
+ Args:
641
+ tool_call: The tool call to execute
642
+ server_info: Server information from the mapping
643
+ output_type: Output format type
644
+
645
+ Returns:
646
+ Execution result with server metadata
647
+ """
648
+ try:
649
+ result = await _execute_tool_call_simple(
650
+ response=tool_call,
651
+ server_path=server_info["url"],
652
+ connection=server_info["connection"],
653
+ output_type=output_type,
654
+ )
655
+
656
+ return {
657
+ "server_url": server_info["url"],
658
+ "server_index": server_info["server_index"],
659
+ "function_name": tool_call.get("function", {}).get(
660
+ "name", "unknown"
661
+ ),
662
+ "result": result,
663
+ "status": "success",
664
+ }
665
+
666
+ except Exception as e:
667
+ logger.error(
668
+ f"Failed to execute tool on server {server_info['url']}: {str(e)}"
669
+ )
670
+ return {
671
+ "server_url": server_info["url"],
672
+ "server_index": server_info["server_index"],
673
+ "function_name": tool_call.get("function", {}).get(
674
+ "name", "unknown"
675
+ ),
676
+ "result": None,
677
+ "error": str(e),
678
+ "status": "error",
679
+ }
680
+
681
+
682
+ async def execute_multiple_tools_on_multiple_mcp_servers(
683
+ responses: List[Dict[str, Any]],
684
+ urls: List[str],
685
+ connections: List[MCPConnection] = None,
686
+ output_type: Literal["json", "dict", "str", "formatted"] = "str",
687
+ max_concurrent: Optional[int] = None,
688
+ *args,
689
+ **kwargs,
690
+ ) -> List[Dict[str, Any]]:
691
+ """
692
+ Execute multiple tool calls across multiple MCP servers.
693
+
694
+ This function creates a mapping of function names to servers, then for each response
695
+ that contains tool calls, it finds the appropriate server for each function and
696
+ executes the calls concurrently.
697
+
698
+ Args:
699
+ responses: List of responses containing tool calls (OpenAI format)
700
+ urls: List of MCP server URLs
701
+ connections: Optional list of MCPConnection objects corresponding to each URL
702
+ output_type: Output format type for results
703
+ max_concurrent: Maximum number of concurrent executions (default: len(responses))
704
+
705
+ Returns:
706
+ List of execution results with server metadata
707
+
708
+ Example:
709
+ # Example responses format:
710
+ responses = [
711
+ {
712
+ "function": {
713
+ "name": "search_web",
714
+ "arguments": {"query": "python programming"}
715
+ }
716
+ },
717
+ {
718
+ "function": {
719
+ "name": "search_database",
720
+ "arguments": {"table": "users", "id": 123}
721
+ }
722
+ }
723
+ ]
724
+
725
+ urls = ["http://server1:8000", "http://server2:8000"]
726
+
727
+ results = await execute_multiple_tools_on_multiple_mcp_servers(
728
+ responses=responses,
729
+ urls=urls
730
+ )
731
+ """
732
+ if not responses:
733
+ logger.warning("No responses provided for execution")
734
+ return []
735
+
736
+ if not urls:
737
+ raise MCPValidationError("No server URLs provided")
738
+
739
+ # Create mapping of function names to servers using async version
740
+ logger.info(f"Creating tool mapping for {len(urls)} servers")
741
+ server_tool_mapping = await _create_server_tool_mapping_async(
742
+ urls=urls, connections=connections, format="openai"
743
+ )
744
+
745
+ if not server_tool_mapping:
746
+ raise MCPExecutionError(
747
+ "No tools found on any of the provided servers"
748
+ )
749
+
750
+ logger.info(
751
+ f"Found {len(server_tool_mapping)} unique functions across all servers"
752
+ )
753
+
754
+ # Extract all tool calls from responses
755
+ all_tool_calls = []
756
+ logger.info(
757
+ f"Processing {len(responses)} responses for tool call extraction"
758
+ )
759
+
760
+ # Check if responses are individual characters that need to be reconstructed
761
+ if len(responses) > 10 and all(
762
+ isinstance(r, str) and len(r) == 1 for r in responses
763
+ ):
764
+ logger.info(
765
+ "Detected character-by-character response, reconstructing JSON string"
766
+ )
767
+ try:
768
+ reconstructed_response = "".join(responses)
769
+ logger.info(
770
+ f"Reconstructed response length: {len(reconstructed_response)}"
771
+ )
772
+ logger.debug(
773
+ f"Reconstructed response: {reconstructed_response}"
774
+ )
775
+
776
+ # Try to parse the reconstructed response to validate it
777
+ try:
778
+ json.loads(reconstructed_response)
779
+ logger.info(
780
+ "Successfully validated reconstructed JSON response"
781
+ )
782
+ except json.JSONDecodeError as e:
783
+ logger.warning(
784
+ f"Reconstructed response is not valid JSON: {str(e)}"
785
+ )
786
+ logger.debug(
787
+ f"First 100 chars: {reconstructed_response[:100]}"
788
+ )
789
+ logger.debug(
790
+ f"Last 100 chars: {reconstructed_response[-100:]}"
791
+ )
792
+
793
+ responses = [reconstructed_response]
794
+ except Exception as e:
795
+ logger.warning(
796
+ f"Failed to reconstruct response from characters: {str(e)}"
797
+ )
798
+
799
+ for i, response in enumerate(responses):
800
+ logger.debug(
801
+ f"Processing response {i}: {type(response)} - {response}"
802
+ )
803
+
804
+ # Handle JSON string responses
805
+ if isinstance(response, str):
806
+ try:
807
+ response = json.loads(response)
808
+ logger.debug(
809
+ f"Parsed JSON string response {i}: {response}"
810
+ )
811
+ except json.JSONDecodeError:
812
+ logger.warning(
813
+ f"Failed to parse JSON response at index {i}: {response}"
814
+ )
815
+ continue
816
+
817
+ if isinstance(response, dict):
818
+ # Single tool call
819
+ if "function" in response:
820
+ logger.debug(
821
+ f"Found single tool call in response {i}: {response['function']}"
822
+ )
823
+ # Parse arguments if they're a JSON string
824
+ if isinstance(
825
+ response["function"].get("arguments"), str
826
+ ):
827
+ try:
828
+ response["function"]["arguments"] = (
829
+ json.loads(
830
+ response["function"]["arguments"]
831
+ )
832
+ )
833
+ logger.debug(
834
+ f"Parsed function arguments: {response['function']['arguments']}"
835
+ )
836
+ except json.JSONDecodeError:
837
+ logger.warning(
838
+ f"Failed to parse function arguments: {response['function']['arguments']}"
839
+ )
840
+
841
+ all_tool_calls.append((i, response))
842
+ # Multiple tool calls
843
+ elif "tool_calls" in response:
844
+ logger.debug(
845
+ f"Found multiple tool calls in response {i}: {len(response['tool_calls'])} calls"
846
+ )
847
+ for tool_call in response["tool_calls"]:
848
+ # Parse arguments if they're a JSON string
849
+ if isinstance(
850
+ tool_call.get("function", {}).get(
851
+ "arguments"
852
+ ),
853
+ str,
854
+ ):
855
+ try:
856
+ tool_call["function"]["arguments"] = (
857
+ json.loads(
858
+ tool_call["function"]["arguments"]
859
+ )
860
+ )
861
+ logger.debug(
862
+ f"Parsed tool call arguments: {tool_call['function']['arguments']}"
863
+ )
864
+ except json.JSONDecodeError:
865
+ logger.warning(
866
+ f"Failed to parse tool call arguments: {tool_call['function']['arguments']}"
867
+ )
868
+
869
+ all_tool_calls.append((i, tool_call))
870
+ # Direct tool call
871
+ elif "name" in response and "arguments" in response:
872
+ logger.debug(
873
+ f"Found direct tool call in response {i}: {response}"
874
+ )
875
+ # Parse arguments if they're a JSON string
876
+ if isinstance(response.get("arguments"), str):
877
+ try:
878
+ response["arguments"] = json.loads(
879
+ response["arguments"]
880
+ )
881
+ logger.debug(
882
+ f"Parsed direct tool call arguments: {response['arguments']}"
883
+ )
884
+ except json.JSONDecodeError:
885
+ logger.warning(
886
+ f"Failed to parse direct tool call arguments: {response['arguments']}"
887
+ )
888
+
889
+ all_tool_calls.append((i, {"function": response}))
890
+ else:
891
+ logger.debug(
892
+ f"Response {i} is a dict but doesn't match expected tool call formats: {list(response.keys())}"
893
+ )
894
+ else:
895
+ logger.warning(
896
+ f"Unsupported response type at index {i}: {type(response)}"
897
+ )
898
+ continue
899
+
900
+ if not all_tool_calls:
901
+ logger.warning("No tool calls found in responses")
902
+ return []
903
+
904
+ logger.info(f"Found {len(all_tool_calls)} tool calls to execute")
905
+
906
+ # Execute tool calls concurrently
907
+ max_concurrent = max_concurrent or len(all_tool_calls)
908
+ semaphore = asyncio.Semaphore(max_concurrent)
909
+
910
+ async def execute_with_semaphore(tool_call_info):
911
+ async with semaphore:
912
+ response_index, tool_call = tool_call_info
913
+ function_name = tool_call.get("function", {}).get(
914
+ "name", "unknown"
915
+ )
916
+
917
+ if function_name not in server_tool_mapping:
918
+ logger.warning(
919
+ f"Function '{function_name}' not found on any server"
920
+ )
921
+ return {
922
+ "response_index": response_index,
923
+ "function_name": function_name,
924
+ "result": None,
925
+ "error": f"Function '{function_name}' not available on any server",
926
+ "status": "not_found",
927
+ }
928
+
929
+ server_info = server_tool_mapping[function_name]
930
+ result = await _execute_tool_on_server(
931
+ tool_call=tool_call,
932
+ server_info=server_info,
933
+ output_type=output_type,
934
+ )
935
+ result["response_index"] = response_index
936
+ return result
937
+
938
+ # Execute all tool calls concurrently
939
+ tasks = [
940
+ execute_with_semaphore(tool_call_info)
941
+ for tool_call_info in all_tool_calls
942
+ ]
943
+ results = await asyncio.gather(*tasks, return_exceptions=True)
944
+
945
+ # Process results and handle exceptions
946
+ processed_results = []
947
+ for i, result in enumerate(results):
948
+ if isinstance(result, Exception):
949
+ logger.error(
950
+ f"Task {i} failed with exception: {str(result)}"
951
+ )
952
+ processed_results.append(
953
+ {
954
+ "response_index": (
955
+ all_tool_calls[i][0]
956
+ if i < len(all_tool_calls)
957
+ else -1
958
+ ),
959
+ "function_name": "unknown",
960
+ "result": None,
961
+ "error": str(result),
962
+ "status": "exception",
963
+ }
964
+ )
965
+ else:
966
+ processed_results.append(result)
967
+
968
+ logger.info(
969
+ f"Completed execution of {len(processed_results)} tool calls"
970
+ )
971
+ return processed_results
972
+
973
+
974
+ def execute_multiple_tools_on_multiple_mcp_servers_sync(
975
+ responses: List[Dict[str, Any]],
976
+ urls: List[str],
977
+ connections: List[MCPConnection] = None,
978
+ output_type: Literal["json", "dict", "str", "formatted"] = "str",
979
+ max_concurrent: Optional[int] = None,
980
+ *args,
981
+ **kwargs,
982
+ ) -> List[Dict[str, Any]]:
983
+ """
984
+ Synchronous version of execute_multiple_tools_on_multiple_mcp_servers.
985
+
986
+ Args:
987
+ responses: List of responses containing tool calls (OpenAI format)
988
+ urls: List of MCP server URLs
989
+ connections: Optional list of MCPConnection objects corresponding to each URL
990
+ output_type: Output format type for results
991
+ max_concurrent: Maximum number of concurrent executions
992
+
993
+ Returns:
994
+ List of execution results with server metadata
995
+ """
996
+ with get_or_create_event_loop() as loop:
997
+ try:
998
+ return loop.run_until_complete(
999
+ execute_multiple_tools_on_multiple_mcp_servers(
1000
+ responses=responses,
1001
+ urls=urls,
1002
+ connections=connections,
1003
+ output_type=output_type,
1004
+ max_concurrent=max_concurrent,
1005
+ *args,
1006
+ **kwargs,
1007
+ )
1008
+ )
1009
+ except Exception as e:
1010
+ logger.error(
1011
+ f"Error in execute_multiple_tools_on_multiple_mcp_servers_sync: {str(e)}"
1012
+ )
1013
+ raise MCPExecutionError(
1014
+ f"Failed to execute multiple tools sync: {str(e)}"
1015
+ )
@@ -492,7 +492,6 @@ def convert_multiple_functions_to_openai_function_schema(
492
492
  # ]
493
493
  # Use 40% of cpu cores
494
494
  max_workers = int(os.cpu_count() * 0.8)
495
- print(f"max_workers: {max_workers}")
496
495
 
497
496
  with concurrent.futures.ThreadPoolExecutor(
498
497
  max_workers=max_workers
@@ -8,9 +8,10 @@ import subprocess
8
8
  import sys
9
9
  from typing import Literal, Optional, Union
10
10
  from swarms.utils.loguru_logger import initialize_logger
11
- import pkg_resources
12
11
 
13
12
 
13
+ from importlib.metadata import distribution, PackageNotFoundError
14
+
14
15
  logger = initialize_logger("autocheckpackages")
15
16
 
16
17
 
@@ -39,13 +40,13 @@ def check_and_install_package(
39
40
  # Check if package exists
40
41
  if package_manager == "pip":
41
42
  try:
42
- pkg_resources.get_distribution(package_name)
43
+ distribution(package_name)
43
44
  if not upgrade:
44
45
  logger.info(
45
46
  f"Package {package_name} is already installed"
46
47
  )
47
48
  return True
48
- except pkg_resources.DistributionNotFound:
49
+ except PackageNotFoundError:
49
50
  pass
50
51
 
51
52
  # Construct installation command
@@ -23,6 +23,8 @@ def history_output_formatter(
23
23
  return yaml.safe_dump(conversation.to_dict(), sort_keys=False)
24
24
  elif type == "dict-all-except-first":
25
25
  return conversation.return_all_except_first()
26
+ elif type == "list-final":
27
+ return conversation.return_list_final()
26
28
  elif type == "str-all-except-first":
27
29
  return conversation.return_all_except_first_string()
28
30
  elif type == "dict-final":
@@ -12,11 +12,11 @@ HistoryOutputType = Literal[
12
12
  "all",
13
13
  "yaml",
14
14
  "xml",
15
- # "dict-final",
16
15
  "dict-all-except-first",
17
16
  "str-all-except-first",
18
17
  "basemodel",
19
18
  "dict-final",
19
+ "list-final",
20
20
  ]
21
21
 
22
22
  OutputType = HistoryOutputType
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: swarms
3
- Version: 7.8.7
3
+ Version: 7.8.9
4
4
  Summary: Swarms - TGSC
5
5
  License: MIT
6
6
  Keywords: artificial intelligence,deep learning,optimizers,Prompt Engineering,swarms,agents,llms,transformers,multi-agent,swarms of agents,Enterprise-Grade Agents,Production-Grade Agents,Agents,Multi-Grade-Agents,Swarms,Transformers,LLMs,Prompt Engineering,Agents,Generative Agents,Generative AI,Agent Marketplace,Agent Store,quant,finance,algorithmic trading,portfolio optimization,risk management,financial modeling,machine learning for finance,natural language processing for finance
@@ -105,7 +105,7 @@ swarms/schemas/mcp_schemas.py,sha256=XZJ4HyiY_cv8Gvj-53ddjzXuqT9hBU2f0cHbhIKs_jY
105
105
  swarms/schemas/swarms_api_schemas.py,sha256=uKqleW_7hNpqHi06yoba9jS2i9yzZp-SBV944MnkN68,6233
106
106
  swarms/schemas/tool_schema_base_model.py,sha256=0biTGIoibsPPP3fOrkC6WvNU5vXaalyccVKC1fpO_eg,1409
107
107
  swarms/structs/__init__.py,sha256=XbUK6MSivL9qHNFlcoGcAVRYPupQssD3dG_-yAqrycw,4345
108
- swarms/structs/agent.py,sha256=dwCuxBLpPEvJCREfsMbp_Imiz_VtFiZTuXZMrWduIAE,102867
108
+ swarms/structs/agent.py,sha256=azNp6iejRn9GnRcWxkPy3hO38TWPvJTYlZysgfV056Q,104857
109
109
  swarms/structs/agent_builder.py,sha256=tYNpfO4_8cgfMHfgA5DAOWffHnt70p6CLt59esqfVCY,12133
110
110
  swarms/structs/agent_rag_handler.py,sha256=g17YRrNmf16TLvyFCCcsitVk3d-QNZmck_XYmjSN_YM,21372
111
111
  swarms/structs/agent_registry.py,sha256=il507cO1NF-d4ChyANVLuWrN8bXsEAi8_7bLJ_sTU6A,12112
@@ -119,9 +119,9 @@ swarms/structs/base_workflow.py,sha256=DTfFwX3AdFYxACDYwUDqhsbcDZnITlg5TeEYyxmJB
119
119
  swarms/structs/batch_agent_execution.py,sha256=d85DzeCq4uTbbPqLhAXFqFx_cxXUS5yRnJ1-gJkwU5w,1871
120
120
  swarms/structs/concat.py,sha256=utezSxNyh1mIwXgdf8-dJ803NDPyEy79WE8zJHuooGk,732
121
121
  swarms/structs/concurrent_workflow.py,sha256=OqXI-X-9a0hG2a7aLzobwd7CVF2ez0rgLj3ZHqri5bg,12952
122
- swarms/structs/conversation.py,sha256=EagQYlcLoa4Kukb5oQnLDQqpM7-HnIeLNepubIk8ono,49225
122
+ swarms/structs/conversation.py,sha256=06CY2vHXbKr9egwPsQMxZbanxEvuMnuLI-8MXz7v5Bo,49390
123
123
  swarms/structs/council_judge.py,sha256=siYDKiHMvFmShUTXxdo4R6vXiQhKt7bEBI205oC3kU4,19639
124
- swarms/structs/csv_to_agent.py,sha256=PVSbLdWqt6VnnekwqcnWQ8-Am3bhNFsIkUK5GliZV18,11178
124
+ swarms/structs/csv_to_agent.py,sha256=Zv41sjeWA50msq-paGHESzlxZyMU78DYDLNNKZtNfoI,11125
125
125
  swarms/structs/de_hallucination_swarm.py,sha256=9cC0rSSXGwYu6SRDwpeMbCcQ40C1WI1RE9SNapKRLOQ,10309
126
126
  swarms/structs/deep_research_swarm.py,sha256=cNLDI7_lT47q4bCRlMJO4IAO3Fu_iF3nPi3jgtg6CJQ,17026
127
127
  swarms/structs/dynamic_conversational_swarm.py,sha256=xm8x_0OCI4ijatgVt8dzHhLNUyMzqG2U_XQL14kcIS8,8354
@@ -160,11 +160,11 @@ swarms/structs/swarming_architectures.py,sha256=guNQU2N7Ofuk01fZbU3tmBJymnZ9zdGU
160
160
  swarms/structs/tree_swarm.py,sha256=AnIxrt0KhWxAQN8uGjfCcOq-XCmsuTJiH8Ex4mXy8V8,12500
161
161
  swarms/structs/utils.py,sha256=Mo6wHQYOB8baWZUKnAJN5Dsgubpo81umNwJIEDitb2A,1873
162
162
  swarms/structs/various_alt_swarms.py,sha256=qdBuOF31UjatlKRu-9bxwyRQzIjohRhTv_63YoUeYEY,27866
163
- swarms/telemetry/__init__.py,sha256=yibtkHEbQRPUv6ir1FhDHlAO_3nwKJPQH4LjzBC2AuQ,661
163
+ swarms/telemetry/__init__.py,sha256=NfKiXtyEtQJuQ74qiFFy2MxMX5KdgUbU7c3cpnHvhmQ,553
164
164
  swarms/telemetry/bootup.py,sha256=0leCNCy5rhzL19EsOsqHWSDI85KVcWO6_5hLDS0h4sY,1155
165
- swarms/telemetry/main.py,sha256=8FxivorvclSvhgfU03cHFktaRgRNV1UXCMi0VV8-U60,11248
166
- swarms/tools/__init__.py,sha256=tyGQpcfrosMx06fdV9h_8_9WB-1vfT-aAjZufiTXyPQ,1838
167
- swarms/tools/base_tool.py,sha256=kyCteIJxk38jE0upttSQA1iJ1k6GEjebYwhl8WmUxGw,107020
165
+ swarms/telemetry/main.py,sha256=Yvc12fUErOdQgUl4B7blBLALLMnvQ4qGh-vgRZDBewQ,7877
166
+ swarms/tools/__init__.py,sha256=6j4tc28dxLrlHG88Yot90PHuNZxhJFb27xqJ8GjwN-0,2268
167
+ swarms/tools/base_tool.py,sha256=gxGqsXNjxmBxLQ4zX3jsGsXYPtWS6autaahAOAvJrfY,107174
168
168
  swarms/tools/cohere_func_call_schema.py,sha256=XJ6_yBMXCrV9KjN7v9Bk1iFj69TRlGIWYKsUTA1oGiQ,600
169
169
  swarms/tools/create_agent_tool.py,sha256=YsiBgrR9gkn2Jenu_mIFXOMJCWb_Hdw4gBYPQN5HEQk,3467
170
170
  swarms/tools/func_calling_utils.py,sha256=PhHHZRHN-vRHA_h21ELRjXIhSRIrsT4UhU5-1Bhy-iU,3542
@@ -173,10 +173,10 @@ swarms/tools/function_util.py,sha256=DAnAPO0Ik__TAqL7IJzFmkukHnhpsW_QtALl3yj837g
173
173
  swarms/tools/json_former.py,sha256=4ugLQ_EZpghhuhFsVKsy-ehin9K64pqVE2gLU7BTO_M,14376
174
174
  swarms/tools/json_utils.py,sha256=WKMZjcJ0Vt6lgIjiTBenslcfjgRSLX4UWs4uDkKFMQI,1316
175
175
  swarms/tools/logits_processor.py,sha256=NifZZ5w9yemWGJAJ5nHFrphtZVX1XlyesgvYZTxK1GM,2965
176
- swarms/tools/mcp_client_call.py,sha256=8cLwtOAYSRGdCRYq_RujuyLHcApQXmNp6K9vYtv1N6U,15362
176
+ swarms/tools/mcp_client_call.py,sha256=DKivM3OVLeoOjx0hiorSyj3m3Z4MWWwqe4LT6KNi8HU,33007
177
177
  swarms/tools/openai_func_calling_schema_pydantic.py,sha256=6BAH9kuaVTvJIbjgSSJ5XvHhWvWszPxgarkfUuE5Ads,978
178
178
  swarms/tools/openai_tool_creator_decorator.py,sha256=SYZjHnARjWvnH9cBdj7Kc_Yy1muvNxMT3RQz8KkA2SE,2578
179
- swarms/tools/py_func_to_openai_func_str.py,sha256=sjoNutRZ11-0kYFDalUTxZxQ0TEDyn5R8EXMdS4gsgw,17091
179
+ swarms/tools/py_func_to_openai_func_str.py,sha256=MoNVYMiLN_aeexEmzwEktCLEouSmjU8j4XMNcSwU_LU,17050
180
180
  swarms/tools/pydantic_to_json.py,sha256=sd5uWwjSHsu7M8wCBrPv0uje05-K4xcfbvKQ_zOaww8,3399
181
181
  swarms/tools/tool_parse_exec.py,sha256=FW5XzkuNEs2YrroybjKChbCzDvaCs7ypknSDpYhfkd4,8717
182
182
  swarms/tools/tool_registry.py,sha256=ULZmIKBTx9XRCJRD9hwXfY3iQw9v94arw-VV6jcuftY,7992
@@ -184,7 +184,7 @@ swarms/tools/tool_utils.py,sha256=yXzzqG7Ytd8ybB8bsjNUNLaXIuIp9JbbpUKCiHxQqo8,28
184
184
  swarms/utils/__init__.py,sha256=tpbhE-BTISDMXemSRSRJz-Rz7m_C05Q5Pre3d9H9SN4,1195
185
185
  swarms/utils/any_to_str.py,sha256=Qi4N9ed6LYnCs2AeFYo1zwEfYhOKUesGVFUmVUz54KI,2936
186
186
  swarms/utils/audio_processing.py,sha256=Y3KaWG9WJrgquWCeaty20HWPIXfeuPAhcJFzoSBIQjE,9893
187
- swarms/utils/auto_download_check_packages.py,sha256=mqx3jCetfkTuxTdeGLx-gGMB1xWOU5vata8lTKXLatk,4580
187
+ swarms/utils/auto_download_check_packages.py,sha256=nnEPfUr2zy_Y6vPZF56zyWLamz0e2gskS4ecKSw30ww,4594
188
188
  swarms/utils/calculate_func_metrics.py,sha256=Nb5r7rWf809m5F7mWIYXZ0H_WeyGr78A2UZD2GHtJkM,5007
189
189
  swarms/utils/check_all_model_max_tokens.py,sha256=ZHIKlrU-L-OM2IJAbYkCoVyBKe2d0JrGhDC9QNppGIs,1519
190
190
  swarms/utils/data_to_text.py,sha256=1PUoWokylp7MOrGNk1cmO3cJlfskdAIiImGk9ECwsKU,3427
@@ -193,20 +193,20 @@ swarms/utils/file_processing.py,sha256=QjQCIPTcwicQlfy656BXBYpIzMR0s2343E7ftnok5
193
193
  swarms/utils/formatter.py,sha256=e15FsyTIIkyRreMUApkkZCzJC1Sm67w5Zd6EQcUkMwA,4533
194
194
  swarms/utils/function_caller_model.py,sha256=ZfgCMzOizNnuZipYLclTziECNHszH9p8RQcUq7VNr4Q,4156
195
195
  swarms/utils/generate_keys.py,sha256=o5zp_8rwu5sgQnItWS1xAuIIRIkahwm02qy1vsV6DSQ,997
196
- swarms/utils/history_output_formatter.py,sha256=hxRVeusMxcwIPcbPpsmWgxd7PGxBv2eJzUDITbyFvKE,1309
196
+ swarms/utils/history_output_formatter.py,sha256=whjfk4N5SjMo3mtrafNny_alNiAhQcGza3l1dCyg7Nw,1388
197
197
  swarms/utils/index.py,sha256=iYVlMiuSpBuKHF34uSrxDUuSYmS26bbYoAqyz_VIyvY,6902
198
198
  swarms/utils/litellm_tokenizer.py,sha256=PqzAY4C5lJ3P-K9SL-dCNtxmHHlZvAw1UohT-ob9lxY,3389
199
199
  swarms/utils/litellm_wrapper.py,sha256=moSaVYIViCSib2r1kS2h1BqltQKcysVJCeI6cAXp2bU,19566
200
200
  swarms/utils/loguru_logger.py,sha256=hIoSK3NHLpe7eAmjHRURrEYzNXYC2gbR7_Vv63Yaydk,685
201
- swarms/utils/output_types.py,sha256=yEggBESV8D-gOh7NR6OpOT0WUmA97oz514f27B9NV1Y,406
201
+ swarms/utils/output_types.py,sha256=jPOiRr2s114Dw2ngG8DTtxHIWZikMfNtXkyLtgghj9w,404
202
202
  swarms/utils/parse_code.py,sha256=XFOLymbdP3HzMZuqsj7pwUyisvUmTm0ev9iThR_ambI,1987
203
203
  swarms/utils/pdf_to_text.py,sha256=nkySOS_sJ4Jf4RP5SoDpMB5WfjJ_GGc5z8gJfn2cxOM,1311
204
204
  swarms/utils/str_to_dict.py,sha256=T3Jsdjz87WIlkSo7jAW6BB80sv0Ns49WT1qXlOrdEoE,874
205
205
  swarms/utils/try_except_wrapper.py,sha256=uvDZDZJcH986EF0Ej6zZBLcqHJ58NHizPsAH5olrE7Q,3919
206
206
  swarms/utils/vllm_wrapper.py,sha256=sNkm4EbeMrqqmHidnvq5zTnofQAaARy3HIrNBu11lKs,5072
207
207
  swarms/utils/xml_utils.py,sha256=D4nEdo1nkHqSoTKrWylXBXjcHFhGaOYvvfGNQQoYV5o,2514
208
- swarms-7.8.7.dist-info/LICENSE,sha256=jwRtEmTWjLrEsvFB6QFdYs2cEeZPRMdj-UMOFkPF8_0,11363
209
- swarms-7.8.7.dist-info/METADATA,sha256=ysQ9oCgqZ8C76O62Z3g0L_RSZOq-4iyw_yjVdUYrAhk,94363
210
- swarms-7.8.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
211
- swarms-7.8.7.dist-info/entry_points.txt,sha256=2K0rTtfO1X1WaO-waJlXIKw5Voa_EpAL_yU0HXE2Jgc,47
212
- swarms-7.8.7.dist-info/RECORD,,
208
+ swarms-7.8.9.dist-info/LICENSE,sha256=jwRtEmTWjLrEsvFB6QFdYs2cEeZPRMdj-UMOFkPF8_0,11363
209
+ swarms-7.8.9.dist-info/METADATA,sha256=-jF_6uuBLf4o-NOrosFWpsPN84oaSLBHa7hw_loIipo,94363
210
+ swarms-7.8.9.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
211
+ swarms-7.8.9.dist-info/entry_points.txt,sha256=2K0rTtfO1X1WaO-waJlXIKw5Voa_EpAL_yU0HXE2Jgc,47
212
+ swarms-7.8.9.dist-info/RECORD,,
File without changes