crackerjack 0.31.10__py3-none-any.whl → 0.31.13__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.

Potentially problematic release.


This version of crackerjack might be problematic. Click here for more details.

Files changed (155) hide show
  1. crackerjack/CLAUDE.md +288 -705
  2. crackerjack/__main__.py +22 -8
  3. crackerjack/agents/__init__.py +0 -3
  4. crackerjack/agents/architect_agent.py +0 -43
  5. crackerjack/agents/base.py +1 -9
  6. crackerjack/agents/coordinator.py +2 -148
  7. crackerjack/agents/documentation_agent.py +109 -81
  8. crackerjack/agents/dry_agent.py +122 -97
  9. crackerjack/agents/formatting_agent.py +3 -16
  10. crackerjack/agents/import_optimization_agent.py +1174 -130
  11. crackerjack/agents/performance_agent.py +956 -188
  12. crackerjack/agents/performance_helpers.py +229 -0
  13. crackerjack/agents/proactive_agent.py +1 -48
  14. crackerjack/agents/refactoring_agent.py +516 -246
  15. crackerjack/agents/refactoring_helpers.py +282 -0
  16. crackerjack/agents/security_agent.py +393 -90
  17. crackerjack/agents/test_creation_agent.py +1776 -120
  18. crackerjack/agents/test_specialist_agent.py +59 -15
  19. crackerjack/agents/tracker.py +0 -102
  20. crackerjack/api.py +145 -37
  21. crackerjack/cli/handlers.py +48 -30
  22. crackerjack/cli/interactive.py +11 -11
  23. crackerjack/cli/options.py +66 -4
  24. crackerjack/code_cleaner.py +808 -148
  25. crackerjack/config/global_lock_config.py +110 -0
  26. crackerjack/config/hooks.py +43 -64
  27. crackerjack/core/async_workflow_orchestrator.py +247 -97
  28. crackerjack/core/autofix_coordinator.py +192 -109
  29. crackerjack/core/enhanced_container.py +46 -63
  30. crackerjack/core/file_lifecycle.py +549 -0
  31. crackerjack/core/performance.py +9 -8
  32. crackerjack/core/performance_monitor.py +395 -0
  33. crackerjack/core/phase_coordinator.py +281 -94
  34. crackerjack/core/proactive_workflow.py +9 -58
  35. crackerjack/core/resource_manager.py +501 -0
  36. crackerjack/core/service_watchdog.py +490 -0
  37. crackerjack/core/session_coordinator.py +4 -8
  38. crackerjack/core/timeout_manager.py +504 -0
  39. crackerjack/core/websocket_lifecycle.py +475 -0
  40. crackerjack/core/workflow_orchestrator.py +343 -209
  41. crackerjack/dynamic_config.py +50 -9
  42. crackerjack/errors.py +3 -4
  43. crackerjack/executors/async_hook_executor.py +63 -13
  44. crackerjack/executors/cached_hook_executor.py +14 -14
  45. crackerjack/executors/hook_executor.py +100 -37
  46. crackerjack/executors/hook_lock_manager.py +856 -0
  47. crackerjack/executors/individual_hook_executor.py +120 -86
  48. crackerjack/intelligence/__init__.py +0 -7
  49. crackerjack/intelligence/adaptive_learning.py +13 -86
  50. crackerjack/intelligence/agent_orchestrator.py +15 -78
  51. crackerjack/intelligence/agent_registry.py +12 -59
  52. crackerjack/intelligence/agent_selector.py +31 -92
  53. crackerjack/intelligence/integration.py +1 -41
  54. crackerjack/interactive.py +9 -9
  55. crackerjack/managers/async_hook_manager.py +25 -8
  56. crackerjack/managers/hook_manager.py +9 -9
  57. crackerjack/managers/publish_manager.py +57 -59
  58. crackerjack/managers/test_command_builder.py +6 -36
  59. crackerjack/managers/test_executor.py +9 -61
  60. crackerjack/managers/test_manager.py +17 -63
  61. crackerjack/managers/test_manager_backup.py +77 -127
  62. crackerjack/managers/test_progress.py +4 -23
  63. crackerjack/mcp/cache.py +5 -12
  64. crackerjack/mcp/client_runner.py +10 -10
  65. crackerjack/mcp/context.py +64 -6
  66. crackerjack/mcp/dashboard.py +14 -11
  67. crackerjack/mcp/enhanced_progress_monitor.py +55 -55
  68. crackerjack/mcp/file_monitor.py +72 -42
  69. crackerjack/mcp/progress_components.py +103 -84
  70. crackerjack/mcp/progress_monitor.py +122 -49
  71. crackerjack/mcp/rate_limiter.py +12 -12
  72. crackerjack/mcp/server_core.py +16 -22
  73. crackerjack/mcp/service_watchdog.py +26 -26
  74. crackerjack/mcp/state.py +15 -0
  75. crackerjack/mcp/tools/core_tools.py +95 -39
  76. crackerjack/mcp/tools/error_analyzer.py +6 -32
  77. crackerjack/mcp/tools/execution_tools.py +1 -56
  78. crackerjack/mcp/tools/execution_tools_backup.py +35 -131
  79. crackerjack/mcp/tools/intelligence_tool_registry.py +0 -36
  80. crackerjack/mcp/tools/intelligence_tools.py +2 -55
  81. crackerjack/mcp/tools/monitoring_tools.py +308 -145
  82. crackerjack/mcp/tools/proactive_tools.py +12 -42
  83. crackerjack/mcp/tools/progress_tools.py +23 -15
  84. crackerjack/mcp/tools/utility_tools.py +3 -40
  85. crackerjack/mcp/tools/workflow_executor.py +40 -60
  86. crackerjack/mcp/websocket/app.py +0 -3
  87. crackerjack/mcp/websocket/endpoints.py +206 -268
  88. crackerjack/mcp/websocket/jobs.py +213 -66
  89. crackerjack/mcp/websocket/server.py +84 -6
  90. crackerjack/mcp/websocket/websocket_handler.py +137 -29
  91. crackerjack/models/config_adapter.py +3 -16
  92. crackerjack/models/protocols.py +162 -3
  93. crackerjack/models/resource_protocols.py +454 -0
  94. crackerjack/models/task.py +3 -3
  95. crackerjack/monitoring/__init__.py +0 -0
  96. crackerjack/monitoring/ai_agent_watchdog.py +25 -71
  97. crackerjack/monitoring/regression_prevention.py +28 -87
  98. crackerjack/orchestration/advanced_orchestrator.py +44 -78
  99. crackerjack/orchestration/coverage_improvement.py +10 -60
  100. crackerjack/orchestration/execution_strategies.py +16 -16
  101. crackerjack/orchestration/test_progress_streamer.py +61 -53
  102. crackerjack/plugins/base.py +1 -1
  103. crackerjack/plugins/managers.py +22 -20
  104. crackerjack/py313.py +65 -21
  105. crackerjack/services/backup_service.py +467 -0
  106. crackerjack/services/bounded_status_operations.py +627 -0
  107. crackerjack/services/cache.py +7 -9
  108. crackerjack/services/config.py +35 -52
  109. crackerjack/services/config_integrity.py +5 -16
  110. crackerjack/services/config_merge.py +542 -0
  111. crackerjack/services/contextual_ai_assistant.py +17 -19
  112. crackerjack/services/coverage_ratchet.py +44 -73
  113. crackerjack/services/debug.py +25 -39
  114. crackerjack/services/dependency_monitor.py +52 -50
  115. crackerjack/services/enhanced_filesystem.py +14 -11
  116. crackerjack/services/file_hasher.py +1 -1
  117. crackerjack/services/filesystem.py +1 -12
  118. crackerjack/services/git.py +71 -47
  119. crackerjack/services/health_metrics.py +31 -27
  120. crackerjack/services/initialization.py +276 -428
  121. crackerjack/services/input_validator.py +760 -0
  122. crackerjack/services/log_manager.py +16 -16
  123. crackerjack/services/logging.py +7 -6
  124. crackerjack/services/metrics.py +43 -43
  125. crackerjack/services/pattern_cache.py +2 -31
  126. crackerjack/services/pattern_detector.py +26 -63
  127. crackerjack/services/performance_benchmarks.py +20 -45
  128. crackerjack/services/regex_patterns.py +2887 -0
  129. crackerjack/services/regex_utils.py +537 -0
  130. crackerjack/services/secure_path_utils.py +683 -0
  131. crackerjack/services/secure_status_formatter.py +534 -0
  132. crackerjack/services/secure_subprocess.py +605 -0
  133. crackerjack/services/security.py +47 -10
  134. crackerjack/services/security_logger.py +492 -0
  135. crackerjack/services/server_manager.py +109 -50
  136. crackerjack/services/smart_scheduling.py +8 -25
  137. crackerjack/services/status_authentication.py +603 -0
  138. crackerjack/services/status_security_manager.py +442 -0
  139. crackerjack/services/thread_safe_status_collector.py +546 -0
  140. crackerjack/services/tool_version_service.py +1 -23
  141. crackerjack/services/unified_config.py +36 -58
  142. crackerjack/services/validation_rate_limiter.py +269 -0
  143. crackerjack/services/version_checker.py +9 -40
  144. crackerjack/services/websocket_resource_limiter.py +572 -0
  145. crackerjack/slash_commands/__init__.py +52 -2
  146. crackerjack/tools/__init__.py +0 -0
  147. crackerjack/tools/validate_input_validator_patterns.py +262 -0
  148. crackerjack/tools/validate_regex_patterns.py +198 -0
  149. {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/METADATA +197 -12
  150. crackerjack-0.31.13.dist-info/RECORD +178 -0
  151. crackerjack/cli/facade.py +0 -104
  152. crackerjack-0.31.10.dist-info/RECORD +0 -149
  153. {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/WHEEL +0 -0
  154. {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/entry_points.txt +0 -0
  155. {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,3 @@
1
- """Adaptive Learning System for Agent Selection.
2
-
3
- Learns from execution results to improve agent selection over time through
4
- success tracking, capability refinement, and performance optimization.
5
- """
6
-
7
1
  import asyncio
8
2
  import json
9
3
  import logging
@@ -19,8 +13,6 @@ from .agent_selector import AgentScore, TaskDescription
19
13
 
20
14
  @dataclass
21
15
  class ExecutionRecord:
22
- """Record of an agent execution."""
23
-
24
16
  timestamp: datetime
25
17
  agent_name: str
26
18
  agent_source: str
@@ -31,13 +23,11 @@ class ExecutionRecord:
31
23
  confidence_score: float
32
24
  final_score: float
33
25
  error_message: str | None = None
34
- task_hash: str | None = None # For grouping similar tasks
26
+ task_hash: str | None = None
35
27
 
36
28
 
37
29
  @dataclass
38
30
  class AgentPerformanceMetrics:
39
- """Performance metrics for an agent."""
40
-
41
31
  total_executions: int = 0
42
32
  successful_executions: int = 0
43
33
  failed_executions: int = 0
@@ -45,25 +35,21 @@ class AgentPerformanceMetrics:
45
35
  average_confidence: float = 0.0
46
36
  success_rate: float = 0.0
47
37
  capability_success_rates: dict[str, float] = field(default_factory=dict)
48
- recent_performance_trend: float = 0.0 # -1 to 1, negative = declining
38
+ recent_performance_trend: float = 0.0
49
39
  last_updated: datetime = field(default_factory=datetime.now)
50
40
 
51
41
 
52
42
  @dataclass
53
43
  class LearningInsight:
54
- """A learning insight discovered from execution data."""
55
-
56
- insight_type: str # "capability_strength", "task_pattern", "failure_pattern"
44
+ insight_type: str
57
45
  agent_name: str
58
- confidence: float # 0-1
46
+ confidence: float
59
47
  description: str
60
48
  supporting_evidence: dict[str, t.Any]
61
49
  discovered_at: datetime = field(default_factory=datetime.now)
62
50
 
63
51
 
64
52
  class AdaptiveLearningSystem:
65
- """System that learns from agent execution results."""
66
-
67
53
  def __init__(self, data_dir: Path | None = None) -> None:
68
54
  self.logger = logging.getLogger(__name__)
69
55
  self.data_dir = data_dir or Path.home() / ".crackerjack" / "intelligence"
@@ -80,7 +66,6 @@ class AdaptiveLearningSystem:
80
66
  self._load_existing_data()
81
67
 
82
68
  def _load_existing_data(self) -> None:
83
- """Load existing learning data from disk."""
84
69
  try:
85
70
  self._load_execution_records()
86
71
  self._load_agent_metrics()
@@ -89,7 +74,6 @@ class AdaptiveLearningSystem:
89
74
  self.logger.warning(f"Error loading existing learning data: {e}")
90
75
 
91
76
  def _load_execution_records(self) -> None:
92
- """Load execution records from disk."""
93
77
  if not self.execution_log_path.exists():
94
78
  return
95
79
 
@@ -104,7 +88,6 @@ class AdaptiveLearningSystem:
104
88
  self.logger.debug(f"Loaded {len(self._execution_records)} execution records")
105
89
 
106
90
  def _load_agent_metrics(self) -> None:
107
- """Load agent metrics from disk."""
108
91
  if not self.metrics_path.exists():
109
92
  return
110
93
 
@@ -117,7 +100,6 @@ class AdaptiveLearningSystem:
117
100
  self.logger.debug(f"Loaded metrics for {len(self._agent_metrics)} agents")
118
101
 
119
102
  def _load_learning_insights(self) -> None:
120
- """Load learning insights from disk."""
121
103
  if not self.insights_path.exists():
122
104
  return
123
105
 
@@ -141,9 +123,7 @@ class AdaptiveLearningSystem:
141
123
  agent_score: AgentScore,
142
124
  error_message: str | None = None,
143
125
  ) -> None:
144
- """Record the result of an agent execution."""
145
126
  try:
146
- # Create execution record
147
127
  record = ExecutionRecord(
148
128
  timestamp=datetime.now(),
149
129
  agent_name=agent.metadata.name,
@@ -160,16 +140,12 @@ class AdaptiveLearningSystem:
160
140
  task_hash=self._hash_task(task),
161
141
  )
162
142
 
163
- # Add to records
164
143
  self._execution_records.append(record)
165
144
 
166
- # Update agent metrics
167
145
  await self._update_agent_metrics(record)
168
146
 
169
- # Persist to disk
170
147
  await self._persist_execution_record(record)
171
148
 
172
- # Trigger learning analysis (async)
173
149
  asyncio.create_task(self._analyze_and_learn())
174
150
 
175
151
  self.logger.debug(
@@ -181,11 +157,9 @@ class AdaptiveLearningSystem:
181
157
  self.logger.error(f"Error recording execution: {e}")
182
158
 
183
159
  def _infer_task_capabilities(self, task: TaskDescription) -> set[AgentCapability]:
184
- """Infer capabilities needed for a task (simplified version)."""
185
160
  capabilities = set()
186
161
  text = task.description.lower()
187
162
 
188
- # Capability mapping for efficiency
189
163
  capability_keywords = {
190
164
  AgentCapability.ARCHITECTURE: ("architect", "design", "structure"),
191
165
  AgentCapability.REFACTORING: ("refactor", "clean", "improve"),
@@ -207,16 +181,11 @@ class AdaptiveLearningSystem:
207
181
  return capabilities
208
182
 
209
183
  def _hash_task(self, task: TaskDescription) -> str:
210
- """Create a hash for grouping similar tasks."""
211
- # Simple hash based on key words
212
184
  words = task.description.lower().split()
213
- key_words = [w for w in words if len(w) > 3][
214
- :10
215
- ] # Take first 10 significant words
185
+ key_words = [w for w in words if len(w) > 3][:10]
216
186
  return "_".join(sorted(key_words))
217
187
 
218
188
  async def _update_agent_metrics(self, record: ExecutionRecord) -> None:
219
- """Update metrics for an agent based on execution record."""
220
189
  agent_name = record.agent_name
221
190
  metrics = self._ensure_agent_metrics(agent_name)
222
191
 
@@ -229,7 +198,6 @@ class AdaptiveLearningSystem:
229
198
  await self._persist_agent_metrics()
230
199
 
231
200
  def _ensure_agent_metrics(self, agent_name: str) -> AgentPerformanceMetrics:
232
- """Ensure agent metrics exist and return them."""
233
201
  if agent_name not in self._agent_metrics:
234
202
  self._agent_metrics[agent_name] = AgentPerformanceMetrics()
235
203
  return self._agent_metrics[agent_name]
@@ -237,7 +205,6 @@ class AdaptiveLearningSystem:
237
205
  def _update_basic_counters(
238
206
  self, metrics: AgentPerformanceMetrics, record: ExecutionRecord
239
207
  ) -> None:
240
- """Update basic execution counters and success rate."""
241
208
  metrics.total_executions += 1
242
209
  if record.success:
243
210
  metrics.successful_executions += 1
@@ -248,7 +215,6 @@ class AdaptiveLearningSystem:
248
215
  def _update_execution_averages(
249
216
  self, metrics: AgentPerformanceMetrics, record: ExecutionRecord
250
217
  ) -> None:
251
- """Update execution time and confidence averages."""
252
218
  if metrics.total_executions == 1:
253
219
  metrics.average_execution_time = record.execution_time
254
220
  metrics.average_confidence = record.confidence_score
@@ -266,7 +232,6 @@ class AdaptiveLearningSystem:
266
232
  def _update_capability_success_rates(
267
233
  self, metrics: AgentPerformanceMetrics, record: ExecutionRecord, agent_name: str
268
234
  ) -> None:
269
- """Update capability-specific success rates."""
270
235
  success_value = 1.0 if record.success else 0.0
271
236
 
272
237
  for capability in record.task_capabilities:
@@ -293,7 +258,6 @@ class AdaptiveLearningSystem:
293
258
  def _update_performance_trend(
294
259
  self, metrics: AgentPerformanceMetrics, agent_name: str
295
260
  ) -> None:
296
- """Update recent performance trend."""
297
261
  recent_records = [
298
262
  r for r in self._execution_records[-20:] if r.agent_name == agent_name
299
263
  ][-10:]
@@ -313,7 +277,6 @@ class AdaptiveLearningSystem:
313
277
  def _calculate_windowed_success_rates(
314
278
  self, recent_records: list[ExecutionRecord]
315
279
  ) -> list[float]:
316
- """Calculate success rates using sliding window."""
317
280
  window_size = 3
318
281
  success_rates = []
319
282
 
@@ -325,7 +288,6 @@ class AdaptiveLearningSystem:
325
288
  return success_rates
326
289
 
327
290
  async def _persist_execution_record(self, record: ExecutionRecord) -> None:
328
- """Persist execution record to disk."""
329
291
  try:
330
292
  with self.execution_log_path.open("a") as f:
331
293
  data = asdict(record)
@@ -335,7 +297,6 @@ class AdaptiveLearningSystem:
335
297
  self.logger.error(f"Error persisting execution record: {e}")
336
298
 
337
299
  async def _persist_agent_metrics(self) -> None:
338
- """Persist agent metrics to disk."""
339
300
  try:
340
301
  metrics_data = {}
341
302
  for agent_name, metrics in self._agent_metrics.items():
@@ -350,7 +311,6 @@ class AdaptiveLearningSystem:
350
311
  self.logger.error(f"Error persisting agent metrics: {e}")
351
312
 
352
313
  async def _persist_learning_insights(self) -> None:
353
- """Persist learning insights to disk."""
354
314
  try:
355
315
  insights_data = []
356
316
  for insight in self._learning_insights:
@@ -365,36 +325,29 @@ class AdaptiveLearningSystem:
365
325
  self.logger.error(f"Error persisting learning insights: {e}")
366
326
 
367
327
  async def _analyze_and_learn(self) -> None:
368
- """Analyze execution data and generate learning insights."""
369
328
  try:
370
329
  new_insights = []
371
330
 
372
- # Analyze capability strengths
373
331
  capability_insights = self._analyze_capability_strengths()
374
332
  new_insights.extend(capability_insights)
375
333
 
376
- # Analyze failure patterns
377
334
  failure_insights = self._analyze_failure_patterns()
378
335
  new_insights.extend(failure_insights)
379
336
 
380
- # Analyze task patterns
381
337
  task_pattern_insights = self._analyze_task_patterns()
382
338
  new_insights.extend(task_pattern_insights)
383
339
 
384
- # Add new insights (avoid duplicates)
385
340
  for insight in new_insights:
386
341
  if not self._is_duplicate_insight(insight):
387
342
  self._learning_insights.append(insight)
388
343
  self.logger.debug(f"New learning insight: {insight.description}")
389
344
 
390
- # Persist insights
391
345
  await self._persist_learning_insights()
392
346
 
393
347
  except Exception as e:
394
348
  self.logger.error(f"Error in learning analysis: {e}")
395
349
 
396
350
  def _analyze_capability_strengths(self) -> list[LearningInsight]:
397
- """Analyze which agents excel at which capabilities."""
398
351
  capability_performance = self._group_capability_performance()
399
352
  insights = []
400
353
 
@@ -404,7 +357,6 @@ class AdaptiveLearningSystem:
404
357
  return insights
405
358
 
406
359
  def _group_capability_performance(self) -> dict[str, dict[str, list[bool]]]:
407
- """Group execution records by capability and agent."""
408
360
  capability_performance = defaultdict(lambda: defaultdict(list))
409
361
 
410
362
  for record in self._execution_records[-100:]:
@@ -418,19 +370,18 @@ class AdaptiveLearningSystem:
418
370
  def _find_capability_experts(
419
371
  self, capability: str, agents: dict[str, list[bool]]
420
372
  ) -> list[LearningInsight]:
421
- """Find agents with exceptional performance in a specific capability."""
422
373
  insights = []
423
374
 
424
375
  for agent_name, successes in agents.items():
425
- if len(successes) >= 3: # Minimum sample size
376
+ if len(successes) >= 3:
426
377
  success_rate = sum(successes) / len(successes)
427
378
 
428
- if success_rate >= 0.9: # High success rate
379
+ if success_rate >= 0.9:
429
380
  insight = LearningInsight(
430
381
  insight_type="capability_strength",
431
382
  agent_name=agent_name,
432
383
  confidence=min(success_rate, len(successes) / 10.0),
433
- description=f"{agent_name} excels at {capability} tasks (success rate: {success_rate:.1%})",
384
+ description=f"{agent_name} excels at {capability} tasks (success rate: {success_rate: .1 %})",
434
385
  supporting_evidence={
435
386
  "capability": capability,
436
387
  "success_rate": success_rate,
@@ -443,12 +394,10 @@ class AdaptiveLearningSystem:
443
394
  return insights
444
395
 
445
396
  def _analyze_failure_patterns(self) -> list[LearningInsight]:
446
- """Analyze common failure patterns."""
447
397
  failure_patterns = self._group_failure_patterns()
448
398
  return self._extract_significant_failure_insights(failure_patterns)
449
399
 
450
400
  def _group_failure_patterns(self) -> dict[str, dict[str, int]]:
451
- """Group failure patterns by agent and error type."""
452
401
  failure_patterns = defaultdict(lambda: defaultdict(int))
453
402
 
454
403
  for record in self._execution_records[-100:]:
@@ -464,7 +413,6 @@ class AdaptiveLearningSystem:
464
413
  def _extract_significant_failure_insights(
465
414
  self, failure_patterns: dict[str, dict[str, int]]
466
415
  ) -> list[LearningInsight]:
467
- """Extract significant failure pattern insights."""
468
416
  insights = []
469
417
 
470
418
  for agent_name, patterns in failure_patterns.items():
@@ -476,14 +424,13 @@ class AdaptiveLearningSystem:
476
424
  def _extract_agent_failure_insights(
477
425
  self, agent_name: str, patterns: dict[str, int]
478
426
  ) -> list[LearningInsight]:
479
- """Extract failure insights for a specific agent."""
480
427
  total_failures = sum(patterns.values())
481
- if total_failures < 3: # Minimum sample size
428
+ if total_failures < 3:
482
429
  return []
483
430
 
484
431
  insights = []
485
432
  for error_type, count in patterns.items():
486
- if count / total_failures >= 0.5: # Common pattern
433
+ if count / total_failures >= 0.5:
487
434
  insight = self._create_failure_insight(
488
435
  agent_name, error_type, count, total_failures
489
436
  )
@@ -494,7 +441,6 @@ class AdaptiveLearningSystem:
494
441
  def _create_failure_insight(
495
442
  self, agent_name: str, error_type: str, count: int, total_failures: int
496
443
  ) -> LearningInsight:
497
- """Create a failure pattern insight."""
498
444
  return LearningInsight(
499
445
  insight_type="failure_pattern",
500
446
  agent_name=agent_name,
@@ -509,12 +455,11 @@ class AdaptiveLearningSystem:
509
455
  )
510
456
 
511
457
  def _analyze_task_patterns(self) -> list[LearningInsight]:
512
- """Analyze task patterns and agent preferences."""
513
458
  task_performance = self._group_task_performance()
514
459
  insights = []
515
460
 
516
461
  for task_hash, agents in task_performance.items():
517
- if len(agents) > 1: # Multiple agents tried this task type
462
+ if len(agents) > 1:
518
463
  best_agent, best_rate = self._find_best_performing_agent(agents)
519
464
 
520
465
  if best_agent and best_rate >= 0.8:
@@ -526,7 +471,6 @@ class AdaptiveLearningSystem:
526
471
  return insights
527
472
 
528
473
  def _group_task_performance(self) -> dict[str, dict[str, list[bool]]]:
529
- """Group task performance by hash and agent."""
530
474
  task_performance = defaultdict(lambda: defaultdict(list))
531
475
 
532
476
  for record in self._execution_records[-100:]:
@@ -540,12 +484,11 @@ class AdaptiveLearningSystem:
540
484
  def _find_best_performing_agent(
541
485
  self, agents: dict[str, list[bool]]
542
486
  ) -> tuple[str | None, float]:
543
- """Find the best performing agent for a task pattern."""
544
487
  best_agent = None
545
488
  best_rate = 0.0
546
489
 
547
490
  for agent_name, successes in agents.items():
548
- if len(successes) >= 2: # Minimum attempts
491
+ if len(successes) >= 2:
549
492
  success_rate = sum(successes) / len(successes)
550
493
  if success_rate > best_rate:
551
494
  best_rate = success_rate
@@ -560,7 +503,6 @@ class AdaptiveLearningSystem:
560
503
  best_rate: float,
561
504
  agents: dict[str, list[bool]],
562
505
  ) -> LearningInsight:
563
- """Create a task pattern insight."""
564
506
  example_task = next(
565
507
  (
566
508
  r.task_description
@@ -584,7 +526,6 @@ class AdaptiveLearningSystem:
584
526
  )
585
527
 
586
528
  def _categorize_error(self, error_message: str) -> str:
587
- """Categorize error message into type."""
588
529
  error_lower = error_message.lower()
589
530
 
590
531
  if "timeout" in error_lower:
@@ -603,7 +544,6 @@ class AdaptiveLearningSystem:
603
544
  return "other"
604
545
 
605
546
  def _is_duplicate_insight(self, new_insight: LearningInsight) -> bool:
606
- """Check if insight already exists."""
607
547
  for existing in self._learning_insights:
608
548
  if (
609
549
  existing.insight_type == new_insight.insight_type
@@ -618,7 +558,6 @@ class AdaptiveLearningSystem:
618
558
  task: TaskDescription,
619
559
  candidate_agents: list[str],
620
560
  ) -> dict[str, float]:
621
- """Get recommendations for agents based on learning."""
622
561
  task_capabilities = [cap.value for cap in self._infer_task_capabilities(task)]
623
562
  task_hash = self._hash_task(task)
624
563
 
@@ -633,15 +572,12 @@ class AdaptiveLearningSystem:
633
572
  def _calculate_agent_score(
634
573
  self, agent_name: str, task_capabilities: list[str], task_hash: str
635
574
  ) -> float:
636
- """Calculate recommendation score for a specific agent."""
637
575
  score = 0.0
638
576
 
639
- # Base score from metrics
640
577
  if agent_name in self._agent_metrics:
641
578
  metrics = self._agent_metrics[agent_name]
642
579
  score += self._calculate_metrics_score(metrics, task_capabilities)
643
580
 
644
- # Insights bonus/penalty
645
581
  score += self._calculate_insights_score(
646
582
  agent_name, task_capabilities, task_hash
647
583
  )
@@ -651,10 +587,8 @@ class AdaptiveLearningSystem:
651
587
  def _calculate_metrics_score(
652
588
  self, metrics: AgentPerformanceMetrics, task_capabilities: list[str]
653
589
  ) -> float:
654
- """Calculate score based on agent metrics."""
655
590
  score = metrics.success_rate * 0.4
656
591
 
657
- # Capability-specific performance
658
592
  capability_scores = [
659
593
  metrics.capability_success_rates[capability]
660
594
  for capability in task_capabilities
@@ -664,18 +598,16 @@ class AdaptiveLearningSystem:
664
598
  if capability_scores:
665
599
  score += (sum(capability_scores) / len(capability_scores)) * 0.4
666
600
 
667
- # Recent trend adjustment
668
601
  if metrics.recent_performance_trend > 0:
669
602
  score += metrics.recent_performance_trend * 0.1
670
603
  elif metrics.recent_performance_trend < 0:
671
- score += metrics.recent_performance_trend * 0.05 # Smaller penalty
604
+ score += metrics.recent_performance_trend * 0.05
672
605
 
673
606
  return score
674
607
 
675
608
  def _calculate_insights_score(
676
609
  self, agent_name: str, task_capabilities: list[str], task_hash: str
677
610
  ) -> float:
678
- """Calculate score adjustment based on learning insights."""
679
611
  relevant_insights = [
680
612
  insight
681
613
  for insight in self._learning_insights
@@ -697,7 +629,6 @@ class AdaptiveLearningSystem:
697
629
  return score_adjustment
698
630
 
699
631
  def get_learning_summary(self) -> dict[str, t.Any]:
700
- """Get a summary of learning progress."""
701
632
  total_records = len(self._execution_records)
702
633
 
703
634
  if total_records == 0:
@@ -708,7 +639,6 @@ class AdaptiveLearningSystem:
708
639
  recent_records
709
640
  )
710
641
 
711
- # Agent performance summary
712
642
  agent_summary = {}
713
643
  for agent_name, metrics in self._agent_metrics.items():
714
644
  agent_summary[agent_name] = {
@@ -717,7 +647,6 @@ class AdaptiveLearningSystem:
717
647
  "trend": metrics.recent_performance_trend,
718
648
  }
719
649
 
720
- # Insights summary
721
650
  insights_by_type = defaultdict(int)
722
651
  for insight in self._learning_insights:
723
652
  insights_by_type[insight.insight_type] += 1
@@ -737,12 +666,10 @@ class AdaptiveLearningSystem:
737
666
  }
738
667
 
739
668
 
740
- # Global learning system instance
741
669
  _learning_system_instance: AdaptiveLearningSystem | None = None
742
670
 
743
671
 
744
672
  async def get_learning_system() -> AdaptiveLearningSystem:
745
- """Get or create the global learning system."""
746
673
  global _learning_system_instance
747
674
 
748
675
  if _learning_system_instance is None: