@fgv/ts-agent-memory 5.1.0-47 → 5.1.0-49

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 (376) hide show
  1. package/dist/packlets/ingest/orchestrator.js +11 -1
  2. package/dist/packlets/ingest/orchestrator.js.map +1 -1
  3. package/dist/packlets/observe/memoryObservationStore.js +6 -0
  4. package/dist/packlets/observe/memoryObservationStore.js.map +1 -1
  5. package/dist/packlets/observe/observer.js.map +1 -1
  6. package/dist/packlets/retrieve/linkTraversalRetriever.js +1 -1
  7. package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  8. package/dist/packlets/retrieve/recencyRetriever.js +1 -1
  9. package/dist/packlets/retrieve/recencyRetriever.js.map +1 -1
  10. package/dist/packlets/retrieve/retriever.js +11 -5
  11. package/dist/packlets/retrieve/retriever.js.map +1 -1
  12. package/dist/packlets/retrieve/structuredFilterRetriever.js +27 -5
  13. package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  14. package/dist/packlets/retrieve/tagRetriever.js +1 -1
  15. package/dist/packlets/retrieve/tagRetriever.js.map +1 -1
  16. package/dist/packlets/retrieve/temporalRetrievers.js +1 -1
  17. package/dist/packlets/retrieve/temporalRetrievers.js.map +1 -1
  18. package/dist/packlets/store/fileTreeMemoryStore.js +152 -132
  19. package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
  20. package/dist/packlets/store/vectorMaintenance.js +251 -0
  21. package/dist/packlets/store/vectorMaintenance.js.map +1 -0
  22. package/dist/packlets/types/envelope.js.map +1 -1
  23. package/dist/packlets/vector/inMemoryCosineIndex.js +81 -18
  24. package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  25. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js +7 -0
  26. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
  27. package/dist/packlets/vector/vectorIndex.js.map +1 -1
  28. package/dist/ts-agent-memory.d.ts +431 -79
  29. package/lib/packlets/ingest/orchestrator.d.ts.map +1 -1
  30. package/lib/packlets/ingest/orchestrator.js +11 -1
  31. package/lib/packlets/ingest/orchestrator.js.map +1 -1
  32. package/lib/packlets/observe/memoryObservationStore.d.ts.map +1 -1
  33. package/lib/packlets/observe/memoryObservationStore.js +6 -0
  34. package/lib/packlets/observe/memoryObservationStore.js.map +1 -1
  35. package/lib/packlets/observe/observer.d.ts +61 -0
  36. package/lib/packlets/observe/observer.d.ts.map +1 -1
  37. package/lib/packlets/observe/observer.js.map +1 -1
  38. package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +1 -1
  39. package/lib/packlets/retrieve/linkTraversalRetriever.js +1 -1
  40. package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
  41. package/lib/packlets/retrieve/recencyRetriever.d.ts +1 -1
  42. package/lib/packlets/retrieve/recencyRetriever.js +1 -1
  43. package/lib/packlets/retrieve/recencyRetriever.js.map +1 -1
  44. package/lib/packlets/retrieve/retriever.d.ts +26 -7
  45. package/lib/packlets/retrieve/retriever.d.ts.map +1 -1
  46. package/lib/packlets/retrieve/retriever.js +11 -5
  47. package/lib/packlets/retrieve/retriever.js.map +1 -1
  48. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts +26 -4
  49. package/lib/packlets/retrieve/structuredFilterRetriever.d.ts.map +1 -1
  50. package/lib/packlets/retrieve/structuredFilterRetriever.js +27 -5
  51. package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
  52. package/lib/packlets/retrieve/tagRetriever.d.ts +1 -1
  53. package/lib/packlets/retrieve/tagRetriever.js +1 -1
  54. package/lib/packlets/retrieve/tagRetriever.js.map +1 -1
  55. package/lib/packlets/retrieve/temporalRetrievers.js +1 -1
  56. package/lib/packlets/retrieve/temporalRetrievers.js.map +1 -1
  57. package/lib/packlets/store/fileTreeMemoryStore.d.ts +135 -59
  58. package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
  59. package/lib/packlets/store/fileTreeMemoryStore.js +151 -131
  60. package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
  61. package/lib/packlets/store/vectorMaintenance.d.ts +149 -0
  62. package/lib/packlets/store/vectorMaintenance.d.ts.map +1 -0
  63. package/lib/packlets/store/vectorMaintenance.js +255 -0
  64. package/lib/packlets/store/vectorMaintenance.js.map +1 -0
  65. package/lib/packlets/types/envelope.d.ts +11 -0
  66. package/lib/packlets/types/envelope.d.ts.map +1 -1
  67. package/lib/packlets/types/envelope.js.map +1 -1
  68. package/lib/packlets/vector/inMemoryCosineIndex.d.ts +30 -7
  69. package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -1
  70. package/lib/packlets/vector/inMemoryCosineIndex.js +80 -17
  71. package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -1
  72. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts +7 -0
  73. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts.map +1 -1
  74. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js +7 -0
  75. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
  76. package/lib/packlets/vector/vectorIndex.d.ts +129 -1
  77. package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
  78. package/lib/packlets/vector/vectorIndex.js.map +1 -1
  79. package/package.json +17 -7
  80. package/.rush/temp/5667e36f1c0cc503a5c20a3ebff76e7b9a702d41.tar.log +0 -468
  81. package/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +0 -9
  82. package/.rush/temp/operation/build/all.log +0 -9
  83. package/.rush/temp/operation/build/log-chunks.jsonl +0 -9
  84. package/.rush/temp/operation/build/state.json +0 -3
  85. package/.rush/temp/shrinkwrap-deps.json +0 -689
  86. package/config/api-extractor.json +0 -343
  87. package/config/jest.config.json +0 -14
  88. package/config/rig.json +0 -4
  89. package/dist/test/unit/converters/antagonistRoundTrip.test.js +0 -95
  90. package/dist/test/unit/converters/antagonistRoundTrip.test.js.map +0 -1
  91. package/dist/test/unit/converters/bodyConverterRegistry.test.js +0 -72
  92. package/dist/test/unit/converters/bodyConverterRegistry.test.js.map +0 -1
  93. package/dist/test/unit/converters/envelopeConverter.test.js +0 -313
  94. package/dist/test/unit/converters/envelopeConverter.test.js.map +0 -1
  95. package/dist/test/unit/index/memoryIndex.test.js +0 -214
  96. package/dist/test/unit/index/memoryIndex.test.js.map +0 -1
  97. package/dist/test/unit/ingest/antagonistCycleAndParity.test.js +0 -277
  98. package/dist/test/unit/ingest/antagonistCycleAndParity.test.js.map +0 -1
  99. package/dist/test/unit/ingest/cycleGuard.test.js +0 -81
  100. package/dist/test/unit/ingest/cycleGuard.test.js.map +0 -1
  101. package/dist/test/unit/ingest/dedupScope.test.js +0 -434
  102. package/dist/test/unit/ingest/dedupScope.test.js.map +0 -1
  103. package/dist/test/unit/ingest/orchestrator.test.js +0 -1058
  104. package/dist/test/unit/ingest/orchestrator.test.js.map +0 -1
  105. package/dist/test/unit/observe/memoryObservationStore.test.js +0 -118
  106. package/dist/test/unit/observe/memoryObservationStore.test.js.map +0 -1
  107. package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js +0 -116
  108. package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +0 -1
  109. package/dist/test/unit/retrieve/linkTraversalRetriever.test.js +0 -257
  110. package/dist/test/unit/retrieve/linkTraversalRetriever.test.js.map +0 -1
  111. package/dist/test/unit/retrieve/retrievers.test.js +0 -768
  112. package/dist/test/unit/retrieve/retrievers.test.js.map +0 -1
  113. package/dist/test/unit/retrieve/temporalRetrievers.test.js +0 -182
  114. package/dist/test/unit/retrieve/temporalRetrievers.test.js.map +0 -1
  115. package/dist/test/unit/store/antagonistTemporalBoundary.test.js +0 -120
  116. package/dist/test/unit/store/antagonistTemporalBoundary.test.js.map +0 -1
  117. package/dist/test/unit/store/embedOnWrite.test.js +0 -317
  118. package/dist/test/unit/store/embedOnWrite.test.js.map +0 -1
  119. package/dist/test/unit/store/fileTreeMemoryStore.test.js +0 -778
  120. package/dist/test/unit/store/fileTreeMemoryStore.test.js.map +0 -1
  121. package/dist/test/unit/store/fragmentEmbedOnWrite.test.js +0 -255
  122. package/dist/test/unit/store/fragmentEmbedOnWrite.test.js.map +0 -1
  123. package/dist/test/unit/store/indexInjection.test.js +0 -432
  124. package/dist/test/unit/store/indexInjection.test.js.map +0 -1
  125. package/dist/test/unit/store/lenientOpen.test.js +0 -248
  126. package/dist/test/unit/store/lenientOpen.test.js.map +0 -1
  127. package/dist/test/unit/store/listScoped.test.js +0 -109
  128. package/dist/test/unit/store/listScoped.test.js.map +0 -1
  129. package/dist/test/unit/store/observations.test.js +0 -239
  130. package/dist/test/unit/store/observations.test.js.map +0 -1
  131. package/dist/test/unit/store/rankAxis.test.js +0 -254
  132. package/dist/test/unit/store/rankAxis.test.js.map +0 -1
  133. package/dist/test/unit/store/scopeEncoding.test.js +0 -24
  134. package/dist/test/unit/store/scopeEncoding.test.js.map +0 -1
  135. package/dist/test/unit/store/temporalStore.test.js +0 -398
  136. package/dist/test/unit/store/temporalStore.test.js.map +0 -1
  137. package/dist/test/unit/tools/memoryTools.test.js +0 -842
  138. package/dist/test/unit/tools/memoryTools.test.js.map +0 -1
  139. package/dist/test/unit/types/identityCodec.test.js +0 -187
  140. package/dist/test/unit/types/identityCodec.test.js.map +0 -1
  141. package/dist/test/unit/types/ids.test.js +0 -84
  142. package/dist/test/unit/types/ids.test.js.map +0 -1
  143. package/dist/test/unit/types/temporalCodec.test.js +0 -203
  144. package/dist/test/unit/types/temporalCodec.test.js.map +0 -1
  145. package/dist/test/unit/types/temporalPolicy.test.js +0 -83
  146. package/dist/test/unit/types/temporalPolicy.test.js.map +0 -1
  147. package/dist/test/unit/types/writePolicy.test.js +0 -331
  148. package/dist/test/unit/types/writePolicy.test.js.map +0 -1
  149. package/dist/test/unit/vector/fragmentConverters.test.js +0 -58
  150. package/dist/test/unit/vector/fragmentConverters.test.js.map +0 -1
  151. package/dist/test/unit/vector/inMemoryCosineIndex.test.js +0 -252
  152. package/dist/test/unit/vector/inMemoryCosineIndex.test.js.map +0 -1
  153. package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js +0 -362
  154. package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +0 -1
  155. package/dist/test/unit/vector/vectorIndex.test.js +0 -51
  156. package/dist/test/unit/vector/vectorIndex.test.js.map +0 -1
  157. package/eslint.config.js +0 -15
  158. package/etc/ts-agent-memory.api.md +0 -940
  159. package/lib/test/unit/converters/antagonistRoundTrip.test.d.ts +0 -10
  160. package/lib/test/unit/converters/antagonistRoundTrip.test.d.ts.map +0 -1
  161. package/lib/test/unit/converters/antagonistRoundTrip.test.js +0 -97
  162. package/lib/test/unit/converters/antagonistRoundTrip.test.js.map +0 -1
  163. package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts +0 -2
  164. package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts.map +0 -1
  165. package/lib/test/unit/converters/bodyConverterRegistry.test.js +0 -74
  166. package/lib/test/unit/converters/bodyConverterRegistry.test.js.map +0 -1
  167. package/lib/test/unit/converters/envelopeConverter.test.d.ts +0 -2
  168. package/lib/test/unit/converters/envelopeConverter.test.d.ts.map +0 -1
  169. package/lib/test/unit/converters/envelopeConverter.test.js +0 -315
  170. package/lib/test/unit/converters/envelopeConverter.test.js.map +0 -1
  171. package/lib/test/unit/index/memoryIndex.test.d.ts +0 -2
  172. package/lib/test/unit/index/memoryIndex.test.d.ts.map +0 -1
  173. package/lib/test/unit/index/memoryIndex.test.js +0 -216
  174. package/lib/test/unit/index/memoryIndex.test.js.map +0 -1
  175. package/lib/test/unit/ingest/antagonistCycleAndParity.test.d.ts +0 -9
  176. package/lib/test/unit/ingest/antagonistCycleAndParity.test.d.ts.map +0 -1
  177. package/lib/test/unit/ingest/antagonistCycleAndParity.test.js +0 -279
  178. package/lib/test/unit/ingest/antagonistCycleAndParity.test.js.map +0 -1
  179. package/lib/test/unit/ingest/cycleGuard.test.d.ts +0 -2
  180. package/lib/test/unit/ingest/cycleGuard.test.d.ts.map +0 -1
  181. package/lib/test/unit/ingest/cycleGuard.test.js +0 -83
  182. package/lib/test/unit/ingest/cycleGuard.test.js.map +0 -1
  183. package/lib/test/unit/ingest/dedupScope.test.d.ts +0 -2
  184. package/lib/test/unit/ingest/dedupScope.test.d.ts.map +0 -1
  185. package/lib/test/unit/ingest/dedupScope.test.js +0 -436
  186. package/lib/test/unit/ingest/dedupScope.test.js.map +0 -1
  187. package/lib/test/unit/ingest/orchestrator.test.d.ts +0 -2
  188. package/lib/test/unit/ingest/orchestrator.test.d.ts.map +0 -1
  189. package/lib/test/unit/ingest/orchestrator.test.js +0 -1060
  190. package/lib/test/unit/ingest/orchestrator.test.js.map +0 -1
  191. package/lib/test/unit/observe/memoryObservationStore.test.d.ts +0 -2
  192. package/lib/test/unit/observe/memoryObservationStore.test.d.ts.map +0 -1
  193. package/lib/test/unit/observe/memoryObservationStore.test.js +0 -120
  194. package/lib/test/unit/observe/memoryObservationStore.test.js.map +0 -1
  195. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts +0 -2
  196. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts.map +0 -1
  197. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js +0 -118
  198. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +0 -1
  199. package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts +0 -2
  200. package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts.map +0 -1
  201. package/lib/test/unit/retrieve/linkTraversalRetriever.test.js +0 -259
  202. package/lib/test/unit/retrieve/linkTraversalRetriever.test.js.map +0 -1
  203. package/lib/test/unit/retrieve/retrievers.test.d.ts +0 -2
  204. package/lib/test/unit/retrieve/retrievers.test.d.ts.map +0 -1
  205. package/lib/test/unit/retrieve/retrievers.test.js +0 -770
  206. package/lib/test/unit/retrieve/retrievers.test.js.map +0 -1
  207. package/lib/test/unit/retrieve/temporalRetrievers.test.d.ts +0 -2
  208. package/lib/test/unit/retrieve/temporalRetrievers.test.d.ts.map +0 -1
  209. package/lib/test/unit/retrieve/temporalRetrievers.test.js +0 -184
  210. package/lib/test/unit/retrieve/temporalRetrievers.test.js.map +0 -1
  211. package/lib/test/unit/store/antagonistTemporalBoundary.test.d.ts +0 -9
  212. package/lib/test/unit/store/antagonistTemporalBoundary.test.d.ts.map +0 -1
  213. package/lib/test/unit/store/antagonistTemporalBoundary.test.js +0 -122
  214. package/lib/test/unit/store/antagonistTemporalBoundary.test.js.map +0 -1
  215. package/lib/test/unit/store/embedOnWrite.test.d.ts +0 -2
  216. package/lib/test/unit/store/embedOnWrite.test.d.ts.map +0 -1
  217. package/lib/test/unit/store/embedOnWrite.test.js +0 -319
  218. package/lib/test/unit/store/embedOnWrite.test.js.map +0 -1
  219. package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts +0 -2
  220. package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts.map +0 -1
  221. package/lib/test/unit/store/fileTreeMemoryStore.test.js +0 -780
  222. package/lib/test/unit/store/fileTreeMemoryStore.test.js.map +0 -1
  223. package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts +0 -2
  224. package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts.map +0 -1
  225. package/lib/test/unit/store/fragmentEmbedOnWrite.test.js +0 -257
  226. package/lib/test/unit/store/fragmentEmbedOnWrite.test.js.map +0 -1
  227. package/lib/test/unit/store/indexInjection.test.d.ts +0 -2
  228. package/lib/test/unit/store/indexInjection.test.d.ts.map +0 -1
  229. package/lib/test/unit/store/indexInjection.test.js +0 -434
  230. package/lib/test/unit/store/indexInjection.test.js.map +0 -1
  231. package/lib/test/unit/store/lenientOpen.test.d.ts +0 -2
  232. package/lib/test/unit/store/lenientOpen.test.d.ts.map +0 -1
  233. package/lib/test/unit/store/lenientOpen.test.js +0 -250
  234. package/lib/test/unit/store/lenientOpen.test.js.map +0 -1
  235. package/lib/test/unit/store/listScoped.test.d.ts +0 -2
  236. package/lib/test/unit/store/listScoped.test.d.ts.map +0 -1
  237. package/lib/test/unit/store/listScoped.test.js +0 -111
  238. package/lib/test/unit/store/listScoped.test.js.map +0 -1
  239. package/lib/test/unit/store/observations.test.d.ts +0 -2
  240. package/lib/test/unit/store/observations.test.d.ts.map +0 -1
  241. package/lib/test/unit/store/observations.test.js +0 -241
  242. package/lib/test/unit/store/observations.test.js.map +0 -1
  243. package/lib/test/unit/store/rankAxis.test.d.ts +0 -2
  244. package/lib/test/unit/store/rankAxis.test.d.ts.map +0 -1
  245. package/lib/test/unit/store/rankAxis.test.js +0 -256
  246. package/lib/test/unit/store/rankAxis.test.js.map +0 -1
  247. package/lib/test/unit/store/scopeEncoding.test.d.ts +0 -2
  248. package/lib/test/unit/store/scopeEncoding.test.d.ts.map +0 -1
  249. package/lib/test/unit/store/scopeEncoding.test.js +0 -26
  250. package/lib/test/unit/store/scopeEncoding.test.js.map +0 -1
  251. package/lib/test/unit/store/temporalStore.test.d.ts +0 -2
  252. package/lib/test/unit/store/temporalStore.test.d.ts.map +0 -1
  253. package/lib/test/unit/store/temporalStore.test.js +0 -400
  254. package/lib/test/unit/store/temporalStore.test.js.map +0 -1
  255. package/lib/test/unit/tools/memoryTools.test.d.ts +0 -2
  256. package/lib/test/unit/tools/memoryTools.test.d.ts.map +0 -1
  257. package/lib/test/unit/tools/memoryTools.test.js +0 -844
  258. package/lib/test/unit/tools/memoryTools.test.js.map +0 -1
  259. package/lib/test/unit/types/identityCodec.test.d.ts +0 -2
  260. package/lib/test/unit/types/identityCodec.test.d.ts.map +0 -1
  261. package/lib/test/unit/types/identityCodec.test.js +0 -189
  262. package/lib/test/unit/types/identityCodec.test.js.map +0 -1
  263. package/lib/test/unit/types/ids.test.d.ts +0 -2
  264. package/lib/test/unit/types/ids.test.d.ts.map +0 -1
  265. package/lib/test/unit/types/ids.test.js +0 -86
  266. package/lib/test/unit/types/ids.test.js.map +0 -1
  267. package/lib/test/unit/types/temporalCodec.test.d.ts +0 -2
  268. package/lib/test/unit/types/temporalCodec.test.d.ts.map +0 -1
  269. package/lib/test/unit/types/temporalCodec.test.js +0 -205
  270. package/lib/test/unit/types/temporalCodec.test.js.map +0 -1
  271. package/lib/test/unit/types/temporalPolicy.test.d.ts +0 -2
  272. package/lib/test/unit/types/temporalPolicy.test.d.ts.map +0 -1
  273. package/lib/test/unit/types/temporalPolicy.test.js +0 -85
  274. package/lib/test/unit/types/temporalPolicy.test.js.map +0 -1
  275. package/lib/test/unit/types/writePolicy.test.d.ts +0 -2
  276. package/lib/test/unit/types/writePolicy.test.d.ts.map +0 -1
  277. package/lib/test/unit/types/writePolicy.test.js +0 -333
  278. package/lib/test/unit/types/writePolicy.test.js.map +0 -1
  279. package/lib/test/unit/vector/fragmentConverters.test.d.ts +0 -2
  280. package/lib/test/unit/vector/fragmentConverters.test.d.ts.map +0 -1
  281. package/lib/test/unit/vector/fragmentConverters.test.js +0 -60
  282. package/lib/test/unit/vector/fragmentConverters.test.js.map +0 -1
  283. package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts +0 -2
  284. package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts.map +0 -1
  285. package/lib/test/unit/vector/inMemoryCosineIndex.test.js +0 -254
  286. package/lib/test/unit/vector/inMemoryCosineIndex.test.js.map +0 -1
  287. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts +0 -2
  288. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts.map +0 -1
  289. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js +0 -364
  290. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +0 -1
  291. package/lib/test/unit/vector/vectorIndex.test.d.ts +0 -2
  292. package/lib/test/unit/vector/vectorIndex.test.d.ts.map +0 -1
  293. package/lib/test/unit/vector/vectorIndex.test.js +0 -53
  294. package/lib/test/unit/vector/vectorIndex.test.js.map +0 -1
  295. package/rush-logs/ts-agent-memory.build.cache.log +0 -3
  296. package/rush-logs/ts-agent-memory.build.log +0 -9
  297. package/src/index.ts +0 -14
  298. package/src/packlets/converters/bodyConverterRegistry.ts +0 -105
  299. package/src/packlets/converters/envelopeConverter.ts +0 -233
  300. package/src/packlets/converters/index.ts +0 -7
  301. package/src/packlets/index/index.ts +0 -6
  302. package/src/packlets/index/memoryIndex.ts +0 -332
  303. package/src/packlets/ingest/cycleGuard.ts +0 -153
  304. package/src/packlets/ingest/hostStages.ts +0 -111
  305. package/src/packlets/ingest/index.ts +0 -9
  306. package/src/packlets/ingest/model.ts +0 -195
  307. package/src/packlets/ingest/orchestrator.ts +0 -968
  308. package/src/packlets/observe/index.ts +0 -7
  309. package/src/packlets/observe/memoryObservationStore.ts +0 -153
  310. package/src/packlets/observe/observer.ts +0 -119
  311. package/src/packlets/retrieve/fragmentSemanticRetriever.ts +0 -138
  312. package/src/packlets/retrieve/hybridRetriever.ts +0 -194
  313. package/src/packlets/retrieve/index.ts +0 -14
  314. package/src/packlets/retrieve/linkTraversalRetriever.ts +0 -158
  315. package/src/packlets/retrieve/recencyRetriever.ts +0 -54
  316. package/src/packlets/retrieve/retriever.ts +0 -291
  317. package/src/packlets/retrieve/semanticRetriever.ts +0 -152
  318. package/src/packlets/retrieve/structuredFilterRetriever.ts +0 -58
  319. package/src/packlets/retrieve/tagRetriever.ts +0 -58
  320. package/src/packlets/retrieve/temporalRetrievers.ts +0 -210
  321. package/src/packlets/store/fileTreeMemoryStore.ts +0 -1872
  322. package/src/packlets/store/index.ts +0 -7
  323. package/src/packlets/store/scopeEncoding.ts +0 -36
  324. package/src/packlets/tools/index.ts +0 -6
  325. package/src/packlets/tools/memoryTools.ts +0 -706
  326. package/src/packlets/types/envelope.ts +0 -196
  327. package/src/packlets/types/filenameSafety.ts +0 -57
  328. package/src/packlets/types/identityCodec.ts +0 -447
  329. package/src/packlets/types/ids.ts +0 -124
  330. package/src/packlets/types/index.ts +0 -11
  331. package/src/packlets/types/temporal.ts +0 -96
  332. package/src/packlets/types/writePolicy.ts +0 -612
  333. package/src/packlets/vector/fragmentConverters.ts +0 -55
  334. package/src/packlets/vector/inMemoryCosineIndex.ts +0 -196
  335. package/src/packlets/vector/inMemoryFragmentCosineIndex.ts +0 -289
  336. package/src/packlets/vector/index.ts +0 -9
  337. package/src/packlets/vector/vectorIndex.ts +0 -273
  338. package/src/test/unit/converters/antagonistRoundTrip.test.ts +0 -110
  339. package/src/test/unit/converters/bodyConverterRegistry.test.ts +0 -89
  340. package/src/test/unit/converters/envelopeConverter.test.ts +0 -418
  341. package/src/test/unit/index/memoryIndex.test.ts +0 -272
  342. package/src/test/unit/ingest/antagonistCycleAndParity.test.ts +0 -367
  343. package/src/test/unit/ingest/cycleGuard.test.ts +0 -110
  344. package/src/test/unit/ingest/dedupScope.test.ts +0 -542
  345. package/src/test/unit/ingest/orchestrator.test.ts +0 -1355
  346. package/src/test/unit/observe/memoryObservationStore.test.ts +0 -158
  347. package/src/test/unit/retrieve/fragmentSemanticRetriever.test.ts +0 -163
  348. package/src/test/unit/retrieve/linkTraversalRetriever.test.ts +0 -329
  349. package/src/test/unit/retrieve/retrievers.test.ts +0 -1018
  350. package/src/test/unit/retrieve/temporalRetrievers.test.ts +0 -226
  351. package/src/test/unit/store/antagonistTemporalBoundary.test.ts +0 -158
  352. package/src/test/unit/store/embedOnWrite.test.ts +0 -418
  353. package/src/test/unit/store/fileTreeMemoryStore.test.ts +0 -1041
  354. package/src/test/unit/store/fragmentEmbedOnWrite.test.ts +0 -349
  355. package/src/test/unit/store/indexInjection.test.ts +0 -550
  356. package/src/test/unit/store/lenientOpen.test.ts +0 -292
  357. package/src/test/unit/store/listScoped.test.ts +0 -138
  358. package/src/test/unit/store/observations.test.ts +0 -290
  359. package/src/test/unit/store/rankAxis.test.ts +0 -349
  360. package/src/test/unit/store/scopeEncoding.test.ts +0 -37
  361. package/src/test/unit/store/temporalStore.test.ts +0 -469
  362. package/src/test/unit/tools/memoryTools.test.ts +0 -1121
  363. package/src/test/unit/types/identityCodec.test.ts +0 -266
  364. package/src/test/unit/types/ids.test.ts +0 -94
  365. package/src/test/unit/types/temporalCodec.test.ts +0 -259
  366. package/src/test/unit/types/temporalPolicy.test.ts +0 -124
  367. package/src/test/unit/types/writePolicy.test.ts +0 -446
  368. package/src/test/unit/vector/fragmentConverters.test.ts +0 -80
  369. package/src/test/unit/vector/inMemoryCosineIndex.test.ts +0 -318
  370. package/src/test/unit/vector/inMemoryFragmentCosineIndex.test.ts +0 -477
  371. package/src/test/unit/vector/vectorIndex.test.ts +0 -64
  372. package/temp/build/lint/_eslint-5eVG3S6w.json +0 -306
  373. package/temp/build/typescript/ts_8nwakTlr.json +0 -1
  374. package/temp/ts-agent-memory.api.json +0 -21030
  375. package/temp/ts-agent-memory.api.md +0 -940
  376. package/tsconfig.json +0 -8
