@cmdoss/memwal-sdk 0.6.2 → 0.8.0

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.
Files changed (247) hide show
  1. package/ARCHITECTURE.md +547 -547
  2. package/BENCHMARKS.md +238 -238
  3. package/README.md +310 -181
  4. package/dist/ai-sdk/tools.d.ts +2 -2
  5. package/dist/ai-sdk/tools.js +2 -2
  6. package/dist/client/ClientMemoryManager.js +2 -2
  7. package/dist/client/ClientMemoryManager.js.map +1 -1
  8. package/dist/client/PersonalDataWallet.d.ts.map +1 -1
  9. package/dist/client/SimplePDWClient.d.ts +29 -1
  10. package/dist/client/SimplePDWClient.d.ts.map +1 -1
  11. package/dist/client/SimplePDWClient.js +45 -13
  12. package/dist/client/SimplePDWClient.js.map +1 -1
  13. package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
  14. package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
  15. package/dist/client/namespaces/MemoryNamespace.d.ts +31 -0
  16. package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
  17. package/dist/client/namespaces/MemoryNamespace.js +272 -39
  18. package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
  19. package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
  20. package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
  21. package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts +12 -2
  22. package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
  23. package/dist/client/namespaces/consolidated/BlockchainNamespace.js +62 -4
  24. package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
  25. package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +67 -2
  26. package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
  27. package/dist/client/namespaces/consolidated/StorageNamespace.js +549 -16
  28. package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
  29. package/dist/config/ConfigurationHelper.js +61 -61
  30. package/dist/config/defaults.js +2 -2
  31. package/dist/config/defaults.js.map +1 -1
  32. package/dist/graph/GraphService.js +21 -21
  33. package/dist/graph/GraphService.js.map +1 -1
  34. package/dist/index.d.ts +3 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/infrastructure/seal/EncryptionService.d.ts +9 -5
  39. package/dist/infrastructure/seal/EncryptionService.d.ts.map +1 -1
  40. package/dist/infrastructure/seal/EncryptionService.js +37 -15
  41. package/dist/infrastructure/seal/EncryptionService.js.map +1 -1
  42. package/dist/infrastructure/seal/SealService.d.ts +13 -5
  43. package/dist/infrastructure/seal/SealService.d.ts.map +1 -1
  44. package/dist/infrastructure/seal/SealService.js +36 -34
  45. package/dist/infrastructure/seal/SealService.js.map +1 -1
  46. package/dist/langchain/createPDWRAG.js +30 -30
  47. package/dist/retrieval/MemoryDecryptionPipeline.d.ts.map +1 -1
  48. package/dist/retrieval/MemoryDecryptionPipeline.js +2 -1
  49. package/dist/retrieval/MemoryDecryptionPipeline.js.map +1 -1
  50. package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
  51. package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
  52. package/dist/retrieval/MemoryRetrievalService.js +44 -4
  53. package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
  54. package/dist/services/CapabilityService.d.ts.map +1 -1
  55. package/dist/services/CapabilityService.js +30 -14
  56. package/dist/services/CapabilityService.js.map +1 -1
  57. package/dist/services/CrossContextPermissionService.d.ts.map +1 -1
  58. package/dist/services/CrossContextPermissionService.js +9 -7
  59. package/dist/services/CrossContextPermissionService.js.map +1 -1
  60. package/dist/services/EmbeddingService.d.ts +28 -1
  61. package/dist/services/EmbeddingService.d.ts.map +1 -1
  62. package/dist/services/EmbeddingService.js +54 -0
  63. package/dist/services/EmbeddingService.js.map +1 -1
  64. package/dist/services/EncryptionService.d.ts.map +1 -1
  65. package/dist/services/EncryptionService.js +6 -5
  66. package/dist/services/EncryptionService.js.map +1 -1
  67. package/dist/services/GeminiAIService.js +309 -309
  68. package/dist/services/IndexManager.d.ts +5 -1
  69. package/dist/services/IndexManager.d.ts.map +1 -1
  70. package/dist/services/IndexManager.js +17 -40
  71. package/dist/services/IndexManager.js.map +1 -1
  72. package/dist/services/QueryService.js +1 -1
  73. package/dist/services/QueryService.js.map +1 -1
  74. package/dist/services/StorageService.d.ts +11 -0
  75. package/dist/services/StorageService.d.ts.map +1 -1
  76. package/dist/services/StorageService.js +73 -10
  77. package/dist/services/StorageService.js.map +1 -1
  78. package/dist/services/TransactionService.d.ts +20 -0
  79. package/dist/services/TransactionService.d.ts.map +1 -1
  80. package/dist/services/TransactionService.js +43 -0
  81. package/dist/services/TransactionService.js.map +1 -1
  82. package/dist/services/ViewService.js +2 -2
  83. package/dist/services/ViewService.js.map +1 -1
  84. package/dist/services/storage/QuiltBatchManager.d.ts +101 -1
  85. package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
  86. package/dist/services/storage/QuiltBatchManager.js +410 -20
  87. package/dist/services/storage/QuiltBatchManager.js.map +1 -1
  88. package/dist/services/storage/index.d.ts +1 -1
  89. package/dist/services/storage/index.d.ts.map +1 -1
  90. package/dist/services/storage/index.js.map +1 -1
  91. package/dist/utils/LRUCache.d.ts +106 -0
  92. package/dist/utils/LRUCache.d.ts.map +1 -0
  93. package/dist/utils/LRUCache.js +281 -0
  94. package/dist/utils/LRUCache.js.map +1 -0
  95. package/dist/utils/index.d.ts +1 -0
  96. package/dist/utils/index.d.ts.map +1 -1
  97. package/dist/utils/index.js +2 -0
  98. package/dist/utils/index.js.map +1 -1
  99. package/dist/utils/memoryIndexOnChain.d.ts +212 -0
  100. package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
  101. package/dist/utils/memoryIndexOnChain.js +312 -0
  102. package/dist/utils/memoryIndexOnChain.js.map +1 -0
  103. package/dist/utils/rebuildIndexNode.d.ts +29 -0
  104. package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
  105. package/dist/utils/rebuildIndexNode.js +366 -98
  106. package/dist/utils/rebuildIndexNode.js.map +1 -1
  107. package/dist/vector/HnswWasmService.d.ts +20 -5
  108. package/dist/vector/HnswWasmService.d.ts.map +1 -1
  109. package/dist/vector/HnswWasmService.js +73 -40
  110. package/dist/vector/HnswWasmService.js.map +1 -1
  111. package/dist/vector/IHnswService.d.ts +10 -1
  112. package/dist/vector/IHnswService.d.ts.map +1 -1
  113. package/dist/vector/IHnswService.js.map +1 -1
  114. package/dist/vector/NodeHnswService.d.ts +16 -0
  115. package/dist/vector/NodeHnswService.d.ts.map +1 -1
  116. package/dist/vector/NodeHnswService.js +84 -5
  117. package/dist/vector/NodeHnswService.js.map +1 -1
  118. package/dist/vector/createHnswService.d.ts +1 -1
  119. package/dist/vector/createHnswService.js +1 -1
  120. package/dist/vector/index.d.ts +1 -1
  121. package/dist/vector/index.js +1 -1
  122. package/package.json +157 -157
  123. package/src/access/PermissionService.ts +635 -635
  124. package/src/aggregation/AggregationService.ts +389 -389
  125. package/src/ai-sdk/PDWVectorStore.ts +715 -715
  126. package/src/ai-sdk/index.ts +65 -65
  127. package/src/ai-sdk/tools.ts +460 -460
  128. package/src/ai-sdk/types.ts +404 -404
  129. package/src/batch/BatchManager.ts +597 -597
  130. package/src/batch/BatchingService.ts +429 -429
  131. package/src/batch/MemoryProcessingCache.ts +492 -492
  132. package/src/batch/index.ts +30 -30
  133. package/src/browser.ts +200 -200
  134. package/src/client/ClientMemoryManager.ts +987 -987
  135. package/src/client/PersonalDataWallet.ts +345 -345
  136. package/src/client/SimplePDWClient.ts +1289 -1222
  137. package/src/client/factory.ts +154 -154
  138. package/src/client/namespaces/AnalyticsNamespace.ts +377 -377
  139. package/src/client/namespaces/BatchNamespace.ts +356 -356
  140. package/src/client/namespaces/CacheNamespace.ts +123 -123
  141. package/src/client/namespaces/CapabilityNamespace.ts +217 -217
  142. package/src/client/namespaces/ClassifyNamespace.ts +169 -169
  143. package/src/client/namespaces/ContextNamespace.ts +297 -297
  144. package/src/client/namespaces/EmbeddingsNamespace.ts +99 -99
  145. package/src/client/namespaces/EncryptionNamespace.ts +221 -221
  146. package/src/client/namespaces/GraphNamespace.ts +468 -468
  147. package/src/client/namespaces/IndexNamespace.ts +361 -361
  148. package/src/client/namespaces/MemoryNamespace.ts +1422 -1135
  149. package/src/client/namespaces/PermissionsNamespace.ts +254 -254
  150. package/src/client/namespaces/PipelineNamespace.ts +220 -220
  151. package/src/client/namespaces/SearchNamespace.ts +1049 -1049
  152. package/src/client/namespaces/StorageNamespace.ts +458 -458
  153. package/src/client/namespaces/TxNamespace.ts +260 -260
  154. package/src/client/namespaces/WalletNamespace.ts +243 -243
  155. package/src/client/namespaces/consolidated/AINamespace.ts +449 -449
  156. package/src/client/namespaces/consolidated/BlockchainNamespace.ts +607 -546
  157. package/src/client/namespaces/consolidated/SecurityNamespace.ts +648 -648
  158. package/src/client/namespaces/consolidated/StorageNamespace.ts +1141 -497
  159. package/src/client/namespaces/consolidated/index.ts +39 -39
  160. package/src/client/signers/KeypairSigner.ts +108 -108
  161. package/src/client/signers/UnifiedSigner.ts +110 -110
  162. package/src/client/signers/WalletAdapterSigner.ts +159 -159
  163. package/src/client/signers/index.ts +26 -26
  164. package/src/config/ConfigurationHelper.ts +412 -412
  165. package/src/config/defaults.ts +51 -51
  166. package/src/config/index.ts +8 -8
  167. package/src/config/validation.ts +70 -70
  168. package/src/core/index.ts +14 -14
  169. package/src/core/interfaces/IService.ts +307 -307
  170. package/src/core/interfaces/index.ts +8 -8
  171. package/src/core/types/capability.ts +297 -297
  172. package/src/core/types/index.ts +870 -870
  173. package/src/core/types/wallet.ts +270 -270
  174. package/src/core/types.ts +9 -9
  175. package/src/core/wallet.ts +222 -222
  176. package/src/embedding/index.ts +19 -19
  177. package/src/embedding/types.ts +357 -357
  178. package/src/errors/index.ts +602 -602
  179. package/src/errors/recovery.ts +461 -461
  180. package/src/errors/validation.ts +567 -567
  181. package/src/generated/pdw/capability.ts +319 -319
  182. package/src/graph/GraphService.ts +887 -887
  183. package/src/graph/KnowledgeGraphManager.ts +728 -728
  184. package/src/graph/index.ts +25 -25
  185. package/src/index.ts +498 -474
  186. package/src/infrastructure/index.ts +22 -22
  187. package/src/infrastructure/seal/EncryptionService.ts +628 -603
  188. package/src/infrastructure/seal/SealService.ts +613 -615
  189. package/src/infrastructure/seal/index.ts +9 -9
  190. package/src/infrastructure/sui/BlockchainManager.ts +627 -627
  191. package/src/infrastructure/sui/SuiService.ts +888 -888
  192. package/src/infrastructure/sui/index.ts +9 -9
  193. package/src/infrastructure/walrus/StorageManager.ts +604 -604
  194. package/src/infrastructure/walrus/WalrusStorageService.ts +612 -612
  195. package/src/infrastructure/walrus/index.ts +9 -9
  196. package/src/langchain/PDWEmbeddings.ts +145 -145
  197. package/src/langchain/PDWVectorStore.ts +456 -456
  198. package/src/langchain/createPDWRAG.ts +303 -303
  199. package/src/langchain/index.ts +47 -47
  200. package/src/permissions/ConsentRepository.browser.ts +249 -249
  201. package/src/permissions/ConsentRepository.ts +364 -364
  202. package/src/pipeline/MemoryPipeline.ts +862 -862
  203. package/src/pipeline/PipelineManager.ts +683 -683
  204. package/src/pipeline/index.ts +26 -26
  205. package/src/retrieval/AdvancedSearchService.ts +629 -629
  206. package/src/retrieval/MemoryAnalyticsService.ts +711 -711
  207. package/src/retrieval/MemoryDecryptionPipeline.ts +825 -824
  208. package/src/retrieval/MemoryRetrievalService.ts +904 -830
  209. package/src/retrieval/index.ts +42 -42
  210. package/src/services/BatchService.ts +352 -352
  211. package/src/services/CapabilityService.ts +464 -448
  212. package/src/services/ClassifierService.ts +465 -465
  213. package/src/services/CrossContextPermissionService.ts +486 -484
  214. package/src/services/EmbeddingService.ts +771 -706
  215. package/src/services/EncryptionService.ts +712 -711
  216. package/src/services/GeminiAIService.ts +753 -753
  217. package/src/services/IndexManager.ts +977 -1004
  218. package/src/services/MemoryIndexService.ts +1003 -1003
  219. package/src/services/MemoryService.ts +369 -369
  220. package/src/services/QueryService.ts +890 -890
  221. package/src/services/StorageService.ts +1182 -1111
  222. package/src/services/TransactionService.ts +838 -790
  223. package/src/services/VectorService.ts +462 -462
  224. package/src/services/ViewService.ts +484 -484
  225. package/src/services/index.ts +25 -25
  226. package/src/services/storage/BlobAttributesManager.ts +333 -333
  227. package/src/services/storage/KnowledgeGraphManager.ts +425 -425
  228. package/src/services/storage/MemorySearchManager.ts +387 -387
  229. package/src/services/storage/QuiltBatchManager.ts +1130 -660
  230. package/src/services/storage/WalrusMetadataManager.ts +268 -268
  231. package/src/services/storage/WalrusStorageManager.ts +287 -287
  232. package/src/services/storage/index.ts +57 -52
  233. package/src/types/index.ts +13 -13
  234. package/src/utils/LRUCache.ts +378 -0
  235. package/src/utils/index.ts +76 -68
  236. package/src/utils/memoryIndexOnChain.ts +507 -0
  237. package/src/utils/rebuildIndex.ts +290 -290
  238. package/src/utils/rebuildIndexNode.ts +771 -424
  239. package/src/vector/BrowserHnswIndexService.ts +758 -758
  240. package/src/vector/HnswWasmService.ts +731 -679
  241. package/src/vector/IHnswService.ts +233 -224
  242. package/src/vector/NodeHnswService.ts +833 -735
  243. package/src/vector/VectorManager.ts +478 -478
  244. package/src/vector/createHnswService.ts +135 -135
  245. package/src/vector/index.ts +56 -56
  246. package/src/wallet/ContextWalletService.ts +656 -656
  247. package/src/wallet/MainWalletService.ts +317 -317
