Spaces:
Runtime error
Runtime error
import json | |
import os | |
import platform | |
import sys | |
import traceback | |
from dataclasses import dataclass | |
from datetime import datetime | |
from typing import Any, Dict, List, Optional, Tuple | |
import psutil | |
import requests | |
from loguru import logger | |
from swarm_models import OpenAIChat | |
from swarms.structs.agent import Agent | |
class SwarmSystemInfo: | |
"""System information for Swarms issue reports.""" | |
os_name: str | |
os_version: str | |
python_version: str | |
cpu_usage: float | |
memory_usage: float | |
disk_usage: float | |
swarms_version: str # Added Swarms version tracking | |
cuda_available: bool # Added CUDA availability check | |
gpu_info: Optional[str] # Added GPU information | |
class SwarmsIssueReporter: | |
""" | |
Production-grade GitHub issue reporter specifically designed for the Swarms library. | |
Automatically creates detailed issues for the https://github.com/kyegomez/swarms repository. | |
Features: | |
- Swarms-specific error categorization | |
- Automatic version and dependency tracking | |
- CUDA and GPU information collection | |
- Integration with Swarms logging system | |
- Detailed environment information | |
""" | |
REPO_OWNER = "kyegomez" | |
REPO_NAME = "swarms" | |
ISSUE_CATEGORIES = { | |
"agent": ["agent", "automation"], | |
"memory": ["memory", "storage"], | |
"tool": ["tools", "integration"], | |
"llm": ["llm", "model"], | |
"performance": ["performance", "optimization"], | |
"compatibility": ["compatibility", "environment"], | |
} | |
def __init__( | |
self, | |
github_token: str, | |
rate_limit: int = 10, | |
rate_period: int = 3600, | |
log_file: str = "swarms_issues.log", | |
enable_duplicate_check: bool = True, | |
): | |
""" | |
Initialize the Swarms Issue Reporter. | |
Args: | |
github_token (str): GitHub personal access token | |
rate_limit (int): Maximum number of issues to create per rate_period | |
rate_period (int): Time period for rate limiting in seconds | |
log_file (str): Path to log file | |
enable_duplicate_check (bool): Whether to check for duplicate issues | |
""" | |
self.github_token = github_token | |
self.rate_limit = rate_limit | |
self.rate_period = rate_period | |
self.enable_duplicate_check = enable_duplicate_check | |
self.github_token = os.getenv("GITHUB_API_KEY") | |
# Initialize logging | |
log_path = os.path.join(os.getcwd(), "logs", log_file) | |
os.makedirs(os.path.dirname(log_path), exist_ok=True) | |
logger.add( | |
log_path, | |
rotation="1 day", | |
retention="1 month", | |
compression="zip", | |
) | |
# Issue tracking | |
self.issues_created = [] | |
self.last_issue_time = datetime.now() | |
def _get_swarms_version(self) -> str: | |
"""Get the installed version of Swarms.""" | |
try: | |
import swarms | |
return swarms.__version__ | |
except: | |
return "Unknown" | |
def _get_gpu_info(self) -> Tuple[bool, Optional[str]]: | |
"""Get GPU information and CUDA availability.""" | |
try: | |
import torch | |
cuda_available = torch.cuda.is_available() | |
if cuda_available: | |
gpu_info = torch.cuda.get_device_name(0) | |
return cuda_available, gpu_info | |
return False, None | |
except: | |
return False, None | |
def _get_system_info(self) -> SwarmSystemInfo: | |
"""Collect system and Swarms-specific information.""" | |
cuda_available, gpu_info = self._get_gpu_info() | |
return SwarmSystemInfo( | |
os_name=platform.system(), | |
os_version=platform.version(), | |
python_version=sys.version, | |
cpu_usage=psutil.cpu_percent(), | |
memory_usage=psutil.virtual_memory().percent, | |
disk_usage=psutil.disk_usage("/").percent, | |
swarms_version=self._get_swarms_version(), | |
cuda_available=cuda_available, | |
gpu_info=gpu_info, | |
) | |
def _categorize_error( | |
self, error: Exception, context: Dict | |
) -> List[str]: | |
"""Categorize the error and return appropriate labels.""" | |
error_str = str(error).lower() | |
type(error).__name__ | |
labels = ["bug", "automated"] | |
# Check error message and context for category keywords | |
for ( | |
category, | |
category_labels, | |
) in self.ISSUE_CATEGORIES.items(): | |
if any( | |
keyword in error_str for keyword in category_labels | |
): | |
labels.extend(category_labels) | |
break | |
# Add severity label based on error type | |
if issubclass(type(error), (SystemError, MemoryError)): | |
labels.append("severity:critical") | |
elif issubclass(type(error), (ValueError, TypeError)): | |
labels.append("severity:medium") | |
else: | |
labels.append("severity:low") | |
return list(set(labels)) # Remove duplicates | |
def _format_swarms_issue_body( | |
self, | |
error: Exception, | |
system_info: SwarmSystemInfo, | |
context: Dict, | |
) -> str: | |
"""Format the issue body with Swarms-specific information.""" | |
return f""" | |
## Swarms Error Report | |
- **Error Type**: {type(error).__name__} | |
- **Error Message**: {str(error)} | |
- **Swarms Version**: {system_info.swarms_version} | |
## Environment Information | |
- **OS**: {system_info.os_name} {system_info.os_version} | |
- **Python Version**: {system_info.python_version} | |
- **CUDA Available**: {system_info.cuda_available} | |
- **GPU**: {system_info.gpu_info or "N/A"} | |
- **CPU Usage**: {system_info.cpu_usage}% | |
- **Memory Usage**: {system_info.memory_usage}% | |
- **Disk Usage**: {system_info.disk_usage}% | |
## Stack Trace | |
{traceback.format_exc()} | |
## Context | |
{json.dumps(context, indent=2)} | |
## Dependencies | |
{self._get_dependencies_info()} | |
## Time of Occurrence | |
{datetime.now().isoformat()} | |
--- | |
*This issue was automatically generated by SwarmsIssueReporter* | |
""" | |
def _get_dependencies_info(self) -> str: | |
"""Get information about installed dependencies.""" | |
try: | |
import pkg_resources | |
deps = [] | |
for dist in pkg_resources.working_set: | |
deps.append(f"- {dist.key} {dist.version}") | |
return "\n".join(deps) | |
except: | |
return "Unable to fetch dependency information" | |
# First, add this method to your SwarmsIssueReporter class | |
def _check_rate_limit(self) -> bool: | |
"""Check if we're within rate limits.""" | |
now = datetime.now() | |
time_diff = (now - self.last_issue_time).total_seconds() | |
if ( | |
len(self.issues_created) >= self.rate_limit | |
and time_diff < self.rate_period | |
): | |
logger.warning("Rate limit exceeded for issue creation") | |
return False | |
# Clean up old issues from tracking | |
self.issues_created = [ | |
time | |
for time in self.issues_created | |
if (now - time).total_seconds() < self.rate_period | |
] | |
return True | |
def report_swarms_issue( | |
self, | |
error: Exception, | |
agent: Optional[Agent] = None, | |
context: Dict[str, Any] = None, | |
priority: str = "normal", | |
) -> Optional[int]: | |
""" | |
Report a Swarms-specific issue to GitHub. | |
Args: | |
error (Exception): The exception to report | |
agent (Optional[Agent]): The Swarms agent instance that encountered the error | |
context (Dict[str, Any]): Additional context about the error | |
priority (str): Issue priority ("low", "normal", "high", "critical") | |
Returns: | |
Optional[int]: Issue number if created successfully | |
""" | |
try: | |
if not self._check_rate_limit(): | |
logger.warning( | |
"Skipping issue creation due to rate limit" | |
) | |
return None | |
# Collect system information | |
system_info = self._get_system_info() | |
# Prepare context with agent information if available | |
full_context = context or {} | |
if agent: | |
full_context.update( | |
{ | |
"agent_name": agent.agent_name, | |
"agent_description": agent.agent_description, | |
"max_loops": agent.max_loops, | |
"context_length": agent.context_length, | |
} | |
) | |
# Create issue title | |
title = f"[{type(error).__name__}] {str(error)[:100]}" | |
if agent: | |
title = f"[Agent: {agent.agent_name}] {title}" | |
# Get appropriate labels | |
labels = self._categorize_error(error, full_context) | |
labels.append(f"priority:{priority}") | |
# Create the issue | |
url = f"https://api.github.com/repos/{self.REPO_OWNER}/{self.REPO_NAME}/issues" | |
data = { | |
"title": title, | |
"body": self._format_swarms_issue_body( | |
error, system_info, full_context | |
), | |
"labels": labels, | |
} | |
response = requests.post( | |
url, | |
headers={ | |
"Authorization": f"token {self.github_token}" | |
}, | |
json=data, | |
) | |
response.raise_for_status() | |
issue_number = response.json()["number"] | |
logger.info( | |
f"Successfully created Swarms issue #{issue_number}" | |
) | |
return issue_number | |
except Exception as e: | |
logger.error(f"Error creating Swarms issue: {str(e)}") | |
return None | |
# Setup the reporter with your GitHub token | |
reporter = SwarmsIssueReporter( | |
github_token=os.getenv("GITHUB_API_KEY") | |
) | |
# Force an error to test the reporter | |
try: | |
# This will raise an error since the input isn't valid | |
# Create an agent that might have issues | |
model = OpenAIChat(model_name="gpt-4o") | |
agent = Agent(agent_name="Test-Agent", max_loops=1) | |
result = agent.run(None) | |
raise ValueError("test") | |
except Exception as e: | |
# Report the issue | |
issue_number = reporter.report_swarms_issue( | |
error=e, | |
agent=agent, | |
context={"task": "test_run"}, | |
priority="high", | |
) | |
print(f"Created issue number: {issue_number}") | |