@@ -1,770 +0,0 @@
1
- "use strict";
2
- /*
3
- * Copyright (c) 2026 Erik Fortune
4
- * SPDX-License-Identifier: MIT
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- require("@fgv/ts-utils-jest");
8
- const ts_utils_1 = require("@fgv/ts-utils");
9
- const index_1 = require("../../../index");
10
- /** A scope-qualified link-traversal seed for the retriever tests. */
11
- function et(id, scope = 'knowledge') {
12
- return { scope: scope, id: id };
13
- }
14
- function makeEntry(spec) {
15
- var _a, _b, _c, _d, _e;
16
- const record = {
17
- envelope: index_1.envelopeConverter
18
- .convert(Object.assign(Object.assign({ id: spec.id, entityId: spec.id, kind: (_a = spec.kind) !== null && _a !== void 0 ? _a : 'knowledge', tags: (_b = spec.tags) !== null && _b !== void 0 ? _b : [], links: [], created: 0, updated: (_c = spec.updated) !== null && _c !== void 0 ? _c : 0, seq: (_d = spec.seq) !== null && _d !== void 0 ? _d : 0, contentHash: 'h' }, (spec.rank !== undefined ? { rank: spec.rank } : {})), { provenance: { source: 'agent' } }))
19
- .orThrow(),
20
- body: `body-${spec.id}`
21
- };
22
- return { scope: ((_e = spec.scope) !== null && _e !== void 0 ? _e : 'knowledge'), record };
23
- }
24
- function buildIndex(specs) {
25
- const index = index_1.MemoryIndex.create().orThrow();
26
- index.rebuild(specs.map(makeEntry)).orThrow();
27
- return index;
28
- }
29
- function ids(records) {
30
- return records.map((r) => r.envelope.id);
31
- }
32
- const knowledge = 'knowledge';
33
- describe('retrieve helpers', () => {
34
- describe('guardRetrieverCapabilities', () => {
35
- const noCaps = {
36
- supportsSemanticRecall: false,
37
- supportsTemporalQuery: false,
38
- supportsLinkTraversal: false
39
- };
40
- test('passes when no unsupported capability is requested', () => {
41
- expect((0, index_1.guardRetrieverCapabilities)({}, noCaps)).toSucceed();
42
- });
43
- test('fails loudly when semantic recall is requested but unsupported', () => {
44
- expect((0, index_1.guardRetrieverCapabilities)({ semantic: 'q' }, noCaps)).toFailWith(/semantic recall requires a vector index; none configured/i);
45
- });
46
- test('fails loudly when an as-of query is requested but unsupported', () => {
47
- expect((0, index_1.guardRetrieverCapabilities)({ asOf: 5 }, noCaps)).toFailWith(/temporal query requires temporal index; none configured/i);
48
- });
49
- test('names the kind in the temporal failure when present', () => {
50
- expect((0, index_1.guardRetrieverCapabilities)({ asOf: 5, kind: knowledge }, noCaps)).toFailWith(/none configured for kind knowledge/i);
51
- });
52
- test('fails loudly when a link-traversal axis is requested but unsupported', () => {
53
- expect((0, index_1.guardRetrieverCapabilities)({ linkedTo: et('x') }, noCaps)).toFailWith(/link traversal requires a backlink index; none configured/i);
54
- expect((0, index_1.guardRetrieverCapabilities)({ linkedFrom: et('x') }, noCaps)).toFailWith(/link traversal requires/i);
55
- expect((0, index_1.guardRetrieverCapabilities)({ hops: 2 }, noCaps)).toFailWith(/link traversal requires/i);
56
- });
57
- test('passes a link-traversal axis when the capability is supported', () => {
58
- expect((0, index_1.guardRetrieverCapabilities)({ linkedTo: et('x') }, Object.assign(Object.assign({}, noCaps), { supportsLinkTraversal: true }))).toSucceed();
59
- });
60
- });
61
- describe('limitRecords', () => {
62
- const records = buildIndex([{ id: 'a' }, { id: 'b' }, { id: 'c' }])
63
- .entries()
64
- .map((e) => e.record);
65
- test('returns all records when no limit is supplied', () => {
66
- expect((0, index_1.limitRecords)(records)).toHaveLength(3);
67
- });
68
- test('truncates to the top-N for a positive limit', () => {
69
- expect((0, index_1.limitRecords)(records, 2)).toHaveLength(2);
70
- });
71
- test('returns an empty array for a zero or negative limit', () => {
72
- expect((0, index_1.limitRecords)(records, 0)).toEqual([]);
73
- expect((0, index_1.limitRecords)(records, -1)).toEqual([]);
74
- });
75
- test('an absent offset is a no-op (byte-identical to today) — same reference returned', () => {
76
- expect((0, index_1.limitRecords)(records, undefined, undefined)).toBe(records);
77
- expect((0, index_1.limitRecords)(records, 2, undefined)).toHaveLength(2);
78
- // A non-positive offset is guarded like a non-positive limit — no skip.
79
- expect((0, index_1.limitRecords)(records, undefined, 0)).toBe(records);
80
- expect(ids((0, index_1.limitRecords)(records, undefined, -5))).toEqual(['a', 'b', 'c']);
81
- });
82
- test('offset skips after ordering; { offset, limit } is a stable page window', () => {
83
- expect(ids((0, index_1.limitRecords)(records, undefined, 1))).toEqual(['b', 'c']);
84
- expect(ids((0, index_1.limitRecords)(records, 1, 1))).toEqual(['b']);
85
- expect(ids((0, index_1.limitRecords)(records, 2, 1))).toEqual(['b', 'c']);
86
- });
87
- test('an offset past the end yields an empty page (never a throw)', () => {
88
- expect((0, index_1.limitRecords)(records, undefined, 3)).toEqual([]);
89
- expect((0, index_1.limitRecords)(records, 5, 99)).toEqual([]);
90
- });
91
- test('a non-positive limit still wins over an offset window', () => {
92
- expect((0, index_1.limitRecords)(records, 0, 1)).toEqual([]);
93
- });
94
- });
95
- });
96
- describe('RecencyRetriever', () => {
97
- test('reports all-false capabilities', () => {
98
- const r = index_1.RecencyRetriever.create(buildIndex([])).orThrow();
99
- expect(r.capabilities).toEqual({
100
- supportsSemanticRecall: false,
101
- supportsTemporalQuery: false,
102
- supportsLinkTraversal: false
103
- });
104
- });
105
- test('returns every record most-recently-updated first', async () => {
106
- const r = index_1.RecencyRetriever.create(buildIndex([
107
- { id: 'a', updated: 10 },
108
- { id: 'b', updated: 30 },
109
- { id: 'c', updated: 20 }
110
- ])).orThrow();
111
- expect(await r.retrieve({})).toSucceedAndSatisfy((records) => {
112
- expect(ids(records)).toEqual(['b', 'c', 'a']);
113
- });
114
- });
115
- test('breaks ties on seq descending', async () => {
116
- const r = index_1.RecencyRetriever.create(buildIndex([
117
- { id: 'a', updated: 10, seq: 1 },
118
- { id: 'b', updated: 10, seq: 3 },
119
- { id: 'c', updated: 10, seq: 2 }
120
- ])).orThrow();
121
- expect(await r.retrieve({})).toSucceedAndSatisfy((records) => {
122
- expect(ids(records)).toEqual(['b', 'c', 'a']);
123
- });
124
- });
125
- test('honors scope, kind, tag, predicate, and limit filters', async () => {
126
- const index = buildIndex([
127
- { id: 'a', scope: 'knowledge', kind: 'knowledge', tags: ['x'], updated: 50 },
128
- { id: 'b', scope: 'knowledge', kind: 'knowledge', tags: ['y'], updated: 40 },
129
- { id: 'c', scope: 'other', kind: 'knowledge', tags: ['x'], updated: 60 },
130
- { id: 'd', scope: 'knowledge', kind: 'note', tags: ['x'], updated: 70 }
131
- ]);
132
- const r = index_1.RecencyRetriever.create(index).orThrow();
133
- expect(await r.retrieve({
134
- scope: 'knowledge',
135
- kind: knowledge,
136
- tag: 'x',
137
- filter: (rec) => rec.envelope.id !== 'skip',
138
- limit: 5
139
- })).toSucceedAndSatisfy((records) => {
140
- expect(ids(records)).toEqual(['a']);
141
- });
142
- });
143
- test('limit truncates to the top-N after ordering', async () => {
144
- const r = index_1.RecencyRetriever.create(buildIndex([
145
- { id: 'a', updated: 10 },
146
- { id: 'b', updated: 30 },
147
- { id: 'c', updated: 20 }
148
- ])).orThrow();
149
- expect(await r.retrieve({ limit: 2 })).toSucceedAndSatisfy((records) => {
150
- expect(ids(records)).toEqual(['b', 'c']);
151
- });
152
- });
153
- test('degrades loudly on a semantic request', async () => {
154
- const r = index_1.RecencyRetriever.create(buildIndex([{ id: 'a' }])).orThrow();
155
- expect(await r.retrieve({ semantic: 'hello' })).toFailWith(/semantic recall requires a vector index/i);
156
- });
157
- test('degrades loudly on a link-traversal request', async () => {
158
- const r = index_1.RecencyRetriever.create(buildIndex([{ id: 'a' }])).orThrow();
159
- expect(await r.retrieve({ linkedTo: et('a') })).toFailWith(/link traversal requires/i);
160
- });
161
- });
162
- describe('orderBy: rank axis', () => {
163
- const a1 = makeEntry({ id: 'a', rank: 1, updated: 100, seq: 1 }).record;
164
- const b3 = makeEntry({ id: 'b', rank: 3, updated: 100, seq: 2 }).record;
165
- const c2 = makeEntry({ id: 'c', rank: 2, updated: 100, seq: 3 }).record;
166
- const unranked = makeEntry({ id: 'z', updated: 999, seq: 4 }).record;
167
- describe('rankCompare', () => {
168
- test('orders by rank descending', () => {
169
- expect([a1, b3, c2]
170
- .slice()
171
- .sort(index_1.rankCompare)
172
- .map((r) => r.envelope.id)).toEqual(['b', 'c', 'a']);
173
- });
174
- test('places an absent-rank record last regardless of recency', () => {
175
- // `unranked` has the newest `updated`, but an absent rank sorts after every ranked record.
176
- expect([unranked, a1, b3]
177
- .slice()
178
- .sort(index_1.rankCompare)
179
- .map((r) => r.envelope.id)).toEqual(['b', 'a', 'z']);
180
- // Symmetric: absent on the left side of the compare too.
181
- expect([a1, unranked]
182
- .slice()
183
- .sort(index_1.rankCompare)
184
- .map((r) => r.envelope.id)).toEqual(['a', 'z']);
185
- });
186
- test('breaks an equal-rank tie by recency', () => {
187
- const b3b = makeEntry({ id: 'b2', rank: 3, updated: 50, seq: 9 }).record;
188
- // Equal rank 3 → newer `updated` (b3 at 100) first.
189
- expect([b3b, b3]
190
- .slice()
191
- .sort(index_1.rankCompare)
192
- .map((r) => r.envelope.id)).toEqual(['b', 'b2']);
193
- });
194
- });
195
- describe('orderingCompare', () => {
196
- test("returns recencyCompare for absent orderBy and 'recency'", () => {
197
- expect((0, index_1.orderingCompare)()).toBe(index_1.recencyCompare);
198
- expect((0, index_1.orderingCompare)('recency')).toBe(index_1.recencyCompare);
199
- });
200
- test("returns rankCompare for 'rank'", () => {
201
- expect((0, index_1.orderingCompare)('rank')).toBe(index_1.rankCompare);
202
- });
203
- });
204
- describe.each([
205
- ['RecencyRetriever', (index) => index_1.RecencyRetriever.create(index).orThrow()],
206
- ['TagRetriever', (index) => index_1.TagRetriever.create(index).orThrow()],
207
- [
208
- 'StructuredFilterRetriever',
209
- (index) => index_1.StructuredFilterRetriever.create(index).orThrow()
210
- ]
211
- ])('%s honors orderBy', (name, make) => {
212
- // Tag / structured-filter need their axis present to return anything.
213
- const axis = name === 'TagRetriever'
214
- ? { tag: 'x' }
215
- : name === 'StructuredFilterRetriever'
216
- ? { filter: () => true }
217
- : {};
218
- function orderedIndex() {
219
- return buildIndex([
220
- { id: 'a', rank: 1, tags: ['x'], updated: 100, seq: 1 },
221
- { id: 'b', rank: 3, tags: ['x'], updated: 100, seq: 2 },
222
- { id: 'c', rank: 2, tags: ['x'], updated: 100, seq: 3 },
223
- { id: 'z', tags: ['x'], updated: 999, seq: 4 }
224
- ]);
225
- }
226
- test("orderBy 'rank' orders by rank descending, absent last", async () => {
227
- const r = make(orderedIndex());
228
- expect(await r.retrieve(Object.assign(Object.assign({}, axis), { orderBy: 'rank' }))).toSucceedAndSatisfy((records) => {
229
- expect(ids(records)).toEqual(['b', 'c', 'a', 'z']);
230
- });
231
- });
232
- test('orderBy absent is unchanged recency order', async () => {
233
- const r = make(orderedIndex());
234
- expect(await r.retrieve(Object.assign({}, axis))).toSucceedAndSatisfy((records) => {
235
- // `z` has the newest `updated`; the rest tie on `updated` and break by
236
- // seq descending (c=3, b=2, a=1) — recency order regardless of rank.
237
- expect(ids(records)).toEqual(['z', 'c', 'b', 'a']);
238
- });
239
- });
240
- test('rank ordering composes with { limit, offset } for a bounded top-M page', async () => {
241
- const r = make(orderedIndex());
242
- expect(await r.retrieve(Object.assign(Object.assign({}, axis), { orderBy: 'rank', limit: 1, offset: 1 }))).toSucceedAndSatisfy((records) => {
243
- expect(ids(records)).toEqual(['c']);
244
- });
245
- });
246
- });
247
- test("HybridRetriever re-orders the merged set by rank for orderBy 'rank'", async () => {
248
- const index = buildIndex([
249
- { id: 'a', rank: 1, tags: ['x'], updated: 100, seq: 1 },
250
- { id: 'b', rank: 3, tags: ['x'], updated: 100, seq: 2 },
251
- { id: 'c', rank: 2, tags: ['x'], updated: 100, seq: 3 }
252
- ]);
253
- const hybrid = index_1.HybridRetriever.create([index_1.RecencyRetriever.create(index).orThrow(), index_1.TagRetriever.create(index).orThrow()], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
254
- expect(await hybrid.retrieve({ tag: 'x', orderBy: 'rank' })).toSucceedAndSatisfy((records) => {
255
- // All three score 2 (surfaced by both children); orderBy rank re-sorts the merge.
256
- expect(ids(records)).toEqual(['b', 'c', 'a']);
257
- });
258
- });
259
- test("SemanticRetriever preserves vector-similarity order regardless of orderBy 'rank'", async () => {
260
- const index = buildIndex([
261
- { id: 'a', rank: 9, updated: 1 },
262
- { id: 'b', rank: 1, updated: 1 }
263
- ]);
264
- const vectorIndex = {
265
- add: (t) => Promise.resolve((0, ts_utils_1.succeed)(`ref-${t.id}`)),
266
- remove: (t) => Promise.resolve((0, ts_utils_1.succeed)(t)),
267
- query: () => Promise.resolve((0, ts_utils_1.succeed)([
268
- { target: et('b'), score: 0.9 },
269
- { target: et('a'), score: 0.5 }
270
- ]))
271
- };
272
- const r = index_1.SemanticRetriever.create({
273
- index,
274
- backend: {
275
- vectorIndex,
276
- embedQuery: () => Promise.resolve((0, ts_utils_1.succeed)(Float32Array.from([0.1])))
277
- }
278
- }).orThrow();
279
- // Even though `a` has the higher rank, semantic keeps the similarity order (b before a).
280
- expect(await r.retrieve({ semantic: 'q', orderBy: 'rank' })).toSucceedAndSatisfy((records) => {
281
- expect(ids(records)).toEqual(['b', 'a']);
282
- });
283
- });
284
- });
285
- describe('query axes: kinds (kind-set) and offset', () => {
286
- function multiKindRetriever() {
287
- return index_1.RecencyRetriever.create(buildIndex([
288
- { id: 'k1', kind: 'knowledge', updated: 40 },
289
- { id: 'n1', kind: 'note', updated: 30 },
290
- { id: 'e1', kind: 'event', updated: 20 },
291
- { id: 'k2', kind: 'knowledge', updated: 10 }
292
- ])).orThrow();
293
- }
294
- describe('kinds', () => {
295
- test("an absent kinds axis imposes no kind constraint (today's behavior)", async () => {
296
- expect(await multiKindRetriever().retrieve({})).toSucceedAndSatisfy((records) => {
297
- expect([...ids(records)].sort()).toEqual(['e1', 'k1', 'k2', 'n1']);
298
- });
299
- });
300
- test('restricts to records in ANY of the listed kinds', async () => {
301
- expect(await multiKindRetriever().retrieve({
302
- kinds: ['knowledge', 'event']
303
- })).toSucceedAndSatisfy((records) => {
304
- expect([...ids(records)].sort()).toEqual(['e1', 'k1', 'k2']);
305
- });
306
- });
307
- test('an explicit empty kinds array matches NOTHING (not match-all)', async () => {
308
- expect(await multiKindRetriever().retrieve({ kinds: [] })).toSucceedWith([]);
309
- });
310
- test('kind and kinds compose as AND (kind must be a member of kinds)', async () => {
311
- // kind=knowledge AND kinds includes knowledge → knowledge records only.
312
- expect(await multiKindRetriever().retrieve({
313
- kind: knowledge,
314
- kinds: ['knowledge', 'note']
315
- })).toSucceedAndSatisfy((records) => {
316
- expect([...ids(records)].sort()).toEqual(['k1', 'k2']);
317
- });
318
- // kind=knowledge but kinds excludes knowledge → nothing can satisfy both.
319
- expect(await multiKindRetriever().retrieve({
320
- kind: knowledge,
321
- kinds: ['note', 'event']
322
- })).toSucceedWith([]);
323
- });
324
- });
325
- describe('offset', () => {
326
- function ordered() {
327
- return index_1.RecencyRetriever.create(buildIndex([
328
- { id: 'a', updated: 10 },
329
- { id: 'b', updated: 40 },
330
- { id: 'c', updated: 30 },
331
- { id: 'd', updated: 20 }
332
- ])).orThrow();
333
- }
334
- test('skips after ordering, forming a stable { offset, limit } page window', async () => {
335
- // Recency order is [b, c, d, a].
336
- expect(await ordered().retrieve({ offset: 1, limit: 2 })).toSucceedAndSatisfy((records) => {
337
- expect(ids(records)).toEqual(['c', 'd']);
338
- });
339
- });
340
- test('an absent offset is unchanged from today', async () => {
341
- expect(await ordered().retrieve({ limit: 2 })).toSucceedAndSatisfy((records) => {
342
- expect(ids(records)).toEqual(['b', 'c']);
343
- });
344
- });
345
- test('an offset past the end yields an empty page', async () => {
346
- expect(await ordered().retrieve({ offset: 99 })).toSucceedWith([]);
347
- });
348
- test('a negative offset does not slip into slice (treated as no skip)', async () => {
349
- expect(await ordered().retrieve({ offset: -3, limit: 2 })).toSucceedAndSatisfy((records) => {
350
- expect(ids(records)).toEqual(['b', 'c']);
351
- });
352
- });
353
- });
354
- });
355
- /** A retriever with configurable capabilities that records the query it received. */
356
- class RecordingRetriever {
357
- constructor(capabilities) {
358
- this.capabilities = capabilities;
359
- }
360
- retrieve(query) {
361
- this.lastQuery = query;
362
- return Promise.resolve((0, ts_utils_1.succeed)([]));
363
- }
364
- }
365
- describe('TagRetriever', () => {
366
- test('returns records carrying the tag, recency-ordered', async () => {
367
- const r = index_1.TagRetriever.create(buildIndex([
368
- { id: 'a', tags: ['x'], updated: 10 },
369
- { id: 'b', tags: ['x', 'y'], updated: 30 },
370
- { id: 'c', tags: ['y'], updated: 20 }
371
- ])).orThrow();
372
- expect(await r.retrieve({ tag: 'x' })).toSucceedAndSatisfy((records) => {
373
- expect(ids(records)).toEqual(['b', 'a']);
374
- });
375
- });
376
- test('returns empty (not failure) when no tag is supplied', async () => {
377
- const r = index_1.TagRetriever.create(buildIndex([{ id: 'a', tags: ['x'] }])).orThrow();
378
- expect(await r.retrieve({})).toSucceedWith([]);
379
- });
380
- test('degrades loudly on a semantic request', async () => {
381
- const r = index_1.TagRetriever.create(buildIndex([{ id: 'a', tags: ['x'] }])).orThrow();
382
- expect(await r.retrieve({ tag: 'x', semantic: 'q' })).toFailWith(/semantic recall requires/i);
383
- });
384
- });
385
- describe('StructuredFilterRetriever', () => {
386
- test('applies the predicate over the scope/kind/tag pre-filter', async () => {
387
- const r = index_1.StructuredFilterRetriever.create(buildIndex([
388
- { id: 'keep-1', updated: 10 },
389
- { id: 'drop-1', updated: 30 },
390
- { id: 'keep-2', updated: 20 }
391
- ])).orThrow();
392
- expect(await r.retrieve({ filter: (rec) => rec.envelope.id.startsWith('keep') })).toSucceedAndSatisfy((records) => {
393
- expect(ids(records)).toEqual(['keep-2', 'keep-1']);
394
- });
395
- });
396
- test('returns empty (not failure) when no predicate is supplied', async () => {
397
- const r = index_1.StructuredFilterRetriever.create(buildIndex([{ id: 'a' }])).orThrow();
398
- expect(await r.retrieve({})).toSucceedWith([]);
399
- });
400
- });
401
- /** A scripted in-memory vector index returning canned hits. */
402
- class FakeVectorIndex {
403
- constructor(hits, failQuery = false) {
404
- this._hits = hits;
405
- this._failQuery = failQuery;
406
- }
407
- add(t) {
408
- return Promise.resolve((0, ts_utils_1.succeed)(`ref-${t.id}`));
409
- }
410
- remove(t) {
411
- return Promise.resolve((0, ts_utils_1.succeed)(t));
412
- }
413
- query(__vector, topK) {
414
- this.lastTopK = topK;
415
- return Promise.resolve(this._failQuery ? (0, ts_utils_1.fail)('vector backend down') : (0, ts_utils_1.succeed)(this._hits));
416
- }
417
- }
418
- describe('SemanticRetriever', () => {
419
- const okEmbed = () => Promise.resolve((0, ts_utils_1.succeed)(Float32Array.from([0.1, 0.2])));
420
- test('reports supportsSemanticRecall=false when no backend is wired', () => {
421
- const r = index_1.SemanticRetriever.create({ index: buildIndex([]) }).orThrow();
422
- expect(r.capabilities.supportsSemanticRecall).toBe(false);
423
- });
424
- test('reports supportsSemanticRecall=true when a backend is wired', () => {
425
- const r = index_1.SemanticRetriever.create({
426
- index: buildIndex([]),
427
- backend: { vectorIndex: new FakeVectorIndex([]), embedQuery: okEmbed }
428
- }).orThrow();
429
- expect(r.capabilities.supportsSemanticRecall).toBe(true);
430
- });
431
- test('degrades loudly on a semantic request when no backend is wired', async () => {
432
- const r = index_1.SemanticRetriever.create({ index: buildIndex([{ id: 'a' }]) }).orThrow();
433
- expect(await r.retrieve({ semantic: 'hi' })).toFailWith(/semantic recall requires a vector index; none configured/i);
434
- });
435
- test('returns empty (not failure) when no semantic term is supplied', async () => {
436
- const r = index_1.SemanticRetriever.create({ index: buildIndex([{ id: 'a' }]) }).orThrow();
437
- expect(await r.retrieve({})).toSucceedWith([]);
438
- });
439
- test('degrades loudly on an as-of request', async () => {
440
- const r = index_1.SemanticRetriever.create({ index: buildIndex([{ id: 'a' }]) }).orThrow();
441
- expect(await r.retrieve({ asOf: 5 })).toFailWith(/temporal query requires temporal index/i);
442
- });
443
- test('resolves vector hits back to records in hit order', async () => {
444
- const index = buildIndex([
445
- { id: 'a', updated: 1 },
446
- { id: 'b', updated: 99 },
447
- { id: 'c', updated: 50 }
448
- ]);
449
- const r = index_1.SemanticRetriever.create({
450
- index,
451
- backend: {
452
- vectorIndex: new FakeVectorIndex([
453
- { target: et('b'), score: 0.9 },
454
- { target: et('a'), score: 0.5 }
455
- ]),
456
- embedQuery: okEmbed
457
- }
458
- }).orThrow();
459
- expect(await r.retrieve({ semantic: 'q' })).toSucceedAndSatisfy((records) => {
460
- // Hit order preserved (b before a), NOT recency order.
461
- expect(ids(records)).toEqual(['b', 'a']);
462
- });
463
- });
464
- test('drops hits not present in the index and applies query filters', async () => {
465
- const index = buildIndex([
466
- { id: 'a', tags: ['x'] },
467
- { id: 'b', tags: ['y'] }
468
- ]);
469
- const r = index_1.SemanticRetriever.create({
470
- index,
471
- backend: {
472
- vectorIndex: new FakeVectorIndex([
473
- { target: et('gone'), score: 0.99 },
474
- { target: et('b'), score: 0.8 },
475
- { target: et('a'), score: 0.7 }
476
- ]),
477
- embedQuery: okEmbed
478
- }
479
- }).orThrow();
480
- expect(await r.retrieve({ semantic: 'q', tag: 'x' })).toSucceedAndSatisfy((records) => {
481
- expect(ids(records)).toEqual(['a']);
482
- });
483
- });
484
- test('resolves a hit to the correctly-scoped record when two records share an id stem across scopes', async () => {
485
- // Two records with the identical stem `turn-3` under different scopes — the
486
- // exact same-stem-across-scopes collision the scope-qualified hit fixes. The
487
- // retriever must re-resolve each hit through its full `(scope, id)` key, not a
488
- // bare id (which would ambiguously match either record).
489
- const index = buildIndex([
490
- { id: 'turn-3', scope: 'conv-a', tags: ['from-a'] },
491
- { id: 'turn-3', scope: 'conv-b', tags: ['from-b'] }
492
- ]);
493
- const r = index_1.SemanticRetriever.create({
494
- index,
495
- backend: {
496
- // The vector backend scored the conv-b record; the retriever must return
497
- // exactly that record, never the same-stem conv-a record.
498
- vectorIndex: new FakeVectorIndex([{ target: et('turn-3', 'conv-b'), score: 0.9 }]),
499
- embedQuery: okEmbed
500
- }
501
- }).orThrow();
502
- expect(await r.retrieve({ semantic: 'q' })).toSucceedAndSatisfy((records) => {
503
- expect(records).toHaveLength(1);
504
- expect(records[0].envelope.id).toBe('turn-3');
505
- // The tag proves it is the conv-b record, not the same-stem conv-a one.
506
- expect(records[0].envelope.tags).toEqual(['from-b']);
507
- });
508
- });
509
- test('forwards topK to the vector index and applies the post-filter limit', async () => {
510
- const index = buildIndex([{ id: 'a' }, { id: 'b' }, { id: 'c' }]);
511
- const vectorIndex = new FakeVectorIndex([
512
- { target: et('a'), score: 0.9 },
513
- { target: et('b'), score: 0.8 },
514
- { target: et('c'), score: 0.7 }
515
- ]);
516
- const r = index_1.SemanticRetriever.create({ index, backend: { vectorIndex, embedQuery: okEmbed } }).orThrow();
517
- expect(await r.retrieve({ semantic: 'q', topK: 2, limit: 2 })).toSucceedAndSatisfy((records) => {
518
- expect(ids(records)).toEqual(['a', 'b']);
519
- });
520
- // The retriever must forward the caller's topK to the vector backend, not its default.
521
- expect(vectorIndex.lastTopK).toBe(2);
522
- });
523
- test('defaults topK to 10 when the query omits it', async () => {
524
- const vectorIndex = new FakeVectorIndex([{ target: et('a'), score: 0.9 }]);
525
- const r = index_1.SemanticRetriever.create({
526
- index: buildIndex([{ id: 'a' }]),
527
- backend: { vectorIndex, embedQuery: okEmbed }
528
- }).orThrow();
529
- expect(await r.retrieve({ semantic: 'q' })).toSucceed();
530
- expect(vectorIndex.lastTopK).toBe(10);
531
- });
532
- test('fails loudly when the embedder fails', async () => {
533
- const r = index_1.SemanticRetriever.create({
534
- index: buildIndex([{ id: 'a' }]),
535
- backend: {
536
- vectorIndex: new FakeVectorIndex([]),
537
- embedQuery: () => Promise.resolve((0, ts_utils_1.fail)('no embed model'))
538
- }
539
- }).orThrow();
540
- expect(await r.retrieve({ semantic: 'q' })).toFailWith(/query embedding failed: no embed model/i);
541
- });
542
- test('fails loudly when the vector backend fails', async () => {
543
- const r = index_1.SemanticRetriever.create({
544
- index: buildIndex([{ id: 'a' }]),
545
- backend: { vectorIndex: new FakeVectorIndex([], true), embedQuery: okEmbed }
546
- }).orThrow();
547
- expect(await r.retrieve({ semantic: 'q' })).toFailWith(/vector query failed: vector backend down/i);
548
- });
549
- test('normalizes a rejecting embedder into a Failure (never escapes as a rejection)', async () => {
550
- const r = index_1.SemanticRetriever.create({
551
- index: buildIndex([{ id: 'a' }]),
552
- backend: {
553
- vectorIndex: new FakeVectorIndex([]),
554
- embedQuery: () => Promise.reject(new Error('embedder blew up'))
555
- }
556
- }).orThrow();
557
- expect(await r.retrieve({ semantic: 'q' })).toFailWith(/query embedding failed: .*embedder blew up/i);
558
- });
559
- test('normalizes a rejecting vector backend into a Failure', async () => {
560
- // A vector index whose `query` rejects (throws) rather than returning a fail.
561
- const rejectingIndex = {
562
- add: (t) => Promise.resolve((0, ts_utils_1.succeed)(`ref-${t.id}`)),
563
- remove: (t) => Promise.resolve((0, ts_utils_1.succeed)(t)),
564
- query: () => Promise.reject(new Error('socket hangup'))
565
- };
566
- const r = index_1.SemanticRetriever.create({
567
- index: buildIndex([{ id: 'a' }]),
568
- backend: { vectorIndex: rejectingIndex, embedQuery: okEmbed }
569
- }).orThrow();
570
- expect(await r.retrieve({ semantic: 'q' })).toFailWith(/vector query failed: .*socket hangup/i);
571
- });
572
- });
573
- describe('ScoreUnionMergeStrategy', () => {
574
- test('unions, dedupes by id, and scores by retriever count', () => {
575
- const strategy = index_1.ScoreUnionMergeStrategy.create().orThrow();
576
- const [a, b, c] = [
577
- makeEntry({ id: 'a', updated: 10 }).record,
578
- makeEntry({ id: 'b', updated: 30 }).record,
579
- makeEntry({ id: 'c', updated: 20 }).record
580
- ];
581
- // 'b' appears in two sets (score 2); 'a' and 'c' in one each (score 1) — among
582
- // score-1 records, recency breaks the tie (c.updated 20 > a.updated 10).
583
- expect(strategy.merge([
584
- [a, b],
585
- [b, c]
586
- ])).toSucceedAndSatisfy((records) => {
587
- expect(ids(records)).toEqual(['b', 'c', 'a']);
588
- });
589
- });
590
- test('counts an id at most once per result set', () => {
591
- const strategy = index_1.ScoreUnionMergeStrategy.create().orThrow();
592
- const a = makeEntry({ id: 'a', updated: 10 }).record;
593
- const b = makeEntry({ id: 'b', updated: 5 }).record;
594
- // 'a' twice in one set still scores 1; 'b' in two sets scores 2 → b ranks first.
595
- expect(strategy.merge([[a, a], [b], [b]])).toSucceedAndSatisfy((records) => {
596
- expect(ids(records)).toEqual(['b', 'a']);
597
- });
598
- });
599
- });
600
- describe('HybridRetriever', () => {
601
- function build() {
602
- return {
603
- index: buildIndex([
604
- { id: 'a', tags: ['x'], updated: 10 },
605
- { id: 'b', tags: ['y'], updated: 30 },
606
- { id: 'c', tags: ['x'], updated: 20 }
607
- ])
608
- };
609
- }
610
- test('requires at least one retriever', () => {
611
- const strategy = index_1.ScoreUnionMergeStrategy.create().orThrow();
612
- expect(index_1.HybridRetriever.create([], strategy)).toFailWith(/at least one retriever is required/i);
613
- });
614
- test('capabilities are the union of composed retrievers', () => {
615
- const { index } = build();
616
- const recency = index_1.RecencyRetriever.create(index).orThrow();
617
- const semantic = index_1.SemanticRetriever.create({
618
- index,
619
- backend: {
620
- vectorIndex: new FakeVectorIndex([]),
621
- embedQuery: () => Promise.resolve((0, ts_utils_1.succeed)(Float32Array.from([1])))
622
- }
623
- }).orThrow();
624
- const hybrid = index_1.HybridRetriever.create([recency, semantic], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
625
- expect(hybrid.capabilities).toEqual({
626
- supportsSemanticRecall: true,
627
- supportsTemporalQuery: false,
628
- supportsLinkTraversal: false
629
- });
630
- });
631
- test('merges the results of composed retrievers', async () => {
632
- const { index } = build();
633
- const recency = index_1.RecencyRetriever.create(index).orThrow();
634
- const tag = index_1.TagRetriever.create(index).orThrow();
635
- const hybrid = index_1.HybridRetriever.create([recency, tag], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
636
- // recency returns a,b,c (with tag x filter: a,c); tag x returns a,c. Both
637
- // surface a & c (score 2), b absent. Use tag:x so recency also filters to x.
638
- expect(await hybrid.retrieve({ tag: 'x' })).toSucceedAndSatisfy((records) => {
639
- expect([...ids(records)].sort()).toEqual(['a', 'c']);
640
- });
641
- });
642
- test('routes a semantic query only to the semantic-capable child', async () => {
643
- const { index } = build();
644
- const recency = index_1.RecencyRetriever.create(index).orThrow();
645
- const semantic = index_1.SemanticRetriever.create({
646
- index,
647
- backend: {
648
- vectorIndex: new FakeVectorIndex([{ target: et('b'), score: 0.9 }]),
649
- embedQuery: () => Promise.resolve((0, ts_utils_1.succeed)(Float32Array.from([1])))
650
- }
651
- }).orThrow();
652
- const hybrid = index_1.HybridRetriever.create([recency, semantic], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
653
- // recency (no semantic support) gets the semantic field stripped → returns all
654
- // three; semantic returns just b. b therefore scores 2 and ranks first.
655
- expect(await hybrid.retrieve({ semantic: 'q' })).toSucceedAndSatisfy((records) => {
656
- expect(records[0].envelope.id).toBe('b');
657
- expect([...ids(records)].sort()).toEqual(['a', 'b', 'c']);
658
- });
659
- });
660
- test('routes link-traversal axes only to the link-capable child', async () => {
661
- var _a, _b, _c, _d;
662
- const linkChild = new RecordingRetriever({
663
- supportsSemanticRecall: false,
664
- supportsTemporalQuery: false,
665
- supportsLinkTraversal: true
666
- });
667
- const plainChild = new RecordingRetriever({
668
- supportsSemanticRecall: false,
669
- supportsTemporalQuery: false,
670
- supportsLinkTraversal: false
671
- });
672
- const hybrid = index_1.HybridRetriever.create([linkChild, plainChild], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
673
- expect(hybrid.capabilities.supportsLinkTraversal).toBe(true);
674
- // Union supports link traversal, so the hybrid does NOT loud-fail.
675
- expect(await hybrid.retrieve({ linkedTo: et('a'), hops: 2 })).toSucceed();
676
- // The link-capable child keeps the axes; the plain child has them stripped.
677
- expect((_a = linkChild.lastQuery) === null || _a === void 0 ? void 0 : _a.linkedTo).toEqual(et('a'));
678
- expect((_b = linkChild.lastQuery) === null || _b === void 0 ? void 0 : _b.hops).toBe(2);
679
- expect((_c = plainChild.lastQuery) === null || _c === void 0 ? void 0 : _c.linkedTo).toBeUndefined();
680
- expect((_d = plainChild.lastQuery) === null || _d === void 0 ? void 0 : _d.hops).toBeUndefined();
681
- });
682
- test('degrades loudly when its union does not support a requested capability', async () => {
683
- const { index } = build();
684
- const recency = index_1.RecencyRetriever.create(index).orThrow();
685
- const hybrid = index_1.HybridRetriever.create([recency], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
686
- expect(await hybrid.retrieve({ semantic: 'q' })).toFailWith(/semantic recall requires/i);
687
- });
688
- test('propagates a child failure rather than dropping it silently', async () => {
689
- const { index } = build();
690
- const semantic = index_1.SemanticRetriever.create({
691
- index,
692
- backend: {
693
- vectorIndex: new FakeVectorIndex([], true),
694
- embedQuery: () => Promise.resolve((0, ts_utils_1.succeed)(Float32Array.from([1])))
695
- }
696
- }).orThrow();
697
- const hybrid = index_1.HybridRetriever.create([semantic], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
698
- expect(await hybrid.retrieve({ semantic: 'q' })).toFailWith(/vector query failed/i);
699
- });
700
- test('does not pre-truncate child result sets: limit is applied only post-merge', async () => {
701
- // Recency full order is [d,c,b,a]; semantic surfaces [d,a]. With a correct
702
- // (post-merge-only) limit, the merge sees BOTH full sets, so d and a each
703
- // score 2 and the limit-2 result is [d,a]. If the limit leaked into the
704
- // children, recency would pre-truncate to [d,c] and the result would wrongly
705
- // be [d,c] — a never reaching the merge to score 2.
706
- const index = buildIndex([
707
- { id: 'a', updated: 10 },
708
- { id: 'b', updated: 20 },
709
- { id: 'c', updated: 30 },
710
- { id: 'd', updated: 40 }
711
- ]);
712
- const recency = index_1.RecencyRetriever.create(index).orThrow();
713
- const semantic = index_1.SemanticRetriever.create({
714
- index,
715
- backend: {
716
- vectorIndex: new FakeVectorIndex([
717
- { target: et('d'), score: 0.9 },
718
- { target: et('a'), score: 0.8 }
719
- ]),
720
- embedQuery: () => Promise.resolve((0, ts_utils_1.succeed)(Float32Array.from([1])))
721
- }
722
- }).orThrow();
723
- const hybrid = index_1.HybridRetriever.create([recency, semantic], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
724
- expect(await hybrid.retrieve({ semantic: 'q', limit: 2 })).toSucceedAndSatisfy((records) => {
725
- expect(ids(records)).toEqual(['d', 'a']);
726
- });
727
- });
728
- test('applies the hybrid-level limit after merge', async () => {
729
- const { index } = build();
730
- const recency = index_1.RecencyRetriever.create(index).orThrow();
731
- const hybrid = index_1.HybridRetriever.create([recency], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
732
- expect(await hybrid.retrieve({ limit: 1 })).toSucceedAndSatisfy((records) => {
733
- expect(records).toHaveLength(1);
734
- expect(records[0].envelope.id).toBe('b');
735
- });
736
- });
737
- test('applies the { offset, limit } window after merge', async () => {
738
- const { index } = build();
739
- const recency = index_1.RecencyRetriever.create(index).orThrow();
740
- const hybrid = index_1.HybridRetriever.create([recency], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
741
- // Merged recency order is [b(30), c(20), a(10)]; offset 1 + limit 1 → [c].
742
- expect(await hybrid.retrieve({ offset: 1, limit: 1 })).toSucceedAndSatisfy((records) => {
743
- expect(ids(records)).toEqual(['c']);
744
- });
745
- });
746
- test('strips offset from child queries (offset is a post-merge concern)', async () => {
747
- var _a, _b;
748
- const child = new RecordingRetriever({
749
- supportsSemanticRecall: false,
750
- supportsTemporalQuery: false,
751
- supportsLinkTraversal: false
752
- });
753
- const hybrid = index_1.HybridRetriever.create([child], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
754
- expect(await hybrid.retrieve({ offset: 2, limit: 3 })).toSucceed();
755
- expect((_a = child.lastQuery) === null || _a === void 0 ? void 0 : _a.offset).toBeUndefined();
756
- expect((_b = child.lastQuery) === null || _b === void 0 ? void 0 : _b.limit).toBeUndefined();
757
- });
758
- test('passes the kinds axis through to children (a shared pre-filter axis)', async () => {
759
- var _a;
760
- const child = new RecordingRetriever({
761
- supportsSemanticRecall: false,
762
- supportsTemporalQuery: false,
763
- supportsLinkTraversal: false
764
- });
765
- const hybrid = index_1.HybridRetriever.create([child], index_1.ScoreUnionMergeStrategy.create().orThrow()).orThrow();
766
- expect(await hybrid.retrieve({ kinds: ['knowledge'] })).toSucceed();
767
- expect((_a = child.lastQuery) === null || _a === void 0 ? void 0 : _a.kinds).toEqual(['knowledge']);
768
- });
769
- });
770
- //# sourceMappingURL=retrievers.test.js.map