@@ -1,891 +1,891 @@
1
- /**
2
- * QueryService - Advanced Memory Query Operations
3
- *
4
- * High-level query service providing sophisticated memory search capabilities
5
- * similar to backend's MemoryQueryService. Combines vector search, semantic search,
6
- * knowledge graph traversal, and complex filtering operations.
7
- *
8
- * This service coordinates between MemoryIndexService, GraphService, and other
9
- * components to provide unified query capabilities.
10
- */
11
-
12
- import { MemoryIndexService, type MemorySearchQuery, type MemorySearchResult } from './MemoryIndexService';
13
- import { EmbeddingService, type EmbeddingResult, type EmbeddingOptions } from './EmbeddingService';
14
- import { StorageService } from './StorageService';
15
- import { GraphService, type KnowledgeGraph } from '../graph/GraphService';
16
-
17
- export interface AdvancedMemoryQuery {
18
- // Basic query parameters
19
- query?: string;
20
- userAddress: string;
21
-
22
- // Query types
23
- queryType?: 'vector' | 'semantic' | 'keyword' | 'hybrid' | 'graph' | 'temporal' | 'analytical';
24
-
25
- // Vector search parameters
26
- vector?: number[];
27
- k?: number;
28
- threshold?: number;
29
-
30
- // Content filters
31
- categories?: string[];
32
- topics?: string[];
33
- tags?: string[];
34
- contentTypes?: string[];
35
-
36
- // Temporal filters
37
- dateRange?: {
38
- start?: Date;
39
- end?: Date;
40
- };
41
-
42
- // Importance and relevance
43
- importanceRange?: {
44
- min?: number;
45
- max?: number;
46
- };
47
- minRelevanceScore?: number;
48
-
49
- // Graph traversal (for graph queries)
50
- graphQuery?: {
51
- entityTypes?: string[];
52
- relationshipTypes?: string[];
53
- maxHops?: number;
54
- seedEntities?: string[];
55
- };
56
-
57
- // Result options
58
- includeContent?: boolean;
59
- includeGraph?: boolean;
60
- includeAnalytics?: boolean;
61
- limit?: number;
62
- offset?: number;
63
-
64
- // Advanced options
65
- boostRecent?: boolean;
66
- boostImportant?: boolean;
67
- diversifyResults?: boolean;
68
- }
69
-
70
- export interface QueryResult {
71
- memories: MemorySearchResult[];
72
- totalCount: number;
73
- queryTime: number;
74
- queryType: string;
75
-
76
- // Optional additional data
77
- graphResults?: {
78
- entities: any[];
79
- relationships: any[];
80
- };
81
- analytics?: {
82
- categoryDistribution: Record<string, number>;
83
- importanceDistribution: Record<number, number>;
84
- temporalDistribution: Record<string, number>;
85
- averageRelevance: number;
86
- };
87
- suggestions?: string[];
88
- }
89
-
90
- export interface SemanticSearchOptions {
91
- expandQuery?: boolean;
92
- includeRelated?: boolean;
93
- semanticThreshold?: number;
94
- maxExpansions?: number;
95
- }
96
-
97
- export interface AnalyticalQuery {
98
- userAddress: string;
99
- analysis: 'trends' | 'categories' | 'importance' | 'temporal' | 'relationships' | 'insights';
100
- timeframe?: {
101
- start?: Date;
102
- end?: Date;
103
- granularity?: 'day' | 'week' | 'month' | 'year';
104
- };
105
- filters?: {
106
- categories?: string[];
107
- importanceRange?: { min?: number; max?: number };
108
- };
109
- }
110
-
111
- /**
112
- * Advanced query service providing unified memory search capabilities
113
- */
114
- export class QueryService {
115
- private memoryIndexService?: MemoryIndexService;
116
- private embeddingService?: EmbeddingService;
117
- private storageService?: StorageService;
118
- private graphService?: GraphService;
119
-
120
- constructor(
121
- memoryIndexService?: MemoryIndexService,
122
- embeddingService?: EmbeddingService,
123
- storageService?: StorageService,
124
- graphService?: GraphService
125
- ) {
126
- this.memoryIndexService = memoryIndexService;
127
- this.embeddingService = embeddingService;
128
- this.storageService = storageService;
129
- this.graphService = graphService;
130
-
131
- console.log('✅ QueryService initialized');
132
- console.log(` Memory Index: ${!!memoryIndexService ? 'available' : 'not available'}`);
133
- console.log(` Embeddings: ${!!embeddingService ? 'available' : 'not available'}`);
134
- if (embeddingService) {
135
- const stats = embeddingService.getStats();
136
- console.log(` Model: ${stats.model}, Dimensions: ${stats.dimensions}`);
137
- }
138
- console.log(` Storage: ${!!storageService ? 'available' : 'not available'}`);
139
- console.log(` Knowledge Graph: ${!!graphService ? 'available' : 'not available'}`);
140
- }
141
-
142
- /**
143
- * Get QueryService statistics including EmbeddingService stats
144
- */
145
- getStats(): {
146
- memoryIndexAvailable: boolean;
147
- embeddingServiceAvailable: boolean;
148
- storageAvailable: boolean;
149
- graphServiceAvailable: boolean;
150
- embeddingStats?: ReturnType<EmbeddingService['getStats']>;
151
- } {
152
- return {
153
- memoryIndexAvailable: !!this.memoryIndexService,
154
- embeddingServiceAvailable: !!this.embeddingService,
155
- storageAvailable: !!this.storageService,
156
- graphServiceAvailable: !!this.graphService,
157
- embeddingStats: this.embeddingService?.getStats()
158
- };
159
- }
160
-
161
- /**
162
- * Initialize services (can be called after construction)
163
- */
164
- initialize(
165
- memoryIndexService: MemoryIndexService,
166
- embeddingService: EmbeddingService,
167
- storageService?: StorageService,
168
- graphService?: GraphService
169
- ) {
170
- this.memoryIndexService = memoryIndexService;
171
- this.embeddingService = embeddingService;
172
- this.storageService = storageService;
173
- this.graphService = graphService;
174
-
175
- console.log('✅ QueryService: All services connected');
176
- }
177
-
178
- /**
179
- * Execute advanced memory query with multiple search strategies
180
- */
181
- async query(query: AdvancedMemoryQuery): Promise<QueryResult> {
182
- const startTime = Date.now();
183
-
184
- try {
185
- console.log(`🔍 Executing ${query.queryType || 'hybrid'} query for user ${query.userAddress}`);
186
- console.log(` Query: "${query.query || 'vector/filter search'}"`);
187
- console.log(` Limit: ${query.limit || 'unlimited'}`);
188
-
189
- let results: MemorySearchResult[] = [];
190
- let totalCount = 0;
191
- let graphResults: any = null;
192
- let analytics: any = null;
193
-
194
- switch (query.queryType) {
195
- case 'vector':
196
- results = await this.vectorSearch(query);
197
- break;
198
-
199
- case 'semantic':
200
- results = await this.semanticSearch(query);
201
- break;
202
-
203
- case 'keyword':
204
- results = await this.keywordSearch(query);
205
- break;
206
-
207
- case 'graph':
208
- const graphQuery = await this.graphSearch(query);
209
- results = graphQuery.memories;
210
- graphResults = graphQuery.graphResults;
211
- break;
212
-
213
- case 'temporal':
214
- results = await this.temporalSearch(query);
215
- break;
216
-
217
- case 'analytical':
218
- const analyticalResults = await this.analyticalSearch(query);
219
- results = analyticalResults.memories;
220
- analytics = analyticalResults.analytics;
221
- break;
222
-
223
- case 'hybrid':
224
- default:
225
- results = await this.hybridSearch(query);
226
- break;
227
- }
228
-
229
- // Apply post-processing
230
- results = this.postProcessResults(results, query);
231
- totalCount = results.length;
232
-
233
- // Apply pagination
234
- if (query.offset || query.limit) {
235
- const start = query.offset || 0;
236
- const end = query.limit ? start + query.limit : undefined;
237
- results = results.slice(start, end);
238
- }
239
-
240
- // Generate analytics if requested
241
- if (query.includeAnalytics && !analytics) {
242
- analytics = this.generateAnalytics(results);
243
- }
244
-
245
- const queryTime = Date.now() - startTime;
246
-
247
- console.log(`✅ Query completed in ${queryTime}ms`);
248
- console.log(` Found: ${totalCount} total results`);
249
- console.log(` Returned: ${results.length} results`);
250
-
251
- return {
252
- memories: results,
253
- totalCount,
254
- queryTime,
255
- queryType: query.queryType || 'hybrid',
256
- graphResults,
257
- analytics
258
- };
259
-
260
- } catch (error) {
261
- console.error('❌ Query failed:', error);
262
- throw error;
263
- }
264
- }
265
-
266
- /**
267
- * Pure vector similarity search
268
- */
269
- async vectorSearch(query: AdvancedMemoryQuery): Promise<MemorySearchResult[]> {
270
- if (!this.memoryIndexService) {
271
- throw new Error('MemoryIndexService not available for vector search');
272
- }
273
-
274
- const searchQuery: MemorySearchQuery = {
275
- query: query.query,
276
- vector: query.vector,
277
- userAddress: query.userAddress,
278
- k: query.k || 20,
279
- threshold: query.threshold || 0.5,
280
- categories: query.categories,
281
- dateRange: query.dateRange,
282
- importanceRange: query.importanceRange,
283
- tags: query.tags,
284
- includeContent: query.includeContent
285
- };
286
-
287
- return await this.memoryIndexService.searchMemories(searchQuery);
288
- }
289
-
290
- /**
291
- * Semantic search with query expansion and context understanding
292
- */
293
- async semanticSearch(
294
- query: AdvancedMemoryQuery,
295
- options: SemanticSearchOptions = {}
296
- ): Promise<MemorySearchResult[]> {
297
- if (!this.embeddingService || !this.memoryIndexService) {
298
- throw new Error('EmbeddingService and MemoryIndexService required for semantic search');
299
- }
300
-
301
- console.log('🧠 Performing semantic search with AI understanding');
302
-
303
- let searchTerms = [query.query || ''];
304
- let queryEmbedding: number[] | undefined;
305
-
306
- // Generate query embedding for semantic analysis
307
- if (query.query) {
308
- try {
309
- const embeddingResult = await this.embeddingService.embedText({
310
- text: query.query,
311
- type: 'query',
312
- taskType: 'RETRIEVAL_QUERY'
313
- });
314
- queryEmbedding = embeddingResult.vector;
315
- console.log(` Generated query embedding: ${embeddingResult.dimension}D in ${embeddingResult.processingTime}ms`);
316
- } catch (error) {
317
- console.warn(' Failed to generate query embedding:', error);
318
- }
319
- }
320
-
321
- // Query expansion using embeddings (enhanced semantic understanding)
322
- if (options.expandQuery && query.query && queryEmbedding) {
323
- console.log(' Query expansion: Using semantic similarity for expanded search');
324
- // Note: Query expansion via similar terms would require a term database
325
- // For now, we use the embedding directly for semantic matching
326
- }
327
-
328
- // Execute multiple searches and combine results
329
- const allResults: MemorySearchResult[] = [];
330
-
331
- for (const term of searchTerms) {
332
- if (term.trim()) {
333
- const results = await this.vectorSearch({
334
- ...query,
335
- query: term,
336
- vector: queryEmbedding, // Use pre-computed embedding for efficiency
337
- k: (query.k || 10) * 2 // Get more results for merging
338
- });
339
- allResults.push(...results);
340
- }
341
- }
342
-
343
- // Deduplicate and re-rank results
344
- const uniqueResults = this.deduplicateResults(allResults);
345
- return this.rerankSemanticResults(uniqueResults, query);
346
- }
347
-
348
- /**
349
- * Keyword-based search in metadata and content
350
- */
351
- async keywordSearch(query: AdvancedMemoryQuery): Promise<MemorySearchResult[]> {
352
- if (!this.memoryIndexService) {
353
- throw new Error('MemoryIndexService not available for keyword search');
354
- }
355
-
356
- console.log('🔤 Performing keyword search in metadata');
357
-
358
- // Get all memories for the user
359
- const allMemories = await this.memoryIndexService.getUserMemories(
360
- query.userAddress,
361
- {
362
- categories: query.categories,
363
- dateRange: query.dateRange,
364
- importanceRange: query.importanceRange
365
- }
366
- );
367
-
368
- // Filter by keywords
369
- const keywords = query.query?.toLowerCase().split(/\s+/) || [];
370
- const results: MemorySearchResult[] = [];
371
-
372
- for (const memory of allMemories) {
373
- let relevanceScore = 0;
374
- const searchableText = [
375
- memory.metadata.category,
376
- memory.metadata.topic,
377
- JSON.stringify(memory.metadata.customMetadata || {})
378
- ].join(' ').toLowerCase();
379
-
380
- // Score based on keyword matches
381
- for (const keyword of keywords) {
382
- const matches = (searchableText.match(new RegExp(keyword, 'g')) || []).length;
383
- relevanceScore += matches * 0.2;
384
- }
385
-
386
- if (relevanceScore > 0) {
387
- results.push({
388
- ...memory,
389
- similarity: Math.min(1.0, relevanceScore),
390
- relevanceScore: Math.min(1.0, relevanceScore)
391
- });
392
- }
393
- }
394
-
395
- return results.sort((a, b) => b.relevanceScore - a.relevanceScore);
396
- }
397
-
398
- /**
399
- * Knowledge graph-based search
400
- */
401
- async graphSearch(query: AdvancedMemoryQuery): Promise<{
402
- memories: MemorySearchResult[];
403
- graphResults: any;
404
- }> {
405
- if (!this.storageService || !query.graphQuery) {
406
- throw new Error('StorageService and graphQuery required for graph search');
407
- }
408
-
409
- console.log('🕸️ Performing knowledge graph search');
410
-
411
- // Execute graph query
412
- const graphResults = await this.storageService.searchKnowledgeGraph(
413
- query.userAddress,
414
- {
415
- entityTypes: query.graphQuery.entityTypes,
416
- relationshipTypes: query.graphQuery.relationshipTypes,
417
- searchText: query.query,
418
- maxHops: query.graphQuery.maxHops,
419
- limit: query.limit
420
- }
421
- );
422
-
423
- // Convert graph results to memory results
424
- // This would need to map entities/relationships back to source memories
425
- const memories: MemorySearchResult[] = [];
426
-
427
- // TODO: Implement graph result to memory mapping
428
- console.log(` Found ${graphResults.entities.length} entities, ${graphResults.relationships.length} relationships`);
429
-
430
- return {
431
- memories,
432
- graphResults
433
- };
434
- }
435
-
436
- /**
437
- * Time-based search with temporal patterns
438
- */
439
- async temporalSearch(query: AdvancedMemoryQuery): Promise<MemorySearchResult[]> {
440
- if (!this.memoryIndexService) {
441
- throw new Error('MemoryIndexService not available for temporal search');
442
- }
443
-
444
- console.log('⏰ Performing temporal search');
445
-
446
- return await this.memoryIndexService.getUserMemories(
447
- query.userAddress,
448
- {
449
- categories: query.categories,
450
- dateRange: query.dateRange,
451
- importanceRange: query.importanceRange,
452
- limit: query.limit
453
- }
454
- );
455
- }
456
-
457
- /**
458
- * Analytical search for insights and patterns
459
- */
460
- async analyticalSearch(query: AdvancedMemoryQuery): Promise<{
461
- memories: MemorySearchResult[];
462
- analytics: any;
463
- }> {
464
- if (!this.memoryIndexService) {
465
- throw new Error('MemoryIndexService not available for analytical search');
466
- }
467
-
468
- console.log('📊 Performing analytical search');
469
-
470
- const memories = await this.memoryIndexService.getUserMemories(query.userAddress);
471
- const analytics = this.generateAnalytics(memories);
472
-
473
- // Filter memories based on analytical criteria
474
- let filteredMemories = memories;
475
-
476
- if (query.importanceRange) {
477
- filteredMemories = filteredMemories.filter(m => {
478
- const importance = m.metadata.importance || 5;
479
- return (!query.importanceRange!.min || importance >= query.importanceRange!.min) &&
480
- (!query.importanceRange!.max || importance <= query.importanceRange!.max);
481
- });
482
- }
483
-
484
- return {
485
- memories: filteredMemories,
486
- analytics
487
- };
488
- }
489
-
490
- /**
491
- * Hybrid search combining multiple strategies
492
- */
493
- async hybridSearch(query: AdvancedMemoryQuery): Promise<MemorySearchResult[]> {
494
- console.log('🔄 Performing hybrid search (vector + semantic + keyword)');
495
-
496
- const results: MemorySearchResult[] = [];
497
-
498
- // Vector search (if we have embeddings)
499
- if (query.query && this.embeddingService && this.memoryIndexService) {
500
- try {
501
- const vectorResults = await this.vectorSearch({
502
- ...query,
503
- k: (query.k || 10) * 2
504
- });
505
- results.push(...vectorResults.map(r => ({ ...r, source: 'vector' as any })));
506
- } catch (error) {
507
- console.warn('Vector search failed in hybrid mode:', error);
508
- }
509
- }
510
-
511
- // Keyword search
512
- if (query.query && this.memoryIndexService) {
513
- try {
514
- const keywordResults = await this.keywordSearch({
515
- ...query,
516
- k: (query.k || 10) * 2
517
- });
518
- results.push(...keywordResults.map(r => ({ ...r, source: 'keyword' as any })));
519
- } catch (error) {
520
- console.warn('Keyword search failed in hybrid mode:', error);
521
- }
522
- }
523
-
524
- // Deduplicate and merge results
525
- const uniqueResults = this.deduplicateResults(results);
526
-
527
- // Re-rank with hybrid scoring
528
- return this.rerankHybridResults(uniqueResults, query);
529
- }
530
-
531
- /**
532
- * Execute analytical queries for insights
533
- */
534
- async analyzeMemories(query: AnalyticalQuery): Promise<any> {
535
- if (!this.memoryIndexService) {
536
- throw new Error('MemoryIndexService not available for analysis');
537
- }
538
-
539
- console.log(`📈 Analyzing memories: ${query.analysis} for user ${query.userAddress}`);
540
-
541
- const stats = this.memoryIndexService.getIndexStats(query.userAddress);
542
-
543
- switch (query.analysis) {
544
- case 'trends':
545
- return this.analyzeTrends(query, stats);
546
-
547
- case 'categories':
548
- return this.analyzeCategories(query, stats);
549
-
550
- case 'importance':
551
- return this.analyzeImportance(query, stats);
552
-
553
- case 'temporal':
554
- return this.analyzeTemporal(query, stats);
555
-
556
- case 'relationships':
557
- return this.analyzeRelationships(query);
558
-
559
- case 'insights':
560
- return this.generateInsights(query, stats);
561
-
562
- default:
563
- throw new Error(`Unknown analysis type: ${query.analysis}`);
564
- }
565
- }
566
-
567
- // ==================== PRIVATE HELPER METHODS ====================
568
-
569
- /**
570
- * Calculate similarity between two vectors using EmbeddingService
571
- */
572
- private calculateSimilarity(vectorA: number[], vectorB: number[], metric: 'cosine' | 'euclidean' = 'cosine'): number {
573
- if (!this.embeddingService) {
574
- throw new Error('EmbeddingService required for similarity calculation');
575
- }
576
-
577
- if (metric === 'cosine') {
578
- return this.embeddingService.calculateCosineSimilarity(vectorA, vectorB);
579
- } else {
580
- const distance = this.embeddingService.calculateEuclideanDistance(vectorA, vectorB);
581
- // Convert distance to similarity (0-1 range)
582
- return 1 / (1 + distance);
583
- }
584
- }
585
-
586
- /**
587
- * Find most similar memories to a query using EmbeddingService
588
- */
589
- private async findSimilarMemories(
590
- queryVector: number[],
591
- candidateMemories: MemorySearchResult[],
592
- k: number = 10
593
- ): Promise<MemorySearchResult[]> {
594
- if (!this.embeddingService) {
595
- throw new Error('EmbeddingService required for similarity search');
596
- }
597
-
598
- // Filter memories that have embeddings
599
- const memoriesWithEmbeddings = candidateMemories.filter(m => m.embedding && m.embedding.length > 0);
600
-
601
- if (memoriesWithEmbeddings.length === 0) {
602
- console.warn('No memories with embeddings found for similarity comparison');
603
- return [];
604
- }
605
-
606
- // Extract vectors from memories
607
- const vectors = memoriesWithEmbeddings.map(m => m.embedding!);
608
-
609
- // Use EmbeddingService to find most similar
610
- const similarities = this.embeddingService.findMostSimilar(queryVector, vectors, k);
611
-
612
- // Map back to memory results with updated scores
613
- return similarities.map(sim => {
614
- const memory = memoriesWithEmbeddings[sim.index];
615
- return {
616
- ...memory,
617
- similarity: sim.similarity,
618
- relevanceScore: sim.similarity
619
- };
620
- });
621
- }
622
-
623
- /**
624
- * Batch generate embeddings for multiple texts using EmbeddingService
625
- */
626
- private async batchEmbedTexts(texts: string[], options: Omit<EmbeddingOptions, 'text'> = {}): Promise<number[][]> {
627
- if (!this.embeddingService) {
628
- throw new Error('EmbeddingService required for batch embedding');
629
- }
630
-
631
- try {
632
- const result = await this.embeddingService.embedBatch(texts, options);
633
- console.log(` Batch embedded ${texts.length} texts in ${result.totalProcessingTime}ms (${result.successCount} successful)`);
634
- return result.vectors;
635
- } catch (error) {
636
- console.error(' Batch embedding failed:', error);
637
- throw error;
638
- }
639
- }
640
-
641
- private postProcessResults(results: MemorySearchResult[], query: AdvancedMemoryQuery): MemorySearchResult[] {
642
- let processed = [...results];
643
-
644
- // Apply minimum relevance threshold
645
- if (query.minRelevanceScore) {
646
- processed = processed.filter(r => r.relevanceScore >= query.minRelevanceScore!);
647
- }
648
-
649
- // Boost recent results if requested
650
- if (query.boostRecent) {
651
- processed = this.boostRecentResults(processed);
652
- }
653
-
654
- // Boost important results if requested
655
- if (query.boostImportant) {
656
- processed = this.boostImportantResults(processed);
657
- }
658
-
659
- // Diversify results if requested
660
- if (query.diversifyResults) {
661
- processed = this.diversifyResults(processed);
662
- }
663
-
664
- return processed;
665
- }
666
-
667
- private deduplicateResults(results: MemorySearchResult[]): MemorySearchResult[] {
668
- const seen = new Set<string>();
669
- const unique: MemorySearchResult[] = [];
670
-
671
- for (const result of results) {
672
- if (!seen.has(result.memoryId)) {
673
- seen.add(result.memoryId);
674
- unique.push(result);
675
- }
676
- }
677
-
678
- return unique;
679
- }
680
-
681
- private rerankSemanticResults(results: MemorySearchResult[], query: AdvancedMemoryQuery): MemorySearchResult[] {
682
- // Enhanced semantic ranking considering context and relationships
683
- return results.sort((a, b) => {
684
- let scoreA = a.similarity * 0.4 + a.relevanceScore * 0.6;
685
- let scoreB = b.similarity * 0.4 + b.relevanceScore * 0.6;
686
-
687
- // Boost exact topic matches
688
- if (query.query && query.topics) {
689
- const queryLower = query.query.toLowerCase();
690
- if (a.metadata.topic?.toLowerCase().includes(queryLower)) scoreA += 0.2;
691
- if (b.metadata.topic?.toLowerCase().includes(queryLower)) scoreB += 0.2;
692
- }
693
-
694
- return scoreB - scoreA;
695
- });
696
- }
697
-
698
- private rerankHybridResults(results: MemorySearchResult[], query: AdvancedMemoryQuery): MemorySearchResult[] {
699
- // Hybrid ranking combining multiple signals
700
- return results.sort((a, b) => {
701
- let scoreA = a.relevanceScore;
702
- let scoreB = b.relevanceScore;
703
-
704
- // Boost by importance
705
- scoreA += (a.metadata.importance || 5) * 0.05;
706
- scoreB += (b.metadata.importance || 5) * 0.05;
707
-
708
- // Boost recent content
709
- const ageA = (Date.now() - (a.metadata.createdTimestamp || 0)) / (1000 * 60 * 60 * 24);
710
- const ageB = (Date.now() - (b.metadata.createdTimestamp || 0)) / (1000 * 60 * 60 * 24);
711
-
712
- scoreA += Math.max(0, (30 - ageA) / 30) * 0.1;
713
- scoreB += Math.max(0, (30 - ageB) / 30) * 0.1;
714
-
715
- return scoreB - scoreA;
716
- });
717
- }
718
-
719
- private boostRecentResults(results: MemorySearchResult[]): MemorySearchResult[] {
720
- const now = Date.now();
721
- return results.map(result => {
722
- const age = (now - (result.metadata.createdTimestamp || 0)) / (1000 * 60 * 60 * 24);
723
- const recencyBoost = Math.max(0, (7 - age) / 7) * 0.3; // Boost content from last 7 days
724
- return {
725
- ...result,
726
- relevanceScore: Math.min(1.0, result.relevanceScore + recencyBoost)
727
- };
728
- });
729
- }
730
-
731
- private boostImportantResults(results: MemorySearchResult[]): MemorySearchResult[] {
732
- return results.map(result => {
733
- const importance = result.metadata.importance || 5;
734
- const importanceBoost = (importance - 5) * 0.05; // Boost high importance, penalize low
735
- return {
736
- ...result,
737
- relevanceScore: Math.max(0, Math.min(1.0, result.relevanceScore + importanceBoost))
738
- };
739
- });
740
- }
741
-
742
- private diversifyResults(results: MemorySearchResult[]): MemorySearchResult[] {
743
- // Simple diversification by category
744
- const diversified: MemorySearchResult[] = [];
745
- const categoryCounts: Record<string, number> = {};
746
- const maxPerCategory = Math.max(2, Math.floor(results.length / 5));
747
-
748
- for (const result of results) {
749
- const category = result.metadata.category;
750
- if ((categoryCounts[category] || 0) < maxPerCategory) {
751
- diversified.push(result);
752
- categoryCounts[category] = (categoryCounts[category] || 0) + 1;
753
- }
754
- }
755
-
756
- // Add remaining results if we haven't reached the limit
757
- const remaining = results.filter(r => !diversified.includes(r));
758
- diversified.push(...remaining.slice(0, results.length - diversified.length));
759
-
760
- return diversified;
761
- }
762
-
763
- private generateAnalytics(results: MemorySearchResult[]): any {
764
- const categoryDist: Record<string, number> = {};
765
- const importanceDist: Record<number, number> = {};
766
- const temporalDist: Record<string, number> = {};
767
- let totalRelevance = 0;
768
-
769
- for (const result of results) {
770
- // Categories
771
- categoryDist[result.metadata.category] = (categoryDist[result.metadata.category] || 0) + 1;
772
-
773
- // Importance
774
- const importance = result.metadata.importance || 5;
775
- importanceDist[importance] = (importanceDist[importance] || 0) + 1;
776
-
777
- // Temporal (by month)
778
- const date = new Date(result.metadata.createdTimestamp || 0);
779
- const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
780
- temporalDist[monthKey] = (temporalDist[monthKey] || 0) + 1;
781
-
782
- totalRelevance += result.relevanceScore;
783
- }
784
-
785
- return {
786
- categoryDistribution: categoryDist,
787
- importanceDistribution: importanceDist,
788
- temporalDistribution: temporalDist,
789
- averageRelevance: results.length > 0 ? totalRelevance / results.length : 0
790
- };
791
- }
792
-
793
- private analyzeTrends(query: AnalyticalQuery, stats: any): any {
794
- // Analyze trends over time
795
- return {
796
- type: 'trends',
797
- totalMemories: stats.totalMemories,
798
- timeRange: {
799
- start: stats.oldestMemory,
800
- end: stats.newestMemory
801
- },
802
- // TODO: Implement detailed trend analysis
803
- trends: []
804
- };
805
- }
806
-
807
- private analyzeCategories(query: AnalyticalQuery, stats: any): any {
808
- return {
809
- type: 'categories',
810
- distribution: stats.categoryCounts,
811
- topCategories: Object.entries(stats.categoryCounts)
812
- .sort(([,a], [,b]) => (b as number) - (a as number))
813
- .slice(0, 10)
814
- };
815
- }
816
-
817
- private analyzeImportance(query: AnalyticalQuery, stats: any): any {
818
- return {
819
- type: 'importance',
820
- distribution: stats.importanceDistribution,
821
- average: stats.averageImportance,
822
- recommendations: this.generateImportanceRecommendations(stats)
823
- };
824
- }
825
-
826
- private analyzeTemporal(query: AnalyticalQuery, stats: any): any {
827
- return {
828
- type: 'temporal',
829
- timeRange: {
830
- oldest: stats.oldestMemory,
831
- newest: stats.newestMemory
832
- },
833
- // TODO: Implement temporal pattern analysis
834
- patterns: []
835
- };
836
- }
837
-
838
- private analyzeRelationships(query: AnalyticalQuery): any {
839
- // This would use GraphService if available
840
- return {
841
- type: 'relationships',
842
- // TODO: Implement relationship analysis
843
- connections: []
844
- };
845
- }
846
-
847
- private generateInsights(query: AnalyticalQuery, stats: any): any {
848
- const insights = [];
849
-
850
- // Category insights
851
- const topCategory = Object.entries(stats.categoryCounts)
852
- .sort(([,a], [,b]) => (b as number) - (a as number))[0];
853
- if (topCategory) {
854
- insights.push(`Your most common memory category is "${topCategory[0]}" with ${topCategory[1]} memories`);
855
- }
856
-
857
- // Importance insights
858
- if (stats.averageImportance < 5) {
859
- insights.push("Consider marking more important memories with higher importance ratings");
860
- }
861
-
862
- // Temporal insights
863
- if (stats.newestMemory && stats.oldestMemory) {
864
- const daysDiff = (new Date(stats.newestMemory).getTime() - new Date(stats.oldestMemory).getTime()) / (1000 * 60 * 60 * 24);
865
- insights.push(`Your memories span ${Math.round(daysDiff)} days`);
866
- }
867
-
868
- return {
869
- type: 'insights',
870
- insights,
871
- stats
872
- };
873
- }
874
-
875
- private generateImportanceRecommendations(stats: any): string[] {
876
- const recommendations = [];
877
-
878
- const lowImportanceCount = (stats.importanceDistribution[1] || 0) + (stats.importanceDistribution[2] || 0);
879
- const highImportanceCount = (stats.importanceDistribution[8] || 0) + (stats.importanceDistribution[9] || 0) + (stats.importanceDistribution[10] || 0);
880
-
881
- if (lowImportanceCount > highImportanceCount * 2) {
882
- recommendations.push("Consider reviewing low-importance memories and increasing ratings for valuable content");
883
- }
884
-
885
- if (stats.averageImportance > 8) {
886
- recommendations.push("Your memories have high average importance - consider using the full 1-10 scale for better prioritization");
887
- }
888
-
889
- return recommendations;
890
- }
1
+ /**
2
+ * QueryService - Advanced Memory Query Operations
3
+ *
4
+ * High-level query service providing sophisticated memory search capabilities
5
+ * similar to backend's MemoryQueryService. Combines vector search, semantic search,
6
+ * knowledge graph traversal, and complex filtering operations.
7
+ *
8
+ * This service coordinates between MemoryIndexService, GraphService, and other
9
+ * components to provide unified query capabilities.
10
+ */
11
+
12
+ import { MemoryIndexService, type MemorySearchQuery, type MemorySearchResult } from './MemoryIndexService';
13
+ import { EmbeddingService, type EmbeddingResult, type EmbeddingOptions } from './EmbeddingService';
14
+ import { StorageService } from './StorageService';
15
+ import { GraphService, type KnowledgeGraph } from '../graph/GraphService';
16
+
17
+ export interface AdvancedMemoryQuery {
18
+ // Basic query parameters
19
+ query?: string;
20
+ userAddress: string;
21
+
22
+ // Query types
23
+ queryType?: 'vector' | 'semantic' | 'keyword' | 'hybrid' | 'graph' | 'temporal' | 'analytical';
24
+
25
+ // Vector search parameters
26
+ vector?: number[];
27
+ k?: number;
28
+ threshold?: number;
29
+
30
+ // Content filters
31
+ categories?: string[];
32
+ topics?: string[];
33
+ tags?: string[];
34
+ contentTypes?: string[];
35
+
36
+ // Temporal filters
37
+ dateRange?: {
38
+ start?: Date;
39
+ end?: Date;
40
+ };
41
+
42
+ // Importance and relevance
43
+ importanceRange?: {
44
+ min?: number;
45
+ max?: number;
46
+ };
47
+ minRelevanceScore?: number;
48
+
49
+ // Graph traversal (for graph queries)
50
+ graphQuery?: {
51
+ entityTypes?: string[];
52
+ relationshipTypes?: string[];
53
+ maxHops?: number;
54
+ seedEntities?: string[];
55
+ };
56
+
57
+ // Result options
58
+ includeContent?: boolean;
59
+ includeGraph?: boolean;
60
+ includeAnalytics?: boolean;
61
+ limit?: number;
62
+ offset?: number;
63
+
64
+ // Advanced options
65
+ boostRecent?: boolean;
66
+ boostImportant?: boolean;
67
+ diversifyResults?: boolean;
68
+ }
69
+
70
+ export interface QueryResult {
71
+ memories: MemorySearchResult[];
72
+ totalCount: number;
73
+ queryTime: number;
74
+ queryType: string;
75
+
76
+ // Optional additional data
77
+ graphResults?: {
78
+ entities: any[];
79
+ relationships: any[];
80
+ };
81
+ analytics?: {
82
+ categoryDistribution: Record<string, number>;
83
+ importanceDistribution: Record<number, number>;
84
+ temporalDistribution: Record<string, number>;
85
+ averageRelevance: number;
86
+ };
87
+ suggestions?: string[];
88
+ }
89
+
90
+ export interface SemanticSearchOptions {
91
+ expandQuery?: boolean;
92
+ includeRelated?: boolean;
93
+ semanticThreshold?: number;
94
+ maxExpansions?: number;
95
+ }
96
+
97
+ export interface AnalyticalQuery {
98
+ userAddress: string;
99
+ analysis: 'trends' | 'categories' | 'importance' | 'temporal' | 'relationships' | 'insights';
100
+ timeframe?: {
101
+ start?: Date;
102
+ end?: Date;
103
+ granularity?: 'day' | 'week' | 'month' | 'year';
104
+ };
105
+ filters?: {
106
+ categories?: string[];
107
+ importanceRange?: { min?: number; max?: number };
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Advanced query service providing unified memory search capabilities
113
+ */
114
+ export class QueryService {
115
+ private memoryIndexService?: MemoryIndexService;
116
+ private embeddingService?: EmbeddingService;
117
+ private storageService?: StorageService;
118
+ private graphService?: GraphService;
119
+
120
+ constructor(
121
+ memoryIndexService?: MemoryIndexService,
122
+ embeddingService?: EmbeddingService,
123
+ storageService?: StorageService,
124
+ graphService?: GraphService
125
+ ) {
126
+ this.memoryIndexService = memoryIndexService;
127
+ this.embeddingService = embeddingService;
128
+ this.storageService = storageService;
129
+ this.graphService = graphService;
130
+
131
+ console.log('✅ QueryService initialized');
132
+ console.log(` Memory Index: ${!!memoryIndexService ? 'available' : 'not available'}`);
133
+ console.log(` Embeddings: ${!!embeddingService ? 'available' : 'not available'}`);
134
+ if (embeddingService) {
135
+ const stats = embeddingService.getStats();
136
+ console.log(` Model: ${stats.model}, Dimensions: ${stats.dimensions}`);
137
+ }
138
+ console.log(` Storage: ${!!storageService ? 'available' : 'not available'}`);
139
+ console.log(` Knowledge Graph: ${!!graphService ? 'available' : 'pending initialization...'}`);
140
+ }
141
+
142
+ /**
143
+ * Get QueryService statistics including EmbeddingService stats
144
+ */
145
+ getStats(): {
146
+ memoryIndexAvailable: boolean;
147
+ embeddingServiceAvailable: boolean;
148
+ storageAvailable: boolean;
149
+ graphServiceAvailable: boolean;
150
+ embeddingStats?: ReturnType<EmbeddingService['getStats']>;
151
+ } {
152
+ return {
153
+ memoryIndexAvailable: !!this.memoryIndexService,
154
+ embeddingServiceAvailable: !!this.embeddingService,
155
+ storageAvailable: !!this.storageService,
156
+ graphServiceAvailable: !!this.graphService,
157
+ embeddingStats: this.embeddingService?.getStats()
158
+ };
159
+ }
160
+
161
+ /**
162
+ * Initialize services (can be called after construction)
163
+ */
164
+ initialize(
165
+ memoryIndexService: MemoryIndexService,
166
+ embeddingService: EmbeddingService,
167
+ storageService?: StorageService,
168
+ graphService?: GraphService
169
+ ) {
170
+ this.memoryIndexService = memoryIndexService;
171
+ this.embeddingService = embeddingService;
172
+ this.storageService = storageService;
173
+ this.graphService = graphService;
174
+
175
+ console.log('✅ QueryService: All services connected');
176
+ }
177
+
178
+ /**
179
+ * Execute advanced memory query with multiple search strategies
180
+ */
181
+ async query(query: AdvancedMemoryQuery): Promise<QueryResult> {
182
+ const startTime = Date.now();
183
+
184
+ try {
185
+ console.log(`🔍 Executing ${query.queryType || 'hybrid'} query for user ${query.userAddress}`);
186
+ console.log(` Query: "${query.query || 'vector/filter search'}"`);
187
+ console.log(` Limit: ${query.limit || 'unlimited'}`);
188
+
189
+ let results: MemorySearchResult[] = [];
190
+ let totalCount = 0;
191
+ let graphResults: any = null;
192
+ let analytics: any = null;
193
+
194
+ switch (query.queryType) {
195
+ case 'vector':
196
+ results = await this.vectorSearch(query);
197
+ break;
198
+
199
+ case 'semantic':
200
+ results = await this.semanticSearch(query);
201
+ break;
202
+
203
+ case 'keyword':
204
+ results = await this.keywordSearch(query);
205
+ break;
206
+
207
+ case 'graph':
208
+ const graphQuery = await this.graphSearch(query);
209
+ results = graphQuery.memories;
210
+ graphResults = graphQuery.graphResults;
211
+ break;
212
+
213
+ case 'temporal':
214
+ results = await this.temporalSearch(query);
215
+ break;
216
+
217
+ case 'analytical':
218
+ const analyticalResults = await this.analyticalSearch(query);
219
+ results = analyticalResults.memories;
220
+ analytics = analyticalResults.analytics;
221
+ break;
222
+
223
+ case 'hybrid':
224
+ default:
225
+ results = await this.hybridSearch(query);
226
+ break;
227
+ }
228
+
229
+ // Apply post-processing
230
+ results = this.postProcessResults(results, query);
231
+ totalCount = results.length;
232
+
233
+ // Apply pagination
234
+ if (query.offset || query.limit) {
235
+ const start = query.offset || 0;
236
+ const end = query.limit ? start + query.limit : undefined;
237
+ results = results.slice(start, end);
238
+ }
239
+
240
+ // Generate analytics if requested
241
+ if (query.includeAnalytics && !analytics) {
242
+ analytics = this.generateAnalytics(results);
243
+ }
244
+
245
+ const queryTime = Date.now() - startTime;
246
+
247
+ console.log(`✅ Query completed in ${queryTime}ms`);
248
+ console.log(` Found: ${totalCount} total results`);
249
+ console.log(` Returned: ${results.length} results`);
250
+
251
+ return {
252
+ memories: results,
253
+ totalCount,
254
+ queryTime,
255
+ queryType: query.queryType || 'hybrid',
256
+ graphResults,
257
+ analytics
258
+ };
259
+
260
+ } catch (error) {
261
+ console.error('❌ Query failed:', error);
262
+ throw error;
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Pure vector similarity search
268
+ */
269
+ async vectorSearch(query: AdvancedMemoryQuery): Promise<MemorySearchResult[]> {
270
+ if (!this.memoryIndexService) {
271
+ throw new Error('MemoryIndexService not available for vector search');
272
+ }
273
+
274
+ const searchQuery: MemorySearchQuery = {
275
+ query: query.query,
276
+ vector: query.vector,
277
+ userAddress: query.userAddress,
278
+ k: query.k || 20,
279
+ threshold: query.threshold || 0.5,
280
+ categories: query.categories,
281
+ dateRange: query.dateRange,
282
+ importanceRange: query.importanceRange,
283
+ tags: query.tags,
284
+ includeContent: query.includeContent
285
+ };
286
+
287
+ return await this.memoryIndexService.searchMemories(searchQuery);
288
+ }
289
+
290
+ /**
291
+ * Semantic search with query expansion and context understanding
292
+ */
293
+ async semanticSearch(
294
+ query: AdvancedMemoryQuery,
295
+ options: SemanticSearchOptions = {}
296
+ ): Promise<MemorySearchResult[]> {
297
+ if (!this.embeddingService || !this.memoryIndexService) {
298
+ throw new Error('EmbeddingService and MemoryIndexService required for semantic search');
299
+ }
300
+
301
+ console.log('🧠 Performing semantic search with AI understanding');
302
+
303
+ let searchTerms = [query.query || ''];
304
+ let queryEmbedding: number[] | undefined;
305
+
306
+ // Generate query embedding for semantic analysis
307
+ if (query.query) {
308
+ try {
309
+ const embeddingResult = await this.embeddingService.embedText({
310
+ text: query.query,
311
+ type: 'query',
312
+ taskType: 'RETRIEVAL_QUERY'
313
+ });
314
+ queryEmbedding = embeddingResult.vector;
315
+ console.log(` Generated query embedding: ${embeddingResult.dimension}D in ${embeddingResult.processingTime}ms`);
316
+ } catch (error) {
317
+ console.warn(' Failed to generate query embedding:', error);
318
+ }
319
+ }
320
+
321
+ // Query expansion using embeddings (enhanced semantic understanding)
322
+ if (options.expandQuery && query.query && queryEmbedding) {
323
+ console.log(' Query expansion: Using semantic similarity for expanded search');
324
+ // Note: Query expansion via similar terms would require a term database
325
+ // For now, we use the embedding directly for semantic matching
326
+ }
327
+
328
+ // Execute multiple searches and combine results
329
+ const allResults: MemorySearchResult[] = [];
330
+
331
+ for (const term of searchTerms) {
332
+ if (term.trim()) {
333
+ const results = await this.vectorSearch({
334
+ ...query,
335
+ query: term,
336
+ vector: queryEmbedding, // Use pre-computed embedding for efficiency
337
+ k: (query.k || 10) * 2 // Get more results for merging
338
+ });
339
+ allResults.push(...results);
340
+ }
341
+ }
342
+
343
+ // Deduplicate and re-rank results
344
+ const uniqueResults = this.deduplicateResults(allResults);
345
+ return this.rerankSemanticResults(uniqueResults, query);
346
+ }
347
+
348
+ /**
349
+ * Keyword-based search in metadata and content
350
+ */
351
+ async keywordSearch(query: AdvancedMemoryQuery): Promise<MemorySearchResult[]> {
352
+ if (!this.memoryIndexService) {
353
+ throw new Error('MemoryIndexService not available for keyword search');
354
+ }
355
+
356
+ console.log('🔤 Performing keyword search in metadata');
357
+
358
+ // Get all memories for the user
359
+ const allMemories = await this.memoryIndexService.getUserMemories(
360
+ query.userAddress,
361
+ {
362
+ categories: query.categories,
363
+ dateRange: query.dateRange,
364
+ importanceRange: query.importanceRange
365
+ }
366
+ );
367
+
368
+ // Filter by keywords
369
+ const keywords = query.query?.toLowerCase().split(/\s+/) || [];
370
+ const results: MemorySearchResult[] = [];
371
+
372
+ for (const memory of allMemories) {
373
+ let relevanceScore = 0;
374
+ const searchableText = [
375
+ memory.metadata.category,
376
+ memory.metadata.topic,
377
+ JSON.stringify(memory.metadata.customMetadata || {})
378
+ ].join(' ').toLowerCase();
379
+
380
+ // Score based on keyword matches
381
+ for (const keyword of keywords) {
382
+ const matches = (searchableText.match(new RegExp(keyword, 'g')) || []).length;
383
+ relevanceScore += matches * 0.2;
384
+ }
385
+
386
+ if (relevanceScore > 0) {
387
+ results.push({
388
+ ...memory,
389
+ similarity: Math.min(1.0, relevanceScore),
390
+ relevanceScore: Math.min(1.0, relevanceScore)
391
+ });
392
+ }
393
+ }
394
+
395
+ return results.sort((a, b) => b.relevanceScore - a.relevanceScore);
396
+ }
397
+
398
+ /**
399
+ * Knowledge graph-based search
400
+ */
401
+ async graphSearch(query: AdvancedMemoryQuery): Promise<{
402
+ memories: MemorySearchResult[];
403
+ graphResults: any;
404
+ }> {
405
+ if (!this.storageService || !query.graphQuery) {
406
+ throw new Error('StorageService and graphQuery required for graph search');
407
+ }
408
+
409
+ console.log('🕸️ Performing knowledge graph search');
410
+
411
+ // Execute graph query
412
+ const graphResults = await this.storageService.searchKnowledgeGraph(
413
+ query.userAddress,
414
+ {
415
+ entityTypes: query.graphQuery.entityTypes,
416
+ relationshipTypes: query.graphQuery.relationshipTypes,
417
+ searchText: query.query,
418
+ maxHops: query.graphQuery.maxHops,
419
+ limit: query.limit
420
+ }
421
+ );
422
+
423
+ // Convert graph results to memory results
424
+ // This would need to map entities/relationships back to source memories
425
+ const memories: MemorySearchResult[] = [];
426
+
427
+ // TODO: Implement graph result to memory mapping
428
+ console.log(` Found ${graphResults.entities.length} entities, ${graphResults.relationships.length} relationships`);
429
+
430
+ return {
431
+ memories,
432
+ graphResults
433
+ };
434
+ }
435
+
436
+ /**
437
+ * Time-based search with temporal patterns
438
+ */
439
+ async temporalSearch(query: AdvancedMemoryQuery): Promise<MemorySearchResult[]> {
440
+ if (!this.memoryIndexService) {
441
+ throw new Error('MemoryIndexService not available for temporal search');
442
+ }
443
+
444
+ console.log('⏰ Performing temporal search');
445
+
446
+ return await this.memoryIndexService.getUserMemories(
447
+ query.userAddress,
448
+ {
449
+ categories: query.categories,
450
+ dateRange: query.dateRange,
451
+ importanceRange: query.importanceRange,
452
+ limit: query.limit
453
+ }
454
+ );
455
+ }
456
+
457
+ /**
458
+ * Analytical search for insights and patterns
459
+ */
460
+ async analyticalSearch(query: AdvancedMemoryQuery): Promise<{
461
+ memories: MemorySearchResult[];
462
+ analytics: any;
463
+ }> {
464
+ if (!this.memoryIndexService) {
465
+ throw new Error('MemoryIndexService not available for analytical search');
466
+ }
467
+
468
+ console.log('📊 Performing analytical search');
469
+
470
+ const memories = await this.memoryIndexService.getUserMemories(query.userAddress);
471
+ const analytics = this.generateAnalytics(memories);
472
+
473
+ // Filter memories based on analytical criteria
474
+ let filteredMemories = memories;
475
+
476
+ if (query.importanceRange) {
477
+ filteredMemories = filteredMemories.filter(m => {
478
+ const importance = m.metadata.importance || 5;
479
+ return (!query.importanceRange!.min || importance >= query.importanceRange!.min) &&
480
+ (!query.importanceRange!.max || importance <= query.importanceRange!.max);
481
+ });
482
+ }
483
+
484
+ return {
485
+ memories: filteredMemories,
486
+ analytics
487
+ };
488
+ }
489
+
490
+ /**
491
+ * Hybrid search combining multiple strategies
492
+ */
493
+ async hybridSearch(query: AdvancedMemoryQuery): Promise<MemorySearchResult[]> {
494
+ console.log('🔄 Performing hybrid search (vector + semantic + keyword)');
495
+
496
+ const results: MemorySearchResult[] = [];
497
+
498
+ // Vector search (if we have embeddings)
499
+ if (query.query && this.embeddingService && this.memoryIndexService) {
500
+ try {
501
+ const vectorResults = await this.vectorSearch({
502
+ ...query,
503
+ k: (query.k || 10) * 2
504
+ });
505
+ results.push(...vectorResults.map(r => ({ ...r, source: 'vector' as any })));
506
+ } catch (error) {
507
+ console.warn('Vector search failed in hybrid mode:', error);
508
+ }
509
+ }
510
+
511
+ // Keyword search
512
+ if (query.query && this.memoryIndexService) {
513
+ try {
514
+ const keywordResults = await this.keywordSearch({
515
+ ...query,
516
+ k: (query.k || 10) * 2
517
+ });
518
+ results.push(...keywordResults.map(r => ({ ...r, source: 'keyword' as any })));
519
+ } catch (error) {
520
+ console.warn('Keyword search failed in hybrid mode:', error);
521
+ }
522
+ }
523
+
524
+ // Deduplicate and merge results
525
+ const uniqueResults = this.deduplicateResults(results);
526
+
527
+ // Re-rank with hybrid scoring
528
+ return this.rerankHybridResults(uniqueResults, query);
529
+ }
530
+
531
+ /**
532
+ * Execute analytical queries for insights
533
+ */
534
+ async analyzeMemories(query: AnalyticalQuery): Promise<any> {
535
+ if (!this.memoryIndexService) {
536
+ throw new Error('MemoryIndexService not available for analysis');
537
+ }
538
+
539
+ console.log(`📈 Analyzing memories: ${query.analysis} for user ${query.userAddress}`);
540
+
541
+ const stats = this.memoryIndexService.getIndexStats(query.userAddress);
542
+
543
+ switch (query.analysis) {
544
+ case 'trends':
545
+ return this.analyzeTrends(query, stats);
546
+
547
+ case 'categories':
548
+ return this.analyzeCategories(query, stats);
549
+
550
+ case 'importance':
551
+ return this.analyzeImportance(query, stats);
552
+
553
+ case 'temporal':
554
+ return this.analyzeTemporal(query, stats);
555
+
556
+ case 'relationships':
557
+ return this.analyzeRelationships(query);
558
+
559
+ case 'insights':
560
+ return this.generateInsights(query, stats);
561
+
562
+ default:
563
+ throw new Error(`Unknown analysis type: ${query.analysis}`);
564
+ }
565
+ }
566
+
567
+ // ==================== PRIVATE HELPER METHODS ====================
568
+
569
+ /**
570
+ * Calculate similarity between two vectors using EmbeddingService
571
+ */
572
+ private calculateSimilarity(vectorA: number[], vectorB: number[], metric: 'cosine' | 'euclidean' = 'cosine'): number {
573
+ if (!this.embeddingService) {
574
+ throw new Error('EmbeddingService required for similarity calculation');
575
+ }
576
+
577
+ if (metric === 'cosine') {
578
+ return this.embeddingService.calculateCosineSimilarity(vectorA, vectorB);
579
+ } else {
580
+ const distance = this.embeddingService.calculateEuclideanDistance(vectorA, vectorB);
581
+ // Convert distance to similarity (0-1 range)
582
+ return 1 / (1 + distance);
583
+ }
584
+ }
585
+
586
+ /**
587
+ * Find most similar memories to a query using EmbeddingService
588
+ */
589
+ private async findSimilarMemories(
590
+ queryVector: number[],
591
+ candidateMemories: MemorySearchResult[],
592
+ k: number = 10
593
+ ): Promise<MemorySearchResult[]> {
594
+ if (!this.embeddingService) {
595
+ throw new Error('EmbeddingService required for similarity search');
596
+ }
597
+
598
+ // Filter memories that have embeddings
599
+ const memoriesWithEmbeddings = candidateMemories.filter(m => m.embedding && m.embedding.length > 0);
600
+
601
+ if (memoriesWithEmbeddings.length === 0) {
602
+ console.warn('No memories with embeddings found for similarity comparison');
603
+ return [];
604
+ }
605
+
606
+ // Extract vectors from memories
607
+ const vectors = memoriesWithEmbeddings.map(m => m.embedding!);
608
+
609
+ // Use EmbeddingService to find most similar
610
+ const similarities = this.embeddingService.findMostSimilar(queryVector, vectors, k);
611
+
612
+ // Map back to memory results with updated scores
613
+ return similarities.map(sim => {
614
+ const memory = memoriesWithEmbeddings[sim.index];
615
+ return {
616
+ ...memory,
617
+ similarity: sim.similarity,
618
+ relevanceScore: sim.similarity
619
+ };
620
+ });
621
+ }
622
+
623
+ /**
624
+ * Batch generate embeddings for multiple texts using EmbeddingService
625
+ */
626
+ private async batchEmbedTexts(texts: string[], options: Omit<EmbeddingOptions, 'text'> = {}): Promise<number[][]> {
627
+ if (!this.embeddingService) {
628
+ throw new Error('EmbeddingService required for batch embedding');
629
+ }
630
+
631
+ try {
632
+ const result = await this.embeddingService.embedBatch(texts, options);
633
+ console.log(` Batch embedded ${texts.length} texts in ${result.totalProcessingTime}ms (${result.successCount} successful)`);
634
+ return result.vectors;
635
+ } catch (error) {
636
+ console.error(' Batch embedding failed:', error);
637
+ throw error;
638
+ }
639
+ }
640
+
641
+ private postProcessResults(results: MemorySearchResult[], query: AdvancedMemoryQuery): MemorySearchResult[] {
642
+ let processed = [...results];
643
+
644
+ // Apply minimum relevance threshold
645
+ if (query.minRelevanceScore) {
646
+ processed = processed.filter(r => r.relevanceScore >= query.minRelevanceScore!);
647
+ }
648
+
649
+ // Boost recent results if requested
650
+ if (query.boostRecent) {
651
+ processed = this.boostRecentResults(processed);
652
+ }
653
+
654
+ // Boost important results if requested
655
+ if (query.boostImportant) {
656
+ processed = this.boostImportantResults(processed);
657
+ }
658
+
659
+ // Diversify results if requested
660
+ if (query.diversifyResults) {
661
+ processed = this.diversifyResults(processed);
662
+ }
663
+
664
+ return processed;
665
+ }
666
+
667
+ private deduplicateResults(results: MemorySearchResult[]): MemorySearchResult[] {
668
+ const seen = new Set<string>();
669
+ const unique: MemorySearchResult[] = [];
670
+
671
+ for (const result of results) {
672
+ if (!seen.has(result.memoryId)) {
673
+ seen.add(result.memoryId);
674
+ unique.push(result);
675
+ }
676
+ }
677
+
678
+ return unique;
679
+ }
680
+
681
+ private rerankSemanticResults(results: MemorySearchResult[], query: AdvancedMemoryQuery): MemorySearchResult[] {
682
+ // Enhanced semantic ranking considering context and relationships
683
+ return results.sort((a, b) => {
684
+ let scoreA = a.similarity * 0.4 + a.relevanceScore * 0.6;
685
+ let scoreB = b.similarity * 0.4 + b.relevanceScore * 0.6;
686
+
687
+ // Boost exact topic matches
688
+ if (query.query && query.topics) {
689
+ const queryLower = query.query.toLowerCase();
690
+ if (a.metadata.topic?.toLowerCase().includes(queryLower)) scoreA += 0.2;
691
+ if (b.metadata.topic?.toLowerCase().includes(queryLower)) scoreB += 0.2;
692
+ }
693
+
694
+ return scoreB - scoreA;
695
+ });
696
+ }
697
+
698
+ private rerankHybridResults(results: MemorySearchResult[], query: AdvancedMemoryQuery): MemorySearchResult[] {
699
+ // Hybrid ranking combining multiple signals
700
+ return results.sort((a, b) => {
701
+ let scoreA = a.relevanceScore;
702
+ let scoreB = b.relevanceScore;
703
+
704
+ // Boost by importance
705
+ scoreA += (a.metadata.importance || 5) * 0.05;
706
+ scoreB += (b.metadata.importance || 5) * 0.05;
707
+
708
+ // Boost recent content
709
+ const ageA = (Date.now() - (a.metadata.createdTimestamp || 0)) / (1000 * 60 * 60 * 24);
710
+ const ageB = (Date.now() - (b.metadata.createdTimestamp || 0)) / (1000 * 60 * 60 * 24);
711
+
712
+ scoreA += Math.max(0, (30 - ageA) / 30) * 0.1;
713
+ scoreB += Math.max(0, (30 - ageB) / 30) * 0.1;
714
+
715
+ return scoreB - scoreA;
716
+ });
717
+ }
718
+
719
+ private boostRecentResults(results: MemorySearchResult[]): MemorySearchResult[] {
720
+ const now = Date.now();
721
+ return results.map(result => {
722
+ const age = (now - (result.metadata.createdTimestamp || 0)) / (1000 * 60 * 60 * 24);
723
+ const recencyBoost = Math.max(0, (7 - age) / 7) * 0.3; // Boost content from last 7 days
724
+ return {
725
+ ...result,
726
+ relevanceScore: Math.min(1.0, result.relevanceScore + recencyBoost)
727
+ };
728
+ });
729
+ }
730
+
731
+ private boostImportantResults(results: MemorySearchResult[]): MemorySearchResult[] {
732
+ return results.map(result => {
733
+ const importance = result.metadata.importance || 5;
734
+ const importanceBoost = (importance - 5) * 0.05; // Boost high importance, penalize low
735
+ return {
736
+ ...result,
737
+ relevanceScore: Math.max(0, Math.min(1.0, result.relevanceScore + importanceBoost))
738
+ };
739
+ });
740
+ }
741
+
742
+ private diversifyResults(results: MemorySearchResult[]): MemorySearchResult[] {
743
+ // Simple diversification by category
744
+ const diversified: MemorySearchResult[] = [];
745
+ const categoryCounts: Record<string, number> = {};
746
+ const maxPerCategory = Math.max(2, Math.floor(results.length / 5));
747
+
748
+ for (const result of results) {
749
+ const category = result.metadata.category;
750
+ if ((categoryCounts[category] || 0) < maxPerCategory) {
751
+ diversified.push(result);
752
+ categoryCounts[category] = (categoryCounts[category] || 0) + 1;
753
+ }
754
+ }
755
+
756
+ // Add remaining results if we haven't reached the limit
757
+ const remaining = results.filter(r => !diversified.includes(r));
758
+ diversified.push(...remaining.slice(0, results.length - diversified.length));
759
+
760
+ return diversified;
761
+ }
762
+
763
+ private generateAnalytics(results: MemorySearchResult[]): any {
764
+ const categoryDist: Record<string, number> = {};
765
+ const importanceDist: Record<number, number> = {};
766
+ const temporalDist: Record<string, number> = {};
767
+ let totalRelevance = 0;
768
+
769
+ for (const result of results) {
770
+ // Categories
771
+ categoryDist[result.metadata.category] = (categoryDist[result.metadata.category] || 0) + 1;
772
+
773
+ // Importance
774
+ const importance = result.metadata.importance || 5;
775
+ importanceDist[importance] = (importanceDist[importance] || 0) + 1;
776
+
777
+ // Temporal (by month)
778
+ const date = new Date(result.metadata.createdTimestamp || 0);
779
+ const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
780
+ temporalDist[monthKey] = (temporalDist[monthKey] || 0) + 1;
781
+
782
+ totalRelevance += result.relevanceScore;
783
+ }
784
+
785
+ return {
786
+ categoryDistribution: categoryDist,
787
+ importanceDistribution: importanceDist,
788
+ temporalDistribution: temporalDist,
789
+ averageRelevance: results.length > 0 ? totalRelevance / results.length : 0
790
+ };
791
+ }
792
+
793
+ private analyzeTrends(query: AnalyticalQuery, stats: any): any {
794
+ // Analyze trends over time
795
+ return {
796
+ type: 'trends',
797
+ totalMemories: stats.totalMemories,
798
+ timeRange: {
799
+ start: stats.oldestMemory,
800
+ end: stats.newestMemory
801
+ },
802
+ // TODO: Implement detailed trend analysis
803
+ trends: []
804
+ };
805
+ }
806
+
807
+ private analyzeCategories(query: AnalyticalQuery, stats: any): any {
808
+ return {
809
+ type: 'categories',
810
+ distribution: stats.categoryCounts,
811
+ topCategories: Object.entries(stats.categoryCounts)
812
+ .sort(([,a], [,b]) => (b as number) - (a as number))
813
+ .slice(0, 10)
814
+ };
815
+ }
816
+
817
+ private analyzeImportance(query: AnalyticalQuery, stats: any): any {
818
+ return {
819
+ type: 'importance',
820
+ distribution: stats.importanceDistribution,
821
+ average: stats.averageImportance,
822
+ recommendations: this.generateImportanceRecommendations(stats)
823
+ };
824
+ }
825
+
826
+ private analyzeTemporal(query: AnalyticalQuery, stats: any): any {
827
+ return {
828
+ type: 'temporal',
829
+ timeRange: {
830
+ oldest: stats.oldestMemory,
831
+ newest: stats.newestMemory
832
+ },
833
+ // TODO: Implement temporal pattern analysis
834
+ patterns: []
835
+ };
836
+ }
837
+
838
+ private analyzeRelationships(query: AnalyticalQuery): any {
839
+ // This would use GraphService if available
840
+ return {
841
+ type: 'relationships',
842
+ // TODO: Implement relationship analysis
843
+ connections: []
844
+ };
845
+ }
846
+
847
+ private generateInsights(query: AnalyticalQuery, stats: any): any {
848
+ const insights = [];
849
+
850
+ // Category insights
851
+ const topCategory = Object.entries(stats.categoryCounts)
852
+ .sort(([,a], [,b]) => (b as number) - (a as number))[0];
853
+ if (topCategory) {
854
+ insights.push(`Your most common memory category is "${topCategory[0]}" with ${topCategory[1]} memories`);
855
+ }
856
+
857
+ // Importance insights
858
+ if (stats.averageImportance < 5) {
859
+ insights.push("Consider marking more important memories with higher importance ratings");
860
+ }
861
+
862
+ // Temporal insights
863
+ if (stats.newestMemory && stats.oldestMemory) {
864
+ const daysDiff = (new Date(stats.newestMemory).getTime() - new Date(stats.oldestMemory).getTime()) / (1000 * 60 * 60 * 24);
865
+ insights.push(`Your memories span ${Math.round(daysDiff)} days`);
866
+ }
867
+
868
+ return {
869
+ type: 'insights',
870
+ insights,
871
+ stats
872
+ };
873
+ }
874
+
875
+ private generateImportanceRecommendations(stats: any): string[] {
876
+ const recommendations = [];
877
+
878
+ const lowImportanceCount = (stats.importanceDistribution[1] || 0) + (stats.importanceDistribution[2] || 0);
879
+ const highImportanceCount = (stats.importanceDistribution[8] || 0) + (stats.importanceDistribution[9] || 0) + (stats.importanceDistribution[10] || 0);
880
+
881
+ if (lowImportanceCount > highImportanceCount * 2) {
882
+ recommendations.push("Consider reviewing low-importance memories and increasing ratings for valuable content");
883
+ }
884
+
885
+ if (stats.averageImportance > 8) {
886
+ recommendations.push("Your memories have high average importance - consider using the full 1-10 scale for better prioritization");
887
+ }
888
+
889
+ return recommendations;
890
+ }
891
891
  }