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.
- 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/quality_intelligence.py +11 -1
- crackerjack/services/smart_scheduling.py +1 -1
- crackerjack/services/vector_store.py +681 -0
- crackerjack/slash_commands/run.md +84 -50
- {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/METADATA +7 -2
- {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/RECORD +37 -27
- {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/WHEEL +0 -0
- {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.38.15.dist-info → crackerjack-0.39.0.dist-info}/licenses/LICENSE +0 -0
crackerjack/agents/dry_agent.py
CHANGED
|
@@ -3,15 +3,32 @@ from pathlib import Path
|
|
|
3
3
|
|
|
4
4
|
from ..services.regex_patterns import SAFE_PATTERNS
|
|
5
5
|
from .base import (
|
|
6
|
+
AgentContext,
|
|
6
7
|
FixResult,
|
|
7
8
|
Issue,
|
|
8
9
|
IssueType,
|
|
9
10
|
SubAgent,
|
|
10
11
|
agent_registry,
|
|
11
12
|
)
|
|
13
|
+
from .semantic_helpers import (
|
|
14
|
+
SemanticInsight,
|
|
15
|
+
create_semantic_enhancer,
|
|
16
|
+
get_session_enhanced_recommendations,
|
|
17
|
+
)
|
|
12
18
|
|
|
13
19
|
|
|
14
20
|
class DRYAgent(SubAgent):
|
|
21
|
+
"""Agent for detecting and fixing DRY (Don't Repeat Yourself) violations.
|
|
22
|
+
|
|
23
|
+
Enhanced with semantic context to detect conceptual duplicates beyond
|
|
24
|
+
just syntactic pattern matching.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, context: AgentContext) -> None:
|
|
28
|
+
super().__init__(context)
|
|
29
|
+
self.semantic_enhancer = create_semantic_enhancer(context.project_path)
|
|
30
|
+
self.semantic_insights: dict[str, SemanticInsight] = {}
|
|
31
|
+
|
|
15
32
|
def get_supported_types(self) -> set[IssueType]:
|
|
16
33
|
return {IssueType.DRY_VIOLATION}
|
|
17
34
|
|
|
@@ -66,8 +83,13 @@ class DRYAgent(SubAgent):
|
|
|
66
83
|
remaining_issues=[f"Could not read file: {file_path}"],
|
|
67
84
|
)
|
|
68
85
|
|
|
86
|
+
# Detect traditional pattern-based violations
|
|
69
87
|
violations = self._detect_dry_violations(content, file_path)
|
|
70
88
|
|
|
89
|
+
# Enhance with semantic duplicate detection
|
|
90
|
+
semantic_violations = await self._detect_semantic_violations(content, file_path)
|
|
91
|
+
violations.extend(semantic_violations)
|
|
92
|
+
|
|
71
93
|
if not violations:
|
|
72
94
|
return FixResult(
|
|
73
95
|
success=True,
|
|
@@ -75,9 +97,9 @@ class DRYAgent(SubAgent):
|
|
|
75
97
|
recommendations=["No DRY violations detected"],
|
|
76
98
|
)
|
|
77
99
|
|
|
78
|
-
return self._apply_and_save_dry_fixes(file_path, content, violations)
|
|
100
|
+
return await self._apply_and_save_dry_fixes(file_path, content, violations)
|
|
79
101
|
|
|
80
|
-
def _apply_and_save_dry_fixes(
|
|
102
|
+
async def _apply_and_save_dry_fixes(
|
|
81
103
|
self,
|
|
82
104
|
file_path: Path,
|
|
83
105
|
content: str,
|
|
@@ -96,6 +118,28 @@ class DRYAgent(SubAgent):
|
|
|
96
118
|
remaining_issues=[f"Failed to write fixed file: {file_path}"],
|
|
97
119
|
)
|
|
98
120
|
|
|
121
|
+
# Enhance recommendations with semantic insights and session continuity
|
|
122
|
+
recommendations = ["Verify functionality after DRY fixes"]
|
|
123
|
+
if hasattr(self, "current_semantic_insight") and self.current_semantic_insight:
|
|
124
|
+
recommendations = self.semantic_enhancer.enhance_recommendations(
|
|
125
|
+
recommendations, self.current_semantic_insight
|
|
126
|
+
)
|
|
127
|
+
# Log semantic context for debugging
|
|
128
|
+
summary = self.semantic_enhancer.get_semantic_context_summary(
|
|
129
|
+
self.current_semantic_insight
|
|
130
|
+
)
|
|
131
|
+
self.log(f"Semantic context: {summary}")
|
|
132
|
+
|
|
133
|
+
# Store insight for session continuity
|
|
134
|
+
await self.semantic_enhancer.store_insight_to_session(
|
|
135
|
+
self.current_semantic_insight, "DRYAgent"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Enhance with session-stored insights
|
|
139
|
+
recommendations = await get_session_enhanced_recommendations(
|
|
140
|
+
recommendations, "DRYAgent", self.context.project_path
|
|
141
|
+
)
|
|
142
|
+
|
|
99
143
|
return FixResult(
|
|
100
144
|
success=True,
|
|
101
145
|
confidence=0.8,
|
|
@@ -104,7 +148,7 @@ class DRYAgent(SubAgent):
|
|
|
104
148
|
"Consolidated repetitive patterns",
|
|
105
149
|
],
|
|
106
150
|
files_modified=[str(file_path)],
|
|
107
|
-
recommendations=
|
|
151
|
+
recommendations=recommendations,
|
|
108
152
|
)
|
|
109
153
|
|
|
110
154
|
def _create_no_fixes_result(self) -> FixResult:
|
|
@@ -397,5 +441,145 @@ def _ensure_path(path: str | Path) -> Path:
|
|
|
397
441
|
|
|
398
442
|
return modified
|
|
399
443
|
|
|
444
|
+
async def _detect_semantic_violations(
|
|
445
|
+
self, content: str, file_path: Path
|
|
446
|
+
) -> list[dict[str, t.Any]]:
|
|
447
|
+
"""Detect semantic code duplicates using vector similarity."""
|
|
448
|
+
violations = []
|
|
449
|
+
|
|
450
|
+
try:
|
|
451
|
+
# Extract key code functions for semantic analysis
|
|
452
|
+
code_elements = self._extract_code_functions(content)
|
|
453
|
+
|
|
454
|
+
for element in code_elements:
|
|
455
|
+
if element["type"] == "function" and len(element["body"]) > 50:
|
|
456
|
+
# Search for semantically similar functions
|
|
457
|
+
insight = await self.semantic_enhancer.find_duplicate_patterns(
|
|
458
|
+
element["signature"]
|
|
459
|
+
+ "\n"
|
|
460
|
+
+ element["body"][:200], # Include body sample
|
|
461
|
+
current_file=file_path,
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
if insight.high_confidence_matches > 0:
|
|
465
|
+
violations.append(
|
|
466
|
+
{
|
|
467
|
+
"type": "semantic_duplicate",
|
|
468
|
+
"element": element,
|
|
469
|
+
"similar_patterns": insight.related_patterns[
|
|
470
|
+
:3
|
|
471
|
+
], # Top 3 matches
|
|
472
|
+
"confidence_score": insight.high_confidence_matches
|
|
473
|
+
/ insight.total_matches
|
|
474
|
+
if insight.total_matches > 0
|
|
475
|
+
else 0,
|
|
476
|
+
"suggestion": "Consider extracting common functionality to shared utility",
|
|
477
|
+
}
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
# Store insight for recommendation enhancement
|
|
481
|
+
self.current_semantic_insight = insight
|
|
482
|
+
|
|
483
|
+
except Exception as e:
|
|
484
|
+
self.log(f"Warning: Semantic violation detection failed: {e}")
|
|
485
|
+
|
|
486
|
+
return violations
|
|
487
|
+
|
|
488
|
+
def _extract_code_functions(self, content: str) -> list[dict[str, t.Any]]:
|
|
489
|
+
"""Extract functions from code for semantic analysis."""
|
|
490
|
+
functions: list[dict[str, t.Any]] = []
|
|
491
|
+
lines = content.split("\n")
|
|
492
|
+
current_function = None
|
|
493
|
+
|
|
494
|
+
for i, line in enumerate(lines):
|
|
495
|
+
stripped = line.strip()
|
|
496
|
+
|
|
497
|
+
if self._should_skip_line(stripped, current_function, line):
|
|
498
|
+
continue
|
|
499
|
+
|
|
500
|
+
indent = len(line) - len(line.lstrip())
|
|
501
|
+
|
|
502
|
+
if self._is_function_definition(stripped):
|
|
503
|
+
current_function = self._handle_function_definition(
|
|
504
|
+
functions, current_function, stripped, indent, i
|
|
505
|
+
)
|
|
506
|
+
elif current_function:
|
|
507
|
+
current_function = self._handle_function_body_line(
|
|
508
|
+
functions, current_function, line, stripped, indent, i
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
# Add last function if exists
|
|
512
|
+
if current_function:
|
|
513
|
+
current_function["end_line"] = len(lines)
|
|
514
|
+
functions.append(current_function)
|
|
515
|
+
|
|
516
|
+
return functions
|
|
517
|
+
|
|
518
|
+
def _should_skip_line(
|
|
519
|
+
self, stripped: str, current_function: dict[str, t.Any] | None, line: str
|
|
520
|
+
) -> bool:
|
|
521
|
+
"""Check if line should be skipped during function extraction."""
|
|
522
|
+
if not stripped or stripped.startswith("#"):
|
|
523
|
+
if current_function:
|
|
524
|
+
current_function["body"] += line + "\n"
|
|
525
|
+
return True
|
|
526
|
+
return False
|
|
527
|
+
|
|
528
|
+
def _is_function_definition(self, stripped: str) -> bool:
|
|
529
|
+
"""Check if line is a function definition."""
|
|
530
|
+
return stripped.startswith("def ") and "(" in stripped
|
|
531
|
+
|
|
532
|
+
def _handle_function_definition(
|
|
533
|
+
self,
|
|
534
|
+
functions: list[dict[str, t.Any]],
|
|
535
|
+
current_function: dict[str, t.Any] | None,
|
|
536
|
+
stripped: str,
|
|
537
|
+
indent: int,
|
|
538
|
+
line_index: int,
|
|
539
|
+
) -> dict[str, t.Any]:
|
|
540
|
+
"""Handle a new function definition."""
|
|
541
|
+
# Save previous function if exists
|
|
542
|
+
if current_function:
|
|
543
|
+
functions.append(current_function)
|
|
544
|
+
|
|
545
|
+
func_name = stripped.split("(")[0].replace("def ", "").strip()
|
|
546
|
+
return {
|
|
547
|
+
"type": "function",
|
|
548
|
+
"name": func_name,
|
|
549
|
+
"signature": stripped,
|
|
550
|
+
"start_line": line_index + 1,
|
|
551
|
+
"body": "",
|
|
552
|
+
"indent_level": indent,
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
def _handle_function_body_line(
|
|
556
|
+
self,
|
|
557
|
+
functions: list[dict[str, t.Any]],
|
|
558
|
+
current_function: dict[str, t.Any],
|
|
559
|
+
line: str,
|
|
560
|
+
stripped: str,
|
|
561
|
+
indent: int,
|
|
562
|
+
line_index: int,
|
|
563
|
+
) -> dict[str, t.Any] | None:
|
|
564
|
+
"""Handle a line within a function body."""
|
|
565
|
+
# Check if we're still inside the function
|
|
566
|
+
if self._is_line_inside_function(current_function, indent, stripped):
|
|
567
|
+
current_function["body"] += line + "\n"
|
|
568
|
+
return current_function
|
|
569
|
+
else:
|
|
570
|
+
# Function ended
|
|
571
|
+
current_function["end_line"] = line_index
|
|
572
|
+
functions.append(current_function)
|
|
573
|
+
return None
|
|
574
|
+
|
|
575
|
+
def _is_line_inside_function(
|
|
576
|
+
self, current_function: dict[str, t.Any], indent: int, stripped: str
|
|
577
|
+
) -> bool:
|
|
578
|
+
"""Check if line is still inside the current function."""
|
|
579
|
+
return indent > current_function["indent_level"] or (
|
|
580
|
+
indent == current_function["indent_level"]
|
|
581
|
+
and stripped.startswith(('"', "'", "@"))
|
|
582
|
+
)
|
|
583
|
+
|
|
400
584
|
|
|
401
585
|
agent_registry.register(DRYAgent)
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Enhanced AgentCoordinator with Claude Code external agent integration.
|
|
3
|
+
|
|
4
|
+
This module extends the base AgentCoordinator to seamlessly integrate with
|
|
5
|
+
Claude Code's external agents while maintaining full compatibility with
|
|
6
|
+
the existing crackerjack agent system.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import typing as t
|
|
10
|
+
|
|
11
|
+
from .base import AgentContext, FixResult, Issue
|
|
12
|
+
from .claude_code_bridge import ClaudeCodeBridge
|
|
13
|
+
from .coordinator import AgentCoordinator
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class EnhancedAgentCoordinator(AgentCoordinator):
|
|
17
|
+
"""
|
|
18
|
+
AgentCoordinator enhanced with Claude Code external agent integration.
|
|
19
|
+
|
|
20
|
+
This coordinator maintains all the functionality of the base AgentCoordinator
|
|
21
|
+
while adding intelligent consultation with external Claude Code agents
|
|
22
|
+
when handling complex issues.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
context: AgentContext,
|
|
28
|
+
cache: t.Any = None,
|
|
29
|
+
enable_external_agents: bool = True,
|
|
30
|
+
) -> None:
|
|
31
|
+
super().__init__(context, cache)
|
|
32
|
+
self.claude_bridge = ClaudeCodeBridge(context)
|
|
33
|
+
self.external_agents_enabled = enable_external_agents
|
|
34
|
+
self._external_consultation_stats: dict[str, int] = {
|
|
35
|
+
"consultations_requested": 0,
|
|
36
|
+
"consultations_successful": 0,
|
|
37
|
+
"improvements_achieved": 0,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
self.logger.info(
|
|
41
|
+
f"Enhanced coordinator initialized with external agents: {enable_external_agents}"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def enable_external_agents(self, enabled: bool = True) -> None:
|
|
45
|
+
"""Enable or disable external Claude Code agent consultation."""
|
|
46
|
+
self.external_agents_enabled = enabled
|
|
47
|
+
self.logger.info(f"External agents {'enabled' if enabled else 'disabled'}")
|
|
48
|
+
|
|
49
|
+
def get_external_consultation_stats(self) -> dict[str, int]:
|
|
50
|
+
"""Get statistics about external agent consultations."""
|
|
51
|
+
return self._external_consultation_stats.copy()
|
|
52
|
+
|
|
53
|
+
async def handle_issues_proactively(self, issues: list[Issue]) -> FixResult:
|
|
54
|
+
"""
|
|
55
|
+
Enhanced proactive handling with external agent consultation.
|
|
56
|
+
|
|
57
|
+
This method extends the base proactive handling to:
|
|
58
|
+
1. Identify issues that would benefit from external consultation
|
|
59
|
+
2. Pre-consult with relevant Claude Code agents for strategic guidance
|
|
60
|
+
3. Apply the combined internal/external strategy
|
|
61
|
+
"""
|
|
62
|
+
if not self.external_agents_enabled:
|
|
63
|
+
return await super().handle_issues_proactively(issues)
|
|
64
|
+
|
|
65
|
+
if not self.agents:
|
|
66
|
+
self.initialize_agents()
|
|
67
|
+
|
|
68
|
+
if not issues:
|
|
69
|
+
return FixResult(success=True, confidence=1.0)
|
|
70
|
+
|
|
71
|
+
self.logger.info(f"Enhanced proactive handling of {len(issues)} issues")
|
|
72
|
+
|
|
73
|
+
# Pre-analyze issues for external consultation opportunities
|
|
74
|
+
strategic_consultations = await self._pre_consult_for_strategy(issues)
|
|
75
|
+
|
|
76
|
+
# Create enhanced architectural plan incorporating external guidance
|
|
77
|
+
architectural_plan = await self._create_enhanced_architectural_plan(
|
|
78
|
+
issues, strategic_consultations
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Apply fixes with enhanced strategy
|
|
82
|
+
overall_result = await self._apply_enhanced_fixes_with_plan(
|
|
83
|
+
issues, architectural_plan, strategic_consultations
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Post-process with external validation if needed
|
|
87
|
+
validated_result = await self._validate_with_external_agents(
|
|
88
|
+
overall_result, architectural_plan
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
self._update_consultation_stats(strategic_consultations, validated_result)
|
|
92
|
+
|
|
93
|
+
return validated_result
|
|
94
|
+
|
|
95
|
+
async def _pre_consult_for_strategy(self, issues: list[Issue]) -> dict[str, t.Any]:
|
|
96
|
+
"""Pre-consult with external agents for strategic guidance."""
|
|
97
|
+
strategic_consultations: dict[str, t.Any] = {
|
|
98
|
+
"crackerjack_architect_guidance": None,
|
|
99
|
+
"specialist_recommendations": {},
|
|
100
|
+
"coordination_strategy": "internal_first",
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# Identify complex issues that need architectural guidance
|
|
104
|
+
complex_issues = [
|
|
105
|
+
issue
|
|
106
|
+
for issue in issues
|
|
107
|
+
if self.claude_bridge.should_consult_external_agent(issue, 0.0)
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
if not complex_issues:
|
|
111
|
+
return strategic_consultations
|
|
112
|
+
|
|
113
|
+
# Consult crackerjack-architect for overall strategy if available
|
|
114
|
+
if self.claude_bridge.verify_agent_availability("crackerjack-architect"):
|
|
115
|
+
self._external_consultation_stats["consultations_requested"] += 1
|
|
116
|
+
|
|
117
|
+
# Use the first complex issue as representative for strategic planning
|
|
118
|
+
primary_issue = complex_issues[0]
|
|
119
|
+
architect_consultation = await self.claude_bridge.consult_external_agent(
|
|
120
|
+
primary_issue,
|
|
121
|
+
"crackerjack-architect",
|
|
122
|
+
{"context": "strategic_planning"},
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if architect_consultation.get("status") == "success":
|
|
126
|
+
strategic_consultations["crackerjack_architect_guidance"] = (
|
|
127
|
+
architect_consultation
|
|
128
|
+
)
|
|
129
|
+
strategic_consultations["coordination_strategy"] = "architect_guided"
|
|
130
|
+
self._external_consultation_stats["consultations_successful"] += 1
|
|
131
|
+
|
|
132
|
+
return strategic_consultations
|
|
133
|
+
|
|
134
|
+
async def _create_enhanced_architectural_plan(
|
|
135
|
+
self, issues: list[Issue], strategic_consultations: dict[str, t.Any]
|
|
136
|
+
) -> dict[str, t.Any]:
|
|
137
|
+
"""Create architectural plan enhanced with external agent guidance."""
|
|
138
|
+
# Start with the base architectural plan
|
|
139
|
+
base_plan = await self._create_architectural_plan(issues)
|
|
140
|
+
|
|
141
|
+
# Enhance with external guidance if available
|
|
142
|
+
architect_guidance = strategic_consultations.get(
|
|
143
|
+
"crackerjack_architect_guidance"
|
|
144
|
+
)
|
|
145
|
+
if architect_guidance and architect_guidance.get("status") == "success":
|
|
146
|
+
# Integrate external architectural guidance
|
|
147
|
+
base_plan["external_guidance"] = architect_guidance
|
|
148
|
+
base_plan["enhanced_patterns"] = architect_guidance.get("patterns", [])
|
|
149
|
+
base_plan["external_validation"] = architect_guidance.get(
|
|
150
|
+
"validation_steps", []
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Update strategy based on external guidance
|
|
154
|
+
if "strategy" in architect_guidance:
|
|
155
|
+
base_plan["strategy"] = "external_specialist_guided"
|
|
156
|
+
|
|
157
|
+
return base_plan
|
|
158
|
+
|
|
159
|
+
async def _apply_enhanced_fixes_with_plan(
|
|
160
|
+
self,
|
|
161
|
+
issues: list[Issue],
|
|
162
|
+
plan: dict[str, t.Any],
|
|
163
|
+
strategic_consultations: dict[str, t.Any],
|
|
164
|
+
) -> FixResult:
|
|
165
|
+
"""Apply fixes using enhanced strategy with external guidance."""
|
|
166
|
+
# Use the base implementation but with enhanced plan
|
|
167
|
+
return await self._apply_fixes_with_plan(issues, plan)
|
|
168
|
+
|
|
169
|
+
async def _validate_with_external_agents(
|
|
170
|
+
self, result: FixResult, plan: dict[str, t.Any]
|
|
171
|
+
) -> FixResult:
|
|
172
|
+
"""Post-validate results with external agents if configured."""
|
|
173
|
+
external_validation = plan.get("external_validation", [])
|
|
174
|
+
|
|
175
|
+
if not external_validation or not self.external_agents_enabled:
|
|
176
|
+
return result
|
|
177
|
+
|
|
178
|
+
# Add validation recommendations from external agents
|
|
179
|
+
validation_recommendations = [
|
|
180
|
+
f"External validation: {validation_step}"
|
|
181
|
+
for validation_step in external_validation
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
enhanced_result = FixResult(
|
|
185
|
+
success=result.success,
|
|
186
|
+
confidence=min(
|
|
187
|
+
result.confidence + 0.1, 1.0
|
|
188
|
+
), # Slight confidence boost for external validation
|
|
189
|
+
fixes_applied=result.fixes_applied.copy(),
|
|
190
|
+
remaining_issues=result.remaining_issues.copy(),
|
|
191
|
+
recommendations=result.recommendations + validation_recommendations,
|
|
192
|
+
files_modified=result.files_modified.copy(),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
return enhanced_result
|
|
196
|
+
|
|
197
|
+
def _update_consultation_stats(
|
|
198
|
+
self, strategic_consultations: dict[str, t.Any], result: FixResult
|
|
199
|
+
) -> None:
|
|
200
|
+
"""Update statistics about external consultations."""
|
|
201
|
+
if strategic_consultations.get("crackerjack_architect_guidance"):
|
|
202
|
+
if result.success and result.confidence > 0.8:
|
|
203
|
+
self._external_consultation_stats["improvements_achieved"] += 1
|
|
204
|
+
|
|
205
|
+
async def _handle_with_single_agent_enhanced(
|
|
206
|
+
self, agent: t.Any, issue: Issue
|
|
207
|
+
) -> FixResult:
|
|
208
|
+
"""Enhanced single agent handling with external consultation."""
|
|
209
|
+
# Check if this agent should consult external experts
|
|
210
|
+
internal_result = await super()._handle_with_single_agent(agent, issue)
|
|
211
|
+
|
|
212
|
+
# If the agent is proactive and has external consultation capability, enhance it
|
|
213
|
+
if (
|
|
214
|
+
hasattr(agent, "claude_bridge")
|
|
215
|
+
and self.external_agents_enabled
|
|
216
|
+
and not internal_result.success
|
|
217
|
+
):
|
|
218
|
+
# Try external consultation for failed fixes
|
|
219
|
+
recommended_agents = self.claude_bridge.get_recommended_external_agents(
|
|
220
|
+
issue
|
|
221
|
+
)
|
|
222
|
+
if recommended_agents:
|
|
223
|
+
self._external_consultation_stats["consultations_requested"] += 1
|
|
224
|
+
|
|
225
|
+
# Consult the top recommended external agent
|
|
226
|
+
consultation = await self.claude_bridge.consult_external_agent(
|
|
227
|
+
issue, recommended_agents[0]
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
if consultation.get("status") == "success":
|
|
231
|
+
self._external_consultation_stats["consultations_successful"] += 1
|
|
232
|
+
enhanced_result = self.claude_bridge.create_enhanced_fix_result(
|
|
233
|
+
internal_result, [consultation]
|
|
234
|
+
)
|
|
235
|
+
return enhanced_result
|
|
236
|
+
|
|
237
|
+
return internal_result
|
|
238
|
+
|
|
239
|
+
def get_enhanced_agent_capabilities(self) -> dict[str, dict[str, t.Any]]:
|
|
240
|
+
"""Get capabilities including external agent integration."""
|
|
241
|
+
base_capabilities = self.get_agent_capabilities()
|
|
242
|
+
|
|
243
|
+
# Add information about external agent integration
|
|
244
|
+
enhanced_info = {
|
|
245
|
+
"external_agents_enabled": self.external_agents_enabled,
|
|
246
|
+
"available_external_agents": [
|
|
247
|
+
agent
|
|
248
|
+
for agent in (
|
|
249
|
+
"crackerjack-architect",
|
|
250
|
+
"python-pro",
|
|
251
|
+
"security-auditor",
|
|
252
|
+
"refactoring-specialist",
|
|
253
|
+
"crackerjack-test-specialist",
|
|
254
|
+
)
|
|
255
|
+
if self.claude_bridge.verify_agent_availability(agent)
|
|
256
|
+
],
|
|
257
|
+
"consultation_stats": self.get_external_consultation_stats(),
|
|
258
|
+
"claude_code_bridge": {
|
|
259
|
+
"agent_mapping_coverage": len(self.claude_bridge._get_agent_mapping()),
|
|
260
|
+
"consultation_threshold": self.claude_bridge._get_consultation_threshold(),
|
|
261
|
+
},
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return base_capabilities | {"_enhanced_coordinator_info": enhanced_info}
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def create_enhanced_coordinator(
|
|
268
|
+
context: AgentContext, cache: t.Any = None, enable_external_agents: bool = True
|
|
269
|
+
) -> EnhancedAgentCoordinator:
|
|
270
|
+
"""
|
|
271
|
+
Factory function to create an enhanced coordinator.
|
|
272
|
+
|
|
273
|
+
This function provides a clean interface for creating coordinators
|
|
274
|
+
with external agent integration while maintaining compatibility
|
|
275
|
+
with existing code.
|
|
276
|
+
"""
|
|
277
|
+
return EnhancedAgentCoordinator(
|
|
278
|
+
context=context, cache=cache, enable_external_agents=enable_external_agents
|
|
279
|
+
)
|