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.
- package/.eslintrc.json +22 -0
- package/.github/workflows/ci.yml +57 -0
- package/.prettierrc +8 -0
- package/README.md +197 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +41 -0
- package/dist/config.js.map +1 -0
- package/dist/contextBuilder.d.ts +16 -0
- package/dist/contextBuilder.d.ts.map +1 -0
- package/dist/contextBuilder.js +139 -0
- package/dist/contextBuilder.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/licensing.d.ts +45 -0
- package/dist/licensing.d.ts.map +1 -0
- package/dist/licensing.js +99 -0
- package/dist/licensing.js.map +1 -0
- package/dist/memoryManager.d.ts +35 -0
- package/dist/memoryManager.d.ts.map +1 -0
- package/dist/memoryManager.js +265 -0
- package/dist/memoryManager.js.map +1 -0
- package/dist/metadataStore.d.ts +24 -0
- package/dist/metadataStore.d.ts.map +1 -0
- package/dist/metadataStore.js +247 -0
- package/dist/metadataStore.js.map +1 -0
- package/dist/planManager.d.ts +80 -0
- package/dist/planManager.d.ts.map +1 -0
- package/dist/planManager.js +327 -0
- package/dist/planManager.js.map +1 -0
- package/dist/rateLimiter.d.ts +49 -0
- package/dist/rateLimiter.d.ts.map +1 -0
- package/dist/rateLimiter.js +142 -0
- package/dist/rateLimiter.js.map +1 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +3 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/postgres.d.ts +31 -0
- package/dist/storage/postgres.d.ts.map +1 -0
- package/dist/storage/postgres.js +171 -0
- package/dist/storage/postgres.js.map +1 -0
- package/dist/storage/redis.d.ts +34 -0
- package/dist/storage/redis.d.ts.map +1 -0
- package/dist/storage/redis.js +101 -0
- package/dist/storage/redis.js.map +1 -0
- package/dist/types.d.ts +95 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/usageTracker.d.ts +63 -0
- package/dist/usageTracker.d.ts.map +1 -0
- package/dist/usageTracker.js +238 -0
- package/dist/usageTracker.js.map +1 -0
- package/dist/vectorStore.d.ts +18 -0
- package/dist/vectorStore.d.ts.map +1 -0
- package/dist/vectorStore.js +97 -0
- package/dist/vectorStore.js.map +1 -0
- package/examples/advanced.ts +164 -0
- package/examples/basic.ts +87 -0
- package/package.json +60 -0
- package/src/config.ts +65 -0
- package/src/contextBuilder.ts +184 -0
- package/src/index.ts +209 -0
- package/src/licensing.ts +138 -0
- package/src/memoryManager.ts +340 -0
- package/src/metadataStore.ts +298 -0
- package/src/planManager.ts +417 -0
- package/src/rateLimiter.ts +186 -0
- package/src/storage/index.ts +2 -0
- package/src/storage/postgres.ts +209 -0
- package/src/storage/redis.ts +117 -0
- package/src/types.ts +114 -0
- package/src/usageTracker.ts +325 -0
- package/src/vectorStore.ts +116 -0
- package/tests/aibrain.test.ts +171 -0
- package/tests/contextBuilder.test.ts +138 -0
- package/tests/memoryManager.test.ts +205 -0
- package/tests/metadataStore.test.ts +131 -0
- package/tests/rateLimiter.test.ts +57 -0
- package/tests/usageTracker.test.ts +62 -0
- package/tests/vectorStore.test.ts +106 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +12 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { Memory, MemoryMetadata, SearchResult, ContextResult, MemoryStats, EmbeddingFunction } from './types';
|
|
2
|
+
import { AIMemoryConfig, validateConfig } from './config';
|
|
3
|
+
import { MemoryManager } from './memoryManager';
|
|
4
|
+
import { ContextBuilder } from './contextBuilder';
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
Memory,
|
|
8
|
+
MemoryMetadata,
|
|
9
|
+
MemoryType,
|
|
10
|
+
SearchResult,
|
|
11
|
+
MemoryQuery,
|
|
12
|
+
MemoryFilter,
|
|
13
|
+
MemoryStats,
|
|
14
|
+
ContextConfig,
|
|
15
|
+
ContextMessage,
|
|
16
|
+
ContextResult,
|
|
17
|
+
EmbeddingFunction,
|
|
18
|
+
StorageAdapter,
|
|
19
|
+
VectorStoreAdapter,
|
|
20
|
+
VectorEntry,
|
|
21
|
+
SearchOptions,
|
|
22
|
+
} from './types';
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
AIMemoryConfig,
|
|
26
|
+
DEFAULT_CONFIG,
|
|
27
|
+
validateConfig,
|
|
28
|
+
} from './config';
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
InMemoryVectorStore,
|
|
32
|
+
VectorStoreFactory,
|
|
33
|
+
} from './vectorStore';
|
|
34
|
+
|
|
35
|
+
export {
|
|
36
|
+
MetadataStore,
|
|
37
|
+
} from './metadataStore';
|
|
38
|
+
|
|
39
|
+
export {
|
|
40
|
+
MemoryManager,
|
|
41
|
+
createMemoryManager,
|
|
42
|
+
} from './memoryManager';
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
ContextBuilder,
|
|
46
|
+
createContextBuilder,
|
|
47
|
+
} from './contextBuilder';
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
RateLimiter,
|
|
51
|
+
RateLimitResult,
|
|
52
|
+
RateLimitConfig,
|
|
53
|
+
RateLimitStore,
|
|
54
|
+
InMemoryRateLimitStore,
|
|
55
|
+
createRateLimiter,
|
|
56
|
+
DEFAULT_RATE_LIMITS,
|
|
57
|
+
} from './rateLimiter';
|
|
58
|
+
|
|
59
|
+
export {
|
|
60
|
+
UsageTracker,
|
|
61
|
+
UsageLimits,
|
|
62
|
+
UsageCheckResult,
|
|
63
|
+
UsageMetric,
|
|
64
|
+
UsageSummary,
|
|
65
|
+
UsageStore,
|
|
66
|
+
InMemoryUsageStore,
|
|
67
|
+
createUsageTracker,
|
|
68
|
+
DEFAULT_USAGE_LIMITS,
|
|
69
|
+
} from './usageTracker';
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
PlanManager,
|
|
73
|
+
PlanManager as AIMemoryPro,
|
|
74
|
+
Plan,
|
|
75
|
+
ExtensionPlan,
|
|
76
|
+
TeamPlan,
|
|
77
|
+
ProductPlan,
|
|
78
|
+
ProductType,
|
|
79
|
+
PlanConfig,
|
|
80
|
+
PlanFeatures,
|
|
81
|
+
PlanLimits,
|
|
82
|
+
PLANS,
|
|
83
|
+
getPlan,
|
|
84
|
+
getPlanLimits,
|
|
85
|
+
getAvailablePlans,
|
|
86
|
+
createPlanManager,
|
|
87
|
+
} from './planManager';
|
|
88
|
+
|
|
89
|
+
export {
|
|
90
|
+
RedisRateLimitStore,
|
|
91
|
+
PostgresUsageStore,
|
|
92
|
+
RedisConfig,
|
|
93
|
+
PostgresConfig,
|
|
94
|
+
createRedisRateLimiter,
|
|
95
|
+
createPostgresUsageStore,
|
|
96
|
+
} from './storage';
|
|
97
|
+
|
|
98
|
+
export {
|
|
99
|
+
LicenseManager,
|
|
100
|
+
AIMemoryLicense,
|
|
101
|
+
LicenseConfig,
|
|
102
|
+
LicenseValidation,
|
|
103
|
+
createLicenseManager,
|
|
104
|
+
getLicenseManager,
|
|
105
|
+
} from './licensing';
|
|
106
|
+
|
|
107
|
+
export class AIMemory {
|
|
108
|
+
private memoryManager: MemoryManager;
|
|
109
|
+
private contextBuilder: ContextBuilder;
|
|
110
|
+
|
|
111
|
+
constructor(config?: Partial<AIMemoryConfig>) {
|
|
112
|
+
const validatedConfig = validateConfig(config || {});
|
|
113
|
+
this.memoryManager = new MemoryManager(validatedConfig);
|
|
114
|
+
this.contextBuilder = new ContextBuilder(
|
|
115
|
+
this.memoryManager,
|
|
116
|
+
validatedConfig.context
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
setEmbeddingFunction(fn: EmbeddingFunction): void {
|
|
121
|
+
this.memoryManager.setEmbeddingFunction(fn);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async remember(content: string, metadata?: Partial<MemoryMetadata>): Promise<Memory> {
|
|
125
|
+
return this.memoryManager.addMemory(content, metadata);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async rememberConversation(
|
|
129
|
+
content: string,
|
|
130
|
+
role: 'user' | 'assistant',
|
|
131
|
+
metadata?: Partial<MemoryMetadata>
|
|
132
|
+
): Promise<Memory> {
|
|
133
|
+
return this.memoryManager.addConversation(content, role, metadata);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async rememberFact(content: string, metadata?: Partial<MemoryMetadata>): Promise<Memory> {
|
|
137
|
+
return this.memoryManager.addFact(content, metadata);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async rememberPreference(content: string, metadata?: Partial<MemoryMetadata>): Promise<Memory> {
|
|
141
|
+
return this.memoryManager.addPreference(content, metadata);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async rememberInstruction(content: string, metadata?: Partial<MemoryMetadata>): Promise<Memory> {
|
|
145
|
+
return this.memoryManager.addInstruction(content, metadata);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async recall(query: string, options?: { limit?: number; threshold?: number }): Promise<SearchResult[]> {
|
|
149
|
+
return this.memoryManager.search({
|
|
150
|
+
text: query,
|
|
151
|
+
limit: options?.limit || 10,
|
|
152
|
+
threshold: options?.threshold,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async getContext(query: string): Promise<ContextResult> {
|
|
157
|
+
return this.contextBuilder.buildContext(query);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async getMemory(id: string): Promise<Memory | null> {
|
|
161
|
+
return this.memoryManager.getMemory(id);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async updateMemory(id: string, updates: Partial<Memory>): Promise<Memory | null> {
|
|
165
|
+
return this.memoryManager.updateMemory(id, updates);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async forget(id: string): Promise<void> {
|
|
169
|
+
return this.memoryManager.deleteMemory(id);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async getRecentMemories(limit?: number): Promise<Memory[]> {
|
|
173
|
+
return this.memoryManager.getRecentMemories(limit);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async getStats(): Promise<MemoryStats> {
|
|
177
|
+
return this.memoryManager.getStats();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async clear(): Promise<void> {
|
|
181
|
+
return this.memoryManager.clear();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async cleanup(): Promise<number> {
|
|
185
|
+
return this.memoryManager.cleanup();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async exportData(): Promise<Memory[]> {
|
|
189
|
+
return this.memoryManager.exportData();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async importData(memories: Memory[]): Promise<void> {
|
|
193
|
+
return this.memoryManager.importData(memories);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
getMemoryManager(): MemoryManager {
|
|
197
|
+
return this.memoryManager;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
getContextBuilder(): ContextBuilder {
|
|
201
|
+
return this.contextBuilder;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function createAIMemory(config?: Partial<AIMemoryConfig>): AIMemory {
|
|
206
|
+
return new AIMemory(config);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export { createAIMemory as createAIBrain };
|
package/src/licensing.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { PLANS, ProductPlan, PlanConfig } from './planManager.js';
|
|
2
|
+
|
|
3
|
+
export interface LicenseConfig {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
userId?: string;
|
|
6
|
+
environment: 'development' | 'production';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface LicenseValidation {
|
|
10
|
+
valid: boolean;
|
|
11
|
+
plan: ProductPlan;
|
|
12
|
+
features: PlanConfig['features'];
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface AIMemoryLicense {
|
|
17
|
+
validate(config: LicenseConfig): Promise<LicenseValidation>;
|
|
18
|
+
getPlan(userId: string): ProductPlan;
|
|
19
|
+
setPlan(userId: string, plan: ProductPlan): void;
|
|
20
|
+
requiresApiKey(): boolean;
|
|
21
|
+
isDevelopmentMode(): boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class LicenseManager implements AIMemoryLicense {
|
|
25
|
+
private userPlans: Map<string, ProductPlan> = new Map();
|
|
26
|
+
private developmentMode: boolean;
|
|
27
|
+
private apiKeys: Map<string, { userId: string; plan: ProductPlan }> = new Map();
|
|
28
|
+
|
|
29
|
+
constructor(options?: { developmentMode?: boolean; apiKeys?: Map<string, { userId: string; plan: ProductPlan }> }) {
|
|
30
|
+
this.developmentMode = options?.developmentMode ?? true;
|
|
31
|
+
if (options?.apiKeys) {
|
|
32
|
+
this.apiKeys = options.apiKeys;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async validate(config: LicenseConfig): Promise<LicenseValidation> {
|
|
37
|
+
if (config.environment === 'development' && this.developmentMode) {
|
|
38
|
+
return {
|
|
39
|
+
valid: true,
|
|
40
|
+
plan: 'free',
|
|
41
|
+
features: PLANS.free.features,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (config.environment === 'production') {
|
|
46
|
+
if (!config.apiKey && !this.developmentMode) {
|
|
47
|
+
return {
|
|
48
|
+
valid: false,
|
|
49
|
+
plan: 'free',
|
|
50
|
+
features: PLANS.free.features,
|
|
51
|
+
error: 'API key required for production use. Get one at https://aimemory.dev/dashboard',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (config.apiKey) {
|
|
56
|
+
const keyData = this.apiKeys.get(config.apiKey);
|
|
57
|
+
if (!keyData) {
|
|
58
|
+
return {
|
|
59
|
+
valid: false,
|
|
60
|
+
plan: 'free',
|
|
61
|
+
features: PLANS.free.features,
|
|
62
|
+
error: 'Invalid API key',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
valid: true,
|
|
67
|
+
plan: keyData.plan,
|
|
68
|
+
features: PLANS[keyData.plan].features,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!config.userId) {
|
|
73
|
+
return {
|
|
74
|
+
valid: false,
|
|
75
|
+
plan: 'free',
|
|
76
|
+
features: PLANS.free.features,
|
|
77
|
+
error: 'User ID required',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const userPlan = this.getPlan(config.userId);
|
|
82
|
+
return {
|
|
83
|
+
valid: true,
|
|
84
|
+
plan: userPlan,
|
|
85
|
+
features: PLANS[userPlan].features,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
valid: true,
|
|
91
|
+
plan: 'free',
|
|
92
|
+
features: PLANS.free.features,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getPlan(userId: string): ProductPlan {
|
|
97
|
+
return this.userPlans.get(userId) || 'free';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
setPlan(userId: string, plan: ProductPlan): void {
|
|
101
|
+
this.userPlans.set(userId, plan);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
registerApiKey(apiKey: string, userId: string, plan: ProductPlan): void {
|
|
105
|
+
this.apiKeys.set(apiKey, { userId, plan });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
revokeApiKey(apiKey: string): boolean {
|
|
109
|
+
return this.apiKeys.delete(apiKey);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
requiresApiKey(): boolean {
|
|
113
|
+
return !this.developmentMode;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
isDevelopmentMode(): boolean {
|
|
117
|
+
return this.developmentMode;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
enableProductionMode(): void {
|
|
121
|
+
this.developmentMode = false;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
disableProductionMode(): void {
|
|
125
|
+
this.developmentMode = true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let globalLicenseManager: LicenseManager | null = null;
|
|
130
|
+
|
|
131
|
+
export function createLicenseManager(options?: { developmentMode?: boolean }): LicenseManager {
|
|
132
|
+
globalLicenseManager = new LicenseManager(options);
|
|
133
|
+
return globalLicenseManager;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function getLicenseManager(): LicenseManager | null {
|
|
137
|
+
return globalLicenseManager;
|
|
138
|
+
}
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import {
|
|
3
|
+
Memory,
|
|
4
|
+
MemoryMetadata,
|
|
5
|
+
MemoryType,
|
|
6
|
+
MemoryQuery,
|
|
7
|
+
SearchResult,
|
|
8
|
+
MemoryStats,
|
|
9
|
+
EmbeddingFunction
|
|
10
|
+
} from './types.js';
|
|
11
|
+
import { InMemoryVectorStore } from './vectorStore.js';
|
|
12
|
+
import { MetadataStore } from './metadataStore.js';
|
|
13
|
+
import { AIMemoryConfig, validateConfig } from './config.js';
|
|
14
|
+
|
|
15
|
+
export class MemoryManager {
|
|
16
|
+
private vectorStore: InMemoryVectorStore;
|
|
17
|
+
private metadataStore: MetadataStore;
|
|
18
|
+
private config: AIMemoryConfig;
|
|
19
|
+
private embeddingFunction: EmbeddingFunction | null = null;
|
|
20
|
+
|
|
21
|
+
constructor(config: Partial<AIMemoryConfig> = {}) {
|
|
22
|
+
this.config = validateConfig(config);
|
|
23
|
+
this.vectorStore = new InMemoryVectorStore(this.config.embeddingDimension);
|
|
24
|
+
this.metadataStore = new MetadataStore();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
setEmbeddingFunction(fn: EmbeddingFunction): void {
|
|
28
|
+
this.embeddingFunction = fn;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async addMemory(
|
|
32
|
+
content: string,
|
|
33
|
+
metadata: Partial<MemoryMetadata> = {}
|
|
34
|
+
): Promise<Memory> {
|
|
35
|
+
const id = uuidv4();
|
|
36
|
+
const timestamp = Date.now();
|
|
37
|
+
|
|
38
|
+
const fullMetadata: MemoryMetadata = {
|
|
39
|
+
type: metadata.type || 'context',
|
|
40
|
+
importance: metadata.importance ?? this.config.defaultImportance,
|
|
41
|
+
tags: metadata.tags || [],
|
|
42
|
+
userId: metadata.userId,
|
|
43
|
+
sessionId: metadata.sessionId,
|
|
44
|
+
source: metadata.source,
|
|
45
|
+
...metadata,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
let embedding: number[] | undefined;
|
|
49
|
+
if (this.embeddingFunction) {
|
|
50
|
+
try {
|
|
51
|
+
embedding = await this.embeddingFunction(content);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.warn('Failed to generate embedding:', error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const memory: Memory = {
|
|
58
|
+
id,
|
|
59
|
+
content,
|
|
60
|
+
embedding,
|
|
61
|
+
timestamp,
|
|
62
|
+
metadata: fullMetadata,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
await this.metadataStore.add(memory);
|
|
66
|
+
|
|
67
|
+
if (embedding) {
|
|
68
|
+
await this.vectorStore.add([{
|
|
69
|
+
id,
|
|
70
|
+
vector: embedding,
|
|
71
|
+
metadata: { ...memory },
|
|
72
|
+
}]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
await this.enforceMaxMemories();
|
|
76
|
+
|
|
77
|
+
return memory;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async addConversation(
|
|
81
|
+
content: string,
|
|
82
|
+
role: 'user' | 'assistant',
|
|
83
|
+
metadata: Partial<MemoryMetadata> = {}
|
|
84
|
+
): Promise<Memory> {
|
|
85
|
+
const prefix = role === 'user' ? 'User: ' : 'Assistant: ';
|
|
86
|
+
return this.addMemory(prefix + content, {
|
|
87
|
+
type: 'conversation',
|
|
88
|
+
...metadata,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async addFact(
|
|
93
|
+
content: string,
|
|
94
|
+
metadata: Partial<MemoryMetadata> = {}
|
|
95
|
+
): Promise<Memory> {
|
|
96
|
+
return this.addMemory(content, {
|
|
97
|
+
type: 'fact',
|
|
98
|
+
importance: Math.max(metadata.importance ?? 0.7, 0.7),
|
|
99
|
+
...metadata,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async addPreference(
|
|
104
|
+
content: string,
|
|
105
|
+
metadata: Partial<MemoryMetadata> = {}
|
|
106
|
+
): Promise<Memory> {
|
|
107
|
+
return this.addMemory(content, {
|
|
108
|
+
type: 'preference',
|
|
109
|
+
importance: Math.max(metadata.importance ?? 0.6, 0.6),
|
|
110
|
+
...metadata,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async addInstruction(
|
|
115
|
+
content: string,
|
|
116
|
+
metadata: Partial<MemoryMetadata> = {}
|
|
117
|
+
): Promise<Memory> {
|
|
118
|
+
return this.addMemory(content, {
|
|
119
|
+
type: 'instruction',
|
|
120
|
+
importance: Math.max(metadata.importance ?? 0.9, 0.9),
|
|
121
|
+
...metadata,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async search(query: MemoryQuery): Promise<SearchResult[]> {
|
|
126
|
+
const { text, embedding, filter, limit = 10, threshold } = query;
|
|
127
|
+
|
|
128
|
+
if (!embedding && !text) {
|
|
129
|
+
throw new Error('Either text or embedding must be provided');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let searchEmbedding = embedding;
|
|
133
|
+
|
|
134
|
+
if (text && !searchEmbedding && this.embeddingFunction) {
|
|
135
|
+
try {
|
|
136
|
+
searchEmbedding = await this.embeddingFunction(text);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.warn('Failed to generate embedding for search:', error);
|
|
139
|
+
const memories = await this.metadataStore.find(filter || {}, limit);
|
|
140
|
+
return memories.map(m => ({ memory: m, score: 1 }));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (searchEmbedding) {
|
|
145
|
+
const vectorResults = await this.vectorStore.search(searchEmbedding, {
|
|
146
|
+
limit: limit * 2,
|
|
147
|
+
threshold,
|
|
148
|
+
filter: filter ? this.buildVectorFilter(filter) : undefined,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
let results = vectorResults;
|
|
152
|
+
|
|
153
|
+
if (filter) {
|
|
154
|
+
results = vectorResults.filter(r => this.matchesFilter(r.memory, filter));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return results.slice(0, limit);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const memories = await this.metadataStore.find(filter || {}, limit);
|
|
161
|
+
return memories.map(m => ({ memory: m, score: 1 }));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private buildVectorFilter(filter: any): Record<string, unknown> {
|
|
165
|
+
const vectorFilter: Record<string, unknown> = {};
|
|
166
|
+
|
|
167
|
+
if (filter.types) {
|
|
168
|
+
vectorFilter['metadata.type'] = { $in: filter.types };
|
|
169
|
+
}
|
|
170
|
+
if (filter.userId) {
|
|
171
|
+
vectorFilter['metadata.userId'] = filter.userId;
|
|
172
|
+
}
|
|
173
|
+
if (filter.sessionId) {
|
|
174
|
+
vectorFilter['metadata.sessionId'] = filter.sessionId;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return vectorFilter;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private matchesFilter(memory: Memory, filter: any): boolean {
|
|
181
|
+
if (filter.types && !filter.types.includes(memory.metadata.type)) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
if (filter.tags) {
|
|
185
|
+
const hasTag = filter.tags.some((tag: string) =>
|
|
186
|
+
memory.metadata.tags.includes(tag)
|
|
187
|
+
);
|
|
188
|
+
if (!hasTag) return false;
|
|
189
|
+
}
|
|
190
|
+
if (filter.userId && memory.metadata.userId !== filter.userId) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
if (filter.sessionId && memory.metadata.sessionId !== filter.sessionId) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
if (filter.minImportance !== undefined &&
|
|
197
|
+
memory.metadata.importance < filter.minImportance) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
if (filter.maxImportance !== undefined &&
|
|
201
|
+
memory.metadata.importance > filter.maxImportance) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
if (filter.startDate !== undefined && memory.timestamp < filter.startDate) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
if (filter.endDate !== undefined && memory.timestamp > filter.endDate) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async getMemory(id: string): Promise<Memory | null> {
|
|
214
|
+
return this.metadataStore.getById(id);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async updateMemory(id: string, updates: Partial<Memory>): Promise<Memory | null> {
|
|
218
|
+
const existing = await this.metadataStore.getById(id);
|
|
219
|
+
if (!existing) return null;
|
|
220
|
+
|
|
221
|
+
const updated: Memory = {
|
|
222
|
+
...existing,
|
|
223
|
+
...updates,
|
|
224
|
+
id,
|
|
225
|
+
metadata: {
|
|
226
|
+
...existing.metadata,
|
|
227
|
+
...updates.metadata,
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
await this.metadataStore.update(updated);
|
|
232
|
+
|
|
233
|
+
if (updates.embedding || updates.content) {
|
|
234
|
+
const embedding = updates.embedding || existing.embedding;
|
|
235
|
+
if (embedding) {
|
|
236
|
+
await this.vectorStore.delete([id]);
|
|
237
|
+
await this.vectorStore.add([{
|
|
238
|
+
id,
|
|
239
|
+
vector: embedding,
|
|
240
|
+
metadata: { ...updated },
|
|
241
|
+
}]);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return updated;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async deleteMemory(id: string): Promise<void> {
|
|
249
|
+
await this.metadataStore.delete(id);
|
|
250
|
+
await this.vectorStore.delete([id]);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async getRecentMemories(limit: number = 10): Promise<Memory[]> {
|
|
254
|
+
return this.metadataStore.getRecent(limit);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async getMemoriesByType(type: MemoryType, limit: number = 50): Promise<Memory[]> {
|
|
258
|
+
return this.metadataStore.find({ types: [type] }, limit);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async getMemoriesByTag(tag: string, limit: number = 50): Promise<Memory[]> {
|
|
262
|
+
return this.metadataStore.find({ tags: [tag] }, limit);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async getMemoriesByUser(userId: string, limit: number = 50): Promise<Memory[]> {
|
|
266
|
+
return this.metadataStore.find({ userId }, limit);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async getMemoriesBySession(sessionId: string, limit: number = 50): Promise<Memory[]> {
|
|
270
|
+
return this.metadataStore.find({ sessionId }, limit);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async getStats(): Promise<MemoryStats> {
|
|
274
|
+
return this.metadataStore.getStats();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async clear(): Promise<void> {
|
|
278
|
+
await this.metadataStore.clear();
|
|
279
|
+
await this.vectorStore.clear();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private async enforceMaxMemories(): Promise<void> {
|
|
283
|
+
const size = await this.metadataStore.size();
|
|
284
|
+
|
|
285
|
+
if (size > this.config.maxMemories) {
|
|
286
|
+
const memories = await this.metadataStore.getRecent(size);
|
|
287
|
+
const toDelete = memories
|
|
288
|
+
.filter(m => m.metadata.importance < this.config.autoCleanup.minImportance)
|
|
289
|
+
.slice(this.config.maxMemories - size);
|
|
290
|
+
|
|
291
|
+
for (const memory of toDelete) {
|
|
292
|
+
await this.deleteMemory(memory.id);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async cleanup(): Promise<number> {
|
|
298
|
+
if (!this.config.autoCleanup.enabled) return 0;
|
|
299
|
+
|
|
300
|
+
const cutoff = Date.now() - this.config.autoCleanup.maxAge;
|
|
301
|
+
const allMemories = await this.metadataStore.getAll();
|
|
302
|
+
|
|
303
|
+
let deletedCount = 0;
|
|
304
|
+
for (const memory of allMemories) {
|
|
305
|
+
if (memory.timestamp < cutoff &&
|
|
306
|
+
memory.metadata.importance < this.config.autoCleanup.minImportance) {
|
|
307
|
+
await this.deleteMemory(memory.id);
|
|
308
|
+
deletedCount++;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return deletedCount;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
getConfig(): Readonly<AIMemoryConfig> {
|
|
316
|
+
return { ...this.config };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async exportData(): Promise<Memory[]> {
|
|
320
|
+
return this.metadataStore.getAll();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async importData(memories: Memory[]): Promise<void> {
|
|
324
|
+
for (const memory of memories) {
|
|
325
|
+
await this.metadataStore.add(memory);
|
|
326
|
+
|
|
327
|
+
if (memory.embedding) {
|
|
328
|
+
await this.vectorStore.add([{
|
|
329
|
+
id: memory.id,
|
|
330
|
+
vector: memory.embedding,
|
|
331
|
+
metadata: { ...memory },
|
|
332
|
+
}]);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export function createMemoryManager(config?: Partial<AIMemoryConfig>): MemoryManager {
|
|
339
|
+
return new MemoryManager(config);
|
|
340
|
+
}
|