Merge branch 'master' into cursor-agent

pull/1182/head
CI-DEV 1 month ago committed by GitHub
commit 3c4d4e19ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,67 +1,36 @@
<div align="center">
<a href="https://swarms.world">
<img src="https://github.com/kyegomez/swarms/blob/master/images/swarmslogobanner.png" style="margin: 15px; max-width: 700px" width="100%" alt="Logo">
<img src="https://github.com/kyegomez/swarms/blob/master/images/new_logo.png" style="margin: 15px; max-width: 350px" width="70%" alt="Logo">
</a>
</div>
<p align="center">
<em>The Enterprise-Grade Production-Ready Multi-Agent Orchestration Framework </em>
</p>
<p align="center">
<a href="https://pypi.org/project/swarms/" target="_blank">
<picture>
<source srcset="https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54" media="(prefers-color-scheme: dark)">
<img alt="Python" src="https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54" />
</picture>
<picture>
<source srcset="https://img.shields.io/pypi/v/swarms?style=for-the-badge&color=3670A0" media="(prefers-color-scheme: dark)">
<img alt="Version" src="https://img.shields.io/pypi/v/swarms?style=for-the-badge&color=3670A0">
</picture>
</a>
<!-- Main Navigation Links -->
<a href="https://swarms.ai">🏠 Swarms Website</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://docs.swarms.world">📙 Documentation</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://swarms.world">🛒 Swarms Marketplace</a>
</p>
<p align="center">
<!-- Project Stats - Most Important First -->
<a href="https://github.com/kyegomez/swarms/stargazers">
<picture>
<source srcset="https://img.shields.io/github/stars/kyegomez/swarms?style=for-the-badge" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/github/stars/kyegomez/swarms?style=for-the-badge" alt="GitHub stars">
</picture>
</a>
<a href="https://github.com/kyegomez/swarms/network">
<picture>
<source srcset="https://img.shields.io/github/forks/kyegomez/swarms?style=for-the-badge" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/github/forks/kyegomez/swarms?style=for-the-badge" alt="GitHub forks">
</picture>
</a>
<a href="https://github.com/kyegomez/swarms/issues">
<picture>
<source srcset="https://img.shields.io/github/issues/kyegomez/swarms?style=for-the-badge" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/github/issues/kyegomez/swarms?style=for-the-badge" alt="GitHub issues">
</picture>
</a>
<a href="https://github.com/kyegomez/swarms/blob/main/LICENSE">
<picture>
<source srcset="https://img.shields.io/github/license/kyegomez/swarms?style=for-the-badge" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/github/license/kyegomez/swarms?style=for-the-badge" alt="GitHub license">
</picture>
</a>
<a href="https://pepy.tech/project/swarms">
<a href="https://pypi.org/project/swarms/" target="_blank">
<picture>
<source srcset="https://static.pepy.tech/badge/swarms/month" media="(prefers-color-scheme: dark)">
<img src="https://static.pepy.tech/badge/swarms/month" alt="Downloads">
<source srcset="https://img.shields.io/pypi/v/swarms?style=for-the-badge&color=3670A0" media="(prefers-color-scheme: dark)">
<img alt="Version" src="https://img.shields.io/pypi/v/swarms?style=for-the-badge&color=3670A0">
</picture>
</a>
<a href="https://libraries.io/github/kyegomez/swarms">
<a href="https://pypi.org/project/swarms/" target="_blank">
<picture>
<source srcset="https://img.shields.io/librariesio/github/kyegomez/swarms?style=for-the-badge" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/librariesio/github/kyegomez/swarms?style=for-the-badge" alt="Dependency Status">
<source srcset="https://img.shields.io/pypi/dm/swarms?style=for-the-badge&color=3670A0" media="(prefers-color-scheme: dark)">
<img alt="Downloads" src="https://img.shields.io/pypi/dm/swarms?style=for-the-badge&color=3670A0">
</picture>
</a>
</p>
<p align="center">
<!-- Social Media -->
<a href="https://twitter.com/swarms_corp/">
<picture>
<source srcset="https://img.shields.io/badge/Twitter-Follow-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white" media="(prefers-color-scheme: dark)">
@ -74,49 +43,6 @@
<img src="https://img.shields.io/badge/Discord-Join-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Discord">
</picture>
</a>
<a href="https://www.youtube.com/@kyegomez3242">
<picture>
<source srcset="https://img.shields.io/badge/YouTube-Subscribe-red?style=for-the-badge&logo=youtube&logoColor=white" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/badge/YouTube-Subscribe-red?style=for-the-badge&logo=youtube&logoColor=white" alt="YouTube">
</picture>
</a>
<a href="https://www.linkedin.com/in/kye-g-38759a207/">
<picture>
<source srcset="https://img.shields.io/badge/LinkedIn-Connect-blue?style=for-the-badge&logo=linkedin&logoColor=white" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/badge/LinkedIn-Connect-blue?style=for-the-badge&logo=linkedin&logoColor=white" alt="LinkedIn">
</picture>
</a>
<a href="https://x.com/swarms_corp">
<picture>
<source srcset="https://img.shields.io/badge/X.com-Follow-1DA1F2?style=for-the-badge&logo=x&logoColor=white" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/badge/X.com-Follow-1DA1F2?style=for-the-badge&logo=x&logoColor=white" alt="X.com">
</picture>
</a>
</p>
<p align="center">
<!-- Main Navigation Links -->
<a href="https://swarms.ai">🏠 Swarms Website</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://docs.swarms.world">📙 Documentation</a>
<span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
<a href="https://swarms.world">🛒 Swarms Marketplace</a>
</p>
<p align="center">
<!-- Share Buttons -->
<a href="https://twitter.com/intent/tweet?text=Check%20out%20this%20amazing%20AI%20project:%20&url=https%3A%2F%2Fgithub.com%2Fkyegomez%2Fswarms">
<picture>
<source srcset="https://img.shields.io/badge/Share%20on%20Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/badge/Share%20on%20Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white" alt="Share on Twitter">
</picture>
</a>
<a href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fgithub.com%2Fkyegomez%2Fswarms&title=&summary=&source=">
<picture>
<source srcset="https://img.shields.io/badge/Share%20on%20LinkedIn-blue?style=for-the-badge" media="(prefers-color-scheme: dark)">
<img src="https://img.shields.io/badge/Share%20on%20LinkedIn-blue?style=for-the-badge" alt="Share on LinkedIn">
</picture>
</a>
</p>
## ✨ Features
@ -160,12 +86,10 @@ $ poetry add swarms
# Clone the repository
$ git clone https://github.com/kyegomez/swarms.git
$ cd swarms
# Install with pip
$ pip install -e .
$ pip install -r requirements.txt
```
### Using Docker
<!-- ### Using Docker
The easiest way to get started with Swarms is using our pre-built Docker image:
@ -181,7 +105,7 @@ $ docker run -it --rm -v $(pwd):/app kyegomez/swarms:latest bash
$ docker-compose up -d
```
For more Docker options and advanced usage, see our [Docker documentation](/scripts/docker/DOCKER.md).
For more Docker options and advanced usage, see our [Docker documentation](/scripts/docker/DOCKER.md). -->
---

