Based on claude-code-tools TmuxCLIController, this refactor: - Added DockerTmuxController class for robust tmux session management - Implements send_keys() with configurable delay_enter - Implements capture_pane() for output retrieval - Implements wait_for_prompt() for pattern-based completion detection - Implements wait_for_idle() for content-hash-based idle detection - Implements wait_for_shell_prompt() for shell prompt detection Also includes workflow improvements: - Pre-task git snapshot before agent execution - Post-task commit protocol in agent guidelines Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
199 lines
6.7 KiB
Python
Executable File
199 lines
6.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Luzia Flow Orchestrator - Main Entry Point
|
|
|
|
Coordinates:
|
|
1. Ingestion (receive tasks)
|
|
2. Analysis (research agent smart filters)
|
|
3. Approval (governance gate)
|
|
4. Execution (task dispatch)
|
|
5. Consolidation (knowledge harvesting)
|
|
6. Closure (results & insights)
|
|
"""
|
|
|
|
import sys
|
|
import json
|
|
import time
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, '/opt/server-agents/orchestrator/lib')
|
|
|
|
from luzia_unified_flow import LuziaUnifiedFlow, TaskSource, FlowState
|
|
from research_agent import LuziaResearchAgent
|
|
|
|
|
|
class LuziaFlowOrchestrator:
|
|
"""Main orchestrator coordinating all flow phases"""
|
|
|
|
def __init__(self):
|
|
self.flow = LuziaUnifiedFlow()
|
|
self.research_agent = LuziaResearchAgent()
|
|
|
|
def process_task(self, description: str, source: str = "user", submitter: str = "admin", tags: list = None) -> dict:
|
|
"""
|
|
Process a task through the complete Luzia flow.
|
|
|
|
Phase 1: Ingestion
|
|
Phase 2: Analysis (security/speed/complexity)
|
|
Phase 3: Approval (governance gate)
|
|
Phase 4: Execution (assign to projects)
|
|
Phase 5: Consolidation (knowledge harvesting)
|
|
Phase 6: Closure (results & insights)
|
|
"""
|
|
|
|
# Phase 1: Receive Task
|
|
source_enum = TaskSource[source.upper()] if source.upper() in TaskSource.__members__ else TaskSource.USER_SUBMISSION
|
|
task_id = self.flow.receive_task(description, source_enum, submitter, tags)
|
|
|
|
if not task_id:
|
|
return {'status': 'failed', 'error': 'Could not receive task'}
|
|
|
|
# Phase 2: Analyze Task
|
|
print(f"\n📊 ANALYZING: {description[:60]}...")
|
|
analysis = self.research_agent.analyze_task(description)
|
|
|
|
# Determine if approval needed
|
|
analysis['requires_approval'] = analysis.get('security') in ['sensitive', 'critical']
|
|
|
|
self.flow.analyze_task(task_id, analysis)
|
|
|
|
# Phase 3: Governance Gate
|
|
if analysis.get('requires_approval'):
|
|
print(f"\n🔒 AWAITING APPROVAL: Task classified as {analysis.get('security')} security")
|
|
print(f" Reason: {analysis.get('reasoning')}")
|
|
# In real system, this would trigger Telegram alert
|
|
# For now, we auto-approve for demo
|
|
self.flow.approve_task(task_id, 'luzia_auto', 'Auto-approved by flow')
|
|
else:
|
|
print(f"\n✅ AUTO-APPROVED: Task routed to {analysis.get('recommended_tool')}")
|
|
self.flow.approve_task(task_id, 'luzia_auto', 'Routine task')
|
|
|
|
# Phase 4: Strategic Execution
|
|
print(f"\n🚀 EXECUTING: Assigning to projects...")
|
|
# Route to appropriate projects based on tool recommendation
|
|
projects = self._get_projects_for_tool(analysis.get('recommended_tool'))
|
|
self.flow.assign_projects(task_id, projects)
|
|
|
|
# Phase 5: Consolidation (simulated)
|
|
print(f"\n📥 CONSOLIDATING: Extracting findings to research KG...")
|
|
results = {
|
|
'analysis': analysis,
|
|
'tool_used': analysis.get('recommended_tool'),
|
|
'projects': projects,
|
|
'status': 'completed'
|
|
}
|
|
self.flow.consolidate_results(task_id, results)
|
|
|
|
# Phase 6: Closure
|
|
print(f"\n✨ RESOLVED: Task complete")
|
|
self.flow.resolve_task(task_id)
|
|
|
|
# Get final status
|
|
status = self.flow.get_task_status(task_id)
|
|
|
|
return {
|
|
'task_id': task_id,
|
|
'status': 'completed',
|
|
'analysis': analysis,
|
|
'final_state': status.get('state'),
|
|
}
|
|
|
|
def _get_projects_for_tool(self, tool: str) -> list:
|
|
"""Map Zen tool to projects that can execute it"""
|
|
mapping = {
|
|
'chat': ['librechat'],
|
|
'debug': ['admin', 'dss'],
|
|
'thinkdeep': ['librechat', 'overbits'],
|
|
'codereview': ['dss', 'overbits'],
|
|
'consensus': ['librechat', 'overbits'],
|
|
'planner': ['overbits'],
|
|
}
|
|
return mapping.get(tool, ['admin'])
|
|
|
|
def get_flow_dashboard(self) -> dict:
|
|
"""Get dashboard view of all tasks in flow"""
|
|
return {
|
|
'timestamp': time.time(),
|
|
'flow_status': self.flow.get_flow_status(),
|
|
}
|
|
|
|
|
|
def main():
|
|
"""CLI interface"""
|
|
orchestrator = LuziaFlowOrchestrator()
|
|
|
|
if len(sys.argv) > 1:
|
|
if sys.argv[1] == '--demo':
|
|
# Demo flow
|
|
demo_tasks = [
|
|
("quick answer: what is OAuth?", "user", "admin"),
|
|
("urgent critical vulnerability in authentication", "user", "admin"),
|
|
("research distributed caching approaches", "user", "admin"),
|
|
]
|
|
|
|
print("\n" + "=" * 80)
|
|
print("🔬 LUZIA UNIFIED FLOW - DEMONSTRATION")
|
|
print("=" * 80)
|
|
|
|
for description, source, submitter in demo_tasks:
|
|
result = orchestrator.process_task(description, source, submitter)
|
|
print(f"\n{'=' * 80}")
|
|
print(f"Result: {json.dumps(result, indent=2)}")
|
|
print(f"{'=' * 80}\n")
|
|
|
|
elif sys.argv[1] == '--status':
|
|
# Show dashboard
|
|
dashboard = orchestrator.get_flow_dashboard()
|
|
print(json.dumps(dashboard, indent=2))
|
|
|
|
elif sys.argv[1] == '--help':
|
|
print("""
|
|
Luzia Flow Orchestrator
|
|
|
|
Usage:
|
|
luzia_flow_orchestrator.py --demo Show flow demonstration
|
|
luzia_flow_orchestrator.py --status Show flow dashboard
|
|
luzia_flow_orchestrator.py --help This help message
|
|
|
|
Direct Python usage:
|
|
orchestrator = LuziaFlowOrchestrator()
|
|
result = orchestrator.process_task("your task description")
|
|
print(result['task_id'])
|
|
""")
|
|
else:
|
|
# Process task from command line
|
|
task_description = ' '.join(sys.argv[1:])
|
|
result = orchestrator.process_task(task_description)
|
|
print(json.dumps(result, indent=2))
|
|
|
|
else:
|
|
# Interactive mode
|
|
print("\n" + "=" * 80)
|
|
print("🔬 LUZIA UNIFIED FLOW - INTERACTIVE MODE")
|
|
print("=" * 80)
|
|
print("\nEnter tasks to process through the flow. Type 'exit' to quit.\n")
|
|
|
|
while True:
|
|
try:
|
|
task = input("📋 Task description: ").strip()
|
|
|
|
if task.lower() in ['exit', 'quit', 'q']:
|
|
break
|
|
|
|
if not task:
|
|
continue
|
|
|
|
result = orchestrator.process_task(task)
|
|
print(f"\n✅ Task {result['task_id']} completed")
|
|
print(f" Final state: {result['final_state']}")
|
|
print()
|
|
|
|
except KeyboardInterrupt:
|
|
break
|
|
except Exception as e:
|
|
print(f"❌ Error: {e}\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|