devsquad 3.6.0__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.
Files changed (95) hide show
  1. devsquad-3.6.0.dist-info/METADATA +944 -0
  2. devsquad-3.6.0.dist-info/RECORD +95 -0
  3. devsquad-3.6.0.dist-info/WHEEL +5 -0
  4. devsquad-3.6.0.dist-info/entry_points.txt +2 -0
  5. devsquad-3.6.0.dist-info/licenses/LICENSE +21 -0
  6. devsquad-3.6.0.dist-info/top_level.txt +2 -0
  7. scripts/__init__.py +0 -0
  8. scripts/ai_semantic_matcher.py +512 -0
  9. scripts/alert_manager.py +505 -0
  10. scripts/api/__init__.py +43 -0
  11. scripts/api/models.py +386 -0
  12. scripts/api/routes/__init__.py +20 -0
  13. scripts/api/routes/dispatch.py +348 -0
  14. scripts/api/routes/lifecycle.py +330 -0
  15. scripts/api/routes/metrics_gates.py +347 -0
  16. scripts/api_server.py +318 -0
  17. scripts/auth.py +451 -0
  18. scripts/cli/__init__.py +1 -0
  19. scripts/cli/cli_visual.py +642 -0
  20. scripts/cli.py +1094 -0
  21. scripts/collaboration/__init__.py +212 -0
  22. scripts/collaboration/_version.py +1 -0
  23. scripts/collaboration/agent_briefing.py +656 -0
  24. scripts/collaboration/ai_semantic_matcher.py +260 -0
  25. scripts/collaboration/anchor_checker.py +281 -0
  26. scripts/collaboration/anti_rationalization.py +470 -0
  27. scripts/collaboration/async_integration_example.py +255 -0
  28. scripts/collaboration/batch_scheduler.py +149 -0
  29. scripts/collaboration/checkpoint_manager.py +561 -0
  30. scripts/collaboration/ci_feedback_adapter.py +351 -0
  31. scripts/collaboration/code_map_generator.py +247 -0
  32. scripts/collaboration/concern_pack_loader.py +352 -0
  33. scripts/collaboration/confidence_score.py +496 -0
  34. scripts/collaboration/config_loader.py +188 -0
  35. scripts/collaboration/consensus.py +244 -0
  36. scripts/collaboration/context_compressor.py +533 -0
  37. scripts/collaboration/coordinator.py +668 -0
  38. scripts/collaboration/dispatcher.py +1636 -0
  39. scripts/collaboration/dual_layer_context.py +128 -0
  40. scripts/collaboration/enhanced_worker.py +539 -0
  41. scripts/collaboration/feature_usage_tracker.py +206 -0
  42. scripts/collaboration/five_axis_consensus.py +334 -0
  43. scripts/collaboration/input_validator.py +401 -0
  44. scripts/collaboration/integration_example.py +287 -0
  45. scripts/collaboration/intent_workflow_mapper.py +350 -0
  46. scripts/collaboration/language_parsers.py +269 -0
  47. scripts/collaboration/lifecycle_protocol.py +1446 -0
  48. scripts/collaboration/llm_backend.py +453 -0
  49. scripts/collaboration/llm_cache.py +448 -0
  50. scripts/collaboration/llm_cache_async.py +347 -0
  51. scripts/collaboration/llm_retry.py +387 -0
  52. scripts/collaboration/llm_retry_async.py +389 -0
  53. scripts/collaboration/mce_adapter.py +597 -0
  54. scripts/collaboration/memory_bridge.py +1607 -0
  55. scripts/collaboration/models.py +537 -0
  56. scripts/collaboration/null_providers.py +297 -0
  57. scripts/collaboration/operation_classifier.py +289 -0
  58. scripts/collaboration/output_slicer.py +225 -0
  59. scripts/collaboration/performance_monitor.py +462 -0
  60. scripts/collaboration/permission_guard.py +865 -0
  61. scripts/collaboration/prompt_assembler.py +756 -0
  62. scripts/collaboration/prompt_variant_generator.py +483 -0
  63. scripts/collaboration/protocols.py +267 -0
  64. scripts/collaboration/report_formatter.py +352 -0
  65. scripts/collaboration/retrospective.py +279 -0
  66. scripts/collaboration/role_matcher.py +92 -0
  67. scripts/collaboration/role_template_market.py +352 -0
  68. scripts/collaboration/rule_collector.py +678 -0
  69. scripts/collaboration/scratchpad.py +346 -0
  70. scripts/collaboration/skill_registry.py +151 -0
  71. scripts/collaboration/skillifier.py +878 -0
  72. scripts/collaboration/standardized_role_template.py +317 -0
  73. scripts/collaboration/task_completion_checker.py +237 -0
  74. scripts/collaboration/test_quality_guard.py +695 -0
  75. scripts/collaboration/unified_gate_engine.py +598 -0
  76. scripts/collaboration/usage_tracker.py +309 -0
  77. scripts/collaboration/user_friendly_error.py +176 -0
  78. scripts/collaboration/verification_gate.py +312 -0
  79. scripts/collaboration/warmup_manager.py +635 -0
  80. scripts/collaboration/worker.py +513 -0
  81. scripts/collaboration/workflow_engine.py +684 -0
  82. scripts/dashboard.py +1088 -0
  83. scripts/generate_benchmark_report.py +786 -0
  84. scripts/history_manager.py +604 -0
  85. scripts/mcp_server.py +289 -0
  86. skills/__init__.py +32 -0
  87. skills/dispatch/handler.py +52 -0
  88. skills/intent/handler.py +59 -0
  89. skills/registry.py +67 -0
  90. skills/retrospective/__init__.py +0 -0
  91. skills/retrospective/handler.py +125 -0
  92. skills/review/handler.py +356 -0
  93. skills/security/handler.py +454 -0
  94. skills/test/__init__.py +0 -0
  95. skills/test/handler.py +78 -0
