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>
317 lines
10 KiB
Python
317 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Luzia Status System - Integration Example
|
|
|
|
This example demonstrates how to integrate the status publishing system
|
|
into your orchestrator code. Each section shows the 7 key integration points.
|
|
|
|
Copy these patterns into your existing code wherever you dispatch tasks,
|
|
monitor progress, or handle completion/failures.
|
|
"""
|
|
|
|
import time
|
|
import uuid
|
|
import asyncio
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
# Setup logging
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Import the sync wrapper (works in both async and sync contexts)
|
|
from luzia_status_sync_wrapper import get_sync_publisher
|
|
|
|
|
|
class TaskDispatcherWithStatus:
|
|
"""Example task dispatcher with integrated status publishing"""
|
|
|
|
def __init__(self):
|
|
self.publisher = get_sync_publisher()
|
|
|
|
def dispatch_task(self, project: str, description: str, estimated_duration: int = 600):
|
|
"""
|
|
Example 1: Publish task started
|
|
Location: In your task dispatcher when you create a new task
|
|
"""
|
|
task_id = f"{project}-{uuid.uuid4().hex[:8]}"
|
|
|
|
logger.info(f"Dispatching task: {task_id}")
|
|
|
|
# PUBLISHING POINT #1: Task Started
|
|
self.publisher.publish_task_started(
|
|
task_id=task_id,
|
|
project=project,
|
|
description=description,
|
|
estimated_duration_seconds=estimated_duration
|
|
)
|
|
|
|
return task_id
|
|
|
|
def monitor_task_progress(self, task_id: str, project: str, total_steps: int = 4):
|
|
"""
|
|
Example 2 & 5: Publish progress updates and warnings
|
|
Location: In your main task execution loop
|
|
"""
|
|
start_time = time.time()
|
|
step_names = ["Analyzing", "Processing", "Validating", "Finalizing"]
|
|
|
|
for step_num, step_name in enumerate(step_names, 1):
|
|
logger.info(f" Step {step_num}/{total_steps}: {step_name}")
|
|
|
|
# Simulate work
|
|
time.sleep(2)
|
|
|
|
elapsed = int(time.time() - start_time)
|
|
progress = int((step_num / total_steps) * 100)
|
|
|
|
# PUBLISHING POINT #2: Progress Update
|
|
# Do this every 30 seconds or at significant milestones
|
|
self.publisher.publish_progress(
|
|
task_id=task_id,
|
|
progress_percent=progress,
|
|
current_step=step_num,
|
|
total_steps=total_steps,
|
|
current_step_name=step_name,
|
|
elapsed_seconds=elapsed,
|
|
estimated_remaining_seconds=int((600 - elapsed) * (100 - progress) / 100)
|
|
)
|
|
|
|
# PUBLISHING POINT #5: Warning (if approaching time limit)
|
|
if elapsed > 480: # 80% of 600 second budget
|
|
remaining = int(600 - elapsed)
|
|
if remaining < 120: # Less than 2 minutes left
|
|
self.publisher.publish_warning(
|
|
task_id=task_id,
|
|
warning_type="DURATION_EXCEEDED",
|
|
message=f"Task approaching time limit: {remaining}s remaining",
|
|
current_step=step_num,
|
|
total_steps=total_steps,
|
|
current_step_name=step_name,
|
|
elapsed_seconds=elapsed,
|
|
progress_percent=progress,
|
|
recommendation="May need optimization or extension"
|
|
)
|
|
|
|
def complete_task(self, task_id: str, project: str, elapsed_secs: int, findings: list):
|
|
"""
|
|
Example 3: Publish task completed
|
|
Location: When task finishes successfully
|
|
"""
|
|
logger.info(f"Task completed: {task_id}")
|
|
|
|
# PUBLISHING POINT #3: Task Completed
|
|
self.publisher.publish_task_completed(
|
|
task_id=task_id,
|
|
elapsed_seconds=elapsed_secs,
|
|
findings_count=len(findings),
|
|
recommendations_count=1, # Number of recommendations
|
|
status="APPROVED" # or NEEDS_WORK, REJECTED
|
|
)
|
|
|
|
def fail_task(self, task_id: str, error: str, elapsed_secs: int, retry_count: int):
|
|
"""
|
|
Example 6: Publish task failed
|
|
Location: In your error handler
|
|
"""
|
|
logger.error(f"Task failed: {task_id}")
|
|
|
|
# PUBLISHING POINT #6: Task Failed
|
|
self.publisher.publish_task_failed(
|
|
task_id=task_id,
|
|
error=error,
|
|
elapsed_seconds=elapsed_secs,
|
|
retry_count=retry_count,
|
|
retriable=retry_count < 5 # Can be retried?
|
|
)
|
|
|
|
|
|
class QueueManagerWithStatus:
|
|
"""Example queue manager with integrated status publishing"""
|
|
|
|
def __init__(self):
|
|
self.publisher = get_sync_publisher()
|
|
self.queue = []
|
|
|
|
def queue_task(self, task_id: str, project: str, description: str, reason: str, wait_estimate: int):
|
|
"""
|
|
Example 4: Publish task queued
|
|
Location: In your queue manager when adding to queue
|
|
"""
|
|
queue_position = len(self.queue) + 1
|
|
|
|
logger.info(f"Queuing task: {task_id} (position {queue_position})")
|
|
|
|
# PUBLISHING POINT #4: Task Queued
|
|
self.publisher.publish_task_queued(
|
|
task_id=task_id,
|
|
project=project,
|
|
description=description,
|
|
reason=reason, # Why it was queued
|
|
queue_position=queue_position,
|
|
queue_ahead=[t['id'] for t in self.queue], # Tasks ahead in queue
|
|
estimated_wait_seconds=wait_estimate
|
|
)
|
|
|
|
self.queue.append({
|
|
'id': task_id,
|
|
'project': project,
|
|
'description': description
|
|
})
|
|
|
|
|
|
class SystemMonitorWithStatus:
|
|
"""Example system monitor with integrated status publishing"""
|
|
|
|
def __init__(self):
|
|
self.publisher = get_sync_publisher()
|
|
|
|
def check_system_health(self):
|
|
"""
|
|
Example 7: Publish system alert
|
|
Location: In your system health monitor
|
|
"""
|
|
import psutil
|
|
|
|
# Check memory
|
|
memory_percent = psutil.virtual_memory().percent
|
|
if memory_percent > 80:
|
|
# PUBLISHING POINT #7: System Alert
|
|
self.publisher.publish_system_alert(
|
|
alert_type="RESOURCE_WARNING",
|
|
message=f"Memory usage at {memory_percent}%",
|
|
recommendation="New tasks will be queued until memory is freed",
|
|
severity="warning"
|
|
)
|
|
|
|
# Check disk
|
|
disk_percent = psutil.disk_usage('/').percent
|
|
if disk_percent > 90:
|
|
self.publisher.publish_system_alert(
|
|
alert_type="DISK_CRITICAL",
|
|
message=f"Disk usage at {disk_percent}%",
|
|
recommendation="Immediate cleanup required",
|
|
severity="critical"
|
|
)
|
|
|
|
|
|
# Example usage
|
|
def example_task_lifecycle():
|
|
"""
|
|
Demonstrate the complete task lifecycle with status publishing
|
|
|
|
This shows all 7 integration points in action
|
|
"""
|
|
dispatcher = TaskDispatcherWithStatus()
|
|
queue_manager = QueueManagerWithStatus()
|
|
monitor = SystemMonitorWithStatus()
|
|
|
|
# Example 1: Dispatch a task
|
|
task_id = dispatcher.dispatch_task(
|
|
project="musica",
|
|
description="Fix audio synthesis engine",
|
|
estimated_duration=600
|
|
)
|
|
|
|
try:
|
|
# Example 2 & 5: Monitor progress (with warnings)
|
|
dispatcher.monitor_task_progress(task_id, "musica")
|
|
|
|
# Example 3: Complete the task
|
|
dispatcher.complete_task(
|
|
task_id=task_id,
|
|
project="musica",
|
|
elapsed_secs=615,
|
|
findings=["Issue A", "Issue B"]
|
|
)
|
|
|
|
except Exception as e:
|
|
# Example 6: Handle failures
|
|
dispatcher.fail_task(
|
|
task_id=task_id,
|
|
error=str(e),
|
|
elapsed_secs=300,
|
|
retry_count=1
|
|
)
|
|
|
|
|
|
def example_queue_management():
|
|
"""Demonstrate queuing with status publishing"""
|
|
queue_manager = QueueManagerWithStatus()
|
|
|
|
# Example 4: Queue a task (when system is busy)
|
|
queue_manager.queue_task(
|
|
task_id="admin-code-001",
|
|
project="admin",
|
|
description="Code review and cleanup",
|
|
reason="System resource limit reached",
|
|
wait_estimate=300
|
|
)
|
|
|
|
|
|
def example_system_monitoring():
|
|
"""Demonstrate system monitoring with alerts"""
|
|
monitor = SystemMonitorWithStatus()
|
|
|
|
# Example 7: Check system health
|
|
try:
|
|
monitor.check_system_health()
|
|
except ImportError:
|
|
logger.warning("psutil not available, skipping system check")
|
|
|
|
|
|
# Integration Points Summary
|
|
"""
|
|
To integrate into your orchestrator, add the following 7 calls:
|
|
|
|
1. Task Dispatcher (when creating task):
|
|
publisher.publish_task_started(task_id, project, description, estimated_duration)
|
|
|
|
2. Progress Loop (every 30 seconds):
|
|
publisher.publish_progress(task_id, progress_percent, current_step, total_steps,
|
|
current_step_name, elapsed_seconds, estimated_remaining)
|
|
|
|
3. Task Completion (when task succeeds):
|
|
publisher.publish_task_completed(task_id, elapsed_seconds, findings_count, status)
|
|
|
|
4. Queue Manager (when queueing task):
|
|
publisher.publish_task_queued(task_id, project, description, reason,
|
|
queue_position, queue_ahead, wait_estimate)
|
|
|
|
5. Resource Monitor (when warning threshold exceeded):
|
|
publisher.publish_warning(task_id, warning_type, message, current_step,
|
|
total_steps, current_step_name, elapsed_seconds,
|
|
progress_percent, recommendation)
|
|
|
|
6. Error Handler (when task fails):
|
|
publisher.publish_task_failed(task_id, error, elapsed_seconds,
|
|
retry_count, retriable)
|
|
|
|
7. System Monitor (on health issues):
|
|
publisher.publish_system_alert(alert_type, message, recommendation, severity)
|
|
|
|
Each call is idempotent and safe to use in production.
|
|
"""
|
|
|
|
if __name__ == "__main__":
|
|
print("\n" + "=" * 60)
|
|
print("LUZIA STATUS INTEGRATION EXAMPLES")
|
|
print("=" * 60)
|
|
|
|
print("\n1. Task Lifecycle Example:")
|
|
print("-" * 60)
|
|
example_task_lifecycle()
|
|
|
|
print("\n2. Queue Management Example:")
|
|
print("-" * 60)
|
|
example_queue_management()
|
|
|
|
print("\n3. System Monitoring Example:")
|
|
print("-" * 60)
|
|
example_system_monitoring()
|
|
|
|
print("\n" + "=" * 60)
|
|
print("Integration complete - status events published")
|
|
print("=" * 60)
|