Initial commit
This commit is contained in:
302
skills/meta-automation-architect/scripts/agent_reuse.py
Normal file
302
skills/meta-automation-architect/scripts/agent_reuse.py
Normal file
@@ -0,0 +1,302 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Agent Reuse Manager
|
||||
Avoids regenerating automation for similar projects
|
||||
Reuses successful configurations
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from difflib import SequenceMatcher
|
||||
|
||||
class AgentReuseManager:
|
||||
"""Manages reuse of automation configurations"""
|
||||
|
||||
def __init__(self, storage_path: str = ".claude/meta-automation/configurations"):
|
||||
self.storage_dir = Path(storage_path)
|
||||
self.storage_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.index_path = self.storage_dir / "index.json"
|
||||
self.index = self._load_index()
|
||||
|
||||
def _load_index(self) -> Dict:
|
||||
"""Load configuration index"""
|
||||
if self.index_path.exists():
|
||||
try:
|
||||
with open(self.index_path, 'r') as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
return {'configurations': []}
|
||||
return {'configurations': []}
|
||||
|
||||
def _save_index(self):
|
||||
"""Save configuration index"""
|
||||
with open(self.index_path, 'w') as f:
|
||||
json.dump(self.index, f, indent=2)
|
||||
|
||||
def save_configuration(self, config: Dict) -> str:
|
||||
"""
|
||||
Save a successful automation configuration
|
||||
|
||||
Args:
|
||||
config: {
|
||||
'project_type': str,
|
||||
'project_name': str,
|
||||
'tech_stack': List[str],
|
||||
'agents_used': List[str],
|
||||
'skills_generated': List[str],
|
||||
'commands_generated': List[str],
|
||||
'hooks_generated': List[str],
|
||||
'success_metrics': Dict,
|
||||
'user_satisfaction': int (1-5)
|
||||
}
|
||||
|
||||
Returns:
|
||||
Configuration ID
|
||||
"""
|
||||
config_id = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
|
||||
# Add metadata
|
||||
config_with_meta = {
|
||||
**config,
|
||||
'config_id': config_id,
|
||||
'created_at': datetime.now().isoformat(),
|
||||
'reuse_count': 0
|
||||
}
|
||||
|
||||
# Save full configuration
|
||||
config_path = self.storage_dir / f"{config_id}.json"
|
||||
with open(config_path, 'w') as f:
|
||||
json.dump(config_with_meta, f, indent=2)
|
||||
|
||||
# Update index
|
||||
self.index['configurations'].append({
|
||||
'config_id': config_id,
|
||||
'project_type': config['project_type'],
|
||||
'project_name': config.get('project_name', 'unknown'),
|
||||
'tech_stack': config.get('tech_stack', []),
|
||||
'created_at': config_with_meta['created_at'],
|
||||
'reuse_count': 0
|
||||
})
|
||||
self._save_index()
|
||||
|
||||
return config_id
|
||||
|
||||
def find_similar_configurations(self, project_info: Dict, min_similarity: float = 0.7) -> List[Dict]:
|
||||
"""
|
||||
Find similar configurations that could be reused
|
||||
|
||||
Args:
|
||||
project_info: {
|
||||
'project_type': str,
|
||||
'tech_stack': List[str],
|
||||
'existing_tools': List[str]
|
||||
}
|
||||
min_similarity: Minimum similarity score (0-1)
|
||||
|
||||
Returns:
|
||||
List of similar configurations sorted by similarity
|
||||
"""
|
||||
similar = []
|
||||
|
||||
for config_ref in self.index['configurations']:
|
||||
config = self._load_configuration(config_ref['config_id'])
|
||||
if not config:
|
||||
continue
|
||||
|
||||
similarity = self._calculate_similarity(project_info, config)
|
||||
|
||||
if similarity >= min_similarity:
|
||||
similar.append({
|
||||
**config_ref,
|
||||
'similarity': round(similarity, 2),
|
||||
'full_config': config
|
||||
})
|
||||
|
||||
# Sort by similarity (descending)
|
||||
similar.sort(key=lambda x: x['similarity'], reverse=True)
|
||||
|
||||
return similar
|
||||
|
||||
def _calculate_similarity(self, project_info: Dict, config: Dict) -> float:
|
||||
"""
|
||||
Calculate similarity between project and configuration
|
||||
|
||||
Returns:
|
||||
Similarity score 0-1
|
||||
"""
|
||||
score = 0.0
|
||||
weights = {
|
||||
'project_type': 0.4,
|
||||
'tech_stack': 0.4,
|
||||
'size': 0.2
|
||||
}
|
||||
|
||||
# Project type match
|
||||
if project_info.get('project_type') == config.get('project_type'):
|
||||
score += weights['project_type']
|
||||
|
||||
# Tech stack similarity
|
||||
project_stack = set(project_info.get('tech_stack', []))
|
||||
config_stack = set(config.get('tech_stack', []))
|
||||
|
||||
if project_stack and config_stack:
|
||||
intersection = len(project_stack & config_stack)
|
||||
union = len(project_stack | config_stack)
|
||||
tech_similarity = intersection / union if union > 0 else 0
|
||||
score += weights['tech_stack'] * tech_similarity
|
||||
|
||||
return min(score, 1.0)
|
||||
|
||||
def reuse_configuration(self, config_id: str) -> Dict:
|
||||
"""
|
||||
Reuse a configuration
|
||||
|
||||
Args:
|
||||
config_id: ID of configuration to reuse
|
||||
|
||||
Returns:
|
||||
Configuration to apply
|
||||
"""
|
||||
config = self._load_configuration(config_id)
|
||||
if not config:
|
||||
return None
|
||||
|
||||
# Increment reuse count
|
||||
config['reuse_count'] += 1
|
||||
self._save_configuration(config_id, config)
|
||||
|
||||
# Update index
|
||||
for cfg in self.index['configurations']:
|
||||
if cfg['config_id'] == config_id:
|
||||
cfg['reuse_count'] += 1
|
||||
self._save_index()
|
||||
|
||||
return config
|
||||
|
||||
def get_reuse_recommendation(self, project_info: Dict) -> Optional[Dict]:
|
||||
"""
|
||||
Get recommendation for reusing a configuration
|
||||
|
||||
Args:
|
||||
project_info: Information about current project
|
||||
|
||||
Returns:
|
||||
Recommendation or None if no good match
|
||||
"""
|
||||
similar = self.find_similar_configurations(project_info, min_similarity=0.75)
|
||||
|
||||
if not similar:
|
||||
return None
|
||||
|
||||
best_match = similar[0]
|
||||
|
||||
return {
|
||||
'recommended': True,
|
||||
'config_id': best_match['config_id'],
|
||||
'similarity': best_match['similarity'],
|
||||
'project_name': best_match['project_name'],
|
||||
'created_at': best_match['created_at'],
|
||||
'reuse_count': best_match['reuse_count'],
|
||||
'time_saved': '5-10 minutes (no need to regenerate)',
|
||||
'agents': best_match['full_config']['agents_used'],
|
||||
'skills': best_match['full_config']['skills_generated'],
|
||||
'reason': f"This configuration was successful for a similar {best_match['project_type']} project"
|
||||
}
|
||||
|
||||
def _load_configuration(self, config_id: str) -> Optional[Dict]:
|
||||
"""Load a configuration file"""
|
||||
config_path = self.storage_dir / f"{config_id}.json"
|
||||
if not config_path.exists():
|
||||
return None
|
||||
|
||||
try:
|
||||
with open(config_path, 'r') as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
return None
|
||||
|
||||
def _save_configuration(self, config_id: str, config: Dict):
|
||||
"""Save a configuration file"""
|
||||
config_path = self.storage_dir / f"{config_id}.json"
|
||||
with open(config_path, 'w') as f:
|
||||
json.dump(config, f, indent=2)
|
||||
|
||||
def get_statistics(self) -> Dict:
|
||||
"""Get reuse statistics"""
|
||||
total_configs = len(self.index['configurations'])
|
||||
total_reuses = sum(cfg['reuse_count'] for cfg in self.index['configurations'])
|
||||
|
||||
project_types = {}
|
||||
for cfg in self.index['configurations']:
|
||||
ptype = cfg['project_type']
|
||||
if ptype not in project_types:
|
||||
project_types[ptype] = 0
|
||||
project_types[ptype] += 1
|
||||
|
||||
return {
|
||||
'total_configurations': total_configs,
|
||||
'total_reuses': total_reuses,
|
||||
'average_reuses': round(total_reuses / total_configs, 1) if total_configs > 0 else 0,
|
||||
'project_types': project_types,
|
||||
'most_reused': sorted(
|
||||
self.index['configurations'],
|
||||
key=lambda x: x['reuse_count'],
|
||||
reverse=True
|
||||
)[:3]
|
||||
}
|
||||
|
||||
# Example usage
|
||||
if __name__ == '__main__':
|
||||
manager = AgentReuseManager()
|
||||
|
||||
# Save a configuration
|
||||
print("Saving successful configuration...")
|
||||
config_id = manager.save_configuration({
|
||||
'project_type': 'programming',
|
||||
'project_name': 'my-web-app',
|
||||
'tech_stack': ['TypeScript', 'React', 'Next.js'],
|
||||
'agents_used': ['project-analyzer', 'security-analyzer', 'test-coverage-analyzer'],
|
||||
'skills_generated': ['security-scanner', 'test-generator'],
|
||||
'commands_generated': ['/security-check', '/generate-tests'],
|
||||
'hooks_generated': ['pre-commit-security'],
|
||||
'success_metrics': {
|
||||
'time_saved': 50,
|
||||
'issues_prevented': 3
|
||||
},
|
||||
'user_satisfaction': 5
|
||||
})
|
||||
|
||||
print(f"Saved configuration: {config_id}\n")
|
||||
|
||||
# Find similar
|
||||
print("Finding similar configurations for new project...")
|
||||
similar = manager.find_similar_configurations({
|
||||
'project_type': 'programming',
|
||||
'tech_stack': ['TypeScript', 'React', 'Vite'], # Similar but not exact
|
||||
'existing_tools': ['ESLint']
|
||||
})
|
||||
|
||||
print(f"Found {len(similar)} similar configurations\n")
|
||||
|
||||
if similar:
|
||||
print("Best match:")
|
||||
print(json.dumps({
|
||||
'config_id': similar[0]['config_id'],
|
||||
'similarity': similar[0]['similarity'],
|
||||
'project_name': similar[0]['project_name']
|
||||
}, indent=2))
|
||||
|
||||
# Get recommendation
|
||||
print("\nRecommendation:")
|
||||
rec = manager.get_reuse_recommendation({
|
||||
'project_type': 'programming',
|
||||
'tech_stack': ['TypeScript', 'React', 'Vite']
|
||||
})
|
||||
print(json.dumps(rec, indent=2))
|
||||
|
||||
# Statistics
|
||||
print("\nReuse Statistics:")
|
||||
stats = manager.get_statistics()
|
||||
print(json.dumps(stats, indent=2))
|
||||
Reference in New Issue
Block a user