File size: 10,750 Bytes
ffcf62f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
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


@dataclass
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}")