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:
@@ -1,7 +1,7 @@
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Dict, List, Any, Optional, Set
|
||||
from datetime import datetime, timedelta, date
|
||||
from datetime import datetime, timedelta, timezone, date
|
||||
from dataclasses import dataclass, asdict
|
||||
from pathlib import Path
|
||||
import aiofiles
|
||||
@@ -51,7 +51,7 @@ class ScheduledEvent:
|
||||
|
||||
def __post_init__(self):
|
||||
if self.created_at is None:
|
||||
self.created_at = datetime.utcnow()
|
||||
self.created_at = datetime.now(timezone.utc)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {
|
||||
@@ -224,7 +224,7 @@ class CalendarTimeAwarenessMCP:
|
||||
|
||||
# Create event
|
||||
event = ScheduledEvent(
|
||||
id=f"event_{character_name}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}",
|
||||
id=f"event_{character_name}_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}",
|
||||
character_name=character_name,
|
||||
event_type=event_type_enum,
|
||||
title=title,
|
||||
@@ -275,7 +275,7 @@ class CalendarTimeAwarenessMCP:
|
||||
) -> List[TextContent]:
|
||||
"""Get character's upcoming events"""
|
||||
try:
|
||||
now = datetime.utcnow()
|
||||
now = datetime.now(timezone.utc)
|
||||
end_time = now + timedelta(days=days_ahead)
|
||||
|
||||
upcoming_events = []
|
||||
@@ -340,7 +340,7 @@ class CalendarTimeAwarenessMCP:
|
||||
|
||||
event = self.scheduled_events[character_name][event_id]
|
||||
event.completed = True
|
||||
event.metadata["completion_time"] = datetime.utcnow().isoformat()
|
||||
event.metadata["completion_time"] = datetime.now(timezone.utc).isoformat()
|
||||
event.metadata["completion_notes"] = notes
|
||||
|
||||
await self._save_character_calendar(character_name)
|
||||
@@ -442,7 +442,7 @@ class CalendarTimeAwarenessMCP:
|
||||
|
||||
# Create milestone
|
||||
milestone = Milestone(
|
||||
id=f"milestone_{character_name}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}",
|
||||
id=f"milestone_{character_name}_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}",
|
||||
character_name=character_name,
|
||||
milestone_type=milestone_type,
|
||||
description=description,
|
||||
@@ -499,7 +499,7 @@ class CalendarTimeAwarenessMCP:
|
||||
) -> List[TextContent]:
|
||||
"""Get upcoming anniversaries and milestones"""
|
||||
try:
|
||||
now = datetime.utcnow()
|
||||
now = datetime.now(timezone.utc)
|
||||
end_time = now + timedelta(days=days_ahead)
|
||||
|
||||
upcoming_anniversaries = []
|
||||
@@ -580,7 +580,7 @@ class CalendarTimeAwarenessMCP:
|
||||
if "celebrations" not in milestone.__dict__:
|
||||
milestone.__dict__["celebrations"] = {}
|
||||
milestone.__dict__["celebrations"][celebration_key] = {
|
||||
"date": datetime.utcnow().isoformat(),
|
||||
"date": datetime.now(timezone.utc).isoformat(),
|
||||
"notes": celebration_notes
|
||||
}
|
||||
|
||||
@@ -628,7 +628,7 @@ class CalendarTimeAwarenessMCP:
|
||||
"""Get time elapsed since a specific type of event"""
|
||||
try:
|
||||
# Search through recent events
|
||||
cutoff_date = datetime.utcnow() - timedelta(days=search_days_back)
|
||||
cutoff_date = datetime.now(timezone.utc) - timedelta(days=search_days_back)
|
||||
matching_events = []
|
||||
|
||||
for event in self.scheduled_events.get(character_name, {}).values():
|
||||
@@ -665,7 +665,7 @@ class CalendarTimeAwarenessMCP:
|
||||
most_recent_description = most_recent_interaction["description"]
|
||||
|
||||
# Calculate time difference
|
||||
time_diff = datetime.utcnow() - most_recent_time
|
||||
time_diff = datetime.now(timezone.utc) - most_recent_time
|
||||
|
||||
# Format time difference
|
||||
if time_diff.days > 0:
|
||||
@@ -709,7 +709,7 @@ class CalendarTimeAwarenessMCP:
|
||||
) -> List[TextContent]:
|
||||
"""Get summary of character's activities over a time period"""
|
||||
try:
|
||||
end_date = datetime.utcnow()
|
||||
end_date = datetime.now(timezone.utc)
|
||||
start_date = end_date - timedelta(days=period_days)
|
||||
|
||||
# Get completed events in period
|
||||
@@ -783,7 +783,7 @@ class CalendarTimeAwarenessMCP:
|
||||
if character_name not in self.last_interactions:
|
||||
self.last_interactions[character_name] = {}
|
||||
|
||||
self.last_interactions[character_name][other_character] = datetime.utcnow()
|
||||
self.last_interactions[character_name][other_character] = datetime.now(timezone.utc)
|
||||
|
||||
# Save to file
|
||||
await self._save_relationship_tracking(character_name)
|
||||
@@ -834,7 +834,7 @@ class CalendarTimeAwarenessMCP:
|
||||
text=f"No recorded interactions with {other_character}"
|
||||
)]
|
||||
|
||||
time_since = datetime.utcnow() - last_interaction
|
||||
time_since = datetime.now(timezone.utc) - last_interaction
|
||||
days_since = time_since.days
|
||||
|
||||
# Determine maintenance status
|
||||
@@ -859,7 +859,7 @@ class CalendarTimeAwarenessMCP:
|
||||
# Get status for all relationships
|
||||
relationships = []
|
||||
for other_char, last_interaction in self.last_interactions.get(character_name, {}).items():
|
||||
time_since = datetime.utcnow() - last_interaction
|
||||
time_since = datetime.now(timezone.utc) - last_interaction
|
||||
days_since = time_since.days
|
||||
|
||||
if days_since <= 1:
|
||||
@@ -914,13 +914,13 @@ class CalendarTimeAwarenessMCP:
|
||||
"""Schedule relationship maintenance activity"""
|
||||
try:
|
||||
# Create relationship maintenance event
|
||||
scheduled_time = datetime.utcnow() + timedelta(days=days_from_now)
|
||||
scheduled_time = datetime.now(timezone.utc) + timedelta(days=days_from_now)
|
||||
|
||||
template = self.event_templates[EventType.RELATIONSHIP_MAINTENANCE]
|
||||
description = template["description_template"].format(target=other_character)
|
||||
|
||||
event = ScheduledEvent(
|
||||
id=f"rel_maintenance_{character_name}_{other_character}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}",
|
||||
id=f"rel_maintenance_{character_name}_{other_character}_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}",
|
||||
character_name=character_name,
|
||||
event_type=EventType.RELATIONSHIP_MAINTENANCE,
|
||||
title=f"Connect with {other_character}",
|
||||
@@ -1002,7 +1002,7 @@ class CalendarTimeAwarenessMCP:
|
||||
|
||||
events_data = {
|
||||
"events": [event.to_dict() for event in self.scheduled_events.get(character_name, {}).values()],
|
||||
"last_updated": datetime.utcnow().isoformat()
|
||||
"last_updated": datetime.now(timezone.utc).isoformat()
|
||||
}
|
||||
|
||||
async with aiofiles.open(calendar_file, 'w') as f:
|
||||
@@ -1019,7 +1019,7 @@ class CalendarTimeAwarenessMCP:
|
||||
|
||||
milestones_data = {
|
||||
"milestones": [milestone.to_dict() for milestone in self.milestones.get(character_name, {}).values()],
|
||||
"last_updated": datetime.utcnow().isoformat()
|
||||
"last_updated": datetime.now(timezone.utc).isoformat()
|
||||
}
|
||||
|
||||
async with aiofiles.open(milestones_file, 'w') as f:
|
||||
@@ -1039,7 +1039,7 @@ class CalendarTimeAwarenessMCP:
|
||||
other_char: timestamp.isoformat()
|
||||
for other_char, timestamp in self.last_interactions.get(character_name, {}).items()
|
||||
},
|
||||
"last_updated": datetime.utcnow().isoformat()
|
||||
"last_updated": datetime.now(timezone.utc).isoformat()
|
||||
}
|
||||
|
||||
async with aiofiles.open(tracking_file, 'w') as f:
|
||||
@@ -1051,7 +1051,7 @@ class CalendarTimeAwarenessMCP:
|
||||
async def _schedule_initial_events(self, character_name: str):
|
||||
"""Schedule initial automatic events for character"""
|
||||
try:
|
||||
now = datetime.utcnow()
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
# Schedule first personal reflection in 6 hours
|
||||
reflection_time = now + timedelta(hours=6)
|
||||
@@ -1120,9 +1120,9 @@ class CalendarTimeAwarenessMCP:
|
||||
next_time = completed_event.scheduled_time + timedelta(days=frequency_days)
|
||||
|
||||
# Only schedule if it's in the future
|
||||
if next_time > datetime.utcnow():
|
||||
if next_time > datetime.now(timezone.utc):
|
||||
follow_up_event = ScheduledEvent(
|
||||
id=f"followup_{completed_event.event_type.value}_{character_name}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}",
|
||||
id=f"followup_{completed_event.event_type.value}_{character_name}_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}",
|
||||
character_name=character_name,
|
||||
event_type=completed_event.event_type,
|
||||
title=completed_event.title,
|
||||
@@ -1259,7 +1259,7 @@ class CalendarTimeAwarenessMCP:
|
||||
if not last_interaction:
|
||||
return
|
||||
|
||||
days_since = (datetime.utcnow() - last_interaction).days
|
||||
days_since = (datetime.now(timezone.utc) - last_interaction).days
|
||||
|
||||
# Auto-schedule maintenance if overdue and not already scheduled
|
||||
if days_since >= 7:
|
||||
|
||||
@@ -7,7 +7,7 @@ import asyncio
|
||||
import json
|
||||
import logging
|
||||
from typing import Dict, List, Any, Optional, Sequence
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from mcp.server import Server
|
||||
from mcp.server.models import InitializationOptions
|
||||
@@ -397,7 +397,7 @@ class CreativeProjectsMCPServer:
|
||||
pending_invitations = []
|
||||
for invitation in self.creative_manager.pending_invitations.values():
|
||||
if invitation.invitee == self.current_character and invitation.status == "pending":
|
||||
if datetime.utcnow() <= invitation.expires_at:
|
||||
if datetime.now(timezone.utc) <= invitation.expires_at:
|
||||
pending_invitations.append(invitation)
|
||||
|
||||
if not pending_invitations:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Dict, Any, List, Optional, Set
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
import aiofiles
|
||||
import hashlib
|
||||
@@ -340,7 +340,7 @@ class CharacterFileSystemMCP:
|
||||
|
||||
# Generate filename
|
||||
safe_title = "".join(c for c in title if c.isalnum() or c in (' ', '-', '_')).rstrip()
|
||||
timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S")
|
||||
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"{work_type}_{safe_title}_{timestamp}.md"
|
||||
file_path = f"creative/{filename}"
|
||||
|
||||
@@ -348,7 +348,7 @@ class CharacterFileSystemMCP:
|
||||
metadata = {
|
||||
"title": title,
|
||||
"type": work_type,
|
||||
"created": datetime.utcnow().isoformat(),
|
||||
"created": datetime.now(timezone.utc).isoformat(),
|
||||
"author": character_name,
|
||||
"tags": tags,
|
||||
"word_count": len(content.split())
|
||||
@@ -358,7 +358,7 @@ class CharacterFileSystemMCP:
|
||||
formatted_content = f"""# {title}
|
||||
|
||||
**Type:** {work_type}
|
||||
**Created:** {datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")}
|
||||
**Created:** {datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")}
|
||||
**Author:** {character_name}
|
||||
**Tags:** {', '.join(tags)}
|
||||
|
||||
@@ -385,7 +385,7 @@ class CharacterFileSystemMCP:
|
||||
content=f"Created {work_type} titled '{title}': {content}",
|
||||
memory_type=MemoryType.CREATIVE,
|
||||
character_name=character_name,
|
||||
timestamp=datetime.utcnow(),
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
importance=0.8,
|
||||
metadata={
|
||||
"work_type": work_type,
|
||||
@@ -432,7 +432,7 @@ class CharacterFileSystemMCP:
|
||||
tags = []
|
||||
|
||||
# Generate diary entry
|
||||
timestamp = datetime.utcnow()
|
||||
timestamp = datetime.now(timezone.utc)
|
||||
entry = f"""
|
||||
## {timestamp.strftime("%Y-%m-%d %H:%M:%S")}
|
||||
|
||||
@@ -519,7 +519,7 @@ class CharacterFileSystemMCP:
|
||||
existing_content = await f.read()
|
||||
|
||||
# Format contribution
|
||||
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
||||
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
||||
contribution_text = f"""
|
||||
|
||||
## Contribution by {character_name} ({timestamp})
|
||||
@@ -544,7 +544,7 @@ class CharacterFileSystemMCP:
|
||||
content=f"Contributed to {document_name}: {contribution}",
|
||||
memory_type=MemoryType.COMMUNITY,
|
||||
character_name=character_name,
|
||||
timestamp=datetime.utcnow(),
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
importance=0.7,
|
||||
metadata={
|
||||
"document": document_name,
|
||||
@@ -601,7 +601,7 @@ class CharacterFileSystemMCP:
|
||||
shared_name = f"{character_name}_{source_path.name}"
|
||||
|
||||
# Create shared file with metadata
|
||||
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
||||
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
||||
shared_content = f"""# Shared by {character_name}
|
||||
|
||||
**Original file:** {source_file_path}
|
||||
@@ -782,7 +782,7 @@ class CharacterFileSystemMCP:
|
||||
character_name=character_name,
|
||||
file_path=file_path,
|
||||
access_type=access_type,
|
||||
timestamp=datetime.utcnow(),
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
success=success
|
||||
)
|
||||
self.access_log.append(access)
|
||||
@@ -815,7 +815,7 @@ class CharacterFileSystemMCP:
|
||||
content=f"File {file_path}: {content}",
|
||||
memory_type=memory_type,
|
||||
character_name=character_name,
|
||||
timestamp=datetime.utcnow(),
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
importance=0.7,
|
||||
metadata={
|
||||
"source": "file_system",
|
||||
@@ -836,13 +836,13 @@ class CharacterFileSystemMCP:
|
||||
"""Create initial files for a new character"""
|
||||
try:
|
||||
# Create initial diary entry
|
||||
diary_file = char_dir / "diary" / f"{datetime.utcnow().strftime('%Y_%m')}_diary.md"
|
||||
diary_file = char_dir / "diary" / f"{datetime.now(timezone.utc).strftime('%Y_%m')}_diary.md"
|
||||
if not diary_file.exists():
|
||||
initial_diary = f"""# {character_name}'s Digital Diary
|
||||
|
||||
Welcome to my personal digital space. This is where I record my thoughts, experiences, and reflections.
|
||||
|
||||
## {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}
|
||||
## {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')}
|
||||
|
||||
**Mood:** curious
|
||||
**Tags:** beginning, digital_life
|
||||
|
||||
@@ -6,7 +6,7 @@ Enables characters to autonomously share memories with trusted friends
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import Dict, List, Any, Optional, Sequence
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import json
|
||||
|
||||
from mcp.server.models import InitializationOptions
|
||||
@@ -414,7 +414,7 @@ class MemorySharingMCPServer:
|
||||
response = f"📬 **{len(pending_requests)} Pending Memory Share Request(s)**\n\n"
|
||||
|
||||
for i, request in enumerate(pending_requests, 1):
|
||||
expires_in = request.expires_at - datetime.utcnow()
|
||||
expires_in = request.expires_at - datetime.now(timezone.utc)
|
||||
expires_days = expires_in.days
|
||||
|
||||
response += f"**{i}. Request from {request.requesting_character}**\n"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Dict, Any, List, Optional, Union
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
import aiofiles
|
||||
from dataclasses import dataclass, asdict
|
||||
@@ -140,7 +140,7 @@ class SelfModificationMCPServer:
|
||||
new_value=new_personality,
|
||||
reason=reason,
|
||||
confidence=confidence,
|
||||
timestamp=datetime.utcnow()
|
||||
timestamp=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
# Apply to database
|
||||
@@ -211,7 +211,7 @@ class SelfModificationMCPServer:
|
||||
goals_data = {
|
||||
"goals": new_goals,
|
||||
"previous_goals": current_goals,
|
||||
"updated_at": datetime.utcnow().isoformat(),
|
||||
"updated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"reason": reason,
|
||||
"confidence": confidence
|
||||
}
|
||||
@@ -282,7 +282,7 @@ class SelfModificationMCPServer:
|
||||
new_value=new_style,
|
||||
reason=reason,
|
||||
confidence=confidence,
|
||||
timestamp=datetime.utcnow()
|
||||
timestamp=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
# Apply to database
|
||||
@@ -354,13 +354,13 @@ class SelfModificationMCPServer:
|
||||
current_rules = json.loads(content)
|
||||
|
||||
# Add new rule
|
||||
rule_id = f"{memory_type}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}"
|
||||
rule_id = f"{memory_type}_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}"
|
||||
current_rules[rule_id] = {
|
||||
"memory_type": memory_type,
|
||||
"importance_weight": importance_weight,
|
||||
"retention_days": retention_days,
|
||||
"description": rule_description,
|
||||
"created_at": datetime.utcnow().isoformat(),
|
||||
"created_at": datetime.now(timezone.utc).isoformat(),
|
||||
"confidence": confidence,
|
||||
"active": True
|
||||
}
|
||||
@@ -521,7 +521,7 @@ class SelfModificationMCPServer:
|
||||
async def get_modification_limits(character_name: str) -> List[TextContent]:
|
||||
"""Get current modification limits and usage"""
|
||||
try:
|
||||
today = datetime.utcnow().date().isoformat()
|
||||
today = datetime.now(timezone.utc).date().isoformat()
|
||||
|
||||
usage = self.daily_modifications.get(character_name, {}).get(today, {})
|
||||
|
||||
@@ -571,7 +571,7 @@ class SelfModificationMCPServer:
|
||||
}
|
||||
|
||||
# Check daily limits
|
||||
today = datetime.utcnow().date().isoformat()
|
||||
today = datetime.now(timezone.utc).date().isoformat()
|
||||
if character_name not in self.daily_modifications:
|
||||
self.daily_modifications[character_name] = {}
|
||||
if today not in self.daily_modifications[character_name]:
|
||||
@@ -605,7 +605,7 @@ class SelfModificationMCPServer:
|
||||
|
||||
async def _track_modification(self, character_name: str, modification_type: str):
|
||||
"""Track modification usage for daily limits"""
|
||||
today = datetime.utcnow().date().isoformat()
|
||||
today = datetime.now(timezone.utc).date().isoformat()
|
||||
|
||||
if character_name not in self.daily_modifications:
|
||||
self.daily_modifications[character_name] = {}
|
||||
|
||||
Reference in New Issue
Block a user