@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.
Files changed (156) hide show
  1. package/.env.example +57 -0
  2. package/README.md +374 -0
  3. package/dist/index.js +189 -0
  4. package/dist/mcp/index.js +1132 -0
  5. package/docker-compose.prod.yml +91 -0
  6. package/docker-compose.yml +358 -0
  7. package/drizzle/0000_dapper_the_professor.sql +159 -0
  8. package/drizzle/0001_api_keys.sql +51 -0
  9. package/drizzle/meta/0000_snapshot.json +1532 -0
  10. package/drizzle/meta/_journal.json +13 -0
  11. package/drizzle.config.ts +20 -0
  12. package/package.json +114 -0
  13. package/scripts/add-extraction-job.ts +122 -0
  14. package/scripts/benchmark-pgvector.ts +122 -0
  15. package/scripts/bootstrap.sh +209 -0
  16. package/scripts/check-runtime-pack.ts +111 -0
  17. package/scripts/claude-mcp-config.ts +336 -0
  18. package/scripts/docker-entrypoint.sh +183 -0
  19. package/scripts/doctor.ts +377 -0
  20. package/scripts/init-db.sql +33 -0
  21. package/scripts/install.sh +1110 -0
  22. package/scripts/mcp-setup.ts +271 -0
  23. package/scripts/migrations/001_create_pgvector_extension.sql +31 -0
  24. package/scripts/migrations/002_create_memory_embeddings_table.sql +75 -0
  25. package/scripts/migrations/003_create_hnsw_index.sql +94 -0
  26. package/scripts/migrations/004_create_memory_embeddings_standalone.sql +70 -0
  27. package/scripts/migrations/005_create_chunks_table.sql +95 -0
  28. package/scripts/migrations/006_create_processing_queue.sql +45 -0
  29. package/scripts/migrations/generate_test_data.sql +42 -0
  30. package/scripts/migrations/phase1_comprehensive_test.sql +204 -0
  31. package/scripts/migrations/run_migrations.sh +286 -0
  32. package/scripts/migrations/test_hnsw_index.sql +255 -0
  33. package/scripts/pre-commit-secrets +282 -0
  34. package/scripts/run-extraction-worker.ts +46 -0
  35. package/scripts/run-phase1-tests.sh +291 -0
  36. package/scripts/setup.ts +222 -0
  37. package/scripts/smoke-install.sh +12 -0
  38. package/scripts/test-health-endpoint.sh +328 -0
  39. package/src/api/index.ts +2 -0
  40. package/src/api/middleware/auth.ts +80 -0
  41. package/src/api/middleware/csrf.ts +308 -0
  42. package/src/api/middleware/errorHandler.ts +166 -0
  43. package/src/api/middleware/rateLimit.ts +360 -0
  44. package/src/api/middleware/validation.ts +514 -0
  45. package/src/api/routes/documents.ts +286 -0
  46. package/src/api/routes/profiles.ts +237 -0
  47. package/src/api/routes/search.ts +71 -0
  48. package/src/api/stores/index.ts +58 -0
  49. package/src/config/bootstrap-env.ts +3 -0
  50. package/src/config/env.ts +71 -0
  51. package/src/config/feature-flags.ts +25 -0
  52. package/src/config/index.ts +140 -0
  53. package/src/config/secrets.config.ts +291 -0
  54. package/src/db/client.ts +92 -0
  55. package/src/db/index.ts +73 -0
  56. package/src/db/postgres.ts +72 -0
  57. package/src/db/schema/chunks.schema.ts +31 -0
  58. package/src/db/schema/containers.schema.ts +46 -0
  59. package/src/db/schema/documents.schema.ts +49 -0
  60. package/src/db/schema/embeddings.schema.ts +32 -0
  61. package/src/db/schema/index.ts +11 -0
  62. package/src/db/schema/memories.schema.ts +72 -0
  63. package/src/db/schema/profiles.schema.ts +34 -0
  64. package/src/db/schema/queue.schema.ts +59 -0
  65. package/src/db/schema/relationships.schema.ts +42 -0
  66. package/src/db/schema.ts +223 -0
  67. package/src/db/worker-connection.ts +47 -0
  68. package/src/index.ts +235 -0
  69. package/src/mcp/CLAUDE.md +1 -0
  70. package/src/mcp/index.ts +1380 -0
  71. package/src/mcp/legacyState.ts +22 -0
  72. package/src/mcp/rateLimit.ts +358 -0
  73. package/src/mcp/resources.ts +309 -0
  74. package/src/mcp/results.ts +104 -0
  75. package/src/mcp/tools.ts +401 -0
  76. package/src/queues/config.ts +119 -0
  77. package/src/queues/index.ts +289 -0
  78. package/src/sdk/client.ts +225 -0
  79. package/src/sdk/errors.ts +266 -0
  80. package/src/sdk/http.ts +560 -0
  81. package/src/sdk/index.ts +244 -0
  82. package/src/sdk/resources/base.ts +65 -0
  83. package/src/sdk/resources/connections.ts +204 -0
  84. package/src/sdk/resources/documents.ts +163 -0
  85. package/src/sdk/resources/index.ts +10 -0
  86. package/src/sdk/resources/memories.ts +150 -0
  87. package/src/sdk/resources/search.ts +60 -0
  88. package/src/sdk/resources/settings.ts +36 -0
  89. package/src/sdk/types.ts +674 -0
  90. package/src/services/chunking/index.ts +451 -0
  91. package/src/services/chunking.service.ts +650 -0
  92. package/src/services/csrf.service.ts +252 -0
  93. package/src/services/documents.repository.ts +219 -0
  94. package/src/services/documents.service.ts +191 -0
  95. package/src/services/embedding.service.ts +404 -0
  96. package/src/services/extraction.service.ts +300 -0
  97. package/src/services/extractors/code.extractor.ts +451 -0
  98. package/src/services/extractors/index.ts +9 -0
  99. package/src/services/extractors/markdown.extractor.ts +461 -0
  100. package/src/services/extractors/pdf.extractor.ts +315 -0
  101. package/src/services/extractors/text.extractor.ts +118 -0
  102. package/src/services/extractors/url.extractor.ts +243 -0
  103. package/src/services/index.ts +235 -0
  104. package/src/services/ingestion.service.ts +177 -0
  105. package/src/services/llm/anthropic.ts +400 -0
  106. package/src/services/llm/base.ts +460 -0
  107. package/src/services/llm/contradiction-detector.service.ts +526 -0
  108. package/src/services/llm/heuristics.ts +148 -0
  109. package/src/services/llm/index.ts +309 -0
  110. package/src/services/llm/memory-classifier.service.ts +383 -0
  111. package/src/services/llm/memory-extension-detector.service.ts +523 -0
  112. package/src/services/llm/mock.ts +470 -0
  113. package/src/services/llm/openai.ts +398 -0
  114. package/src/services/llm/prompts.ts +438 -0
  115. package/src/services/llm/types.ts +373 -0
  116. package/src/services/memory.repository.ts +1769 -0
  117. package/src/services/memory.service.ts +1338 -0
  118. package/src/services/memory.types.ts +234 -0
  119. package/src/services/persistence/index.ts +295 -0
  120. package/src/services/pipeline.service.ts +509 -0
  121. package/src/services/profile.repository.ts +436 -0
  122. package/src/services/profile.service.ts +560 -0
  123. package/src/services/profile.types.ts +270 -0
  124. package/src/services/relationships/detector.ts +1128 -0
  125. package/src/services/relationships/index.ts +268 -0
  126. package/src/services/relationships/memory-integration.ts +459 -0
  127. package/src/services/relationships/strategies.ts +132 -0
  128. package/src/services/relationships/types.ts +370 -0
  129. package/src/services/search.service.ts +761 -0
  130. package/src/services/search.types.ts +220 -0
  131. package/src/services/secrets.service.ts +384 -0
  132. package/src/services/vectorstore/base.ts +327 -0
  133. package/src/services/vectorstore/index.ts +444 -0
  134. package/src/services/vectorstore/memory.ts +286 -0
  135. package/src/services/vectorstore/migration.ts +295 -0
  136. package/src/services/vectorstore/mock.ts +403 -0
  137. package/src/services/vectorstore/pgvector.ts +695 -0
  138. package/src/services/vectorstore/types.ts +247 -0
  139. package/src/startup.ts +389 -0
  140. package/src/types/api.types.ts +193 -0
  141. package/src/types/document.types.ts +103 -0
  142. package/src/types/index.ts +241 -0
  143. package/src/types/profile.base.ts +133 -0
  144. package/src/utils/errors.ts +447 -0
  145. package/src/utils/id.ts +15 -0
  146. package/src/utils/index.ts +101 -0
  147. package/src/utils/logger.ts +313 -0
  148. package/src/utils/sanitization.ts +501 -0
  149. package/src/utils/secret-validation.ts +273 -0
  150. package/src/utils/synonyms.ts +188 -0
  151. package/src/utils/validation.ts +581 -0
  152. package/src/workers/chunking.worker.ts +242 -0
  153. package/src/workers/embedding.worker.ts +358 -0
  154. package/src/workers/extraction.worker.ts +346 -0
  155. package/src/workers/indexing.worker.ts +505 -0
  156. package/tsconfig.json +38 -0
