moflo 4.0.1 → 4.0.3
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/.claude/guidance/agent-bootstrap.md +12 -6
- package/bin/setup-project.mjs +201 -0
- package/package.json +114 -109
- package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.js +194 -81
- package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +1892 -1841
- package/v3/@claude-flow/memory/README.md +587 -0
- package/v3/@claude-flow/memory/dist/agent-memory-scope.d.ts +131 -0
- package/v3/@claude-flow/memory/dist/agent-memory-scope.js +223 -0
- package/v3/@claude-flow/memory/dist/agent-memory-scope.test.d.ts +8 -0
- package/v3/@claude-flow/memory/dist/agent-memory-scope.test.js +463 -0
- package/v3/@claude-flow/memory/dist/agentdb-adapter.d.ts +165 -0
- package/v3/@claude-flow/memory/dist/agentdb-adapter.js +806 -0
- package/v3/@claude-flow/memory/dist/agentdb-backend.d.ts +214 -0
- package/v3/@claude-flow/memory/dist/agentdb-backend.js +844 -0
- package/v3/@claude-flow/memory/dist/agentdb-backend.test.d.ts +7 -0
- package/v3/@claude-flow/memory/dist/agentdb-backend.test.js +258 -0
- package/v3/@claude-flow/memory/dist/application/commands/delete-memory.command.d.ts +65 -0
- package/v3/@claude-flow/memory/dist/application/commands/delete-memory.command.js +129 -0
- package/v3/@claude-flow/memory/dist/application/commands/store-memory.command.d.ts +48 -0
- package/v3/@claude-flow/memory/dist/application/commands/store-memory.command.js +72 -0
- package/v3/@claude-flow/memory/dist/application/index.d.ts +12 -0
- package/v3/@claude-flow/memory/dist/application/index.js +15 -0
- package/v3/@claude-flow/memory/dist/application/queries/search-memory.query.d.ts +72 -0
- package/v3/@claude-flow/memory/dist/application/queries/search-memory.query.js +143 -0
- package/v3/@claude-flow/memory/dist/application/services/memory-application-service.d.ts +121 -0
- package/v3/@claude-flow/memory/dist/application/services/memory-application-service.js +190 -0
- package/v3/@claude-flow/memory/dist/auto-memory-bridge.d.ts +226 -0
- package/v3/@claude-flow/memory/dist/auto-memory-bridge.js +709 -0
- package/v3/@claude-flow/memory/dist/auto-memory-bridge.test.d.ts +8 -0
- package/v3/@claude-flow/memory/dist/auto-memory-bridge.test.js +754 -0
- package/v3/@claude-flow/memory/dist/benchmark.test.d.ts +2 -0
- package/v3/@claude-flow/memory/dist/benchmark.test.js +277 -0
- package/v3/@claude-flow/memory/dist/cache-manager.d.ts +134 -0
- package/v3/@claude-flow/memory/dist/cache-manager.js +407 -0
- package/v3/@claude-flow/memory/dist/controller-registry.d.ts +216 -0
- package/v3/@claude-flow/memory/dist/controller-registry.js +893 -0
- package/v3/@claude-flow/memory/dist/controller-registry.test.d.ts +14 -0
- package/v3/@claude-flow/memory/dist/controller-registry.test.js +636 -0
- package/v3/@claude-flow/memory/dist/database-provider.d.ts +87 -0
- package/v3/@claude-flow/memory/dist/database-provider.js +410 -0
- package/v3/@claude-flow/memory/dist/database-provider.test.d.ts +7 -0
- package/v3/@claude-flow/memory/dist/database-provider.test.js +285 -0
- package/v3/@claude-flow/memory/dist/domain/entities/memory-entry.d.ts +143 -0
- package/v3/@claude-flow/memory/dist/domain/entities/memory-entry.js +226 -0
- package/v3/@claude-flow/memory/dist/domain/index.d.ts +11 -0
- package/v3/@claude-flow/memory/dist/domain/index.js +12 -0
- package/v3/@claude-flow/memory/dist/domain/repositories/memory-repository.interface.d.ts +102 -0
- package/v3/@claude-flow/memory/dist/domain/repositories/memory-repository.interface.js +11 -0
- package/v3/@claude-flow/memory/dist/domain/services/memory-domain-service.d.ts +105 -0
- package/v3/@claude-flow/memory/dist/domain/services/memory-domain-service.js +297 -0
- package/v3/@claude-flow/memory/dist/hnsw-index.d.ts +111 -0
- package/v3/@claude-flow/memory/dist/hnsw-index.js +781 -0
- package/v3/@claude-flow/memory/dist/hnsw-lite.d.ts +23 -0
- package/v3/@claude-flow/memory/dist/hnsw-lite.js +168 -0
- package/v3/@claude-flow/memory/dist/hybrid-backend.d.ts +245 -0
- package/v3/@claude-flow/memory/dist/hybrid-backend.js +569 -0
- package/v3/@claude-flow/memory/dist/hybrid-backend.test.d.ts +8 -0
- package/v3/@claude-flow/memory/dist/hybrid-backend.test.js +320 -0
- package/v3/@claude-flow/memory/dist/index.d.ts +208 -0
- package/v3/@claude-flow/memory/dist/index.js +362 -0
- package/v3/@claude-flow/memory/dist/infrastructure/index.d.ts +17 -0
- package/v3/@claude-flow/memory/dist/infrastructure/index.js +16 -0
- package/v3/@claude-flow/memory/dist/infrastructure/repositories/hybrid-memory-repository.d.ts +66 -0
- package/v3/@claude-flow/memory/dist/infrastructure/repositories/hybrid-memory-repository.js +409 -0
- package/v3/@claude-flow/memory/dist/learning-bridge.d.ts +137 -0
- package/v3/@claude-flow/memory/dist/learning-bridge.js +335 -0
- package/v3/@claude-flow/memory/dist/learning-bridge.test.d.ts +8 -0
- package/v3/@claude-flow/memory/dist/learning-bridge.test.js +578 -0
- package/v3/@claude-flow/memory/dist/memory-graph.d.ts +100 -0
- package/v3/@claude-flow/memory/dist/memory-graph.js +333 -0
- package/v3/@claude-flow/memory/dist/memory-graph.test.d.ts +8 -0
- package/v3/@claude-flow/memory/dist/memory-graph.test.js +609 -0
- package/v3/@claude-flow/memory/dist/migration.d.ts +68 -0
- package/v3/@claude-flow/memory/dist/migration.js +513 -0
- package/v3/@claude-flow/memory/dist/persistent-sona.d.ts +144 -0
- package/v3/@claude-flow/memory/dist/persistent-sona.js +332 -0
- package/v3/@claude-flow/memory/dist/query-builder.d.ts +211 -0
- package/v3/@claude-flow/memory/dist/query-builder.js +438 -0
- package/v3/@claude-flow/memory/dist/rvf-backend.d.ts +51 -0
- package/v3/@claude-flow/memory/dist/rvf-backend.js +481 -0
- package/v3/@claude-flow/memory/dist/rvf-learning-store.d.ts +139 -0
- package/v3/@claude-flow/memory/dist/rvf-learning-store.js +295 -0
- package/v3/@claude-flow/memory/dist/rvf-migration.d.ts +45 -0
- package/v3/@claude-flow/memory/dist/rvf-migration.js +254 -0
- package/v3/@claude-flow/memory/dist/sqlite-backend.d.ts +121 -0
- package/v3/@claude-flow/memory/dist/sqlite-backend.js +564 -0
- package/v3/@claude-flow/memory/dist/sqljs-backend.d.ts +128 -0
- package/v3/@claude-flow/memory/dist/sqljs-backend.js +601 -0
- package/v3/@claude-flow/memory/dist/types.d.ts +484 -0
- package/v3/@claude-flow/memory/dist/types.js +58 -0
- package/v3/@claude-flow/memory/package.json +46 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Repository Interface - Domain Layer
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for memory persistence.
|
|
5
|
+
* Following DDD, the interface belongs to the domain layer
|
|
6
|
+
* while implementations belong to infrastructure.
|
|
7
|
+
*
|
|
8
|
+
* @module v3/memory/domain/repositories
|
|
9
|
+
*/
|
|
10
|
+
import { MemoryEntry, MemoryType, MemoryStatus } from '../entities/memory-entry.js';
|
|
11
|
+
/**
|
|
12
|
+
* Query options for memory retrieval
|
|
13
|
+
*/
|
|
14
|
+
export interface MemoryQueryOptions {
|
|
15
|
+
namespace?: string;
|
|
16
|
+
type?: MemoryType;
|
|
17
|
+
status?: MemoryStatus;
|
|
18
|
+
limit?: number;
|
|
19
|
+
offset?: number;
|
|
20
|
+
orderBy?: 'createdAt' | 'updatedAt' | 'accessCount' | 'lastAccessedAt';
|
|
21
|
+
orderDirection?: 'asc' | 'desc';
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Vector search options
|
|
25
|
+
*/
|
|
26
|
+
export interface VectorSearchOptions {
|
|
27
|
+
vector: Float32Array;
|
|
28
|
+
namespace?: string;
|
|
29
|
+
limit?: number;
|
|
30
|
+
threshold?: number;
|
|
31
|
+
type?: MemoryType;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Vector search result
|
|
35
|
+
*/
|
|
36
|
+
export interface VectorSearchResult {
|
|
37
|
+
entry: MemoryEntry;
|
|
38
|
+
similarity: number;
|
|
39
|
+
distance: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Bulk operation result
|
|
43
|
+
*/
|
|
44
|
+
export interface BulkOperationResult {
|
|
45
|
+
success: number;
|
|
46
|
+
failed: number;
|
|
47
|
+
errors: Array<{
|
|
48
|
+
id: string;
|
|
49
|
+
error: string;
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Memory statistics
|
|
54
|
+
*/
|
|
55
|
+
export interface MemoryStatistics {
|
|
56
|
+
totalEntries: number;
|
|
57
|
+
activeEntries: number;
|
|
58
|
+
archivedEntries: number;
|
|
59
|
+
deletedEntries: number;
|
|
60
|
+
totalSize: number;
|
|
61
|
+
entriesByNamespace: Record<string, number>;
|
|
62
|
+
entriesByType: Record<MemoryType, number>;
|
|
63
|
+
averageAccessCount: number;
|
|
64
|
+
hottestEntries: string[];
|
|
65
|
+
coldestEntries: string[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Memory Repository Interface
|
|
69
|
+
*
|
|
70
|
+
* Defines all operations for memory persistence.
|
|
71
|
+
* Implementations can use SQLite, AgentDB, or hybrid backends.
|
|
72
|
+
*/
|
|
73
|
+
export interface IMemoryRepository {
|
|
74
|
+
save(entry: MemoryEntry): Promise<void>;
|
|
75
|
+
findById(id: string): Promise<MemoryEntry | null>;
|
|
76
|
+
findByKey(namespace: string, key: string): Promise<MemoryEntry | null>;
|
|
77
|
+
findByCompositeKey(compositeKey: string): Promise<MemoryEntry | null>;
|
|
78
|
+
delete(id: string): Promise<boolean>;
|
|
79
|
+
exists(id: string): Promise<boolean>;
|
|
80
|
+
saveMany(entries: MemoryEntry[]): Promise<BulkOperationResult>;
|
|
81
|
+
findByIds(ids: string[]): Promise<MemoryEntry[]>;
|
|
82
|
+
deleteMany(ids: string[]): Promise<BulkOperationResult>;
|
|
83
|
+
findAll(options?: MemoryQueryOptions): Promise<MemoryEntry[]>;
|
|
84
|
+
findByNamespace(namespace: string, options?: Omit<MemoryQueryOptions, 'namespace'>): Promise<MemoryEntry[]>;
|
|
85
|
+
findByType(type: MemoryType, options?: Omit<MemoryQueryOptions, 'type'>): Promise<MemoryEntry[]>;
|
|
86
|
+
findByStatus(status: MemoryStatus, options?: Omit<MemoryQueryOptions, 'status'>): Promise<MemoryEntry[]>;
|
|
87
|
+
searchByVector(options: VectorSearchOptions): Promise<VectorSearchResult[]>;
|
|
88
|
+
findSimilar(entryId: string, limit?: number): Promise<VectorSearchResult[]>;
|
|
89
|
+
findExpired(): Promise<MemoryEntry[]>;
|
|
90
|
+
deleteExpired(): Promise<number>;
|
|
91
|
+
findCold(milliseconds: number): Promise<MemoryEntry[]>;
|
|
92
|
+
archiveCold(milliseconds: number): Promise<number>;
|
|
93
|
+
getStatistics(): Promise<MemoryStatistics>;
|
|
94
|
+
count(options?: MemoryQueryOptions): Promise<number>;
|
|
95
|
+
listNamespaces(): Promise<string[]>;
|
|
96
|
+
deleteNamespace(namespace: string): Promise<number>;
|
|
97
|
+
getNamespaceSize(namespace: string): Promise<number>;
|
|
98
|
+
initialize(): Promise<void>;
|
|
99
|
+
shutdown(): Promise<void>;
|
|
100
|
+
clear(): Promise<void>;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=memory-repository.interface.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Repository Interface - Domain Layer
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for memory persistence.
|
|
5
|
+
* Following DDD, the interface belongs to the domain layer
|
|
6
|
+
* while implementations belong to infrastructure.
|
|
7
|
+
*
|
|
8
|
+
* @module v3/memory/domain/repositories
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=memory-repository.interface.js.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Domain Service - Domain Layer
|
|
3
|
+
*
|
|
4
|
+
* Contains domain logic that doesn't naturally fit within a single entity.
|
|
5
|
+
* Coordinates between multiple memory entries and enforces domain rules.
|
|
6
|
+
*
|
|
7
|
+
* @module v3/memory/domain/services
|
|
8
|
+
*/
|
|
9
|
+
import { MemoryEntry, MemoryType } from '../entities/memory-entry.js';
|
|
10
|
+
import { IMemoryRepository, VectorSearchResult } from '../repositories/memory-repository.interface.js';
|
|
11
|
+
/**
|
|
12
|
+
* Memory consolidation strategy
|
|
13
|
+
*/
|
|
14
|
+
export type ConsolidationStrategy = 'merge' | 'dedupe' | 'prune' | 'summarize';
|
|
15
|
+
/**
|
|
16
|
+
* Memory consolidation options
|
|
17
|
+
*/
|
|
18
|
+
export interface ConsolidationOptions {
|
|
19
|
+
strategy: ConsolidationStrategy;
|
|
20
|
+
namespace?: string;
|
|
21
|
+
threshold?: number;
|
|
22
|
+
maxAge?: number;
|
|
23
|
+
keepHot?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Consolidation result
|
|
27
|
+
*/
|
|
28
|
+
export interface ConsolidationResult {
|
|
29
|
+
processed: number;
|
|
30
|
+
consolidated: number;
|
|
31
|
+
removed: number;
|
|
32
|
+
newEntries: MemoryEntry[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Memory deduplication result
|
|
36
|
+
*/
|
|
37
|
+
export interface DeduplicationResult {
|
|
38
|
+
duplicatesFound: number;
|
|
39
|
+
duplicatesRemoved: number;
|
|
40
|
+
groupsProcessed: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Memory namespace statistics
|
|
44
|
+
*/
|
|
45
|
+
export interface NamespaceAnalysis {
|
|
46
|
+
namespace: string;
|
|
47
|
+
totalEntries: number;
|
|
48
|
+
activeEntries: number;
|
|
49
|
+
totalSize: number;
|
|
50
|
+
averageAccessCount: number;
|
|
51
|
+
oldestEntry: Date;
|
|
52
|
+
newestEntry: Date;
|
|
53
|
+
typeDistribution: Record<MemoryType, number>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Memory Domain Service
|
|
57
|
+
*
|
|
58
|
+
* Provides domain-level operations that span multiple entities.
|
|
59
|
+
* Implements business rules for memory management.
|
|
60
|
+
*/
|
|
61
|
+
export declare class MemoryDomainService {
|
|
62
|
+
private readonly repository;
|
|
63
|
+
constructor(repository: IMemoryRepository);
|
|
64
|
+
/**
|
|
65
|
+
* Store a new memory with automatic type detection
|
|
66
|
+
*/
|
|
67
|
+
storeWithTypeDetection(namespace: string, key: string, value: unknown, vector?: Float32Array): Promise<MemoryEntry>;
|
|
68
|
+
/**
|
|
69
|
+
* Retrieve and record access
|
|
70
|
+
*/
|
|
71
|
+
retrieveWithAccessTracking(namespace: string, key: string): Promise<MemoryEntry | null>;
|
|
72
|
+
/**
|
|
73
|
+
* Search for similar memories and record access
|
|
74
|
+
*/
|
|
75
|
+
searchSimilarWithTracking(vector: Float32Array, namespace?: string, limit?: number): Promise<VectorSearchResult[]>;
|
|
76
|
+
/**
|
|
77
|
+
* Consolidate memories based on strategy
|
|
78
|
+
*/
|
|
79
|
+
consolidate(options: ConsolidationOptions): Promise<ConsolidationResult>;
|
|
80
|
+
/**
|
|
81
|
+
* Detect memory type based on value structure
|
|
82
|
+
*/
|
|
83
|
+
private detectMemoryType;
|
|
84
|
+
/**
|
|
85
|
+
* Prune old, rarely accessed memories
|
|
86
|
+
*/
|
|
87
|
+
private pruneOldMemories;
|
|
88
|
+
/**
|
|
89
|
+
* Find and remove duplicate memories
|
|
90
|
+
*/
|
|
91
|
+
private deduplicateMemories;
|
|
92
|
+
/**
|
|
93
|
+
* Merge related memories into consolidated entries
|
|
94
|
+
*/
|
|
95
|
+
private mergeRelatedMemories;
|
|
96
|
+
/**
|
|
97
|
+
* Merge multiple entries into one
|
|
98
|
+
*/
|
|
99
|
+
private mergeEntries;
|
|
100
|
+
/**
|
|
101
|
+
* Analyze a namespace
|
|
102
|
+
*/
|
|
103
|
+
analyzeNamespace(namespace: string): Promise<NamespaceAnalysis>;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=memory-domain-service.d.ts.map
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Domain Service - Domain Layer
|
|
3
|
+
*
|
|
4
|
+
* Contains domain logic that doesn't naturally fit within a single entity.
|
|
5
|
+
* Coordinates between multiple memory entries and enforces domain rules.
|
|
6
|
+
*
|
|
7
|
+
* @module v3/memory/domain/services
|
|
8
|
+
*/
|
|
9
|
+
import { MemoryEntry } from '../entities/memory-entry.js';
|
|
10
|
+
/**
|
|
11
|
+
* Memory Domain Service
|
|
12
|
+
*
|
|
13
|
+
* Provides domain-level operations that span multiple entities.
|
|
14
|
+
* Implements business rules for memory management.
|
|
15
|
+
*/
|
|
16
|
+
export class MemoryDomainService {
|
|
17
|
+
repository;
|
|
18
|
+
constructor(repository) {
|
|
19
|
+
this.repository = repository;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Store a new memory with automatic type detection
|
|
23
|
+
*/
|
|
24
|
+
async storeWithTypeDetection(namespace, key, value, vector) {
|
|
25
|
+
const type = this.detectMemoryType(value);
|
|
26
|
+
const entry = MemoryEntry.create({
|
|
27
|
+
namespace,
|
|
28
|
+
key,
|
|
29
|
+
value,
|
|
30
|
+
type,
|
|
31
|
+
vector,
|
|
32
|
+
});
|
|
33
|
+
await this.repository.save(entry);
|
|
34
|
+
return entry;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Retrieve and record access
|
|
38
|
+
*/
|
|
39
|
+
async retrieveWithAccessTracking(namespace, key) {
|
|
40
|
+
const entry = await this.repository.findByKey(namespace, key);
|
|
41
|
+
if (entry && entry.isAccessible()) {
|
|
42
|
+
entry.recordAccess();
|
|
43
|
+
await this.repository.save(entry);
|
|
44
|
+
}
|
|
45
|
+
return entry;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Search for similar memories and record access
|
|
49
|
+
*/
|
|
50
|
+
async searchSimilarWithTracking(vector, namespace, limit = 10) {
|
|
51
|
+
const results = await this.repository.searchByVector({
|
|
52
|
+
vector,
|
|
53
|
+
namespace,
|
|
54
|
+
limit,
|
|
55
|
+
});
|
|
56
|
+
// Record access for all returned entries
|
|
57
|
+
await Promise.all(results.map(async (result) => {
|
|
58
|
+
result.entry.recordAccess();
|
|
59
|
+
await this.repository.save(result.entry);
|
|
60
|
+
}));
|
|
61
|
+
return results;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Consolidate memories based on strategy
|
|
65
|
+
*/
|
|
66
|
+
async consolidate(options) {
|
|
67
|
+
const entries = await this.repository.findByNamespace(options.namespace ?? 'default', { status: 'active' });
|
|
68
|
+
let result = {
|
|
69
|
+
processed: entries.length,
|
|
70
|
+
consolidated: 0,
|
|
71
|
+
removed: 0,
|
|
72
|
+
newEntries: [],
|
|
73
|
+
};
|
|
74
|
+
switch (options.strategy) {
|
|
75
|
+
case 'prune':
|
|
76
|
+
result = await this.pruneOldMemories(entries, options);
|
|
77
|
+
break;
|
|
78
|
+
case 'dedupe':
|
|
79
|
+
const dedupeResult = await this.deduplicateMemories(entries, options);
|
|
80
|
+
result.removed = dedupeResult.duplicatesRemoved;
|
|
81
|
+
break;
|
|
82
|
+
case 'merge':
|
|
83
|
+
result = await this.mergeRelatedMemories(entries, options);
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
// No-op for unknown strategies
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Detect memory type based on value structure
|
|
92
|
+
*/
|
|
93
|
+
detectMemoryType(value) {
|
|
94
|
+
if (typeof value === 'string') {
|
|
95
|
+
// Long text is likely semantic
|
|
96
|
+
if (value.length > 500)
|
|
97
|
+
return 'semantic';
|
|
98
|
+
// Short instructions are procedural
|
|
99
|
+
if (value.includes('->') || value.includes('then'))
|
|
100
|
+
return 'procedural';
|
|
101
|
+
}
|
|
102
|
+
if (typeof value === 'object' && value !== null) {
|
|
103
|
+
const obj = value;
|
|
104
|
+
// Objects with timestamps are episodic
|
|
105
|
+
if ('timestamp' in obj || 'when' in obj || 'date' in obj)
|
|
106
|
+
return 'episodic';
|
|
107
|
+
// Objects with steps are procedural
|
|
108
|
+
if ('steps' in obj || 'actions' in obj)
|
|
109
|
+
return 'procedural';
|
|
110
|
+
}
|
|
111
|
+
// Default to working memory for short-term storage
|
|
112
|
+
return 'working';
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Prune old, rarely accessed memories
|
|
116
|
+
*/
|
|
117
|
+
async pruneOldMemories(entries, options) {
|
|
118
|
+
const maxAge = options.maxAge ?? 7 * 24 * 60 * 60 * 1000; // 7 days default
|
|
119
|
+
const threshold = options.threshold ?? 5; // Minimum access count to keep
|
|
120
|
+
const now = Date.now();
|
|
121
|
+
const toRemove = [];
|
|
122
|
+
for (const entry of entries) {
|
|
123
|
+
const age = now - entry.createdAt.getTime();
|
|
124
|
+
const isOld = age > maxAge;
|
|
125
|
+
const isRarelyAccessed = entry.accessCount < threshold;
|
|
126
|
+
// Keep hot memories if requested
|
|
127
|
+
if (options.keepHot && entry.isHot())
|
|
128
|
+
continue;
|
|
129
|
+
if (isOld && isRarelyAccessed) {
|
|
130
|
+
entry.archive();
|
|
131
|
+
toRemove.push(entry.id);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (toRemove.length > 0) {
|
|
135
|
+
await this.repository.deleteMany(toRemove);
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
processed: entries.length,
|
|
139
|
+
consolidated: 0,
|
|
140
|
+
removed: toRemove.length,
|
|
141
|
+
newEntries: [],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Find and remove duplicate memories
|
|
146
|
+
*/
|
|
147
|
+
async deduplicateMemories(entries, options) {
|
|
148
|
+
const threshold = options.threshold ?? 0.95; // Similarity threshold
|
|
149
|
+
const duplicates = [];
|
|
150
|
+
const processed = new Set();
|
|
151
|
+
for (let i = 0; i < entries.length; i++) {
|
|
152
|
+
if (processed.has(entries[i].id))
|
|
153
|
+
continue;
|
|
154
|
+
const entry = entries[i];
|
|
155
|
+
if (!entry.vector)
|
|
156
|
+
continue;
|
|
157
|
+
// Find similar entries
|
|
158
|
+
const similar = await this.repository.searchByVector({
|
|
159
|
+
vector: entry.vector,
|
|
160
|
+
namespace: entry.namespace,
|
|
161
|
+
limit: 10,
|
|
162
|
+
threshold,
|
|
163
|
+
});
|
|
164
|
+
// Mark duplicates (keep the one with highest access count)
|
|
165
|
+
const group = similar
|
|
166
|
+
.filter((s) => s.entry.id !== entry.id && s.similarity >= threshold)
|
|
167
|
+
.sort((a, b) => b.entry.accessCount - a.entry.accessCount);
|
|
168
|
+
for (const dup of group.slice(1)) {
|
|
169
|
+
duplicates.push(dup.entry.id);
|
|
170
|
+
processed.add(dup.entry.id);
|
|
171
|
+
}
|
|
172
|
+
processed.add(entry.id);
|
|
173
|
+
}
|
|
174
|
+
if (duplicates.length > 0) {
|
|
175
|
+
await this.repository.deleteMany(duplicates);
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
duplicatesFound: duplicates.length,
|
|
179
|
+
duplicatesRemoved: duplicates.length,
|
|
180
|
+
groupsProcessed: processed.size,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Merge related memories into consolidated entries
|
|
185
|
+
*/
|
|
186
|
+
async mergeRelatedMemories(entries, options) {
|
|
187
|
+
const threshold = options.threshold ?? 0.8;
|
|
188
|
+
const newEntries = [];
|
|
189
|
+
const toRemove = [];
|
|
190
|
+
const processed = new Set();
|
|
191
|
+
for (const entry of entries) {
|
|
192
|
+
if (processed.has(entry.id))
|
|
193
|
+
continue;
|
|
194
|
+
if (!entry.vector) {
|
|
195
|
+
processed.add(entry.id);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
// Find related entries
|
|
199
|
+
const related = await this.repository.searchByVector({
|
|
200
|
+
vector: entry.vector,
|
|
201
|
+
namespace: entry.namespace,
|
|
202
|
+
limit: 5,
|
|
203
|
+
threshold,
|
|
204
|
+
});
|
|
205
|
+
if (related.length > 1) {
|
|
206
|
+
// Merge related entries
|
|
207
|
+
const merged = this.mergeEntries(related.map((r) => r.entry));
|
|
208
|
+
newEntries.push(merged);
|
|
209
|
+
for (const r of related) {
|
|
210
|
+
toRemove.push(r.entry.id);
|
|
211
|
+
processed.add(r.entry.id);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
processed.add(entry.id);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Remove old entries and save merged ones
|
|
219
|
+
if (toRemove.length > 0) {
|
|
220
|
+
await this.repository.deleteMany(toRemove);
|
|
221
|
+
}
|
|
222
|
+
if (newEntries.length > 0) {
|
|
223
|
+
await this.repository.saveMany(newEntries);
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
processed: entries.length,
|
|
227
|
+
consolidated: newEntries.length,
|
|
228
|
+
removed: toRemove.length,
|
|
229
|
+
newEntries,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Merge multiple entries into one
|
|
234
|
+
*/
|
|
235
|
+
mergeEntries(entries) {
|
|
236
|
+
// Sort by access count to prioritize most accessed
|
|
237
|
+
const sorted = [...entries].sort((a, b) => b.accessCount - a.accessCount);
|
|
238
|
+
const primary = sorted[0];
|
|
239
|
+
// Combine metadata
|
|
240
|
+
const combinedMetadata = {};
|
|
241
|
+
for (const entry of entries) {
|
|
242
|
+
Object.assign(combinedMetadata, entry.metadata);
|
|
243
|
+
}
|
|
244
|
+
combinedMetadata.mergedFrom = entries.map((e) => e.id);
|
|
245
|
+
combinedMetadata.mergedAt = new Date().toISOString();
|
|
246
|
+
// Create merged entry
|
|
247
|
+
return MemoryEntry.create({
|
|
248
|
+
namespace: primary.namespace,
|
|
249
|
+
key: `merged_${Date.now()}`,
|
|
250
|
+
value: {
|
|
251
|
+
primary: primary.value,
|
|
252
|
+
related: sorted.slice(1).map((e) => e.value),
|
|
253
|
+
},
|
|
254
|
+
type: primary.type,
|
|
255
|
+
vector: primary.vector,
|
|
256
|
+
metadata: combinedMetadata,
|
|
257
|
+
accessCount: entries.reduce((sum, e) => sum + e.accessCount, 0),
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Analyze a namespace
|
|
262
|
+
*/
|
|
263
|
+
async analyzeNamespace(namespace) {
|
|
264
|
+
const entries = await this.repository.findByNamespace(namespace);
|
|
265
|
+
const active = entries.filter((e) => e.status === 'active');
|
|
266
|
+
const typeDistribution = {
|
|
267
|
+
semantic: 0,
|
|
268
|
+
episodic: 0,
|
|
269
|
+
procedural: 0,
|
|
270
|
+
working: 0,
|
|
271
|
+
};
|
|
272
|
+
let totalAccessCount = 0;
|
|
273
|
+
let totalSize = 0;
|
|
274
|
+
let oldestDate = new Date();
|
|
275
|
+
let newestDate = new Date(0);
|
|
276
|
+
for (const entry of entries) {
|
|
277
|
+
typeDistribution[entry.type]++;
|
|
278
|
+
totalAccessCount += entry.accessCount;
|
|
279
|
+
totalSize += JSON.stringify(entry.value).length;
|
|
280
|
+
if (entry.createdAt < oldestDate)
|
|
281
|
+
oldestDate = entry.createdAt;
|
|
282
|
+
if (entry.createdAt > newestDate)
|
|
283
|
+
newestDate = entry.createdAt;
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
namespace,
|
|
287
|
+
totalEntries: entries.length,
|
|
288
|
+
activeEntries: active.length,
|
|
289
|
+
totalSize,
|
|
290
|
+
averageAccessCount: entries.length > 0 ? totalAccessCount / entries.length : 0,
|
|
291
|
+
oldestEntry: oldestDate,
|
|
292
|
+
newestEntry: newestDate,
|
|
293
|
+
typeDistribution,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=memory-domain-service.js.map
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 HNSW Vector Index
|
|
3
|
+
*
|
|
4
|
+
* High-performance Hierarchical Navigable Small World (HNSW) index for
|
|
5
|
+
* 150x-12,500x faster vector similarity search compared to brute force.
|
|
6
|
+
*
|
|
7
|
+
* OPTIMIZATIONS:
|
|
8
|
+
* - BinaryMinHeap/BinaryMaxHeap for O(log n) operations (vs O(n log n) Array.sort)
|
|
9
|
+
* - Pre-normalized vectors for O(1) cosine similarity (no sqrt needed)
|
|
10
|
+
* - Bounded max-heap for efficient top-k tracking
|
|
11
|
+
*
|
|
12
|
+
* @module v3/memory/hnsw-index
|
|
13
|
+
*/
|
|
14
|
+
import { EventEmitter } from 'node:events';
|
|
15
|
+
import { HNSWConfig, HNSWStats } from './types.js';
|
|
16
|
+
/**
|
|
17
|
+
* HNSW Index implementation for ultra-fast vector similarity search
|
|
18
|
+
*
|
|
19
|
+
* Performance characteristics:
|
|
20
|
+
* - Search: O(log n) approximate nearest neighbor
|
|
21
|
+
* - Insert: O(log n) amortized
|
|
22
|
+
* - Memory: O(n * M * L) where M is max connections, L is layers
|
|
23
|
+
*/
|
|
24
|
+
export declare class HNSWIndex extends EventEmitter {
|
|
25
|
+
private config;
|
|
26
|
+
private nodes;
|
|
27
|
+
private entryPoint;
|
|
28
|
+
private maxLevel;
|
|
29
|
+
private levelMult;
|
|
30
|
+
private stats;
|
|
31
|
+
private quantizer;
|
|
32
|
+
constructor(config?: Partial<HNSWConfig>);
|
|
33
|
+
/**
|
|
34
|
+
* Add a vector to the index
|
|
35
|
+
*/
|
|
36
|
+
addPoint(id: string, vector: Float32Array): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Search for k nearest neighbors
|
|
39
|
+
*/
|
|
40
|
+
search(query: Float32Array, k: number, ef?: number): Promise<Array<{
|
|
41
|
+
id: string;
|
|
42
|
+
distance: number;
|
|
43
|
+
}>>;
|
|
44
|
+
/**
|
|
45
|
+
* Search with filters applied post-retrieval
|
|
46
|
+
*/
|
|
47
|
+
searchWithFilters(query: Float32Array, k: number, filter: (id: string) => boolean, ef?: number): Promise<Array<{
|
|
48
|
+
id: string;
|
|
49
|
+
distance: number;
|
|
50
|
+
}>>;
|
|
51
|
+
/**
|
|
52
|
+
* Remove a point from the index
|
|
53
|
+
*/
|
|
54
|
+
removePoint(id: string): Promise<boolean>;
|
|
55
|
+
/**
|
|
56
|
+
* Rebuild the index from scratch
|
|
57
|
+
*/
|
|
58
|
+
rebuild(entries: Array<{
|
|
59
|
+
id: string;
|
|
60
|
+
vector: Float32Array;
|
|
61
|
+
}>): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Get index statistics
|
|
64
|
+
*/
|
|
65
|
+
getStats(): HNSWStats;
|
|
66
|
+
/**
|
|
67
|
+
* Clear the index
|
|
68
|
+
*/
|
|
69
|
+
clear(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Check if an ID exists in the index
|
|
72
|
+
*/
|
|
73
|
+
has(id: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Get the number of vectors in the index
|
|
76
|
+
*/
|
|
77
|
+
get size(): number;
|
|
78
|
+
private mergeConfig;
|
|
79
|
+
private getRandomLevel;
|
|
80
|
+
private insertNode;
|
|
81
|
+
private searchLayer;
|
|
82
|
+
/**
|
|
83
|
+
* OPTIMIZED searchLayer using heap-based priority queues
|
|
84
|
+
* Performance: O(log n) per operation vs O(n log n) for Array.sort()
|
|
85
|
+
* Expected speedup: 3-5x for large result sets
|
|
86
|
+
*/
|
|
87
|
+
private searchLayerOptimized;
|
|
88
|
+
private selectNeighbors;
|
|
89
|
+
private pruneConnections;
|
|
90
|
+
private distance;
|
|
91
|
+
private cosineDistance;
|
|
92
|
+
/**
|
|
93
|
+
* OPTIMIZED: Cosine distance using pre-normalized vectors
|
|
94
|
+
* Only requires dot product (no sqrt operations)
|
|
95
|
+
* Performance: O(n) with ~2x speedup over standard cosine
|
|
96
|
+
*/
|
|
97
|
+
private cosineDistanceNormalized;
|
|
98
|
+
/**
|
|
99
|
+
* Normalize a vector to unit length for O(1) cosine similarity
|
|
100
|
+
*/
|
|
101
|
+
private normalizeVector;
|
|
102
|
+
/**
|
|
103
|
+
* OPTIMIZED distance calculation that uses pre-normalized vectors when available
|
|
104
|
+
*/
|
|
105
|
+
private distanceOptimized;
|
|
106
|
+
private euclideanDistance;
|
|
107
|
+
private dotProductDistance;
|
|
108
|
+
private manhattanDistance;
|
|
109
|
+
}
|
|
110
|
+
export default HNSWIndex;
|
|
111
|
+
//# sourceMappingURL=hnsw-index.d.ts.map
|