Features: - 30+ Custom Skills (cognitive, development, UI/UX, autonomous agents) - RalphLoop autonomous agent integration - Multi-AI consultation (Qwen) - Agent management system with sync capabilities - Custom hooks for session management - MCP servers integration - Plugin marketplace setup - Comprehensive installation script Components: - Skills: always-use-superpowers, ralph, brainstorming, ui-ux-pro-max, etc. - Agents: 100+ agents across engineering, marketing, product, etc. - Hooks: session-start-superpowers, qwen-consult, ralph-auto-trigger - Commands: /brainstorm, /write-plan, /execute-plan - MCP Servers: zai-mcp-server, web-search-prime, web-reader, zread - Binaries: ralphloop wrapper Installation: ./supercharge.sh
351 lines
10 KiB
Python
351 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Ralph Integration for Agent Pipeline Builder
|
|
|
|
Generates pipeline manifests for Ralph Orchestrator to autonomously build and test multi-agent pipelines.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
from typing import Optional, Dict, Any, List
|
|
|
|
# Configuration
|
|
RALPHLOOP_CMD = Path(__file__).parent.parent.parent.parent / "obsidian-web-interface" / "bin" / "ralphloop"
|
|
PIPELINE_THRESHOLD = 3 # Minimum number of stages to trigger Ralph
|
|
|
|
|
|
def analyze_pipeline_complexity(stages: List[Dict[str, str]]) -> int:
|
|
"""
|
|
Analyze pipeline complexity and return estimated difficulty.
|
|
|
|
Returns: 1-10 scale
|
|
"""
|
|
complexity = len(stages) # Base: one point per stage
|
|
|
|
# Check for complex patterns
|
|
for stage in stages:
|
|
description = stage.get("description", "").lower()
|
|
|
|
# External data sources (+1)
|
|
if any(word in description for word in ["fetch", "api", "database", "web", "search"]):
|
|
complexity += 1
|
|
|
|
# Complex processing (+1)
|
|
if any(word in description for word in ["analyze", "transform", "aggregate", "compute"]):
|
|
complexity += 1
|
|
|
|
# Conditional logic (+1)
|
|
if any(word in description for word in ["filter", "validate", "check", "select"]):
|
|
complexity += 1
|
|
|
|
# Parallel stages add complexity
|
|
stage_names = [s.get("name", "") for s in stages]
|
|
if "parallel" in str(stage_names).lower():
|
|
complexity += 2
|
|
|
|
return min(10, complexity)
|
|
|
|
|
|
def create_pipeline_manifest(stages: List[Dict[str, str]], manifest_path: str = ".ralph/PIPELINE.md") -> str:
|
|
"""
|
|
Create a Ralph-formatted pipeline manifest.
|
|
|
|
Returns the path to the created manifest file.
|
|
"""
|
|
ralph_dir = Path(".ralph")
|
|
ralph_dir.mkdir(exist_ok=True)
|
|
|
|
manifest_file = ralph_dir / "PIPELINE.md"
|
|
|
|
# Format the pipeline for Ralph
|
|
manifest_content = f"""# Pipeline: Multi-Agent Workflow
|
|
|
|
## Stages
|
|
|
|
"""
|
|
for i, stage in enumerate(stages, 1):
|
|
manifest_content += f"{i}. **{stage['name']}** - {stage['description']}\n"
|
|
|
|
manifest_content += f"""
|
|
## Data Format
|
|
|
|
All stages use JSON with markers: `<<<stage-name>>>...<<<end-stage-name>>>`
|
|
|
|
## Task
|
|
|
|
Build a complete multi-agent pipeline with the following stages:
|
|
|
|
"""
|
|
for stage in stages:
|
|
manifest_content += f"""
|
|
### {stage['name']}
|
|
|
|
**Purpose:** {stage['description']}
|
|
|
|
**Agent Configuration:**
|
|
- Model: {stage.get('model', 'sonnet')}
|
|
- Allowed Tools: {', '.join(stage.get('tools', ['Read', 'Write', 'Bash']))}
|
|
|
|
**Output Format:**
|
|
<<<{stage['name']}>>>
|
|
```json
|
|
{{
|
|
"result": "...",
|
|
"metadata": {{...}}
|
|
}}
|
|
```
|
|
<<<end-{stage['name']}>>>
|
|
|
|
"""
|
|
|
|
manifest_content += """
|
|
## Success Criteria
|
|
|
|
The pipeline is complete when:
|
|
- [ ] All agent definitions are created in `.claude/agents/`
|
|
- [ ] Pipeline orchestration script is implemented
|
|
- [ ] Each stage is tested independently
|
|
- [ ] End-to-end pipeline test passes
|
|
- [ ] Error handling is verified
|
|
- [ ] Documentation is complete
|
|
|
|
## Instructions
|
|
|
|
1. Create agent definition files for each stage
|
|
2. Implement the pipeline orchestration script
|
|
3. Test each stage independently with mock data
|
|
4. Run the full end-to-end pipeline
|
|
5. Verify error handling and edge cases
|
|
6. Document usage and testing procedures
|
|
|
|
When complete, add <!-- COMPLETE --> marker to this file.
|
|
Output the final pipeline to `.ralph/iterations/pipeline.md`.
|
|
"""
|
|
|
|
manifest_file.write_text(manifest_content)
|
|
|
|
return str(manifest_file)
|
|
|
|
|
|
def should_use_ralph(stages: List[Dict[str, str]]) -> bool:
|
|
"""
|
|
Determine if pipeline is complex enough to warrant RalphLoop.
|
|
"""
|
|
# Check for explicit opt-in via environment
|
|
if os.getenv("RALPH_AUTO", "").lower() in ("true", "1", "yes"):
|
|
return True
|
|
|
|
if os.getenv("PIPELINE_USE_RALPH", "").lower() in ("true", "1", "yes"):
|
|
return True
|
|
|
|
# Check stage count
|
|
if len(stages) >= PIPELINE_THRESHOLD:
|
|
return True
|
|
|
|
# Check complexity
|
|
complexity = analyze_pipeline_complexity(stages)
|
|
return complexity >= 5
|
|
|
|
|
|
def run_ralphloop_for_pipeline(stages: List[Dict[str, str]],
|
|
pipeline_name: str = "multi-agent-pipeline",
|
|
max_iterations: Optional[int] = None) -> Dict[str, Any]:
|
|
"""
|
|
Run RalphLoop for autonomous pipeline construction.
|
|
|
|
Returns a dict with:
|
|
- success: bool
|
|
- iterations: int
|
|
- pipeline_path: str (path to generated pipeline)
|
|
- state: dict (Ralph's final state)
|
|
- error: str (if failed)
|
|
"""
|
|
print("🔄 Delegating to RalphLoop 'Tackle Until Solved' for autonomous pipeline construction...")
|
|
print(f" Stages: {len(stages)}")
|
|
print(f" Complexity: {analyze_pipeline_complexity(stages)}/10")
|
|
print()
|
|
|
|
# Create pipeline manifest
|
|
manifest_path = create_pipeline_manifest(stages)
|
|
print(f"✅ Pipeline manifest created: {manifest_path}")
|
|
print()
|
|
|
|
# Check if ralphloop exists
|
|
if not RALPHLOOP_CMD.exists():
|
|
return {
|
|
"success": False,
|
|
"error": f"RalphLoop not found at {RALPHLOOP_CMD}",
|
|
"iterations": 0,
|
|
"pipeline_path": "",
|
|
"state": {}
|
|
}
|
|
|
|
# Build command - use the manifest file as input
|
|
cmd = [str(RALPHLOOP_CMD), "-i", manifest_path]
|
|
|
|
# Add optional parameters
|
|
if max_iterations:
|
|
cmd.extend(["--max-iterations", str(max_iterations)])
|
|
|
|
# Environment variables
|
|
env = os.environ.copy()
|
|
env.setdefault("RALPH_AGENT", "claude")
|
|
env.setdefault("RALPH_MAX_ITERATIONS", str(max_iterations or 100))
|
|
|
|
print(f"Command: {' '.join(cmd)}")
|
|
print("=" * 60)
|
|
print()
|
|
|
|
# Run RalphLoop
|
|
try:
|
|
process = subprocess.Popen(
|
|
cmd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
text=True,
|
|
bufsize=1,
|
|
env=env
|
|
)
|
|
|
|
# Stream output
|
|
output_lines = []
|
|
for line in process.stdout:
|
|
print(line, end='', flush=True)
|
|
output_lines.append(line)
|
|
|
|
process.wait()
|
|
returncode = process.returncode
|
|
|
|
print()
|
|
print("=" * 60)
|
|
|
|
if returncode == 0:
|
|
# Read final state
|
|
state_file = Path(".ralph/state.json")
|
|
pipeline_file = Path(".ralph/iterations/pipeline.md")
|
|
|
|
state = {}
|
|
if state_file.exists():
|
|
state = json.loads(state_file.read_text())
|
|
|
|
pipeline_path = ""
|
|
if pipeline_file.exists():
|
|
pipeline_path = str(pipeline_file)
|
|
|
|
iterations = state.get("iteration", 0)
|
|
|
|
print(f"✅ Pipeline construction completed in {iterations} iterations")
|
|
if pipeline_path:
|
|
print(f" Pipeline: {pipeline_path}")
|
|
print()
|
|
|
|
return {
|
|
"success": True,
|
|
"iterations": iterations,
|
|
"pipeline_path": pipeline_path,
|
|
"state": state,
|
|
"error": None
|
|
}
|
|
else:
|
|
return {
|
|
"success": False,
|
|
"error": f"RalphLoop exited with code {returncode}",
|
|
"iterations": 0,
|
|
"pipeline_path": "",
|
|
"state": {}
|
|
}
|
|
|
|
except KeyboardInterrupt:
|
|
print()
|
|
print("⚠️ RalphLoop interrupted by user")
|
|
return {
|
|
"success": False,
|
|
"error": "Interrupted by user",
|
|
"iterations": 0,
|
|
"pipeline_path": "",
|
|
"state": {}
|
|
}
|
|
except Exception as e:
|
|
return {
|
|
"success": False,
|
|
"error": str(e),
|
|
"iterations": 0,
|
|
"pipeline_path": "",
|
|
"state": {}
|
|
}
|
|
|
|
|
|
def delegate_pipeline_to_ralph(stages: List[Dict[str, str]],
|
|
pipeline_name: str = "multi-agent-pipeline") -> Optional[str]:
|
|
"""
|
|
Main entry point: Delegate pipeline construction to Ralph if complex.
|
|
|
|
If Ralph is used, returns the path to the generated pipeline.
|
|
If pipeline is simple, returns None (caller should build directly).
|
|
"""
|
|
if not should_use_ralph(stages):
|
|
return None
|
|
|
|
result = run_ralphloop_for_pipeline(stages, pipeline_name)
|
|
|
|
if result["success"]:
|
|
return result.get("pipeline_path", "")
|
|
else:
|
|
print(f"❌ RalphLoop failed: {result.get('error', 'Unknown error')}")
|
|
print("Falling back to direct pipeline construction...")
|
|
return None
|
|
|
|
|
|
# Example pipeline stages for testing
|
|
EXAMPLE_PIPELINE = [
|
|
{
|
|
"name": "researcher",
|
|
"description": "Finds and fetches raw data from various sources",
|
|
"model": "haiku",
|
|
"tools": ["WebSearch", "WebFetch", "Read"]
|
|
},
|
|
{
|
|
"name": "analyzer",
|
|
"description": "Processes data and selects best options",
|
|
"model": "sonnet",
|
|
"tools": ["Read", "Write", "Bash"]
|
|
},
|
|
{
|
|
"name": "writer",
|
|
"description": "Creates final output from analyzed data",
|
|
"model": "sonnet",
|
|
"tools": ["Write", "Edit"]
|
|
}
|
|
]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description="Test Ralph pipeline integration")
|
|
parser.add_argument("--test-complexity", action="store_true", help="Only test complexity")
|
|
parser.add_argument("--force", action="store_true", help="Force Ralph mode")
|
|
parser.add_argument("--example", action="store_true", help="Run with example pipeline")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.test_complexity:
|
|
complexity = analyze_pipeline_complexity(EXAMPLE_PIPELINE)
|
|
print(f"Pipeline complexity: {complexity}/10")
|
|
print(f"Should use Ralph: {should_use_ralph(EXAMPLE_PIPELINE)}")
|
|
elif args.example:
|
|
if args.force:
|
|
os.environ["PIPELINE_USE_RALPH"] = "true"
|
|
|
|
result = delegate_pipeline_to_ralph(EXAMPLE_PIPELINE, "example-pipeline")
|
|
|
|
if result:
|
|
print("\n" + "=" * 60)
|
|
print(f"PIPELINE GENERATED: {result}")
|
|
print("=" * 60)
|
|
else:
|
|
print("\nPipeline not complex enough for Ralph. Building directly...")
|