aimemory-core 1.0.1

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 (86) hide show
  1. package/.eslintrc.json +22 -0
  2. package/.github/workflows/ci.yml +57 -0
  3. package/.prettierrc +8 -0
  4. package/README.md +197 -0
  5. package/dist/config.d.ts +20 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +41 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/contextBuilder.d.ts +16 -0
  10. package/dist/contextBuilder.d.ts.map +1 -0
  11. package/dist/contextBuilder.js +139 -0
  12. package/dist/contextBuilder.js.map +1 -0
  13. package/dist/index.d.ts +45 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +88 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/licensing.d.ts +45 -0
  18. package/dist/licensing.d.ts.map +1 -0
  19. package/dist/licensing.js +99 -0
  20. package/dist/licensing.js.map +1 -0
  21. package/dist/memoryManager.d.ts +35 -0
  22. package/dist/memoryManager.d.ts.map +1 -0
  23. package/dist/memoryManager.js +265 -0
  24. package/dist/memoryManager.js.map +1 -0
  25. package/dist/metadataStore.d.ts +24 -0
  26. package/dist/metadataStore.d.ts.map +1 -0
  27. package/dist/metadataStore.js +247 -0
  28. package/dist/metadataStore.js.map +1 -0
  29. package/dist/planManager.d.ts +80 -0
  30. package/dist/planManager.d.ts.map +1 -0
  31. package/dist/planManager.js +327 -0
  32. package/dist/planManager.js.map +1 -0
  33. package/dist/rateLimiter.d.ts +49 -0
  34. package/dist/rateLimiter.d.ts.map +1 -0
  35. package/dist/rateLimiter.js +142 -0
  36. package/dist/rateLimiter.js.map +1 -0
  37. package/dist/storage/index.d.ts +3 -0
  38. package/dist/storage/index.d.ts.map +1 -0
  39. package/dist/storage/index.js +3 -0
  40. package/dist/storage/index.js.map +1 -0
  41. package/dist/storage/postgres.d.ts +31 -0
  42. package/dist/storage/postgres.d.ts.map +1 -0
  43. package/dist/storage/postgres.js +171 -0
  44. package/dist/storage/postgres.js.map +1 -0
  45. package/dist/storage/redis.d.ts +34 -0
  46. package/dist/storage/redis.d.ts.map +1 -0
  47. package/dist/storage/redis.js +101 -0
  48. package/dist/storage/redis.js.map +1 -0
  49. package/dist/types.d.ts +95 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +2 -0
  52. package/dist/types.js.map +1 -0
  53. package/dist/usageTracker.d.ts +63 -0
  54. package/dist/usageTracker.d.ts.map +1 -0
  55. package/dist/usageTracker.js +238 -0
  56. package/dist/usageTracker.js.map +1 -0
  57. package/dist/vectorStore.d.ts +18 -0
  58. package/dist/vectorStore.d.ts.map +1 -0
  59. package/dist/vectorStore.js +97 -0
  60. package/dist/vectorStore.js.map +1 -0
  61. package/examples/advanced.ts +164 -0
  62. package/examples/basic.ts +87 -0
  63. package/package.json +60 -0
  64. package/src/config.ts +65 -0
  65. package/src/contextBuilder.ts +184 -0
  66. package/src/index.ts +209 -0
  67. package/src/licensing.ts +138 -0
  68. package/src/memoryManager.ts +340 -0
  69. package/src/metadataStore.ts +298 -0
  70. package/src/planManager.ts +417 -0
  71. package/src/rateLimiter.ts +186 -0
  72. package/src/storage/index.ts +2 -0
  73. package/src/storage/postgres.ts +209 -0
  74. package/src/storage/redis.ts +117 -0
  75. package/src/types.ts +114 -0
  76. package/src/usageTracker.ts +325 -0
  77. package/src/vectorStore.ts +116 -0
  78. package/tests/aibrain.test.ts +171 -0
  79. package/tests/contextBuilder.test.ts +138 -0
  80. package/tests/memoryManager.test.ts +205 -0
  81. package/tests/metadataStore.test.ts +131 -0
  82. package/tests/rateLimiter.test.ts +57 -0
  83. package/tests/usageTracker.test.ts +62 -0
  84. package/tests/vectorStore.test.ts +106 -0
  85. package/tsconfig.json +25 -0
  86. package/vitest.config.ts +12 -0
