@twelvehart/supermemory-runtime 1.0.0-next.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/.env.example +57 -0
- package/README.md +374 -0
- package/dist/index.js +189 -0
- package/dist/mcp/index.js +1132 -0
- package/docker-compose.prod.yml +91 -0
- package/docker-compose.yml +358 -0
- package/drizzle/0000_dapper_the_professor.sql +159 -0
- package/drizzle/0001_api_keys.sql +51 -0
- package/drizzle/meta/0000_snapshot.json +1532 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +20 -0
- package/package.json +114 -0
- package/scripts/add-extraction-job.ts +122 -0
- package/scripts/benchmark-pgvector.ts +122 -0
- package/scripts/bootstrap.sh +209 -0
- package/scripts/check-runtime-pack.ts +111 -0
- package/scripts/claude-mcp-config.ts +336 -0
- package/scripts/docker-entrypoint.sh +183 -0
- package/scripts/doctor.ts +377 -0
- package/scripts/init-db.sql +33 -0
- package/scripts/install.sh +1110 -0
- package/scripts/mcp-setup.ts +271 -0
- package/scripts/migrations/001_create_pgvector_extension.sql +31 -0
- package/scripts/migrations/002_create_memory_embeddings_table.sql +75 -0
- package/scripts/migrations/003_create_hnsw_index.sql +94 -0
- package/scripts/migrations/004_create_memory_embeddings_standalone.sql +70 -0
- package/scripts/migrations/005_create_chunks_table.sql +95 -0
- package/scripts/migrations/006_create_processing_queue.sql +45 -0
- package/scripts/migrations/generate_test_data.sql +42 -0
- package/scripts/migrations/phase1_comprehensive_test.sql +204 -0
- package/scripts/migrations/run_migrations.sh +286 -0
- package/scripts/migrations/test_hnsw_index.sql +255 -0
- package/scripts/pre-commit-secrets +282 -0
- package/scripts/run-extraction-worker.ts +46 -0
- package/scripts/run-phase1-tests.sh +291 -0
- package/scripts/setup.ts +222 -0
- package/scripts/smoke-install.sh +12 -0
- package/scripts/test-health-endpoint.sh +328 -0
- package/src/api/index.ts +2 -0
- package/src/api/middleware/auth.ts +80 -0
- package/src/api/middleware/csrf.ts +308 -0
- package/src/api/middleware/errorHandler.ts +166 -0
- package/src/api/middleware/rateLimit.ts +360 -0
- package/src/api/middleware/validation.ts +514 -0
- package/src/api/routes/documents.ts +286 -0
- package/src/api/routes/profiles.ts +237 -0
- package/src/api/routes/search.ts +71 -0
- package/src/api/stores/index.ts +58 -0
- package/src/config/bootstrap-env.ts +3 -0
- package/src/config/env.ts +71 -0
- package/src/config/feature-flags.ts +25 -0
- package/src/config/index.ts +140 -0
- package/src/config/secrets.config.ts +291 -0
- package/src/db/client.ts +92 -0
- package/src/db/index.ts +73 -0
- package/src/db/postgres.ts +72 -0
- package/src/db/schema/chunks.schema.ts +31 -0
- package/src/db/schema/containers.schema.ts +46 -0
- package/src/db/schema/documents.schema.ts +49 -0
- package/src/db/schema/embeddings.schema.ts +32 -0
- package/src/db/schema/index.ts +11 -0
- package/src/db/schema/memories.schema.ts +72 -0
- package/src/db/schema/profiles.schema.ts +34 -0
- package/src/db/schema/queue.schema.ts +59 -0
- package/src/db/schema/relationships.schema.ts +42 -0
- package/src/db/schema.ts +223 -0
- package/src/db/worker-connection.ts +47 -0
- package/src/index.ts +235 -0
- package/src/mcp/CLAUDE.md +1 -0
- package/src/mcp/index.ts +1380 -0
- package/src/mcp/legacyState.ts +22 -0
- package/src/mcp/rateLimit.ts +358 -0
- package/src/mcp/resources.ts +309 -0
- package/src/mcp/results.ts +104 -0
- package/src/mcp/tools.ts +401 -0
- package/src/queues/config.ts +119 -0
- package/src/queues/index.ts +289 -0
- package/src/sdk/client.ts +225 -0
- package/src/sdk/errors.ts +266 -0
- package/src/sdk/http.ts +560 -0
- package/src/sdk/index.ts +244 -0
- package/src/sdk/resources/base.ts +65 -0
- package/src/sdk/resources/connections.ts +204 -0
- package/src/sdk/resources/documents.ts +163 -0
- package/src/sdk/resources/index.ts +10 -0
- package/src/sdk/resources/memories.ts +150 -0
- package/src/sdk/resources/search.ts +60 -0
- package/src/sdk/resources/settings.ts +36 -0
- package/src/sdk/types.ts +674 -0
- package/src/services/chunking/index.ts +451 -0
- package/src/services/chunking.service.ts +650 -0
- package/src/services/csrf.service.ts +252 -0
- package/src/services/documents.repository.ts +219 -0
- package/src/services/documents.service.ts +191 -0
- package/src/services/embedding.service.ts +404 -0
- package/src/services/extraction.service.ts +300 -0
- package/src/services/extractors/code.extractor.ts +451 -0
- package/src/services/extractors/index.ts +9 -0
- package/src/services/extractors/markdown.extractor.ts +461 -0
- package/src/services/extractors/pdf.extractor.ts +315 -0
- package/src/services/extractors/text.extractor.ts +118 -0
- package/src/services/extractors/url.extractor.ts +243 -0
- package/src/services/index.ts +235 -0
- package/src/services/ingestion.service.ts +177 -0
- package/src/services/llm/anthropic.ts +400 -0
- package/src/services/llm/base.ts +460 -0
- package/src/services/llm/contradiction-detector.service.ts +526 -0
- package/src/services/llm/heuristics.ts +148 -0
- package/src/services/llm/index.ts +309 -0
- package/src/services/llm/memory-classifier.service.ts +383 -0
- package/src/services/llm/memory-extension-detector.service.ts +523 -0
- package/src/services/llm/mock.ts +470 -0
- package/src/services/llm/openai.ts +398 -0
- package/src/services/llm/prompts.ts +438 -0
- package/src/services/llm/types.ts +373 -0
- package/src/services/memory.repository.ts +1769 -0
- package/src/services/memory.service.ts +1338 -0
- package/src/services/memory.types.ts +234 -0
- package/src/services/persistence/index.ts +295 -0
- package/src/services/pipeline.service.ts +509 -0
- package/src/services/profile.repository.ts +436 -0
- package/src/services/profile.service.ts +560 -0
- package/src/services/profile.types.ts +270 -0
- package/src/services/relationships/detector.ts +1128 -0
- package/src/services/relationships/index.ts +268 -0
- package/src/services/relationships/memory-integration.ts +459 -0
- package/src/services/relationships/strategies.ts +132 -0
- package/src/services/relationships/types.ts +370 -0
- package/src/services/search.service.ts +761 -0
- package/src/services/search.types.ts +220 -0
- package/src/services/secrets.service.ts +384 -0
- package/src/services/vectorstore/base.ts +327 -0
- package/src/services/vectorstore/index.ts +444 -0
- package/src/services/vectorstore/memory.ts +286 -0
- package/src/services/vectorstore/migration.ts +295 -0
- package/src/services/vectorstore/mock.ts +403 -0
- package/src/services/vectorstore/pgvector.ts +695 -0
- package/src/services/vectorstore/types.ts +247 -0
- package/src/startup.ts +389 -0
- package/src/types/api.types.ts +193 -0
- package/src/types/document.types.ts +103 -0
- package/src/types/index.ts +241 -0
- package/src/types/profile.base.ts +133 -0
- package/src/utils/errors.ts +447 -0
- package/src/utils/id.ts +15 -0
- package/src/utils/index.ts +101 -0
- package/src/utils/logger.ts +313 -0
- package/src/utils/sanitization.ts +501 -0
- package/src/utils/secret-validation.ts +273 -0
- package/src/utils/synonyms.ts +188 -0
- package/src/utils/validation.ts +581 -0
- package/src/workers/chunking.worker.ts +242 -0
- package/src/workers/embedding.worker.ts +358 -0
- package/src/workers/extraction.worker.ts +346 -0
- package/src/workers/indexing.worker.ts +505 -0
- package/tsconfig.json +38 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Vector Store
|
|
3
|
+
*
|
|
4
|
+
* Abstract base class for vector store implementations.
|
|
5
|
+
* Provides common utilities and defines the interface that all
|
|
6
|
+
* vector store implementations must follow.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
VectorEntry,
|
|
11
|
+
VectorSearchResult,
|
|
12
|
+
SearchOptions,
|
|
13
|
+
AddOptions,
|
|
14
|
+
DeleteOptions,
|
|
15
|
+
VectorStoreConfig,
|
|
16
|
+
VectorStoreStats,
|
|
17
|
+
BatchResult,
|
|
18
|
+
MetadataFilter,
|
|
19
|
+
SimilarityMetric,
|
|
20
|
+
DEFAULT_SEARCH_OPTIONS,
|
|
21
|
+
VectorStoreEvent,
|
|
22
|
+
VectorStoreEventListener,
|
|
23
|
+
} from './types.js'
|
|
24
|
+
import { ValidationError } from '../../utils/errors.js'
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Calculate cosine similarity between two vectors
|
|
28
|
+
*/
|
|
29
|
+
export function cosineSimilarity(a: number[], b: number[]): number {
|
|
30
|
+
if (a.length !== b.length) {
|
|
31
|
+
throw new ValidationError(`Vector dimension mismatch: ${a.length} vs ${b.length}`, {
|
|
32
|
+
vectorA: [`Expected dimension ${b.length}, got ${a.length}`],
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let dotProduct = 0
|
|
37
|
+
let normA = 0
|
|
38
|
+
let normB = 0
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < a.length; i++) {
|
|
41
|
+
const aVal = a[i] ?? 0
|
|
42
|
+
const bVal = b[i] ?? 0
|
|
43
|
+
dotProduct += aVal * bVal
|
|
44
|
+
normA += aVal * aVal
|
|
45
|
+
normB += bVal * bVal
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const magnitude = Math.sqrt(normA) * Math.sqrt(normB)
|
|
49
|
+
if (magnitude === 0) return 0
|
|
50
|
+
|
|
51
|
+
return dotProduct / magnitude
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Calculate Euclidean distance between two vectors
|
|
56
|
+
*/
|
|
57
|
+
export function euclideanDistance(a: number[], b: number[]): number {
|
|
58
|
+
if (a.length !== b.length) {
|
|
59
|
+
throw new ValidationError(`Vector dimension mismatch: ${a.length} vs ${b.length}`, {
|
|
60
|
+
vectorA: [`Expected dimension ${b.length}, got ${a.length}`],
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let sum = 0
|
|
65
|
+
for (let i = 0; i < a.length; i++) {
|
|
66
|
+
const diff = (a[i] ?? 0) - (b[i] ?? 0)
|
|
67
|
+
sum += diff * diff
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return Math.sqrt(sum)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Calculate dot product between two vectors
|
|
75
|
+
*/
|
|
76
|
+
export function dotProduct(a: number[], b: number[]): number {
|
|
77
|
+
if (a.length !== b.length) {
|
|
78
|
+
throw new ValidationError(`Vector dimension mismatch: ${a.length} vs ${b.length}`, {
|
|
79
|
+
vectorA: [`Expected dimension ${b.length}, got ${a.length}`],
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let sum = 0
|
|
84
|
+
for (let i = 0; i < a.length; i++) {
|
|
85
|
+
sum += (a[i] ?? 0) * (b[i] ?? 0)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return sum
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Normalize a vector to unit length (L2 normalization)
|
|
93
|
+
*/
|
|
94
|
+
export function normalizeVector(vector: number[]): number[] {
|
|
95
|
+
const magnitude = Math.sqrt(vector.reduce((sum, val) => sum + val * val, 0))
|
|
96
|
+
if (magnitude === 0) return vector
|
|
97
|
+
return vector.map((val) => val / magnitude)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Validate vector dimensions
|
|
102
|
+
*/
|
|
103
|
+
export function validateVector(vector: number[], expectedDimensions: number): void {
|
|
104
|
+
if (!Array.isArray(vector)) {
|
|
105
|
+
throw new ValidationError('Vector must be an array', {
|
|
106
|
+
vector: ['Vector must be an array of numbers'],
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
if (vector.length !== expectedDimensions) {
|
|
110
|
+
throw new ValidationError(`Vector dimension mismatch: expected ${expectedDimensions}, got ${vector.length}`, {
|
|
111
|
+
vector: [`Expected ${expectedDimensions} dimensions, got ${vector.length}`],
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
if (vector.some((v) => typeof v !== 'number' || Number.isNaN(v))) {
|
|
115
|
+
throw new ValidationError('Vector must contain only valid numbers', {
|
|
116
|
+
vector: ['All vector elements must be valid numbers (no NaN or non-numeric values)'],
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Abstract base class for vector stores
|
|
123
|
+
*/
|
|
124
|
+
export abstract class BaseVectorStore {
|
|
125
|
+
protected readonly config: VectorStoreConfig
|
|
126
|
+
protected readonly listeners: VectorStoreEventListener[] = []
|
|
127
|
+
|
|
128
|
+
constructor(config: VectorStoreConfig) {
|
|
129
|
+
this.config = {
|
|
130
|
+
metric: 'cosine',
|
|
131
|
+
indexType: 'flat',
|
|
132
|
+
defaultNamespace: 'default',
|
|
133
|
+
...config,
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get the configured dimensions
|
|
139
|
+
*/
|
|
140
|
+
getDimensions(): number {
|
|
141
|
+
return this.config.dimensions
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get the configured similarity metric
|
|
146
|
+
*/
|
|
147
|
+
getMetric(): SimilarityMetric {
|
|
148
|
+
return this.config.metric ?? 'cosine'
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Calculate similarity between two vectors using configured metric
|
|
153
|
+
*/
|
|
154
|
+
calculateSimilarity(a: number[], b: number[]): number {
|
|
155
|
+
const metric = this.getMetric()
|
|
156
|
+
switch (metric) {
|
|
157
|
+
case 'cosine':
|
|
158
|
+
return cosineSimilarity(a, b)
|
|
159
|
+
case 'euclidean':
|
|
160
|
+
// Convert distance to similarity (1 / (1 + distance))
|
|
161
|
+
return 1 / (1 + euclideanDistance(a, b))
|
|
162
|
+
case 'dot_product':
|
|
163
|
+
return dotProduct(a, b)
|
|
164
|
+
default:
|
|
165
|
+
return cosineSimilarity(a, b)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Validate a vector entry
|
|
171
|
+
*/
|
|
172
|
+
protected validateEntry(entry: VectorEntry): void {
|
|
173
|
+
if (!entry.id || typeof entry.id !== 'string') {
|
|
174
|
+
throw new ValidationError('Vector entry must have a valid string ID', {
|
|
175
|
+
id: ['Entry ID must be a non-empty string'],
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
validateVector(entry.embedding, this.config.dimensions)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Apply metadata filters to entries
|
|
183
|
+
*/
|
|
184
|
+
protected applyFilters(entries: VectorEntry[], filters?: MetadataFilter[]): VectorEntry[] {
|
|
185
|
+
if (!filters || filters.length === 0) {
|
|
186
|
+
return entries
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return entries.filter((entry) => {
|
|
190
|
+
return filters.every((filter) => this.matchesFilter(entry.metadata, filter))
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Check if metadata matches a filter
|
|
196
|
+
*/
|
|
197
|
+
protected matchesFilter(metadata: Record<string, unknown>, filter: MetadataFilter): boolean {
|
|
198
|
+
const value = metadata[filter.key]
|
|
199
|
+
if (value === undefined) return false
|
|
200
|
+
|
|
201
|
+
switch (filter.operator) {
|
|
202
|
+
case 'eq':
|
|
203
|
+
return value === filter.value
|
|
204
|
+
case 'ne':
|
|
205
|
+
return value !== filter.value
|
|
206
|
+
case 'gt':
|
|
207
|
+
return typeof value === 'number' && typeof filter.value === 'number' && value > filter.value
|
|
208
|
+
case 'gte':
|
|
209
|
+
return typeof value === 'number' && typeof filter.value === 'number' && value >= filter.value
|
|
210
|
+
case 'lt':
|
|
211
|
+
return typeof value === 'number' && typeof filter.value === 'number' && value < filter.value
|
|
212
|
+
case 'lte':
|
|
213
|
+
return typeof value === 'number' && typeof filter.value === 'number' && value <= filter.value
|
|
214
|
+
case 'in':
|
|
215
|
+
return Array.isArray(filter.value) && filter.value.includes(value as string | number)
|
|
216
|
+
case 'nin':
|
|
217
|
+
return Array.isArray(filter.value) && !filter.value.includes(value as string | number)
|
|
218
|
+
case 'contains':
|
|
219
|
+
return typeof value === 'string' && typeof filter.value === 'string' && value.includes(filter.value)
|
|
220
|
+
case 'startsWith':
|
|
221
|
+
return typeof value === 'string' && typeof filter.value === 'string' && value.startsWith(filter.value)
|
|
222
|
+
default:
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Merge search options with defaults
|
|
229
|
+
*/
|
|
230
|
+
protected mergeOptions(options?: SearchOptions): Required<Omit<SearchOptions, 'filters'>> & {
|
|
231
|
+
filters?: MetadataFilter[]
|
|
232
|
+
} {
|
|
233
|
+
return {
|
|
234
|
+
...DEFAULT_SEARCH_OPTIONS,
|
|
235
|
+
...options,
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Add an event listener
|
|
241
|
+
*/
|
|
242
|
+
addEventListener(event: VectorStoreEvent, callback: (data: unknown) => void): void {
|
|
243
|
+
this.listeners.push({ event, callback })
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Remove an event listener
|
|
248
|
+
*/
|
|
249
|
+
removeEventListener(event: VectorStoreEvent, callback: (data: unknown) => void): void {
|
|
250
|
+
const index = this.listeners.findIndex((l) => l.event === event && l.callback === callback)
|
|
251
|
+
if (index !== -1) {
|
|
252
|
+
this.listeners.splice(index, 1)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Emit an event to all listeners
|
|
258
|
+
*/
|
|
259
|
+
protected emit(event: VectorStoreEvent, data: unknown): void {
|
|
260
|
+
for (const listener of this.listeners) {
|
|
261
|
+
if (listener.event === event) {
|
|
262
|
+
try {
|
|
263
|
+
listener.callback(data)
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.error(`Error in vector store event listener:`, error)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Abstract methods that must be implemented by subclasses
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Initialize the vector store
|
|
275
|
+
*/
|
|
276
|
+
abstract initialize(): Promise<void>
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Add a single vector entry
|
|
280
|
+
*/
|
|
281
|
+
abstract add(entry: VectorEntry, options?: AddOptions): Promise<void>
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Add multiple vector entries
|
|
285
|
+
*/
|
|
286
|
+
abstract addBatch(entries: VectorEntry[], options?: AddOptions): Promise<BatchResult>
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Update an existing vector entry
|
|
290
|
+
*/
|
|
291
|
+
abstract update(id: string, entry: Partial<VectorEntry>): Promise<boolean>
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Delete vector entries
|
|
295
|
+
*/
|
|
296
|
+
abstract delete(options: DeleteOptions): Promise<number>
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Get a vector entry by ID
|
|
300
|
+
*/
|
|
301
|
+
abstract get(id: string): Promise<VectorEntry | null>
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Check if a vector entry exists
|
|
305
|
+
*/
|
|
306
|
+
abstract exists(id: string): Promise<boolean>
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Search for similar vectors
|
|
310
|
+
*/
|
|
311
|
+
abstract search(query: number[], options?: SearchOptions): Promise<VectorSearchResult[]>
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Get statistics about the vector store
|
|
315
|
+
*/
|
|
316
|
+
abstract getStats(): Promise<VectorStoreStats>
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Clear all vectors from the store
|
|
320
|
+
*/
|
|
321
|
+
abstract clear(): Promise<void>
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Close the vector store and release resources
|
|
325
|
+
*/
|
|
326
|
+
abstract close(): Promise<void>
|
|
327
|
+
}
|