@fgv/ts-agent-memory 5.1.0-46 → 5.1.0-48

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 (336) hide show
  1. package/README.md +55 -0
  2. package/dist/packlets/ingest/orchestrator.js +115 -20
  3. package/dist/packlets/ingest/orchestrator.js.map +1 -1
  4. package/dist/packlets/observe/memoryObservationStore.js +6 -0
  5. package/dist/packlets/observe/memoryObservationStore.js.map +1 -1
  6. package/dist/packlets/observe/observer.js.map +1 -1
  7. package/dist/packlets/store/fileTreeMemoryStore.js +63 -135
  8. package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
  9. package/dist/packlets/store/vectorMaintenance.js +251 -0
  10. package/dist/packlets/store/vectorMaintenance.js.map +1 -0
  11. package/dist/packlets/vector/inMemoryCosineIndex.js +81 -18
  12. package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  13. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js +7 -0
  14. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
  15. package/dist/packlets/vector/vectorIndex.js.map +1 -1
  16. package/dist/ts-agent-memory.d.ts +389 -71
  17. package/lib/packlets/ingest/orchestrator.d.ts +62 -5
  18. package/lib/packlets/ingest/orchestrator.d.ts.map +1 -1
  19. package/lib/packlets/ingest/orchestrator.js +115 -20
  20. package/lib/packlets/ingest/orchestrator.js.map +1 -1
  21. package/lib/packlets/observe/memoryObservationStore.d.ts.map +1 -1
  22. package/lib/packlets/observe/memoryObservationStore.js +6 -0
  23. package/lib/packlets/observe/memoryObservationStore.js.map +1 -1
  24. package/lib/packlets/observe/observer.d.ts +61 -0
  25. package/lib/packlets/observe/observer.d.ts.map +1 -1
  26. package/lib/packlets/observe/observer.js.map +1 -1
  27. package/lib/packlets/store/fileTreeMemoryStore.d.ts +97 -60
  28. package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
  29. package/lib/packlets/store/fileTreeMemoryStore.js +63 -135
  30. package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
  31. package/lib/packlets/store/vectorMaintenance.d.ts +149 -0
  32. package/lib/packlets/store/vectorMaintenance.d.ts.map +1 -0
  33. package/lib/packlets/store/vectorMaintenance.js +255 -0
  34. package/lib/packlets/store/vectorMaintenance.js.map +1 -0
  35. package/lib/packlets/vector/inMemoryCosineIndex.d.ts +30 -7
  36. package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -1
  37. package/lib/packlets/vector/inMemoryCosineIndex.js +80 -17
  38. package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  39. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts +7 -0
  40. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts.map +1 -1
  41. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js +7 -0
  42. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
  43. package/lib/packlets/vector/vectorIndex.d.ts +129 -1
  44. package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
  45. package/lib/packlets/vector/vectorIndex.js.map +1 -1
  46. package/package.json +17 -7
  47. package/.rush/temp/6e1299d1cebb080772163a532c221cd181b54f9f.tar.log +0 -462
  48. package/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +0 -9
  49. package/.rush/temp/operation/build/all.log +0 -9
  50. package/.rush/temp/operation/build/log-chunks.jsonl +0 -9
  51. package/.rush/temp/operation/build/state.json +0 -3
  52. package/.rush/temp/shrinkwrap-deps.json +0 -689
  53. package/config/api-extractor.json +0 -343
  54. package/config/jest.config.json +0 -14
  55. package/config/rig.json +0 -4
  56. package/dist/test/unit/converters/antagonistRoundTrip.test.js +0 -95
  57. package/dist/test/unit/converters/antagonistRoundTrip.test.js.map +0 -1
  58. package/dist/test/unit/converters/bodyConverterRegistry.test.js +0 -72
  59. package/dist/test/unit/converters/bodyConverterRegistry.test.js.map +0 -1
  60. package/dist/test/unit/converters/envelopeConverter.test.js +0 -313
  61. package/dist/test/unit/converters/envelopeConverter.test.js.map +0 -1
  62. package/dist/test/unit/index/memoryIndex.test.js +0 -214
  63. package/dist/test/unit/index/memoryIndex.test.js.map +0 -1
  64. package/dist/test/unit/ingest/antagonistCycleAndParity.test.js +0 -277
  65. package/dist/test/unit/ingest/antagonistCycleAndParity.test.js.map +0 -1
  66. package/dist/test/unit/ingest/cycleGuard.test.js +0 -81
  67. package/dist/test/unit/ingest/cycleGuard.test.js.map +0 -1
  68. package/dist/test/unit/ingest/orchestrator.test.js +0 -1055
  69. package/dist/test/unit/ingest/orchestrator.test.js.map +0 -1
  70. package/dist/test/unit/observe/memoryObservationStore.test.js +0 -118
  71. package/dist/test/unit/observe/memoryObservationStore.test.js.map +0 -1
  72. package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js +0 -116
  73. package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +0 -1
  74. package/dist/test/unit/retrieve/linkTraversalRetriever.test.js +0 -257
  75. package/dist/test/unit/retrieve/linkTraversalRetriever.test.js.map +0 -1
  76. package/dist/test/unit/retrieve/retrievers.test.js +0 -768
  77. package/dist/test/unit/retrieve/retrievers.test.js.map +0 -1
  78. package/dist/test/unit/retrieve/temporalRetrievers.test.js +0 -182
  79. package/dist/test/unit/retrieve/temporalRetrievers.test.js.map +0 -1
  80. package/dist/test/unit/store/antagonistTemporalBoundary.test.js +0 -120
  81. package/dist/test/unit/store/antagonistTemporalBoundary.test.js.map +0 -1
  82. package/dist/test/unit/store/embedOnWrite.test.js +0 -317
  83. package/dist/test/unit/store/embedOnWrite.test.js.map +0 -1
  84. package/dist/test/unit/store/fileTreeMemoryStore.test.js +0 -778
  85. package/dist/test/unit/store/fileTreeMemoryStore.test.js.map +0 -1
  86. package/dist/test/unit/store/fragmentEmbedOnWrite.test.js +0 -255
  87. package/dist/test/unit/store/fragmentEmbedOnWrite.test.js.map +0 -1
  88. package/dist/test/unit/store/indexInjection.test.js +0 -432
  89. package/dist/test/unit/store/indexInjection.test.js.map +0 -1
  90. package/dist/test/unit/store/lenientOpen.test.js +0 -248
  91. package/dist/test/unit/store/lenientOpen.test.js.map +0 -1
  92. package/dist/test/unit/store/listScoped.test.js +0 -109
  93. package/dist/test/unit/store/listScoped.test.js.map +0 -1
  94. package/dist/test/unit/store/observations.test.js +0 -239
  95. package/dist/test/unit/store/observations.test.js.map +0 -1
  96. package/dist/test/unit/store/rankAxis.test.js +0 -254
  97. package/dist/test/unit/store/rankAxis.test.js.map +0 -1
  98. package/dist/test/unit/store/scopeEncoding.test.js +0 -24
  99. package/dist/test/unit/store/scopeEncoding.test.js.map +0 -1
  100. package/dist/test/unit/store/temporalStore.test.js +0 -398
  101. package/dist/test/unit/store/temporalStore.test.js.map +0 -1
  102. package/dist/test/unit/tools/memoryTools.test.js +0 -841
  103. package/dist/test/unit/tools/memoryTools.test.js.map +0 -1
  104. package/dist/test/unit/types/identityCodec.test.js +0 -187
  105. package/dist/test/unit/types/identityCodec.test.js.map +0 -1
  106. package/dist/test/unit/types/ids.test.js +0 -84
  107. package/dist/test/unit/types/ids.test.js.map +0 -1
  108. package/dist/test/unit/types/temporalCodec.test.js +0 -203
  109. package/dist/test/unit/types/temporalCodec.test.js.map +0 -1
  110. package/dist/test/unit/types/temporalPolicy.test.js +0 -83
  111. package/dist/test/unit/types/temporalPolicy.test.js.map +0 -1
  112. package/dist/test/unit/types/writePolicy.test.js +0 -331
  113. package/dist/test/unit/types/writePolicy.test.js.map +0 -1
  114. package/dist/test/unit/vector/fragmentConverters.test.js +0 -58
  115. package/dist/test/unit/vector/fragmentConverters.test.js.map +0 -1
  116. package/dist/test/unit/vector/inMemoryCosineIndex.test.js +0 -252
  117. package/dist/test/unit/vector/inMemoryCosineIndex.test.js.map +0 -1
  118. package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js +0 -362
  119. package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +0 -1
  120. package/dist/test/unit/vector/vectorIndex.test.js +0 -51
  121. package/dist/test/unit/vector/vectorIndex.test.js.map +0 -1
  122. package/eslint.config.js +0 -15
  123. package/etc/ts-agent-memory.api.md +0 -938
  124. package/lib/test/unit/converters/antagonistRoundTrip.test.d.ts +0 -10
  125. package/lib/test/unit/converters/antagonistRoundTrip.test.d.ts.map +0 -1
  126. package/lib/test/unit/converters/antagonistRoundTrip.test.js +0 -97
  127. package/lib/test/unit/converters/antagonistRoundTrip.test.js.map +0 -1
  128. package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts +0 -2
  129. package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts.map +0 -1
  130. package/lib/test/unit/converters/bodyConverterRegistry.test.js +0 -74
  131. package/lib/test/unit/converters/bodyConverterRegistry.test.js.map +0 -1
  132. package/lib/test/unit/converters/envelopeConverter.test.d.ts +0 -2
  133. package/lib/test/unit/converters/envelopeConverter.test.d.ts.map +0 -1
  134. package/lib/test/unit/converters/envelopeConverter.test.js +0 -315
  135. package/lib/test/unit/converters/envelopeConverter.test.js.map +0 -1
  136. package/lib/test/unit/index/memoryIndex.test.d.ts +0 -2
  137. package/lib/test/unit/index/memoryIndex.test.d.ts.map +0 -1
  138. package/lib/test/unit/index/memoryIndex.test.js +0 -216
  139. package/lib/test/unit/index/memoryIndex.test.js.map +0 -1
  140. package/lib/test/unit/ingest/antagonistCycleAndParity.test.d.ts +0 -9
  141. package/lib/test/unit/ingest/antagonistCycleAndParity.test.d.ts.map +0 -1
  142. package/lib/test/unit/ingest/antagonistCycleAndParity.test.js +0 -279
  143. package/lib/test/unit/ingest/antagonistCycleAndParity.test.js.map +0 -1
  144. package/lib/test/unit/ingest/cycleGuard.test.d.ts +0 -2
  145. package/lib/test/unit/ingest/cycleGuard.test.d.ts.map +0 -1
  146. package/lib/test/unit/ingest/cycleGuard.test.js +0 -83
  147. package/lib/test/unit/ingest/cycleGuard.test.js.map +0 -1
  148. package/lib/test/unit/ingest/orchestrator.test.d.ts +0 -2
  149. package/lib/test/unit/ingest/orchestrator.test.d.ts.map +0 -1
  150. package/lib/test/unit/ingest/orchestrator.test.js +0 -1057
  151. package/lib/test/unit/ingest/orchestrator.test.js.map +0 -1
  152. package/lib/test/unit/observe/memoryObservationStore.test.d.ts +0 -2
  153. package/lib/test/unit/observe/memoryObservationStore.test.d.ts.map +0 -1
  154. package/lib/test/unit/observe/memoryObservationStore.test.js +0 -120
  155. package/lib/test/unit/observe/memoryObservationStore.test.js.map +0 -1
  156. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts +0 -2
  157. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts.map +0 -1
  158. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js +0 -118
  159. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +0 -1
  160. package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts +0 -2
  161. package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts.map +0 -1
  162. package/lib/test/unit/retrieve/linkTraversalRetriever.test.js +0 -259
  163. package/lib/test/unit/retrieve/linkTraversalRetriever.test.js.map +0 -1
  164. package/lib/test/unit/retrieve/retrievers.test.d.ts +0 -2
  165. package/lib/test/unit/retrieve/retrievers.test.d.ts.map +0 -1
  166. package/lib/test/unit/retrieve/retrievers.test.js +0 -770
  167. package/lib/test/unit/retrieve/retrievers.test.js.map +0 -1
  168. package/lib/test/unit/retrieve/temporalRetrievers.test.d.ts +0 -2
  169. package/lib/test/unit/retrieve/temporalRetrievers.test.d.ts.map +0 -1
  170. package/lib/test/unit/retrieve/temporalRetrievers.test.js +0 -184
  171. package/lib/test/unit/retrieve/temporalRetrievers.test.js.map +0 -1
  172. package/lib/test/unit/store/antagonistTemporalBoundary.test.d.ts +0 -9
  173. package/lib/test/unit/store/antagonistTemporalBoundary.test.d.ts.map +0 -1
  174. package/lib/test/unit/store/antagonistTemporalBoundary.test.js +0 -122
  175. package/lib/test/unit/store/antagonistTemporalBoundary.test.js.map +0 -1
  176. package/lib/test/unit/store/embedOnWrite.test.d.ts +0 -2
  177. package/lib/test/unit/store/embedOnWrite.test.d.ts.map +0 -1
  178. package/lib/test/unit/store/embedOnWrite.test.js +0 -319
  179. package/lib/test/unit/store/embedOnWrite.test.js.map +0 -1
  180. package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts +0 -2
  181. package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts.map +0 -1
  182. package/lib/test/unit/store/fileTreeMemoryStore.test.js +0 -780
  183. package/lib/test/unit/store/fileTreeMemoryStore.test.js.map +0 -1
  184. package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts +0 -2
  185. package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts.map +0 -1
  186. package/lib/test/unit/store/fragmentEmbedOnWrite.test.js +0 -257
  187. package/lib/test/unit/store/fragmentEmbedOnWrite.test.js.map +0 -1
  188. package/lib/test/unit/store/indexInjection.test.d.ts +0 -2
  189. package/lib/test/unit/store/indexInjection.test.d.ts.map +0 -1
  190. package/lib/test/unit/store/indexInjection.test.js +0 -434
  191. package/lib/test/unit/store/indexInjection.test.js.map +0 -1
  192. package/lib/test/unit/store/lenientOpen.test.d.ts +0 -2
  193. package/lib/test/unit/store/lenientOpen.test.d.ts.map +0 -1
  194. package/lib/test/unit/store/lenientOpen.test.js +0 -250
  195. package/lib/test/unit/store/lenientOpen.test.js.map +0 -1
  196. package/lib/test/unit/store/listScoped.test.d.ts +0 -2
  197. package/lib/test/unit/store/listScoped.test.d.ts.map +0 -1
  198. package/lib/test/unit/store/listScoped.test.js +0 -111
  199. package/lib/test/unit/store/listScoped.test.js.map +0 -1
  200. package/lib/test/unit/store/observations.test.d.ts +0 -2
  201. package/lib/test/unit/store/observations.test.d.ts.map +0 -1
  202. package/lib/test/unit/store/observations.test.js +0 -241
  203. package/lib/test/unit/store/observations.test.js.map +0 -1
  204. package/lib/test/unit/store/rankAxis.test.d.ts +0 -2
  205. package/lib/test/unit/store/rankAxis.test.d.ts.map +0 -1
  206. package/lib/test/unit/store/rankAxis.test.js +0 -256
  207. package/lib/test/unit/store/rankAxis.test.js.map +0 -1
  208. package/lib/test/unit/store/scopeEncoding.test.d.ts +0 -2
  209. package/lib/test/unit/store/scopeEncoding.test.d.ts.map +0 -1
  210. package/lib/test/unit/store/scopeEncoding.test.js +0 -26
  211. package/lib/test/unit/store/scopeEncoding.test.js.map +0 -1
  212. package/lib/test/unit/store/temporalStore.test.d.ts +0 -2
  213. package/lib/test/unit/store/temporalStore.test.d.ts.map +0 -1
  214. package/lib/test/unit/store/temporalStore.test.js +0 -400
  215. package/lib/test/unit/store/temporalStore.test.js.map +0 -1
  216. package/lib/test/unit/tools/memoryTools.test.d.ts +0 -2
  217. package/lib/test/unit/tools/memoryTools.test.d.ts.map +0 -1
  218. package/lib/test/unit/tools/memoryTools.test.js +0 -843
  219. package/lib/test/unit/tools/memoryTools.test.js.map +0 -1
  220. package/lib/test/unit/types/identityCodec.test.d.ts +0 -2
  221. package/lib/test/unit/types/identityCodec.test.d.ts.map +0 -1
  222. package/lib/test/unit/types/identityCodec.test.js +0 -189
  223. package/lib/test/unit/types/identityCodec.test.js.map +0 -1
  224. package/lib/test/unit/types/ids.test.d.ts +0 -2
  225. package/lib/test/unit/types/ids.test.d.ts.map +0 -1
  226. package/lib/test/unit/types/ids.test.js +0 -86
  227. package/lib/test/unit/types/ids.test.js.map +0 -1
  228. package/lib/test/unit/types/temporalCodec.test.d.ts +0 -2
  229. package/lib/test/unit/types/temporalCodec.test.d.ts.map +0 -1
  230. package/lib/test/unit/types/temporalCodec.test.js +0 -205
  231. package/lib/test/unit/types/temporalCodec.test.js.map +0 -1
  232. package/lib/test/unit/types/temporalPolicy.test.d.ts +0 -2
  233. package/lib/test/unit/types/temporalPolicy.test.d.ts.map +0 -1
  234. package/lib/test/unit/types/temporalPolicy.test.js +0 -85
  235. package/lib/test/unit/types/temporalPolicy.test.js.map +0 -1
  236. package/lib/test/unit/types/writePolicy.test.d.ts +0 -2
  237. package/lib/test/unit/types/writePolicy.test.d.ts.map +0 -1
  238. package/lib/test/unit/types/writePolicy.test.js +0 -333
  239. package/lib/test/unit/types/writePolicy.test.js.map +0 -1
  240. package/lib/test/unit/vector/fragmentConverters.test.d.ts +0 -2
  241. package/lib/test/unit/vector/fragmentConverters.test.d.ts.map +0 -1
  242. package/lib/test/unit/vector/fragmentConverters.test.js +0 -60
  243. package/lib/test/unit/vector/fragmentConverters.test.js.map +0 -1
  244. package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts +0 -2
  245. package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts.map +0 -1
  246. package/lib/test/unit/vector/inMemoryCosineIndex.test.js +0 -254
  247. package/lib/test/unit/vector/inMemoryCosineIndex.test.js.map +0 -1
  248. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts +0 -2
  249. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts.map +0 -1
  250. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js +0 -364
  251. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +0 -1
  252. package/lib/test/unit/vector/vectorIndex.test.d.ts +0 -2
  253. package/lib/test/unit/vector/vectorIndex.test.d.ts.map +0 -1
  254. package/lib/test/unit/vector/vectorIndex.test.js +0 -53
  255. package/lib/test/unit/vector/vectorIndex.test.js.map +0 -1
  256. package/rush-logs/ts-agent-memory.build.cache.log +0 -3
  257. package/rush-logs/ts-agent-memory.build.log +0 -9
  258. package/src/index.ts +0 -14
  259. package/src/packlets/converters/bodyConverterRegistry.ts +0 -105
  260. package/src/packlets/converters/envelopeConverter.ts +0 -233
  261. package/src/packlets/converters/index.ts +0 -7
  262. package/src/packlets/index/index.ts +0 -6
  263. package/src/packlets/index/memoryIndex.ts +0 -332
  264. package/src/packlets/ingest/cycleGuard.ts +0 -153
  265. package/src/packlets/ingest/hostStages.ts +0 -111
  266. package/src/packlets/ingest/index.ts +0 -9
  267. package/src/packlets/ingest/model.ts +0 -195
  268. package/src/packlets/ingest/orchestrator.ts +0 -873
  269. package/src/packlets/observe/index.ts +0 -7
  270. package/src/packlets/observe/memoryObservationStore.ts +0 -153
  271. package/src/packlets/observe/observer.ts +0 -119
  272. package/src/packlets/retrieve/fragmentSemanticRetriever.ts +0 -138
  273. package/src/packlets/retrieve/hybridRetriever.ts +0 -194
  274. package/src/packlets/retrieve/index.ts +0 -14
  275. package/src/packlets/retrieve/linkTraversalRetriever.ts +0 -158
  276. package/src/packlets/retrieve/recencyRetriever.ts +0 -54
  277. package/src/packlets/retrieve/retriever.ts +0 -291
  278. package/src/packlets/retrieve/semanticRetriever.ts +0 -152
  279. package/src/packlets/retrieve/structuredFilterRetriever.ts +0 -58
  280. package/src/packlets/retrieve/tagRetriever.ts +0 -58
  281. package/src/packlets/retrieve/temporalRetrievers.ts +0 -210
  282. package/src/packlets/store/fileTreeMemoryStore.ts +0 -1834
  283. package/src/packlets/store/index.ts +0 -7
  284. package/src/packlets/store/scopeEncoding.ts +0 -36
  285. package/src/packlets/tools/index.ts +0 -6
  286. package/src/packlets/tools/memoryTools.ts +0 -706
  287. package/src/packlets/types/envelope.ts +0 -196
  288. package/src/packlets/types/filenameSafety.ts +0 -57
  289. package/src/packlets/types/identityCodec.ts +0 -447
  290. package/src/packlets/types/ids.ts +0 -124
  291. package/src/packlets/types/index.ts +0 -11
  292. package/src/packlets/types/temporal.ts +0 -96
  293. package/src/packlets/types/writePolicy.ts +0 -612
  294. package/src/packlets/vector/fragmentConverters.ts +0 -55
  295. package/src/packlets/vector/inMemoryCosineIndex.ts +0 -196
  296. package/src/packlets/vector/inMemoryFragmentCosineIndex.ts +0 -289
  297. package/src/packlets/vector/index.ts +0 -9
  298. package/src/packlets/vector/vectorIndex.ts +0 -273
  299. package/src/test/unit/converters/antagonistRoundTrip.test.ts +0 -110
  300. package/src/test/unit/converters/bodyConverterRegistry.test.ts +0 -89
  301. package/src/test/unit/converters/envelopeConverter.test.ts +0 -418
  302. package/src/test/unit/index/memoryIndex.test.ts +0 -272
  303. package/src/test/unit/ingest/antagonistCycleAndParity.test.ts +0 -367
  304. package/src/test/unit/ingest/cycleGuard.test.ts +0 -110
  305. package/src/test/unit/ingest/orchestrator.test.ts +0 -1351
  306. package/src/test/unit/observe/memoryObservationStore.test.ts +0 -158
  307. package/src/test/unit/retrieve/fragmentSemanticRetriever.test.ts +0 -163
  308. package/src/test/unit/retrieve/linkTraversalRetriever.test.ts +0 -329
  309. package/src/test/unit/retrieve/retrievers.test.ts +0 -1018
  310. package/src/test/unit/retrieve/temporalRetrievers.test.ts +0 -226
  311. package/src/test/unit/store/antagonistTemporalBoundary.test.ts +0 -158
  312. package/src/test/unit/store/embedOnWrite.test.ts +0 -418
  313. package/src/test/unit/store/fileTreeMemoryStore.test.ts +0 -1041
  314. package/src/test/unit/store/fragmentEmbedOnWrite.test.ts +0 -349
  315. package/src/test/unit/store/indexInjection.test.ts +0 -550
  316. package/src/test/unit/store/lenientOpen.test.ts +0 -292
  317. package/src/test/unit/store/listScoped.test.ts +0 -138
  318. package/src/test/unit/store/observations.test.ts +0 -290
  319. package/src/test/unit/store/rankAxis.test.ts +0 -349
  320. package/src/test/unit/store/scopeEncoding.test.ts +0 -37
  321. package/src/test/unit/store/temporalStore.test.ts +0 -469
  322. package/src/test/unit/tools/memoryTools.test.ts +0 -1120
  323. package/src/test/unit/types/identityCodec.test.ts +0 -266
  324. package/src/test/unit/types/ids.test.ts +0 -94
  325. package/src/test/unit/types/temporalCodec.test.ts +0 -259
  326. package/src/test/unit/types/temporalPolicy.test.ts +0 -124
  327. package/src/test/unit/types/writePolicy.test.ts +0 -446
  328. package/src/test/unit/vector/fragmentConverters.test.ts +0 -80
  329. package/src/test/unit/vector/inMemoryCosineIndex.test.ts +0 -318
  330. package/src/test/unit/vector/inMemoryFragmentCosineIndex.test.ts +0 -477
  331. package/src/test/unit/vector/vectorIndex.test.ts +0 -64
  332. package/temp/build/lint/_eslint-5eVG3S6w.json +0 -302
  333. package/temp/build/typescript/ts_8nwakTlr.json +0 -1
  334. package/temp/ts-agent-memory.api.json +0 -20933
  335. package/temp/ts-agent-memory.api.md +0 -938
  336. package/tsconfig.json +0 -8