@ -199,9 +199,14 @@ Run the MCP server (alias for start_server).
##### get_server_info()
Get information about the MCP server and registered tools.
**Returns:** `Dict[str, Any]` - Server information
Get comprehensive information about the MCP server and registered tools, including metadata, configuration, tool details, queue stats, and network status.
**Returns:** `Dict[str, Any]` - Server information including:
- Server metadata (name, description, creation time, uptime)
- Configuration (host, port, transport, log level)
- Agent information (total count, names, detailed tool info)
- Queue configuration and statistics (if queue enabled)
- Persistence and network status
##### _register_tool()

@ -0,0 +1,88 @@
import json
from swarms import Agent
blood_analysis_system_prompt = """You are a clinical laboratory data analyst assistant focused on hematology and basic metabolic panels.
Your goals:
1) Interpret common blood test panels (CBC, CMP/BMP, lipid panel, HbA1c, thyroid panels) based on provided values, reference ranges, flags, and units.
2) Provide structured findings: out-of-range markers, degree of deviation, likely clinical significance, and differential considerations.
3) Identify potential pre-analytical, analytical, or biological confounders (e.g., hemolysis, fasting status, pregnancy, medications).
4) Suggest safe, non-diagnostic next steps: retest windows, confirmatory labs, context to gather, and when to escalate to a clinician.
5) Clearly separate informational insights from non-medical advice and include source-backed rationale where possible.
Reliability and safety:
- This is not medical advice. Do not diagnose, treat, or provide definitive clinical decisions.
- Use cautious language; do not overstate certainty. Include confidence levels (low/medium/high).
- Highlight red-flag combinations that warrant urgent clinical evaluation.
- Prefer reputable sources: peerreviewed literature, clinical guidelines (e.g., WHO, CDC, NIH, NICE), and standard lab references.
Output format (JSON-like sections, not strict JSON):
SECTION: SUMMARY
SECTION: KEY ABNORMALITIES
SECTION: DIFFERENTIAL CONSIDERATIONS
SECTION: RED FLAGS (if any)
SECTION: CONTEXT/CONFIDENCE
SECTION: SUGGESTED NON-CLINICAL NEXT STEPS
SECTION: SOURCES
"""
# =========================
# Medical Agents
# =========================
blood_analysis_agent = Agent(
agent_name="Blood-Data-Analysis-Agent",
agent_description="Explains and contextualizes common blood test panels with structured insights",
model_name="claude-haiku-4-5",
max_loops=1,
top_p=None,
dynamic_temperature_enabled=True,
system_prompt=blood_analysis_system_prompt,
tags=["lab", "hematology", "metabolic", "education"],
capabilities=[
"panel-interpretation",
"risk-flagging",
"guideline-citation",
],
role="worker",
temperature=None,
output_type="dict",
publish_to_marketplace=True,
use_cases=[
{
"title": "Blood Analysis",
"description": (
"Analyze blood samples and provide a report on the results, "
"highlighting significant deviations, clinical context, red flags, "
"and referencing established guidelines for lab test interpretation."
),
},
{
"title": "Longitudinal Patient Lab Monitoring",
"description": (
"Process serial blood test results for a patient over time to identify clinical trends in key parameters (e.g., "
"progression of anemia, impact of pharmacologic therapy, signs of organ dysfunction). Generate structured summaries "
"that succinctly track rises, drops, or persistently abnormal markers. Flag patterns that suggest evolving risk or "
"require physician escalation, such as a dropping platelet count, rising creatinine, or new-onset hyperglycemia. "
"Report should distinguish true trends from ordinary biological variability, referencing clinical guidelines for "
"critical-change thresholds and best-practice follow-up actions."
),
},
{
"title": "Preoperative Laboratory Risk Stratification",
"description": (
"Interpret pre-surgical laboratory panels as part of risk assessment for patients scheduled for procedures. Identify "
"abnormal or borderline values that may increase the risk of perioperative complications (e.g., bleeding risk from "
"thrombocytopenia, signs of undiagnosed infection, electrolyte imbalances affecting anesthesia safety). Structure the "
"output to clearly separate routine findings from emergent concerns, and suggest evidence-based adjustments, further "
"workup, or consultation needs before proceeding with surgery, based on current clinical best practices and guideline "
"recommendations."
),
},
],
)
out = blood_analysis_agent.run(
task="Analyze this blood sample: Hematology and Basic Metabolic Panel"
)
print(json.dumps(out, indent=4))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

