Modernized build tooling
This commit is contained in:
@@ -0,0 +1,376 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Claude Code Subagent Management System
|
||||
|
||||
This script provides comprehensive management for Claude Code subagents,
|
||||
including initialization, coordination, and workflow execution.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SubagentStatus(Enum):
|
||||
AVAILABLE = "available"
|
||||
BUSY = "busy"
|
||||
ERROR = "error"
|
||||
OFFLINE = "offline"
|
||||
|
||||
|
||||
@dataclass
|
||||
class SubagentInstance:
|
||||
name: str
|
||||
config: dict[str, Any]
|
||||
status: SubagentStatus = SubagentStatus.AVAILABLE
|
||||
current_task: str | None = None
|
||||
load_factor: float = 0.0
|
||||
|
||||
|
||||
class SubagentManager:
|
||||
"""Advanced subagent management and coordination system"""
|
||||
|
||||
def __init__(self, registry_path: str = ".claude-code/subagents/registry.json"):
|
||||
self.registry_path = Path(registry_path)
|
||||
self.subagents: dict[str, SubagentInstance] = {}
|
||||
self.collaboration_patterns: dict[str, list[str]] = {}
|
||||
self.active_workflows: dict[str, dict] = {}
|
||||
|
||||
self._load_registry()
|
||||
self._initialize_subagents()
|
||||
|
||||
def _load_registry(self):
|
||||
"""Load subagent registry configuration"""
|
||||
try:
|
||||
with self.registry_path.open() as f:
|
||||
self.registry = json.load(f)
|
||||
|
||||
self.collaboration_patterns = self.registry.get("interaction_patterns", {})
|
||||
logger.info(f"Loaded registry with {len(self.registry.get('subagents', {}))} subagents")
|
||||
|
||||
except FileNotFoundError:
|
||||
logger.error(f"Registry file not found: {self.registry_path}")
|
||||
self.registry = {"subagents": {}}
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"Invalid JSON in registry: {e}")
|
||||
self.registry = {"subagents": {}}
|
||||
|
||||
def _initialize_subagents(self):
|
||||
"""Initialize all subagents from registry"""
|
||||
for _category, subagents in self.registry.get("subagents", {}).items():
|
||||
for name, config in subagents.items():
|
||||
try:
|
||||
subagent_config = self._load_subagent_config(config["file"])
|
||||
self.subagents[name] = SubagentInstance(name=name, config=subagent_config)
|
||||
logger.info(f"Initialized subagent: {name}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize subagent {name}: {e}")
|
||||
|
||||
def _load_subagent_config(self, config_file: str) -> dict[str, Any]:
|
||||
"""Load individual subagent configuration"""
|
||||
config_path = self.registry_path.parent / config_file
|
||||
|
||||
try:
|
||||
with config_path.open() as f:
|
||||
return json.load(f)
|
||||
except FileNotFoundError:
|
||||
logger.warning(f"Config file not found: {config_path}")
|
||||
return {}
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"Invalid JSON in config {config_path}: {e}")
|
||||
return {}
|
||||
|
||||
def get_subagent_capabilities(self, subagent_name: str) -> list[str]:
|
||||
"""Get capabilities of a specific subagent"""
|
||||
if subagent_name in self.subagents:
|
||||
return self.subagents[subagent_name].config.get("capabilities", [])
|
||||
return []
|
||||
|
||||
def find_subagents_by_capability(self, capability: str) -> list[str]:
|
||||
"""Find all subagents with a specific capability"""
|
||||
matching_subagents = []
|
||||
for name, instance in self.subagents.items():
|
||||
if capability in instance.config.get("capabilities", []):
|
||||
matching_subagents.append(name)
|
||||
return matching_subagents
|
||||
|
||||
def get_collaboration_pattern(self, pattern_name: str) -> list[str]:
|
||||
"""Get predefined collaboration pattern"""
|
||||
return self.collaboration_patterns.get(pattern_name, [])
|
||||
|
||||
def analyze_task_requirements(self, task_description: str) -> dict[str, Any]:
|
||||
"""Analyze task and determine required capabilities and subagents"""
|
||||
# This would use NLP/ML in a real implementation
|
||||
# For now, provide a rule-based analysis
|
||||
|
||||
capabilities_needed = []
|
||||
priority_subagents = []
|
||||
|
||||
# Code quality tasks
|
||||
if any(keyword in task_description.lower() for keyword in ["lint", "format", "quality", "ruff", "type"]):
|
||||
capabilities_needed.extend(["static-code-analysis", "type-checking"])
|
||||
priority_subagents.append("python-quality-analyst")
|
||||
|
||||
# Testing tasks
|
||||
if any(keyword in task_description.lower() for keyword in ["test", "bdd", "behave", "coverage"]):
|
||||
capabilities_needed.extend(["bdd-scenario-design", "test-execution"])
|
||||
priority_subagents.extend(["test-architect", "test-executor"])
|
||||
|
||||
# Security tasks
|
||||
if any(keyword in task_description.lower() for keyword in ["security", "vulnerability", "scan", "audit"]):
|
||||
capabilities_needed.extend(["security-scanning", "vulnerability-assessment"])
|
||||
priority_subagents.append("security-auditor")
|
||||
|
||||
# Performance tasks
|
||||
if any(keyword in task_description.lower() for keyword in ["performance", "optimize", "profile", "benchmark"]):
|
||||
capabilities_needed.extend(["performance-profiling", "optimization"])
|
||||
priority_subagents.append("performance-optimizer")
|
||||
|
||||
# Container/deployment tasks
|
||||
if any(keyword in task_description.lower() for keyword in ["docker", "container", "deploy", "kubernetes"]):
|
||||
capabilities_needed.extend(["container-design", "deployment"])
|
||||
priority_subagents.extend(["container-architect", "kubernetes-specialist"])
|
||||
|
||||
return {
|
||||
"capabilities_needed": capabilities_needed,
|
||||
"priority_subagents": priority_subagents,
|
||||
"complexity": self._assess_task_complexity(task_description),
|
||||
"estimated_duration": self._estimate_task_duration(task_description),
|
||||
}
|
||||
|
||||
def _assess_task_complexity(self, task_description: str) -> str:
|
||||
"""Assess task complexity based on description"""
|
||||
complexity_indicators = {
|
||||
"simple": ["fix", "update", "change"],
|
||||
"medium": ["implement", "create", "design", "optimize"],
|
||||
"complex": ["architect", "integrate", "migrate", "refactor"],
|
||||
"very_complex": ["orchestrate", "coordinate", "comprehensive"],
|
||||
}
|
||||
|
||||
task_lower = task_description.lower()
|
||||
for complexity, indicators in complexity_indicators.items():
|
||||
if any(indicator in task_lower for indicator in indicators):
|
||||
return complexity
|
||||
|
||||
return "medium" # default
|
||||
|
||||
def _estimate_task_duration(self, task_description: str) -> str:
|
||||
"""Estimate task duration based on complexity and scope"""
|
||||
task_lower = task_description.lower()
|
||||
|
||||
if any(keyword in task_lower for keyword in ["quick", "simple", "minor"]):
|
||||
return "short" # < 30 minutes
|
||||
elif any(keyword in task_lower for keyword in ["comprehensive", "complete", "full"]):
|
||||
return "long" # > 2 hours
|
||||
else:
|
||||
return "medium" # 30 minutes - 2 hours
|
||||
|
||||
async def execute_workflow(self, workflow_name: str, context: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Execute a predefined workflow pattern"""
|
||||
if workflow_name not in self.collaboration_patterns:
|
||||
raise ValueError(f"Unknown workflow: {workflow_name}")
|
||||
|
||||
workflow_id = f"{workflow_name}_{asyncio.get_event_loop().time()}"
|
||||
self.active_workflows[workflow_id] = {
|
||||
"name": workflow_name,
|
||||
"status": "running",
|
||||
"context": context,
|
||||
"start_time": asyncio.get_event_loop().time(),
|
||||
"subagents": self.collaboration_patterns[workflow_name],
|
||||
"results": {},
|
||||
}
|
||||
|
||||
try:
|
||||
results = await self._execute_workflow_steps(workflow_id)
|
||||
self.active_workflows[workflow_id]["status"] = "completed"
|
||||
self.active_workflows[workflow_id]["results"] = results
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
self.active_workflows[workflow_id]["status"] = "failed"
|
||||
self.active_workflows[workflow_id]["error"] = str(e)
|
||||
logger.error(f"Workflow {workflow_name} failed: {e}")
|
||||
raise
|
||||
|
||||
async def _execute_workflow_steps(self, workflow_id: str) -> dict[str, Any]:
|
||||
"""Execute workflow steps with proper coordination"""
|
||||
workflow = self.active_workflows[workflow_id]
|
||||
subagent_names = workflow["subagents"]
|
||||
context = workflow["context"]
|
||||
|
||||
results = {}
|
||||
|
||||
# For now, execute sequentially - in real implementation,
|
||||
# this would use intelligent parallel execution
|
||||
for subagent_name in subagent_names:
|
||||
if subagent_name in self.subagents:
|
||||
subagent = self.subagents[subagent_name]
|
||||
|
||||
# Update subagent status
|
||||
subagent.status = SubagentStatus.BUSY
|
||||
subagent.current_task = workflow_id
|
||||
|
||||
try:
|
||||
# Simulate subagent execution
|
||||
result = await self._simulate_subagent_execution(subagent_name, context)
|
||||
results[subagent_name] = result
|
||||
|
||||
# Update context with results for next subagent
|
||||
context.update({f"{subagent_name}_result": result})
|
||||
|
||||
finally:
|
||||
# Reset subagent status
|
||||
subagent.status = SubagentStatus.AVAILABLE
|
||||
subagent.current_task = None
|
||||
|
||||
return results
|
||||
|
||||
async def _simulate_subagent_execution(self, subagent_name: str, _context: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Simulate subagent execution (placeholder for actual implementation)"""
|
||||
subagent = self.subagents[subagent_name]
|
||||
|
||||
# Simulate processing time based on subagent complexity
|
||||
processing_time = len(subagent.config.get("capabilities", [])) * 0.5
|
||||
await asyncio.sleep(processing_time)
|
||||
|
||||
return {
|
||||
"status": "completed",
|
||||
"subagent": subagent_name,
|
||||
"capabilities_used": subagent.config.get("capabilities", []),
|
||||
"processing_time": processing_time,
|
||||
"recommendations": f"Recommendations from {subagent_name}",
|
||||
"artifacts": [f"artifact_{subagent_name}.json"],
|
||||
}
|
||||
|
||||
def get_system_status(self) -> dict[str, Any]:
|
||||
"""Get comprehensive system status"""
|
||||
status_summary = {
|
||||
"total_subagents": len(self.subagents),
|
||||
"available_subagents": sum(1 for s in self.subagents.values() if s.status == SubagentStatus.AVAILABLE),
|
||||
"busy_subagents": sum(1 for s in self.subagents.values() if s.status == SubagentStatus.BUSY),
|
||||
"active_workflows": len([w for w in self.active_workflows.values() if w["status"] == "running"]),
|
||||
"subagent_details": {},
|
||||
}
|
||||
|
||||
for name, instance in self.subagents.items():
|
||||
status_summary["subagent_details"][name] = {
|
||||
"status": instance.status.value,
|
||||
"current_task": instance.current_task,
|
||||
"capabilities": len(instance.config.get("capabilities", [])),
|
||||
"load_factor": instance.load_factor,
|
||||
}
|
||||
|
||||
return status_summary
|
||||
|
||||
def get_available_workflows(self) -> list[str]:
|
||||
"""Get list of available workflow patterns"""
|
||||
return list(self.collaboration_patterns.keys())
|
||||
|
||||
def recommend_subagents(self, task_description: str) -> dict[str, Any]:
|
||||
"""Recommend optimal subagents for a given task"""
|
||||
analysis = self.analyze_task_requirements(task_description)
|
||||
|
||||
# Find subagents with required capabilities
|
||||
recommended_subagents = []
|
||||
for capability in analysis["capabilities_needed"]:
|
||||
capable_subagents = self.find_subagents_by_capability(capability)
|
||||
recommended_subagents.extend(capable_subagents)
|
||||
|
||||
# Remove duplicates and prioritize
|
||||
recommended_subagents = list(set(recommended_subagents))
|
||||
|
||||
# Add priority subagents
|
||||
for priority_subagent in analysis["priority_subagents"]:
|
||||
if priority_subagent not in recommended_subagents:
|
||||
recommended_subagents.append(priority_subagent)
|
||||
|
||||
# Check availability
|
||||
available_subagents = [
|
||||
name
|
||||
for name in recommended_subagents
|
||||
if name in self.subagents and self.subagents[name].status == SubagentStatus.AVAILABLE
|
||||
]
|
||||
|
||||
return {
|
||||
"task_analysis": analysis,
|
||||
"recommended_subagents": recommended_subagents,
|
||||
"available_subagents": available_subagents,
|
||||
"coordination_recommendation": self._recommend_coordination_pattern(recommended_subagents),
|
||||
}
|
||||
|
||||
def _recommend_coordination_pattern(self, subagents: list[str]) -> dict[str, Any]:
|
||||
"""Recommend coordination pattern based on subagent combination"""
|
||||
# Find matching workflow patterns
|
||||
matching_patterns = []
|
||||
for pattern_name, pattern_subagents in self.collaboration_patterns.items():
|
||||
overlap = set(subagents) & set(pattern_subagents)
|
||||
if overlap:
|
||||
matching_patterns.append(
|
||||
{
|
||||
"pattern": pattern_name,
|
||||
"overlap_count": len(overlap),
|
||||
"coverage": len(overlap) / len(set(subagents) | set(pattern_subagents)),
|
||||
}
|
||||
)
|
||||
|
||||
# Sort by coverage
|
||||
matching_patterns.sort(key=lambda x: x["coverage"], reverse=True)
|
||||
|
||||
return {
|
||||
"recommended_pattern": matching_patterns[0]["pattern"] if matching_patterns else None,
|
||||
"pattern_options": matching_patterns,
|
||||
"custom_coordination_needed": len(matching_patterns) == 0,
|
||||
}
|
||||
|
||||
|
||||
# CLI Interface
|
||||
def main():
|
||||
"""Command-line interface for subagent management"""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Claude Code Subagent Manager")
|
||||
parser.add_argument("--status", action="store_true", help="Show system status")
|
||||
parser.add_argument("--workflows", action="store_true", help="List available workflows")
|
||||
parser.add_argument("--recommend", type=str, help="Recommend subagents for task")
|
||||
parser.add_argument("--execute", type=str, help="Execute workflow")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
manager = SubagentManager()
|
||||
|
||||
if args.status:
|
||||
status = manager.get_system_status()
|
||||
print(json.dumps(status, indent=2))
|
||||
|
||||
elif args.workflows:
|
||||
workflows = manager.get_available_workflows()
|
||||
print("Available workflows:")
|
||||
for workflow in workflows:
|
||||
print(f" - {workflow}")
|
||||
|
||||
elif args.recommend:
|
||||
recommendations = manager.recommend_subagents(args.recommend)
|
||||
print(json.dumps(recommendations, indent=2))
|
||||
|
||||
elif args.execute:
|
||||
|
||||
async def run_workflow():
|
||||
result = await manager.execute_workflow(args.execute, {})
|
||||
print(json.dumps(result, indent=2))
|
||||
|
||||
asyncio.run(run_workflow())
|
||||
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user