@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,447 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- import { Result, fail, succeed } from '@fgv/ts-utils';
7
- import { Convert, EntityId, MemoryScopeKey } from './ids';
8
- import { assertPortableFilenameStem } from './filenameSafety';
9
-
10
- /**
11
- * The FileTree storage address an {@link IIdentityCodec} maps a domain key to.
12
- * @public
13
- */
14
- export interface IIdentityCodecResult {
15
- /** Scope path segment (may be multi-level, e.g. `conversations/<id>`). */
16
- readonly scope: MemoryScopeKey;
17
- /** Filename stem (the part before `.md`). Filename-safe after encoding. */
18
- readonly idStem: string;
19
- /**
20
- * Whether this kind uses a versioned layout (temporal: multiple files per
21
- * entity) vs. a flat layout (one file per entity). Non-temporal = always
22
- * `false`.
23
- */
24
- readonly isVersioned: boolean;
25
- }
26
-
27
- /**
28
- * Maps a consumer-supplied domain key ⇄ a FileTree storage address. Injected
29
- * per kind so the store never touches raw domain keys: the codec owns all
30
- * filename escaping and the flat-vs-versioned layout dispatch.
31
- * @public
32
- */
33
- export interface IIdentityCodec {
34
- /**
35
- * Encode a consumer-supplied entity id to a FileTree address. Deterministic
36
- * and pure — no I/O.
37
- */
38
- encode(entityId: EntityId): Result<IIdentityCodecResult>;
39
-
40
- /**
41
- * Decode a FileTree address back to the original {@link EntityId}. The exact
42
- * inverse of {@link IIdentityCodec.encode | encode} for non-versioned kinds.
43
- */
44
- decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId>;
45
-
46
- /**
47
- * Assert that `encode(decode(scope, stem)).idStem === stem`. Used by the
48
- * store's `verifyFilenameId` check on load.
49
- */
50
- verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true>;
51
- }
52
-
53
- /**
54
- * The `(entityId, version seq)` an {@link ITemporalIdentityCodec.decodeVersion}
55
- * recovers from a version file address.
56
- * @public
57
- */
58
- export interface ITemporalVersionAddress {
59
- /** The stable consumer-supplied domain key. */
60
- readonly entityId: EntityId;
61
- /** The version's monotonic `seq` (the `v<seq>` component of the file stem). */
62
- readonly seq: number;
63
- }
64
-
65
- /**
66
- * Additive extension of {@link IIdentityCodec} for versioned (temporal) kinds. A
67
- * codec whose {@link IIdentityCodec.encode | encode} reports `isVersioned: true`
68
- * implements this so the store can form and parse per-version filenames without
69
- * knowing the layout. Non-versioned codecs do NOT implement it (probe with
70
- * {@link isTemporalIdentityCodec}).
71
- * @public
72
- */
73
- export interface ITemporalIdentityCodec extends IIdentityCodec {
74
- /**
75
- * Form the version filename stem for a specific `(entityId, seq)`. The store
76
- * appends the extension and writes it under the entity subtree returned by
77
- * {@link IIdentityCodec.encode | encode}.
78
- */
79
- encodeVersion(entityId: EntityId, seq: number): Result<string>;
80
-
81
- /**
82
- * Parse a `(subtree scope, version stem)` back to its
83
- * {@link ITemporalVersionAddress}. The subtree scope is authoritative for the
84
- * `entityId`, disambiguating a stem whose `entityId` itself ends in
85
- * `-v<digits>`.
86
- */
87
- decodeVersion(scope: MemoryScopeKey, stem: string): Result<ITemporalVersionAddress>;
88
- }
89
-
90
- /**
91
- * Narrow an {@link IIdentityCodec} to {@link ITemporalIdentityCodec} by probing
92
- * for the versioned methods. Used by the store when an `encode` result reports
93
- * `isVersioned: true`.
94
- * @public
95
- */
96
- export function isTemporalIdentityCodec(codec: IIdentityCodec): codec is ITemporalIdentityCodec {
97
- const candidate: Partial<ITemporalIdentityCodec> = codec as Partial<ITemporalIdentityCodec>;
98
- return typeof candidate.encodeVersion === 'function' && typeof candidate.decodeVersion === 'function';
99
- }
100
-
101
- /**
102
- * Identity codec for a versioned (temporal) kind family, resolving OQ-11 to the
103
- * subtree-per-entity layout: every version of an entity is a distinct file under
104
- * a per-entity subtree.
105
- *
106
- * @remarks
107
- * - `encode`: scope = `<baseScope>/entities/<entityId>`, idStem = `<entityId>`,
108
- * `isVersioned = true`. The idStem is the stable entity prefix; the store forms
109
- * each version's filename via {@link TemporalIdentityCodec.encodeVersion}.
110
- * - `encodeVersion`: version stem = `<entityId>-v<seq>`.
111
- * - `decode` / `decodeVersion`: recover `entityId` (and `seq`) from a
112
- * `(subtree scope, version stem)` pair; the scope is authoritative for the
113
- * `entityId`.
114
- * - Escaping: `baseScope` and `entityId` must each match the POSIX portable
115
- * filename set (they become path segments); `seq` is a non-negative integer.
116
- * - Layout: `vault/<baseScope>/entities/<entityId>/<entityId>-v<seq>.md`.
117
- * @public
118
- */
119
- export class TemporalIdentityCodec implements ITemporalIdentityCodec {
120
- /** The fixed subtree segment separating an entity's versions from its scope. */
121
- public static readonly entitiesSegment: string = 'entities';
122
- /** The version-stem infix: `<entityId>` + this + `<seq>`. */
123
- public static readonly versionInfix: string = '-v';
124
-
125
- /** A non-negative integer string (the version seq). */
126
- private static readonly _versionSeqRe: RegExp = /^\d+$/;
127
-
128
- /** The base scope segment this codec's entities live under. */
129
- public readonly baseScope: string;
130
-
131
- private constructor(baseScope: string) {
132
- this.baseScope = baseScope;
133
- }
134
-
135
- /**
136
- * Family-convention factory. Validates that `baseScope` is a single portable
137
- * filename segment (it becomes the top-level path component).
138
- */
139
- public static create(baseScope: string): Result<TemporalIdentityCodec> {
140
- return assertPortableFilenameStem(baseScope)
141
- .withErrorFormat((msg) => `temporal codec: baseScope '${baseScope}': ${msg}`)
142
- .onSuccess(() => succeed(new TemporalIdentityCodec(baseScope)));
143
- }
144
-
145
- /** {@inheritDoc IIdentityCodec.encode} */
146
- public encode(entityId: EntityId): Result<IIdentityCodecResult> {
147
- return assertPortableFilenameStem(entityId)
148
- .withErrorFormat((msg) => `temporal codec: entityId '${entityId}': ${msg}`)
149
- .onSuccess((stem) =>
150
- succeed({
151
- scope: `${this.baseScope}/${TemporalIdentityCodec.entitiesSegment}/${stem}` as MemoryScopeKey,
152
- idStem: stem,
153
- isVersioned: true
154
- })
155
- );
156
- }
157
-
158
- /** {@inheritDoc ITemporalIdentityCodec.encodeVersion} */
159
- public encodeVersion(entityId: EntityId, seq: number): Result<string> {
160
- return assertPortableFilenameStem(entityId)
161
- .withErrorFormat((msg) => `temporal codec: entityId '${entityId}': ${msg}`)
162
- .onSuccess((stem) => {
163
- if (!Number.isInteger(seq) || seq < 0) {
164
- return fail(`temporal codec: version seq '${seq}' must be a non-negative integer`);
165
- }
166
- return succeed(`${stem}${TemporalIdentityCodec.versionInfix}${seq}`);
167
- });
168
- }
169
-
170
- /** {@inheritDoc IIdentityCodec.decode} */
171
- public decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId> {
172
- return this.decodeVersion(scope, encodedStem).onSuccess((addr) =>
173
- Convert.entityId.convert(addr.entityId)
174
- );
175
- }
176
-
177
- /** {@inheritDoc ITemporalIdentityCodec.decodeVersion} */
178
- public decodeVersion(scope: MemoryScopeKey, stem: string): Result<ITemporalVersionAddress> {
179
- return this._entityIdFromScope(scope).onSuccess((entityId) => {
180
- const prefix: string = `${entityId}${TemporalIdentityCodec.versionInfix}`;
181
- if (!stem.startsWith(prefix)) {
182
- return fail(
183
- `temporal codec: version stem '${stem}' must begin with '${prefix}' (from scope '${scope}')`
184
- );
185
- }
186
- const seqText: string = stem.slice(prefix.length);
187
- if (!TemporalIdentityCodec._versionSeqRe.test(seqText)) {
188
- return fail(`temporal codec: version stem '${stem}' has a non-integer version suffix '${seqText}'`);
189
- }
190
- // The regex admits digit strings of unbounded length; `parseInt` would silently
191
- // lose precision past MAX_SAFE_INTEGER, decoding a corrupt/tampered filename to a
192
- // plausible-but-wrong `seq` that drives version ordering. Reject rather than corrupt.
193
- const seq: number = Number.parseInt(seqText, 10);
194
- if (!Number.isSafeInteger(seq)) {
195
- return fail(
196
- `temporal codec: version stem '${stem}' has a version suffix '${seqText}' outside the safe integer range`
197
- );
198
- }
199
- return Convert.entityId.convert(entityId).onSuccess((branded) => succeed({ entityId: branded, seq }));
200
- });
201
- }
202
-
203
- /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
204
- public verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true> {
205
- return this.decodeVersion(scope, stem).onSuccess((addr) =>
206
- this.encode(addr.entityId).onSuccess((encoded) =>
207
- this.encodeVersion(addr.entityId, addr.seq).onSuccess((reStem) => {
208
- if (encoded.scope !== scope || reStem !== stem) {
209
- return fail(
210
- `temporal codec: round-trip mismatch for scope '${scope}' stem '${stem}' (re-encoded to scope '${encoded.scope}' stem '${reStem}')`
211
- );
212
- }
213
- return succeed(true);
214
- })
215
- )
216
- );
217
- }
218
-
219
- /** Validate and extract the `entityId` from a `<baseScope>/entities/<entityId>` scope. */
220
- private _entityIdFromScope(scope: MemoryScopeKey): Result<string> {
221
- const segments: string[] = scope.split('/');
222
- if (
223
- segments.length !== 3 ||
224
- segments[0] !== this.baseScope ||
225
- segments[1] !== TemporalIdentityCodec.entitiesSegment
226
- ) {
227
- return fail(
228
- `temporal codec: scope '${scope}' must be '${this.baseScope}/${TemporalIdentityCodec.entitiesSegment}/<entityId>'`
229
- );
230
- }
231
- const entityId: string = segments[2];
232
- return assertPortableFilenameStem(entityId)
233
- .withErrorFormat((msg) => `temporal codec: entityId '${entityId}': ${msg}`)
234
- .onSuccess(() => succeed(entityId));
235
- }
236
- }
237
-
238
- /**
239
- * Identity codec for the knowledge kind family. A knowledge entity is keyed
240
- * by its consumer-supplied `docId`, which is used verbatim as the filename
241
- * stem under the flat `knowledge` scope.
242
- *
243
- * @remarks
244
- * - `encode`: scope = `knowledge`, idStem = `docId`, `isVersioned = false`.
245
- * - `decode`: brands the stem back to an {@link EntityId}.
246
- * - Escaping: the `docId` must match the POSIX portable filename set.
247
- * - Layout: `vault/knowledge/<docId>.md`.
248
- * @public
249
- */
250
- export class KnowledgeIdentityCodec implements IIdentityCodec {
251
- /** The fixed scope for every knowledge entity. */
252
- public static readonly scope: MemoryScopeKey = 'knowledge' as MemoryScopeKey;
253
-
254
- /** {@inheritDoc IIdentityCodec.encode} */
255
- public encode(entityId: EntityId): Result<IIdentityCodecResult> {
256
- return assertPortableFilenameStem(entityId).onSuccess((idStem) =>
257
- succeed({ scope: KnowledgeIdentityCodec.scope, idStem, isVersioned: false })
258
- );
259
- }
260
-
261
- /** {@inheritDoc IIdentityCodec.decode} */
262
- public decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId> {
263
- if (scope !== KnowledgeIdentityCodec.scope) {
264
- return fail(
265
- `knowledge codec: scope '${scope}' does not match expected scope '${KnowledgeIdentityCodec.scope}'`
266
- );
267
- }
268
- return assertPortableFilenameStem(encodedStem).onSuccess((stem) => Convert.entityId.convert(stem));
269
- }
270
-
271
- /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
272
- public verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true> {
273
- return this.decode(scope, stem)
274
- .onSuccess((entityId) => this.encode(entityId))
275
- .onSuccess((encoded) => {
276
- /* c8 ignore start -- defensive: for the identity (knowledge) codec, encode(decode(stem)).idStem always equals stem when both succeed; the guard exists for the non-identity codecs (LTM/MTM, Phase C) that reuse this contract */
277
- if (encoded.idStem !== stem) {
278
- return fail(
279
- `knowledge codec: round-trip mismatch for stem '${stem}' (re-encoded to '${encoded.idStem}')`
280
- );
281
- }
282
- /* c8 ignore stop */
283
- return succeed(true);
284
- });
285
- }
286
- }
287
-
288
- /**
289
- * Identity codec for the long-term-memory (LTM) kind family. An LTM entity is
290
- * keyed by its `conversationId`, used verbatim as the filename stem under the
291
- * flat `conversations` scope.
292
- *
293
- * @remarks
294
- * - `encode`: scope = `conversations`, idStem = `conversationId`, `isVersioned = false`.
295
- * - `decode`: brands the stem back to an {@link EntityId}.
296
- * - Escaping: the `conversationId` must match the POSIX portable filename set.
297
- * - Layout: `vault/conversations/<conversationId>.md`.
298
- *
299
- * An LTM file (`conversations/<id>.md`) and the MTM subtree
300
- * (`conversations/<id>/turn-N.md`) coexist — a file and a same-named directory
301
- * are independent on every supported FileTree backend.
302
- * @public
303
- */
304
- export class LtmIdentityCodec implements IIdentityCodec {
305
- /** The fixed scope for every LTM entity. */
306
- public static readonly scope: MemoryScopeKey = 'conversations' as MemoryScopeKey;
307
-
308
- /** {@inheritDoc IIdentityCodec.encode} */
309
- public encode(entityId: EntityId): Result<IIdentityCodecResult> {
310
- return assertPortableFilenameStem(entityId).onSuccess((idStem) =>
311
- succeed({ scope: LtmIdentityCodec.scope, idStem, isVersioned: false })
312
- );
313
- }
314
-
315
- /** {@inheritDoc IIdentityCodec.decode} */
316
- public decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId> {
317
- if (scope !== LtmIdentityCodec.scope) {
318
- return fail(`LTM codec: scope '${scope}' does not match expected scope '${LtmIdentityCodec.scope}'`);
319
- }
320
- return assertPortableFilenameStem(encodedStem).onSuccess((stem) => Convert.entityId.convert(stem));
321
- }
322
-
323
- /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
324
- public verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true> {
325
- return this.decode(scope, stem)
326
- .onSuccess((entityId) => this.encode(entityId))
327
- .onSuccess((encoded) => {
328
- /* c8 ignore start -- defensive: LTM encode(decode(stem)).idStem always equals stem when both succeed (identity mapping); guard preserves the contract for direct callers */
329
- if (encoded.idStem !== stem) {
330
- return fail(
331
- `LTM codec: round-trip mismatch for stem '${stem}' (re-encoded to '${encoded.idStem}')`
332
- );
333
- }
334
- /* c8 ignore stop */
335
- return succeed(true);
336
- });
337
- }
338
- }
339
-
340
- /**
341
- * Identity codec for the medium-term-memory (MTM) kind family. An MTM entity is
342
- * keyed by the colon-composite `<conversationId>:<turnIndex>` and maps into a
343
- * per-conversation subtree.
344
- *
345
- * @remarks
346
- * - `encode`: splits the entity id on `:`; scope =
347
- * `conversations/<conversationId>` (multi-segment), idStem = `turn-<turnIndex>`,
348
- * `isVersioned = false`.
349
- * - `decode`: reverses scope `conversations/<id>` + stem `turn-<N>` to the
350
- * composite `<id>:<N>`.
351
- * - Escaping: `conversationId` must match the POSIX portable filename set (so it
352
- * contains no `/` or `:`); `turnIndex` must be a non-negative integer string,
353
- * preserved verbatim so the round-trip is exact.
354
- * - Layout: `vault/conversations/<conversationId>/turn-<N>.md`. The `/` in the
355
- * scope is handled by the store's multi-segment scope resolver.
356
- *
357
- * **Verbatim turn index (caller-canonicalization note).** The turn index is
358
- * preserved exactly — `conv-1:7` and `conv-1:007` are DISTINCT entities mapping
359
- * to distinct files (`turn-7.md` / `turn-007.md`). Verbatim preservation is what
360
- * makes the round-trip exact, but it means a caller that formats turn indices
361
- * inconsistently (some zero-padded, some not) will silently mint separate
362
- * entities. Callers should canonicalize to one form (e.g. no leading zeros).
363
- * @public
364
- */
365
- export class MtmIdentityCodec implements IIdentityCodec {
366
- /** The top-level scope segment under which every MTM subtree lives. */
367
- public static readonly rootScopeSegment: string = 'conversations';
368
- /** The fixed filename-stem prefix for a turn record. */
369
- public static readonly turnStemPrefix: string = 'turn-';
370
-
371
- /** A non-negative integer string (the turn index), preserved verbatim. */
372
- private static readonly _turnIndexRe: RegExp = /^\d+$/;
373
-
374
- /** {@inheritDoc IIdentityCodec.encode} */
375
- public encode(entityId: EntityId): Result<IIdentityCodecResult> {
376
- const parts: string[] = entityId.split(':');
377
- if (parts.length !== 2) {
378
- return fail(`MTM codec: entity id '${entityId}' must be a '<conversationId>:<turnIndex>' composite`);
379
- }
380
- const [conversationId, turnIndex] = parts;
381
- return assertPortableFilenameStem(conversationId)
382
- .withErrorFormat((msg) => `MTM codec: conversationId '${conversationId}': ${msg}`)
383
- .onSuccess(() => MtmIdentityCodec._assertTurnIndex(turnIndex))
384
- .onSuccess(() =>
385
- succeed({
386
- scope: `${MtmIdentityCodec.rootScopeSegment}/${conversationId}` as MemoryScopeKey,
387
- idStem: `${MtmIdentityCodec.turnStemPrefix}${turnIndex}`,
388
- isVersioned: false
389
- })
390
- );
391
- }
392
-
393
- /** {@inheritDoc IIdentityCodec.decode} */
394
- public decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId> {
395
- return MtmIdentityCodec._conversationIdFromScope(scope).onSuccess((conversationId) =>
396
- MtmIdentityCodec._turnIndexFromStem(encodedStem).onSuccess((turnIndex) =>
397
- Convert.entityId.convert(`${conversationId}:${turnIndex}`)
398
- )
399
- );
400
- }
401
-
402
- /** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
403
- public verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true> {
404
- return this.decode(scope, stem)
405
- .onSuccess((entityId) => this.encode(entityId))
406
- .onSuccess((encoded) => {
407
- /* c8 ignore start -- defensive: MTM encode(decode(scope, stem)) reproduces the same scope+stem whenever both succeed (no normalization); guard preserves the contract for direct callers */
408
- if (encoded.idStem !== stem || encoded.scope !== scope) {
409
- return fail(
410
- `MTM codec: round-trip mismatch for scope '${scope}' stem '${stem}' (re-encoded to scope '${encoded.scope}' stem '${encoded.idStem}')`
411
- );
412
- }
413
- /* c8 ignore stop */
414
- return succeed(true);
415
- });
416
- }
417
-
418
- /** Validate and extract the `conversationId` from a `conversations/<id>` scope. */
419
- private static _conversationIdFromScope(scope: MemoryScopeKey): Result<string> {
420
- const segments: string[] = scope.split('/');
421
- if (segments.length !== 2 || segments[0] !== MtmIdentityCodec.rootScopeSegment) {
422
- return fail(
423
- `MTM codec: scope '${scope}' must be '${MtmIdentityCodec.rootScopeSegment}/<conversationId>'`
424
- );
425
- }
426
- const conversationId: string = segments[1];
427
- return assertPortableFilenameStem(conversationId)
428
- .withErrorFormat((msg) => `MTM codec: conversationId '${conversationId}': ${msg}`)
429
- .onSuccess(() => succeed(conversationId));
430
- }
431
-
432
- /** Validate and extract the turn-index digits from a `turn-<N>` stem. */
433
- private static _turnIndexFromStem(stem: string): Result<string> {
434
- if (!stem.startsWith(MtmIdentityCodec.turnStemPrefix)) {
435
- return fail(`MTM codec: stem '${stem}' must begin with '${MtmIdentityCodec.turnStemPrefix}'`);
436
- }
437
- return MtmIdentityCodec._assertTurnIndex(stem.slice(MtmIdentityCodec.turnStemPrefix.length));
438
- }
439
-
440
- /** Assert a string is a non-negative integer (the turn index). */
441
- private static _assertTurnIndex(turnIndex: string): Result<string> {
442
- if (!MtmIdentityCodec._turnIndexRe.test(turnIndex)) {
443
- return fail(`MTM codec: turnIndex '${turnIndex}' must be a non-negative integer`);
444
- }
445
- return succeed(turnIndex);
446
- }
447
- }
@@ -1,124 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- import { Brand, Converter, Converters, Result, fail, succeed } from '@fgv/ts-utils';
7
- import { assertPortableFilenameStem } from './filenameSafety';
8
-
9
- /**
10
- * Stable file-stem identifier for a memory record. Equals the codec-produced
11
- * `idStem` and the on-disk filename stem (`verifyFilenameId` enforces the
12
- * round-trip).
13
- * @public
14
- */
15
- export type MemoryId = Brand<string, 'MemoryId'>;
16
-
17
- /**
18
- * Consumer-supplied domain key. The stable entity identity across versions;
19
- * the package never mints identity. Equals {@link MemoryId} for non-temporal
20
- * kinds.
21
- * @public
22
- */
23
- export type EntityId = Brand<string, 'EntityId'>;
24
-
25
- /**
26
- * Open-vocabulary record classifier. Consumers register one body
27
- * {@link https://www.npmjs.com/package/@fgv/ts-utils | Converter} per kind.
28
- * @public
29
- */
30
- export type Kind = Brand<string, 'Kind'>;
31
-
32
- /**
33
- * Open-vocabulary tag label.
34
- * @public
35
- */
36
- export type Tag = Brand<string, 'Tag'>;
37
-
38
- /**
39
- * Scope path segment. May be multi-segment (`/`-separated) for kinds whose
40
- * codec maps an entity into a sub-tree (e.g. MTM: `conversations/<id>`). The
41
- * codec — not this brand — owns filename-safe escaping, so the converter
42
- * validates only the non-empty/length/whitespace hygiene shared by every
43
- * brand.
44
- * @public
45
- */
46
- export type MemoryScopeKey = Brand<string, 'MemoryScopeKey'>;
47
-
48
- /**
49
- * Open-vocabulary link-relation type for an attributed {@link IEdge}.
50
- * @public
51
- */
52
- export type LinkType = Brand<string, 'LinkType'>;
53
-
54
- /**
55
- * Maximum length of any branded identifier in the library. Picked to be
56
- * larger than any reasonable id a consumer would supply while still bounded
57
- * to defuse adversarial inputs (e.g. multi-megabyte ids used as map keys).
58
- */
59
- const MAX_BRAND_LENGTH: number = 256;
60
-
61
- /**
62
- * Builds a `Converter` for one of the branded id scalars in this library.
63
- * All brands share the same hygiene: non-empty, length-capped, and free of
64
- * leading/trailing whitespace. Filename-safety and single-segment
65
- * constraints are intentionally NOT enforced here — the per-kind
66
- * {@link IIdentityCodec} owns escaping so that multi-segment scope keys
67
- * (`conversations/<id>`) and composite entity ids (`<id>:<turn>`) validate
68
- * cleanly.
69
- *
70
- * Not exported — the per-brand `Convert.<brand>` constants are the public
71
- * surface.
72
- */
73
- function brandedIdConverter<T extends string>(brand: string): Converter<T> {
74
- return Converters.string.map((from: string): Result<T> => {
75
- if (from.length === 0) {
76
- return fail(`${brand}: must be a non-empty string`);
77
- }
78
- if (from.length > MAX_BRAND_LENGTH) {
79
- return fail(`${brand}: exceeds maximum length ${MAX_BRAND_LENGTH} (got ${from.length})`);
80
- }
81
- if (from !== from.trim()) {
82
- return fail(`${brand}: must not have leading or trailing whitespace`);
83
- }
84
- return succeed(from as unknown as T);
85
- });
86
- }
87
-
88
- /**
89
- * Converters for the branded identifier scalars. Each validates an `unknown`
90
- * value into the corresponding brand, enforcing the shared hygiene
91
- * (non-empty, length-capped, trimmed).
92
- * @public
93
- */
94
- export const Convert: {
95
- readonly memoryId: Converter<MemoryId>;
96
- readonly entityId: Converter<EntityId>;
97
- readonly kind: Converter<Kind>;
98
- readonly tag: Converter<Tag>;
99
- readonly scopeKey: Converter<MemoryScopeKey>;
100
- readonly linkType: Converter<LinkType>;
101
- } = {
102
- /**
103
- * Validates an `unknown` value as a {@link MemoryId}. Unlike the other
104
- * brands, `MemoryId` IS the on-disk filename stem (`id === idStem`, enforced
105
- * by the store's `verifyFilenameId`), so it additionally enforces the
106
- * portable-filename-stem contract — rejecting path-unsafe ids (`a/b`,
107
- * `conv-1:7`) at convert time rather than letting them surface as a file-path
108
- * failure later. (`EntityId` stays relaxed: a domain key may legitimately be
109
- * a composite like `conv-1:7`; the codec maps it to a safe stem.)
110
- */
111
- memoryId: brandedIdConverter<MemoryId>('MemoryId').map((id) =>
112
- assertPortableFilenameStem(id).onSuccess(() => succeed(id))
113
- ),
114
- /** Validates an `unknown` value as an {@link EntityId}. */
115
- entityId: brandedIdConverter<EntityId>('EntityId'),
116
- /** Validates an `unknown` value as a {@link Kind}. */
117
- kind: brandedIdConverter<Kind>('Kind'),
118
- /** Validates an `unknown` value as a {@link Tag}. */
119
- tag: brandedIdConverter<Tag>('Tag'),
120
- /** Validates an `unknown` value as a {@link MemoryScopeKey}. */
121
- scopeKey: brandedIdConverter<MemoryScopeKey>('MemoryScopeKey'),
122
- /** Validates an `unknown` value as a {@link LinkType}. */
123
- linkType: brandedIdConverter<LinkType>('LinkType')
124
- } as const;
@@ -1,11 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- export * from './ids';
7
- export * from './envelope';
8
- export * from './filenameSafety';
9
- export * from './identityCodec';
10
- export * from './temporal';
11
- export * from './writePolicy';
@@ -1,96 +0,0 @@
1
- /*
2
- * Copyright (c) 2026 Erik Fortune
3
- * SPDX-License-Identifier: MIT
4
- */
5
-
6
- import { IMemoryRecord } from './envelope';
7
-
8
- /**
9
- * Whether a record participates in the versioned (temporal) layout. A temporal
10
- * record always carries a {@link ITemporalBlock | temporal} block (the store
11
- * stamps `valid_at` on every versioned write); an atemporal record never does,
12
- * so presence of `temporal` is the discriminator. Independent of `id`/`entityId`
13
- * divergence (MTM is flat yet has `entityId !== id`).
14
- * @public
15
- */
16
- export function isTemporalRecord(record: IMemoryRecord<unknown>): boolean {
17
- return record.envelope.temporal !== undefined;
18
- }
19
-
20
- /**
21
- * Whether a temporal record is a *current* version — its `temporal.invalid_at`
22
- * is `null` or absent (the still-valid sentinel). A non-temporal record is never
23
- * current in this sense (returns `false`).
24
- * @public
25
- */
26
- export function isVersionCurrent(record: IMemoryRecord<unknown>): boolean {
27
- const temporal: IMemoryRecord<unknown>['envelope']['temporal'] = record.envelope.temporal;
28
- if (temporal === undefined) {
29
- return false;
30
- }
31
- return temporal.invalid_at === null || temporal.invalid_at === undefined;
32
- }
33
-
34
- /**
35
- * Whether a temporal record's validity interval contains `asOf` (epoch ms):
36
- * `valid_at <= asOf` and (`invalid_at` is null/absent OR `asOf < invalid_at`).
37
- * The version's `valid_at` defaults to its `created` when absent; a non-temporal
38
- * record is never "valid at" a point (returns `false`).
39
- * @public
40
- */
41
- export function isVersionValidAt(record: IMemoryRecord<unknown>, asOf: number): boolean {
42
- const temporal: IMemoryRecord<unknown>['envelope']['temporal'] = record.envelope.temporal;
43
- if (temporal === undefined) {
44
- return false;
45
- }
46
- const start: number = temporal.valid_at ?? record.envelope.created;
47
- if (start > asOf) {
48
- return false;
49
- }
50
- const end: number | null | undefined = temporal.invalid_at;
51
- if (end === null || end === undefined) {
52
- return true;
53
- }
54
- return asOf < end;
55
- }
56
-
57
- /**
58
- * The version with the highest `seq` among `candidates` (undefined when empty).
59
- * `seq` is the store's monotonic write counter, so highest `seq` is the newest
60
- * version. Shared tiebreak for {@link selectCurrentVersion} /
61
- * {@link selectVersionAsOf}.
62
- */
63
- function highestSeq(candidates: ReadonlyArray<IMemoryRecord<unknown>>): IMemoryRecord<unknown> | undefined {
64
- let best: IMemoryRecord<unknown> | undefined;
65
- for (const candidate of candidates) {
66
- if (best === undefined || candidate.envelope.seq > best.envelope.seq) {
67
- best = candidate;
68
- }
69
- }
70
- return best;
71
- }
72
-
73
- /**
74
- * Select the current version from a set of an entity's versions: the newest
75
- * (highest `seq`) version whose `invalid_at` is null/absent. `undefined` when the
76
- * entity has no current version (fully invalidated / soft-deleted, or empty).
77
- * @public
78
- */
79
- export function selectCurrentVersion(
80
- versions: ReadonlyArray<IMemoryRecord<unknown>>
81
- ): IMemoryRecord<unknown> | undefined {
82
- return highestSeq(versions.filter(isVersionCurrent));
83
- }
84
-
85
- /**
86
- * Select the version of an entity valid at `asOf` (epoch ms): the newest
87
- * (highest `seq`) version whose validity interval contains `asOf`. `undefined`
88
- * when no version was valid at that instant.
89
- * @public
90
- */
91
- export function selectVersionAsOf(
92
- versions: ReadonlyArray<IMemoryRecord<unknown>>,
93
- asOf: number
94
- ): IMemoryRecord<unknown> | undefined {
95
- return highestSeq(versions.filter((version) => isVersionValidAt(version, asOf)));
96
- }