family-ai-agent 1.0.6 → 1.0.8
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/.letta/settings.local.json +3 -0
- package/dist/cli/index.js +1 -1
- package/dist/database/adapters/base-adapter.d.ts +81 -0
- package/dist/database/adapters/base-adapter.d.ts.map +1 -0
- package/dist/database/adapters/base-adapter.js +105 -0
- package/dist/database/adapters/base-adapter.js.map +1 -0
- package/dist/database/adapters/index.d.ts +49 -0
- package/dist/database/adapters/index.d.ts.map +1 -0
- package/dist/database/adapters/index.js +200 -0
- package/dist/database/adapters/index.js.map +1 -0
- package/dist/database/adapters/postgres-adapter.d.ts +75 -0
- package/dist/database/adapters/postgres-adapter.d.ts.map +1 -0
- package/dist/database/adapters/postgres-adapter.js +225 -0
- package/dist/database/adapters/postgres-adapter.js.map +1 -0
- package/dist/database/adapters/sqlite-adapter.d.ts +72 -0
- package/dist/database/adapters/sqlite-adapter.d.ts.map +1 -0
- package/dist/database/adapters/sqlite-adapter.js +368 -0
- package/dist/database/adapters/sqlite-adapter.js.map +1 -0
- package/dist/database/cache/cache-keys.d.ts +180 -0
- package/dist/database/cache/cache-keys.d.ts.map +1 -0
- package/dist/database/cache/cache-keys.js +107 -0
- package/dist/database/cache/cache-keys.js.map +1 -0
- package/dist/database/cache/index.d.ts +24 -0
- package/dist/database/cache/index.d.ts.map +1 -0
- package/dist/database/cache/index.js +34 -0
- package/dist/database/cache/index.js.map +1 -0
- package/dist/database/cache/query-cache.d.ts +67 -0
- package/dist/database/cache/query-cache.d.ts.map +1 -0
- package/dist/database/cache/query-cache.js +177 -0
- package/dist/database/cache/query-cache.js.map +1 -0
- package/dist/database/client.d.ts +63 -4
- package/dist/database/client.d.ts.map +1 -1
- package/dist/database/client.js +147 -59
- package/dist/database/client.js.map +1 -1
- package/dist/database/db-config.d.ts +104 -0
- package/dist/database/db-config.d.ts.map +1 -0
- package/dist/database/db-config.js +167 -0
- package/dist/database/db-config.js.map +1 -0
- package/dist/database/drizzle/index.d.ts +42 -0
- package/dist/database/drizzle/index.d.ts.map +1 -0
- package/dist/database/drizzle/index.js +48 -0
- package/dist/database/drizzle/index.js.map +1 -0
- package/dist/database/drizzle/schema/audit.d.ts +533 -0
- package/dist/database/drizzle/schema/audit.d.ts.map +1 -0
- package/dist/database/drizzle/schema/audit.js +71 -0
- package/dist/database/drizzle/schema/audit.js.map +1 -0
- package/dist/database/drizzle/schema/checkpoints.d.ts +665 -0
- package/dist/database/drizzle/schema/checkpoints.d.ts.map +1 -0
- package/dist/database/drizzle/schema/checkpoints.js +110 -0
- package/dist/database/drizzle/schema/checkpoints.js.map +1 -0
- package/dist/database/drizzle/schema/conversations.d.ts +449 -0
- package/dist/database/drizzle/schema/conversations.d.ts.map +1 -0
- package/dist/database/drizzle/schema/conversations.js +91 -0
- package/dist/database/drizzle/schema/conversations.js.map +1 -0
- package/dist/database/drizzle/schema/documents.d.ts +600 -0
- package/dist/database/drizzle/schema/documents.d.ts.map +1 -0
- package/dist/database/drizzle/schema/documents.js +100 -0
- package/dist/database/drizzle/schema/documents.js.map +1 -0
- package/dist/database/drizzle/schema/index.d.ts +3084 -0
- package/dist/database/drizzle/schema/index.d.ts.map +1 -0
- package/dist/database/drizzle/schema/index.js +46 -0
- package/dist/database/drizzle/schema/index.js.map +1 -0
- package/dist/database/drizzle/schema/memories.d.ts +435 -0
- package/dist/database/drizzle/schema/memories.d.ts.map +1 -0
- package/dist/database/drizzle/schema/memories.js +73 -0
- package/dist/database/drizzle/schema/memories.js.map +1 -0
- package/dist/database/drizzle/schema/tasks.d.ts +565 -0
- package/dist/database/drizzle/schema/tasks.d.ts.map +1 -0
- package/dist/database/drizzle/schema/tasks.js +84 -0
- package/dist/database/drizzle/schema/tasks.js.map +1 -0
- package/dist/database/health/circuit-breaker.d.ts +81 -0
- package/dist/database/health/circuit-breaker.d.ts.map +1 -0
- package/dist/database/health/circuit-breaker.js +184 -0
- package/dist/database/health/circuit-breaker.js.map +1 -0
- package/dist/database/health/health-monitor.d.ts +69 -0
- package/dist/database/health/health-monitor.d.ts.map +1 -0
- package/dist/database/health/health-monitor.js +174 -0
- package/dist/database/health/health-monitor.js.map +1 -0
- package/dist/database/health/index.d.ts +27 -0
- package/dist/database/health/index.d.ts.map +1 -0
- package/dist/database/health/index.js +23 -0
- package/dist/database/health/index.js.map +1 -0
- package/dist/database/index.d.ts +16 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +41 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/migrations/index.d.ts +34 -0
- package/dist/database/migrations/index.d.ts.map +1 -0
- package/dist/database/migrations/index.js +45 -0
- package/dist/database/migrations/index.js.map +1 -0
- package/dist/database/migrations/migrator.d.ts +77 -0
- package/dist/database/migrations/migrator.d.ts.map +1 -0
- package/dist/database/migrations/migrator.js +258 -0
- package/dist/database/migrations/migrator.js.map +1 -0
- package/dist/database/migrations/versions/001_initial.d.ts +9 -0
- package/dist/database/migrations/versions/001_initial.d.ts.map +1 -0
- package/dist/database/migrations/versions/001_initial.js +183 -0
- package/dist/database/migrations/versions/001_initial.js.map +1 -0
- package/dist/database/types.d.ts +255 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/database/types.js +8 -0
- package/dist/database/types.js.map +1 -0
- package/dist/database/vector/embedding-cache.d.ts +92 -0
- package/dist/database/vector/embedding-cache.d.ts.map +1 -0
- package/dist/database/vector/embedding-cache.js +185 -0
- package/dist/database/vector/embedding-cache.js.map +1 -0
- package/dist/database/vector/hnsw-index.d.ts +111 -0
- package/dist/database/vector/hnsw-index.d.ts.map +1 -0
- package/dist/database/vector/hnsw-index.js +337 -0
- package/dist/database/vector/hnsw-index.js.map +1 -0
- package/dist/database/vector/index.d.ts +75 -0
- package/dist/database/vector/index.d.ts.map +1 -0
- package/dist/database/vector/index.js +213 -0
- package/dist/database/vector/index.js.map +1 -0
- package/dist/database/vector/similarity.d.ts +67 -0
- package/dist/database/vector/similarity.d.ts.map +1 -0
- package/dist/database/vector/similarity.js +176 -0
- package/dist/database/vector/similarity.js.map +1 -0
- package/package.json +6 -3
- package/src/cli/index.ts +1 -1
- package/src/database/adapters/base-adapter.ts +171 -0
- package/src/database/adapters/index.ts +224 -0
- package/src/database/adapters/postgres-adapter.ts +285 -0
- package/src/database/adapters/sqlite-adapter.ts +420 -0
- package/src/database/cache/cache-keys.ts +150 -0
- package/src/database/cache/index.ts +44 -0
- package/src/database/cache/query-cache.ts +213 -0
- package/src/database/client.ts +166 -64
- package/src/database/db-config.ts +194 -0
- package/src/database/drizzle/index.ts +66 -0
- package/src/database/drizzle/schema/audit.ts +127 -0
- package/src/database/drizzle/schema/checkpoints.ts +164 -0
- package/src/database/drizzle/schema/conversations.ts +138 -0
- package/src/database/drizzle/schema/documents.ts +157 -0
- package/src/database/drizzle/schema/index.ts +139 -0
- package/src/database/drizzle/schema/memories.ts +127 -0
- package/src/database/drizzle/schema/tasks.ts +129 -0
- package/src/database/health/circuit-breaker.ts +214 -0
- package/src/database/health/health-monitor.ts +224 -0
- package/src/database/health/index.ts +41 -0
- package/src/database/index.ts +157 -0
- package/src/database/migrations/index.ts +52 -0
- package/src/database/migrations/migrator.ts +325 -0
- package/src/database/migrations/versions/001_initial.ts +198 -0
- package/src/database/types.ts +324 -0
- package/src/database/vector/embedding-cache.ts +234 -0
- package/src/database/vector/hnsw-index.ts +452 -0
- package/src/database/vector/index.ts +292 -0
- package/src/database/vector/similarity.ts +198 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Layer Types
|
|
3
|
+
*
|
|
4
|
+
* Shared TypeScript types for the database abstraction layer.
|
|
5
|
+
* Supports both PostgreSQL and SQLite backends.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { DrizzleConfig } from 'drizzle-orm';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Supported database types
|
|
12
|
+
*/
|
|
13
|
+
export type DatabaseType = 'postgresql' | 'sqlite';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Database detection modes
|
|
17
|
+
*/
|
|
18
|
+
export type DatabaseDetectionMode = 'auto' | 'postgresql' | 'sqlite';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Query result row constraint (compatible with pg.QueryResultRow)
|
|
22
|
+
*/
|
|
23
|
+
export type QueryResultRow = Record<string, any>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Query result interface (compatible with pg.QueryResult)
|
|
27
|
+
*/
|
|
28
|
+
export interface QueryResult<T extends QueryResultRow = Record<string, any>> {
|
|
29
|
+
rows: T[];
|
|
30
|
+
rowCount: number | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Transaction client interface
|
|
35
|
+
*/
|
|
36
|
+
export interface TransactionClient {
|
|
37
|
+
query<T extends QueryResultRow = Record<string, any>>(
|
|
38
|
+
sql: string,
|
|
39
|
+
params?: unknown[]
|
|
40
|
+
): Promise<QueryResult<T>>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Connection pool statistics
|
|
45
|
+
*/
|
|
46
|
+
export interface PoolStats {
|
|
47
|
+
total: number;
|
|
48
|
+
idle: number;
|
|
49
|
+
waiting: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Database health status
|
|
54
|
+
*/
|
|
55
|
+
export interface DatabaseHealth {
|
|
56
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
57
|
+
type: DatabaseType;
|
|
58
|
+
latencyMs: number;
|
|
59
|
+
poolStats?: PoolStats;
|
|
60
|
+
circuitState: CircuitBreakerState;
|
|
61
|
+
lastCheck: Date;
|
|
62
|
+
errors: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Circuit breaker states
|
|
67
|
+
*/
|
|
68
|
+
export type CircuitBreakerState = 'closed' | 'open' | 'half-open';
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Migration result
|
|
72
|
+
*/
|
|
73
|
+
export interface MigrationResult {
|
|
74
|
+
version: number;
|
|
75
|
+
name: string;
|
|
76
|
+
success: boolean;
|
|
77
|
+
error?: string;
|
|
78
|
+
durationMs: number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Cache statistics
|
|
83
|
+
*/
|
|
84
|
+
export interface CacheStats {
|
|
85
|
+
size: number;
|
|
86
|
+
maxSize: number;
|
|
87
|
+
hitCount: number;
|
|
88
|
+
missCount: number;
|
|
89
|
+
hitRate: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Vector search options
|
|
94
|
+
*/
|
|
95
|
+
export interface VectorSearchOptions {
|
|
96
|
+
userId?: string;
|
|
97
|
+
memoryType?: string;
|
|
98
|
+
limit?: number;
|
|
99
|
+
minSimilarity?: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Vector search result
|
|
104
|
+
*/
|
|
105
|
+
export interface VectorSearchResult {
|
|
106
|
+
id: string;
|
|
107
|
+
content: string;
|
|
108
|
+
similarity: number;
|
|
109
|
+
memoryType: string;
|
|
110
|
+
metadata: Record<string, unknown>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Embedding entry for vector index
|
|
115
|
+
*/
|
|
116
|
+
export interface EmbeddingEntry {
|
|
117
|
+
id: string;
|
|
118
|
+
vector: number[];
|
|
119
|
+
metadata?: Record<string, unknown>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Database adapter interface
|
|
124
|
+
*/
|
|
125
|
+
export interface DatabaseAdapter {
|
|
126
|
+
/** Database type */
|
|
127
|
+
readonly type: DatabaseType;
|
|
128
|
+
|
|
129
|
+
/** Whether the adapter is initialized */
|
|
130
|
+
readonly isInitialized: boolean;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Initialize the database connection
|
|
134
|
+
*/
|
|
135
|
+
initialize(): Promise<void>;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Execute a raw SQL query
|
|
139
|
+
*/
|
|
140
|
+
query<T extends QueryResultRow = Record<string, any>>(
|
|
141
|
+
sql: string,
|
|
142
|
+
params?: unknown[]
|
|
143
|
+
): Promise<QueryResult<T>>;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Execute a transaction
|
|
147
|
+
*/
|
|
148
|
+
transaction<T>(
|
|
149
|
+
callback: (client: TransactionClient) => Promise<T>
|
|
150
|
+
): Promise<T>;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Check database health
|
|
154
|
+
*/
|
|
155
|
+
healthCheck(): Promise<boolean>;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get connection pool statistics (PostgreSQL only)
|
|
159
|
+
*/
|
|
160
|
+
getPoolStats?(): PoolStats;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Close all connections
|
|
164
|
+
*/
|
|
165
|
+
close(): Promise<void>;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Vector search engine interface
|
|
170
|
+
*/
|
|
171
|
+
export interface VectorSearchEngine {
|
|
172
|
+
/**
|
|
173
|
+
* Initialize the vector index
|
|
174
|
+
*/
|
|
175
|
+
initialize(): Promise<void>;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Store an embedding
|
|
179
|
+
*/
|
|
180
|
+
store(
|
|
181
|
+
id: string,
|
|
182
|
+
embedding: number[],
|
|
183
|
+
metadata?: Record<string, unknown>
|
|
184
|
+
): Promise<void>;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Search for similar embeddings
|
|
188
|
+
*/
|
|
189
|
+
search(
|
|
190
|
+
queryEmbedding: number[],
|
|
191
|
+
options?: VectorSearchOptions
|
|
192
|
+
): Promise<VectorSearchResult[]>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Remove an embedding
|
|
196
|
+
*/
|
|
197
|
+
remove(id: string): Promise<void>;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Rebuild the vector index
|
|
201
|
+
*/
|
|
202
|
+
rebuildIndex(): Promise<void>;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get index statistics
|
|
206
|
+
*/
|
|
207
|
+
getStats(): { size: number; dimension: number };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Database detection result
|
|
212
|
+
*/
|
|
213
|
+
export interface DetectionResult {
|
|
214
|
+
type: DatabaseType;
|
|
215
|
+
connectionString?: string;
|
|
216
|
+
sqlitePath?: string;
|
|
217
|
+
reason: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Migration definition
|
|
222
|
+
*/
|
|
223
|
+
export interface Migration {
|
|
224
|
+
version: number;
|
|
225
|
+
name: string;
|
|
226
|
+
up: (adapter: DatabaseAdapter) => Promise<void>;
|
|
227
|
+
down: (adapter: DatabaseAdapter) => Promise<void>;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Cache entry
|
|
232
|
+
*/
|
|
233
|
+
export interface CacheEntry<T> {
|
|
234
|
+
value: T;
|
|
235
|
+
expiresAt: number;
|
|
236
|
+
hits: number;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Query cache options
|
|
241
|
+
*/
|
|
242
|
+
export interface QueryCacheOptions {
|
|
243
|
+
maxSize: number;
|
|
244
|
+
defaultTtlMs: number;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Circuit breaker options
|
|
249
|
+
*/
|
|
250
|
+
export interface CircuitBreakerOptions {
|
|
251
|
+
failureThreshold: number;
|
|
252
|
+
resetTimeoutMs: number;
|
|
253
|
+
halfOpenMaxAttempts: number;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Health monitor options
|
|
258
|
+
*/
|
|
259
|
+
export interface HealthMonitorOptions {
|
|
260
|
+
checkIntervalMs: number;
|
|
261
|
+
errorThreshold: number;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Database configuration
|
|
266
|
+
*/
|
|
267
|
+
export interface DatabaseConfig {
|
|
268
|
+
// Detection mode
|
|
269
|
+
type: DatabaseDetectionMode;
|
|
270
|
+
|
|
271
|
+
// PostgreSQL settings
|
|
272
|
+
postgresUrl?: string;
|
|
273
|
+
postgresHost: string;
|
|
274
|
+
postgresPort: number;
|
|
275
|
+
postgresUser: string;
|
|
276
|
+
postgresPassword: string;
|
|
277
|
+
postgresDatabase: string;
|
|
278
|
+
postgresPoolMax: number;
|
|
279
|
+
postgresIdleTimeoutMs: number;
|
|
280
|
+
postgresConnectionTimeoutMs: number;
|
|
281
|
+
|
|
282
|
+
// SQLite settings
|
|
283
|
+
sqlitePath?: string;
|
|
284
|
+
|
|
285
|
+
// Health monitoring
|
|
286
|
+
healthCheckIntervalMs: number;
|
|
287
|
+
circuitBreakerThreshold: number;
|
|
288
|
+
circuitBreakerTimeoutMs: number;
|
|
289
|
+
|
|
290
|
+
// Cache settings
|
|
291
|
+
cacheMaxSize: number;
|
|
292
|
+
cacheTtlMs: number;
|
|
293
|
+
|
|
294
|
+
// Vector settings
|
|
295
|
+
vectorDimension: number;
|
|
296
|
+
vectorMinSimilarity: number;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Memory types for vector storage
|
|
301
|
+
*/
|
|
302
|
+
export type MemoryType = 'semantic' | 'episodic' | 'procedural';
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Message roles
|
|
306
|
+
*/
|
|
307
|
+
export type MessageRole = 'user' | 'assistant' | 'system';
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Task status
|
|
311
|
+
*/
|
|
312
|
+
export type TaskStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Audit log action types
|
|
316
|
+
*/
|
|
317
|
+
export type AuditActionType =
|
|
318
|
+
| 'chat_message'
|
|
319
|
+
| 'memory_store'
|
|
320
|
+
| 'memory_search'
|
|
321
|
+
| 'document_upload'
|
|
322
|
+
| 'agent_invocation'
|
|
323
|
+
| 'tool_execution'
|
|
324
|
+
| 'safety_block';
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedding Cache
|
|
3
|
+
*
|
|
4
|
+
* LRU cache for embeddings to avoid redundant database queries.
|
|
5
|
+
* Improves performance for frequently accessed vectors.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createLogger } from '../../utils/logger.js';
|
|
9
|
+
|
|
10
|
+
const logger = createLogger('EmbeddingCache');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Cache entry with metadata
|
|
14
|
+
*/
|
|
15
|
+
interface CacheEntry {
|
|
16
|
+
embedding: number[];
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
accessCount: number;
|
|
19
|
+
lastAccessed: number;
|
|
20
|
+
addedAt: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Cache statistics
|
|
25
|
+
*/
|
|
26
|
+
export interface EmbeddingCacheStats {
|
|
27
|
+
size: number;
|
|
28
|
+
maxSize: number;
|
|
29
|
+
hitCount: number;
|
|
30
|
+
missCount: number;
|
|
31
|
+
hitRate: number;
|
|
32
|
+
memoryUsageBytes: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* LRU cache for embeddings
|
|
37
|
+
*/
|
|
38
|
+
export class EmbeddingCache {
|
|
39
|
+
private cache: Map<string, CacheEntry> = new Map();
|
|
40
|
+
private maxSize: number;
|
|
41
|
+
private hitCount: number = 0;
|
|
42
|
+
private missCount: number = 0;
|
|
43
|
+
private dimension: number;
|
|
44
|
+
|
|
45
|
+
constructor(options: { maxSize?: number; dimension?: number } = {}) {
|
|
46
|
+
this.maxSize = options.maxSize ?? 10000;
|
|
47
|
+
this.dimension = options.dimension ?? 1536;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get embedding from cache
|
|
52
|
+
*/
|
|
53
|
+
get(id: string): number[] | undefined {
|
|
54
|
+
const entry = this.cache.get(id);
|
|
55
|
+
|
|
56
|
+
if (!entry) {
|
|
57
|
+
this.missCount++;
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Update access metadata
|
|
62
|
+
entry.accessCount++;
|
|
63
|
+
entry.lastAccessed = Date.now();
|
|
64
|
+
|
|
65
|
+
// Move to end for LRU
|
|
66
|
+
this.cache.delete(id);
|
|
67
|
+
this.cache.set(id, entry);
|
|
68
|
+
|
|
69
|
+
this.hitCount++;
|
|
70
|
+
return entry.embedding;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Set embedding in cache
|
|
75
|
+
*/
|
|
76
|
+
set(id: string, embedding: number[], metadata?: Record<string, unknown>): void {
|
|
77
|
+
// Evict if at capacity
|
|
78
|
+
if (this.cache.size >= this.maxSize && !this.cache.has(id)) {
|
|
79
|
+
this.evictLRU();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const entry: CacheEntry = {
|
|
83
|
+
embedding,
|
|
84
|
+
metadata,
|
|
85
|
+
accessCount: 1,
|
|
86
|
+
lastAccessed: Date.now(),
|
|
87
|
+
addedAt: Date.now(),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Delete first to ensure it's at the end
|
|
91
|
+
this.cache.delete(id);
|
|
92
|
+
this.cache.set(id, entry);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Check if ID is in cache
|
|
97
|
+
*/
|
|
98
|
+
has(id: string): boolean {
|
|
99
|
+
return this.cache.has(id);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Remove embedding from cache
|
|
104
|
+
*/
|
|
105
|
+
delete(id: string): boolean {
|
|
106
|
+
return this.cache.delete(id);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Clear the cache
|
|
111
|
+
*/
|
|
112
|
+
clear(): void {
|
|
113
|
+
this.cache.clear();
|
|
114
|
+
this.hitCount = 0;
|
|
115
|
+
this.missCount = 0;
|
|
116
|
+
logger.debug('Embedding cache cleared');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Evict least recently used entry
|
|
121
|
+
*/
|
|
122
|
+
private evictLRU(): void {
|
|
123
|
+
// First entry is LRU due to Map ordering
|
|
124
|
+
const firstKey = this.cache.keys().next().value;
|
|
125
|
+
if (firstKey) {
|
|
126
|
+
this.cache.delete(firstKey);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Evict entries matching a pattern
|
|
132
|
+
*/
|
|
133
|
+
evictPattern(pattern: (id: string) => boolean): number {
|
|
134
|
+
let count = 0;
|
|
135
|
+
for (const id of this.cache.keys()) {
|
|
136
|
+
if (pattern(id)) {
|
|
137
|
+
this.cache.delete(id);
|
|
138
|
+
count++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return count;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get multiple embeddings (batch)
|
|
146
|
+
*/
|
|
147
|
+
getMany(ids: string[]): Map<string, number[]> {
|
|
148
|
+
const result = new Map<string, number[]>();
|
|
149
|
+
for (const id of ids) {
|
|
150
|
+
const embedding = this.get(id);
|
|
151
|
+
if (embedding) {
|
|
152
|
+
result.set(id, embedding);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Set multiple embeddings (batch)
|
|
160
|
+
*/
|
|
161
|
+
setMany(entries: Array<{ id: string; embedding: number[]; metadata?: Record<string, unknown> }>): void {
|
|
162
|
+
for (const { id, embedding, metadata } of entries) {
|
|
163
|
+
this.set(id, embedding, metadata);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get cache statistics
|
|
169
|
+
*/
|
|
170
|
+
getStats(): EmbeddingCacheStats {
|
|
171
|
+
const totalRequests = this.hitCount + this.missCount;
|
|
172
|
+
const memoryUsageBytes = this.cache.size * this.dimension * 4; // 4 bytes per float32
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
size: this.cache.size,
|
|
176
|
+
maxSize: this.maxSize,
|
|
177
|
+
hitCount: this.hitCount,
|
|
178
|
+
missCount: this.missCount,
|
|
179
|
+
hitRate: totalRequests > 0 ? this.hitCount / totalRequests : 0,
|
|
180
|
+
memoryUsageBytes,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Get cache size
|
|
186
|
+
*/
|
|
187
|
+
get size(): number {
|
|
188
|
+
return this.cache.size;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Preload embeddings from database records
|
|
193
|
+
*/
|
|
194
|
+
preload(records: Array<{ id: string; embedding: number[] | string }>): void {
|
|
195
|
+
for (const record of records) {
|
|
196
|
+
let embedding: number[];
|
|
197
|
+
|
|
198
|
+
if (typeof record.embedding === 'string') {
|
|
199
|
+
try {
|
|
200
|
+
embedding = JSON.parse(record.embedding);
|
|
201
|
+
} catch {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
embedding = record.embedding;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
this.set(record.id, embedding);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
logger.debug('Embeddings preloaded', { count: records.length });
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Trim cache to a smaller size
|
|
216
|
+
*/
|
|
217
|
+
trim(newMaxSize: number): void {
|
|
218
|
+
if (newMaxSize >= this.cache.size) return;
|
|
219
|
+
|
|
220
|
+
const toRemove = this.cache.size - newMaxSize;
|
|
221
|
+
let removed = 0;
|
|
222
|
+
|
|
223
|
+
for (const id of this.cache.keys()) {
|
|
224
|
+
if (removed >= toRemove) break;
|
|
225
|
+
this.cache.delete(id);
|
|
226
|
+
removed++;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
this.maxSize = newMaxSize;
|
|
230
|
+
logger.debug('Cache trimmed', { removed, newSize: this.cache.size });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export default EmbeddingCache;
|