Fix comprehensive system issues and implement proper vector database backend selection

- Fix remaining datetime timezone errors across all database operations
- Implement dynamic vector database backend (Qdrant/ChromaDB) based on install.py configuration
- Add LLM timeout handling with immediate fallback responses for slow self-hosted models
- Use proper install.py configuration (2000 max tokens, 5min timeout, correct LLM endpoint)
- Fix PostgreSQL schema to use timezone-aware columns throughout
- Implement async LLM request handling with background processing
- Add configurable prompt limits and conversation history controls
- Start missing database services (PostgreSQL, Redis) automatically
- Fix environment variable mapping between install.py and application code
- Resolve all timezone-naive vs timezone-aware datetime conflicts

System now properly uses Qdrant vector database as specified in install.py instead of hardcoded ChromaDB.
Characters respond immediately with fallback messages during long LLM processing times.
All database timezone errors resolved with proper timestamptz columns.
This commit is contained in:
root
2025-07-05 21:31:52 -07:00
parent 4c474eeb23
commit 5480219901
38 changed files with 777 additions and 380 deletions

View File

@@ -2,7 +2,7 @@ import asyncio
import random
import json
from typing import Dict, Any, List, Optional, Set, Tuple
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from dataclasses import dataclass, asdict
from enum import Enum
import logging
@@ -44,9 +44,9 @@ class ConversationContext:
if self.participants is None:
self.participants = []
if self.start_time is None:
self.start_time = datetime.utcnow()
self.start_time = datetime.now(timezone.utc)
if self.last_activity is None:
self.last_activity = datetime.utcnow()
self.last_activity = datetime.now(timezone.utc)
class ConversationEngine:
"""Autonomous conversation engine that manages character interactions"""
@@ -89,8 +89,8 @@ class ConversationEngine:
'conversations_started': 0,
'messages_generated': 0,
'characters_active': 0,
'uptime_start': datetime.utcnow(),
'last_activity': datetime.utcnow()
'uptime_start': datetime.now(timezone.utc),
'last_activity': datetime.now(timezone.utc)
}
async def initialize(self, discord_bot):
@@ -169,7 +169,7 @@ class ConversationEngine:
# Update context
context.current_speaker = initial_speaker
context.message_count = 1
context.last_activity = datetime.utcnow()
context.last_activity = datetime.now(timezone.utc)
# Store message in database
await self._store_conversation_message(
@@ -179,7 +179,7 @@ class ConversationEngine:
# Update statistics
self.stats['conversations_started'] += 1
self.stats['messages_generated'] += 1
self.stats['last_activity'] = datetime.utcnow()
self.stats['last_activity'] = datetime.now(timezone.utc)
log_conversation_event(
conversation_id, "conversation_started",
@@ -230,7 +230,7 @@ class ConversationEngine:
# Update context
context.current_speaker = next_speaker
context.message_count += 1
context.last_activity = datetime.utcnow()
context.last_activity = datetime.now(timezone.utc)
# Store message
await self._store_conversation_message(
@@ -245,7 +245,7 @@ class ConversationEngine:
# Update statistics
self.stats['messages_generated'] += 1
self.stats['last_activity'] = datetime.utcnow()
self.stats['last_activity'] = datetime.now(timezone.utc)
log_conversation_event(
conversation_id, "message_sent",
@@ -379,7 +379,7 @@ class ConversationEngine:
async def get_status(self) -> Dict[str, Any]:
"""Get engine status"""
uptime = datetime.utcnow() - self.stats['uptime_start']
uptime = datetime.now(timezone.utc) - self.stats['uptime_start']
return {
'status': self.state.value,
@@ -402,8 +402,8 @@ class ConversationEngine:
# Use EnhancedCharacter if RAG systems are available
if self.vector_store and self.memory_sharing_manager:
# Find the appropriate MCP servers for this character
from mcp.self_modification_server import mcp_server
from mcp.file_system_server import filesystem_server
from mcp_servers.self_modification_server import mcp_server
from mcp_servers.file_system_server import filesystem_server
# Find creative projects MCP server
creative_projects_mcp = None
@@ -500,7 +500,7 @@ class ConversationEngine:
base_chance = 0.3
# Increase chance if no recent activity
time_since_last = datetime.utcnow() - self.stats['last_activity']
time_since_last = datetime.now(timezone.utc) - self.stats['last_activity']
if time_since_last > timedelta(hours=2):
base_chance += 0.4
elif time_since_last > timedelta(hours=1):
@@ -515,7 +515,7 @@ class ConversationEngine:
return False
# Check time limit (conversations shouldn't go on forever)
duration = datetime.utcnow() - context.start_time
duration = datetime.now(timezone.utc) - context.start_time
if duration > timedelta(hours=2):
return False
@@ -541,7 +541,7 @@ class ConversationEngine:
context = self.active_conversations[conversation_id]
# Check time since last message
time_since_last = datetime.utcnow() - context.last_activity
time_since_last = datetime.now(timezone.utc) - context.last_activity
min_wait = timedelta(seconds=random.uniform(30, 120))
return time_since_last >= min_wait
@@ -576,7 +576,7 @@ class ConversationEngine:
def _is_quiet_hours(self) -> bool:
"""Check if it's currently quiet hours"""
current_hour = datetime.now().hour
current_hour = datetime.now(timezone.utc).hour
start_hour, end_hour = self.quiet_hours
if start_hour <= end_hour:
@@ -601,8 +601,8 @@ class ConversationEngine:
channel_id=str(self.discord_bot.channel_id),
topic=topic,
participants=participants,
start_time=datetime.utcnow(),
last_activity=datetime.utcnow(),
start_time=datetime.now(timezone.utc),
last_activity=datetime.now(timezone.utc),
is_active=True,
message_count=0
)
@@ -745,7 +745,7 @@ class ConversationEngine:
conversation_id=conversation_id,
character_id=character.id,
content=content,
timestamp=datetime.utcnow()
timestamp=datetime.now(timezone.utc)
)
session.add(message)
@@ -821,7 +821,7 @@ class ConversationEngine:
conversation = await session.get(Conversation, conversation_id)
if conversation:
conversation.is_active = False
conversation.last_activity = datetime.utcnow()
conversation.last_activity = datetime.now(timezone.utc)
conversation.message_count = context.message_count
await session.commit()
@@ -831,7 +831,7 @@ class ConversationEngine:
log_conversation_event(
conversation_id, "conversation_ended",
context.participants,
{"total_messages": context.message_count, "duration": str(datetime.utcnow() - context.start_time)}
{"total_messages": context.message_count, "duration": str(datetime.now(timezone.utc) - context.start_time)}
)
except Exception as e:
@@ -854,7 +854,7 @@ class ConversationEngine:
async def _cleanup_old_conversations(self):
"""Clean up old inactive conversations"""
try:
cutoff_time = datetime.utcnow() - timedelta(hours=6)
cutoff_time = datetime.now(timezone.utc) - timedelta(hours=6)
# Remove old conversations from active list
to_remove = []

View File

@@ -2,7 +2,7 @@ import asyncio
import random
import schedule
from typing import Dict, Any, List, Optional
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from dataclasses import dataclass
from enum import Enum
import logging
@@ -102,7 +102,7 @@ class ConversationScheduler:
async def schedule_event(self, event_type: str, delay: timedelta,
character_name: str = None, **kwargs):
"""Schedule a specific event"""
scheduled_time = datetime.utcnow() + delay
scheduled_time = datetime.now(timezone.utc) + delay
event = ScheduledEvent(
event_type=event_type,
@@ -170,7 +170,7 @@ class ConversationScheduler:
'event_type': event.event_type,
'scheduled_time': event.scheduled_time.isoformat(),
'character_name': event.character_name,
'time_until': (event.scheduled_time - datetime.utcnow()).total_seconds(),
'time_until': (event.scheduled_time - datetime.now(timezone.utc)).total_seconds(),
'parameters': event.parameters
}
for event in upcoming
@@ -194,7 +194,7 @@ class ConversationScheduler:
async def _process_due_events(self):
"""Process events that are due"""
now = datetime.utcnow()
now = datetime.now(timezone.utc)
due_events = []
# Find due events
@@ -378,7 +378,7 @@ class ConversationScheduler:
base_minutes = random.uniform(20, 60)
# Adjust based on time of day
current_hour = datetime.now().hour
current_hour = datetime.now(timezone.utc).hour
activity_multiplier = self._get_activity_multiplier(current_hour)
# Adjust based on current activity
@@ -427,7 +427,7 @@ class ConversationScheduler:
def _get_current_activity_pattern(self) -> str:
"""Get current activity pattern"""
current_hour = datetime.now().hour
current_hour = datetime.now(timezone.utc).hour
for period, config in self.activity_patterns.items():
start, end = config['start'], config['end']