@cmdoss/memwal-sdk 0.6.1 → 0.7.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.
- package/dist/ai-sdk/PDWVectorStore.d.ts.map +1 -1
- package/dist/ai-sdk/PDWVectorStore.js +4 -1
- package/dist/ai-sdk/PDWVectorStore.js.map +1 -1
- package/dist/ai-sdk/tools.d.ts +2 -2
- package/dist/ai-sdk/tools.js +2 -2
- package/dist/browser.d.ts +5 -6
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +7 -6
- package/dist/browser.js.map +1 -1
- package/dist/client/ClientMemoryManager.d.ts +1 -0
- package/dist/client/ClientMemoryManager.d.ts.map +1 -1
- package/dist/client/ClientMemoryManager.js +5 -1
- package/dist/client/ClientMemoryManager.js.map +1 -1
- package/dist/client/SimplePDWClient.d.ts +24 -1
- package/dist/client/SimplePDWClient.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.js +31 -9
- package/dist/client/SimplePDWClient.js.map +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
- package/dist/client/namespaces/IndexNamespace.d.ts +38 -9
- package/dist/client/namespaces/IndexNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/IndexNamespace.js +77 -10
- package/dist/client/namespaces/IndexNamespace.js.map +1 -1
- package/dist/client/namespaces/MemoryNamespace.d.ts +27 -0
- package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/MemoryNamespace.js +104 -0
- package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
- package/dist/client/namespaces/SearchNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/SearchNamespace.js +25 -14
- package/dist/client/namespaces/SearchNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
- package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js +69 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +46 -0
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.js +34 -0
- package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
- package/dist/graph/GraphService.js +2 -2
- package/dist/graph/GraphService.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/permissions/ConsentRepository.browser.d.ts +56 -0
- package/dist/permissions/ConsentRepository.browser.d.ts.map +1 -0
- package/dist/permissions/ConsentRepository.browser.js +198 -0
- package/dist/permissions/ConsentRepository.browser.js.map +1 -0
- package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
- package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.js +44 -4
- package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
- package/dist/services/EmbeddingService.d.ts +28 -1
- package/dist/services/EmbeddingService.d.ts.map +1 -1
- package/dist/services/EmbeddingService.js +54 -0
- package/dist/services/EmbeddingService.js.map +1 -1
- package/dist/services/GeminiAIService.d.ts.map +1 -1
- package/dist/services/GeminiAIService.js +283 -27
- package/dist/services/GeminiAIService.js.map +1 -1
- package/dist/services/IndexManager.d.ts +5 -1
- package/dist/services/IndexManager.d.ts.map +1 -1
- package/dist/services/IndexManager.js +17 -40
- package/dist/services/IndexManager.js.map +1 -1
- package/dist/services/MemoryIndexService.d.ts +31 -2
- package/dist/services/MemoryIndexService.d.ts.map +1 -1
- package/dist/services/MemoryIndexService.js +75 -3
- package/dist/services/MemoryIndexService.js.map +1 -1
- package/dist/services/QueryService.js +1 -1
- package/dist/services/QueryService.js.map +1 -1
- package/dist/services/StorageService.d.ts +10 -0
- package/dist/services/StorageService.d.ts.map +1 -1
- package/dist/services/StorageService.js +13 -0
- package/dist/services/StorageService.js.map +1 -1
- package/dist/services/storage/QuiltBatchManager.d.ts +111 -4
- package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
- package/dist/services/storage/QuiltBatchManager.js +450 -38
- package/dist/services/storage/QuiltBatchManager.js.map +1 -1
- package/dist/services/storage/index.d.ts +1 -1
- package/dist/services/storage/index.d.ts.map +1 -1
- package/dist/services/storage/index.js.map +1 -1
- package/dist/utils/LRUCache.d.ts +106 -0
- package/dist/utils/LRUCache.d.ts.map +1 -0
- package/dist/utils/LRUCache.js +281 -0
- package/dist/utils/LRUCache.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/memoryIndexOnChain.d.ts +212 -0
- package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
- package/dist/utils/memoryIndexOnChain.js +312 -0
- package/dist/utils/memoryIndexOnChain.js.map +1 -0
- package/dist/utils/rebuildIndexNode.d.ts +29 -0
- package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
- package/dist/utils/rebuildIndexNode.js +387 -45
- package/dist/utils/rebuildIndexNode.js.map +1 -1
- package/dist/vector/HnswWasmService.d.ts +20 -5
- package/dist/vector/HnswWasmService.d.ts.map +1 -1
- package/dist/vector/HnswWasmService.js +73 -40
- package/dist/vector/HnswWasmService.js.map +1 -1
- package/dist/vector/IHnswService.d.ts +10 -1
- package/dist/vector/IHnswService.d.ts.map +1 -1
- package/dist/vector/IHnswService.js.map +1 -1
- package/dist/vector/NodeHnswService.d.ts +16 -0
- package/dist/vector/NodeHnswService.d.ts.map +1 -1
- package/dist/vector/NodeHnswService.js +108 -10
- package/dist/vector/NodeHnswService.js.map +1 -1
- package/dist/vector/createHnswService.d.ts +1 -1
- package/dist/vector/createHnswService.js +1 -1
- package/dist/vector/index.d.ts +1 -1
- package/dist/vector/index.js +1 -1
- package/package.json +157 -157
- package/src/ai-sdk/PDWVectorStore.ts +4 -1
- package/src/ai-sdk/tools.ts +2 -2
- package/src/browser.ts +15 -10
- package/src/client/ClientMemoryManager.ts +6 -1
- package/src/client/SimplePDWClient.ts +63 -10
- package/src/client/namespaces/EmbeddingsNamespace.ts +1 -1
- package/src/client/namespaces/IndexNamespace.ts +89 -11
- package/src/client/namespaces/MemoryNamespace.ts +137 -0
- package/src/client/namespaces/SearchNamespace.ts +27 -14
- package/src/client/namespaces/consolidated/AINamespace.ts +2 -2
- package/src/client/namespaces/consolidated/BlockchainNamespace.ts +73 -1
- package/src/client/namespaces/consolidated/StorageNamespace.ts +57 -0
- package/src/core/types/index.ts +1 -1
- package/src/generated/pdw/capability.ts +319 -319
- package/src/graph/GraphService.ts +2 -2
- package/src/index.ts +25 -1
- package/src/permissions/ConsentRepository.browser.ts +249 -0
- package/src/retrieval/MemoryRetrievalService.ts +78 -4
- package/src/services/EmbeddingService.ts +66 -1
- package/src/services/GeminiAIService.ts +283 -27
- package/src/services/IndexManager.ts +18 -45
- package/src/services/MemoryIndexService.ts +85 -3
- package/src/services/QueryService.ts +1 -1
- package/src/services/StorageService.ts +15 -0
- package/src/services/storage/QuiltBatchManager.ts +538 -42
- package/src/services/storage/index.ts +6 -1
- package/src/utils/LRUCache.ts +378 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/memoryIndexOnChain.ts +507 -0
- package/src/utils/rebuildIndexNode.ts +482 -52
- package/src/vector/HnswWasmService.ts +95 -43
- package/src/vector/IHnswService.ts +10 -1
- package/src/vector/NodeHnswService.ts +130 -10
- package/src/vector/createHnswService.ts +1 -1
- package/src/vector/index.ts +1 -1
package/src/index.ts
CHANGED
|
@@ -33,7 +33,12 @@ import type { PipelineConfig, PipelineManagerConfig } from './pipeline';
|
|
|
33
33
|
// ==================== SERVICES ====================
|
|
34
34
|
// Business logic services
|
|
35
35
|
export { StorageService } from './services/StorageService';
|
|
36
|
-
export {
|
|
36
|
+
export {
|
|
37
|
+
EmbeddingService,
|
|
38
|
+
getSharedEmbeddingService,
|
|
39
|
+
clearSharedEmbeddingServices,
|
|
40
|
+
getSharedEmbeddingStats,
|
|
41
|
+
} from './services/EmbeddingService';
|
|
37
42
|
export { GeminiAIService } from './services/GeminiAIService';
|
|
38
43
|
export { QueryService } from './services/QueryService';
|
|
39
44
|
export { ClassifierService } from './services/ClassifierService';
|
|
@@ -454,6 +459,25 @@ export type { RebuildIndexOptions, RebuildIndexResult } from './utils/rebuildInd
|
|
|
454
459
|
export { rebuildIndexNode, hasExistingIndexNode, clearIndexNode } from './utils/rebuildIndexNode';
|
|
455
460
|
export type { RebuildIndexNodeOptions, RebuildIndexNodeResult } from './utils/rebuildIndexNode';
|
|
456
461
|
|
|
462
|
+
// MemoryIndex on-chain utilities
|
|
463
|
+
export {
|
|
464
|
+
getMemoryIndex,
|
|
465
|
+
updateMemoryIndexOnChain,
|
|
466
|
+
createMemoryIndexOnChain,
|
|
467
|
+
syncIndexAndUpdateOnChain,
|
|
468
|
+
uploadPlaceholderToWalrus
|
|
469
|
+
} from './utils/memoryIndexOnChain';
|
|
470
|
+
export type {
|
|
471
|
+
OnChainMemoryIndex,
|
|
472
|
+
GetMemoryIndexOptions,
|
|
473
|
+
UpdateMemoryIndexOnChainOptions,
|
|
474
|
+
CreateMemoryIndexOnChainOptions,
|
|
475
|
+
UpdateMemoryIndexResult,
|
|
476
|
+
CreateMemoryIndexResult,
|
|
477
|
+
SyncAndUpdateOptions,
|
|
478
|
+
SyncAndUpdateResult
|
|
479
|
+
} from './utils/memoryIndexOnChain';
|
|
480
|
+
|
|
457
481
|
// ==================== AI SDK INTEGRATION ====================
|
|
458
482
|
// AI SDK tools and vector store for Vercel AI SDK integration
|
|
459
483
|
export { pdwTools } from './ai-sdk/tools';
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-safe Consent Repository implementations
|
|
3
|
+
*
|
|
4
|
+
* This file contains only browser-compatible implementations.
|
|
5
|
+
* FileSystemConsentRepository is excluded as it requires Node.js fs/promises.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
ConsentRequestRecord,
|
|
10
|
+
ConsentStatus,
|
|
11
|
+
} from '../core/types/wallet.js';
|
|
12
|
+
import { normalizeSuiAddress } from '@mysten/sui/utils';
|
|
13
|
+
|
|
14
|
+
export interface ConsentRepository {
|
|
15
|
+
save(request: ConsentRequestRecord): Promise<void>;
|
|
16
|
+
updateStatus(requestId: string, status: ConsentStatus, updatedAt: number): Promise<void>;
|
|
17
|
+
getById(requestId: string): Promise<ConsentRequestRecord | null>;
|
|
18
|
+
listByTarget(targetWallet: string, status?: ConsentStatus): Promise<ConsentRequestRecord[]>;
|
|
19
|
+
listByRequester(requesterWallet: string, status?: ConsentStatus): Promise<ConsentRequestRecord[]>;
|
|
20
|
+
delete(requestId: string): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface StoredConsentRecord extends ConsentRequestRecord {}
|
|
24
|
+
|
|
25
|
+
function normalizeRecord(record: ConsentRequestRecord): StoredConsentRecord {
|
|
26
|
+
return {
|
|
27
|
+
...record,
|
|
28
|
+
requesterWallet: normalizeSuiAddress(record.requesterWallet),
|
|
29
|
+
targetWallet: normalizeSuiAddress(record.targetWallet),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class InMemoryConsentRepository implements ConsentRepository {
|
|
34
|
+
private store = new Map<string, StoredConsentRecord>();
|
|
35
|
+
|
|
36
|
+
async save(request: ConsentRequestRecord): Promise<void> {
|
|
37
|
+
const normalized = normalizeRecord(request);
|
|
38
|
+
this.store.set(normalized.requestId, normalized);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async updateStatus(requestId: string, status: ConsentStatus, updatedAt: number): Promise<void> {
|
|
42
|
+
const record = this.store.get(requestId);
|
|
43
|
+
if (!record) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this.store.set(requestId, {
|
|
47
|
+
...record,
|
|
48
|
+
status,
|
|
49
|
+
updatedAt,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async getById(requestId: string): Promise<ConsentRequestRecord | null> {
|
|
54
|
+
const record = this.store.get(requestId);
|
|
55
|
+
return record ? { ...record } : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async listByTarget(targetWallet: string, status?: ConsentStatus): Promise<ConsentRequestRecord[]> {
|
|
59
|
+
const normalizedTarget = normalizeSuiAddress(targetWallet);
|
|
60
|
+
return Array.from(this.store.values())
|
|
61
|
+
.filter((record) => record.targetWallet === normalizedTarget)
|
|
62
|
+
.filter((record) => (status ? record.status === status : true))
|
|
63
|
+
.map((record) => ({ ...record }));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async listByRequester(requesterWallet: string, status?: ConsentStatus): Promise<ConsentRequestRecord[]> {
|
|
67
|
+
const normalizedRequester = normalizeSuiAddress(requesterWallet);
|
|
68
|
+
return Array.from(this.store.values())
|
|
69
|
+
.filter((record) => record.requesterWallet === normalizedRequester)
|
|
70
|
+
.filter((record) => (status ? record.status === status : true))
|
|
71
|
+
.map((record) => ({ ...record }));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async delete(requestId: string): Promise<void> {
|
|
75
|
+
this.store.delete(requestId);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* IndexedDBConsentRepository - Browser-compatible implementation
|
|
81
|
+
* Uses IndexedDB for persistent storage in browser environments.
|
|
82
|
+
*/
|
|
83
|
+
export class IndexedDBConsentRepository implements ConsentRepository {
|
|
84
|
+
private dbName = 'pdw-consent-store';
|
|
85
|
+
private storeName = 'consent-requests';
|
|
86
|
+
private dbVersion = 1;
|
|
87
|
+
private db: IDBDatabase | null = null;
|
|
88
|
+
|
|
89
|
+
constructor(options?: { dbName?: string }) {
|
|
90
|
+
if (options?.dbName) {
|
|
91
|
+
this.dbName = options.dbName;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private async getDB(): Promise<IDBDatabase> {
|
|
96
|
+
if (this.db) {
|
|
97
|
+
return this.db;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
const request = indexedDB.open(this.dbName, this.dbVersion);
|
|
102
|
+
|
|
103
|
+
request.onerror = () => reject(request.error);
|
|
104
|
+
request.onsuccess = () => {
|
|
105
|
+
this.db = request.result;
|
|
106
|
+
resolve(request.result);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
request.onupgradeneeded = (event) => {
|
|
110
|
+
const db = (event.target as IDBOpenDBRequest).result;
|
|
111
|
+
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
112
|
+
const store = db.createObjectStore(this.storeName, { keyPath: 'requestId' });
|
|
113
|
+
store.createIndex('targetWallet', 'targetWallet', { unique: false });
|
|
114
|
+
store.createIndex('requesterWallet', 'requesterWallet', { unique: false });
|
|
115
|
+
store.createIndex('status', 'status', { unique: false });
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async save(request: ConsentRequestRecord): Promise<void> {
|
|
122
|
+
const db = await this.getDB();
|
|
123
|
+
const normalized = normalizeRecord(request);
|
|
124
|
+
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
const tx = db.transaction(this.storeName, 'readwrite');
|
|
127
|
+
const store = tx.objectStore(this.storeName);
|
|
128
|
+
const req = store.put(normalized);
|
|
129
|
+
|
|
130
|
+
req.onerror = () => reject(req.error);
|
|
131
|
+
req.onsuccess = () => resolve();
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async updateStatus(requestId: string, status: ConsentStatus, updatedAt: number): Promise<void> {
|
|
136
|
+
const record = await this.getById(requestId);
|
|
137
|
+
if (!record) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await this.save({
|
|
142
|
+
...record,
|
|
143
|
+
status,
|
|
144
|
+
updatedAt,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async getById(requestId: string): Promise<ConsentRequestRecord | null> {
|
|
149
|
+
const db = await this.getDB();
|
|
150
|
+
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
const tx = db.transaction(this.storeName, 'readonly');
|
|
153
|
+
const store = tx.objectStore(this.storeName);
|
|
154
|
+
const req = store.get(requestId);
|
|
155
|
+
|
|
156
|
+
req.onerror = () => reject(req.error);
|
|
157
|
+
req.onsuccess = () => {
|
|
158
|
+
const record = req.result as StoredConsentRecord | undefined;
|
|
159
|
+
resolve(record ? { ...record } : null);
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async listByTarget(targetWallet: string, status?: ConsentStatus): Promise<ConsentRequestRecord[]> {
|
|
165
|
+
const normalizedTarget = normalizeSuiAddress(targetWallet);
|
|
166
|
+
const db = await this.getDB();
|
|
167
|
+
|
|
168
|
+
return new Promise((resolve, reject) => {
|
|
169
|
+
const tx = db.transaction(this.storeName, 'readonly');
|
|
170
|
+
const store = tx.objectStore(this.storeName);
|
|
171
|
+
const index = store.index('targetWallet');
|
|
172
|
+
const req = index.getAll(normalizedTarget);
|
|
173
|
+
|
|
174
|
+
req.onerror = () => reject(req.error);
|
|
175
|
+
req.onsuccess = () => {
|
|
176
|
+
let records = req.result as StoredConsentRecord[];
|
|
177
|
+
if (status) {
|
|
178
|
+
records = records.filter((r) => r.status === status);
|
|
179
|
+
}
|
|
180
|
+
resolve(records.map((r) => ({ ...r })));
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async listByRequester(requesterWallet: string, status?: ConsentStatus): Promise<ConsentRequestRecord[]> {
|
|
186
|
+
const normalizedRequester = normalizeSuiAddress(requesterWallet);
|
|
187
|
+
const db = await this.getDB();
|
|
188
|
+
|
|
189
|
+
return new Promise((resolve, reject) => {
|
|
190
|
+
const tx = db.transaction(this.storeName, 'readonly');
|
|
191
|
+
const store = tx.objectStore(this.storeName);
|
|
192
|
+
const index = store.index('requesterWallet');
|
|
193
|
+
const req = index.getAll(normalizedRequester);
|
|
194
|
+
|
|
195
|
+
req.onerror = () => reject(req.error);
|
|
196
|
+
req.onsuccess = () => {
|
|
197
|
+
let records = req.result as StoredConsentRecord[];
|
|
198
|
+
if (status) {
|
|
199
|
+
records = records.filter((r) => r.status === status);
|
|
200
|
+
}
|
|
201
|
+
resolve(records.map((r) => ({ ...r })));
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async delete(requestId: string): Promise<void> {
|
|
207
|
+
const db = await this.getDB();
|
|
208
|
+
|
|
209
|
+
return new Promise((resolve, reject) => {
|
|
210
|
+
const tx = db.transaction(this.storeName, 'readwrite');
|
|
211
|
+
const store = tx.objectStore(this.storeName);
|
|
212
|
+
const req = store.delete(requestId);
|
|
213
|
+
|
|
214
|
+
req.onerror = () => reject(req.error);
|
|
215
|
+
req.onsuccess = () => resolve();
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Close the database connection
|
|
221
|
+
*/
|
|
222
|
+
close(): void {
|
|
223
|
+
if (this.db) {
|
|
224
|
+
this.db.close();
|
|
225
|
+
this.db = null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Factory function to create the appropriate ConsentRepository for browser
|
|
232
|
+
*/
|
|
233
|
+
export function createBrowserConsentRepository(options?: {
|
|
234
|
+
dbName?: string;
|
|
235
|
+
forceInMemory?: boolean;
|
|
236
|
+
}): ConsentRepository {
|
|
237
|
+
// Force in-memory for testing
|
|
238
|
+
if (options?.forceInMemory) {
|
|
239
|
+
return new InMemoryConsentRepository();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Browser environment - use IndexedDB
|
|
243
|
+
if (typeof window !== 'undefined' && typeof indexedDB !== 'undefined') {
|
|
244
|
+
return new IndexedDBConsentRepository({ dbName: options?.dbName });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Fallback to in-memory
|
|
248
|
+
return new InMemoryConsentRepository();
|
|
249
|
+
}
|
|
@@ -182,10 +182,15 @@ export class MemoryRetrievalService {
|
|
|
182
182
|
private contentCache = new Map<string, { content: string; metadata: any; timestamp: number }>();
|
|
183
183
|
private analyticsCache = new Map<string, { analytics: any; timestamp: number }>();
|
|
184
184
|
|
|
185
|
-
// Cache TTL settings
|
|
186
|
-
private readonly QUERY_CACHE_TTL
|
|
187
|
-
private readonly CONTENT_CACHE_TTL
|
|
188
|
-
private readonly ANALYTICS_CACHE_TTL
|
|
185
|
+
// Cache TTL settings (configurable)
|
|
186
|
+
private readonly QUERY_CACHE_TTL: number;
|
|
187
|
+
private readonly CONTENT_CACHE_TTL: number;
|
|
188
|
+
private readonly ANALYTICS_CACHE_TTL: number;
|
|
189
|
+
|
|
190
|
+
// Cache size limits to prevent memory leaks (configurable)
|
|
191
|
+
private readonly MAX_QUERY_CACHE_SIZE: number;
|
|
192
|
+
private readonly MAX_CONTENT_CACHE_SIZE: number;
|
|
193
|
+
private readonly MAX_ANALYTICS_CACHE_SIZE: number;
|
|
189
194
|
|
|
190
195
|
constructor(config?: {
|
|
191
196
|
embeddingService?: EmbeddingService;
|
|
@@ -196,7 +201,29 @@ export class MemoryRetrievalService {
|
|
|
196
201
|
encryptionService?: EncryptionService;
|
|
197
202
|
batchManager?: BatchManager;
|
|
198
203
|
decryptionConfig?: DecryptionConfig;
|
|
204
|
+
/** Cache configuration for memory management */
|
|
205
|
+
cacheConfig?: {
|
|
206
|
+
/** Query cache TTL in ms (default: 5 minutes) */
|
|
207
|
+
queryCacheTtlMs?: number;
|
|
208
|
+
/** Content cache TTL in ms (default: 30 minutes) */
|
|
209
|
+
contentCacheTtlMs?: number;
|
|
210
|
+
/** Analytics cache TTL in ms (default: 1 hour) */
|
|
211
|
+
analyticsCacheTtlMs?: number;
|
|
212
|
+
/** Max query cache entries (default: 100) */
|
|
213
|
+
maxQueryCacheSize?: number;
|
|
214
|
+
/** Max content cache entries (default: 50) */
|
|
215
|
+
maxContentCacheSize?: number;
|
|
216
|
+
/** Max analytics cache entries (default: 100) */
|
|
217
|
+
maxAnalyticsCacheSize?: number;
|
|
218
|
+
};
|
|
199
219
|
}) {
|
|
220
|
+
// Initialize cache settings with configurable defaults
|
|
221
|
+
this.QUERY_CACHE_TTL = config?.cacheConfig?.queryCacheTtlMs ?? 5 * 60 * 1000; // 5 minutes
|
|
222
|
+
this.CONTENT_CACHE_TTL = config?.cacheConfig?.contentCacheTtlMs ?? 30 * 60 * 1000; // 30 minutes
|
|
223
|
+
this.ANALYTICS_CACHE_TTL = config?.cacheConfig?.analyticsCacheTtlMs ?? 60 * 60 * 1000; // 1 hour
|
|
224
|
+
this.MAX_QUERY_CACHE_SIZE = config?.cacheConfig?.maxQueryCacheSize ?? 100;
|
|
225
|
+
this.MAX_CONTENT_CACHE_SIZE = config?.cacheConfig?.maxContentCacheSize ?? 50; // Content can be large
|
|
226
|
+
this.MAX_ANALYTICS_CACHE_SIZE = config?.cacheConfig?.maxAnalyticsCacheSize ?? 100;
|
|
200
227
|
// Initialize services (can be injected or created with default configs)
|
|
201
228
|
this.embeddingService = config?.embeddingService ?? new EmbeddingService();
|
|
202
229
|
this.storageManager = config?.storageManager ?? new StorageManager();
|
|
@@ -684,9 +711,56 @@ export class MemoryRetrievalService {
|
|
|
684
711
|
}
|
|
685
712
|
|
|
686
713
|
private cacheQuery(key: string, result: RetrievalContext): void {
|
|
714
|
+
this.enforceCacheLimit(this.queryCache, this.MAX_QUERY_CACHE_SIZE, this.QUERY_CACHE_TTL);
|
|
687
715
|
this.queryCache.set(key, { result, timestamp: Date.now() });
|
|
688
716
|
}
|
|
689
717
|
|
|
718
|
+
/**
|
|
719
|
+
* Cache content with size limit enforcement
|
|
720
|
+
*/
|
|
721
|
+
private cacheContent(key: string, content: string, metadata: any): void {
|
|
722
|
+
this.enforceCacheLimit(this.contentCache, this.MAX_CONTENT_CACHE_SIZE, this.CONTENT_CACHE_TTL);
|
|
723
|
+
this.contentCache.set(key, { content, metadata, timestamp: Date.now() });
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Cache analytics with size limit enforcement
|
|
728
|
+
*/
|
|
729
|
+
private cacheAnalytics(key: string, analytics: any): void {
|
|
730
|
+
this.enforceCacheLimit(this.analyticsCache, this.MAX_ANALYTICS_CACHE_SIZE, this.ANALYTICS_CACHE_TTL);
|
|
731
|
+
this.analyticsCache.set(key, { analytics, timestamp: Date.now() });
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Enforce cache size limit using LRU eviction (oldest entries first)
|
|
736
|
+
* Also removes expired entries based on TTL
|
|
737
|
+
*/
|
|
738
|
+
private enforceCacheLimit<T extends { timestamp: number }>(
|
|
739
|
+
cache: Map<string, T>,
|
|
740
|
+
maxSize: number,
|
|
741
|
+
ttl: number
|
|
742
|
+
): void {
|
|
743
|
+
// First, clean up expired entries
|
|
744
|
+
const now = Date.now();
|
|
745
|
+
|
|
746
|
+
for (const [key, value] of cache.entries()) {
|
|
747
|
+
if (now - value.timestamp > ttl) {
|
|
748
|
+
cache.delete(key);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// If still over limit, remove oldest entries (LRU)
|
|
753
|
+
if (cache.size >= maxSize) {
|
|
754
|
+
const entries = Array.from(cache.entries())
|
|
755
|
+
.sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
756
|
+
|
|
757
|
+
const toRemove = cache.size - maxSize + 1; // +1 to make room for new entry
|
|
758
|
+
for (let i = 0; i < toRemove && i < entries.length; i++) {
|
|
759
|
+
cache.delete(entries[i][0]);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
690
764
|
// ==================== UTILITY METHODS ====================
|
|
691
765
|
|
|
692
766
|
private calculateCacheHitRate(): number {
|
|
@@ -83,7 +83,7 @@ export interface EmbeddingConfig {
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Embedding dimensions (optional, provider-dependent)
|
|
86
|
-
* - Google: Up to
|
|
86
|
+
* - Google: Up to 3072
|
|
87
87
|
* - OpenAI: 256, 512, 1024, 1536, 3072 (depending on model)
|
|
88
88
|
* - OpenRouter: Depends on the underlying model
|
|
89
89
|
* - Cohere: Model-specific
|
|
@@ -704,3 +704,68 @@ export class EmbeddingService {
|
|
|
704
704
|
}
|
|
705
705
|
|
|
706
706
|
export default EmbeddingService;
|
|
707
|
+
|
|
708
|
+
// ==================== Singleton Pattern ====================
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Generate config key for singleton cache
|
|
712
|
+
*/
|
|
713
|
+
function getConfigKey(config: EmbeddingConfig): string {
|
|
714
|
+
const provider = config.provider || 'google';
|
|
715
|
+
const modelName = typeof config.model === 'string'
|
|
716
|
+
? config.model
|
|
717
|
+
: (config.modelName || 'default');
|
|
718
|
+
const dimensions = config.dimensions || 'default';
|
|
719
|
+
return `${provider}:${modelName}:${dimensions}`;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/** Singleton cache */
|
|
723
|
+
const sharedInstances = new Map<string, EmbeddingService>();
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Get or create a shared EmbeddingService instance (Singleton)
|
|
727
|
+
*
|
|
728
|
+
* All clients with same provider/model/dimensions share one instance.
|
|
729
|
+
* Reduces memory usage and connection overhead.
|
|
730
|
+
*
|
|
731
|
+
* @example
|
|
732
|
+
* ```typescript
|
|
733
|
+
* // Instead of: new EmbeddingService({ apiKey, modelName })
|
|
734
|
+
* const embedding = getSharedEmbeddingService({ apiKey, modelName });
|
|
735
|
+
* ```
|
|
736
|
+
*/
|
|
737
|
+
export function getSharedEmbeddingService(config: EmbeddingConfig): EmbeddingService {
|
|
738
|
+
const key = getConfigKey(config);
|
|
739
|
+
|
|
740
|
+
let instance = sharedInstances.get(key);
|
|
741
|
+
if (!instance) {
|
|
742
|
+
console.log(`🔧 [Singleton] Creating shared EmbeddingService: ${key}`);
|
|
743
|
+
instance = new EmbeddingService(config);
|
|
744
|
+
sharedInstances.set(key, instance);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
return instance;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Clear all shared instances (for testing)
|
|
752
|
+
*/
|
|
753
|
+
export function clearSharedEmbeddingServices(): void {
|
|
754
|
+
sharedInstances.clear();
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* Get singleton stats
|
|
759
|
+
*/
|
|
760
|
+
export function getSharedEmbeddingStats(): {
|
|
761
|
+
instanceCount: number;
|
|
762
|
+
instances: Array<{ key: string; stats: ReturnType<EmbeddingService['getStats']> }>;
|
|
763
|
+
} {
|
|
764
|
+
return {
|
|
765
|
+
instanceCount: sharedInstances.size,
|
|
766
|
+
instances: Array.from(sharedInstances.entries()).map(([key, svc]) => ({
|
|
767
|
+
key,
|
|
768
|
+
stats: svc.getStats(),
|
|
769
|
+
})),
|
|
770
|
+
};
|
|
771
|
+
}
|