@ -102,6 +102,9 @@ from swarms.utils.litellm_tokenizer import count_tokens
from swarms.utils.litellm_wrapper import LiteLLM
from swarms.utils.output_types import OutputType
from swarms.utils.pdf_to_text import pdf_to_text
from swarms.utils.swarms_marketplace_utils import (
add_prompt_to_marketplace,
)
# REACT workflow tools for auto mode
@ -479,7 +482,6 @@ class Agent:
created_at: float = time.time(),
return_step_meta: Optional[bool] = False,
tags: Optional[List[str]] = None,
use_cases: Optional[List[Dict[str, str]]] = None,
step_pool: List[Step] = [],
print_every_step: Optional[bool] = False,
time_created: Optional[str] = time.strftime(
@ -531,6 +533,8 @@ class Agent:
handoffs: Optional[Union[Sequence[Callable], Any]] = None,
capabilities: Optional[List[str]] = None,
mode: Literal["interactive", "fast", "standard"] = "standard",
publish_to_marketplace: bool = False,
use_cases: Optional[List[Dict[str, Any]]] = None,
*args,
**kwargs,
):
@ -682,6 +686,7 @@ class Agent:
self.handoffs = handoffs
self.capabilities = capabilities
self.mode = mode
self.publish_to_marketplace = publish_to_marketplace
# Initialize transforms
if transforms is None:
@ -755,6 +760,30 @@ class Agent:
self.print_on = False
self.verbose = False
if self.publish_to_marketplace is True:
# Join tags and capabilities into a single string
tags_and_capabilities = ", ".join(
self.tags + self.capabilities
if self.tags and self.capabilities
else None
)
if self.use_cases is None:
raise AgentInitializationError(
"Use cases are required when publishing to the marketplace. The schema is a list of dictionaries with 'title' and 'description' keys."
)
add_prompt_to_marketplace(
name=self.agent_name,
prompt=self.short_memory.get_str(),
description=self.agent_description,
tags=tags_and_capabilities,
category="research",
use_cases=(
self.use_cases if self.use_cases else None
),
)
def handle_handoffs(self, task: Optional[str] = None):
router = MultiAgentRouter(
name=self.agent_name,

@ -659,6 +659,9 @@ class AOP:
self._last_network_error = None
self._network_connected = True
# Server creation timestamp
self._created_at = time.time()
self.agents: Dict[str, Agent] = {}
self.tool_configs: Dict[str, AgentToolConfig] = {}
self.task_queues: Dict[str, TaskQueue] = {}
@ -1980,6 +1983,53 @@ class AOP:
"matching_agents": [],
}
@self.mcp_server.tool(
name="get_server_info",
description="Get comprehensive server information including metadata, configuration, tool details, queue stats, and network status.",
)
def get_server_info_tool() -> Dict[str, Any]:
"""
Get comprehensive information about the MCP server and registered tools.
Returns:
Dict containing server information with the following fields:
- server_name: Name of the server
- description: Server description
- total_tools/total_agents: Total number of agents registered
- tools/agent_names: List of all agent names
- created_at: Unix timestamp when server was created
- created_at_iso: ISO formatted creation time
- uptime_seconds: Server uptime in seconds
- host: Server host address
- port: Server port number
- transport: Transport protocol used
- log_level: Logging level
- queue_enabled: Whether queue system is enabled
- persistence_enabled: Whether persistence mode is enabled
- network_monitoring_enabled: Whether network monitoring is enabled
- persistence: Detailed persistence status
- network: Detailed network status
- tool_details: Detailed information about each agent tool
- queue_config: Queue configuration (if queue enabled)
- queue_stats: Queue statistics for each agent (if queue enabled)
"""
try:
server_info = self.get_server_info()
return {
"success": True,
"server_info": server_info,
}
except Exception as e:
error_msg = str(e)
logger.error(
f"Error in get_server_info tool: {error_msg}"
)
return {
"success": False,
"error": error_msg,
"server_info": None,
}
def _register_queue_management_tools(self) -> None:
"""
Register queue management tools for the MCP server.
@ -2699,18 +2749,32 @@ class AOP:
Get information about the MCP server and registered tools.
Returns:
Dict containing server information
Dict containing server information including metadata, configuration,
and tool details
"""
info = {
"server_name": self.server_name,
"description": self.description,
"total_tools": len(self.agents),
"total_agents": len(
self.agents
), # Alias for compatibility
"tools": self.list_agents(),
"agent_names": self.list_agents(), # Alias for compatibility
"created_at": self._created_at,
"created_at_iso": time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(self._created_at)
),
"uptime_seconds": time.time() - self._created_at,
"verbose": self.verbose,
"traceback_enabled": self.traceback_enabled,
"log_level": self.log_level,
"transport": self.transport,
"host": self.host,
"port": self.port,
"queue_enabled": self.queue_enabled,
"persistence_enabled": self._persistence_enabled, # Top-level for compatibility
"network_monitoring_enabled": self.network_monitoring, # Top-level for compatibility
"persistence": self.get_persistence_status(),
"network": self.get_network_status(),
"tool_details": {

@ -0,0 +1,145 @@
import os
import traceback
from typing import Any, Dict, List
import httpx
from loguru import logger
def add_prompt_to_marketplace(
name: str = None,
prompt: str = None,
description: str = None,
use_cases: List[Dict[str, str]] = None,
tags: str = None,
is_free: bool = True,
price_usd: float = 0.0,
category: str = "research",
timeout: float = 30.0,
) -> Dict[str, Any]:
"""
Add a prompt to the Swarms marketplace.
Args:
name: The name of the prompt.
prompt: The prompt text/template.
description: A description of what the prompt does.
use_cases: List of dictionaries with 'title' and 'description' keys
describing use cases for the prompt.
tags: Comma-separated string of tags for the prompt.
is_free: Whether the prompt is free or paid.
price_usd: Price in USD (ignored if is_free is True).
category: Category of the prompt (e.g., "content", "coding", etc.).
timeout: Request timeout in seconds. Defaults to 30.0.
Returns:
Dictionary containing the API response.
Raises:
httpx.HTTPError: If the HTTP request fails.
httpx.RequestError: If there's an error making the request.
"""
try:
url = "https://swarms.world/api/add-prompt"
api_key = os.getenv("SWARMS_API_KEY")
if api_key is None or api_key.strip() == "":
raise ValueError(
"Swarms API key is not set. Please set the SWARMS_API_KEY environment variable. "
"You can get your key here: https://swarms.world/platform/api-keys"
)
# Log that we have an API key (without exposing it)
logger.debug(
f"Using API key (length: {len(api_key)} characters)"
)
# Validate required fields
if name is None:
raise ValueError("name is required")
if prompt is None:
raise ValueError("prompt is required")
if description is None:
raise ValueError("description is required")
if category is None:
raise ValueError("category is required")
if use_cases is None:
raise ValueError("use_cases is required")
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
data = {
"name": name,
"prompt": prompt,
"description": description,
"useCases": use_cases or [],
"tags": tags or "",
"is_free": is_free,
"price_usd": price_usd,
"category": category,
}
with httpx.Client(timeout=timeout) as client:
response = client.post(url, json=data, headers=headers)
# Try to get response body for better error messages
try:
response_body = response.json()
except Exception:
response_body = response.text
if response.status_code >= 400:
error_msg = f"HTTP {response.status_code}: {response.reason_phrase}"
if response_body:
error_msg += f"\nResponse: {response_body}"
logger.error(
f"Error adding prompt to marketplace: {error_msg}"
)
response.raise_for_status()
logger.info(
f"Prompt Name: {name} Successfully added to marketplace"
)
return response_body
except httpx.HTTPStatusError as e:
logger.error(f"HTTP error adding prompt to marketplace: {e}")
if hasattr(e, "response") and e.response is not None:
try:
error_body = e.response.json()
logger.error(f"Error response body: {error_body}")
# Provide helpful error message for authentication failures
if (
e.response.status_code == 401
or e.response.status_code == 500
):
if isinstance(error_body, dict):
if (
"authentication"
in str(error_body).lower()
or "auth" in str(error_body).lower()
):
logger.error(
"Authentication failed. Please check:\n"
"1. Your SWARMS_API_KEY environment variable is set correctly\n"
"2. Your API key is valid and not expired\n"
"3. You can verify your key at: https://swarms.world/platform/api-keys"
)
except Exception:
logger.error(
f"Error response text: {e.response.text}"
)
raise
except httpx.RequestError as e:
logger.error(
f"Request error adding prompt to marketplace: {e}"
)
raise
except Exception as e:
logger.error(
f"Error adding prompt to marketplace: {e} Traceback: {traceback.format_exc()}"
)
raise

@ -0,0 +1,306 @@
"""
Pytest tests for swarms_marketplace_utils module.
"""
import os
from unittest.mock import Mock, patch
import pytest
from swarms.utils.swarms_marketplace_utils import (
add_prompt_to_marketplace,
)
class TestAddPromptToMarketplace:
"""Test cases for add_prompt_to_marketplace function."""
@patch.dict(os.environ, {"SWARMS_API_KEY": "test_api_key_12345"})
@patch("swarms.utils.swarms_marketplace_utils.httpx.Client")
def test_add_prompt_success(self, mock_client_class):
"""Test successful addition of prompt to marketplace."""
# Mock response
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"id": "123",
"name": "Blood Analysis Agent",
"status": "success",
}
mock_response.text = ""
mock_response.raise_for_status = Mock()
# Mock client
mock_client = Mock()
mock_client.__enter__ = Mock(return_value=mock_client)
mock_client.__exit__ = Mock(return_value=False)
mock_client.post.return_value = mock_response
mock_client_class.return_value = mock_client
# Call function
result = add_prompt_to_marketplace(
name="Blood Analysis Agent",
prompt="You are a blood analysis agent that can analyze blood samples and provide a report on the results.",
description="A blood analysis agent that can analyze blood samples and provide a report on the results.",
use_cases=[
{
"title": "Blood Analysis",
"description": "Analyze blood samples and provide a report on the results.",
}
],
tags="blood, analysis, report",
category="research",
)
# Assertions
assert result["id"] == "123"
assert result["name"] == "Blood Analysis Agent"
assert result["status"] == "success"
mock_client.post.assert_called_once()
call_args = mock_client.post.call_args
assert call_args[0][0] == "https://swarms.world/api/add-prompt"
assert call_args[1]["headers"]["Authorization"] == "Bearer test_api_key_12345"
assert call_args[1]["json"]["name"] == "Blood Analysis Agent"
assert call_args[1]["json"]["category"] == "research"
@patch.dict(os.environ, {"SWARMS_API_KEY": "test_api_key_12345"})
@patch("swarms.utils.swarms_marketplace_utils.httpx.Client")
def test_add_prompt_with_all_parameters(self, mock_client_class):
"""Test adding prompt with all optional parameters."""
# Mock response
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"id": "456", "status": "success"}
mock_response.text = ""
mock_response.raise_for_status = Mock()
# Mock client
mock_client = Mock()
mock_client.__enter__ = Mock(return_value=mock_client)
mock_client.__exit__ = Mock(return_value=False)
mock_client.post.return_value = mock_response
mock_client_class.return_value = mock_client
# Call function with all parameters
result = add_prompt_to_marketplace(
name="Test Prompt",
prompt="Test prompt text",
description="Test description",
use_cases=[{"title": "Use Case 1", "description": "Description 1"}],
tags="tag1, tag2",
is_free=False,
price_usd=9.99,
category="coding",
timeout=60.0,
)
# Assertions
assert result["id"] == "456"
call_args = mock_client.post.call_args
json_data = call_args[1]["json"]
assert json_data["is_free"] is False
assert json_data["price_usd"] == 9.99
assert json_data["category"] == "coding"
assert json_data["tags"] == "tag1, tag2"
def test_add_prompt_missing_api_key(self):
"""Test that missing API key raises ValueError."""
with patch.dict(os.environ, {}, clear=True):
with pytest.raises(ValueError, match="Swarms API key is not set"):
add_prompt_to_marketplace(
name="Test",
prompt="Test prompt",
description="Test description",
use_cases=[],
category="research",
)
def test_add_prompt_empty_api_key(self):
"""Test that empty API key raises ValueError."""
with patch.dict(os.environ, {"SWARMS_API_KEY": ""}):
with pytest.raises(ValueError, match="Swarms API key is not set"):
add_prompt_to_marketplace(
name="Test",
prompt="Test prompt",
description="Test description",
use_cases=[],
category="research",
)
def test_add_prompt_missing_name(self):
"""Test that missing name raises ValueError."""
with patch.dict(os.environ, {"SWARMS_API_KEY": "test_key"}):
with pytest.raises(ValueError, match="name is required"):
add_prompt_to_marketplace(
name=None,
prompt="Test prompt",
description="Test description",
use_cases=[],
category="research",
)
def test_add_prompt_missing_prompt(self):
"""Test that missing prompt raises ValueError."""
with patch.dict(os.environ, {"SWARMS_API_KEY": "test_key"}):
with pytest.raises(ValueError, match="prompt is required"):
add_prompt_to_marketplace(
name="Test",
prompt=None,
description="Test description",
use_cases=[],
category="research",
)
def test_add_prompt_missing_description(self):
"""Test that missing description raises ValueError."""
with patch.dict(os.environ, {"SWARMS_API_KEY": "test_key"}):
with pytest.raises(ValueError, match="description is required"):
add_prompt_to_marketplace(
name="Test",
prompt="Test prompt",
description=None,
use_cases=[],
category="research",
)
def test_add_prompt_missing_category(self):
"""Test that missing category raises ValueError."""
with patch.dict(os.environ, {"SWARMS_API_KEY": "test_key"}):
with pytest.raises(ValueError, match="category is required"):
add_prompt_to_marketplace(
name="Test",
prompt="Test prompt",
description="Test description",
use_cases=[],
category=None,
)
def test_add_prompt_missing_use_cases(self):
"""Test that missing use_cases raises ValueError."""
with patch.dict(os.environ, {"SWARMS_API_KEY": "test_key"}):
with pytest.raises(ValueError, match="use_cases is required"):
add_prompt_to_marketplace(
name="Test",
prompt="Test prompt",
description="Test description",
use_cases=None,
category="research",
)
@patch.dict(os.environ, {"SWARMS_API_KEY": "test_api_key_12345"})
@patch("swarms.utils.swarms_marketplace_utils.httpx.Client")
def test_add_prompt_http_error(self, mock_client_class):
"""Test handling of HTTP error responses."""
# Mock response with error
mock_response = Mock()
mock_response.status_code = 400
mock_response.reason_phrase = "Bad Request"
mock_response.json.return_value = {"error": "Invalid request"}
mock_response.text = '{"error": "Invalid request"}'
mock_response.raise_for_status.side_effect = Exception("HTTP 400")
# Mock client
mock_client = Mock()
mock_client.__enter__ = Mock(return_value=mock_client)
mock_client.__exit__ = Mock(return_value=False)
mock_client.post.return_value = mock_response
mock_client_class.return_value = mock_client
# Call function and expect exception
with pytest.raises(Exception):
add_prompt_to_marketplace(
name="Test",
prompt="Test prompt",
description="Test description",
use_cases=[],
category="research",
)
@patch.dict(os.environ, {"SWARMS_API_KEY": "test_api_key_12345"})
@patch("swarms.utils.swarms_marketplace_utils.httpx.Client")
def test_add_prompt_authentication_error(self, mock_client_class):
"""Test handling of authentication errors."""
# Mock response with 401 error
mock_response = Mock()
mock_response.status_code = 401
mock_response.reason_phrase = "Unauthorized"
mock_response.json.return_value = {
"error": "Authentication failed"
}
mock_response.text = '{"error": "Authentication failed"}'
mock_response.raise_for_status.side_effect = Exception("HTTP 401")
# Mock client
mock_client = Mock()
mock_client.__enter__ = Mock(return_value=mock_client)
mock_client.__exit__ = Mock(return_value=False)
mock_client.post.return_value = mock_response
mock_client_class.return_value = mock_client
# Call function and expect exception
with pytest.raises(Exception):
add_prompt_to_marketplace(
name="Test",
prompt="Test prompt",
description="Test description",
use_cases=[],
category="research",
)
@patch.dict(os.environ, {"SWARMS_API_KEY": "test_api_key_12345"})
@patch("swarms.utils.swarms_marketplace_utils.httpx.Client")
def test_add_prompt_with_empty_tags(self, mock_client_class):
"""Test adding prompt with empty tags."""
# Mock response
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"id": "789", "status": "success"}
mock_response.text = ""
mock_response.raise_for_status = Mock()
# Mock client
mock_client = Mock()
mock_client.__enter__ = Mock(return_value=mock_client)
mock_client.__exit__ = Mock(return_value=False)
mock_client.post.return_value = mock_response
mock_client_class.return_value = mock_client
# Call function with empty tags
result = add_prompt_to_marketplace(
name="Test",
prompt="Test prompt",
description="Test description",
use_cases=[],
tags=None,
category="research",
)
# Assertions
assert result["id"] == "789"
call_args = mock_client.post.call_args
assert call_args[1]["json"]["tags"] == ""
@patch.dict(os.environ, {"SWARMS_API_KEY": "test_api_key_12345"})
@patch("swarms.utils.swarms_marketplace_utils.httpx.Client")
def test_add_prompt_request_timeout(self, mock_client_class):
"""Test handling of request timeout."""
# Mock client to raise timeout error
mock_client = Mock()
mock_client.__enter__ = Mock(return_value=mock_client)
mock_client.__exit__ = Mock(return_value=False)
mock_client.post.side_effect = Exception("Request timeout")
mock_client_class.return_value = mock_client
# Call function and expect exception
with pytest.raises(Exception):
add_prompt_to_marketplace(
name="Test",
prompt="Test prompt",
description="Test description",
use_cases=[],
category="research",
timeout=5.0,
)
if __name__ == "__main__":
pytest.main([__file__, "-v"])
Loading…
Cancel
Save