crackerjack 0.38.15__py3-none-any.whl → 0.39.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.

Potentially problematic release.


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

Files changed (37) hide show
  1. crackerjack/__main__.py +134 -13
  2. crackerjack/agents/__init__.py +2 -0
  3. crackerjack/agents/base.py +1 -0
  4. crackerjack/agents/claude_code_bridge.py +319 -0
  5. crackerjack/agents/coordinator.py +6 -3
  6. crackerjack/agents/dry_agent.py +187 -3
  7. crackerjack/agents/enhanced_coordinator.py +279 -0
  8. crackerjack/agents/enhanced_proactive_agent.py +185 -0
  9. crackerjack/agents/performance_agent.py +324 -3
  10. crackerjack/agents/refactoring_agent.py +254 -5
  11. crackerjack/agents/semantic_agent.py +479 -0
  12. crackerjack/agents/semantic_helpers.py +356 -0
  13. crackerjack/cli/options.py +27 -0
  14. crackerjack/cli/semantic_handlers.py +290 -0
  15. crackerjack/core/async_workflow_orchestrator.py +9 -8
  16. crackerjack/core/enhanced_container.py +1 -1
  17. crackerjack/core/phase_coordinator.py +1 -1
  18. crackerjack/core/proactive_workflow.py +1 -1
  19. crackerjack/core/workflow_orchestrator.py +9 -6
  20. crackerjack/documentation/ai_templates.py +1 -1
  21. crackerjack/interactive.py +1 -1
  22. crackerjack/mcp/server_core.py +2 -0
  23. crackerjack/mcp/tools/__init__.py +2 -0
  24. crackerjack/mcp/tools/semantic_tools.py +584 -0
  25. crackerjack/models/semantic_models.py +271 -0
  26. crackerjack/plugins/loader.py +2 -2
  27. crackerjack/py313.py +4 -1
  28. crackerjack/services/embeddings.py +444 -0
  29. crackerjack/services/quality_intelligence.py +11 -1
  30. crackerjack/services/smart_scheduling.py +1 -1
  31. crackerjack/services/vector_store.py +681 -0
  32. crackerjack/slash_commands/run.md +84 -50
  33. {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/METADATA +7 -2
  34. {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/RECORD +37 -27
  35. {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/WHEEL +0 -0
  36. {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/entry_points.txt +0 -0
  37. {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,185 @@
1
+ """
2
+ Enhanced proactive agent that integrates Claude Code external agent consultation.
3
+
4
+ This module extends the base ProactiveAgent to consult with Claude Code's external
5
+ agents (like crackerjack-architect, python-pro, security-auditor) when handling
6
+ complex issues that require specialized expertise.
7
+ """
8
+
9
+ import typing as t
10
+ from abc import abstractmethod
11
+
12
+ from .base import AgentContext, FixResult, Issue
13
+ from .claude_code_bridge import ClaudeCodeBridge
14
+ from .proactive_agent import ProactiveAgent
15
+
16
+
17
+ class EnhancedProactiveAgent(ProactiveAgent):
18
+ """
19
+ Proactive agent enhanced with Claude Code external agent consultation.
20
+
21
+ This agent follows the standard crackerjack agent pattern but adds intelligent
22
+ consultation with external Claude Code agents for complex scenarios that
23
+ require specialized expertise.
24
+ """
25
+
26
+ def __init__(self, context: AgentContext) -> None:
27
+ super().__init__(context)
28
+ self.claude_bridge = ClaudeCodeBridge(context)
29
+ self._external_consultation_enabled = True
30
+
31
+ def enable_external_consultation(self, enabled: bool = True) -> None:
32
+ """Enable or disable external Claude Code agent consultation."""
33
+ self._external_consultation_enabled = enabled
34
+
35
+ async def _execute_with_plan(
36
+ self, issue: Issue, plan: dict[str, t.Any]
37
+ ) -> FixResult:
38
+ """
39
+ Execute fix with plan, consulting external agents when appropriate.
40
+
41
+ This method enhances the base implementation by:
42
+ 1. First attempting the internal fix
43
+ 2. Evaluating if external consultation would improve the result
44
+ 3. Consulting with relevant Claude Code agents
45
+ 4. Combining internal and external guidance for better results
46
+ """
47
+ # First, get the internal fix result
48
+ internal_result = await self._execute_internal_fix(issue, plan)
49
+
50
+ # Determine if we should consult external agents
51
+ if not self._should_consult_external_agents(issue, internal_result, plan):
52
+ return internal_result
53
+
54
+ # Consult with relevant external agents
55
+ external_consultations = await self._consult_external_agents(issue, plan)
56
+
57
+ # Enhance the result with external guidance
58
+ enhanced_result = self._combine_internal_and_external_results(
59
+ internal_result, external_consultations
60
+ )
61
+
62
+ return enhanced_result
63
+
64
+ async def _execute_internal_fix(
65
+ self, issue: Issue, plan: dict[str, t.Any]
66
+ ) -> FixResult:
67
+ """Execute the internal fix using the built-in agent logic."""
68
+ # This calls the concrete agent's analyze_and_fix implementation
69
+ return await self.analyze_and_fix(issue)
70
+
71
+ def _should_consult_external_agents(
72
+ self, issue: Issue, internal_result: FixResult, plan: dict[str, t.Any]
73
+ ) -> bool:
74
+ """Determine if external consultation would be beneficial."""
75
+ if not self._external_consultation_enabled:
76
+ return False
77
+
78
+ # Consult external agents if:
79
+ # 1. Internal result has low confidence
80
+ # 2. Issue is complex and requires specialized expertise
81
+ # 3. Plan strategy indicates external specialist guidance
82
+ return (
83
+ self.claude_bridge.should_consult_external_agent(
84
+ issue, internal_result.confidence
85
+ )
86
+ or plan.get("strategy") == "external_specialist_guided"
87
+ or not internal_result.success
88
+ )
89
+
90
+ async def _consult_external_agents(
91
+ self, issue: Issue, plan: dict[str, t.Any]
92
+ ) -> list[dict[str, t.Any]]:
93
+ """Consult with relevant external Claude Code agents."""
94
+ recommended_agents = self.claude_bridge.get_recommended_external_agents(issue)
95
+ consultations = []
96
+
97
+ # Limit to top 2 agents to avoid overwhelming the system
98
+ for agent_name in recommended_agents[:2]:
99
+ if self.claude_bridge.verify_agent_availability(agent_name):
100
+ consultation = await self.claude_bridge.consult_external_agent(
101
+ issue, agent_name, {"plan": plan}
102
+ )
103
+ if consultation.get("status") == "success":
104
+ consultations.append(consultation)
105
+
106
+ return consultations
107
+
108
+ def _combine_internal_and_external_results(
109
+ self, internal_result: FixResult, external_consultations: list[dict[str, t.Any]]
110
+ ) -> FixResult:
111
+ """Combine internal fix result with external agent consultations."""
112
+ if not external_consultations:
113
+ return internal_result
114
+
115
+ # Use the bridge to create an enhanced result
116
+ enhanced_result = self.claude_bridge.create_enhanced_fix_result(
117
+ internal_result, external_consultations
118
+ )
119
+
120
+ # Add metadata about external consultation
121
+ enhanced_result.recommendations.insert(
122
+ 0,
123
+ f"Enhanced with consultation from {len(external_consultations)} Claude Code agents",
124
+ )
125
+
126
+ return enhanced_result
127
+
128
+ async def plan_before_action(self, issue: Issue) -> dict[str, t.Any]:
129
+ """
130
+ Create a plan that considers both internal and external capabilities.
131
+
132
+ This method should be implemented by concrete agents to define their
133
+ specific planning logic while having access to external consultation.
134
+ """
135
+ # Default implementation - concrete agents should override this
136
+ if self.claude_bridge.should_consult_external_agent(issue, 0.0):
137
+ return {
138
+ "strategy": "external_specialist_guided",
139
+ "approach": "consult_claude_code_experts",
140
+ "patterns": ["external_guidance"],
141
+ "validation": ["verify_with_external_agents"],
142
+ }
143
+
144
+ return {
145
+ "strategy": "internal_pattern_based",
146
+ "approach": "apply_internal_logic",
147
+ "patterns": ["standard_patterns"],
148
+ "validation": ["run_internal_checks"],
149
+ }
150
+
151
+ @abstractmethod
152
+ async def analyze_and_fix(self, issue: Issue) -> FixResult:
153
+ """
154
+ Concrete agents must implement their specific fix logic.
155
+
156
+ This method contains the core agent-specific logic for analyzing
157
+ and fixing issues. The enhanced execution framework will automatically
158
+ handle external consultation when appropriate.
159
+ """
160
+ pass
161
+
162
+
163
+ # Convenience function to enhance existing agents
164
+ def enhance_agent_with_claude_code_bridge(
165
+ agent_class: type[ProactiveAgent],
166
+ ) -> type[EnhancedProactiveAgent]:
167
+ """
168
+ Enhance an existing ProactiveAgent class with Claude Code external consultation.
169
+
170
+ This function creates a new class that inherits from both the original agent
171
+ and EnhancedProactiveAgent, providing external consultation capabilities
172
+ while preserving the original agent's logic.
173
+ """
174
+
175
+ class EnhancedAgent(EnhancedProactiveAgent, agent_class): # type: ignore[misc,valid-type]
176
+ def __init__(self, context: AgentContext) -> None:
177
+ # Initialize both parent classes
178
+ EnhancedProactiveAgent.__init__(self, context)
179
+ agent_class.__init__(self, context)
180
+
181
+ # Preserve the original class name and metadata
182
+ EnhancedAgent.__name__ = f"Enhanced{agent_class.__name__}"
183
+ EnhancedAgent.__qualname__ = f"Enhanced{agent_class.__qualname__}"
184
+
185
+ return EnhancedAgent
@@ -16,11 +16,24 @@ from .base import (
16
16
  agent_registry,
17
17
  )
18
18
  from .performance_helpers import OptimizationResult
19
+ from .semantic_helpers import (
20
+ SemanticInsight,
21
+ create_semantic_enhancer,
22
+ get_session_enhanced_recommendations,
23
+ )
19
24
 
20
25
 
21
26
  class PerformanceAgent(SubAgent):
27
+ """Agent for detecting and fixing performance issues.
28
+
29
+ Enhanced with semantic context to detect performance patterns across
30
+ the codebase and find similar bottlenecks that may not be immediately visible.
31
+ """
32
+
22
33
  def __init__(self, context: AgentContext) -> None:
23
34
  super().__init__(context)
35
+ self.semantic_enhancer = create_semantic_enhancer(context.project_path)
36
+ self.semantic_insights: dict[str, SemanticInsight] = {}
24
37
  self.performance_metrics: dict[str, t.Any] = {}
25
38
  self.optimization_stats: dict[str, int] = {
26
39
  "nested_loops_optimized": 0,
@@ -118,8 +131,15 @@ class PerformanceAgent(SubAgent):
118
131
  remaining_issues=[f"Could not read file: {file_path}"],
119
132
  )
120
133
 
134
+ # Detect traditional performance issues
121
135
  performance_issues = self._detect_performance_issues(content, file_path)
122
136
 
137
+ # Enhance with semantic performance pattern detection
138
+ semantic_issues = await self._detect_semantic_performance_issues(
139
+ content, file_path
140
+ )
141
+ performance_issues.extend(semantic_issues)
142
+
123
143
  if not performance_issues:
124
144
  return FixResult(
125
145
  success=True,
@@ -127,13 +147,13 @@ class PerformanceAgent(SubAgent):
127
147
  recommendations=["No performance issues detected"],
128
148
  )
129
149
 
130
- return self._apply_and_save_optimizations(
150
+ return await self._apply_and_save_optimizations(
131
151
  file_path,
132
152
  content,
133
153
  performance_issues,
134
154
  )
135
155
 
136
- def _apply_and_save_optimizations(
156
+ async def _apply_and_save_optimizations(
137
157
  self,
138
158
  file_path: Path,
139
159
  content: str,
@@ -160,7 +180,7 @@ class PerformanceAgent(SubAgent):
160
180
  "Applied algorithmic improvements",
161
181
  ],
162
182
  files_modified=[str(file_path)],
163
- recommendations=["Test performance improvements with benchmarks"],
183
+ recommendations=await self._generate_enhanced_recommendations(issues),
164
184
  )
165
185
 
166
186
  @staticmethod
@@ -1352,5 +1372,306 @@ class PerformanceAgent(SubAgent):
1352
1372
 
1353
1373
  return lines, modified
1354
1374
 
1375
+ async def _detect_semantic_performance_issues(
1376
+ self, content: str, file_path: Path
1377
+ ) -> list[dict[str, t.Any]]:
1378
+ """Detect performance issues using semantic analysis of similar code patterns."""
1379
+ issues = []
1380
+
1381
+ try:
1382
+ # Extract performance-critical functions for analysis
1383
+ critical_functions = self._extract_performance_critical_functions(content)
1384
+
1385
+ for func in critical_functions:
1386
+ if (
1387
+ func["estimated_complexity"] > 2
1388
+ ): # Focus on potentially complex functions
1389
+ # Search for similar performance patterns
1390
+ insight = await self.semantic_enhancer.find_similar_patterns(
1391
+ f"performance {func['signature']} {func['body_sample']}",
1392
+ current_file=file_path,
1393
+ min_similarity=0.6,
1394
+ max_results=8,
1395
+ )
1396
+
1397
+ if insight.total_matches > 1:
1398
+ # Analyze the similar patterns for performance insights
1399
+ analysis = self._analyze_performance_patterns(insight, func)
1400
+ if analysis["issues_found"]:
1401
+ issues.append(
1402
+ {
1403
+ "type": "semantic_performance_pattern",
1404
+ "function": func,
1405
+ "similar_patterns": insight.related_patterns,
1406
+ "performance_analysis": analysis,
1407
+ "confidence_score": insight.high_confidence_matches
1408
+ / max(insight.total_matches, 1),
1409
+ "suggestion": analysis["optimization_suggestion"],
1410
+ }
1411
+ )
1412
+
1413
+ # Store insight for recommendation enhancement
1414
+ self.semantic_insights[func["name"]] = insight
1415
+
1416
+ except Exception as e:
1417
+ self.log(f"Warning: Semantic performance analysis failed: {e}")
1418
+
1419
+ return issues
1420
+
1421
+ def _extract_performance_critical_functions(
1422
+ self, content: str
1423
+ ) -> list[dict[str, t.Any]]:
1424
+ """Extract functions that are likely performance-critical."""
1425
+ functions: list[dict[str, t.Any]] = []
1426
+ lines = content.split("\n")
1427
+ current_function = None
1428
+
1429
+ for i, line in enumerate(lines):
1430
+ stripped = line.strip()
1431
+
1432
+ if self._is_empty_or_comment_line(stripped):
1433
+ if current_function:
1434
+ current_function["body"] += line + "\n"
1435
+ continue
1436
+
1437
+ indent = len(line) - len(line.lstrip())
1438
+
1439
+ if self._is_function_definition(stripped):
1440
+ current_function = self._handle_function_definition(
1441
+ current_function, functions, stripped, indent, i
1442
+ )
1443
+ elif current_function:
1444
+ current_function = self._handle_function_body_line(
1445
+ current_function, functions, line, stripped, indent, i
1446
+ )
1447
+
1448
+ self._handle_last_function(current_function, functions, len(lines))
1449
+ return functions
1450
+
1451
+ def _is_empty_or_comment_line(self, stripped: str) -> bool:
1452
+ """Check if line is empty or a comment."""
1453
+ return not stripped or stripped.startswith("#")
1454
+
1455
+ def _is_function_definition(self, stripped: str) -> bool:
1456
+ """Check if line is a function definition."""
1457
+ return stripped.startswith("def ") and "(" in stripped
1458
+
1459
+ def _handle_function_definition(
1460
+ self,
1461
+ current_function: dict[str, t.Any] | None,
1462
+ functions: list[dict[str, t.Any]],
1463
+ stripped: str,
1464
+ indent: int,
1465
+ line_number: int,
1466
+ ) -> dict[str, t.Any]:
1467
+ """Handle a function definition line."""
1468
+ # Save previous function if it looks performance-critical
1469
+ if current_function and self._is_performance_critical(current_function):
1470
+ self._finalize_function(current_function, functions, line_number)
1471
+
1472
+ func_name = stripped.split("(")[0].replace("def ", "").strip()
1473
+ return {
1474
+ "name": func_name,
1475
+ "signature": stripped,
1476
+ "start_line": line_number + 1,
1477
+ "body": "",
1478
+ "indent_level": indent,
1479
+ }
1480
+
1481
+ def _handle_function_body_line(
1482
+ self,
1483
+ current_function: dict[str, t.Any],
1484
+ functions: list[dict[str, t.Any]],
1485
+ line: str,
1486
+ stripped: str,
1487
+ indent: int,
1488
+ line_number: int,
1489
+ ) -> dict[str, t.Any] | None:
1490
+ """Handle a line within a function body."""
1491
+ # Check if we're still inside the function
1492
+ if self._is_still_in_function(current_function, indent, stripped):
1493
+ current_function["body"] += line + "\n"
1494
+ return current_function
1495
+ else:
1496
+ # Function ended - check if performance-critical
1497
+ if self._is_performance_critical(current_function):
1498
+ self._finalize_function(current_function, functions, line_number)
1499
+ return None
1500
+
1501
+ def _is_still_in_function(
1502
+ self, current_function: dict[str, t.Any], indent: int, stripped: str
1503
+ ) -> bool:
1504
+ """Check if we're still inside the current function."""
1505
+ return indent > current_function["indent_level"] or (
1506
+ indent == current_function["indent_level"]
1507
+ and stripped.startswith(('"', "'", "@"))
1508
+ )
1509
+
1510
+ def _finalize_function(
1511
+ self,
1512
+ function: dict[str, t.Any],
1513
+ functions: list[dict[str, t.Any]],
1514
+ end_line: int,
1515
+ ) -> None:
1516
+ """Finalize a function and add it to the results."""
1517
+ function["end_line"] = end_line
1518
+ function["body_sample"] = function["body"][:300]
1519
+ function["estimated_complexity"] = self._estimate_complexity(function["body"])
1520
+ functions.append(function)
1521
+
1522
+ def _handle_last_function(
1523
+ self,
1524
+ current_function: dict[str, t.Any] | None,
1525
+ functions: list[dict[str, t.Any]],
1526
+ total_lines: int,
1527
+ ) -> None:
1528
+ """Handle the last function in the file."""
1529
+ if current_function and self._is_performance_critical(current_function):
1530
+ self._finalize_function(current_function, functions, total_lines)
1531
+
1532
+ def _is_performance_critical(self, function_info: dict[str, t.Any]) -> bool:
1533
+ """Determine if a function is likely performance-critical."""
1534
+ body = function_info.get("body", "")
1535
+ name = function_info.get("name", "")
1536
+
1537
+ # Check for performance indicators
1538
+ performance_indicators = [
1539
+ "for " in body
1540
+ and len([line for line in body.split("\n") if "for " in line])
1541
+ > 1, # Multiple loops
1542
+ "while " in body, # While loops
1543
+ body.count("for ") > 0 and len(body) > 200, # Long function with loops
1544
+ any(
1545
+ pattern in body for pattern in (".append(", "+=", ".extend(", "len(")
1546
+ ), # List operations
1547
+ any(
1548
+ pattern in name
1549
+ for pattern in (
1550
+ "process",
1551
+ "analyze",
1552
+ "compute",
1553
+ "calculate",
1554
+ "optimize",
1555
+ )
1556
+ ), # Performance-related names
1557
+ "range(" in body
1558
+ and ("1000" in body or "len(" in body), # Large ranges or length operations
1559
+ ]
1560
+
1561
+ return any(performance_indicators)
1562
+
1563
+ def _estimate_complexity(self, body: str) -> int:
1564
+ """Estimate the computational complexity of a function body."""
1565
+ complexity = 1
1566
+
1567
+ # Count nested structures
1568
+ nested_for_loops = 0
1569
+ for_depth = 0
1570
+ lines = body.split("\n")
1571
+
1572
+ for line in lines:
1573
+ stripped = line.strip()
1574
+ if "for " in stripped:
1575
+ for_depth += 1
1576
+ nested_for_loops = max(nested_for_loops, for_depth)
1577
+ elif (
1578
+ stripped
1579
+ and not stripped.startswith("#")
1580
+ and len(line) - len(line.lstrip()) == 0
1581
+ ):
1582
+ for_depth = 0 # Reset at function/class level
1583
+
1584
+ # Estimate complexity based on nested loops and other factors
1585
+ complexity = max(complexity, nested_for_loops)
1586
+
1587
+ # Add complexity for other expensive operations
1588
+ if ".sort(" in body or "sorted(" in body:
1589
+ complexity += 1
1590
+ if body.count("len(") > 5: # Many length operations
1591
+ complexity += 1
1592
+ if ".index(" in body or ".find(" in body: # Linear search operations
1593
+ complexity += 1
1594
+
1595
+ return complexity
1596
+
1597
+ def _analyze_performance_patterns(
1598
+ self, insight: SemanticInsight, current_func: dict[str, t.Any]
1599
+ ) -> dict[str, t.Any]:
1600
+ """Analyze semantic patterns for performance insights."""
1601
+ analysis: dict[str, t.Any] = {
1602
+ "issues_found": False,
1603
+ "optimization_suggestion": "Consider reviewing similar implementations for consistency",
1604
+ "pattern_insights": [],
1605
+ }
1606
+
1607
+ if insight.high_confidence_matches > 0:
1608
+ analysis["issues_found"] = True
1609
+ analysis["pattern_insights"].append(
1610
+ f"Found {insight.high_confidence_matches} highly similar implementations"
1611
+ )
1612
+
1613
+ # Analyze the patterns for common performance issues
1614
+ performance_concerns = []
1615
+ for pattern in insight.related_patterns:
1616
+ content = pattern.get("content", "").lower()
1617
+ if any(
1618
+ concern in content for concern in ("for", "while", "+=", "append")
1619
+ ):
1620
+ performance_concerns.append(pattern["file_path"])
1621
+
1622
+ if performance_concerns:
1623
+ analysis["optimization_suggestion"] = (
1624
+ f"Performance review needed: {len(performance_concerns)} similar functions "
1625
+ f"may benefit from the same optimization approach"
1626
+ )
1627
+ analysis["pattern_insights"].append(
1628
+ f"Similar performance patterns found in: {', '.join(list(set(performance_concerns))[:3])}"
1629
+ )
1630
+
1631
+ return analysis
1632
+
1633
+ async def _generate_enhanced_recommendations(
1634
+ self, issues: list[dict[str, t.Any]]
1635
+ ) -> list[str]:
1636
+ """Generate enhanced recommendations including semantic insights."""
1637
+ recommendations = ["Test performance improvements with benchmarks"]
1638
+
1639
+ # Add semantic insights
1640
+ semantic_issues = [
1641
+ issue for issue in issues if issue["type"] == "semantic_performance_pattern"
1642
+ ]
1643
+ if semantic_issues:
1644
+ recommendations.append(
1645
+ f"Semantic analysis found {len(semantic_issues)} similar performance patterns "
1646
+ "across codebase - consider applying optimizations consistently"
1647
+ )
1648
+
1649
+ # Store insights for session continuity
1650
+ for issue in semantic_issues:
1651
+ if "semantic_insight" in issue:
1652
+ await self.semantic_enhancer.store_insight_to_session(
1653
+ issue["semantic_insight"], "PerformanceAgent"
1654
+ )
1655
+
1656
+ # Enhance with session-stored insights
1657
+ recommendations = await get_session_enhanced_recommendations(
1658
+ recommendations, "PerformanceAgent", self.context.project_path
1659
+ )
1660
+
1661
+ # Add insights from stored semantic analysis
1662
+ for func_name, insight in self.semantic_insights.items():
1663
+ if insight.high_confidence_matches > 0:
1664
+ enhanced_recs = self.semantic_enhancer.enhance_recommendations(
1665
+ [], # Start with empty list to get just semantic recommendations
1666
+ insight,
1667
+ )
1668
+ recommendations.extend(enhanced_recs)
1669
+
1670
+ # Log semantic context for debugging
1671
+ summary = self.semantic_enhancer.get_semantic_context_summary(insight)
1672
+ self.log(f"Performance semantic context for {func_name}: {summary}")
1673
+
1674
+ return recommendations
1675
+
1355
1676
 
1356
1677
  agent_registry.register(PerformanceAgent)