Files
luzia/luzia_flow_orchestrator.py
admin ec33ac1936 Refactor cockpit to use DockerTmuxController pattern
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>
2026-01-14 10:42:16 -03:00

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()