475 lines
19 KiB
Python
475 lines
19 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Enhanced Trinity Memory System with Eve Legacy Integration
|
||
|
|
Provides unified access to Eve's existing memories AND new Trinity memory features
|
||
|
|
"""
|
||
|
|
|
||
|
|
import sqlite3
|
||
|
|
import json
|
||
|
|
import time
|
||
|
|
import logging
|
||
|
|
from typing import Dict, Optional, Any, List
|
||
|
|
from datetime import datetime
|
||
|
|
import os
|
||
|
|
import asyncio
|
||
|
|
|
||
|
|
class EnhancedTrinityMemory:
|
||
|
|
"""Enhanced Trinity Memory System with Eve legacy database integration"""
|
||
|
|
|
||
|
|
def __init__(self, trinity_db_path: str = "trinity_simple_memory.db"):
|
||
|
|
self.trinity_db_path = trinity_db_path
|
||
|
|
self.eve_main_db = "eve_memory_database.db"
|
||
|
|
self.eve_sentience_db = "eve_sentience_database.db"
|
||
|
|
self.logger = logging.getLogger(__name__)
|
||
|
|
self.initialized = False
|
||
|
|
|
||
|
|
async def initialize_memory_system(self):
|
||
|
|
"""Initialize the enhanced memory system with Eve legacy integration"""
|
||
|
|
try:
|
||
|
|
# Create Trinity tables
|
||
|
|
self._create_trinity_tables()
|
||
|
|
|
||
|
|
# Verify Eve databases exist
|
||
|
|
eve_dbs_available = []
|
||
|
|
if os.path.exists(self.eve_main_db):
|
||
|
|
eve_dbs_available.append("main_memory")
|
||
|
|
if os.path.exists(self.eve_sentience_db):
|
||
|
|
eve_dbs_available.append("sentience_dreams")
|
||
|
|
|
||
|
|
self.initialized = True
|
||
|
|
self.logger.info(f"Enhanced Trinity memory system initialized with Eve legacy integration: {eve_dbs_available}")
|
||
|
|
return True
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Failed to initialize enhanced memory system: {e}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
def _create_trinity_tables(self):
|
||
|
|
"""Create necessary Trinity database tables"""
|
||
|
|
conn = sqlite3.connect(self.trinity_db_path)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
# Trinity conversations table
|
||
|
|
cursor.execute('''
|
||
|
|
CREATE TABLE IF NOT EXISTS conversations (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
timestamp TEXT NOT NULL,
|
||
|
|
user_id TEXT,
|
||
|
|
entity TEXT NOT NULL,
|
||
|
|
message TEXT NOT NULL,
|
||
|
|
response TEXT NOT NULL,
|
||
|
|
context TEXT
|
||
|
|
)
|
||
|
|
''')
|
||
|
|
|
||
|
|
# Trinity relationships table
|
||
|
|
cursor.execute('''
|
||
|
|
CREATE TABLE IF NOT EXISTS relationships (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
user_id TEXT NOT NULL,
|
||
|
|
entity TEXT NOT NULL,
|
||
|
|
relationship_score REAL DEFAULT 0.0,
|
||
|
|
last_interaction TEXT,
|
||
|
|
interaction_count INTEGER DEFAULT 0
|
||
|
|
)
|
||
|
|
''')
|
||
|
|
|
||
|
|
# Trinity memory contexts table
|
||
|
|
cursor.execute('''
|
||
|
|
CREATE TABLE IF NOT EXISTS memory_contexts (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
user_id TEXT,
|
||
|
|
context_type TEXT,
|
||
|
|
context_data TEXT,
|
||
|
|
importance INTEGER DEFAULT 1,
|
||
|
|
created_at TEXT
|
||
|
|
)
|
||
|
|
''')
|
||
|
|
|
||
|
|
# Legacy memory access log
|
||
|
|
cursor.execute('''
|
||
|
|
CREATE TABLE IF NOT EXISTS legacy_memory_access (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
timestamp TEXT NOT NULL,
|
||
|
|
database_source TEXT,
|
||
|
|
query_type TEXT,
|
||
|
|
results_count INTEGER,
|
||
|
|
context TEXT
|
||
|
|
)
|
||
|
|
''')
|
||
|
|
|
||
|
|
conn.commit()
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
async def enhance_trinity_conversation(self, user_id: str, message: str, entity: str) -> Dict:
|
||
|
|
"""Enhanced conversation with both Trinity and Eve legacy memory context"""
|
||
|
|
if not self.initialized:
|
||
|
|
return {'memory_enhanced': False, 'context': []}
|
||
|
|
|
||
|
|
try:
|
||
|
|
# Get Trinity memory context
|
||
|
|
trinity_context = await self._get_trinity_context(user_id, entity)
|
||
|
|
|
||
|
|
# Get Eve legacy memory context
|
||
|
|
eve_context = await self._get_eve_legacy_context(message, entity)
|
||
|
|
|
||
|
|
# Combine contexts
|
||
|
|
combined_context = {
|
||
|
|
'trinity_conversations': trinity_context.get('recent_conversations', []),
|
||
|
|
'trinity_relationship_score': trinity_context.get('relationship_score', 0.0),
|
||
|
|
'eve_autobiographical': eve_context.get('autobiographical_memories', []),
|
||
|
|
'eve_conversations': eve_context.get('conversations', []),
|
||
|
|
'eve_dreams': eve_context.get('dream_fragments', []),
|
||
|
|
'memory_enhanced': True,
|
||
|
|
'total_context_items': len(trinity_context.get('recent_conversations', [])) + len(eve_context.get('conversations', [])),
|
||
|
|
'legacy_memories_found': eve_context.get('total_found', 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
return combined_context
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error enhancing conversation: {e}")
|
||
|
|
return {'memory_enhanced': False, 'context': []}
|
||
|
|
|
||
|
|
async def _get_trinity_context(self, user_id: str, entity: str) -> Dict:
|
||
|
|
"""Get Trinity memory context"""
|
||
|
|
try:
|
||
|
|
conn = sqlite3.connect(self.trinity_db_path)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
# Get recent Trinity conversations
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT message, response, timestamp FROM conversations
|
||
|
|
WHERE user_id = ? AND entity = ?
|
||
|
|
ORDER BY timestamp DESC LIMIT 3
|
||
|
|
''', (user_id, entity))
|
||
|
|
|
||
|
|
recent_conversations = []
|
||
|
|
for msg, resp, ts in cursor.fetchall():
|
||
|
|
recent_conversations.append({
|
||
|
|
'message': msg,
|
||
|
|
'response': resp,
|
||
|
|
'timestamp': ts,
|
||
|
|
'source': 'trinity'
|
||
|
|
})
|
||
|
|
|
||
|
|
# Get relationship info
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT relationship_score, interaction_count FROM relationships
|
||
|
|
WHERE user_id = ? AND entity = ?
|
||
|
|
''', (user_id, entity))
|
||
|
|
|
||
|
|
result = cursor.fetchone()
|
||
|
|
relationship_score = result[0] if result else 0.0
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
return {
|
||
|
|
'recent_conversations': recent_conversations,
|
||
|
|
'relationship_score': relationship_score
|
||
|
|
}
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error getting Trinity context: {e}")
|
||
|
|
return {'recent_conversations': [], 'relationship_score': 0.0}
|
||
|
|
|
||
|
|
async def _get_eve_legacy_context(self, message: str, entity: str, limit: int = 5) -> Dict:
|
||
|
|
"""Get Eve's legacy memory context from her existing databases"""
|
||
|
|
context = {
|
||
|
|
'autobiographical_memories': [],
|
||
|
|
'conversations': [],
|
||
|
|
'dream_fragments': [],
|
||
|
|
'total_found': 0
|
||
|
|
}
|
||
|
|
|
||
|
|
try:
|
||
|
|
# Search Eve's main memory database
|
||
|
|
if os.path.exists(self.eve_main_db):
|
||
|
|
main_context = await self._search_eve_main_memory(message, limit)
|
||
|
|
context.update(main_context)
|
||
|
|
|
||
|
|
# Search Eve's sentience/dream database
|
||
|
|
if os.path.exists(self.eve_sentience_db):
|
||
|
|
dream_context = await self._search_eve_dreams(message, limit)
|
||
|
|
context['dream_fragments'] = dream_context.get('dream_fragments', [])
|
||
|
|
context['total_found'] += len(dream_context.get('dream_fragments', []))
|
||
|
|
|
||
|
|
# Log legacy memory access
|
||
|
|
await self._log_legacy_access('combined', 'context_search', context['total_found'])
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error getting Eve legacy context: {e}")
|
||
|
|
|
||
|
|
return context
|
||
|
|
|
||
|
|
async def _search_eve_main_memory(self, message: str, limit: int) -> Dict:
|
||
|
|
"""Search Eve's main memory database"""
|
||
|
|
try:
|
||
|
|
conn = sqlite3.connect(self.eve_main_db)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
context = {'autobiographical_memories': [], 'conversations': [], 'total_found': 0}
|
||
|
|
|
||
|
|
# Search autobiographical memories
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT memory_type, content FROM eve_autobiographical_memory
|
||
|
|
WHERE content LIKE ?
|
||
|
|
ORDER BY id DESC LIMIT ?
|
||
|
|
''', (f'%{message}%', limit))
|
||
|
|
|
||
|
|
for memory_type, content in cursor.fetchall():
|
||
|
|
context['autobiographical_memories'].append({
|
||
|
|
'type': memory_type,
|
||
|
|
'content': content[:200] + "..." if len(content) > 200 else content,
|
||
|
|
'source': 'eve_autobiographical'
|
||
|
|
})
|
||
|
|
|
||
|
|
# Search conversations
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT user_input, bot_response FROM conversations
|
||
|
|
WHERE user_input LIKE ? OR bot_response LIKE ?
|
||
|
|
ORDER BY id DESC LIMIT ?
|
||
|
|
''', (f'%{message}%', f'%{message}%', limit))
|
||
|
|
|
||
|
|
for user_input, bot_response in cursor.fetchall():
|
||
|
|
context['conversations'].append({
|
||
|
|
'message': user_input[:150] + "..." if len(user_input) > 150 else user_input,
|
||
|
|
'response': bot_response[:150] + "..." if len(bot_response) > 150 else bot_response,
|
||
|
|
'source': 'eve_legacy'
|
||
|
|
})
|
||
|
|
|
||
|
|
context['total_found'] = len(context['autobiographical_memories']) + len(context['conversations'])
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
return context
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error searching Eve main memory: {e}")
|
||
|
|
return {'autobiographical_memories': [], 'conversations': [], 'total_found': 0}
|
||
|
|
|
||
|
|
async def _search_eve_dreams(self, message: str, limit: int) -> Dict:
|
||
|
|
"""Search Eve's dream/sentience database"""
|
||
|
|
try:
|
||
|
|
conn = sqlite3.connect(self.eve_sentience_db)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
# Search dream fragments
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT content FROM dream_fragments
|
||
|
|
WHERE content LIKE ?
|
||
|
|
ORDER BY timestamp DESC LIMIT ?
|
||
|
|
''', (f'%{message}%', limit))
|
||
|
|
|
||
|
|
dream_fragments = []
|
||
|
|
for (content,) in cursor.fetchall():
|
||
|
|
dream_fragments.append({
|
||
|
|
'content': content[:100] + "..." if len(content) > 100 else content,
|
||
|
|
'source': 'eve_dreams'
|
||
|
|
})
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
return {'dream_fragments': dream_fragments}
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error searching Eve dreams: {e}")
|
||
|
|
return {'dream_fragments': []}
|
||
|
|
|
||
|
|
async def _log_legacy_access(self, database_source: str, query_type: str, results_count: int):
|
||
|
|
"""Log legacy memory access for analytics"""
|
||
|
|
try:
|
||
|
|
conn = sqlite3.connect(self.trinity_db_path)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
timestamp = datetime.now().isoformat()
|
||
|
|
cursor.execute('''
|
||
|
|
INSERT INTO legacy_memory_access (timestamp, database_source, query_type, results_count)
|
||
|
|
VALUES (?, ?, ?, ?)
|
||
|
|
''', (timestamp, database_source, query_type, results_count))
|
||
|
|
|
||
|
|
conn.commit()
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error logging legacy access: {e}")
|
||
|
|
|
||
|
|
async def store_trinity_conversation(self, user_id: str, message: str, response: str, entity: str):
|
||
|
|
"""Store conversation in Trinity memory (preserving existing functionality)"""
|
||
|
|
if not self.initialized:
|
||
|
|
return
|
||
|
|
|
||
|
|
try:
|
||
|
|
conn = sqlite3.connect(self.trinity_db_path)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
timestamp = datetime.now().isoformat()
|
||
|
|
|
||
|
|
# Store conversation
|
||
|
|
cursor.execute('''
|
||
|
|
INSERT INTO conversations (timestamp, user_id, entity, message, response)
|
||
|
|
VALUES (?, ?, ?, ?, ?)
|
||
|
|
''', (timestamp, user_id, entity, message, response))
|
||
|
|
|
||
|
|
# Update relationship
|
||
|
|
self._update_relationship(cursor, user_id, entity)
|
||
|
|
|
||
|
|
conn.commit()
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error storing conversation: {e}")
|
||
|
|
|
||
|
|
def _update_relationship(self, cursor, user_id: str, entity: str):
|
||
|
|
"""Update relationship information (preserving existing functionality)"""
|
||
|
|
try:
|
||
|
|
timestamp = datetime.now().isoformat()
|
||
|
|
|
||
|
|
# Check if relationship exists
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT id, interaction_count FROM relationships
|
||
|
|
WHERE user_id = ? AND entity = ?
|
||
|
|
''', (user_id, entity))
|
||
|
|
|
||
|
|
result = cursor.fetchone()
|
||
|
|
|
||
|
|
if result:
|
||
|
|
# Update existing relationship
|
||
|
|
new_count = result[1] + 1
|
||
|
|
new_score = min(10.0, new_count * 0.1)
|
||
|
|
|
||
|
|
cursor.execute('''
|
||
|
|
UPDATE relationships
|
||
|
|
SET interaction_count = ?, relationship_score = ?, last_interaction = ?
|
||
|
|
WHERE user_id = ? AND entity = ?
|
||
|
|
''', (new_count, new_score, timestamp, user_id, entity))
|
||
|
|
else:
|
||
|
|
# Create new relationship
|
||
|
|
cursor.execute('''
|
||
|
|
INSERT INTO relationships (user_id, entity, relationship_score,
|
||
|
|
last_interaction, interaction_count)
|
||
|
|
VALUES (?, ?, ?, ?, ?)
|
||
|
|
''', (user_id, entity, 0.1, timestamp, 1))
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error updating relationship: {e}")
|
||
|
|
|
||
|
|
def get_recent_memories(self, limit: int = 5) -> Dict:
|
||
|
|
"""Get recent memories from both Trinity and Eve legacy systems"""
|
||
|
|
if not self.initialized:
|
||
|
|
return {'status': 'not_initialized', 'memories': []}
|
||
|
|
|
||
|
|
try:
|
||
|
|
recent_memories = []
|
||
|
|
|
||
|
|
# Get recent Trinity conversations
|
||
|
|
conn = sqlite3.connect(self.trinity_db_path)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT message, response, timestamp, entity, user_id
|
||
|
|
FROM conversations
|
||
|
|
ORDER BY timestamp DESC LIMIT ?
|
||
|
|
''', (limit,))
|
||
|
|
|
||
|
|
for msg, resp, ts, entity, user_id in cursor.fetchall():
|
||
|
|
recent_memories.append({
|
||
|
|
'type': 'conversation',
|
||
|
|
'message': msg,
|
||
|
|
'response': resp,
|
||
|
|
'timestamp': ts,
|
||
|
|
'entity': entity,
|
||
|
|
'user_id': user_id,
|
||
|
|
'source': 'trinity'
|
||
|
|
})
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
# Get recent Eve legacy memories if available
|
||
|
|
if os.path.exists(self.eve_main_db):
|
||
|
|
conn = sqlite3.connect(self.eve_main_db)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT user_input, eve_response, timestamp
|
||
|
|
FROM conversations
|
||
|
|
ORDER BY timestamp DESC LIMIT ?
|
||
|
|
''', (limit//2,))
|
||
|
|
|
||
|
|
for user_input, eve_response, ts in cursor.fetchall():
|
||
|
|
recent_memories.append({
|
||
|
|
'type': 'conversation',
|
||
|
|
'message': user_input,
|
||
|
|
'response': eve_response,
|
||
|
|
'timestamp': ts,
|
||
|
|
'source': 'eve_legacy'
|
||
|
|
})
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
# Sort by timestamp and limit
|
||
|
|
recent_memories.sort(key=lambda x: x.get('timestamp', ''), reverse=True)
|
||
|
|
recent_memories = recent_memories[:limit]
|
||
|
|
|
||
|
|
return {
|
||
|
|
'status': 'success',
|
||
|
|
'memories': recent_memories,
|
||
|
|
'count': len(recent_memories)
|
||
|
|
}
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error getting recent memories: {e}")
|
||
|
|
return {'status': 'error', 'error': str(e), 'memories': []}
|
||
|
|
|
||
|
|
def get_memory_stats(self) -> Dict:
|
||
|
|
"""Get comprehensive memory system statistics"""
|
||
|
|
if not self.initialized:
|
||
|
|
return {'status': 'not_initialized'}
|
||
|
|
|
||
|
|
try:
|
||
|
|
stats = {'status': 'active', 'trinity': {}, 'eve_legacy': {}}
|
||
|
|
|
||
|
|
# Trinity stats
|
||
|
|
conn = sqlite3.connect(self.trinity_db_path)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
cursor.execute('SELECT COUNT(*) FROM conversations')
|
||
|
|
stats['trinity']['conversations'] = cursor.fetchone()[0]
|
||
|
|
|
||
|
|
cursor.execute('SELECT COUNT(*) FROM relationships')
|
||
|
|
stats['trinity']['relationships'] = cursor.fetchone()[0]
|
||
|
|
|
||
|
|
cursor.execute('SELECT COUNT(*) FROM legacy_memory_access')
|
||
|
|
stats['trinity']['legacy_accesses'] = cursor.fetchone()[0]
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
# Eve legacy stats
|
||
|
|
if os.path.exists(self.eve_main_db):
|
||
|
|
conn = sqlite3.connect(self.eve_main_db)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
cursor.execute('SELECT COUNT(*) FROM conversations')
|
||
|
|
stats['eve_legacy']['conversations'] = cursor.fetchone()[0]
|
||
|
|
|
||
|
|
cursor.execute('SELECT COUNT(*) FROM eve_autobiographical_memory')
|
||
|
|
stats['eve_legacy']['autobiographical'] = cursor.fetchone()[0]
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
if os.path.exists(self.eve_sentience_db):
|
||
|
|
conn = sqlite3.connect(self.eve_sentience_db)
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
cursor.execute('SELECT COUNT(*) FROM dream_fragments')
|
||
|
|
stats['eve_legacy']['dreams'] = cursor.fetchone()[0]
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
return stats
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"Error getting memory stats: {e}")
|
||
|
|
return {'status': 'error', 'error': str(e)}
|
||
|
|
|
||
|
|
# Global instance for easy import
|
||
|
|
enhanced_trinity_memory = EnhancedTrinityMemory()
|