@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
@@ -0,0 +1,149 @@
1
+ import { Result } from '@fgv/ts-utils';
2
+ import { MemoryEmbedOutcome } from '../observe';
3
+ import { IEdgeTarget, IMemoryRecord, Kind, MemoryId, MemoryScopeKey } from '../types';
4
+ import { FragmentEmbedder, IFragmentVectorIndex, IVectorIndex, MemoryEmbedder } from '../vector';
5
+ /**
6
+ * The internal outcome of record-level embed-on-write: the record to persist,
7
+ * plus — only when the embedder declined a record that already carried an
8
+ * `embeddingRef` — the index entry that reference superseded.
9
+ *
10
+ * `stale` is carried out to the caller rather than acted on in place because the
11
+ * prune belongs on the far side of `_persist`: a persist that fails leaves the
12
+ * PREVIOUS content on disk, and the superseded vector is still an accurate
13
+ * embedding of that content.
14
+ * @internal
15
+ */
16
+ export interface IEmbedOnWriteOutcome {
17
+ readonly record: IMemoryRecord<string>;
18
+ readonly stale?: {
19
+ readonly index: IVectorIndex;
20
+ readonly target: IEdgeTarget;
21
+ };
22
+ /**
23
+ * What the record-granular index did, surfaced on the write observation.
24
+ * `undefined` when the question does not apply (nothing wired).
25
+ */
26
+ readonly embed?: MemoryEmbedOutcome;
27
+ }
28
+ /**
29
+ * What {@link VectorMaintenance} needs from the store it serves. Every field is
30
+ * the store's own, passed in rather than reached for, so this collaborator holds
31
+ * no reference back to the store and cannot quietly grow one.
32
+ * @internal
33
+ */
34
+ export interface IVectorMaintenanceParams {
35
+ readonly vectorIndex?: IVectorIndex;
36
+ readonly embed?: MemoryEmbedder;
37
+ readonly fragmentIndex?: IFragmentVectorIndex;
38
+ readonly fragmentEmbedder?: FragmentEmbedder;
39
+ /** The store's swallowed-failure logger; every vector fault is best-effort. */
40
+ readonly warn: (message: string) => void;
41
+ /**
42
+ * The store's per-kind record-index participation predicate
43
+ * (`IMemoryStore.embedsKind`). Passed in rather than re-derived so the store's
44
+ * declaration and the gate that enforces it cannot disagree.
45
+ */
46
+ readonly embedsKind: (kind: Kind) => boolean;
47
+ }
48
+ /**
49
+ * The store's record- and fragment-vector maintenance, extracted from
50
+ * {@link FileTreeMemoryStore} as a collaborator.
51
+ *
52
+ * @remarks
53
+ * Everything here is **best-effort by contract**: the durable record store is
54
+ * authoritative and both indexes are derived, rebuildable views, so a failed
55
+ * embed, add or remove is logged and the write still succeeds. Nothing in this
56
+ * class can turn a committed write into a `Failure` — which is exactly why it
57
+ * separates cleanly from the store's write path, where every step is fallible
58
+ * and fatal.
59
+ *
60
+ * The split is behavior-preserving: these are the same methods the store used to
61
+ * carry as privates, with the same call order and the same logging. What moved is
62
+ * where they live, not what they do.
63
+ * @internal
64
+ */
65
+ export declare class VectorMaintenance {
66
+ private readonly _vectorIndex;
67
+ private readonly _embed;
68
+ private readonly _fragmentIndex;
69
+ private readonly _fragmentEmbedder;
70
+ private readonly _warn;
71
+ private readonly _embedsKind;
72
+ constructor(params: IVectorMaintenanceParams);
73
+ /**
74
+ * Best-effort removal of everything the two indexes hold for one record. Used
75
+ * by the delete path and by cull-oldest eviction, both of which have already
76
+ * committed by the time they call it.
77
+ */
78
+ removeAll(target: IEdgeTarget): Promise<void>;
79
+ /**
80
+ * Best-effort embed-on-write. When a vector index AND an embedder are wired,
81
+ * embeds the built record, `add`s the vector (replace semantics handle a same-id
82
+ * re-embed — no explicit remove), and stamps the returned `embeddingRef`. A
83
+ * failure (returned `fail` OR a thrown/rejected hook) is logged and the
84
+ * unembedded record is returned unchanged — the put still persists, and the
85
+ * derived index is reconciled by a later `rebuild`. A pass-through no-op when
86
+ * unwired (byte-identical record).
87
+ *
88
+ * A **decline** is not a failure and is handled differently: see
89
+ * `declineEmbedding`.
90
+ *
91
+ * Always succeeds (`Result` is the chain's shape, never a vector-induced
92
+ * failure).
93
+ */
94
+ embedOnWrite(built: IMemoryRecord<string>, scope: MemoryScopeKey): Promise<Result<IEmbedOnWriteOutcome>>;
95
+ /**
96
+ * Prune the vector a decline superseded. Best-effort like the rest of the
97
+ * vector path: a failed `remove` is logged and the (already-persisted) record
98
+ * still carries no `embeddingRef`, because the record's own claim about itself
99
+ * should be true even when the derived index is momentarily stale — that is
100
+ * exactly what a later `rebuild` reconciles.
101
+ *
102
+ * The index travels with the target rather than being re-read from the instance
103
+ * so the prune lands on the same index the decline was made against, and so
104
+ * there is no second "is a vector index wired?" check whose false branch cannot
105
+ * be reached.
106
+ */
107
+ pruneStaleVector(stale: IEmbedOnWriteOutcome['stale']): Promise<void>;
108
+ /**
109
+ * Best-effort fragment-embed-on-write. When a fragment index AND a fragment
110
+ * embedder are wired, chunks + embeds the built record and replaces its
111
+ * fragments in the index (`addFragments` is whole-record-replace, so a re-authored
112
+ * document never leaves stale fragments behind — no explicit remove needed). A
113
+ * failure (returned `fail` OR a thrown/rejected hook) is logged and the record is
114
+ * returned unchanged — the put still persists, and the fragment index is a derived
115
+ * view a later `rebuild` reconciles. Unlike `embedOnWrite`
116
+ * it stamps nothing on the record (fragments have no per-record `embeddingRef`
117
+ * analog). A pass-through no-op when unwired (byte-identical record).
118
+ */
119
+ embedFragmentsOnWrite(built: IMemoryRecord<string>, scope: MemoryScopeKey): Promise<Result<IMemoryRecord<string>>>;
120
+ /**
121
+ * Best-effort fragment removal. A no-op unless the full fragment lifecycle is
122
+ * wired (both an index AND an embedder), so an unwired store does no fragment
123
+ * work and behaves byte-identically. Failures are logged, never surfaced — a
124
+ * committed delete/eviction must not fail because a derived fragment index could
125
+ * not be pruned.
126
+ */
127
+ private _removeFragmentsBestEffort;
128
+ /**
129
+ * Best-effort vector removal for each evicted record (never fails the put).
130
+ * Every evicted record is in the same `scope` as the incoming write (the
131
+ * cull-oldest cohort is the incoming record's `(scope, kind)` cohort), so that
132
+ * scope qualifies each removal target.
133
+ */
134
+ removeEvictedVectors(evicted: ReadonlyArray<MemoryId>, scope: MemoryScopeKey): Promise<void>;
135
+ /**
136
+ * Run a consumer-supplied vector hook, normalizing a thrown/rejected hook into a
137
+ * `Failure` and logging any failure at `warn`. Best-effort: the caller proceeds
138
+ * regardless, since the index is rebuildable.
139
+ */
140
+ private _tryVectorOp;
141
+ /**
142
+ * Best-effort vector removal. A no-op unless the full vector lifecycle is wired
143
+ * (both an index AND an embedder), so an unwired store does no vector work and
144
+ * behaves byte-identically. Failures are logged, never surfaced — a committed
145
+ * delete/eviction must not fail because a derived index could not be pruned.
146
+ */
147
+ private _removeVectorBestEffort;
148
+ }
149
+ //# sourceMappingURL=vectorMaintenance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectorMaintenance.d.ts","sourceRoot":"","sources":["../../../src/packlets/store/vectorMaintenance.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EACL,gBAAgB,EAEhB,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACf,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;KAAE,CAAC;IAChF;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAC;CACrC;AA4CD;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,oBAAoB,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2B;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmC;IAClE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA+B;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA0B;gBAEnC,MAAM,EAAE,wBAAwB;IASnD;;;;OAIG;IACU,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1D;;;;;;;;;;;;;;OAcG;IACU,YAAY,CACvB,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAC5B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAuDxC;;;;;;;;;;;OAWG;IACU,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlF;;;;;;;;;;OAUG;IACU,qBAAqB,CAChC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAC5B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IAqBzC;;;;;;OAMG;YACW,0BAA0B;IAQxC;;;;;OAKG;IACU,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzG;;;;OAIG;YACW,YAAY;IAa1B;;;;;OAKG;YACW,uBAAuB;CAOtC"}
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ var __rest = (this && this.__rest) || function (s, e) {
7
+ var t = {};
8
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
9
+ t[p] = s[p];
10
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
11
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
12
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
13
+ t[p[i]] = s[p[i]];
14
+ }
15
+ return t;
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.VectorMaintenance = void 0;
19
+ const ts_utils_1 = require("@fgv/ts-utils");
20
+ /**
21
+ * Project a record the embedder **declined** into its written form: the same
22
+ * record with no `embeddingRef`, plus the vector (if any) that reference
23
+ * superseded, for the caller to prune after the commit.
24
+ *
25
+ * @remarks
26
+ * A decline says "this record is intentionally not embedded". A re-put of a
27
+ * record that *was* embedded (or a caller who supplied an `embeddingRef` — the
28
+ * field is store-derived by contract but nothing strips it) arrives here
29
+ * carrying an inherited reference, so returning it unchanged would persist
30
+ * `embeddingRef` on a record the store just decided not to embed.
31
+ *
32
+ * Clearing the reference alone would be cosmetic and arguably worse: the index
33
+ * entry keyed on this target would survive, so a semantic query would keep
34
+ * returning the record — scored on its **previous** content — while the record
35
+ * itself claimed not to be indexed. So the vector goes too, via
36
+ * `pruneStaleVector` once the write has committed.
37
+ * `stale` is set only when a reference was actually inherited, which keeps the
38
+ * common decline (a record that was never embedded) free of an index round
39
+ * trip.
40
+ *
41
+ * Pure and static: the decision needs nothing from the instance, and deferring
42
+ * the index call to the caller is what lets it run on the far side of
43
+ * `_persist`.
44
+ */
45
+ function declineEmbedding(built, index, target, embed) {
46
+ if (built.envelope.embeddingRef === undefined) {
47
+ return { record: built, embed };
48
+ }
49
+ // Rest-spread rather than `embeddingRef: undefined`: the envelope is YAML-
50
+ // serialized, and an explicitly-undefined key is a serializer-dependent way
51
+ // to say "absent" where dropping the key is not.
52
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
53
+ const _a = built.envelope, { embeddingRef } = _a, envelope = __rest(_a, ["embeddingRef"]);
54
+ return { record: { envelope, body: built.body }, stale: { index, target }, embed };
55
+ }
56
+ /**
57
+ * The store's record- and fragment-vector maintenance, extracted from
58
+ * {@link FileTreeMemoryStore} as a collaborator.
59
+ *
60
+ * @remarks
61
+ * Everything here is **best-effort by contract**: the durable record store is
62
+ * authoritative and both indexes are derived, rebuildable views, so a failed
63
+ * embed, add or remove is logged and the write still succeeds. Nothing in this
64
+ * class can turn a committed write into a `Failure` — which is exactly why it
65
+ * separates cleanly from the store's write path, where every step is fallible
66
+ * and fatal.
67
+ *
68
+ * The split is behavior-preserving: these are the same methods the store used to
69
+ * carry as privates, with the same call order and the same logging. What moved is
70
+ * where they live, not what they do.
71
+ * @internal
72
+ */
73
+ class VectorMaintenance {
74
+ constructor(params) {
75
+ this._vectorIndex = params.vectorIndex;
76
+ this._embed = params.embed;
77
+ this._fragmentIndex = params.fragmentIndex;
78
+ this._fragmentEmbedder = params.fragmentEmbedder;
79
+ this._warn = params.warn;
80
+ this._embedsKind = params.embedsKind;
81
+ }
82
+ /**
83
+ * Best-effort removal of everything the two indexes hold for one record. Used
84
+ * by the delete path and by cull-oldest eviction, both of which have already
85
+ * committed by the time they call it.
86
+ */
87
+ async removeAll(target) {
88
+ await this._removeVectorBestEffort(target);
89
+ await this._removeFragmentsBestEffort(target);
90
+ }
91
+ /**
92
+ * Best-effort embed-on-write. When a vector index AND an embedder are wired,
93
+ * embeds the built record, `add`s the vector (replace semantics handle a same-id
94
+ * re-embed — no explicit remove), and stamps the returned `embeddingRef`. A
95
+ * failure (returned `fail` OR a thrown/rejected hook) is logged and the
96
+ * unembedded record is returned unchanged — the put still persists, and the
97
+ * derived index is reconciled by a later `rebuild`. A pass-through no-op when
98
+ * unwired (byte-identical record).
99
+ *
100
+ * A **decline** is not a failure and is handled differently: see
101
+ * `declineEmbedding`.
102
+ *
103
+ * Always succeeds (`Result` is the chain's shape, never a vector-induced
104
+ * failure).
105
+ */
106
+ async embedOnWrite(built, scope) {
107
+ if (this._vectorIndex === undefined || this._embed === undefined) {
108
+ // No outcome: with nothing wired there is no index for the record to be
109
+ // absent from, so reporting one would invent a coverage question the
110
+ // deployment has not asked.
111
+ return (0, ts_utils_1.succeed)({ record: built });
112
+ }
113
+ const vectorIndex = this._vectorIndex;
114
+ const embed = this._embed;
115
+ const target = { scope, id: built.envelope.id };
116
+ // Gate BEFORE the embedder call, which is the whole point: a `MemoryEmbedder`
117
+ // decline still pays the round trip, and on a locally-hosted model that round
118
+ // trip IS the cost. A kind excluded here is never handed to the embedder.
119
+ //
120
+ // An exclusion reaches the same conclusion as a decline — this record is
121
+ // intentionally not embedded — so it takes the same path: an inherited
122
+ // `embeddingRef` is dropped and the vector it named is pruned after the
123
+ // commit. Otherwise narrowing `embedKinds` on an existing vault would leave
124
+ // every previously-embedded record of the excluded kind claiming an
125
+ // embedding the store no longer maintains.
126
+ if (!this._embedsKind(built.envelope.kind)) {
127
+ return (0, ts_utils_1.succeed)(declineEmbedding(built, vectorIndex, target, 'excluded'));
128
+ }
129
+ const embedded = await this._tryVectorOp(() => embed(built), `embedding '${built.envelope.id}'`);
130
+ if (embedded.isFailure()) {
131
+ return (0, ts_utils_1.succeed)({ record: built, embed: 'failed' });
132
+ }
133
+ // A deliberate decline (`undefined`) stores the record with no embedding
134
+ // reference. Deliberately NOT logged, unlike the failure path above: a warning
135
+ // per write would make routine policy look like a recurring fault, which is
136
+ // the confusion this return value exists to end. It is still *reported* — as
137
+ // `embed: 'declined'` on the write observation — because saying nothing at all
138
+ // is what left `embeddingRef` absence three-ways ambiguous.
139
+ if (embedded.value === undefined) {
140
+ return (0, ts_utils_1.succeed)(declineEmbedding(built, vectorIndex, target, 'declined'));
141
+ }
142
+ // Hoisted: the `undefined` check above does not narrow across the callback
143
+ // boundary below, and a local keeps the non-null assertion out of the code.
144
+ const vector = embedded.value;
145
+ const added = await this._tryVectorOp(() => vectorIndex.add(target, vector), `vector add for '${built.envelope.id}'`);
146
+ if (added.isFailure()) {
147
+ return (0, ts_utils_1.succeed)({ record: built, embed: 'failed' });
148
+ }
149
+ return (0, ts_utils_1.succeed)({
150
+ record: { envelope: Object.assign(Object.assign({}, built.envelope), { embeddingRef: added.value }), body: built.body },
151
+ embed: 'embedded'
152
+ });
153
+ }
154
+ /**
155
+ * Prune the vector a decline superseded. Best-effort like the rest of the
156
+ * vector path: a failed `remove` is logged and the (already-persisted) record
157
+ * still carries no `embeddingRef`, because the record's own claim about itself
158
+ * should be true even when the derived index is momentarily stale — that is
159
+ * exactly what a later `rebuild` reconciles.
160
+ *
161
+ * The index travels with the target rather than being re-read from the instance
162
+ * so the prune lands on the same index the decline was made against, and so
163
+ * there is no second "is a vector index wired?" check whose false branch cannot
164
+ * be reached.
165
+ */
166
+ async pruneStaleVector(stale) {
167
+ if (stale === undefined) {
168
+ return;
169
+ }
170
+ await this._tryVectorOp(() => stale.index.remove(stale.target), `vector remove for declined '${stale.target.id}'`);
171
+ }
172
+ /**
173
+ * Best-effort fragment-embed-on-write. When a fragment index AND a fragment
174
+ * embedder are wired, chunks + embeds the built record and replaces its
175
+ * fragments in the index (`addFragments` is whole-record-replace, so a re-authored
176
+ * document never leaves stale fragments behind — no explicit remove needed). A
177
+ * failure (returned `fail` OR a thrown/rejected hook) is logged and the record is
178
+ * returned unchanged — the put still persists, and the fragment index is a derived
179
+ * view a later `rebuild` reconciles. Unlike `embedOnWrite`
180
+ * it stamps nothing on the record (fragments have no per-record `embeddingRef`
181
+ * analog). A pass-through no-op when unwired (byte-identical record).
182
+ */
183
+ async embedFragmentsOnWrite(built, scope) {
184
+ if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {
185
+ return (0, ts_utils_1.succeed)(built);
186
+ }
187
+ const fragmentIndex = this._fragmentIndex;
188
+ const fragmentEmbedder = this._fragmentEmbedder;
189
+ const target = { scope, id: built.envelope.id };
190
+ const embedded = await this._tryVectorOp(() => fragmentEmbedder(built), `fragment embedding '${built.envelope.id}'`);
191
+ if (embedded.isFailure()) {
192
+ return (0, ts_utils_1.succeed)(built);
193
+ }
194
+ await this._tryVectorOp(() => fragmentIndex.addFragments(target, embedded.value), `fragment add for '${built.envelope.id}'`);
195
+ return (0, ts_utils_1.succeed)(built);
196
+ }
197
+ /**
198
+ * Best-effort fragment removal. A no-op unless the full fragment lifecycle is
199
+ * wired (both an index AND an embedder), so an unwired store does no fragment
200
+ * work and behaves byte-identically. Failures are logged, never surfaced — a
201
+ * committed delete/eviction must not fail because a derived fragment index could
202
+ * not be pruned.
203
+ */
204
+ async _removeFragmentsBestEffort(target) {
205
+ if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {
206
+ return;
207
+ }
208
+ const fragmentIndex = this._fragmentIndex;
209
+ await this._tryVectorOp(() => fragmentIndex.remove(target), `fragment removal for '${target.id}'`);
210
+ }
211
+ /**
212
+ * Best-effort vector removal for each evicted record (never fails the put).
213
+ * Every evicted record is in the same `scope` as the incoming write (the
214
+ * cull-oldest cohort is the incoming record's `(scope, kind)` cohort), so that
215
+ * scope qualifies each removal target.
216
+ */
217
+ async removeEvictedVectors(evicted, scope) {
218
+ for (const id of evicted) {
219
+ await this.removeAll({ scope, id });
220
+ }
221
+ }
222
+ /**
223
+ * Run a consumer-supplied vector hook, normalizing a thrown/rejected hook into a
224
+ * `Failure` and logging any failure at `warn`. Best-effort: the caller proceeds
225
+ * regardless, since the index is rebuildable.
226
+ */
227
+ async _tryVectorOp(op, label) {
228
+ let result;
229
+ try {
230
+ result = await op();
231
+ }
232
+ catch (err) {
233
+ result = (0, ts_utils_1.fail)(`${label} threw: ${String(err)}`);
234
+ }
235
+ if (result.isFailure()) {
236
+ this._warn(`memory: ${label} failed (best-effort; derived index left for rebuild): ${result.message}`);
237
+ }
238
+ return result;
239
+ }
240
+ /**
241
+ * Best-effort vector removal. A no-op unless the full vector lifecycle is wired
242
+ * (both an index AND an embedder), so an unwired store does no vector work and
243
+ * behaves byte-identically. Failures are logged, never surfaced — a committed
244
+ * delete/eviction must not fail because a derived index could not be pruned.
245
+ */
246
+ async _removeVectorBestEffort(target) {
247
+ if (this._vectorIndex === undefined || this._embed === undefined) {
248
+ return;
249
+ }
250
+ const vectorIndex = this._vectorIndex;
251
+ await this._tryVectorOp(() => vectorIndex.remove(target), `vector removal for '${target.id}'`);
252
+ }
253
+ }
254
+ exports.VectorMaintenance = VectorMaintenance;
255
+ //# sourceMappingURL=vectorMaintenance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectorMaintenance.js","sourceRoot":"","sources":["../../../src/packlets/store/vectorMaintenance.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, fail, succeed } from '@fgv/ts-utils';\nimport { MemoryEmbedOutcome } from '../observe';\nimport { IEdgeTarget, IMemoryRecord, Kind, MemoryId, MemoryScopeKey } from '../types';\nimport {\n FragmentEmbedder,\n IEmbeddedFragment,\n IFragmentVectorIndex,\n IVectorIndex,\n MemoryEmbedder\n} from '../vector';\n\n/**\n * The internal outcome of record-level embed-on-write: the record to persist,\n * plus — only when the embedder declined a record that already carried an\n * `embeddingRef` — the index entry that reference superseded.\n *\n * `stale` is carried out to the caller rather than acted on in place because the\n * prune belongs on the far side of `_persist`: a persist that fails leaves the\n * PREVIOUS content on disk, and the superseded vector is still an accurate\n * embedding of that content.\n * @internal\n */\nexport interface IEmbedOnWriteOutcome {\n readonly record: IMemoryRecord<string>;\n readonly stale?: { readonly index: IVectorIndex; readonly target: IEdgeTarget };\n /**\n * What the record-granular index did, surfaced on the write observation.\n * `undefined` when the question does not apply (nothing wired).\n */\n readonly embed?: MemoryEmbedOutcome;\n}\n\n/**\n * Project a record the embedder **declined** into its written form: the same\n * record with no `embeddingRef`, plus the vector (if any) that reference\n * superseded, for the caller to prune after the commit.\n *\n * @remarks\n * A decline says \"this record is intentionally not embedded\". A re-put of a\n * record that *was* embedded (or a caller who supplied an `embeddingRef` — the\n * field is store-derived by contract but nothing strips it) arrives here\n * carrying an inherited reference, so returning it unchanged would persist\n * `embeddingRef` on a record the store just decided not to embed.\n *\n * Clearing the reference alone would be cosmetic and arguably worse: the index\n * entry keyed on this target would survive, so a semantic query would keep\n * returning the record — scored on its **previous** content — while the record\n * itself claimed not to be indexed. So the vector goes too, via\n * `pruneStaleVector` once the write has committed.\n * `stale` is set only when a reference was actually inherited, which keeps the\n * common decline (a record that was never embedded) free of an index round\n * trip.\n *\n * Pure and static: the decision needs nothing from the instance, and deferring\n * the index call to the caller is what lets it run on the far side of\n * `_persist`.\n */\nfunction declineEmbedding(\n built: IMemoryRecord<string>,\n index: IVectorIndex,\n target: IEdgeTarget,\n embed: MemoryEmbedOutcome\n): IEmbedOnWriteOutcome {\n if (built.envelope.embeddingRef === undefined) {\n return { record: built, embed };\n }\n // Rest-spread rather than `embeddingRef: undefined`: the envelope is YAML-\n // serialized, and an explicitly-undefined key is a serializer-dependent way\n // to say \"absent\" where dropping the key is not.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { embeddingRef, ...envelope } = built.envelope;\n return { record: { envelope, body: built.body }, stale: { index, target }, embed };\n}\n\n/**\n * What {@link VectorMaintenance} needs from the store it serves. Every field is\n * the store's own, passed in rather than reached for, so this collaborator holds\n * no reference back to the store and cannot quietly grow one.\n * @internal\n */\nexport interface IVectorMaintenanceParams {\n readonly vectorIndex?: IVectorIndex;\n readonly embed?: MemoryEmbedder;\n readonly fragmentIndex?: IFragmentVectorIndex;\n readonly fragmentEmbedder?: FragmentEmbedder;\n /** The store's swallowed-failure logger; every vector fault is best-effort. */\n readonly warn: (message: string) => void;\n /**\n * The store's per-kind record-index participation predicate\n * (`IMemoryStore.embedsKind`). Passed in rather than re-derived so the store's\n * declaration and the gate that enforces it cannot disagree.\n */\n readonly embedsKind: (kind: Kind) => boolean;\n}\n\n/**\n * The store's record- and fragment-vector maintenance, extracted from\n * {@link FileTreeMemoryStore} as a collaborator.\n *\n * @remarks\n * Everything here is **best-effort by contract**: the durable record store is\n * authoritative and both indexes are derived, rebuildable views, so a failed\n * embed, add or remove is logged and the write still succeeds. Nothing in this\n * class can turn a committed write into a `Failure` — which is exactly why it\n * separates cleanly from the store's write path, where every step is fallible\n * and fatal.\n *\n * The split is behavior-preserving: these are the same methods the store used to\n * carry as privates, with the same call order and the same logging. What moved is\n * where they live, not what they do.\n * @internal\n */\nexport class VectorMaintenance {\n private readonly _vectorIndex: IVectorIndex | undefined;\n private readonly _embed: MemoryEmbedder | undefined;\n private readonly _fragmentIndex: IFragmentVectorIndex | undefined;\n private readonly _fragmentEmbedder: FragmentEmbedder | undefined;\n private readonly _warn: (message: string) => void;\n private readonly _embedsKind: (kind: Kind) => boolean;\n\n public constructor(params: IVectorMaintenanceParams) {\n this._vectorIndex = params.vectorIndex;\n this._embed = params.embed;\n this._fragmentIndex = params.fragmentIndex;\n this._fragmentEmbedder = params.fragmentEmbedder;\n this._warn = params.warn;\n this._embedsKind = params.embedsKind;\n }\n\n /**\n * Best-effort removal of everything the two indexes hold for one record. Used\n * by the delete path and by cull-oldest eviction, both of which have already\n * committed by the time they call it.\n */\n public async removeAll(target: IEdgeTarget): Promise<void> {\n await this._removeVectorBestEffort(target);\n await this._removeFragmentsBestEffort(target);\n }\n\n /**\n * Best-effort embed-on-write. When a vector index AND an embedder are wired,\n * embeds the built record, `add`s the vector (replace semantics handle a same-id\n * re-embed — no explicit remove), and stamps the returned `embeddingRef`. A\n * failure (returned `fail` OR a thrown/rejected hook) is logged and the\n * unembedded record is returned unchanged — the put still persists, and the\n * derived index is reconciled by a later `rebuild`. A pass-through no-op when\n * unwired (byte-identical record).\n *\n * A **decline** is not a failure and is handled differently: see\n * `declineEmbedding`.\n *\n * Always succeeds (`Result` is the chain's shape, never a vector-induced\n * failure).\n */\n public async embedOnWrite(\n built: IMemoryRecord<string>,\n scope: MemoryScopeKey\n ): Promise<Result<IEmbedOnWriteOutcome>> {\n if (this._vectorIndex === undefined || this._embed === undefined) {\n // No outcome: with nothing wired there is no index for the record to be\n // absent from, so reporting one would invent a coverage question the\n // deployment has not asked.\n return succeed({ record: built });\n }\n const vectorIndex: IVectorIndex = this._vectorIndex;\n const embed: MemoryEmbedder = this._embed;\n const target: IEdgeTarget = { scope, id: built.envelope.id };\n // Gate BEFORE the embedder call, which is the whole point: a `MemoryEmbedder`\n // decline still pays the round trip, and on a locally-hosted model that round\n // trip IS the cost. A kind excluded here is never handed to the embedder.\n //\n // An exclusion reaches the same conclusion as a decline — this record is\n // intentionally not embedded — so it takes the same path: an inherited\n // `embeddingRef` is dropped and the vector it named is pruned after the\n // commit. Otherwise narrowing `embedKinds` on an existing vault would leave\n // every previously-embedded record of the excluded kind claiming an\n // embedding the store no longer maintains.\n if (!this._embedsKind(built.envelope.kind)) {\n return succeed(declineEmbedding(built, vectorIndex, target, 'excluded'));\n }\n const embedded: Result<Float32Array | undefined> = await this._tryVectorOp(\n () => embed(built),\n `embedding '${built.envelope.id}'`\n );\n if (embedded.isFailure()) {\n return succeed({ record: built, embed: 'failed' });\n }\n // A deliberate decline (`undefined`) stores the record with no embedding\n // reference. Deliberately NOT logged, unlike the failure path above: a warning\n // per write would make routine policy look like a recurring fault, which is\n // the confusion this return value exists to end. It is still *reported* — as\n // `embed: 'declined'` on the write observation — because saying nothing at all\n // is what left `embeddingRef` absence three-ways ambiguous.\n if (embedded.value === undefined) {\n return succeed(declineEmbedding(built, vectorIndex, target, 'declined'));\n }\n // Hoisted: the `undefined` check above does not narrow across the callback\n // boundary below, and a local keeps the non-null assertion out of the code.\n const vector: Float32Array = embedded.value;\n const added: Result<string> = await this._tryVectorOp(\n () => vectorIndex.add(target, vector),\n `vector add for '${built.envelope.id}'`\n );\n if (added.isFailure()) {\n return succeed({ record: built, embed: 'failed' });\n }\n return succeed({\n record: { envelope: { ...built.envelope, embeddingRef: added.value }, body: built.body },\n embed: 'embedded'\n });\n }\n\n /**\n * Prune the vector a decline superseded. Best-effort like the rest of the\n * vector path: a failed `remove` is logged and the (already-persisted) record\n * still carries no `embeddingRef`, because the record's own claim about itself\n * should be true even when the derived index is momentarily stale — that is\n * exactly what a later `rebuild` reconciles.\n *\n * The index travels with the target rather than being re-read from the instance\n * so the prune lands on the same index the decline was made against, and so\n * there is no second \"is a vector index wired?\" check whose false branch cannot\n * be reached.\n */\n public async pruneStaleVector(stale: IEmbedOnWriteOutcome['stale']): Promise<void> {\n if (stale === undefined) {\n return;\n }\n await this._tryVectorOp(\n () => stale.index.remove(stale.target),\n `vector remove for declined '${stale.target.id}'`\n );\n }\n\n /**\n * Best-effort fragment-embed-on-write. When a fragment index AND a fragment\n * embedder are wired, chunks + embeds the built record and replaces its\n * fragments in the index (`addFragments` is whole-record-replace, so a re-authored\n * document never leaves stale fragments behind — no explicit remove needed). A\n * failure (returned `fail` OR a thrown/rejected hook) is logged and the record is\n * returned unchanged — the put still persists, and the fragment index is a derived\n * view a later `rebuild` reconciles. Unlike `embedOnWrite`\n * it stamps nothing on the record (fragments have no per-record `embeddingRef`\n * analog). A pass-through no-op when unwired (byte-identical record).\n */\n public async embedFragmentsOnWrite(\n built: IMemoryRecord<string>,\n scope: MemoryScopeKey\n ): Promise<Result<IMemoryRecord<string>>> {\n if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {\n return succeed(built);\n }\n const fragmentIndex: IFragmentVectorIndex = this._fragmentIndex;\n const fragmentEmbedder: FragmentEmbedder = this._fragmentEmbedder;\n const target: IEdgeTarget = { scope, id: built.envelope.id };\n const embedded: Result<ReadonlyArray<IEmbeddedFragment>> = await this._tryVectorOp(\n () => fragmentEmbedder(built),\n `fragment embedding '${built.envelope.id}'`\n );\n if (embedded.isFailure()) {\n return succeed(built);\n }\n await this._tryVectorOp(\n () => fragmentIndex.addFragments(target, embedded.value),\n `fragment add for '${built.envelope.id}'`\n );\n return succeed(built);\n }\n\n /**\n * Best-effort fragment removal. A no-op unless the full fragment lifecycle is\n * wired (both an index AND an embedder), so an unwired store does no fragment\n * work and behaves byte-identically. Failures are logged, never surfaced — a\n * committed delete/eviction must not fail because a derived fragment index could\n * not be pruned.\n */\n private async _removeFragmentsBestEffort(target: IEdgeTarget): Promise<void> {\n if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {\n return;\n }\n const fragmentIndex: IFragmentVectorIndex = this._fragmentIndex;\n await this._tryVectorOp(() => fragmentIndex.remove(target), `fragment removal for '${target.id}'`);\n }\n\n /**\n * Best-effort vector removal for each evicted record (never fails the put).\n * Every evicted record is in the same `scope` as the incoming write (the\n * cull-oldest cohort is the incoming record's `(scope, kind)` cohort), so that\n * scope qualifies each removal target.\n */\n public async removeEvictedVectors(evicted: ReadonlyArray<MemoryId>, scope: MemoryScopeKey): Promise<void> {\n for (const id of evicted) {\n await this.removeAll({ scope, id });\n }\n }\n\n /**\n * Run a consumer-supplied vector hook, normalizing a thrown/rejected hook into a\n * `Failure` and logging any failure at `warn`. Best-effort: the caller proceeds\n * regardless, since the index is rebuildable.\n */\n private async _tryVectorOp<T>(op: () => Promise<Result<T>>, label: string): Promise<Result<T>> {\n let result: Result<T>;\n try {\n result = await op();\n } catch (err) {\n result = fail(`${label} threw: ${String(err)}`);\n }\n if (result.isFailure()) {\n this._warn(`memory: ${label} failed (best-effort; derived index left for rebuild): ${result.message}`);\n }\n return result;\n }\n\n /**\n * Best-effort vector removal. A no-op unless the full vector lifecycle is wired\n * (both an index AND an embedder), so an unwired store does no vector work and\n * behaves byte-identically. Failures are logged, never surfaced — a committed\n * delete/eviction must not fail because a derived index could not be pruned.\n */\n private async _removeVectorBestEffort(target: IEdgeTarget): Promise<void> {\n if (this._vectorIndex === undefined || this._embed === undefined) {\n return;\n }\n const vectorIndex: IVectorIndex = this._vectorIndex;\n await this._tryVectorOp(() => vectorIndex.remove(target), `vector removal for '${target.id}'`);\n }\n}\n"]}
@@ -133,6 +133,14 @@ export interface IMemoryEnvelope {
133
133
  * Absent when the kind has no registered projector (or the projector threw on
134
134
  * this record). Ordered retrieval (`orderBy: 'rank'`) and the index's rank view
135
135
  * sort by this value descending, placing records with an absent `rank` last.
136
+ *
137
+ * **The projector runs on the write path only — registering one does not rank
138
+ * records already in the store.** Because absent sorts last, those records land
139
+ * below every subsequently-written one regardless of what the projector would
140
+ * have scored them, so the result is not a partial ordering but one inverted
141
+ * with respect to the projector's intent, with nothing failing to say so. Call
142
+ * `IMemoryStore.reconcileRank` after registering a projector against a
143
+ * populated store.
136
144
  */
137
145
  readonly rank?: number;
138
146
  /** Structured provenance (never a flat enum). */
@@ -166,6 +174,9 @@ export interface IMemoryRecord<TBody = unknown> {
166
174
  * {@link IMemoryEnvelope.rank}. The store never interprets the body — the host
167
175
  * owns what the number means. A projector that throws is treated as "no rank
168
176
  * for this record" (logged at `warn`), never failing the write.
177
+ *
178
+ * Runs on writes only. To apply a newly-registered projector to records that
179
+ * already exist, call `IMemoryStore.reconcileRank`.
169
180
  * @public
170
181
  */
171
182
  export type RankProjector = (record: IMemoryRecord<unknown>) => number;
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../../src/packlets/types/envelope.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../../src/packlets/types/envelope.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,aAAa,GAAG,OAAO,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAEjF;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC,iFAAiF;IACjF,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEzD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,KAAK;IACpB,qCAAqC;IACrC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,uCAAuC;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IAEH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IAEjE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAE9B,yEAAyE;IACzE,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,mGAAmG;IACnG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,4BAA4B;IAC5B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAClC,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAGrC,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IAGjC,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAEnC;;;OAGG;IAEH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,OAAO;IAC5C,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,MAAM,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../../src/packlets/types/envelope.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAmEH,sCAEC;AAZD;;;;;;;;;GASG;AACH,SAAgB,aAAa,CAAC,MAAmB;IAC/C,OAAO,GAAG,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;AACzC,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { EntityId, Kind, LinkType, MemoryId, MemoryScopeKey, Tag } from './ids';\n\n/**\n * Origin of a provenance attribution. Open vocabulary: the three named\n * sources are conventional, but the `(string & {})` arm admits any other\n * source string without resignature.\n * @public\n */\nexport type ProvenanceSource = 'agent' | 'host-ingest' | 'human' | (string & {});\n\n/**\n * Structured provenance for a record or an edge. Never a flat enum — the\n * `[key: string]: unknown` index signature lets a consumer attach an opaque\n * domain payload (e.g. PersonAIlity's sentiment / epistemic blocks) without\n * changing this interface, while still satisfying the no-`any` rule.\n * @public\n */\nexport interface IProvenance {\n /** Where the attribution came from. */\n readonly source: ProvenanceSource;\n /** Optional human or agent identifier responsible for the write. */\n readonly by?: string;\n /** Optional model identifier, when a model produced the content. */\n readonly model?: string;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /**\n * Scope-qualified back-link to the source record. Enables the cross-kind\n * provenance spine. A scope-qualified {@link IEdgeTarget} (not a bare\n * {@link MemoryId}) because per-scope codecs (e.g. the MTM codec's `turn-<n>`\n * stems) legally reuse a stem across scopes, so a bare id would be ambiguous —\n * the same reason {@link IEdge.target} is scope-qualified.\n */\n readonly derivedFrom?: IEdgeTarget;\n /** Opaque extension payload — consumer-owned, never interpreted by the store. */\n readonly [key: string]: unknown;\n}\n\n/**\n * The physical address of a linked-to record: the `(scope, id)` pair that\n * uniquely identifies it. Both components are required because a bare\n * {@link MemoryId} is NOT unique across scopes — per-scope codecs (e.g. the\n * medium-term codec's `turn-<n>` stems) legally mint the same stem under\n * different scopes, so an edge that carried only the id would be ambiguous.\n * `(scope, id)` matches the store's `getById(scope, id)` addressing and the\n * index's composite primary key.\n * @public\n */\nexport interface IEdgeTarget {\n /** The scope the target record lives under. */\n readonly scope: MemoryScopeKey;\n /** The target record's stable file-stem id (unique WITHIN {@link IEdgeTarget.scope}). */\n readonly id: MemoryId;\n}\n\n/**\n * The canonical composite-key string for an {@link IEdgeTarget}: scope + id,\n * NUL-separated. NUL is excluded from both components (scope segments are\n * filename-safe; {@link MemoryId} is portable-filename-safe), so it is a\n * collision-proof separator. This is the ONE canonicalization every consumer\n * that keys on a scoped target uses — the backlink index, the cycle guard, and\n * the ingest edge-validation path all route through it so their notions of\n * \"same target\" cannot drift.\n * @public\n */\nexport function edgeTargetKey(target: IEdgeTarget): string {\n return `${target.scope}\\0${target.id}`;\n}\n\n/**\n * An attributed link between two records. Carries the relation type, the\n * scope-qualified {@link IEdgeTarget | target}, and optional confidence /\n * provenance / world-truth validity. Replaces bare string references (e.g.\n * PersonAIlity's `IMtmRef` becomes an `IEdge` with `type: LinkType('mtm-ref')`).\n * @public\n */\nexport interface IEdge {\n /** Open-vocabulary relation type. */\n readonly type: LinkType;\n /** The scope-qualified address of the linked-to record. */\n readonly target: IEdgeTarget;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /** Optional structured provenance for the link itself. */\n readonly provenance?: IProvenance;\n /** World-truth validity start (epoch ms). Present only on temporal edges. */\n readonly valid_at?: number;\n /**\n * World-truth validity end (epoch ms). `null` = still valid; absent = no\n * temporal extent.\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent (no temporal extent); design-lock §2.3\n readonly invalid_at?: number | null;\n}\n\n/**\n * Optional bi-temporal validity block on an envelope. Present only on\n * temporal kinds; absent = zero cost for atemporal kinds.\n * @public\n */\nexport interface ITemporalBlock {\n /** World-truth validity start (epoch ms). */\n readonly valid_at?: number;\n /** World-truth validity end (epoch ms). `null` = still valid. */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent; design-lock §2.4\n readonly invalid_at?: number | null;\n}\n\n/**\n * The invariant identity + transaction-time envelope carried by every memory\n * record, independent of the per-kind body.\n * @public\n */\nexport interface IMemoryEnvelope {\n // --- Core identity ---\n /** Stable file-stem identifier. MUST equal the on-disk filename stem. */\n readonly id: MemoryId;\n /** Consumer-supplied domain key. Equals {@link IMemoryEnvelope.id | id} for non-temporal kinds. */\n readonly entityId: EntityId;\n /** Consumer-registered kind; dispatches the body Converter. */\n readonly kind: Kind;\n /** Open-vocabulary tags. */\n readonly tags: ReadonlyArray<Tag>;\n /** Attributed outbound edges. */\n readonly links: ReadonlyArray<IEdge>;\n\n // --- Transaction-time metadata (always present) ---\n /** Epoch ms of the first write. Immutable after creation. */\n readonly created: number;\n /** Epoch ms of the most recent write. */\n readonly updated: number;\n /**\n * Monotonic write counter within the store instance, assigned by the store\n * on every successful put. Enables stable cursor paging over observation\n * records without a full walk.\n */\n readonly seq: number;\n /**\n * Content hash over the canonical `{ kind, body, links }`. The dedup key:\n * an exact match is a no-op upsert that returns the existing record.\n */\n readonly contentHash: string;\n /**\n * Store-computed host-defined ordering value, produced by the kind's\n * {@link RankProjector} on every put/update and stamped into the envelope in\n * the same pass that recomputes {@link IMemoryEnvelope.contentHash | contentHash}.\n * Absent when the kind has no registered projector (or the projector threw on\n * this record). Ordered retrieval (`orderBy: 'rank'`) and the index's rank view\n * sort by this value descending, placing records with an absent `rank` last.\n */\n readonly rank?: number;\n /** Structured provenance (never a flat enum). */\n readonly provenance: IProvenance;\n\n // --- Optional temporal block ---\n /** Bi-temporal validity. Present only on temporal kinds. */\n readonly temporal?: ITemporalBlock;\n\n /**\n * Vector-index entry reference, set by the vector index on write. `null` =\n * not embedded; absent = same as `null` (backwards-compat seam).\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is the explicit \"not embedded\" sentinel distinct from absent (backwards-compat seam); design-lock §2.5\n readonly embeddingRef?: string | null;\n}\n\n/**\n * A complete memory record: the invariant {@link IMemoryEnvelope} plus the\n * typed, per-kind body. The store's public surface uses\n * `IMemoryRecord<unknown>`; consumers narrow `TBody` by checking\n * `envelope.kind` and validating through the registered Converter.\n * @public\n */\nexport interface IMemoryRecord<TBody = unknown> {\n /** The invariant identity + transaction-time envelope. */\n readonly envelope: IMemoryEnvelope;\n /** The per-kind, Converter-validated body. */\n readonly body: TBody;\n}\n\n/**\n * A per-kind host projection from a fully-resolved (post-merge) memory record\n * to a numeric ordering value. Registered per kind at store construction (see\n * `rankProjectors`); the store runs it on every put/update over the same\n * resolved record whose `contentHash` it computes, stamping the result into\n * {@link IMemoryEnvelope.rank}. The store never interprets the body — the host\n * owns what the number means. A projector that throws is treated as \"no rank\n * for this record\" (logged at `warn`), never failing the write.\n * @public\n */\nexport type RankProjector = (record: IMemoryRecord<unknown>) => number;\n"]}
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../../src/packlets/types/envelope.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAmEH,sCAEC;AAZD;;;;;;;;;GASG;AACH,SAAgB,aAAa,CAAC,MAAmB;IAC/C,OAAO,GAAG,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC;AACzC,CAAC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { EntityId, Kind, LinkType, MemoryId, MemoryScopeKey, Tag } from './ids';\n\n/**\n * Origin of a provenance attribution. Open vocabulary: the three named\n * sources are conventional, but the `(string & {})` arm admits any other\n * source string without resignature.\n * @public\n */\nexport type ProvenanceSource = 'agent' | 'host-ingest' | 'human' | (string & {});\n\n/**\n * Structured provenance for a record or an edge. Never a flat enum — the\n * `[key: string]: unknown` index signature lets a consumer attach an opaque\n * domain payload (e.g. PersonAIlity's sentiment / epistemic blocks) without\n * changing this interface, while still satisfying the no-`any` rule.\n * @public\n */\nexport interface IProvenance {\n /** Where the attribution came from. */\n readonly source: ProvenanceSource;\n /** Optional human or agent identifier responsible for the write. */\n readonly by?: string;\n /** Optional model identifier, when a model produced the content. */\n readonly model?: string;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /**\n * Scope-qualified back-link to the source record. Enables the cross-kind\n * provenance spine. A scope-qualified {@link IEdgeTarget} (not a bare\n * {@link MemoryId}) because per-scope codecs (e.g. the MTM codec's `turn-<n>`\n * stems) legally reuse a stem across scopes, so a bare id would be ambiguous —\n * the same reason {@link IEdge.target} is scope-qualified.\n */\n readonly derivedFrom?: IEdgeTarget;\n /** Opaque extension payload — consumer-owned, never interpreted by the store. */\n readonly [key: string]: unknown;\n}\n\n/**\n * The physical address of a linked-to record: the `(scope, id)` pair that\n * uniquely identifies it. Both components are required because a bare\n * {@link MemoryId} is NOT unique across scopes — per-scope codecs (e.g. the\n * medium-term codec's `turn-<n>` stems) legally mint the same stem under\n * different scopes, so an edge that carried only the id would be ambiguous.\n * `(scope, id)` matches the store's `getById(scope, id)` addressing and the\n * index's composite primary key.\n * @public\n */\nexport interface IEdgeTarget {\n /** The scope the target record lives under. */\n readonly scope: MemoryScopeKey;\n /** The target record's stable file-stem id (unique WITHIN {@link IEdgeTarget.scope}). */\n readonly id: MemoryId;\n}\n\n/**\n * The canonical composite-key string for an {@link IEdgeTarget}: scope + id,\n * NUL-separated. NUL is excluded from both components (scope segments are\n * filename-safe; {@link MemoryId} is portable-filename-safe), so it is a\n * collision-proof separator. This is the ONE canonicalization every consumer\n * that keys on a scoped target uses — the backlink index, the cycle guard, and\n * the ingest edge-validation path all route through it so their notions of\n * \"same target\" cannot drift.\n * @public\n */\nexport function edgeTargetKey(target: IEdgeTarget): string {\n return `${target.scope}\\0${target.id}`;\n}\n\n/**\n * An attributed link between two records. Carries the relation type, the\n * scope-qualified {@link IEdgeTarget | target}, and optional confidence /\n * provenance / world-truth validity. Replaces bare string references (e.g.\n * PersonAIlity's `IMtmRef` becomes an `IEdge` with `type: LinkType('mtm-ref')`).\n * @public\n */\nexport interface IEdge {\n /** Open-vocabulary relation type. */\n readonly type: LinkType;\n /** The scope-qualified address of the linked-to record. */\n readonly target: IEdgeTarget;\n /** Optional confidence in `[0, 1]`. */\n readonly confidence?: number;\n /** Optional structured provenance for the link itself. */\n readonly provenance?: IProvenance;\n /** World-truth validity start (epoch ms). Present only on temporal edges. */\n readonly valid_at?: number;\n /**\n * World-truth validity end (epoch ms). `null` = still valid; absent = no\n * temporal extent.\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent (no temporal extent); design-lock §2.3\n readonly invalid_at?: number | null;\n}\n\n/**\n * Optional bi-temporal validity block on an envelope. Present only on\n * temporal kinds; absent = zero cost for atemporal kinds.\n * @public\n */\nexport interface ITemporalBlock {\n /** World-truth validity start (epoch ms). */\n readonly valid_at?: number;\n /** World-truth validity end (epoch ms). `null` = still valid. */\n // eslint-disable-next-line @rushstack/no-new-null -- null is a meaningful value here (still-valid) distinct from absent; design-lock §2.4\n readonly invalid_at?: number | null;\n}\n\n/**\n * The invariant identity + transaction-time envelope carried by every memory\n * record, independent of the per-kind body.\n * @public\n */\nexport interface IMemoryEnvelope {\n // --- Core identity ---\n /** Stable file-stem identifier. MUST equal the on-disk filename stem. */\n readonly id: MemoryId;\n /** Consumer-supplied domain key. Equals {@link IMemoryEnvelope.id | id} for non-temporal kinds. */\n readonly entityId: EntityId;\n /** Consumer-registered kind; dispatches the body Converter. */\n readonly kind: Kind;\n /** Open-vocabulary tags. */\n readonly tags: ReadonlyArray<Tag>;\n /** Attributed outbound edges. */\n readonly links: ReadonlyArray<IEdge>;\n\n // --- Transaction-time metadata (always present) ---\n /** Epoch ms of the first write. Immutable after creation. */\n readonly created: number;\n /** Epoch ms of the most recent write. */\n readonly updated: number;\n /**\n * Monotonic write counter within the store instance, assigned by the store\n * on every successful put. Enables stable cursor paging over observation\n * records without a full walk.\n */\n readonly seq: number;\n /**\n * Content hash over the canonical `{ kind, body, links }`. The dedup key:\n * an exact match is a no-op upsert that returns the existing record.\n */\n readonly contentHash: string;\n /**\n * Store-computed host-defined ordering value, produced by the kind's\n * {@link RankProjector} on every put/update and stamped into the envelope in\n * the same pass that recomputes {@link IMemoryEnvelope.contentHash | contentHash}.\n * Absent when the kind has no registered projector (or the projector threw on\n * this record). Ordered retrieval (`orderBy: 'rank'`) and the index's rank view\n * sort by this value descending, placing records with an absent `rank` last.\n *\n * **The projector runs on the write path only — registering one does not rank\n * records already in the store.** Because absent sorts last, those records land\n * below every subsequently-written one regardless of what the projector would\n * have scored them, so the result is not a partial ordering but one inverted\n * with respect to the projector's intent, with nothing failing to say so. Call\n * `IMemoryStore.reconcileRank` after registering a projector against a\n * populated store.\n */\n readonly rank?: number;\n /** Structured provenance (never a flat enum). */\n readonly provenance: IProvenance;\n\n // --- Optional temporal block ---\n /** Bi-temporal validity. Present only on temporal kinds. */\n readonly temporal?: ITemporalBlock;\n\n /**\n * Vector-index entry reference, set by the vector index on write. `null` =\n * not embedded; absent = same as `null` (backwards-compat seam).\n */\n // eslint-disable-next-line @rushstack/no-new-null -- null is the explicit \"not embedded\" sentinel distinct from absent (backwards-compat seam); design-lock §2.5\n readonly embeddingRef?: string | null;\n}\n\n/**\n * A complete memory record: the invariant {@link IMemoryEnvelope} plus the\n * typed, per-kind body. The store's public surface uses\n * `IMemoryRecord<unknown>`; consumers narrow `TBody` by checking\n * `envelope.kind` and validating through the registered Converter.\n * @public\n */\nexport interface IMemoryRecord<TBody = unknown> {\n /** The invariant identity + transaction-time envelope. */\n readonly envelope: IMemoryEnvelope;\n /** The per-kind, Converter-validated body. */\n readonly body: TBody;\n}\n\n/**\n * A per-kind host projection from a fully-resolved (post-merge) memory record\n * to a numeric ordering value. Registered per kind at store construction (see\n * `rankProjectors`); the store runs it on every put/update over the same\n * resolved record whose `contentHash` it computes, stamping the result into\n * {@link IMemoryEnvelope.rank}. The store never interprets the body — the host\n * owns what the number means. A projector that throws is treated as \"no rank\n * for this record\" (logged at `warn`), never failing the write.\n *\n * Runs on writes only. To apply a newly-registered projector to records that\n * already exist, call `IMemoryStore.reconcileRank`.\n * @public\n */\nexport type RankProjector = (record: IMemoryRecord<unknown>) => number;\n"]}
@@ -1,6 +1,6 @@
1
1
  import { Result } from '@fgv/ts-utils';
2
2
  import { IEdgeTarget } from '../types';
3
- import { IMemoryRecordSource, IVectorIndex, IVectorQueryHit, MemoryEmbedder } from './vectorIndex';
3
+ import { IMemoryRecordSource, IVectorIndex, IVectorQueryHit, IVectorRebuildOptions, IVectorRebuildReport, MemoryEmbedder } from './vectorIndex';
4
4
  /**
5
5
  * The brute-force, in-memory cosine {@link IVectorIndex}. Stores one
6
6
  * `Float32Array` per record and answers a query by computing cosine similarity
@@ -47,17 +47,40 @@ export declare class InMemoryCosineIndex implements IVectorIndex {
47
47
  /**
48
48
  * Re-embed every record from `source` and rebuild the index from scratch.
49
49
  * Clears the current contents (and the established dimension) first, so a
50
- * re-embed with a different model is supported. Returns the number of vectors
51
- * indexed.
50
+ * re-embed with a different model is supported. Returns an
51
+ * {@link IVectorRebuildReport} describing what was indexed, declined and skipped.
52
52
  *
53
- * On any failure (list, embed, or add) the index is rolled back to empty
54
- * rather than left in a partially-rebuilt state a caller that retries a query
55
- * after a failed rebuild sees a clean empty index, never a half-populated one.
53
+ * @remarks
54
+ * **A failure to LIST is always fatal**, under either mode and **leaves the
55
+ * existing index untouched**: an unreadable source says nothing about which
56
+ * records exist, so there is neither an honest partial to report nor any reason
57
+ * to discard what is already held.
58
+ *
59
+ * Per-record embed/add failures are governed by
60
+ * {@link IVectorRebuildOptions.onRecordError}, which defaults to `'fail'` —
61
+ * **the historical all-or-nothing contract, unchanged**: the index is rolled back
62
+ * to empty rather than left partially rebuilt, so a caller that retries a query
63
+ * sees a clean empty index it can reason about.
64
+ *
65
+ * `'skip'` opts into the lenient shape the store's own open already uses: the
66
+ * rebuild continues and every casualty is returned structurally on
67
+ * {@link IVectorRebuildReport.skipped}. **It reports more, it does not report
68
+ * less** — the point is to stop one bad record emptying an entire index, not to
69
+ * make failures quieter. A caller that ignores `skipped` under `'skip'` has
70
+ * chosen to, rather than been given no way to know.
71
+ *
72
+ * A {@link MemoryEmbedder} decline is not a failure under either mode: it is
73
+ * counted on {@link IVectorRebuildReport.declined} and never appears in `skipped`.
74
+ *
75
+ * Both consumer-supplied hooks are capture-wrapped, so a `source` or `embed`
76
+ * that throws or rejects becomes a `Failure` on the path above rather than an
77
+ * exception escaping mid-rebuild — which would bypass the rollback entirely.
56
78
  *
57
79
  * @param source - The scope-qualified record source to re-embed.
58
80
  * @param embed - The embedder applied to each record.
81
+ * @param options - Rebuild options; omit for the historical `'fail'` behavior.
59
82
  */
60
- rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder): Promise<Result<number>>;
83
+ rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder, options?: IVectorRebuildOptions): Promise<Result<IVectorRebuildReport>>;
61
84
  /** Empty the index and forget the established dimension. */
62
85
  private _reset;
63
86
  /** The Euclidean magnitude (L2 norm) of a vector. */
@@ -1 +1 @@
1
- {"version":3,"file":"inMemoryCosineIndex.d.ts","sourceRoot":"","sources":["../../../src/packlets/vector/inMemoryCosineIndex.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,WAAW,EAAiB,MAAM,UAAU,CAAC;AACtD,OAAO,EACL,mBAAmB,EAEnB,YAAY,EACZ,eAAe,EACf,cAAc,EACf,MAAM,eAAe,CAAC;AAQvB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,mBAAoB,YAAW,YAAY;IACtD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,+EAA+E;IAC/E,OAAO,CAAC,UAAU,CAAqB;IAEvC,OAAO;IAKP,4CAA4C;IAC5C,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,iCAAiC;WACnB,MAAM,IAAI,MAAM,CAAC,mBAAmB,CAAC;IAInD,qCAAqC;IAC9B,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAsB9E,wCAAwC;IACjC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAKhE,uCAAuC;IAChC,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;IAyBjG;;;;;;;;;;;;OAYG;IACU,OAAO,CAAC,MAAM,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IA0BjG,4DAA4D;IAC5D,OAAO,CAAC,MAAM;IAKd,qDAAqD;IACrD,OAAO,CAAC,MAAM,CAAC,UAAU;IAQzB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,OAAO;CAWvB"}
1
+ {"version":3,"file":"inMemoryCosineIndex.d.ts","sourceRoot":"","sources":["../../../src/packlets/vector/inMemoryCosineIndex.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAqC,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAiB,MAAM,UAAU,CAAC;AACtD,OAAO,EACL,mBAAmB,EAGnB,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACf,MAAM,eAAe,CAAC;AAkBvB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,mBAAoB,YAAW,YAAY;IACtD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,+EAA+E;IAC/E,OAAO,CAAC,UAAU,CAAqB;IAEvC,OAAO;IAKP,4CAA4C;IAC5C,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,iCAAiC;WACnB,MAAM,IAAI,MAAM,CAAC,mBAAmB,CAAC;IAInD,qCAAqC;IAC9B,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAsB9E,wCAAwC;IACjC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAKhE,uCAAuC;IAChC,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;IAyBjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACU,OAAO,CAClB,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAwDxC,4DAA4D;IAC5D,OAAO,CAAC,MAAM;IAKd,qDAAqD;IACrD,OAAO,CAAC,MAAM,CAAC,UAAU;IAQzB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,OAAO;CAWvB"}