@@ -1,7 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- export * from './observer';
7
- export * from './memoryObservationStore';
@@ -1,153 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- import { Collections, Result, fail, succeed } from '@fgv/ts-utils';
7
- import { IMemoryObservationQuery, IMemoryObservationRecord, IMemoryObserver } from './observer';
8
-
9
- /**
10
- * Construction options for {@link MemoryObservationStore.create}.
11
- * @public
12
- */
13
- export interface IMemoryObservationStoreCreateParams {
14
- /**
15
- * Maximum number of observation records retained before the oldest is
16
- * overwritten. Defaults to `1000`. Must be a positive integer if supplied.
17
- */
18
- readonly maxRecords?: number;
19
- }
20
-
21
- /**
22
- * The default in-memory observation store: an {@link IMemoryObserver} that
23
- * retains the records it observes in a bounded ring and answers schema-aware
24
- * {@link MemoryObservationStore.query | queries} over them.
25
- *
26
- * @remarks
27
- * **Privacy posture — this store is most-permissive by design.** It retains
28
- * every field of every record verbatim, including any `provenance` and
29
- * `querySnapshot`. The library bakes in **no** redaction, retention, or
30
- * field-stripping policy — that is deployment policy, not library policy. A
31
- * deployment that must redact wraps this store with its own
32
- * {@link IMemoryObserver} that transforms records before forwarding, or
33
- * substitutes a different observer entirely. Size is the only bounded
34
- * dimension, via `maxRecords`.
35
- *
36
- * The store composes `RetainingRingBuffer` from `@fgv/ts-utils` (it does not
37
- * hand-roll a ring) and implements {@link IMemoryObserver} directly — `observe`
38
- * (the hook) and `query` (the read surface) live on the same class. Wire it via
39
- * {@link IFileTreeMemoryStoreCreateParams.observers}. `seq` and `timestamp` are
40
- * assigned by the firing authority (the store) before `observe`, so this store
41
- * never mints them.
42
- * @public
43
- */
44
- export class MemoryObservationStore implements IMemoryObserver {
45
- /**
46
- * The bounded ring of observed records. The firing authority assigns each
47
- * record's `seq`, so the ring's monotonic-`seq` cursor contract is satisfied
48
- * by that authority's per-instance counter.
49
- * @internal
50
- */
51
- private readonly _buffer: Collections.RetainingRingBuffer<IMemoryObservationRecord>;
52
-
53
- /**
54
- * @param buffer - The pre-constructed backing ring buffer.
55
- * @internal
56
- */
57
- private constructor(buffer: Collections.RetainingRingBuffer<IMemoryObservationRecord>) {
58
- this._buffer = buffer;
59
- }
60
-
61
- /**
62
- * The highest `seq` observed so far. Hold this value and pass it as
63
- * `sinceSeq` to {@link MemoryObservationStore.query | query} to page only
64
- * records observed afterward. Stable across ring eviction and
65
- * {@link MemoryObservationStore.clear | clear}.
66
- */
67
- public get lastSeq(): number {
68
- return this._buffer.lastSeq;
69
- }
70
-
71
- /**
72
- * The number of records currently retained.
73
- */
74
- public get size(): number {
75
- return this._buffer.size;
76
- }
77
-
78
- /**
79
- * Family-convention factory.
80
- * @param params - {@link IMemoryObservationStoreCreateParams | Construction options}.
81
- * @returns On success, a new store. Fails if `maxRecords` is supplied and is
82
- * not a positive integer.
83
- */
84
- public static create(params?: IMemoryObservationStoreCreateParams): Result<MemoryObservationStore> {
85
- const maxRecords: number | undefined = params?.maxRecords;
86
- if (maxRecords !== undefined && (!Number.isInteger(maxRecords) || maxRecords < 1)) {
87
- return fail(`MemoryObservationStore: maxRecords must be a positive integer (got ${maxRecords})`);
88
- }
89
- return succeed(
90
- new MemoryObservationStore(
91
- new Collections.RetainingRingBuffer<IMemoryObservationRecord>({ maxRecords })
92
- )
93
- );
94
- }
95
-
96
- /**
97
- * {@inheritDoc IMemoryObserver.observe}
98
- */
99
- public observe(record: IMemoryObservationRecord): Promise<Result<unknown>> {
100
- this._buffer.push(record);
101
- return Promise.resolve(succeed(record));
102
- }
103
-
104
- /**
105
- * Returns retained records, oldest-first, narrowed by the supplied criteria.
106
- * @param criteria - {@link IMemoryObservationQuery | AND-combined filter criteria}.
107
- * @returns The matching records, oldest-first.
108
- */
109
- public query(criteria?: IMemoryObservationQuery): ReadonlyArray<IMemoryObservationRecord> {
110
- return this._buffer.query({
111
- sinceSeq: criteria?.sinceSeq,
112
- limit: criteria?.limit,
113
- filter:
114
- criteria === undefined ? undefined : (record) => MemoryObservationStore._matches(record, criteria)
115
- });
116
- }
117
-
118
- /**
119
- * Clears all retained records. Does NOT reset
120
- * {@link MemoryObservationStore.lastSeq | lastSeq}, so a held `sinceSeq`
121
- * cursor never re-sees a sequence number.
122
- */
123
- public clear(): void {
124
- this._buffer.clear();
125
- }
126
-
127
- /**
128
- * Tests a record against the non-`seq`/`limit` criteria (those are applied by
129
- * the ring buffer itself).
130
- * @internal
131
- */
132
- private static _matches(record: IMemoryObservationRecord, criteria: IMemoryObservationQuery): boolean {
133
- if (criteria.since !== undefined && record.timestamp < criteria.since) {
134
- return false;
135
- }
136
- if (criteria.until !== undefined && record.timestamp > criteria.until) {
137
- return false;
138
- }
139
- if (criteria.scope !== undefined && record.scope !== criteria.scope) {
140
- return false;
141
- }
142
- if (criteria.kind !== undefined && record.kind !== criteria.kind) {
143
- return false;
144
- }
145
- if (criteria.phase !== undefined && record.phase !== criteria.phase) {
146
- return false;
147
- }
148
- if (criteria.outcome !== undefined && record.outcome !== criteria.outcome) {
149
- return false;
150
- }
151
- return true;
152
- }
153
- }
@@ -1,119 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- import { Result } from '@fgv/ts-utils';
7
- import { IProvenance, Kind, MemoryId, MemoryScopeKey } from '../types';
8
-
9
- /**
10
- * The store/retriever operation an observation record describes.
11
- *
12
- * @remarks
13
- * `'read'` / `'write'` / `'delete'` are fired post-op by
14
- * {@link FileTreeMemoryStore} (on `get` / `put` / `delete` respectively) when
15
- * observers are wired. `'retrieve'` is reserved for retriever-fired
16
- * observations; no B2 retriever fires one (a single seq authority per
17
- * observation store is the supported topology), so it never appears in B2 but
18
- * is part of the vocabulary so a future retriever-firing hook is additive.
19
- * @public
20
- */
21
- export type MemoryObservationPhase = 'read' | 'write' | 'delete' | 'retrieve';
22
-
23
- /**
24
- * The outcome of the observed operation.
25
- * @public
26
- */
27
- export type MemoryObservationOutcome = 'success' | 'failure';
28
-
29
- /**
30
- * A single audit record produced by an observed store (or retriever) operation.
31
- *
32
- * @remarks
33
- * `seq` and `timestamp` are assigned by the firing authority (the store) before
34
- * fan-out, so the same record carries the same `seq` across every observer it
35
- * lands in. `seq` is strictly increasing per authority, satisfying the
36
- * `RetainingRingBuffer` cursor contract that {@link MemoryObservationStore}
37
- * relies on.
38
- * @public
39
- */
40
- export interface IMemoryObservationRecord {
41
- /**
42
- * Monotonic 1-based sequence number assigned by the firing authority, stable
43
- * across a store's ring eviction. The ordering / paging key.
44
- */
45
- readonly seq: number;
46
- /** Milliseconds since epoch when the firing authority produced the record. */
47
- readonly timestamp: number;
48
- /** Which operation this record describes. */
49
- readonly phase: MemoryObservationPhase;
50
- /** The scope the operation touched, when resolvable. */
51
- readonly scope?: MemoryScopeKey;
52
- /** The record id the operation touched, when resolvable. */
53
- readonly id?: MemoryId;
54
- /** The kind the operation targeted, when known. */
55
- readonly kind?: Kind;
56
- /** Whether the operation succeeded. */
57
- readonly outcome: MemoryObservationOutcome;
58
- /** Present on failure: the failure `Result`'s message. */
59
- readonly error?: string;
60
- /** Structured provenance of the write, when the operation carried one. */
61
- readonly provenance?: IProvenance;
62
- /**
63
- * For `'retrieve'` observations: an opaque snapshot of the query that drove
64
- * the retrieval. Carried verbatim; never interpreted by the store.
65
- */
66
- readonly querySnapshot?: Readonly<Record<string, unknown>>;
67
- }
68
-
69
- /**
70
- * Single-method async observer hook. The store fires `observe` once per public
71
- * `get` / `put` / `delete` call when observers are wired.
72
- *
73
- * @remarks
74
- * Observer errors never affect the store operation — the store swallows a
75
- * failed `Result` or a thrown / rejected `observe`, logging it to the injected
76
- * diagnostic logger at `warn`.
77
- * @public
78
- */
79
- export interface IMemoryObserver {
80
- /**
81
- * When `true`, the store dispatches `observe` without awaiting it, so a slow
82
- * remote observer (SIEM, network sink) does not extend the store operation's
83
- * latency. Defaults to `false` (awaited), which is correct for the cheap
84
- * in-memory default {@link MemoryObservationStore}. Errors are swallowed
85
- * either way.
86
- */
87
- readonly fireAndForget?: boolean;
88
- /**
89
- * Receives a fully-formed observation record.
90
- * @param record - The observation record.
91
- * @returns A `Result` whose failure is swallowed (logged to the store's
92
- * diagnostic logger). A rejected promise is likewise swallowed.
93
- */
94
- observe(record: IMemoryObservationRecord): Promise<Result<unknown>>;
95
- }
96
-
97
- /**
98
- * Query criteria for {@link MemoryObservationStore.query}. All supplied criteria
99
- * are AND-combined.
100
- * @public
101
- */
102
- export interface IMemoryObservationQuery {
103
- /** Only records with `seq > sinceSeq` (incremental paging cursor). */
104
- readonly sinceSeq?: number;
105
- /** Return at most this many records — the most-recent N, still oldest-first. */
106
- readonly limit?: number;
107
- /** Only records with `timestamp >= since`. */
108
- readonly since?: number;
109
- /** Only records with `timestamp <= until`. */
110
- readonly until?: number;
111
- /** Only records that touched this scope. */
112
- readonly scope?: MemoryScopeKey;
113
- /** Only records that targeted this kind. */
114
- readonly kind?: Kind;
115
- /** Only records of this phase. */
116
- readonly phase?: MemoryObservationPhase;
117
- /** Only records with this outcome. */
118
- readonly outcome?: MemoryObservationOutcome;
119
- }
@@ -1,138 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- import { Result, fail, succeed } from '@fgv/ts-utils';
7
- import { IFragmentVectorIndex, IVectorQueryHit } from '../vector';
8
- import { QueryEmbedder } from './semanticRetriever';
9
-
10
- /**
11
- * The loud-degradation message a {@link FragmentSemanticRetriever} returns when a
12
- * fragment query is issued but no {@link IFragmentSemanticBackend | backend} is
13
- * wired — the discovery surface NEVER answers a fragment query with a silent empty.
14
- * @public
15
- */
16
- export const FRAGMENT_SEMANTIC_UNWIRED_MESSAGE: string =
17
- 'fragment recall: no fragment index is wired; wire an IFragmentSemanticBackend to enable sub-document search';
18
-
19
- /**
20
- * The fragment backend wired into a {@link FragmentSemanticRetriever}: the fragment
21
- * index to query and the embedder that turns the query text into a vector. Both are
22
- * required together — a fragment index is useless without a way to embed the query.
23
- * @public
24
- */
25
- export interface IFragmentSemanticBackend {
26
- /** The fragment-granular vector index to query. */
27
- readonly fragmentIndex: IFragmentVectorIndex;
28
- /** Turns the query text into a vector. */
29
- readonly embedQuery: QueryEmbedder;
30
- }
31
-
32
- /**
33
- * A sub-document semantic-search request: the natural-language `semantic` text to
34
- * match, an optional `topK` result cap (default 10), and an optional
35
- * `maxPerRecord` cap that keeps one long document from monopolizing the result.
36
- * @public
37
- */
38
- export interface IFragmentQuery {
39
- /** The natural-language text to embed and match against stored fragments. */
40
- readonly semantic: string;
41
- /** Maximum number of fragment hits to return. Defaults to 10. */
42
- readonly topK?: number;
43
- /**
44
- * Maximum number of fragments any single record may contribute to the result.
45
- * Applied during selection (before the `topK` cut). Omit for uncapped.
46
- */
47
- readonly maxPerRecord?: number;
48
- }
49
-
50
- /**
51
- * What a {@link FragmentSemanticRetriever} can do given its wiring.
52
- * @public
53
- */
54
- export interface IFragmentRetrieverCapabilities {
55
- /** `true` when a fragment backend is wired and fragment recall is operational. */
56
- readonly supportsFragmentRecall: boolean;
57
- }
58
-
59
- /**
60
- * The sub-document semantic-search retriever — the "discovery" half of a
61
- * search-then-read contract. It embeds a fragment query, queries the
62
- * {@link IFragmentVectorIndex}, and returns the raw per-fragment
63
- * {@link IVectorQueryHit | hits} (each carrying a record `target` AND whichever of
64
- * `locator` / `fragmentId` the stored fragment was indexed with), NOT resolved
65
- * records: the consumer re-reads each record and resolves the fragment on its own
66
- * read side. Note the `locator` span is advisory — see {@link IFragmentLocator}; it
67
- * is not a slice guaranteed to reproduce the fragment's text.
68
- *
69
- * @remarks
70
- * Deliberately NOT an {@link IMemoryRetriever}: memory recall is record-granular and
71
- * returns records; fragment discovery is fragment-granular and returns fragment
72
- * identities. Keeping it a distinct surface matches the consumer contract (memory
73
- * stays record-granular; sub-document knowledge uses a separate fragment index) and
74
- * avoids overloading the record retriever's return type with identity fields that
75
- * only make sense here.
76
- *
77
- * When no backend is wired, `supportsFragmentRecall` is `false` and any fragment
78
- * query degrades loudly ({@link FRAGMENT_SEMANTIC_UNWIRED_MESSAGE}) — it NEVER
79
- * returns a silent empty. A consumer-supplied backend that rejects (throws) is
80
- * normalized into a `Failure`.
81
- * @public
82
- */
83
- export class FragmentSemanticRetriever {
84
- private readonly _backend: IFragmentSemanticBackend | undefined;
85
-
86
- private constructor(backend: IFragmentSemanticBackend | undefined) {
87
- this._backend = backend;
88
- }
89
-
90
- /** What this retriever can do given its wiring. */
91
- public get capabilities(): IFragmentRetrieverCapabilities {
92
- return { supportsFragmentRecall: this._backend !== undefined };
93
- }
94
-
95
- /** Family-convention factory. */
96
- public static create(params: {
97
- readonly backend?: IFragmentSemanticBackend;
98
- }): Result<FragmentSemanticRetriever> {
99
- return succeed(new FragmentSemanticRetriever(params.backend));
100
- }
101
-
102
- /**
103
- * Embed `query.semantic`, query the fragment index, and return the per-fragment
104
- * hits in descending score order. Fails loudly when no backend is wired.
105
- */
106
- public async retrieve(query: IFragmentQuery): Promise<Result<ReadonlyArray<IVectorQueryHit>>> {
107
- if (this._backend === undefined) {
108
- return fail(FRAGMENT_SEMANTIC_UNWIRED_MESSAGE);
109
- }
110
- const backend: IFragmentSemanticBackend = this._backend;
111
- // Consumer-supplied hooks may throw; normalize both a returned `fail` and a
112
- // rejection into a single `fragment recall: <label> failed` Failure so
113
- // `retrieve` always honors its `Promise<Result<...>>` contract.
114
- const embedded: Result<Float32Array> = await FragmentSemanticRetriever._callBackend(
115
- 'query embedding',
116
- () => backend.embedQuery(query.semantic)
117
- );
118
- if (embedded.isFailure()) {
119
- return fail(embedded.message);
120
- }
121
- return FragmentSemanticRetriever._callBackend('fragment query', () =>
122
- backend.fragmentIndex.query(embedded.value, query.topK ?? 10, query.maxPerRecord)
123
- );
124
- }
125
-
126
- /**
127
- * Invoke a consumer-supplied backend hook, normalizing both a returned `fail`
128
- * and a thrown/rejected promise into a single `fragment recall: <label> failed`
129
- * `Failure`.
130
- */
131
- private static async _callBackend<T>(label: string, op: () => Promise<Result<T>>): Promise<Result<T>> {
132
- try {
133
- return (await op()).withErrorFormat((msg) => `fragment recall: ${label} failed: ${msg}`);
134
- } catch (err) {
135
- return fail(`fragment recall: ${label} failed: ${String(err)}`);
136
- }
137
- }
138
- }
@@ -1,194 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- import { Result, fail, mapResults, succeed } from '@fgv/ts-utils';
7
- import { IMemoryRecord, MemoryId } from '../types';
8
- import {
9
- IMemoryQuery,
10
- IMemoryRetriever,
11
- IMemoryRetrieverCapabilities,
12
- guardRetrieverCapabilities,
13
- limitRecords,
14
- rankCompare,
15
- recencyCompare
16
- } from './retriever';
17
-
18
- /**
19
- * Strategy for combining the result sets of the retrievers a
20
- * {@link HybridRetriever} composes. Injectable so a consumer can weight,
21
- * re-rank, or intersect instead of the default union.
22
- * @public
23
- */
24
- export interface IMergeStrategy {
25
- /**
26
- * Merge the per-retriever result sets into a single ordered result.
27
- * @param resultSets - One entry per composed retriever, in composition order.
28
- */
29
- merge(
30
- resultSets: ReadonlyArray<ReadonlyArray<IMemoryRecord<unknown>>>
31
- ): Result<ReadonlyArray<IMemoryRecord<unknown>>>;
32
- }
33
-
34
- /**
35
- * The reference {@link IMergeStrategy}: a score-union. Every record is scored by
36
- * the number of composed result sets it appears in (deduplicated by
37
- * {@link IMemoryEnvelope.id | id}); the merged result is ordered by descending
38
- * score, then by recency. Records surfaced by more retrievers rank higher.
39
- *
40
- * @remarks
41
- * Dedup is by `id` alone, which is unambiguous for the flat (one-file-per-entity)
42
- * kinds B2 ships. Phase-C versioned kinds that reuse a stem across scopes will
43
- * extend the dedup key — additive, no API change.
44
- * @public
45
- */
46
- export class ScoreUnionMergeStrategy implements IMergeStrategy {
47
- private constructor() {}
48
-
49
- /** Family-convention factory. */
50
- public static create(): Result<ScoreUnionMergeStrategy> {
51
- return succeed(new ScoreUnionMergeStrategy());
52
- }
53
-
54
- /** {@inheritDoc IMergeStrategy.merge} */
55
- public merge(
56
- resultSets: ReadonlyArray<ReadonlyArray<IMemoryRecord<unknown>>>
57
- ): Result<ReadonlyArray<IMemoryRecord<unknown>>> {
58
- const scored: Map<MemoryId, { readonly record: IMemoryRecord<unknown>; score: number }> = new Map();
59
- for (const set of resultSets) {
60
- // Count each id at most once per result set, so the score is "how many
61
- // retrievers surfaced this record" rather than "how many copies total".
62
- const seenInSet: Set<MemoryId> = new Set<MemoryId>();
63
- for (const record of set) {
64
- const id: MemoryId = record.envelope.id;
65
- if (seenInSet.has(id)) {
66
- continue;
67
- }
68
- seenInSet.add(id);
69
- const existing = scored.get(id);
70
- if (existing === undefined) {
71
- scored.set(id, { record, score: 1 });
72
- } else {
73
- existing.score += 1;
74
- }
75
- }
76
- }
77
- const merged: IMemoryRecord<unknown>[] = Array.from(scored.values())
78
- .sort((a, b) => (b.score !== a.score ? b.score - a.score : recencyCompare(a.record, b.record)))
79
- .map((entry) => entry.record);
80
- return succeed(merged);
81
- }
82
- }
83
-
84
- /**
85
- * Composes several retrievers, dispatches a query to each, and merges their
86
- * results via an injectable {@link IMergeStrategy}. Its capabilities are the
87
- * union of the composed retrievers' capabilities.
88
- *
89
- * @remarks
90
- * The hybrid enforces the loud-degradation contract against its OWN (union)
91
- * capabilities, then projects the query for each child: a child that does not
92
- * support the `semantic` (or `asOf`) axis is handed a query with that axis
93
- * stripped, so it returns its normal results instead of loud-failing on a field
94
- * a sibling handles. A child that genuinely fails (e.g. a wired semantic backend
95
- * erroring) propagates — the hybrid never silently drops a failure.
96
- * @public
97
- */
98
- export class HybridRetriever implements IMemoryRetriever {
99
- private readonly _retrievers: ReadonlyArray<IMemoryRetriever>;
100
- private readonly _mergeStrategy: IMergeStrategy;
101
- private readonly _capabilities: IMemoryRetrieverCapabilities;
102
-
103
- private constructor(
104
- retrievers: ReadonlyArray<IMemoryRetriever>,
105
- mergeStrategy: IMergeStrategy,
106
- capabilities: IMemoryRetrieverCapabilities
107
- ) {
108
- this._retrievers = retrievers;
109
- this._mergeStrategy = mergeStrategy;
110
- this._capabilities = capabilities;
111
- }
112
-
113
- /** {@inheritDoc IMemoryRetriever.capabilities} */
114
- public get capabilities(): IMemoryRetrieverCapabilities {
115
- return this._capabilities;
116
- }
117
-
118
- /**
119
- * Family-convention factory.
120
- * @param retrievers - The retrievers to compose (at least one).
121
- * @param mergeStrategy - How to combine their results.
122
- */
123
- public static create(
124
- retrievers: ReadonlyArray<IMemoryRetriever>,
125
- mergeStrategy: IMergeStrategy
126
- ): Result<HybridRetriever> {
127
- if (retrievers.length === 0) {
128
- return fail('HybridRetriever: at least one retriever is required');
129
- }
130
- // Snapshot the caller's array so a later mutation cannot make `retrieve()`
131
- // and the cached `capabilities` disagree.
132
- const stableRetrievers: ReadonlyArray<IMemoryRetriever> = [...retrievers];
133
- const capabilities: IMemoryRetrieverCapabilities = {
134
- supportsSemanticRecall: stableRetrievers.some((r) => r.capabilities.supportsSemanticRecall),
135
- supportsTemporalQuery: stableRetrievers.some((r) => r.capabilities.supportsTemporalQuery),
136
- supportsLinkTraversal: stableRetrievers.some((r) => r.capabilities.supportsLinkTraversal)
137
- };
138
- return succeed(new HybridRetriever(stableRetrievers, mergeStrategy, capabilities));
139
- }
140
-
141
- /** {@inheritDoc IMemoryRetriever.retrieve} */
142
- public async retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {
143
- return guardRetrieverCapabilities(query, this._capabilities).thenOnSuccess(async () => {
144
- const perRetriever: Result<ReadonlyArray<IMemoryRecord<unknown>>>[] = await Promise.all(
145
- this._retrievers.map((retriever) => retriever.retrieve(this._projectQuery(query, retriever)))
146
- );
147
- return mapResults(perRetriever)
148
- .onSuccess((resultSets) => this._mergeStrategy.merge(resultSets))
149
- .onSuccess((merged) => {
150
- // `orderBy: 'rank'` re-orders the merged set by rank (descending, absent
151
- // last) before the page window, so a rank-ordered hybrid query yields a
152
- // rank-ordered page. Absent / `'recency'` preserves the merge strategy's
153
- // own ordering (byte-identical to the pre-`orderBy` behavior).
154
- const ordered: ReadonlyArray<IMemoryRecord<unknown>> =
155
- query.orderBy === 'rank' ? [...merged].sort(rankCompare) : merged;
156
- return succeed(limitRecords(ordered, query.limit, query.offset));
157
- });
158
- });
159
- }
160
-
161
- /**
162
- * Project the query for one child retriever. Two adjustments:
163
- *
164
- * - Strip axes the child does not support (`semantic` / `topK` for a
165
- * non-semantic child, `asOf` for a non-temporal child, the link axes for a
166
- * non-link child) so it returns its normal results rather than loud-failing
167
- * on a field a sibling handles.
168
- * - Strip `limit` unconditionally: limit is a post-merge concern. A child that
169
- * pre-truncated its result set would starve the merge strategy of candidates
170
- * it needs to score correctly (a record both children would surface must
171
- * reach the merge to score 2). The hybrid applies `limit` once, after merge.
172
- */
173
- private _projectQuery(query: IMemoryQuery, retriever: IMemoryRetriever): IMemoryQuery {
174
- const projected: { -readonly [K in keyof IMemoryQuery]: IMemoryQuery[K] } = { ...query };
175
- delete projected.limit;
176
- // Offset, like limit, is a post-merge concern: a child that pre-skipped its
177
- // own ordered set would drop candidates the merge needs to score correctly.
178
- // The hybrid applies the `{ offset, limit }` window once, after merge.
179
- delete projected.offset;
180
- if (!retriever.capabilities.supportsSemanticRecall) {
181
- delete projected.semantic;
182
- delete projected.topK;
183
- }
184
- if (!retriever.capabilities.supportsTemporalQuery) {
185
- delete projected.asOf;
186
- }
187
- if (!retriever.capabilities.supportsLinkTraversal) {
188
- delete projected.linkedFrom;
189
- delete projected.linkedTo;
190
- delete projected.hops;
191
- }
192
- return projected;
193
- }
194
- }
@@ -1,14 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- export * from './retriever';
7
- export * from './recencyRetriever';
8
- export * from './linkTraversalRetriever';
9
- export * from './tagRetriever';
10
- export * from './structuredFilterRetriever';
11
- export * from './semanticRetriever';
12
- export * from './fragmentSemanticRetriever';
13
- export * from './temporalRetrievers';
14
- export * from './hybridRetriever';