crackerjack 0.38.15__py3-none-any.whl → 0.39.1__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.1.dist-info}/METADATA +7 -2
  34. {crackerjack-0.38.15.dist-info → crackerjack-0.39.1.dist-info}/RECORD +37 -27
  35. {crackerjack-0.38.15.dist-info → crackerjack-0.39.1.dist-info}/WHEEL +0 -0
  36. {crackerjack-0.38.15.dist-info → crackerjack-0.39.1.dist-info}/entry_points.txt +0 -0
  37. {crackerjack-0.38.15.dist-info → crackerjack-0.39.1.dist-info}/licenses/LICENSE +0 -0
crackerjack/__main__.py CHANGED
@@ -34,6 +34,12 @@ from .cli.handlers import (
34
34
  handle_stop_zuban_lsp,
35
35
  handle_watchdog_mode,
36
36
  )
37
+ from .cli.semantic_handlers import (
38
+ handle_remove_from_semantic_index,
39
+ handle_semantic_index,
40
+ handle_semantic_search,
41
+ handle_semantic_stats,
42
+ )
37
43
 
38
44
  console = Console(force_terminal=True)
39
45
  app = typer.Typer(
@@ -1041,17 +1047,10 @@ def _handle_mkdocs_integration(
1041
1047
  return False
1042
1048
 
1043
1049
 
1044
- def _create_mkdocs_services() -> dict[str, t.Any]:
1045
- """Create and configure MkDocs services."""
1046
- from logging import getLogger
1050
+ def _create_sync_filesystem_service() -> t.Any:
1051
+ """Create filesystem service that matches FileSystemServiceProtocol."""
1047
1052
  from pathlib import Path
1048
1053
 
1049
- from crackerjack.documentation.mkdocs_integration import (
1050
- MkDocsIntegrationService,
1051
- MkDocsSiteBuilder,
1052
- )
1053
-
1054
- # Create filesystem service that matches FileSystemServiceProtocol
1055
1054
  class SyncFileSystemService:
1056
1055
  def read_file(self, path: str | Path) -> str:
1057
1056
  return Path(path).read_text()
@@ -1068,7 +1067,12 @@ def _create_mkdocs_services() -> dict[str, t.Any]:
1068
1067
  def ensure_directory(self, path: str | Path) -> None:
1069
1068
  Path(path).mkdir(parents=True, exist_ok=True)
1070
1069
 
1071
- # Create config manager that implements ConfigManagerProtocol
1070
+ return SyncFileSystemService()
1071
+
1072
+
1073
+ def _create_config_manager() -> t.Any:
1074
+ """Create config manager that implements ConfigManagerProtocol."""
1075
+
1072
1076
  class ConfigManager:
1073
1077
  def __init__(self) -> None:
1074
1078
  self._config: dict[str, t.Any] = {}
@@ -1085,11 +1089,48 @@ def _create_mkdocs_services() -> dict[str, t.Any]:
1085
1089
  def load(self) -> bool:
1086
1090
  return True
1087
1091
 
1088
- filesystem = SyncFileSystemService()
1089
- config_manager = ConfigManager()
1092
+ return ConfigManager()
1093
+
1094
+
1095
+ def _create_logger_adapter(logger: t.Any) -> t.Any:
1096
+ """Create logger adapter for protocol compatibility."""
1097
+
1098
+ class LoggerAdapter:
1099
+ def __init__(self, logger: t.Any) -> None:
1100
+ self._logger = logger
1101
+
1102
+ def debug(self, message: str, **kwargs: t.Any) -> None:
1103
+ self._logger.debug(message)
1104
+
1105
+ def info(self, message: str, **kwargs: t.Any) -> None:
1106
+ self._logger.info(message)
1107
+
1108
+ def warning(self, message: str, **kwargs: t.Any) -> None:
1109
+ self._logger.warning(message)
1110
+
1111
+ def error(self, message: str, **kwargs: t.Any) -> None:
1112
+ self._logger.error(message)
1113
+
1114
+ return LoggerAdapter(logger)
1115
+
1116
+
1117
+ def _create_mkdocs_services() -> dict[str, t.Any]:
1118
+ """Create and configure MkDocs services."""
1119
+ from logging import getLogger
1120
+
1121
+ from crackerjack.documentation.mkdocs_integration import (
1122
+ MkDocsIntegrationService,
1123
+ MkDocsSiteBuilder,
1124
+ )
1125
+
1126
+ filesystem = _create_sync_filesystem_service()
1127
+ config_manager = _create_config_manager()
1090
1128
  logger = getLogger(__name__)
1129
+ logger_adapter = _create_logger_adapter(logger)
1091
1130
 
1092
- integration_service = MkDocsIntegrationService(config_manager, filesystem, logger)
1131
+ integration_service = MkDocsIntegrationService(
1132
+ config_manager, filesystem, logger_adapter
1133
+ )
1093
1134
  builder = MkDocsSiteBuilder(integration_service)
1094
1135
 
1095
1136
  return {"builder": builder, "filesystem": filesystem, "config": config_manager}
@@ -1317,6 +1358,11 @@ def main(
1317
1358
  diff_config: str | None = CLI_OPTIONS["diff_config"],
1318
1359
  config_interactive: bool = CLI_OPTIONS["config_interactive"],
1319
1360
  refresh_cache: bool = CLI_OPTIONS["refresh_cache"],
1361
+ # Semantic search options
1362
+ index: str | None = CLI_OPTIONS["index"],
1363
+ search: str | None = CLI_OPTIONS["search"],
1364
+ semantic_stats: bool = CLI_OPTIONS["semantic_stats"],
1365
+ remove_from_index: str | None = CLI_OPTIONS["remove_from_index"],
1320
1366
  ) -> None:
1321
1367
  options = create_options(
1322
1368
  commit,
@@ -1409,6 +1455,12 @@ def main(
1409
1455
  run_tests=run_tests,
1410
1456
  )
1411
1457
 
1458
+ # Add semantic search options to the options object
1459
+ options.index = index
1460
+ options.search = search
1461
+ options.semantic_stats = semantic_stats
1462
+ options.remove_from_index = remove_from_index
1463
+
1412
1464
  # Setup debug and verbose flags
1413
1465
  ai_fix, verbose = _setup_debug_and_verbose_flags(ai_debug, debug, verbose, options)
1414
1466
  setup_ai_agent_env(ai_fix, ai_debug or debug)
@@ -1442,6 +1494,17 @@ def _process_all_commands(local_vars: t.Any, console: t.Any, options: t.Any) ->
1442
1494
  handle_config_updates(options)
1443
1495
  return False
1444
1496
 
1497
+ # Handle semantic search commands early (they exit after execution)
1498
+ if not _handle_semantic_commands(
1499
+ local_vars["index"],
1500
+ local_vars["search"],
1501
+ local_vars["semantic_stats"],
1502
+ local_vars["remove_from_index"],
1503
+ console,
1504
+ options,
1505
+ ):
1506
+ return False
1507
+
1445
1508
  # Handle server commands (monitoring, websocket, MCP, zuban LSP)
1446
1509
  if _handle_server_commands(
1447
1510
  local_vars["monitor"],
@@ -1625,6 +1688,64 @@ def _handle_coverage_status(
1625
1688
  return False
1626
1689
 
1627
1690
 
1691
+ def _handle_semantic_commands(
1692
+ index: str | None,
1693
+ search: str | None,
1694
+ semantic_stats: bool,
1695
+ remove_from_index: str | None,
1696
+ console: Console,
1697
+ options: t.Any,
1698
+ ) -> bool:
1699
+ """Handle semantic search commands.
1700
+
1701
+ Returns True if execution should continue, False if should return early.
1702
+ """
1703
+ if not _has_semantic_operations(index, search, semantic_stats, remove_from_index):
1704
+ return True
1705
+
1706
+ console.print("[cyan]🔍[/cyan] Running semantic search operations...")
1707
+
1708
+ try:
1709
+ _execute_semantic_operations(index, search, semantic_stats, remove_from_index)
1710
+ return False # Exit after semantic operations
1711
+
1712
+ except Exception as e:
1713
+ console.print(f"[red]❌[/red] Semantic search error: {e}")
1714
+ return False
1715
+
1716
+
1717
+ def _has_semantic_operations(
1718
+ index: str | None,
1719
+ search: str | None,
1720
+ semantic_stats: bool,
1721
+ remove_from_index: str | None,
1722
+ ) -> bool:
1723
+ """Check if any semantic operations are requested."""
1724
+ return any([index, search, semantic_stats, remove_from_index])
1725
+
1726
+
1727
+ def _execute_semantic_operations(
1728
+ index: str | None,
1729
+ search: str | None,
1730
+ semantic_stats: bool,
1731
+ remove_from_index: str | None,
1732
+ ) -> list[str]:
1733
+ """Execute semantic operations in sequence and return remaining operations."""
1734
+ if index:
1735
+ handle_semantic_index(index)
1736
+
1737
+ if search:
1738
+ handle_semantic_search(search)
1739
+
1740
+ if semantic_stats:
1741
+ handle_semantic_stats()
1742
+
1743
+ if remove_from_index:
1744
+ handle_remove_from_semantic_index(remove_from_index)
1745
+
1746
+ return []
1747
+
1748
+
1628
1749
  def _handle_enterprise_features(local_vars: t.Any, console: t.Any) -> bool:
1629
1750
  """Handle enterprise features."""
1630
1751
  # Handle enterprise optimizer
@@ -7,6 +7,7 @@ from . import (
7
7
  performance_agent,
8
8
  refactoring_agent,
9
9
  security_agent,
10
+ semantic_agent,
10
11
  test_creation_agent,
11
12
  test_specialist_agent,
12
13
  )
@@ -33,6 +34,7 @@ __all__ = [
33
34
  "refactoring_agent",
34
35
  "reset_agent_tracker",
35
36
  "security_agent",
37
+ "semantic_agent",
36
38
  "test_creation_agent",
37
39
  "test_specialist_agent",
38
40
  ]
@@ -28,6 +28,7 @@ class IssueType(Enum):
28
28
  TEST_ORGANIZATION = "test_organization"
29
29
  COVERAGE_IMPROVEMENT = "coverage_improvement"
30
30
  REGEX_VALIDATION = "regex_validation"
31
+ SEMANTIC_CONTEXT = "semantic_context"
31
32
 
32
33
 
33
34
  @dataclass
@@ -0,0 +1,319 @@
1
+ """
2
+ Bridge between crackerjack's built-in agents and Claude Code's external agents.
3
+
4
+ This module provides integration between the internal agent system and Claude Code's
5
+ specialized agents located in ~/.claude/agents. It enables crackerjack's built-in
6
+ agents to consult with expert external agents for complex scenarios.
7
+ """
8
+
9
+ import logging
10
+ import typing as t
11
+ from pathlib import Path
12
+
13
+ from .base import AgentContext, FixResult, Issue, IssueType
14
+
15
+ # Mapping of internal issue types to Claude Code external agents
16
+ CLAUDE_CODE_AGENT_MAPPING = {
17
+ IssueType.COMPLEXITY: ["refactoring-specialist", "crackerjack-architect"],
18
+ IssueType.DRY_VIOLATION: ["refactoring-specialist", "crackerjack-architect"],
19
+ IssueType.PERFORMANCE: ["performance-specialist", "python-pro"],
20
+ IssueType.SECURITY: ["security-auditor", "python-pro"],
21
+ IssueType.TYPE_ERROR: ["python-pro", "crackerjack-architect"],
22
+ IssueType.TEST_FAILURE: ["crackerjack-test-specialist", "python-pro"],
23
+ IssueType.TEST_ORGANIZATION: ["crackerjack-test-specialist", "testing-specialist"],
24
+ IssueType.IMPORT_ERROR: ["python-pro", "refactoring-specialist"],
25
+ IssueType.DOCUMENTATION: ["documentation-specialist", "crackerjack-architect"],
26
+ IssueType.FORMATTING: ["python-pro"],
27
+ }
28
+
29
+ # Minimum confidence threshold for consulting external agents
30
+ EXTERNAL_CONSULTATION_THRESHOLD = 0.8
31
+
32
+
33
+ class ClaudeCodeBridge:
34
+ """Bridge for consulting Claude Code external agents."""
35
+
36
+ def __init__(self, context: AgentContext) -> None:
37
+ self.context = context
38
+ self.logger = logging.getLogger(__name__)
39
+ self._agent_path = Path.home() / ".claude" / "agents"
40
+ self._consultation_cache: dict[str, dict[str, t.Any]] = {}
41
+
42
+ def should_consult_external_agent(
43
+ self, issue: Issue, internal_confidence: float
44
+ ) -> bool:
45
+ """Determine if we should consult an external Claude Code agent."""
46
+ # Only consult for complex issues that meet threshold
47
+ if internal_confidence >= EXTERNAL_CONSULTATION_THRESHOLD:
48
+ return False
49
+
50
+ # Check if we have relevant external agents for this issue type
51
+ return issue.type in CLAUDE_CODE_AGENT_MAPPING
52
+
53
+ def _get_agent_mapping(self) -> dict[t.Any, list[str]]:
54
+ """Get the agent mapping for external access."""
55
+ return CLAUDE_CODE_AGENT_MAPPING
56
+
57
+ def _get_consultation_threshold(self) -> float:
58
+ """Get the consultation threshold for external access."""
59
+ return EXTERNAL_CONSULTATION_THRESHOLD
60
+
61
+ def get_recommended_external_agents(self, issue: Issue) -> list[str]:
62
+ """Get list of recommended external agents for an issue."""
63
+ return CLAUDE_CODE_AGENT_MAPPING.get(issue.type, [])
64
+
65
+ def verify_agent_availability(self, agent_name: str) -> bool:
66
+ """Check if a Claude Code agent file exists."""
67
+ agent_file = self._agent_path / f"{agent_name}.md"
68
+ return agent_file.exists()
69
+
70
+ async def consult_external_agent(
71
+ self, issue: Issue, agent_name: str, context: dict[str, t.Any] | None = None
72
+ ) -> dict[str, t.Any]:
73
+ """
74
+ Consult with a Claude Code external agent for expert guidance.
75
+
76
+ This method would ideally use the Task tool to invoke external agents,
77
+ but since we're within crackerjack's internal system, we'll simulate
78
+ the consultation process and provide structured recommendations.
79
+ """
80
+ cache_key = (
81
+ f"{agent_name}:{issue.type.value}:{issue.file_path}:{issue.line_number}"
82
+ )
83
+
84
+ if cache_key in self._consultation_cache:
85
+ self.logger.debug(f"Using cached consultation for {agent_name}")
86
+ return self._consultation_cache[cache_key]
87
+
88
+ if not self.verify_agent_availability(agent_name):
89
+ self.logger.warning(f"Agent {agent_name} not available in ~/.claude/agents")
90
+ return {"status": "unavailable", "recommendations": []}
91
+
92
+ # Generate consultation based on agent expertise and issue type
93
+ consultation = await self._generate_agent_consultation(
94
+ issue, agent_name, context
95
+ )
96
+
97
+ # Cache successful consultations
98
+ if consultation.get("status") == "success":
99
+ self._consultation_cache[cache_key] = consultation
100
+
101
+ return consultation
102
+
103
+ async def _generate_agent_consultation(
104
+ self, issue: Issue, agent_name: str, context: dict[str, t.Any] | None = None
105
+ ) -> dict[str, t.Any]:
106
+ """Generate structured consultation response from agent expertise."""
107
+ consultation: dict[str, t.Any] = {
108
+ "status": "success",
109
+ "agent": agent_name,
110
+ "issue_type": issue.type.value,
111
+ "recommendations": [],
112
+ "patterns": [],
113
+ "validation_steps": [],
114
+ "confidence": 0.9,
115
+ }
116
+
117
+ # Agent-specific consultation logic
118
+ if agent_name == "crackerjack-architect":
119
+ consultation.update(
120
+ await self._consult_crackerjack_architect(issue, context)
121
+ )
122
+ elif agent_name == "python-pro":
123
+ consultation.update(await self._consult_python_pro(issue, context))
124
+ elif agent_name == "security-auditor":
125
+ consultation.update(await self._consult_security_auditor(issue, context))
126
+ elif agent_name == "refactoring-specialist":
127
+ consultation.update(
128
+ await self._consult_refactoring_specialist(issue, context)
129
+ )
130
+ elif agent_name == "crackerjack-test-specialist":
131
+ consultation.update(await self._consult_test_specialist(issue, context))
132
+ else:
133
+ consultation.update(
134
+ await self._consult_generic_agent(issue, agent_name, context)
135
+ )
136
+
137
+ return consultation
138
+
139
+ async def _consult_crackerjack_architect(
140
+ self, issue: Issue, context: dict[str, t.Any] | None = None
141
+ ) -> dict[str, t.Any]:
142
+ """Consult with crackerjack-architect for architectural guidance."""
143
+ return {
144
+ "recommendations": [
145
+ "Apply clean code principles (DRY, YAGNI, KISS)",
146
+ "Follow crackerjack's modular architecture patterns",
147
+ "Use protocol-based dependency injection",
148
+ "Break complex functions into focused helper methods",
149
+ "Maintain single responsibility principle",
150
+ ],
151
+ "patterns": [
152
+ "extract_method",
153
+ "dependency_injection",
154
+ "protocol_interfaces",
155
+ "helper_methods",
156
+ "single_responsibility",
157
+ ],
158
+ "validation_steps": [
159
+ "run_complexity_check",
160
+ "verify_type_annotations",
161
+ "check_architectural_consistency",
162
+ "validate_against_crackerjack_patterns",
163
+ ],
164
+ }
165
+
166
+ async def _consult_python_pro(
167
+ self, issue: Issue, context: dict[str, t.Any] | None = None
168
+ ) -> dict[str, t.Any]:
169
+ """Consult with python-pro for Python-specific best practices."""
170
+ return {
171
+ "recommendations": [
172
+ "Use modern Python 3.13+ type hints with | unions",
173
+ "Apply proper error handling patterns",
174
+ "Follow PEP 8 style guidelines",
175
+ "Use pathlib over os.path",
176
+ "Implement proper context managers",
177
+ ],
178
+ "patterns": [
179
+ "type_annotations",
180
+ "context_managers",
181
+ "exception_handling",
182
+ "python_idioms",
183
+ "modern_syntax",
184
+ ],
185
+ "validation_steps": [
186
+ "run_type_checking",
187
+ "verify_python_compatibility",
188
+ "check_style_compliance",
189
+ "validate_error_handling",
190
+ ],
191
+ }
192
+
193
+ async def _consult_security_auditor(
194
+ self, issue: Issue, context: dict[str, t.Any] | None = None
195
+ ) -> dict[str, t.Any]:
196
+ """Consult with security-auditor for security best practices."""
197
+ return {
198
+ "recommendations": [
199
+ "Never use hardcoded paths or credentials",
200
+ "Use secure temp file creation",
201
+ "Avoid shell=True in subprocess calls",
202
+ "Implement proper input validation",
203
+ "Use environment variables for sensitive data",
204
+ ],
205
+ "patterns": [
206
+ "secure_temp_files",
207
+ "input_validation",
208
+ "safe_subprocess",
209
+ "environment_variables",
210
+ "sanitization",
211
+ ],
212
+ "validation_steps": [
213
+ "run_security_scan",
214
+ "check_for_hardcoded_secrets",
215
+ "validate_subprocess_calls",
216
+ "verify_temp_file_handling",
217
+ ],
218
+ }
219
+
220
+ async def _consult_refactoring_specialist(
221
+ self, issue: Issue, context: dict[str, t.Any] | None = None
222
+ ) -> dict[str, t.Any]:
223
+ """Consult with refactoring-specialist for code improvement."""
224
+ return {
225
+ "recommendations": [
226
+ "Break down complex functions (complexity ≤ 15)",
227
+ "Extract common patterns into utilities",
228
+ "Remove dead code and unused imports",
229
+ "Apply DRY principle to eliminate duplication",
230
+ "Use composition over inheritance",
231
+ ],
232
+ "patterns": [
233
+ "extract_method",
234
+ "eliminate_duplication",
235
+ "dead_code_removal",
236
+ "complexity_reduction",
237
+ "composition_pattern",
238
+ ],
239
+ "validation_steps": [
240
+ "measure_complexity_reduction",
241
+ "verify_test_coverage_maintained",
242
+ "check_for_dead_code",
243
+ "validate_duplication_removal",
244
+ ],
245
+ }
246
+
247
+ async def _consult_test_specialist(
248
+ self, issue: Issue, context: dict[str, t.Any] | None = None
249
+ ) -> dict[str, t.Any]:
250
+ """Consult with crackerjack-test-specialist for testing guidance."""
251
+ return {
252
+ "recommendations": [
253
+ "Avoid complex async tests that can hang",
254
+ "Use synchronous config tests for reliability",
255
+ "Mock external dependencies properly",
256
+ "Follow crackerjack's testing patterns",
257
+ "Maintain test coverage ratchet",
258
+ ],
259
+ "patterns": [
260
+ "synchronous_tests",
261
+ "proper_mocking",
262
+ "test_organization",
263
+ "coverage_improvement",
264
+ "fixture_patterns",
265
+ ],
266
+ "validation_steps": [
267
+ "run_test_suite",
268
+ "verify_coverage_increase",
269
+ "check_test_reliability",
270
+ "validate_mock_usage",
271
+ ],
272
+ }
273
+
274
+ async def _consult_generic_agent(
275
+ self, issue: Issue, agent_name: str, context: dict[str, t.Any] | None = None
276
+ ) -> dict[str, t.Any]:
277
+ """Generic consultation for unspecified agents."""
278
+ return {
279
+ "recommendations": [
280
+ f"Consult {agent_name} documentation for specific guidance",
281
+ "Apply domain-specific best practices",
282
+ "Follow established patterns and conventions",
283
+ ],
284
+ "patterns": ["domain_specific_patterns"],
285
+ "validation_steps": ["validate_domain_requirements"],
286
+ }
287
+
288
+ def create_enhanced_fix_result(
289
+ self, base_result: FixResult, consultations: list[dict[str, t.Any]]
290
+ ) -> FixResult:
291
+ """Enhance a FixResult with external agent consultations."""
292
+ enhanced_result = FixResult(
293
+ success=base_result.success,
294
+ confidence=base_result.confidence,
295
+ fixes_applied=base_result.fixes_applied.copy(),
296
+ remaining_issues=base_result.remaining_issues.copy(),
297
+ recommendations=base_result.recommendations.copy(),
298
+ files_modified=base_result.files_modified.copy(),
299
+ )
300
+
301
+ # Aggregate recommendations from all consultations
302
+ for consultation in consultations:
303
+ if consultation.get("status") == "success":
304
+ agent_name = consultation.get("agent", "unknown")
305
+ enhanced_result.recommendations.extend(
306
+ [
307
+ f"[{agent_name}] {rec}"
308
+ for rec in consultation.get("recommendations", [])
309
+ ]
310
+ )
311
+
312
+ # Boost confidence if external agents provided guidance
313
+ external_confidence = consultation.get("confidence", 0.0)
314
+ enhanced_result.confidence = max(
315
+ enhanced_result.confidence,
316
+ (enhanced_result.confidence + external_confidence) / 2,
317
+ )
318
+
319
+ return enhanced_result
@@ -450,12 +450,15 @@ class AgentCoordinator:
450
450
 
451
451
  try:
452
452
  plan = await architect.plan_before_action(primary_issue)
453
- plan = self._enrich_architectural_plan(plan, all_issues)
453
+ # Ensure plan is properly typed as dict[str, Any]
454
+ if not isinstance(plan, dict):
455
+ plan = {"strategy": "default", "confidence": 0.5}
456
+ enriched_plan = self._enrich_architectural_plan(plan, all_issues)
454
457
 
455
458
  self.logger.info(
456
- f"Created architectural plan: {plan.get('strategy', 'unknown')}"
459
+ f"Created architectural plan: {enriched_plan.get('strategy', 'unknown')}"
457
460
  )
458
- return plan # type: ignore[no-any-return]
461
+ return enriched_plan
459
462
 
460
463
  except Exception as e:
461
464
  self.logger.exception(f"Failed to create architectural plan: {e}")