Files
luzia/lib/chat_memory_lookup.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

216 lines
6.6 KiB
Python

#!/usr/bin/env python3
"""
Chat Memory Lookup - Fast local memory queries
Queries shared project memory without external calls
"""
import sqlite3
from pathlib import Path
from typing import Dict, List, Optional
import time
class ChatMemoryLookup:
"""Query local project memory for chat interface"""
MEMORY_DB = Path('/etc/zen-swarm/memory/projects.db')
def __init__(self, timeout_ms: int = 150):
"""Initialize with query timeout"""
self.timeout_ms = timeout_ms
self.timeout_seconds = timeout_ms / 1000.0
def search_entities(self, query: str, limit: int = 10) -> Dict:
"""Search for entities by name"""
if not self.MEMORY_DB.exists():
return {'error': 'Memory database not found', 'entities': []}
try:
conn = sqlite3.connect(str(self.MEMORY_DB), timeout=self.timeout_seconds)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute(
"SELECT id, name, type FROM entities WHERE name LIKE ? LIMIT ?",
(f'%{query}%', limit)
)
entities = [
{
'id': row['id'],
'name': row['name'],
'type': row['type']
}
for row in cursor.fetchall()
]
conn.close()
return {'entities': entities, 'count': len(entities)}
except Exception as e:
return {'error': str(e), 'entities': []}
def get_entity(self, entity_name: str) -> Dict:
"""Get entity and its relations"""
if not self.MEMORY_DB.exists():
return {'error': 'Memory database not found'}
try:
conn = sqlite3.connect(str(self.MEMORY_DB), timeout=self.timeout_seconds)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
# Get entity
cursor.execute(
"SELECT id, name, type FROM entities WHERE name = ?",
(entity_name,)
)
entity_row = cursor.fetchone()
if not entity_row:
conn.close()
return {'error': f'Entity {entity_name} not found'}
entity_id = entity_row['id']
entity = {
'name': entity_row['name'],
'type': entity_row['type'],
'relations': []
}
# Get relations (join to get entity names)
cursor.execute("""
SELECT e1.name as from_name, e2.name as to_name, r.relation, r.context
FROM relations r
JOIN entities e1 ON r.source_id = e1.id
JOIN entities e2 ON r.target_id = e2.id
WHERE r.source_id = ? OR r.target_id = ?
LIMIT 20
""", (entity_id, entity_id))
for row in cursor.fetchall():
entity['relations'].append({
'from': row['from_name'],
'to': row['to_name'],
'type': row['relation'],
'context': row['context']
})
conn.close()
return entity
except Exception as e:
return {'error': str(e)}
def get_project_info(self, project_name: str) -> Dict:
"""Get project-specific information"""
if not self.MEMORY_DB.exists():
return {'error': 'Memory database not found'}
try:
conn = sqlite3.connect(str(self.MEMORY_DB), timeout=self.timeout_seconds)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
# Get project entity
cursor.execute(
"SELECT id, name, type FROM entities WHERE name = ? AND type = 'project'",
(project_name,)
)
project_row = cursor.fetchone()
if not project_row:
conn.close()
return {'error': f'Project {project_name} not found'}
project_id = project_row['id']
project = {
'name': project_row['name'],
'type': project_row['type'],
'related_entities': []
}
# Get related entities
cursor.execute("""
SELECT e.name FROM entities e
JOIN relations r ON r.target_id = e.id
WHERE r.source_id = ?
LIMIT 10
""", (project_id,))
for row in cursor.fetchall():
project['related_entities'].append(row['name'])
conn.close()
return project
except Exception as e:
return {'error': str(e)}
def list_all_projects(self) -> Dict:
"""List all projects in memory"""
if not self.MEMORY_DB.exists():
return {'error': 'Memory database not found', 'projects': []}
try:
conn = sqlite3.connect(str(self.MEMORY_DB), timeout=self.timeout_seconds)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute(
"SELECT name, type FROM entities WHERE type = 'project' OR type = 'Project' LIMIT 50"
)
projects = [
{
'name': row['name'],
'type': row['type']
}
for row in cursor.fetchall()
]
conn.close()
return {'projects': projects, 'count': len(projects)}
except Exception as e:
return {'error': str(e), 'projects': []}
def memory_statistics(self) -> Dict:
"""Get memory database statistics"""
if not self.MEMORY_DB.exists():
return {'available': False}
try:
conn = sqlite3.connect(str(self.MEMORY_DB), timeout=self.timeout_seconds)
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM entities")
entity_count = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(*) FROM relations")
relation_count = cursor.fetchone()[0]
stats = {
'available': True,
'entities': entity_count,
'relations': relation_count
}
conn.close()
return stats
except Exception as e:
return {'available': False, 'error': str(e)}
if __name__ == '__main__':
import json
lookup = ChatMemoryLookup()
print("Memory Statistics:")
print(json.dumps(lookup.memory_statistics(), indent=2))
print()
print("List Projects:")
print(json.dumps(lookup.list_all_projects(), indent=2))