Circular Import Fix: UnifiedMemoryManager
Problem
WARNING: Intelligent Model Router not available
Could not import real UnifiedMemoryManager: cannot import name 'UnifiedMemoryManager'
from partially initialized module 'atles.unified_memory_manager'
(most likely due to a circular import) (D:\.atles\atles_app\atles\unified_memory_manager.py)
Memory system will not function properly!
Root Cause Analysis
The circular import occurs because:
atles_desktop_pyqt.pyimportsintelligent_model_routerat module level (line 30)ConversationMemoryManager(in same file) importsunified_memory_managerat module level (line 210)- When Python tries to import these modules, it creates a circular dependency chain:
atles_desktop_pyqt.pyβintelligent_model_routerβ (some module) βunified_memory_manageratles_desktop_pyqt.pyβConversationMemoryManagerβunified_memory_managerunified_memory_managerβmemory_integrationβ (possibly back to something that imports router)
Solutions (Multiple Approaches)
Solution 1: Lazy Import in ConversationMemoryManager (RECOMMENDED)
Move the import of UnifiedMemoryManager inside the __init__ method or use lazy import pattern.
Current Code:
# In ConversationMemoryManager.__init__
from atles.unified_memory_manager import UnifiedMemoryManager, get_unified_memory
Fixed Code:
# Import moved inside try block, already done, but need to ensure it's truly lazy
Solution 2: Defer Router Import (RECOMMENDED)
Move the router import to be lazy/conditional, only importing when actually needed.
Current Code:
# At top of atles_desktop_pyqt.py
try:
from atles.intelligent_model_router import IntelligentModelRouter, ModelType, TaskType
from atles.router_performance_monitor import RouterPerformanceMonitor
ROUTER_AVAILABLE = True
except ImportError:
ROUTER_AVAILABLE = False
print("WARNING: Intelligent Model Router not available")
Fixed Code:
# Use lazy import pattern - import only when needed
ROUTER_AVAILABLE = None # Will be set on first use
def _get_router_imports():
"""Lazy import of router components"""
global ROUTER_AVAILABLE
if ROUTER_AVAILABLE is None:
try:
from atles.intelligent_model_router import IntelligentModelRouter, ModelType, TaskType
from atles.router_performance_monitor import RouterPerformanceMonitor
ROUTER_AVAILABLE = True
return IntelligentModelRouter, ModelType, TaskType, RouterPerformanceMonitor
except ImportError as e:
ROUTER_AVAILABLE = False
print(f"WARNING: Intelligent Model Router not available: {e}")
return None, None, None, None
elif ROUTER_AVAILABLE:
from atles.intelligent_model_router import IntelligentModelRouter, ModelType, TaskType
from atles.router_performance_monitor import RouterPerformanceMonitor
return IntelligentModelRouter, ModelType, TaskType, RouterPerformanceMonitor
else:
return None, None, None, None
Solution 3: Use TYPE_CHECKING Guard
Use TYPE_CHECKING to avoid runtime imports for type hints.
Implementation:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from atles.intelligent_model_router import IntelligentModelRouter
from atles.unified_memory_manager import UnifiedMemoryManager
Solution 4: Break Circular Dependency with Import Inside Function
Ensure all imports of UnifiedMemoryManager happen inside functions, not at module level.
Current Issue:
ConversationMemoryManager.__init__imports at method level (good)- But if
ConversationMemoryManagerclass is defined/imported at module load time, it might trigger issues
Fix:
- Ensure the import is truly inside
__init__and wrapped in try/except - Add better error handling
Solution 5: Use sys.modules Check (DEFENSIVE)
Add a check to prevent re-import during circular import:
def safe_import_unified_memory():
"""Safely import UnifiedMemoryManager, handling circular imports"""
import sys
# Check if module is already being imported
if 'atles.unified_memory_manager' in sys.modules:
module = sys.modules['atles.unified_memory_manager']
if hasattr(module, 'UnifiedMemoryManager'):
return module.UnifiedMemoryManager, module.get_unified_memory
# Safe import
try:
from atles.unified_memory_manager import UnifiedMemoryManager, get_unified_memory
return UnifiedMemoryManager, get_unified_memory
except (ImportError, AttributeError) as e:
# Module might be partially initialized
import time
time.sleep(0.01) # Brief delay
try:
from atles.unified_memory_manager import UnifiedMemoryManager, get_unified_memory
return UnifiedMemoryManager, get_unified_memory
except (ImportError, AttributeError):
return None, None
Recommended Implementation Plan
- Immediate Fix: Use Solution 2 (Lazy Router Import) - This breaks the top-level import cycle
- Secondary Fix: Ensure Solution 1 is properly implemented (lazy import in ConversationMemoryManager)
- Defensive Fix: Add Solution 5 as a fallback
Implementation Status β
Fix 1: Lazy Router Import (IMPLEMENTED)
File: atles_app/atles_desktop_pyqt.py
- Changed router imports from module-level to lazy function
_get_router_imports() - Router classes are only imported when actually needed (in
ATLESCommunicationThread.__init__) - This breaks the circular dependency at the top level
Before:
# Module-level import (causes circular dependency)
from atles.intelligent_model_router import IntelligentModelRouter, ModelType, TaskType
from atles.router_performance_monitor import RouterPerformanceMonitor
After:
# Lazy import function
def _get_router_imports():
"""Lazy import of router components to avoid circular dependencies."""
global ROUTER_AVAILABLE, _router_classes
if ROUTER_AVAILABLE is None:
try:
from atles.intelligent_model_router import IntelligentModelRouter, ModelType, TaskType
from atles.router_performance_monitor import RouterPerformanceMonitor
ROUTER_AVAILABLE = True
_router_classes = (IntelligentModelRouter, ModelType, TaskType, RouterPerformanceMonitor)
return _router_classes
except ImportError as e:
ROUTER_AVAILABLE = False
print(f"WARNING: Intelligent Model Router not available: {e}")
return (None, None, None, None)
# ... rest of function
Fix 2: Retry Logic for Memory Import (IMPLEMENTED)
File: atles_app/atles_desktop_pyqt.py - ConversationMemoryManager.__init__
- Added retry logic with delay to handle partially initialized modules
- Better error messages for circular import detection
- Graceful fallback if import fails
Key Changes:
- Retry up to 3 times with 50ms delay between attempts
- Detects circular import errors specifically
- Provides clear warning messages
Fix 3: Missing Import (FIXED)
- Added
import shutilto fix linter error
Testing
After implementing fixes:
- β Restart the application
- β Check that router imports successfully (no circular import error)
- β Check that memory system initializes correctly
- β Verify no circular import warnings
Expected Behavior:
- Router should import successfully when first used
- Memory system should initialize without "partially initialized module" errors
- No warnings about circular imports
Files Modified
- β
atles_app/atles_desktop_pyqt.py- Lines 28-59: Changed router import to lazy function
- Lines 225-277: Added retry logic for memory import
- Line 21: Added
import shutil - Lines 588-597: Updated router initialization to use lazy import
How It Works
- At Module Load: Router imports are deferred (no top-level import)
- When Router Needed:
_get_router_imports()is called, imports happen then - Memory Import: Retry logic handles partially initialized modules
- Result: Circular dependency broken, both systems can initialize independently
Verification
To verify the fix works:
- Start the desktop app
- Check console output - should see:
ATLES Intelligent Model Router initialized INFO: Using Unified Episodic & Semantic Memory System - Should NOT see:
WARNING: Circular import detected with UnifiedMemoryManager Could not import real UnifiedMemoryManager: cannot import name 'UnifiedMemoryManager' from partially initialized module