superlocalmemory 2.6.0 → 2.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ SuperLocalMemory V2 - Learning System (v2.7)
4
+ Copyright (c) 2026 Varun Pratap Bhardwaj
5
+ Licensed under MIT License
6
+
7
+ Repository: https://github.com/varun369/SuperLocalMemoryV2
8
+ Author: Varun Pratap Bhardwaj (Solution Architect)
9
+
10
+ NOTICE: This software is protected by MIT License.
11
+ Attribution must be preserved in all copies or derivatives.
12
+ """
13
+
14
+ """
15
+ Learning System — Feature detection and graceful import.
16
+
17
+ This module detects available dependencies and exposes feature flags
18
+ that the rest of the system uses to enable/disable learning features.
19
+
20
+ Design principle: If ANY import fails, the entire learning system
21
+ degrades gracefully to v2.6 behavior. Core memory operations are
22
+ NEVER affected by learning system failures.
23
+
24
+ Dependencies (all optional):
25
+ lightgbm>=4.0.0 — Learning-to-Rank re-ranker
26
+ scipy>=1.9.0 — Statistical functions (temporal decay, KDE)
27
+ """
28
+
29
+ import logging
30
+ from pathlib import Path
31
+
32
+ logger = logging.getLogger("superlocalmemory.learning")
33
+
34
+ # ============================================================================
35
+ # Feature Detection
36
+ # ============================================================================
37
+
38
+ # Check LightGBM availability (required for ML ranking)
39
+ try:
40
+ import lightgbm # noqa: F401
41
+ HAS_LIGHTGBM = True
42
+ LIGHTGBM_VERSION = lightgbm.__version__
43
+ except ImportError:
44
+ HAS_LIGHTGBM = False
45
+ LIGHTGBM_VERSION = None
46
+
47
+ # Check SciPy availability (required for statistical functions)
48
+ try:
49
+ import scipy # noqa: F401
50
+ HAS_SCIPY = True
51
+ SCIPY_VERSION = scipy.__version__
52
+ except ImportError:
53
+ HAS_SCIPY = False
54
+ SCIPY_VERSION = None
55
+
56
+ # Check scikit-learn availability (already in core, but verify)
57
+ try:
58
+ import sklearn # noqa: F401
59
+ HAS_SKLEARN = True
60
+ except ImportError:
61
+ HAS_SKLEARN = False
62
+
63
+ # ============================================================================
64
+ # Composite Feature Flags
65
+ # ============================================================================
66
+
67
+ # ML ranking requires LightGBM
68
+ ML_RANKING_AVAILABLE = HAS_LIGHTGBM
69
+
70
+ # Full learning requires LightGBM + SciPy
71
+ FULL_LEARNING_AVAILABLE = HAS_LIGHTGBM and HAS_SCIPY
72
+
73
+ # Rule-based ranking works with zero optional deps
74
+ RULE_BASED_RANKING_AVAILABLE = True
75
+
76
+ # ============================================================================
77
+ # Paths
78
+ # ============================================================================
79
+
80
+ MEMORY_DIR = Path.home() / ".claude-memory"
81
+ LEARNING_DB_PATH = MEMORY_DIR / "learning.db"
82
+ MEMORY_DB_PATH = MEMORY_DIR / "memory.db"
83
+ MODELS_DIR = MEMORY_DIR / "models"
84
+
85
+ # ============================================================================
86
+ # Module-level lazy imports
87
+ # ============================================================================
88
+
89
+ # These are imported lazily to avoid circular imports and to allow
90
+ # individual module failures without breaking the whole system.
91
+
92
+ _learning_db = None
93
+ _adaptive_ranker = None
94
+ _feedback_collector = None
95
+ _engagement_tracker = None
96
+
97
+
98
+ def get_learning_db():
99
+ """Get or create the LearningDB singleton."""
100
+ global _learning_db
101
+ if _learning_db is None:
102
+ try:
103
+ from .learning_db import LearningDB
104
+ _learning_db = LearningDB()
105
+ except Exception as e:
106
+ logger.warning("Failed to initialize LearningDB: %s", e)
107
+ return None
108
+ return _learning_db
109
+
110
+
111
+ def get_adaptive_ranker():
112
+ """Get or create the AdaptiveRanker singleton."""
113
+ global _adaptive_ranker
114
+ if _adaptive_ranker is None:
115
+ try:
116
+ from .adaptive_ranker import AdaptiveRanker
117
+ _adaptive_ranker = AdaptiveRanker()
118
+ except Exception as e:
119
+ logger.warning("Failed to initialize AdaptiveRanker: %s", e)
120
+ return None
121
+ return _adaptive_ranker
122
+
123
+
124
+ def get_feedback_collector():
125
+ """Get or create the FeedbackCollector singleton."""
126
+ global _feedback_collector
127
+ if _feedback_collector is None:
128
+ try:
129
+ from .feedback_collector import FeedbackCollector
130
+ _feedback_collector = FeedbackCollector()
131
+ except Exception as e:
132
+ logger.warning("Failed to initialize FeedbackCollector: %s", e)
133
+ return None
134
+ return _feedback_collector
135
+
136
+
137
+ def get_engagement_tracker():
138
+ """Get or create the EngagementTracker singleton."""
139
+ global _engagement_tracker
140
+ if _engagement_tracker is None:
141
+ try:
142
+ from .engagement_tracker import EngagementTracker
143
+ _engagement_tracker = EngagementTracker()
144
+ except Exception as e:
145
+ logger.warning("Failed to initialize EngagementTracker: %s", e)
146
+ return None
147
+ return _engagement_tracker
148
+
149
+
150
+ def get_status() -> dict:
151
+ """Return learning system status for diagnostics."""
152
+ status = {
153
+ "learning_available": FULL_LEARNING_AVAILABLE,
154
+ "ml_ranking_available": ML_RANKING_AVAILABLE,
155
+ "rule_based_available": RULE_BASED_RANKING_AVAILABLE,
156
+ "dependencies": {
157
+ "lightgbm": {
158
+ "installed": HAS_LIGHTGBM,
159
+ "version": LIGHTGBM_VERSION,
160
+ },
161
+ "scipy": {
162
+ "installed": HAS_SCIPY,
163
+ "version": SCIPY_VERSION,
164
+ },
165
+ "sklearn": {
166
+ "installed": HAS_SKLEARN,
167
+ },
168
+ },
169
+ "paths": {
170
+ "learning_db": str(LEARNING_DB_PATH),
171
+ "models_dir": str(MODELS_DIR),
172
+ },
173
+ }
174
+
175
+ # Add learning DB stats if available
176
+ ldb = get_learning_db()
177
+ if ldb:
178
+ try:
179
+ status["learning_db_stats"] = ldb.get_stats()
180
+ except Exception:
181
+ status["learning_db_stats"] = None
182
+
183
+ return status
184
+
185
+
186
+ # Log feature availability on import
187
+ if FULL_LEARNING_AVAILABLE:
188
+ logger.info(
189
+ "Learning system available: LightGBM %s, SciPy %s",
190
+ LIGHTGBM_VERSION, SCIPY_VERSION
191
+ )
192
+ elif ML_RANKING_AVAILABLE:
193
+ logger.info(
194
+ "Partial learning: LightGBM %s available, SciPy missing",
195
+ LIGHTGBM_VERSION
196
+ )
197
+ else:
198
+ logger.info(
199
+ "Learning dependencies not installed. "
200
+ "Install with: pip3 install -r requirements-learning.txt"
201
+ )