@@ -0,0 +1,459 @@
1
+ /**
2
+ * Memory Service Integration for Embedding-Based Relationship Detection
3
+ *
4
+ * Provides integration helpers and an enhanced memory service wrapper
5
+ * that uses embedding-based relationship detection instead of regex patterns.
6
+ */
7
+
8
+ import type { Memory, Relationship, MemoryServiceConfig } from '../memory.types.js'
9
+ import type { EmbeddingService } from '../embedding.service.js'
10
+ import { getEmbeddingService } from '../embedding.service.js'
11
+ import { MemoryService, getMemoryService } from '../memory.service.js'
12
+ import { type MemoryRepository, getMemoryRepository } from '../memory.repository.js'
13
+ import { getLogger } from '../../utils/logger.js'
14
+ import type { RelationshipConfig, RelationshipDetectionResult, Contradiction, LLMProvider } from './types.js'
15
+ import {
16
+ EmbeddingRelationshipDetector,
17
+ InMemoryVectorStoreAdapter,
18
+ createEmbeddingRelationshipDetector,
19
+ } from './detector.js'
20
+ import { getSharedVectorStore } from './index.js'
21
+ import { isEmbeddingRelationshipsEnabled } from '../../config/feature-flags.js'
22
+
23
+ const logger = getLogger('EnhancedMemoryService')
24
+
25
+ // ============================================================================
26
+ // Enhanced Memory Service Configuration
27
+ // ============================================================================
28
+
29
+ /**
30
+ * Configuration for the enhanced memory service
31
+ */
32
+ export interface EnhancedMemoryServiceConfig extends MemoryServiceConfig {
33
+ /** Configuration for embedding-based relationship detection */
34
+ relationshipDetection: Partial<RelationshipConfig>
35
+
36
+ /** Whether to use embedding-based detection (true) or regex (false) */
37
+ useEmbeddingDetection: boolean
38
+
39
+ /** Whether to automatically index memories for relationship detection */
40
+ autoIndexMemories: boolean
41
+
42
+ /** Whether to detect contradictions */
43
+ detectContradictions: boolean
44
+ }
45
+
46
+ /**
47
+ * Default enhanced configuration
48
+ */
49
+ export const DEFAULT_ENHANCED_CONFIG: Partial<EnhancedMemoryServiceConfig> = {
50
+ useEmbeddingDetection: isEmbeddingRelationshipsEnabled(),
51
+ autoIndexMemories: isEmbeddingRelationshipsEnabled(),
52
+ detectContradictions: true,
53
+ relationshipDetection: {
54
+ maxCandidates: 50,
55
+ enableLLMVerification: false,
56
+ enableContradictionDetection: true,
57
+ enableCausalDetection: true,
58
+ },
59
+ }
60
+
61
+ // ============================================================================
62
+ // Enhanced Memory Service
63
+ // ============================================================================
64
+
65
+ /**
66
+ * Enhanced Memory Service with embedding-based relationship detection.
67
+ *
68
+ * This extends the base MemoryService to use vector similarity for
69
+ * relationship detection instead of regex patterns.
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * const service = createEnhancedMemoryService();
74
+ *
75
+ * // Process content with embedding-based relationship detection
76
+ * const result = await service.processAndStoreMemoriesEnhanced(content, {
77
+ * containerTag: 'user-123',
78
+ * detectRelationships: true,
79
+ * });
80
+ *
81
+ * console.log(`Found ${result.relationships.length} relationships`);
82
+ * console.log(`Contradictions: ${result.contradictions.length}`);
83
+ * ```
84
+ */
85
+ export class EnhancedMemoryService {
86
+ private readonly baseService: MemoryService
87
+ private readonly repository: MemoryRepository
88
+ private readonly embeddingService: EmbeddingService
89
+ private readonly relationshipDetector: EmbeddingRelationshipDetector
90
+ private readonly config: EnhancedMemoryServiceConfig
91
+ private readonly vectorStore: InMemoryVectorStoreAdapter
92
+
93
+ constructor(
94
+ config: Partial<EnhancedMemoryServiceConfig> = {},
95
+ dependencies?: {
96
+ baseService?: MemoryService
97
+ repository?: MemoryRepository
98
+ embeddingService?: EmbeddingService
99
+ vectorStore?: InMemoryVectorStoreAdapter
100
+ llmProvider?: LLMProvider
101
+ }
102
+ ) {
103
+ // Merge configuration
104
+ this.config = {
105
+ ...DEFAULT_ENHANCED_CONFIG,
106
+ ...config,
107
+ } as EnhancedMemoryServiceConfig
108
+
109
+ // Set up dependencies
110
+ this.baseService = dependencies?.baseService ?? getMemoryService(config)
111
+ this.repository = dependencies?.repository ?? getMemoryRepository()
112
+ this.embeddingService = dependencies?.embeddingService ?? getEmbeddingService()
113
+ this.vectorStore = dependencies?.vectorStore ?? getSharedVectorStore()
114
+
115
+ // Create relationship detector
116
+ this.relationshipDetector = createEmbeddingRelationshipDetector(
117
+ this.embeddingService,
118
+ this.vectorStore,
119
+ this.config.relationshipDetection,
120
+ dependencies?.llmProvider
121
+ )
122
+
123
+ logger.debug('EnhancedMemoryService initialized', {
124
+ useEmbeddingDetection: this.config.useEmbeddingDetection,
125
+ autoIndexMemories: this.config.autoIndexMemories,
126
+ })
127
+ }
128
+
129
+ // ============================================================================
130
+ // Enhanced Processing Methods
131
+ // ============================================================================
132
+
133
+ /**
134
+ * Process and store memories with embedding-based relationship detection.
135
+ *
136
+ * This is the main entry point that replaces the base service's
137
+ * processAndStoreMemories method with enhanced detection.
138
+ */
139
+ async processAndStoreMemoriesEnhanced(
140
+ content: string,
141
+ options: {
142
+ containerTag?: string
143
+ sourceId?: string
144
+ detectRelationships?: boolean
145
+ detectContradictions?: boolean
146
+ } = {}
147
+ ): Promise<{
148
+ memories: Memory[]
149
+ relationships: Relationship[]
150
+ supersededMemoryIds: string[]
151
+ contradictions: Contradiction[]
152
+ detectionResults: RelationshipDetectionResult[]
153
+ }> {
154
+ const shouldDetectRelationships = options.detectRelationships ?? this.config.autoDetectRelationships
155
+ const shouldDetectContradictions = options.detectContradictions ?? this.config.detectContradictions
156
+
157
+ if (!this.config.useEmbeddingDetection || !shouldDetectRelationships) {
158
+ const baseResult = await this.baseService.processAndStoreMemories(content, {
159
+ containerTag: options.containerTag,
160
+ sourceId: options.sourceId,
161
+ detectRelationships: shouldDetectRelationships,
162
+ })
163
+
164
+ return {
165
+ ...baseResult,
166
+ contradictions: [],
167
+ detectionResults: [],
168
+ }
169
+ }
170
+
171
+ logger.debug('Processing content with enhanced detection', {
172
+ containerTag: options.containerTag,
173
+ detectRelationships: shouldDetectRelationships,
174
+ detectContradictions: shouldDetectContradictions,
175
+ })
176
+
177
+ // Step 1: Extract memories using base service
178
+ const extractedMemories = await this.baseService.extractMemories(content)
179
+
180
+ // Update container tags and source info
181
+ for (const memory of extractedMemories) {
182
+ memory.containerTag = options.containerTag ?? this.config.defaultContainerTag
183
+ if (options.sourceId) {
184
+ memory.sourceId = options.sourceId
185
+ }
186
+ }
187
+
188
+ // Step 2: Generate embeddings for extracted memories
189
+ const embeddings = await this.embeddingService.batchEmbed(extractedMemories.map((m) => m.content))
190
+
191
+ // Attach embeddings to memories
192
+ for (let i = 0; i < extractedMemories.length; i++) {
193
+ const memory = extractedMemories[i]
194
+ const embedding = embeddings[i]
195
+ if (memory && embedding) {
196
+ memory.embedding = embedding
197
+ }
198
+ }
199
+
200
+ const allRelationships: Relationship[] = []
201
+ const allSupersededIds: string[] = []
202
+ const allContradictions: Contradiction[] = []
203
+ const detectionResults: RelationshipDetectionResult[] = []
204
+
205
+ // Step 3: Process each memory
206
+ for (const memory of extractedMemories) {
207
+ // Store the memory
208
+ await this.repository.create(memory)
209
+
210
+ // Index for future relationship detection
211
+ if (this.config.autoIndexMemories && memory.embedding) {
212
+ this.vectorStore.addMemory(memory, memory.embedding)
213
+ }
214
+
215
+ // Detect relationships if enabled
216
+ if (shouldDetectRelationships) {
217
+ const result = await this.relationshipDetector.detectRelationships(memory, {
218
+ containerTag: options.containerTag,
219
+ excludeIds: extractedMemories.map((m) => m.id),
220
+ })
221
+
222
+ detectionResults.push(result)
223
+
224
+ // Process detected relationships
225
+ for (const detected of result.relationships) {
226
+ allRelationships.push(detected.relationship)
227
+
228
+ // Mark superseded memories
229
+ if (detected.relationship.type === 'updates' || detected.relationship.type === 'supersedes') {
230
+ const target = await this.repository.findById(detected.relationship.targetMemoryId)
231
+ if (target && memory.containerTag && target.containerTag && memory.containerTag !== target.containerTag) {
232
+ continue
233
+ }
234
+
235
+ await this.repository.markSuperseded(detected.relationship.targetMemoryId, memory.id)
236
+ allSupersededIds.push(detected.relationship.targetMemoryId)
237
+ }
238
+ }
239
+
240
+ // Store relationships
241
+ if (result.relationships.length > 0) {
242
+ await this.repository.createRelationshipBatch(result.relationships.map((r) => r.relationship))
243
+ }
244
+
245
+ // Collect contradictions
246
+ if (shouldDetectContradictions) {
247
+ allContradictions.push(...result.contradictions)
248
+ }
249
+ }
250
+ }
251
+
252
+ logger.info('Enhanced processing complete', {
253
+ memoriesCount: extractedMemories.length,
254
+ relationshipsCount: allRelationships.length,
255
+ supersededCount: allSupersededIds.length,
256
+ contradictionsCount: allContradictions.length,
257
+ })
258
+
259
+ return {
260
+ memories: extractedMemories,
261
+ relationships: allRelationships,
262
+ supersededMemoryIds: [...new Set(allSupersededIds)],
263
+ contradictions: allContradictions,
264
+ detectionResults,
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Detect relationships for a single memory using embedding similarity.
270
+ */
271
+ async detectRelationshipsEmbedding(
272
+ memory: Memory,
273
+ options: {
274
+ containerTag?: string
275
+ excludeIds?: string[]
276
+ } = {}
277
+ ): Promise<RelationshipDetectionResult> {
278
+ // Ensure memory has embedding
279
+ if (!memory.embedding || memory.embedding.length === 0) {
280
+ memory.embedding = await this.embeddingService.generateEmbedding(memory.content)
281
+ }
282
+
283
+ return this.relationshipDetector.detectRelationships(memory, options)
284
+ }
285
+
286
+ /**
287
+ * Detect contradictions among a group of memories.
288
+ */
289
+ async detectContradictions(memories: Memory[]): Promise<Contradiction[]> {
290
+ return this.relationshipDetector.detectContradictionsInGroup(memories)
291
+ }
292
+
293
+ /**
294
+ * Index a memory for relationship detection.
295
+ */
296
+ async indexMemory(memory: Memory): Promise<void> {
297
+ const embedding = memory.embedding ?? (await this.embeddingService.generateEmbedding(memory.content))
298
+ this.vectorStore.addMemory(memory, embedding)
299
+ }
300
+
301
+ /**
302
+ * Batch index memories for relationship detection.
303
+ */
304
+ async batchIndexMemories(memories: Memory[]): Promise<void> {
305
+ const memoriesToEmbed = memories.filter((m) => !m.embedding || m.embedding.length === 0)
306
+
307
+ if (memoriesToEmbed.length > 0) {
308
+ const embeddings = await this.embeddingService.batchEmbed(memoriesToEmbed.map((m) => m.content))
309
+
310
+ for (let i = 0; i < memoriesToEmbed.length; i++) {
311
+ const memory = memoriesToEmbed[i]
312
+ const embedding = embeddings[i]
313
+ if (memory && embedding) {
314
+ memory.embedding = embedding
315
+ }
316
+ }
317
+ }
318
+
319
+ const items = memories.map((m) => ({
320
+ memory: m,
321
+ embedding: m.embedding!,
322
+ }))
323
+
324
+ this.vectorStore.addMemories(items)
325
+ }
326
+
327
+ /**
328
+ * Remove a memory from the relationship index.
329
+ */
330
+ removeFromIndex(memoryId: string): boolean {
331
+ return this.vectorStore.removeMemory(memoryId)
332
+ }
333
+
334
+ /**
335
+ * Clear the relationship index.
336
+ */
337
+ clearIndex(): void {
338
+ this.vectorStore.clear()
339
+ }
340
+
341
+ // ============================================================================
342
+ // Delegation Methods (pass through to base service)
343
+ // ============================================================================
344
+
345
+ async extractMemories(content: string): Promise<Memory[]> {
346
+ return this.baseService.extractMemories(content)
347
+ }
348
+
349
+ classifyMemoryType(content: string) {
350
+ return this.baseService.classifyMemoryType(content)
351
+ }
352
+
353
+ async storeMemory(memory: Memory): Promise<Memory> {
354
+ const stored = await this.baseService.storeMemory(memory)
355
+
356
+ // Auto-index if enabled
357
+ if (this.config.autoIndexMemories) {
358
+ await this.indexMemory(stored)
359
+ }
360
+
361
+ return stored
362
+ }
363
+
364
+ async getMemory(id: string): Promise<Memory | null> {
365
+ return this.baseService.getMemory(id)
366
+ }
367
+
368
+ async getAllMemories(): Promise<Memory[]> {
369
+ return this.baseService.getAllMemories()
370
+ }
371
+
372
+ async getLatestMemories(): Promise<Memory[]> {
373
+ return this.baseService.getLatestMemories()
374
+ }
375
+
376
+ // ============================================================================
377
+ // Configuration
378
+ // ============================================================================
379
+
380
+ getConfig(): EnhancedMemoryServiceConfig {
381
+ return { ...this.config }
382
+ }
383
+
384
+ /**
385
+ * Update relationship detection configuration.
386
+ */
387
+ updateRelationshipConfig(updates: Partial<RelationshipConfig>): void {
388
+ this.relationshipDetector.updateConfig(updates)
389
+ }
390
+
391
+ /**
392
+ * Set LLM provider for verification.
393
+ */
394
+ setLLMProvider(provider: LLMProvider): void {
395
+ this.relationshipDetector.setLLMProvider(provider)
396
+ }
397
+
398
+ /**
399
+ * Get the underlying relationship detector.
400
+ */
401
+ getRelationshipDetector(): EmbeddingRelationshipDetector {
402
+ return this.relationshipDetector
403
+ }
404
+
405
+ /**
406
+ * Get the underlying base memory service.
407
+ */
408
+ getBaseService(): MemoryService {
409
+ return this.baseService
410
+ }
411
+ }
412
+
413
+ // ============================================================================
414
+ // Factory Functions
415
+ // ============================================================================
416
+
417
+ let _enhancedServiceInstance: EnhancedMemoryService | null = null
418
+
419
+ /**
420
+ * Create an enhanced memory service instance.
421
+ */
422
+ export function createEnhancedMemoryService(
423
+ config?: Partial<EnhancedMemoryServiceConfig>,
424
+ dependencies?: {
425
+ baseService?: MemoryService
426
+ repository?: MemoryRepository
427
+ embeddingService?: EmbeddingService
428
+ vectorStore?: InMemoryVectorStoreAdapter
429
+ llmProvider?: LLMProvider
430
+ }
431
+ ): EnhancedMemoryService {
432
+ return new EnhancedMemoryService(config, dependencies)
433
+ }
434
+
435
+ /**
436
+ * Get the singleton enhanced memory service instance.
437
+ */
438
+ export function getEnhancedMemoryService(config?: Partial<EnhancedMemoryServiceConfig>): EnhancedMemoryService {
439
+ if (!_enhancedServiceInstance) {
440
+ _enhancedServiceInstance = createEnhancedMemoryService(config)
441
+ }
442
+ return _enhancedServiceInstance
443
+ }
444
+
445
+ /**
446
+ * Reset the singleton instance (for testing).
447
+ */
448
+ export function resetEnhancedMemoryService(): void {
449
+ _enhancedServiceInstance = null
450
+ }
451
+
452
+ /**
453
+ * Proxy-based lazy singleton for backwards compatibility.
454
+ */
455
+ export const enhancedMemoryService = new Proxy({} as EnhancedMemoryService, {
456
+ get(_, prop) {
457
+ return getEnhancedMemoryService()[prop as keyof EnhancedMemoryService]
458
+ },
459
+ })
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Relationship Detection Helper Functions
3
+ *
4
+ * This file has been simplified to contain only the core helper functions.
5
+ * The strategy pattern has been removed as it was over-engineered - all access
6
+ * went through HybridStrategy which internally called 3 strategies.
7
+ *
8
+ * The detection logic has been inlined directly into EmbeddingRelationshipDetector
9
+ * as private methods, reducing complexity by ~400 LOC.
10
+ */
11
+
12
+ import type { RelationshipType } from '../../types/index.js'
13
+ import type { Memory, Relationship } from '../memory.types.js'
14
+ import { generateId } from '../../utils/id.js'
15
+ import type { DetectedRelationship, RelationshipCandidate, DetectionStrategyType } from './types.js'
16
+
17
+ // ============================================================================
18
+ // Helper Functions
19
+ // ============================================================================
20
+
21
+ /**
22
+ * Create a detected relationship object
23
+ */
24
+ export function createDetectedRelationship(
25
+ sourceMemory: Memory,
26
+ targetMemory: Memory,
27
+ type: RelationshipType,
28
+ candidate: RelationshipCandidate,
29
+ strategy: string,
30
+ llmVerified: boolean = false,
31
+ llmConfidence?: number
32
+ ): DetectedRelationship {
33
+ // Validate and cast strategy to DetectionStrategyType
34
+ const validStrategy: DetectionStrategyType =
35
+ strategy === 'similarity' ||
36
+ strategy === 'temporal' ||
37
+ strategy === 'entityOverlap' ||
38
+ strategy === 'llmVerification' ||
39
+ strategy === 'hybrid'
40
+ ? strategy
41
+ : 'hybrid'
42
+
43
+ const relationship: Relationship = {
44
+ id: generateId(),
45
+ sourceMemoryId: sourceMemory.id,
46
+ targetMemoryId: targetMemory.id,
47
+ type,
48
+ confidence: candidate.combinedScore,
49
+ description: `${type} relationship detected via ${strategy} strategy`,
50
+ createdAt: new Date(),
51
+ metadata: {
52
+ vectorSimilarity: candidate.vectorSimilarity,
53
+ entityOverlap: candidate.entityOverlap,
54
+ temporalScore: candidate.temporalScore,
55
+ detectionStrategy: strategy,
56
+ },
57
+ }
58
+
59
+ return {
60
+ relationship,
61
+ score: candidate.combinedScore,
62
+ vectorSimilarity: candidate.vectorSimilarity,
63
+ entityOverlap: candidate.entityOverlap,
64
+ temporalScore: candidate.temporalScore,
65
+ llmVerified,
66
+ llmConfidence,
67
+ detectionStrategy: validStrategy,
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Check if content contains update/correction indicators
73
+ */
74
+ export function hasUpdateIndicators(content: string): boolean {
75
+ const patterns = [
76
+ /\b(?:update|updated|updating|correction|corrected)\b/i,
77
+ /\b(?:now|actually|instead)\b/i,
78
+ /\b(?:changed|revised|modified)\b/i,
79
+ /\b(?:no longer|used to be|previously)\b/i,
80
+ ]
81
+ return patterns.some((p) => p.test(content))
82
+ }
83
+
84
+ /**
85
+ * Check if content contains extension indicators
86
+ */
87
+ export function hasExtensionIndicators(content: string): boolean {
88
+ const patterns = [
89
+ /\b(?:also|additionally|furthermore|moreover)\b/i,
90
+ /\b(?:in addition|on top of|besides)\b/i,
91
+ /\b(?:extending|building on|adding to)\b/i,
92
+ ]
93
+ return patterns.some((p) => p.test(content))
94
+ }
95
+
96
+ /**
97
+ * Check if content contains contradiction indicators
98
+ */
99
+ export function hasContradictionIndicators(content: string): boolean {
100
+ const patterns = [
101
+ /\b(?:however|but|although|despite)\b/i,
102
+ /\b(?:contrary|opposite|different)\b/i,
103
+ /\b(?:not true|incorrect|wrong|false)\b/i,
104
+ /\b(?:disagree|dispute|reject)\b/i,
105
+ ]
106
+ return patterns.some((p) => p.test(content))
107
+ }
108
+
109
+ /**
110
+ * Check if content contains supersession indicators
111
+ */
112
+ export function hasSupersessionIndicators(content: string): boolean {
113
+ const patterns = [
114
+ /\b(?:replaces|supersedes|overrides)\b/i,
115
+ /\b(?:no longer|obsolete|deprecated)\b/i,
116
+ /\b(?:new version|latest|current)\b/i,
117
+ ]
118
+ return patterns.some((p) => p.test(content))
119
+ }
120
+
121
+ /**
122
+ * Check if content contains causal/derivation indicators
123
+ */
124
+ export function hasCausalIndicators(content: string): boolean {
125
+ const patterns = [
126
+ /\b(?:therefore|thus|hence|consequently)\b/i,
127
+ /\b(?:because|since|as a result)\b/i,
128
+ /\b(?:based on|derived from|follows from)\b/i,
129
+ /\b(?:leads to|results in|causes)\b/i,
130
+ ]
131
+ return patterns.some((p) => p.test(content))
132
+ }