@claude-flow/memory 3.0.0-alpha.2 → 3.0.0-alpha.20

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 (253) hide show
  1. package/README.md +858 -249
  2. package/dist/agent-memory-scope.d.ts +131 -0
  3. package/dist/agent-memory-scope.d.ts.map +1 -0
  4. package/dist/agent-memory-scope.js +223 -0
  5. package/dist/agent-memory-scope.js.map +1 -0
  6. package/dist/agent-memory-scope.test.d.ts +8 -0
  7. package/dist/agent-memory-scope.test.d.ts.map +1 -0
  8. package/dist/agent-memory-scope.test.js +463 -0
  9. package/dist/agent-memory-scope.test.js.map +1 -0
  10. package/dist/agentdb-adapter.d.ts +82 -4
  11. package/dist/agentdb-adapter.d.ts.map +1 -1
  12. package/dist/agentdb-adapter.js +388 -17
  13. package/dist/agentdb-adapter.js.map +1 -1
  14. package/dist/agentdb-backend.d.ts +6 -0
  15. package/dist/agentdb-backend.d.ts.map +1 -1
  16. package/dist/agentdb-backend.js +115 -51
  17. package/dist/agentdb-backend.js.map +1 -1
  18. package/dist/auto-memory-bridge.d.ts +237 -0
  19. package/dist/auto-memory-bridge.d.ts.map +1 -0
  20. package/dist/auto-memory-bridge.js +758 -0
  21. package/dist/auto-memory-bridge.js.map +1 -0
  22. package/dist/auto-memory-bridge.test.d.ts +8 -0
  23. package/dist/auto-memory-bridge.test.d.ts.map +1 -0
  24. package/dist/auto-memory-bridge.test.js +849 -0
  25. package/dist/auto-memory-bridge.test.js.map +1 -0
  26. package/dist/benchmark.test.d.ts +2 -0
  27. package/dist/benchmark.test.d.ts.map +1 -0
  28. package/dist/benchmark.test.js +277 -0
  29. package/dist/benchmark.test.js.map +1 -0
  30. package/dist/consolidator.d.ts +96 -0
  31. package/dist/consolidator.d.ts.map +1 -0
  32. package/dist/consolidator.js +209 -0
  33. package/dist/consolidator.js.map +1 -0
  34. package/dist/consolidator.test.d.ts +17 -0
  35. package/dist/consolidator.test.d.ts.map +1 -0
  36. package/dist/consolidator.test.js +239 -0
  37. package/dist/consolidator.test.js.map +1 -0
  38. package/dist/controller-registry.d.ts +232 -0
  39. package/dist/controller-registry.d.ts.map +1 -0
  40. package/dist/controller-registry.js +1049 -0
  41. package/dist/controller-registry.js.map +1 -0
  42. package/dist/controller-registry.test.d.ts +14 -0
  43. package/dist/controller-registry.test.d.ts.map +1 -0
  44. package/dist/controller-registry.test.js +691 -0
  45. package/dist/controller-registry.test.js.map +1 -0
  46. package/dist/database-provider.d.ts +14 -2
  47. package/dist/database-provider.d.ts.map +1 -1
  48. package/dist/database-provider.js +63 -3
  49. package/dist/database-provider.js.map +1 -1
  50. package/dist/database-provider.test.js +56 -3
  51. package/dist/database-provider.test.js.map +1 -1
  52. package/dist/entity-tagger.d.ts +31 -0
  53. package/dist/entity-tagger.d.ts.map +1 -0
  54. package/dist/entity-tagger.js +80 -0
  55. package/dist/entity-tagger.js.map +1 -0
  56. package/dist/entity-tagger.test.d.ts +12 -0
  57. package/dist/entity-tagger.test.d.ts.map +1 -0
  58. package/dist/entity-tagger.test.js +70 -0
  59. package/dist/entity-tagger.test.js.map +1 -0
  60. package/dist/fts5.test.d.ts +13 -0
  61. package/dist/fts5.test.d.ts.map +1 -0
  62. package/dist/fts5.test.js +144 -0
  63. package/dist/fts5.test.js.map +1 -0
  64. package/dist/graceful-retrieval.test.d.ts +14 -0
  65. package/dist/graceful-retrieval.test.d.ts.map +1 -0
  66. package/dist/graceful-retrieval.test.js +192 -0
  67. package/dist/graceful-retrieval.test.js.map +1 -0
  68. package/dist/hnsw-index.d.ts +51 -0
  69. package/dist/hnsw-index.d.ts.map +1 -1
  70. package/dist/hnsw-index.js +396 -12
  71. package/dist/hnsw-index.js.map +1 -1
  72. package/dist/hnsw-persistence.test.d.ts +13 -0
  73. package/dist/hnsw-persistence.test.d.ts.map +1 -0
  74. package/dist/hnsw-persistence.test.js +208 -0
  75. package/dist/hnsw-persistence.test.js.map +1 -0
  76. package/dist/hybrid-backend.d.ts +28 -0
  77. package/dist/hybrid-backend.d.ts.map +1 -1
  78. package/dist/hybrid-backend.js +82 -4
  79. package/dist/hybrid-backend.js.map +1 -1
  80. package/dist/hybrid-backend.test.js +6 -5
  81. package/dist/hybrid-backend.test.js.map +1 -1
  82. package/dist/index.d.ts +167 -9
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +277 -30
  85. package/dist/index.js.map +1 -1
  86. package/dist/index.test.d.ts +10 -0
  87. package/dist/index.test.d.ts.map +1 -0
  88. package/dist/index.test.js +71 -0
  89. package/dist/index.test.js.map +1 -0
  90. package/dist/json-security.d.ts +12 -0
  91. package/dist/json-security.d.ts.map +1 -0
  92. package/dist/json-security.js +20 -0
  93. package/dist/json-security.js.map +1 -0
  94. package/dist/learning-bridge.d.ts +137 -0
  95. package/dist/learning-bridge.d.ts.map +1 -0
  96. package/dist/learning-bridge.js +335 -0
  97. package/dist/learning-bridge.js.map +1 -0
  98. package/dist/learning-bridge.test.d.ts +8 -0
  99. package/dist/learning-bridge.test.d.ts.map +1 -0
  100. package/dist/learning-bridge.test.js +578 -0
  101. package/dist/learning-bridge.test.js.map +1 -0
  102. package/dist/memory-graph.d.ts +100 -0
  103. package/dist/memory-graph.d.ts.map +1 -0
  104. package/dist/memory-graph.js +333 -0
  105. package/dist/memory-graph.js.map +1 -0
  106. package/dist/memory-graph.test.d.ts +8 -0
  107. package/dist/memory-graph.test.d.ts.map +1 -0
  108. package/dist/memory-graph.test.js +609 -0
  109. package/dist/memory-graph.test.js.map +1 -0
  110. package/dist/persistent-sona.d.ts +144 -0
  111. package/dist/persistent-sona.d.ts.map +1 -0
  112. package/dist/persistent-sona.js +332 -0
  113. package/dist/persistent-sona.js.map +1 -0
  114. package/dist/rvf-backend.d.ts +53 -0
  115. package/dist/rvf-backend.d.ts.map +1 -0
  116. package/dist/rvf-backend.js +643 -0
  117. package/dist/rvf-backend.js.map +1 -0
  118. package/dist/rvf-learning-store.d.ts +139 -0
  119. package/dist/rvf-learning-store.d.ts.map +1 -0
  120. package/dist/rvf-learning-store.js +295 -0
  121. package/dist/rvf-learning-store.js.map +1 -0
  122. package/dist/rvf-migration.d.ts +45 -0
  123. package/dist/rvf-migration.d.ts.map +1 -0
  124. package/dist/rvf-migration.js +254 -0
  125. package/dist/rvf-migration.js.map +1 -0
  126. package/dist/smart-retrieval.d.ts +118 -0
  127. package/dist/smart-retrieval.d.ts.map +1 -0
  128. package/dist/smart-retrieval.js +322 -0
  129. package/dist/smart-retrieval.js.map +1 -0
  130. package/dist/smart-retrieval.test.d.ts +2 -0
  131. package/dist/smart-retrieval.test.d.ts.map +1 -0
  132. package/dist/smart-retrieval.test.js +238 -0
  133. package/dist/smart-retrieval.test.js.map +1 -0
  134. package/dist/sqlite-backend.d.ts +10 -0
  135. package/dist/sqlite-backend.d.ts.map +1 -1
  136. package/dist/sqlite-backend.js +170 -74
  137. package/dist/sqlite-backend.js.map +1 -1
  138. package/dist/sqljs-backend.d.ts +9 -0
  139. package/dist/sqljs-backend.d.ts.map +1 -1
  140. package/dist/sqljs-backend.js +120 -29
  141. package/dist/sqljs-backend.js.map +1 -1
  142. package/dist/types.d.ts +3 -0
  143. package/dist/types.d.ts.map +1 -1
  144. package/package.json +48 -35
  145. package/.agentic-flow/intelligence.json +0 -16
  146. package/__tests__/coverage/base.css +0 -224
  147. package/__tests__/coverage/block-navigation.js +0 -87
  148. package/__tests__/coverage/coverage-final.json +0 -19
  149. package/__tests__/coverage/favicon.png +0 -0
  150. package/__tests__/coverage/index.html +0 -206
  151. package/__tests__/coverage/lcov-report/base.css +0 -224
  152. package/__tests__/coverage/lcov-report/block-navigation.js +0 -87
  153. package/__tests__/coverage/lcov-report/favicon.png +0 -0
  154. package/__tests__/coverage/lcov-report/index.html +0 -206
  155. package/__tests__/coverage/lcov-report/prettify.css +0 -1
  156. package/__tests__/coverage/lcov-report/prettify.js +0 -2
  157. package/__tests__/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  158. package/__tests__/coverage/lcov-report/sorter.js +0 -210
  159. package/__tests__/coverage/lcov-report/src/agentdb-adapter.ts.html +0 -2737
  160. package/__tests__/coverage/lcov-report/src/agentdb-backend.ts.html +0 -3130
  161. package/__tests__/coverage/lcov-report/src/application/commands/delete-memory.command.ts.html +0 -601
  162. package/__tests__/coverage/lcov-report/src/application/commands/index.html +0 -131
  163. package/__tests__/coverage/lcov-report/src/application/commands/store-memory.command.ts.html +0 -394
  164. package/__tests__/coverage/lcov-report/src/application/queries/index.html +0 -116
  165. package/__tests__/coverage/lcov-report/src/application/queries/search-memory.query.ts.html +0 -796
  166. package/__tests__/coverage/lcov-report/src/application/services/index.html +0 -116
  167. package/__tests__/coverage/lcov-report/src/application/services/memory-application-service.ts.html +0 -793
  168. package/__tests__/coverage/lcov-report/src/cache-manager.ts.html +0 -1633
  169. package/__tests__/coverage/lcov-report/src/database-provider.ts.html +0 -1618
  170. package/__tests__/coverage/lcov-report/src/domain/entities/index.html +0 -116
  171. package/__tests__/coverage/lcov-report/src/domain/entities/memory-entry.ts.html +0 -952
  172. package/__tests__/coverage/lcov-report/src/domain/services/index.html +0 -116
  173. package/__tests__/coverage/lcov-report/src/domain/services/memory-domain-service.ts.html +0 -1294
  174. package/__tests__/coverage/lcov-report/src/hnsw-index.ts.html +0 -3124
  175. package/__tests__/coverage/lcov-report/src/hybrid-backend.ts.html +0 -2167
  176. package/__tests__/coverage/lcov-report/src/index.html +0 -266
  177. package/__tests__/coverage/lcov-report/src/infrastructure/repositories/hybrid-memory-repository.ts.html +0 -1633
  178. package/__tests__/coverage/lcov-report/src/infrastructure/repositories/index.html +0 -116
  179. package/__tests__/coverage/lcov-report/src/migration.ts.html +0 -2092
  180. package/__tests__/coverage/lcov-report/src/query-builder.ts.html +0 -1711
  181. package/__tests__/coverage/lcov-report/src/sqlite-backend.ts.html +0 -2281
  182. package/__tests__/coverage/lcov-report/src/sqljs-backend.ts.html +0 -2374
  183. package/__tests__/coverage/lcov-report/src/types.ts.html +0 -2266
  184. package/__tests__/coverage/lcov.info +0 -10238
  185. package/__tests__/coverage/prettify.css +0 -1
  186. package/__tests__/coverage/prettify.js +0 -2
  187. package/__tests__/coverage/sort-arrow-sprite.png +0 -0
  188. package/__tests__/coverage/sorter.js +0 -210
  189. package/__tests__/coverage/src/agentdb-adapter.ts.html +0 -2737
  190. package/__tests__/coverage/src/agentdb-backend.ts.html +0 -3130
  191. package/__tests__/coverage/src/application/commands/delete-memory.command.ts.html +0 -601
  192. package/__tests__/coverage/src/application/commands/index.html +0 -131
  193. package/__tests__/coverage/src/application/commands/store-memory.command.ts.html +0 -394
  194. package/__tests__/coverage/src/application/queries/index.html +0 -116
  195. package/__tests__/coverage/src/application/queries/search-memory.query.ts.html +0 -796
  196. package/__tests__/coverage/src/application/services/index.html +0 -116
  197. package/__tests__/coverage/src/application/services/memory-application-service.ts.html +0 -793
  198. package/__tests__/coverage/src/cache-manager.ts.html +0 -1633
  199. package/__tests__/coverage/src/database-provider.ts.html +0 -1618
  200. package/__tests__/coverage/src/domain/entities/index.html +0 -116
  201. package/__tests__/coverage/src/domain/entities/memory-entry.ts.html +0 -952
  202. package/__tests__/coverage/src/domain/services/index.html +0 -116
  203. package/__tests__/coverage/src/domain/services/memory-domain-service.ts.html +0 -1294
  204. package/__tests__/coverage/src/hnsw-index.ts.html +0 -3124
  205. package/__tests__/coverage/src/hybrid-backend.ts.html +0 -2167
  206. package/__tests__/coverage/src/index.html +0 -266
  207. package/__tests__/coverage/src/infrastructure/repositories/hybrid-memory-repository.ts.html +0 -1633
  208. package/__tests__/coverage/src/infrastructure/repositories/index.html +0 -116
  209. package/__tests__/coverage/src/migration.ts.html +0 -2092
  210. package/__tests__/coverage/src/query-builder.ts.html +0 -1711
  211. package/__tests__/coverage/src/sqlite-backend.ts.html +0 -2281
  212. package/__tests__/coverage/src/sqljs-backend.ts.html +0 -2374
  213. package/__tests__/coverage/src/types.ts.html +0 -2266
  214. package/benchmarks/cache-hit-rate.bench.ts +0 -535
  215. package/benchmarks/hnsw-indexing.bench.ts +0 -552
  216. package/benchmarks/memory-write.bench.ts +0 -469
  217. package/benchmarks/vector-search.bench.ts +0 -449
  218. package/docs/AGENTDB-INTEGRATION.md +0 -388
  219. package/docs/CROSS_PLATFORM.md +0 -505
  220. package/docs/WINDOWS_SUPPORT.md +0 -422
  221. package/examples/agentdb-example.ts +0 -345
  222. package/examples/cross-platform-usage.ts +0 -326
  223. package/framework/benchmark.ts +0 -112
  224. package/src/agentdb-adapter.ts +0 -884
  225. package/src/agentdb-backend.test.ts +0 -339
  226. package/src/agentdb-backend.ts +0 -1016
  227. package/src/application/commands/delete-memory.command.ts +0 -172
  228. package/src/application/commands/store-memory.command.ts +0 -103
  229. package/src/application/index.ts +0 -36
  230. package/src/application/queries/search-memory.query.ts +0 -237
  231. package/src/application/services/memory-application-service.ts +0 -236
  232. package/src/cache-manager.ts +0 -516
  233. package/src/database-provider.test.ts +0 -364
  234. package/src/database-provider.ts +0 -511
  235. package/src/domain/entities/memory-entry.ts +0 -289
  236. package/src/domain/index.ts +0 -35
  237. package/src/domain/repositories/memory-repository.interface.ts +0 -120
  238. package/src/domain/services/memory-domain-service.ts +0 -403
  239. package/src/hnsw-index.ts +0 -1013
  240. package/src/hybrid-backend.test.ts +0 -399
  241. package/src/hybrid-backend.ts +0 -694
  242. package/src/index.ts +0 -515
  243. package/src/infrastructure/index.ts +0 -23
  244. package/src/infrastructure/repositories/hybrid-memory-repository.ts +0 -516
  245. package/src/migration.ts +0 -669
  246. package/src/query-builder.ts +0 -542
  247. package/src/sqlite-backend.ts +0 -732
  248. package/src/sqljs-backend.ts +0 -763
  249. package/src/types.ts +0 -727
  250. package/tmp.json +0 -0
  251. package/tsconfig.json +0 -9
  252. package/tsconfig.tsbuildinfo +0 -1
  253. package/verify-cross-platform.ts +0 -170
