crackerjack 0.38.14__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.
- crackerjack/__main__.py +134 -13
- crackerjack/agents/__init__.py +2 -0
- crackerjack/agents/base.py +1 -0
- crackerjack/agents/claude_code_bridge.py +319 -0
- crackerjack/agents/coordinator.py +6 -3
- crackerjack/agents/dry_agent.py +187 -3
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/performance_agent.py +324 -3
- crackerjack/agents/refactoring_agent.py +254 -5
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/cli/options.py +27 -0
- crackerjack/cli/semantic_handlers.py +290 -0
- crackerjack/core/async_workflow_orchestrator.py +9 -8
- crackerjack/core/enhanced_container.py +1 -1
- crackerjack/core/phase_coordinator.py +1 -1
- crackerjack/core/proactive_workflow.py +1 -1
- crackerjack/core/workflow_orchestrator.py +9 -6
- crackerjack/documentation/ai_templates.py +1 -1
- crackerjack/interactive.py +1 -1
- crackerjack/mcp/server_core.py +2 -0
- crackerjack/mcp/tools/__init__.py +2 -0
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/models/semantic_models.py +271 -0
- crackerjack/plugins/loader.py +2 -2
- crackerjack/py313.py +4 -1
- crackerjack/services/embeddings.py +444 -0
- crackerjack/services/initialization.py +1 -1
- crackerjack/services/quality_intelligence.py +11 -1
- crackerjack/services/smart_scheduling.py +1 -1
- crackerjack/services/status_authentication.py +3 -3
- crackerjack/services/vector_store.py +681 -0
- crackerjack/slash_commands/run.md +84 -50
- {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/METADATA +7 -2
- {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/RECORD +39 -29
- {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/WHEEL +0 -0
- {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.38.14.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=
|
|
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)
|