@@ -0,0 +1,505 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ DevSquad Alert Manager
5
+
6
+ Notification system for critical events and alerts.
7
+
8
+ Features:
9
+ - Multiple notification channels (Slack, Email, Console)
10
+ - Alert severity levels (INFO, WARNING, ERROR, CRITICAL)
11
+ - Rate limiting to prevent alert spam
12
+ - Alert history and deduplication
13
+ - Configurable via config/alerts.yaml
14
+
15
+ Usage:
16
+ from scripts.alert_manager import AlertManager, AlertSeverity
17
+
18
+ alerts = AlertManager()
19
+ alerts.send_alert(
20
+ severity=AlertSeverity.ERROR,
21
+ title="Gate Check Failed",
22
+ message="Build gate failed for project X",
23
+ channel="slack"
24
+ )
25
+ """
26
+
27
+ import logging
28
+ import smtplib
29
+ import sys
30
+ from dataclasses import dataclass
31
+ from datetime import datetime, timedelta
32
+ from email.mime.text import MIMEText
33
+ from email.mime.multipart import MIMEMultipart
34
+ from enum import Enum
35
+ from typing import Any, Dict, List, Optional
36
+
37
+ import os
38
+ import yaml
39
+
40
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
41
+
42
+ logger = logging.getLogger(__name__)
43
+
44
+
45
+ class AlertSeverity(Enum):
46
+ """Alert severity levels."""
47
+ INFO = "info"
48
+ WARNING = "warning"
49
+ ERROR = "error"
50
+ CRITICAL = "critical"
51
+
52
+
53
+ class AlertChannel(Enum):
54
+ """Notification channels."""
55
+ CONSOLE = "console"
56
+ SLACK = "slack"
57
+ EMAIL = "email"
58
+ WEBHOOK = "webhook"
59
+ ALL = "all"
60
+
61
+
62
+ @dataclass
63
+ class Alert:
64
+ """Alert data structure."""
65
+ id: str
66
+ severity: AlertSeverity
67
+ title: str
68
+ message: str
69
+ source: str
70
+ timestamp: datetime
71
+ channel: AlertChannel
72
+ acknowledged: bool = False
73
+ resolved_at: Optional[datetime] = None
74
+
75
+ def to_dict(self) -> Dict[str, Any]:
76
+ return {
77
+ "id": self.id,
78
+ "severity": self.severity.value,
79
+ "title": self.title,
80
+ "message": self.message,
81
+ "source": self.source,
82
+ "timestamp": self.timestamp.isoformat(),
83
+ "channel": self.channel.value,
84
+ "acknowledged": self.acknowledged,
85
+ "resolved_at": self.resolved_at.isoformat() if self.resolved_at else None
86
+ }
87
+
88
+
89
+ class AlertManager:
90
+ """
91
+ Centralized alert management system.
92
+
93
+ Handles sending notifications through multiple channels
94
+ with rate limiting and deduplication.
95
+ """
96
+
97
+ def __init__(self, config_path: Optional[str] = None):
98
+ """
99
+ Initialize AlertManager.
100
+
101
+ Args:
102
+ config_path: Path to alerts configuration file.
103
+ Defaults to config/alerts.yaml
104
+ """
105
+ self.config_path = config_path or os.path.join(
106
+ os.path.dirname(__file__),
107
+ "..",
108
+ "config",
109
+ "alerts.yaml"
110
+ )
111
+
112
+ self.config = self._load_config()
113
+ self.alert_history: List[Alert] = []
114
+ self.recent_alerts: Dict[str, datetime] = {} # For deduplication
115
+
116
+ # Rate limiting settings
117
+ self.rate_limit_window = self.config.get("rate_limit", {}).get("window_seconds", 60)
118
+ self.max_alerts_per_window = self.config.get("rate_limit", {}).get("max_alerts", 10)
119
+ self._alert_count_in_window = 0
120
+ self._window_start = datetime.now()
121
+
122
+ logger.info(f"AlertManager initialized")
123
+
124
+ def _load_config(self) -> Dict[str, Any]:
125
+ """Load alert configuration."""
126
+ try:
127
+ if os.path.exists(self.config_path):
128
+ with open(self.config_path, "r", encoding="utf-8") as f:
129
+ return yaml.safe_load(f) or {}
130
+ return {}
131
+ except Exception as e:
132
+ logger.error(f"Failed to load alert config: {e}")
133
+ return {}
134
+
135
+ def _generate_alert_id(self) -> str:
136
+ """Generate unique alert ID."""
137
+ import hashlib
138
+ timestamp = datetime.now().isoformat()
139
+ return hashlib.md5(timestamp.encode()).hexdigest()[:12]
140
+
141
+ def _check_rate_limit(self) -> bool:
142
+ """
143
+ Check if we're within rate limits.
144
+
145
+ Returns:
146
+ True if allowed to send, False if rate limited
147
+ """
148
+ now = datetime.now()
149
+
150
+ # Reset window if expired
151
+ if now - self._window_start > timedelta(seconds=self.rate_limit_window):
152
+ self._window_start = now
153
+ self._alert_count_in_window = 0
154
+
155
+ if self._alert_count_in_window >= self.max_alerts_per_window:
156
+ logger.warning("Rate limit exceeded for alerts")
157
+ return False
158
+
159
+ self._alert_count_in_window += 1
160
+ return True
161
+
162
+ def _deduplicate(self, title: str, message: str, window_minutes: int = 5) -> bool:
163
+ """
164
+ Check for duplicate alerts within time window.
165
+
166
+ Args:
167
+ title: Alert title
168
+ message: Alert message
169
+ window_minutes: Deduplication window in minutes
170
+
171
+ Returns:
172
+ True if duplicate (should skip), False if unique
173
+ """
174
+ key = f"{title}:{message[:50]}"
175
+ now = datetime.now()
176
+
177
+ if key in self.recent_alerts:
178
+ last_sent = self.recent_alerts[key]
179
+ if now - last_sent < timedelta(minutes=window_minutes):
180
+ logger.debug(f"Duplicate alert suppressed: {title}")
181
+ return True
182
+
183
+ self.recent_alerts[key] = now
184
+ return False
185
+
186
+ def send_alert(
187
+ self,
188
+ severity: AlertSeverity,
189
+ title: str,
190
+ message: str,
191
+ source: str = "devsquad",
192
+ channel: Optional[str] = None,
193
+ deduplicate: bool = True
194
+ ) -> Optional[Alert]:
195
+ """
196
+ Send an alert notification.
197
+
198
+ Args:
199
+ severity: Alert severity level
200
+ title: Short alert title
201
+ message: Detailed alert message
202
+ source: Alert source identifier
203
+ channel: Specific channel or None for default
204
+ deduplicate: Whether to check for duplicates
205
+
206
+ Returns:
207
+ Alert object if sent, None if suppressed
208
+ """
209
+ # Check rate limit
210
+ if not self._check_rate_limit():
211
+ return None
212
+
213
+ # Check for duplicates
214
+ if deduplicate and self._deduplicate(title, message):
215
+ return None
216
+
217
+ # Determine target channels
218
+ target_channel = AlertChannel(channel) if channel else self._get_default_channel(severity)
219
+
220
+ # Create alert object
221
+ alert = Alert(
222
+ id=self._generate_alert_id(),
223
+ severity=severity,
224
+ title=title,
225
+ message=message,
226
+ source=source,
227
+ timestamp=datetime.now(),
228
+ channel=target_channel
229
+ )
230
+
231
+ # Send to appropriate channel(s)
232
+ try:
233
+ if target_channel == AlertChannel.ALL:
234
+ self._send_to_console(alert)
235
+ self._send_to_slack(alert)
236
+ self._send_to_email(alert)
237
+ elif target_channel == AlertChannel.SLACK:
238
+ self._send_to_slack(alert)
239
+ self._send_to_console(alert) # Also log to console
240
+ elif target_channel == AlertChannel.EMAIL:
241
+ self._send_to_email(alert)
242
+ self._send_to_console(alert)
243
+ else:
244
+ self._send_to_console(alert)
245
+
246
+ # Store in history
247
+ self.alert_history.append(alert)
248
+
249
+ # Trim history if too large (keep last 1000)
250
+ if len(self.alert_history) > 1000:
251
+ self.alert_history = self.alert_history[-1000:]
252
+
253
+ logger.info(f"Alert sent: [{severity.value.upper()}] {title}")
254
+ return alert
255
+
256
+ except Exception as e:
257
+ logger.error(f"Failed to send alert: {e}")
258
+ return None
259
+
260
+ def _get_default_channel(self, severity: AlertSeverity) -> AlertChannel:
261
+ """Get default channel based on severity."""
262
+ defaults = self.config.get("defaults", {})
263
+ channel_map = defaults.get("channels_by_severity", {
264
+ "critical": ["slack", "email"],
265
+ "error": ["slack", "console"],
266
+ "warning": ["console"],
267
+ "info": ["console"]
268
+ })
269
+
270
+ channels = channel_map.get(severity.value, ["console"])
271
+ if len(channels) > 1:
272
+ return AlertChannel.ALL
273
+ return AlertChannel(channels[0])
274
+
275
+ def _send_to_console(self, alert: Alert):
276
+ """Send alert to console/log."""
277
+ emoji_map = {
278
+ AlertSeverity.INFO: "ā„¹ļø",
279
+ AlertSeverity.WARNING: "āš ļø",
280
+ AlertSeverity.ERROR: "āŒ",
281
+ AlertSeverity.CRITICAL: "🚨"
282
+ }
283
+
284
+ emoji = emoji_map.get(alert.severity, "šŸ“¢")
285
+
286
+ log_method = {
287
+ AlertSeverity.INFO: logger.info,
288
+ AlertSeverity.WARNING: logger.warning,
289
+ AlertSeverity.ERROR: logger.error,
290
+ AlertSeverity.CRITICAL: logger.critical
291
+ }.get(alert.severity, logger.info)
292
+
293
+ log_method(
294
+ f"{emoji} [{alert.severity.value.upper()}] {alert.title}\n"
295
+ f" Source: {alert.source}\n"
296
+ f" Message: {alert.message}\n"
297
+ f" ID: {alert.id}"
298
+ )
299
+
300
+ def _send_to_slack(self, alert: Alert):
301
+ """Send alert to Slack webhook."""
302
+ slack_config = self.config.get("channels", {}).get("slack", {})
303
+ webhook_url = slack_config.get("webhook_url")
304
+
305
+ if not webhook_url:
306
+ logger.debug("Slack webhook URL not configured")
307
+ return
308
+
309
+ try:
310
+ import urllib.request
311
+ import json
312
+
313
+ color_map = {
314
+ AlertSeverity.INFO: "#36a64f",
315
+ AlertSeverity.WARNING: "#ff9800",
316
+ AlertSeverity.ERROR: "#f44336",
317
+ AlertSeverity.CRITICAL: "#9c27b0"
318
+ }
319
+
320
+ payload = {
321
+ "attachments": [{
322
+ "color": color_map.get(alert.severity, "#808080"),
323
+ "title": f"[{alert.severity.value.upper()}] {alert.title}",
324
+ "text": alert.message,
325
+ "fields": [
326
+ {"title": "Source", "value": alert.source, "short": True},
327
+ {"title": "Severity", "value": alert.severity.value.upper(), "short": True},
328
+ {"title": "Alert ID", "value": alert.id, "short": True},
329
+ {"title": "Time", "value": alert.timestamp.strftime("%Y-%m-%d %H:%M:%S"), "short": True}
330
+ ],
331
+ "footer": "DevSquad Alert System",
332
+ "ts": int(alert.timestamp.timestamp())
333
+ }]
334
+ }
335
+
336
+ data = json.dumps(payload).encode('utf-8')
337
+ req = urllib.request.Request(
338
+ webhook_url,
339
+ data=data,
340
+ headers={'Content-Type': 'application/json'}
341
+ )
342
+
343
+ with urllib.request.urlopen(req, timeout=10) as response:
344
+ if response.status == 200:
345
+ logger.info(f"Slack alert sent successfully: {alert.id}")
346
+
347
+ except ImportError:
348
+ logger.warning("urllib not available for Slack integration")
349
+ except Exception as e:
350
+ logger.error(f"Failed to send Slack alert: {e}")
351
+
352
+ def _send_to_email(self, alert: Alert):
353
+ """Send alert via email."""
354
+ email_config = self.config.get("channels", {}).get("email", {})
355
+
356
+ smtp_server = email_config.get("smtp_server")
357
+ smtp_port = email_config.get("smtp_port", 587)
358
+ sender = email_config.get("sender")
359
+ recipients = email_config.get("recipients", [])
360
+ username = email_config.get("username")
361
+ password = email_config.get("password")
362
+
363
+ if not all([smtp_server, sender, recipients]):
364
+ logger.debug("Email configuration incomplete")
365
+ return
366
+
367
+ try:
368
+ msg = MIMEMultipart()
369
+ msg['From'] = sender
370
+ msg['To'] = ', '.join(recipients)
371
+ msg['Subject'] = f"[DevSquad-{alert.severity.value.upper()}] {alert.title}"
372
+
373
+ body = f"""
374
+ DevSquad Alert Notification
375
+ ============================
376
+
377
+ Severity: {alert.severity.value.upper()}
378
+ Title: {alert.title}
379
+ Source: {alert.source}
380
+ Time: {alert.timestamp.strftime("%Y-%m-%d %H:%M:%S")}
381
+ Alert ID: {alert.id}
382
+
383
+ Message:
384
+ {alert.message}
385
+
386
+ ---
387
+ This is an automated message from DevSquad Alert System.
388
+ """
389
+
390
+ msg.attach(MIMEText(body, 'plain'))
391
+
392
+ with smtplib.SMTP(smtp_server, smtp_port) as server:
393
+ server.starttls()
394
+ if username and password:
395
+ server.login(username, password)
396
+ server.sendmail(sender, recipients, msg.as_string())
397
+
398
+ logger.info(f"Email alert sent successfully: {alert.id}")
399
+
400
+ except Exception as e:
401
+ logger.error(f"Failed to send email alert: {e}")
402
+
403
+ def get_alert_history(
404
+ self,
405
+ severity: Optional[AlertSeverity] = None,
406
+ hours: int = 24,
407
+ limit: int = 50
408
+ ) -> List[Dict]:
409
+ """
410
+ Get alert history.
411
+
412
+ Args:
413
+ severity: Filter by severity (optional)
414
+ hours: Look back period in hours
415
+ limit: Maximum number of alerts to return
416
+
417
+ Returns:
418
+ List of alert dictionaries
419
+ """
420
+ cutoff = datetime.now() - timedelta(hours=hours)
421
+
422
+ filtered = [
423
+ alert.to_dict()
424
+ for alert in self.alert_history
425
+ if alert.timestamp >= cutoff
426
+ and (severity is None or alert.severity == severity)
427
+ ]
428
+
429
+ # Sort by timestamp descending
430
+ filtered.sort(key=lambda x: x["timestamp"], reverse=True)
431
+
432
+ return filtered[:limit]
433
+
434
+ def get_alert_stats(self, hours: int = 24) -> Dict[str, Any]:
435
+ """
436
+ Get alert statistics.
437
+
438
+ Args:
439
+ hours: Statistics period in hours
440
+
441
+ Returns:
442
+ Dictionary with alert statistics
443
+ """
444
+ cutoff = datetime.now() - timedelta(hours=hours)
445
+ recent_alerts = [a for a in self.alert_history if a.timestamp >= cutoff]
446
+
447
+ stats = {
448
+ "total": len(recent_alerts),
449
+ "by_severity": {},
450
+ "by_source": {},
451
+ "period_hours": hours
452
+ }
453
+
454
+ for alert in recent_alerts:
455
+ sev = alert.severity.value
456
+ stats["by_severity"][sev] = stats["by_severity"].get(sev, 0) + 1
457
+
458
+ src = alert.source
459
+ stats["by_source"][src] = stats["by_source"].get(src, 0) + 1
460
+
461
+ return stats
462
+
463
+
464
+ # Convenience functions for quick alerts
465
+ def alert_info(title: str, message: str, **kwargs) -> Optional[Alert]:
466
+ """Send INFO level alert."""
467
+ mgr = AlertManager()
468
+ return mgr.send_alert(AlertSeverity.INFO, title, message, **kwargs)
469
+
470
+ def alert_warning(title: str, message: str, **kwargs) -> Optional[Alert]:
471
+ """Send WARNING level alert."""
472
+ mgr = AlertManager()
473
+ return mgr.send_alert(AlertSeverity.WARNING, title, message, **kwargs)
474
+
475
+ def alert_error(title: str, message: str, **kwargs) -> Optional[Alert]:
476
+ """Send ERROR level alert."""
477
+ mgr = AlertManager()
478
+ return mgr.send_alert(AlertSeverity.ERROR, title, message, **kwargs)
479
+
480
+ def alert_critical(title: str, message: str, **kwargs) -> Optional[Alert]:
481
+ """Send CRITICAL level alert."""
482
+ mgr = AlertManager()
483
+ return mgr.send_alert(AlertSeverity.CRITICAL, title, message, **kwargs)
484
+
485
+
486
+ if __name__ == "__main__":
487
+ # Demo: Send test alerts
488
+ print("\nšŸ”” DevSquad Alert Manager Demo\n")
489
+ print("=" * 50)
490
+
491
+ alerts = AlertManager()
492
+
493
+ # Test different severity levels
494
+ alerts.send_alert(AlertSeverity.INFO, "Test Info", "This is an info message")
495
+ alerts.send_alert(AlertSeverity.WARNING, "Test Warning", "This is a warning")
496
+ alerts.send_alert(AlertSeverity.ERROR, "Test Error", "This is an error message")
497
+ alerts.send_alert(AlertSeverity.CRITICAL, "Test Critical", "This is critical!")
498
+
499
+ # Show statistics
500
+ stats = alerts.get_alert_stats()
501
+ print(f"\nšŸ“Š Alert Statistics:")
502
+ print(f"Total alerts: {stats['total']}")
503
+ print(f"By severity: {stats['by_severity']}")
504
+
505
+ print("\nāœ… Demo completed!")
@@ -0,0 +1,43 @@
1
+ # API Package
2
+
3
+ """
4
+ DevSquad REST API Package
5
+
6
+ Provides FastAPI-based REST API for DevSquad multi-agent collaboration system.
7
+
8
+ Modules:
9
+ - models: Pydantic request/response models
10
+ - routes: API endpoint routers (lifecycle, metrics_gates, dispatch)
11
+ """
12
+
13
+ from scripts.api.models import *
14
+
15
+ __all__ = [
16
+ # Lifecycle models
17
+ "LifecyclePhase",
18
+ "PhaseStatus",
19
+ "PhaseActionRequest",
20
+ "PhaseActionResult",
21
+ "CommandMapping",
22
+ # Metrics & Gates models
23
+ "GateCheckRequest",
24
+ "GateResult",
25
+ "MetricsSnapshot",
26
+ "HealthCheck",
27
+ # Task Dispatch models (NEW in V3.6.0)
28
+ "TaskDispatchRequest",
29
+ "QuickDispatchRequest",
30
+ "DispatchResponse",
31
+ "WorkerResultItem",
32
+ "IntentMatchInfo",
33
+ "FiveAxisResult",
34
+ "AnchorResult",
35
+ "RoleInfo",
36
+ "RolesListResponse",
37
+ "DispatchHistoryResponse",
38
+ # Common models
39
+ "UserRole",
40
+ "APIError",
41
+ "APISuccess",
42
+ "PaginatedResponse",
43
+ ]