@@ -1,694 +0,0 @@
1
- /**
2
- * HybridBackend - Combines SQLite (structured queries) + AgentDB (vector search)
3
- *
4
- * Per ADR-009: "HybridBackend (SQLite + AgentDB) as default"
5
- * - SQLite for: Structured queries, ACID transactions, exact matches
6
- * - AgentDB for: Semantic search, vector similarity, RAG
7
- *
8
- * @module v3/memory/hybrid-backend
9
- */
10
-
11
- import { EventEmitter } from 'node:events';
12
- import {
13
- IMemoryBackend,
14
- MemoryEntry,
15
- MemoryEntryInput,
16
- MemoryEntryUpdate,
17
- MemoryQuery,
18
- SearchOptions,
19
- SearchResult,
20
- BackendStats,
21
- HealthCheckResult,
22
- ComponentHealth,
23
- EmbeddingGenerator,
24
- createDefaultEntry,
25
- QueryType,
26
- } from './types.js';
27
- import { SQLiteBackend, SQLiteBackendConfig } from './sqlite-backend.js';
28
- import { AgentDBBackend, AgentDBBackendConfig } from './agentdb-backend.js';
29
-
30
- /**
31
- * Configuration for HybridBackend
32
- */
33
- export interface HybridBackendConfig {
34
- /** SQLite configuration */
35
- sqlite?: Partial<SQLiteBackendConfig>;
36
-
37
- /** AgentDB configuration */
38
- agentdb?: Partial<AgentDBBackendConfig>;
39
-
40
- /** Default namespace */
41
- defaultNamespace?: string;
42
-
43
- /** Embedding generator function */
44
- embeddingGenerator?: EmbeddingGenerator;
45
-
46
- /** Query routing strategy */
47
- routingStrategy?: 'auto' | 'sqlite-first' | 'agentdb-first';
48
-
49
- /** Enable dual-write (write to both backends) */
50
- dualWrite?: boolean;
51
-
52
- /** Semantic search threshold for hybrid queries */
53
- semanticThreshold?: number;
54
-
55
- /** Maximum results to fetch from each backend in hybrid queries */
56
- hybridMaxResults?: number;
57
- }
58
-
59
- /**
60
- * Default configuration
61
- */
62
- const DEFAULT_CONFIG: Required<HybridBackendConfig> = {
63
- sqlite: {},
64
- agentdb: {},
65
- defaultNamespace: 'default',
66
- embeddingGenerator: undefined as any,
67
- routingStrategy: 'auto',
68
- dualWrite: true,
69
- semanticThreshold: 0.7,
70
- hybridMaxResults: 100,
71
- };
72
-
73
- /**
74
- * Structured Query Interface
75
- * Optimized for SQLite's strengths
76
- */
77
- export interface StructuredQuery {
78
- /** Exact key match */
79
- key?: string;
80
-
81
- /** Key prefix match */
82
- keyPrefix?: string;
83
-
84
- /** Namespace filter */
85
- namespace?: string;
86
-
87
- /** Owner filter */
88
- ownerId?: string;
89
-
90
- /** Type filter */
91
- type?: string;
92
-
93
- /** Time range filters */
94
- createdAfter?: number;
95
- createdBefore?: number;
96
- updatedAfter?: number;
97
- updatedBefore?: number;
98
-
99
- /** Pagination */
100
- limit?: number;
101
- offset?: number;
102
- }
103
-
104
- /**
105
- * Semantic Query Interface
106
- * Optimized for AgentDB's vector search
107
- */
108
- export interface SemanticQuery {
109
- /** Content to search for (will be embedded) */
110
- content?: string;
111
-
112
- /** Pre-computed embedding */
113
- embedding?: Float32Array;
114
-
115
- /** Number of results */
116
- k?: number;
117
-
118
- /** Similarity threshold (0-1) */
119
- threshold?: number;
120
-
121
- /** Additional filters */
122
- filters?: Partial<MemoryQuery>;
123
- }
124
-
125
- /**
126
- * Hybrid Query Interface
127
- * Combines structured + semantic search
128
- */
129
- export interface HybridQuery {
130
- /** Semantic component */
131
- semantic: SemanticQuery;
132
-
133
- /** Structured component */
134
- structured?: StructuredQuery;
135
-
136
- /** How to combine results */
137
- combineStrategy?: 'union' | 'intersection' | 'semantic-first' | 'structured-first';
138
-
139
- /** Weights for score combination */
140
- weights?: {
141
- semantic: number;
142
- structured: number;
143
- };
144
- }
145
-
146
- /**
147
- * HybridBackend Implementation
148
- *
149
- * Intelligently routes queries between SQLite and AgentDB:
150
- * - Exact matches, prefix queries → SQLite
151
- * - Semantic search, similarity → AgentDB
152
- * - Complex hybrid queries → Both backends with intelligent merging
153
- */
154
- export class HybridBackend extends EventEmitter implements IMemoryBackend {
155
- private sqlite: SQLiteBackend;
156
- private agentdb: AgentDBBackend;
157
- private config: Required<HybridBackendConfig>;
158
- private initialized: boolean = false;
159
-
160
- // Performance tracking
161
- private stats = {
162
- sqliteQueries: 0,
163
- agentdbQueries: 0,
164
- hybridQueries: 0,
165
- totalQueryTime: 0,
166
- };
167
-
168
- constructor(config: HybridBackendConfig = {}) {
169
- super();
170
- this.config = { ...DEFAULT_CONFIG, ...config };
171
-
172
- // Initialize SQLite backend
173
- this.sqlite = new SQLiteBackend({
174
- ...this.config.sqlite,
175
- defaultNamespace: this.config.defaultNamespace,
176
- embeddingGenerator: this.config.embeddingGenerator,
177
- });
178
-
179
- // Initialize AgentDB backend
180
- this.agentdb = new AgentDBBackend({
181
- ...this.config.agentdb,
182
- namespace: this.config.defaultNamespace,
183
- embeddingGenerator: this.config.embeddingGenerator,
184
- });
185
-
186
- // Forward events from both backends
187
- this.sqlite.on('entry:stored', (data) => this.emit('sqlite:stored', data));
188
- this.sqlite.on('entry:updated', (data) => this.emit('sqlite:updated', data));
189
- this.sqlite.on('entry:deleted', (data) => this.emit('sqlite:deleted', data));
190
-
191
- this.agentdb.on('entry:stored', (data) => this.emit('agentdb:stored', data));
192
- this.agentdb.on('entry:updated', (data) => this.emit('agentdb:updated', data));
193
- this.agentdb.on('entry:deleted', (data) => this.emit('agentdb:deleted', data));
194
- this.agentdb.on('cache:hit', (data) => this.emit('cache:hit', data));
195
- this.agentdb.on('cache:miss', (data) => this.emit('cache:miss', data));
196
- }
197
-
198
- /**
199
- * Initialize both backends
200
- */
201
- async initialize(): Promise<void> {
202
- if (this.initialized) return;
203
-
204
- await Promise.all([this.sqlite.initialize(), this.agentdb.initialize()]);
205
-
206
- this.initialized = true;
207
- this.emit('initialized');
208
- }
209
-
210
- /**
211
- * Shutdown both backends
212
- */
213
- async shutdown(): Promise<void> {
214
- if (!this.initialized) return;
215
-
216
- await Promise.all([this.sqlite.shutdown(), this.agentdb.shutdown()]);
217
-
218
- this.initialized = false;
219
- this.emit('shutdown');
220
- }
221
-
222
- /**
223
- * Store in both backends (dual-write for consistency)
224
- */
225
- async store(entry: MemoryEntry): Promise<void> {
226
- if (this.config.dualWrite) {
227
- // Write to both backends in parallel
228
- await Promise.all([this.sqlite.store(entry), this.agentdb.store(entry)]);
229
- } else {
230
- // Write to primary backend only (AgentDB has vector search)
231
- await this.agentdb.store(entry);
232
- }
233
-
234
- this.emit('entry:stored', { id: entry.id });
235
- }
236
-
237
- /**
238
- * Get from AgentDB (has caching enabled)
239
- */
240
- async get(id: string): Promise<MemoryEntry | null> {
241
- return this.agentdb.get(id);
242
- }
243
-
244
- /**
245
- * Get by key (SQLite optimized for exact matches)
246
- */
247
- async getByKey(namespace: string, key: string): Promise<MemoryEntry | null> {
248
- return this.sqlite.getByKey(namespace, key);
249
- }
250
-
251
- /**
252
- * Update in both backends
253
- */
254
- async update(id: string, update: MemoryEntryUpdate): Promise<MemoryEntry | null> {
255
- if (this.config.dualWrite) {
256
- // Update both backends
257
- const [sqliteResult, agentdbResult] = await Promise.all([
258
- this.sqlite.update(id, update),
259
- this.agentdb.update(id, update),
260
- ]);
261
- return agentdbResult || sqliteResult;
262
- } else {
263
- return this.agentdb.update(id, update);
264
- }
265
- }
266
-
267
- /**
268
- * Delete from both backends
269
- */
270
- async delete(id: string): Promise<boolean> {
271
- if (this.config.dualWrite) {
272
- const [sqliteResult, agentdbResult] = await Promise.all([
273
- this.sqlite.delete(id),
274
- this.agentdb.delete(id),
275
- ]);
276
- return sqliteResult || agentdbResult;
277
- } else {
278
- return this.agentdb.delete(id);
279
- }
280
- }
281
-
282
- /**
283
- * Query routing - semantic goes to AgentDB, structured to SQLite
284
- */
285
- async query(query: MemoryQuery): Promise<MemoryEntry[]> {
286
- const startTime = performance.now();
287
-
288
- let results: MemoryEntry[];
289
-
290
- // Route based on query type
291
- switch (query.type) {
292
- case 'exact':
293
- // SQLite optimized for exact matches
294
- this.stats.sqliteQueries++;
295
- results = await this.sqlite.query(query);
296
- break;
297
-
298
- case 'prefix':
299
- // SQLite optimized for prefix queries
300
- this.stats.sqliteQueries++;
301
- results = await this.sqlite.query(query);
302
- break;
303
-
304
- case 'tag':
305
- // Both can handle tags, use SQLite for structured filtering
306
- this.stats.sqliteQueries++;
307
- results = await this.sqlite.query(query);
308
- break;
309
-
310
- case 'semantic':
311
- // AgentDB optimized for semantic search
312
- this.stats.agentdbQueries++;
313
- results = await this.agentdb.query(query);
314
- break;
315
-
316
- case 'hybrid':
317
- // Use hybrid query combining both backends
318
- this.stats.hybridQueries++;
319
- results = await this.queryHybridInternal(query);
320
- break;
321
-
322
- default:
323
- // Auto-routing based on query properties
324
- results = await this.autoRoute(query);
325
- }
326
-
327
- const duration = performance.now() - startTime;
328
- this.stats.totalQueryTime += duration;
329
-
330
- this.emit('query:completed', { type: query.type, duration, count: results.length });
331
- return results;
332
- }
333
-
334
- /**
335
- * Structured queries (SQL)
336
- * Routes to SQLite for optimal performance
337
- */
338
- async queryStructured(query: StructuredQuery): Promise<MemoryEntry[]> {
339
- this.stats.sqliteQueries++;
340
-
341
- const memoryQuery: MemoryQuery = {
342
- type: query.key ? 'exact' : query.keyPrefix ? 'prefix' : 'hybrid',
343
- key: query.key,
344
- keyPrefix: query.keyPrefix,
345
- namespace: query.namespace,
346
- ownerId: query.ownerId,
347
- memoryType: query.type as any,
348
- createdAfter: query.createdAfter,
349
- createdBefore: query.createdBefore,
350
- updatedAfter: query.updatedAfter,
351
- updatedBefore: query.updatedBefore,
352
- limit: query.limit || 100,
353
- offset: query.offset || 0,
354
- };
355
-
356
- return this.sqlite.query(memoryQuery);
357
- }
358
-
359
- /**
360
- * Semantic queries (vector)
361
- * Routes to AgentDB for HNSW-based vector search
362
- */
363
- async querySemantic(query: SemanticQuery): Promise<MemoryEntry[]> {
364
- this.stats.agentdbQueries++;
365
-
366
- let embedding = query.embedding;
367
-
368
- // Generate embedding if content provided
369
- if (!embedding && query.content && this.config.embeddingGenerator) {
370
- embedding = await this.config.embeddingGenerator(query.content);
371
- }
372
-
373
- if (!embedding) {
374
- throw new Error('SemanticQuery requires either content or embedding');
375
- }
376
-
377
- const searchResults = await this.agentdb.search(embedding, {
378
- k: query.k || 10,
379
- threshold: query.threshold || this.config.semanticThreshold,
380
- filters: query.filters as MemoryQuery | undefined,
381
- });
382
-
383
- return searchResults.map((r) => r.entry);
384
- }
385
-
386
- /**
387
- * Hybrid queries (combine both)
388
- * Intelligently merges results from both backends
389
- */
390
- async queryHybrid(query: HybridQuery): Promise<MemoryEntry[]> {
391
- this.stats.hybridQueries++;
392
-
393
- const strategy = query.combineStrategy || 'semantic-first';
394
- const weights = query.weights || { semantic: 0.7, structured: 0.3 };
395
-
396
- // Execute both queries in parallel
397
- const [semanticResults, structuredResults] = await Promise.all([
398
- this.querySemantic(query.semantic),
399
- query.structured ? this.queryStructured(query.structured) : Promise.resolve([]),
400
- ]);
401
-
402
- // Combine results based on strategy
403
- switch (strategy) {
404
- case 'union':
405
- return this.combineUnion(semanticResults, structuredResults);
406
-
407
- case 'intersection':
408
- return this.combineIntersection(semanticResults, structuredResults);
409
-
410
- case 'semantic-first':
411
- return this.combineSemanticFirst(semanticResults, structuredResults);
412
-
413
- case 'structured-first':
414
- return this.combineStructuredFirst(semanticResults, structuredResults);
415
-
416
- default:
417
- return this.combineUnion(semanticResults, structuredResults);
418
- }
419
- }
420
-
421
- /**
422
- * Semantic vector search (routes to AgentDB)
423
- */
424
- async search(embedding: Float32Array, options: SearchOptions): Promise<SearchResult[]> {
425
- this.stats.agentdbQueries++;
426
- return this.agentdb.search(embedding, options);
427
- }
428
-
429
- /**
430
- * Bulk insert to both backends
431
- */
432
- async bulkInsert(entries: MemoryEntry[]): Promise<void> {
433
- if (this.config.dualWrite) {
434
- await Promise.all([this.sqlite.bulkInsert(entries), this.agentdb.bulkInsert(entries)]);
435
- } else {
436
- await this.agentdb.bulkInsert(entries);
437
- }
438
- }
439
-
440
- /**
441
- * Bulk delete from both backends
442
- */
443
- async bulkDelete(ids: string[]): Promise<number> {
444
- if (this.config.dualWrite) {
445
- const [sqliteCount, agentdbCount] = await Promise.all([
446
- this.sqlite.bulkDelete(ids),
447
- this.agentdb.bulkDelete(ids),
448
- ]);
449
- return Math.max(sqliteCount, agentdbCount);
450
- } else {
451
- return this.agentdb.bulkDelete(ids);
452
- }
453
- }
454
-
455
- /**
456
- * Count entries (use SQLite for efficiency)
457
- */
458
- async count(namespace?: string): Promise<number> {
459
- return this.sqlite.count(namespace);
460
- }
461
-
462
- /**
463
- * List namespaces (use SQLite)
464
- */
465
- async listNamespaces(): Promise<string[]> {
466
- return this.sqlite.listNamespaces();
467
- }
468
-
469
- /**
470
- * Clear namespace in both backends
471
- */
472
- async clearNamespace(namespace: string): Promise<number> {
473
- if (this.config.dualWrite) {
474
- const [sqliteCount, agentdbCount] = await Promise.all([
475
- this.sqlite.clearNamespace(namespace),
476
- this.agentdb.clearNamespace(namespace),
477
- ]);
478
- return Math.max(sqliteCount, agentdbCount);
479
- } else {
480
- return this.agentdb.clearNamespace(namespace);
481
- }
482
- }
483
-
484
- /**
485
- * Get combined statistics from both backends
486
- */
487
- async getStats(): Promise<BackendStats> {
488
- const [sqliteStats, agentdbStats] = await Promise.all([
489
- this.sqlite.getStats(),
490
- this.agentdb.getStats(),
491
- ]);
492
-
493
- return {
494
- totalEntries: Math.max(sqliteStats.totalEntries, agentdbStats.totalEntries),
495
- entriesByNamespace: agentdbStats.entriesByNamespace,
496
- entriesByType: agentdbStats.entriesByType,
497
- memoryUsage: sqliteStats.memoryUsage + agentdbStats.memoryUsage,
498
- hnswStats: agentdbStats.hnswStats,
499
- cacheStats: agentdbStats.cacheStats,
500
- avgQueryTime:
501
- this.stats.hybridQueries + this.stats.sqliteQueries + this.stats.agentdbQueries > 0
502
- ? this.stats.totalQueryTime /
503
- (this.stats.hybridQueries + this.stats.sqliteQueries + this.stats.agentdbQueries)
504
- : 0,
505
- avgSearchTime: agentdbStats.avgSearchTime,
506
- };
507
- }
508
-
509
- /**
510
- * Health check for both backends
511
- */
512
- async healthCheck(): Promise<HealthCheckResult> {
513
- const [sqliteHealth, agentdbHealth] = await Promise.all([
514
- this.sqlite.healthCheck(),
515
- this.agentdb.healthCheck(),
516
- ]);
517
-
518
- const allIssues = [...sqliteHealth.issues, ...agentdbHealth.issues];
519
- const allRecommendations = [
520
- ...sqliteHealth.recommendations,
521
- ...agentdbHealth.recommendations,
522
- ];
523
-
524
- // Determine overall status
525
- let status: 'healthy' | 'degraded' | 'unhealthy' = 'healthy';
526
- if (
527
- sqliteHealth.status === 'unhealthy' ||
528
- agentdbHealth.status === 'unhealthy'
529
- ) {
530
- status = 'unhealthy';
531
- } else if (
532
- sqliteHealth.status === 'degraded' ||
533
- agentdbHealth.status === 'degraded'
534
- ) {
535
- status = 'degraded';
536
- }
537
-
538
- return {
539
- status,
540
- components: {
541
- storage: sqliteHealth.components.storage,
542
- index: agentdbHealth.components.index,
543
- cache: agentdbHealth.components.cache,
544
- },
545
- timestamp: Date.now(),
546
- issues: allIssues,
547
- recommendations: allRecommendations,
548
- };
549
- }
550
-
551
- // ===== Private Methods =====
552
-
553
- /**
554
- * Auto-route queries based on properties
555
- */
556
- private async autoRoute(query: MemoryQuery): Promise<MemoryEntry[]> {
557
- // If has embedding or content, use semantic search (AgentDB)
558
- const hasEmbeddingGenerator = typeof this.config.embeddingGenerator === 'function';
559
- if (query.embedding || (query.content && hasEmbeddingGenerator)) {
560
- this.stats.agentdbQueries++;
561
- return this.agentdb.query(query);
562
- }
563
-
564
- // If has exact key or prefix, use structured search (SQLite)
565
- if (query.key || query.keyPrefix) {
566
- this.stats.sqliteQueries++;
567
- return this.sqlite.query(query);
568
- }
569
-
570
- // For other filters, use routing strategy
571
- switch (this.config.routingStrategy) {
572
- case 'sqlite-first':
573
- this.stats.sqliteQueries++;
574
- return this.sqlite.query(query);
575
-
576
- case 'agentdb-first':
577
- this.stats.agentdbQueries++;
578
- return this.agentdb.query(query);
579
-
580
- case 'auto':
581
- default:
582
- // Default to AgentDB (has caching)
583
- this.stats.agentdbQueries++;
584
- return this.agentdb.query(query);
585
- }
586
- }
587
-
588
- /**
589
- * Internal hybrid query implementation
590
- */
591
- private async queryHybridInternal(query: MemoryQuery): Promise<MemoryEntry[]> {
592
- // If semantic component exists, use hybrid
593
- if (query.embedding || query.content) {
594
- const semanticQuery: SemanticQuery = {
595
- content: query.content,
596
- embedding: query.embedding,
597
- k: query.limit || 10,
598
- threshold: query.threshold,
599
- filters: query,
600
- };
601
-
602
- const structuredQuery: StructuredQuery = {
603
- namespace: query.namespace,
604
- key: query.key,
605
- keyPrefix: query.keyPrefix,
606
- ownerId: query.ownerId,
607
- type: query.memoryType,
608
- createdAfter: query.createdAfter,
609
- createdBefore: query.createdBefore,
610
- updatedAfter: query.updatedAfter,
611
- updatedBefore: query.updatedBefore,
612
- limit: query.limit,
613
- offset: query.offset,
614
- };
615
-
616
- return this.queryHybrid({
617
- semantic: semanticQuery,
618
- structured: structuredQuery,
619
- combineStrategy: 'semantic-first',
620
- });
621
- }
622
-
623
- // Otherwise, route to structured
624
- return this.autoRoute(query);
625
- }
626
-
627
- /**
628
- * Combine results using union (all unique results)
629
- */
630
- private combineUnion(
631
- semanticResults: MemoryEntry[],
632
- structuredResults: MemoryEntry[]
633
- ): MemoryEntry[] {
634
- const seen = new Set<string>();
635
- const combined: MemoryEntry[] = [];
636
-
637
- for (const entry of [...semanticResults, ...structuredResults]) {
638
- if (!seen.has(entry.id)) {
639
- seen.add(entry.id);
640
- combined.push(entry);
641
- }
642
- }
643
-
644
- return combined;
645
- }
646
-
647
- /**
648
- * Combine results using intersection (only common results)
649
- */
650
- private combineIntersection(
651
- semanticResults: MemoryEntry[],
652
- structuredResults: MemoryEntry[]
653
- ): MemoryEntry[] {
654
- const semanticIds = new Set(semanticResults.map((e) => e.id));
655
- return structuredResults.filter((e) => semanticIds.has(e.id));
656
- }
657
-
658
- /**
659
- * Semantic-first: Prefer semantic results, add structured if not present
660
- */
661
- private combineSemanticFirst(
662
- semanticResults: MemoryEntry[],
663
- structuredResults: MemoryEntry[]
664
- ): MemoryEntry[] {
665
- const semanticIds = new Set(semanticResults.map((e) => e.id));
666
- const additional = structuredResults.filter((e) => !semanticIds.has(e.id));
667
- return [...semanticResults, ...additional];
668
- }
669
-
670
- /**
671
- * Structured-first: Prefer structured results, add semantic if not present
672
- */
673
- private combineStructuredFirst(
674
- semanticResults: MemoryEntry[],
675
- structuredResults: MemoryEntry[]
676
- ): MemoryEntry[] {
677
- const structuredIds = new Set(structuredResults.map((e) => e.id));
678
- const additional = semanticResults.filter((e) => !structuredIds.has(e.id));
679
- return [...structuredResults, ...additional];
680
- }
681
-
682
- /**
683
- * Get underlying backends for advanced operations
684
- */
685
- getSQLiteBackend(): SQLiteBackend {
686
- return this.sqlite;
687
- }
688
-
689
- getAgentDBBackend(): AgentDBBackend {
690
- return this.agentdb;
691
- }
692
- }
693
-
694
- export default HybridBackend;