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>
This commit is contained in:
169
luzia_research_agent.py
Executable file
169
luzia_research_agent.py
Executable file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Luzia Research Agent Loop - Interactive Research Task Processing
|
||||
|
||||
Continuously monitors incoming research tasks and routes them intelligently
|
||||
based on security, speed, and complexity filters.
|
||||
|
||||
Can run in:
|
||||
- Interactive mode: Process individual tasks
|
||||
- Loop mode: Monitor queue continuously (default)
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
sys.path.insert(0, '/opt/server-agents/orchestrator/lib')
|
||||
|
||||
from research_agent import LuziaResearchAgent, TaskFilter, ToolRouter
|
||||
|
||||
|
||||
def run_interactive():
|
||||
"""Interactive mode: process user input"""
|
||||
agent = LuziaResearchAgent()
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print("🔬 LUZIA RESEARCH AGENT - INTERACTIVE MODE")
|
||||
print("=" * 70)
|
||||
print("\nEnter research tasks to analyze. Type 'exit' to quit.\n")
|
||||
|
||||
while True:
|
||||
try:
|
||||
task = input("📋 Research task: ").strip()
|
||||
|
||||
if task.lower() in ['exit', 'quit', 'q']:
|
||||
print("✅ Exiting research agent")
|
||||
break
|
||||
|
||||
if not task:
|
||||
print("⚠️ Empty task, try again\n")
|
||||
continue
|
||||
|
||||
# Process the task
|
||||
result = agent.process_research_task(task)
|
||||
|
||||
print(f"\n{result['analysis']['routing_summary']}")
|
||||
|
||||
if result['clarification']:
|
||||
print("❓ Clarification Questions:")
|
||||
for q in result['clarification']['questions']:
|
||||
print(f" {q}")
|
||||
|
||||
print()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n✅ Exiting research agent")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"❌ Error: {e}\n")
|
||||
|
||||
|
||||
def run_continuous():
|
||||
"""Continuous loop mode: monitor and process tasks"""
|
||||
agent = LuziaResearchAgent()
|
||||
queue_file = Path("/opt/server-agents/state/research-queue.json")
|
||||
|
||||
agent.log("🔬 Luzia Research Agent started (continuous mode)")
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Check if queue file exists
|
||||
if not queue_file.exists():
|
||||
time.sleep(10)
|
||||
continue
|
||||
|
||||
# Read queue
|
||||
with open(queue_file) as f:
|
||||
queue_data = json.load(f)
|
||||
|
||||
pending = queue_data.get('pending', [])
|
||||
if not pending:
|
||||
time.sleep(10)
|
||||
continue
|
||||
|
||||
# Process first pending task
|
||||
task_entry = pending[0]
|
||||
task_id = task_entry.get('id', str(uuid.uuid4()))
|
||||
task = task_entry.get('task', '')
|
||||
|
||||
agent.log(f"📥 Processing task {task_id}: {task[:50]}...")
|
||||
|
||||
# Analyze and route
|
||||
result = agent.process_research_task(task)
|
||||
|
||||
# Move to processed
|
||||
queue_data['pending'].pop(0)
|
||||
queue_data['processed'] = queue_data.get('processed', [])
|
||||
queue_data['processed'].append({
|
||||
'id': task_id,
|
||||
'task': task,
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'analysis': result['analysis'],
|
||||
'status': result['status'],
|
||||
})
|
||||
|
||||
# Write back
|
||||
with open(queue_file, 'w') as f:
|
||||
json.dump(queue_data, f, indent=2)
|
||||
|
||||
agent.log(f"✅ Processed: {task[:50]}... → {result['analysis']['recommended_tool']}")
|
||||
|
||||
# Brief sleep between tasks
|
||||
time.sleep(2)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
agent.log("🛑 Research agent stopped by user")
|
||||
break
|
||||
except Exception as e:
|
||||
agent.log(f"❌ Error in loop: {e}")
|
||||
time.sleep(5)
|
||||
|
||||
|
||||
def show_demo():
|
||||
"""Show demonstration of smart filtering"""
|
||||
agent = LuziaResearchAgent()
|
||||
|
||||
demo_tasks = [
|
||||
("quick answer: what is REST?", "Simple question, no urgency"),
|
||||
("urgent critical vulnerability in auth system", "Critical security, needs immediate review"),
|
||||
("research distributed caching approaches and tradeoffs", "Complex decision, needs exploration"),
|
||||
("debug: zen-proxy max_tokens not working", "Error diagnosis, straightforward"),
|
||||
("design: REST vs GraphQL for new API", "Architecture decision, multiple perspectives"),
|
||||
]
|
||||
|
||||
print("\n" + "=" * 80)
|
||||
print("🔬 LUZIA RESEARCH AGENT - SMART FILTER DEMONSTRATION")
|
||||
print("=" * 80)
|
||||
|
||||
for task, context in demo_tasks:
|
||||
print(f"\n📋 Task: {task}")
|
||||
print(f" Context: {context}")
|
||||
print(" " + "-" * 70)
|
||||
|
||||
analysis = agent.analyze_task(task)
|
||||
print(f" Security: {analysis['security']}")
|
||||
print(f" Speed: {analysis['speed']}")
|
||||
print(f" Complexity: {analysis['complexity']}")
|
||||
print(f" → Tool: {analysis['recommended_tool']}")
|
||||
print(f" Reason: {analysis['reasoning']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] == "--demo":
|
||||
show_demo()
|
||||
elif sys.argv[1] == "--interactive":
|
||||
run_interactive()
|
||||
elif sys.argv[1] == "--continuous":
|
||||
run_continuous()
|
||||
else:
|
||||
print("Usage:")
|
||||
print(" luzia_research_agent.py --demo Show demonstration")
|
||||
print(" luzia_research_agent.py --interactive Interactive mode")
|
||||
print(" luzia_research_agent.py --continuous Continuous queue monitoring")
|
||||
else:
|
||||
# Default: interactive mode
|
||||
run_interactive()
|
||||
Reference in New Issue
Block a user