@@ -0,0 +1,325 @@
1
+ export type UsageMetric =
2
+ | 'memories_added'
3
+ | 'memories_searched'
4
+ | 'context_built'
5
+ | 'api_calls'
6
+ | 'storage_used';
7
+
8
+ export interface UsageRecord {
9
+ userId: string;
10
+ date: string;
11
+ metrics: Record<UsageMetric, number>;
12
+ }
13
+
14
+ export interface UsageSummary {
15
+ userId: string;
16
+ period: 'daily' | 'monthly' | 'yearly';
17
+ startDate: Date;
18
+ endDate: Date;
19
+ metrics: Record<UsageMetric, number>;
20
+ totalOperations: number;
21
+ }
22
+
23
+ export interface UsageLimits {
24
+ maxMemories: number;
25
+ maxSearchPerDay: number;
26
+ maxContextPerDay: number;
27
+ maxApiCallsPerDay: number;
28
+ maxStorageMB: number;
29
+ }
30
+
31
+ export interface UsageCheckResult {
32
+ allowed: boolean;
33
+ metric: UsageMetric;
34
+ current: number;
35
+ limit: number;
36
+ remaining: number;
37
+ resetDate: Date;
38
+ }
39
+
40
+ export interface UsageStore {
41
+ get(userId: string, date: string): Promise<UsageRecord | null>;
42
+ set(userId: string, date: string, record: UsageRecord): Promise<void>;
43
+ increment(userId: string, metric: UsageMetric, amount?: number): Promise<void>;
44
+ getRange(userId: string, startDate: string, endDate: string): Promise<UsageRecord[]>;
45
+ reset(userId: string, date: string): Promise<void>;
46
+ deleteUser(userId: string): Promise<void>;
47
+ }
48
+
49
+ export class InMemoryUsageStore implements UsageStore {
50
+ private store: Map<string, Map<string, UsageRecord>> = new Map();
51
+
52
+ private getKey(userId: string, date: string): string {
53
+ return `${userId}:${date}`;
54
+ }
55
+
56
+ async get(userId: string, date: string): Promise<UsageRecord | null> {
57
+ const userMap = this.store.get(userId);
58
+ if (!userMap) return null;
59
+ return userMap.get(date) || null;
60
+ }
61
+
62
+ async set(userId: string, date: string, record: UsageRecord): Promise<void> {
63
+ if (!this.store.has(userId)) {
64
+ this.store.set(userId, new Map());
65
+ }
66
+ this.store.get(userId)!.set(date, record);
67
+ }
68
+
69
+ async increment(userId: string, metric: UsageMetric, amount: number = 1): Promise<void> {
70
+ const today = new Date().toISOString().split('T')[0];
71
+
72
+ if (!this.store.has(userId)) {
73
+ this.store.set(userId, new Map());
74
+ }
75
+
76
+ const userMap = this.store.get(userId)!;
77
+ let record = userMap.get(today);
78
+
79
+ if (!record) {
80
+ record = {
81
+ userId,
82
+ date: today,
83
+ metrics: {
84
+ memories_added: 0,
85
+ memories_searched: 0,
86
+ context_built: 0,
87
+ api_calls: 0,
88
+ storage_used: 0,
89
+ },
90
+ };
91
+ }
92
+
93
+ record.metrics[metric] = (record.metrics[metric] || 0) + amount;
94
+ userMap.set(today, record);
95
+ }
96
+
97
+ async getRange(userId: string, startDate: string, endDate: string): Promise<UsageRecord[]> {
98
+ const userMap = this.store.get(userId);
99
+ if (!userMap) return [];
100
+
101
+ const results: UsageRecord[] = [];
102
+ const start = new Date(startDate);
103
+ const end = new Date(endDate);
104
+
105
+ for (const record of userMap.values()) {
106
+ const recordDate = new Date(record.date);
107
+ if (recordDate >= start && recordDate <= end) {
108
+ results.push(record);
109
+ }
110
+ }
111
+
112
+ return results;
113
+ }
114
+
115
+ async reset(userId: string, date: string): Promise<void> {
116
+ const userMap = this.store.get(userId);
117
+ if (userMap) {
118
+ userMap.delete(date);
119
+ }
120
+ }
121
+
122
+ async deleteUser(userId: string): Promise<void> {
123
+ this.store.delete(userId);
124
+ }
125
+ }
126
+
127
+ export class UsageTracker {
128
+ private store: UsageStore;
129
+ private limits: UsageLimits;
130
+
131
+ constructor(limits: UsageLimits, store?: UsageStore) {
132
+ this.limits = limits;
133
+ this.store = store || new InMemoryUsageStore();
134
+ }
135
+
136
+ async checkLimit(userId: string, metric: UsageMetric): Promise<UsageCheckResult> {
137
+ const today = new Date().toISOString().split('T')[0];
138
+ const record = await this.store.get(userId, today);
139
+
140
+ const current = record?.metrics[metric] || 0;
141
+ const limit = this.getLimitForMetric(metric);
142
+ const remaining = Math.max(0, limit - current);
143
+
144
+ const now = new Date();
145
+ const resetDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
146
+
147
+ return {
148
+ allowed: current < limit,
149
+ metric,
150
+ current,
151
+ limit,
152
+ remaining,
153
+ resetDate,
154
+ };
155
+ }
156
+
157
+ async recordUsage(userId: string, metric: UsageMetric, amount: number = 1): Promise<UsageCheckResult> {
158
+ const checkResult = await this.checkLimit(userId, metric);
159
+
160
+ if (!checkResult.allowed) {
161
+ return checkResult;
162
+ }
163
+
164
+ await this.store.increment(userId, metric, amount);
165
+
166
+ return this.checkLimit(userId, metric);
167
+ }
168
+
169
+ async getUsageSummary(userId: string, period: 'daily' | 'monthly' | 'yearly'): Promise<UsageSummary> {
170
+ const now = new Date();
171
+ let startDate: Date;
172
+ let endDate: Date = now;
173
+
174
+ switch (period) {
175
+ case 'daily':
176
+ startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
177
+ break;
178
+ case 'monthly':
179
+ startDate = new Date(now.getFullYear(), now.getMonth(), 1);
180
+ break;
181
+ case 'yearly':
182
+ startDate = new Date(now.getFullYear(), 0, 1);
183
+ break;
184
+ }
185
+
186
+ const records = await this.store.getRange(
187
+ userId,
188
+ startDate.toISOString().split('T')[0],
189
+ endDate.toISOString().split('T')[0]
190
+ );
191
+
192
+ const metrics: Record<UsageMetric, number> = {
193
+ memories_added: 0,
194
+ memories_searched: 0,
195
+ context_built: 0,
196
+ api_calls: 0,
197
+ storage_used: 0,
198
+ };
199
+
200
+ let totalOperations = 0;
201
+
202
+ for (const record of records) {
203
+ for (const [key, value] of Object.entries(record.metrics)) {
204
+ metrics[key as UsageMetric] += value;
205
+ totalOperations += value;
206
+ }
207
+ }
208
+
209
+ return {
210
+ userId,
211
+ period,
212
+ startDate,
213
+ endDate,
214
+ metrics,
215
+ totalOperations,
216
+ };
217
+ }
218
+
219
+ async getAllUsage(userId: string): Promise<Record<UsageMetric, number>> {
220
+ const summary = await this.getUsageSummary(userId, 'monthly');
221
+ return summary.metrics;
222
+ }
223
+
224
+ private getLimitForMetric(metric: UsageMetric): number {
225
+ switch (metric) {
226
+ case 'memories_added':
227
+ return this.limits.maxMemories;
228
+ case 'memories_searched':
229
+ return this.limits.maxSearchPerDay;
230
+ case 'context_built':
231
+ return this.limits.maxContextPerDay;
232
+ case 'api_calls':
233
+ return this.limits.maxApiCallsPerDay;
234
+ case 'storage_used':
235
+ return this.limits.maxStorageMB;
236
+ default:
237
+ return 0;
238
+ }
239
+ }
240
+
241
+ updateLimits(limits: Partial<UsageLimits>): void {
242
+ this.limits = { ...this.limits, ...limits };
243
+ }
244
+
245
+ async resetUser(userId: string): Promise<void> {
246
+ await this.store.deleteUser(userId);
247
+ }
248
+
249
+ async resetDay(userId: string): Promise<void> {
250
+ const today = new Date().toISOString().split('T')[0];
251
+ await this.store.reset(userId, today);
252
+ }
253
+ }
254
+
255
+ export const DEFAULT_USAGE_LIMITS: Record<string, UsageLimits> = {
256
+ // NPM & Extension Free
257
+ free: {
258
+ maxMemories: 5000,
259
+ maxSearchPerDay: 500,
260
+ maxContextPerDay: 200,
261
+ maxApiCallsPerDay: 5000,
262
+ maxStorageMB: 50,
263
+ },
264
+ // Extension Starter
265
+ starter: {
266
+ maxMemories: 30000,
267
+ maxSearchPerDay: 1000,
268
+ maxContextPerDay: 500,
269
+ maxApiCallsPerDay: 10000,
270
+ maxStorageMB: 100,
271
+ },
272
+ // NPM Pro
273
+ pro: {
274
+ maxMemories: 50000,
275
+ maxSearchPerDay: 10000,
276
+ maxContextPerDay: 5000,
277
+ maxApiCallsPerDay: 100000,
278
+ maxStorageMB: 500,
279
+ },
280
+ // Extension Plus
281
+ plus: {
282
+ maxMemories: 150000,
283
+ maxSearchPerDay: 5000,
284
+ maxContextPerDay: 2000,
285
+ maxApiCallsPerDay: 50000,
286
+ maxStorageMB: 250,
287
+ },
288
+ // Extension Premium
289
+ premium: {
290
+ maxMemories: -1,
291
+ maxSearchPerDay: -1,
292
+ maxContextPerDay: -1,
293
+ maxApiCallsPerDay: -1,
294
+ maxStorageMB: -1,
295
+ },
296
+ // Team
297
+ team: {
298
+ maxMemories: 500000,
299
+ maxSearchPerDay: 100000,
300
+ maxContextPerDay: 50000,
301
+ maxApiCallsPerDay: 1000000,
302
+ maxStorageMB: 5000,
303
+ },
304
+ // Business
305
+ business: {
306
+ maxMemories: 2000000,
307
+ maxSearchPerDay: 500000,
308
+ maxContextPerDay: 200000,
309
+ maxApiCallsPerDay: 5000000,
310
+ maxStorageMB: 20000,
311
+ },
312
+ // Enterprise
313
+ enterprise: {
314
+ maxMemories: -1,
315
+ maxSearchPerDay: -1,
316
+ maxContextPerDay: -1,
317
+ maxApiCallsPerDay: -1,
318
+ maxStorageMB: -1,
319
+ },
320
+ };
321
+
322
+ export function createUsageTracker(plan: string = 'free', store?: UsageStore): UsageTracker {
323
+ const limits = DEFAULT_USAGE_LIMITS[plan] || DEFAULT_USAGE_LIMITS.free;
324
+ return new UsageTracker(limits, store);
325
+ }
@@ -0,0 +1,116 @@
1
+ import { VectorStoreAdapter, VectorEntry, SearchOptions, SearchResult, Memory } from './types.js';
2
+
3
+ export class InMemoryVectorStore implements VectorStoreAdapter {
4
+ private vectors: Map<string, VectorEntry> = new Map();
5
+ private dimension: number;
6
+
7
+ constructor(dimension: number = 1536) {
8
+ this.dimension = dimension;
9
+ }
10
+
11
+ async add(entries: VectorEntry[]): Promise<void> {
12
+ for (const entry of entries) {
13
+ if (!entry.vector || entry.vector.length !== this.dimension) {
14
+ throw new Error(`Invalid vector dimension. Expected ${this.dimension}, got ${entry.vector?.length || 0}`);
15
+ }
16
+ this.vectors.set(entry.id, {
17
+ id: entry.id,
18
+ vector: [...entry.vector],
19
+ metadata: { ...entry.metadata },
20
+ });
21
+ }
22
+ }
23
+
24
+ async search(query: number[], options: SearchOptions): Promise<SearchResult[]> {
25
+ if (query.length !== this.dimension) {
26
+ throw new Error(`Invalid query dimension. Expected ${this.dimension}, got ${query.length}`);
27
+ }
28
+
29
+ const results: SearchResult[] = [];
30
+ const { limit, threshold, filter } = options;
31
+
32
+ for (const entry of this.vectors.values()) {
33
+ if (filter) {
34
+ const matchesFilter = Object.entries(filter).every(
35
+ ([key, value]) => entry.metadata[key] === value
36
+ );
37
+ if (!matchesFilter) continue;
38
+ }
39
+
40
+ const score = this.cosineSimilarity(query, entry.vector);
41
+
42
+ if (threshold !== undefined && score < threshold) {
43
+ continue;
44
+ }
45
+
46
+ results.push({
47
+ memory: {
48
+ id: entry.id,
49
+ content: entry.metadata.content || '',
50
+ timestamp: entry.metadata.timestamp as number || Date.now(),
51
+ metadata: entry.metadata,
52
+ } as unknown as Memory,
53
+ score,
54
+ });
55
+ }
56
+
57
+ results.sort((a, b) => b.score - a.score);
58
+ return results.slice(0, limit);
59
+ }
60
+
61
+ async delete(ids: string[]): Promise<void> {
62
+ for (const id of ids) {
63
+ this.vectors.delete(id);
64
+ }
65
+ }
66
+
67
+ async getById(id: string): Promise<VectorEntry | null> {
68
+ const entry = this.vectors.get(id);
69
+ if (!entry) return null;
70
+ return {
71
+ id: entry.id,
72
+ vector: [...entry.vector],
73
+ metadata: { ...entry.metadata },
74
+ };
75
+ }
76
+
77
+ async getAll(): Promise<VectorEntry[]> {
78
+ return Array.from(this.vectors.values()).map(entry => ({
79
+ id: entry.id,
80
+ vector: [...entry.vector],
81
+ metadata: { ...entry.metadata },
82
+ }));
83
+ }
84
+
85
+ async clear(): Promise<void> {
86
+ this.vectors.clear();
87
+ }
88
+
89
+ async size(): Promise<number> {
90
+ return this.vectors.size;
91
+ }
92
+
93
+ private cosineSimilarity(a: number[], b: number[]): number {
94
+ if (a.length !== b.length) return 0;
95
+
96
+ let dotProduct = 0;
97
+ let normA = 0;
98
+ let normB = 0;
99
+
100
+ for (let i = 0; i < a.length; i++) {
101
+ dotProduct += a[i] * b[i];
102
+ normA += a[i] * a[i];
103
+ normB += b[i] * b[i];
104
+ }
105
+
106
+ if (normA === 0 || normB === 0) return 0;
107
+
108
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
109
+ }
110
+ }
111
+
112
+ export class VectorStoreFactory {
113
+ static create(dimension: number = 1536): VectorStoreAdapter {
114
+ return new InMemoryVectorStore(dimension);
115
+ }
116
+ }
@@ -0,0 +1,171 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { createAIMemory, AIMemory } from '../src/index.js';
3
+ import { EmbeddingFunction } from '../src/types.js';
4
+
5
+ const mockEmbedding: EmbeddingFunction = async (text: string): Promise<number[]> => {
6
+ const hash = text.split('').reduce((acc, char) => {
7
+ return ((acc << 5) - acc) + char.charCodeAt(0);
8
+ }, 0);
9
+
10
+ const embedding = new Array(1536).fill(0);
11
+ for (let i = 0; i < embedding.length; i++) {
12
+ embedding[i] = Math.sin(hash * i) * Math.cos(hash * i);
13
+ }
14
+
15
+ const magnitude = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
16
+ return embedding.map(val => val / magnitude);
17
+ };
18
+
19
+ describe('AIMemory', () => {
20
+ let memory: AIMemory;
21
+
22
+ beforeEach(() => {
23
+ memory = createAIMemory();
24
+ memory.setEmbeddingFunction(mockEmbedding);
25
+ });
26
+
27
+ it('should create instance', () => {
28
+ expect(memory).toBeDefined();
29
+ });
30
+
31
+ it('should remember content', async () => {
32
+ const mem = await memory.remember('Test content', {
33
+ type: 'fact',
34
+ });
35
+
36
+ expect(mem.content).toBe('Test content');
37
+ });
38
+
39
+ it('should remember conversation', async () => {
40
+ const mem = await memory.rememberConversation('Hello', 'user');
41
+
42
+ expect(mem.content).toBe('User: Hello');
43
+ expect(mem.metadata.type).toBe('conversation');
44
+ });
45
+
46
+ it('should remember fact', async () => {
47
+ const mem = await memory.rememberFact('The earth is round');
48
+
49
+ expect(mem.metadata.type).toBe('fact');
50
+ });
51
+
52
+ it('should remember preference', async () => {
53
+ const mem = await memory.rememberPreference('I like coffee');
54
+
55
+ expect(mem.metadata.type).toBe('preference');
56
+ });
57
+
58
+ it('should remember instruction', async () => {
59
+ const mem = await memory.rememberInstruction('Be polite');
60
+
61
+ expect(mem.metadata.type).toBe('instruction');
62
+ });
63
+
64
+ it('should recall memories', async () => {
65
+ await memory.remember('Python programming', { type: 'fact' });
66
+ await memory.remember('JavaScript programming', { type: 'fact' });
67
+
68
+ const results = await memory.recall('programming');
69
+
70
+ expect(results.length).toBeGreaterThan(0);
71
+ });
72
+
73
+ it('should get context', async () => {
74
+ await memory.rememberFact('User likes cats');
75
+
76
+ const context = await memory.getContext('pets');
77
+
78
+ expect(context.messages.length).toBeGreaterThan(0);
79
+ expect(context.stats).toBeDefined();
80
+ });
81
+
82
+ it('should get memory by id', async () => {
83
+ const added = await memory.remember('Test');
84
+
85
+ const retrieved = await memory.getMemory(added.id);
86
+
87
+ expect(retrieved).not.toBeNull();
88
+ expect(retrieved!.content).toBe('Test');
89
+ });
90
+
91
+ it('should update memory', async () => {
92
+ const added = await memory.remember('Original');
93
+
94
+ const updated = await memory.updateMemory(added.id, {
95
+ content: 'Updated',
96
+ });
97
+
98
+ expect(updated!.content).toBe('Updated');
99
+ });
100
+
101
+ it('should forget memory', async () => {
102
+ const added = await memory.remember('To forget');
103
+
104
+ await memory.forget(added.id);
105
+
106
+ const retrieved = await memory.getMemory(added.id);
107
+ expect(retrieved).toBeNull();
108
+ });
109
+
110
+ it('should get recent memories', async () => {
111
+ await memory.remember('First');
112
+ await memory.remember('Second');
113
+
114
+ const recent = await memory.getRecentMemories();
115
+
116
+ expect(recent.length).toBe(2);
117
+ });
118
+
119
+ it('should get stats', async () => {
120
+ await memory.remember('Test 1', { type: 'fact' });
121
+ await memory.remember('Test 2', { type: 'fact' });
122
+
123
+ const stats = await memory.getStats();
124
+
125
+ expect(stats.totalMemories).toBe(2);
126
+ expect(stats.memoriesByType.fact).toBe(2);
127
+ });
128
+
129
+ it('should clear all memories', async () => {
130
+ await memory.remember('Test');
131
+ await memory.clear();
132
+
133
+ const stats = await memory.getStats();
134
+ expect(stats.totalMemories).toBe(0);
135
+ });
136
+
137
+ it('should export and import data', async () => {
138
+ await memory.remember('Memory 1');
139
+ await memory.remember('Memory 2');
140
+
141
+ const exported = await memory.exportData();
142
+
143
+ await memory.clear();
144
+ await memory.importData(exported);
145
+
146
+ const stats = await memory.getStats();
147
+ expect(stats.totalMemories).toBe(2);
148
+ });
149
+
150
+ it('should work with config', () => {
151
+ const customMemory = createAIMemory({
152
+ maxMemories: 500,
153
+ context: {
154
+ maxTokens: 3000,
155
+ relevanceThreshold: 0.6,
156
+ },
157
+ });
158
+
159
+ expect(customMemory).toBeDefined();
160
+ });
161
+
162
+ it('should get underlying memory manager', () => {
163
+ const manager = memory.getMemoryManager();
164
+ expect(manager).toBeDefined();
165
+ });
166
+
167
+ it('should get underlying context builder', () => {
168
+ const contextBuilder = memory.getContextBuilder();
169
+ expect(contextBuilder).toBeDefined();
170
+ });
171
+ });