@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.
- package/dist/packlets/ingest/orchestrator.js +11 -1
- package/dist/packlets/ingest/orchestrator.js.map +1 -1
- package/dist/packlets/observe/memoryObservationStore.js +6 -0
- package/dist/packlets/observe/memoryObservationStore.js.map +1 -1
- package/dist/packlets/observe/observer.js.map +1 -1
- package/dist/packlets/retrieve/linkTraversalRetriever.js +1 -1
- package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
- package/dist/packlets/retrieve/recencyRetriever.js +1 -1
- package/dist/packlets/retrieve/recencyRetriever.js.map +1 -1
- package/dist/packlets/retrieve/retriever.js +11 -5
- package/dist/packlets/retrieve/retriever.js.map +1 -1
- package/dist/packlets/retrieve/structuredFilterRetriever.js +27 -5
- package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
- package/dist/packlets/retrieve/tagRetriever.js +1 -1
- package/dist/packlets/retrieve/tagRetriever.js.map +1 -1
- package/dist/packlets/retrieve/temporalRetrievers.js +1 -1
- package/dist/packlets/retrieve/temporalRetrievers.js.map +1 -1
- package/dist/packlets/store/fileTreeMemoryStore.js +152 -132
- package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/dist/packlets/store/vectorMaintenance.js +251 -0
- package/dist/packlets/store/vectorMaintenance.js.map +1 -0
- package/dist/packlets/types/envelope.js.map +1 -1
- package/dist/packlets/vector/inMemoryCosineIndex.js +81 -18
- package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -1
- package/dist/packlets/vector/inMemoryFragmentCosineIndex.js +7 -0
- package/dist/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
- package/dist/packlets/vector/vectorIndex.js.map +1 -1
- package/dist/ts-agent-memory.d.ts +431 -79
- package/lib/packlets/ingest/orchestrator.d.ts.map +1 -1
- package/lib/packlets/ingest/orchestrator.js +11 -1
- package/lib/packlets/ingest/orchestrator.js.map +1 -1
- package/lib/packlets/observe/memoryObservationStore.d.ts.map +1 -1
- package/lib/packlets/observe/memoryObservationStore.js +6 -0
- package/lib/packlets/observe/memoryObservationStore.js.map +1 -1
- package/lib/packlets/observe/observer.d.ts +61 -0
- package/lib/packlets/observe/observer.d.ts.map +1 -1
- package/lib/packlets/observe/observer.js.map +1 -1
- package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +1 -1
- package/lib/packlets/retrieve/linkTraversalRetriever.js +1 -1
- package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
- package/lib/packlets/retrieve/recencyRetriever.d.ts +1 -1
- package/lib/packlets/retrieve/recencyRetriever.js +1 -1
- package/lib/packlets/retrieve/recencyRetriever.js.map +1 -1
- package/lib/packlets/retrieve/retriever.d.ts +26 -7
- package/lib/packlets/retrieve/retriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/retriever.js +11 -5
- package/lib/packlets/retrieve/retriever.js.map +1 -1
- package/lib/packlets/retrieve/structuredFilterRetriever.d.ts +26 -4
- package/lib/packlets/retrieve/structuredFilterRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/structuredFilterRetriever.js +27 -5
- package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
- package/lib/packlets/retrieve/tagRetriever.d.ts +1 -1
- package/lib/packlets/retrieve/tagRetriever.js +1 -1
- package/lib/packlets/retrieve/tagRetriever.js.map +1 -1
- package/lib/packlets/retrieve/temporalRetrievers.js +1 -1
- package/lib/packlets/retrieve/temporalRetrievers.js.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.d.ts +135 -59
- package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.js +151 -131
- package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/lib/packlets/store/vectorMaintenance.d.ts +149 -0
- package/lib/packlets/store/vectorMaintenance.d.ts.map +1 -0
- package/lib/packlets/store/vectorMaintenance.js +255 -0
- package/lib/packlets/store/vectorMaintenance.js.map +1 -0
- package/lib/packlets/types/envelope.d.ts +11 -0
- package/lib/packlets/types/envelope.d.ts.map +1 -1
- package/lib/packlets/types/envelope.js.map +1 -1
- package/lib/packlets/vector/inMemoryCosineIndex.d.ts +30 -7
- package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -1
- package/lib/packlets/vector/inMemoryCosineIndex.js +80 -17
- package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -1
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts +7 -0
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts.map +1 -1
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.js +7 -0
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
- package/lib/packlets/vector/vectorIndex.d.ts +129 -1
- package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
- package/lib/packlets/vector/vectorIndex.js.map +1 -1
- package/package.json +17 -7
- package/.rush/temp/5667e36f1c0cc503a5c20a3ebff76e7b9a702d41.tar.log +0 -468
- package/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +0 -9
- package/.rush/temp/operation/build/all.log +0 -9
- package/.rush/temp/operation/build/log-chunks.jsonl +0 -9
- package/.rush/temp/operation/build/state.json +0 -3
- package/.rush/temp/shrinkwrap-deps.json +0 -689
- package/config/api-extractor.json +0 -343
- package/config/jest.config.json +0 -14
- package/config/rig.json +0 -4
- package/dist/test/unit/converters/antagonistRoundTrip.test.js +0 -95
- package/dist/test/unit/converters/antagonistRoundTrip.test.js.map +0 -1
- package/dist/test/unit/converters/bodyConverterRegistry.test.js +0 -72
- package/dist/test/unit/converters/bodyConverterRegistry.test.js.map +0 -1
- package/dist/test/unit/converters/envelopeConverter.test.js +0 -313
- package/dist/test/unit/converters/envelopeConverter.test.js.map +0 -1
- package/dist/test/unit/index/memoryIndex.test.js +0 -214
- package/dist/test/unit/index/memoryIndex.test.js.map +0 -1
- package/dist/test/unit/ingest/antagonistCycleAndParity.test.js +0 -277
- package/dist/test/unit/ingest/antagonistCycleAndParity.test.js.map +0 -1
- package/dist/test/unit/ingest/cycleGuard.test.js +0 -81
- package/dist/test/unit/ingest/cycleGuard.test.js.map +0 -1
- package/dist/test/unit/ingest/dedupScope.test.js +0 -434
- package/dist/test/unit/ingest/dedupScope.test.js.map +0 -1
- package/dist/test/unit/ingest/orchestrator.test.js +0 -1058
- package/dist/test/unit/ingest/orchestrator.test.js.map +0 -1
- package/dist/test/unit/observe/memoryObservationStore.test.js +0 -118
- package/dist/test/unit/observe/memoryObservationStore.test.js.map +0 -1
- package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js +0 -116
- package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +0 -1
- package/dist/test/unit/retrieve/linkTraversalRetriever.test.js +0 -257
- package/dist/test/unit/retrieve/linkTraversalRetriever.test.js.map +0 -1
- package/dist/test/unit/retrieve/retrievers.test.js +0 -768
- package/dist/test/unit/retrieve/retrievers.test.js.map +0 -1
- package/dist/test/unit/retrieve/temporalRetrievers.test.js +0 -182
- package/dist/test/unit/retrieve/temporalRetrievers.test.js.map +0 -1
- package/dist/test/unit/store/antagonistTemporalBoundary.test.js +0 -120
- package/dist/test/unit/store/antagonistTemporalBoundary.test.js.map +0 -1
- package/dist/test/unit/store/embedOnWrite.test.js +0 -317
- package/dist/test/unit/store/embedOnWrite.test.js.map +0 -1
- package/dist/test/unit/store/fileTreeMemoryStore.test.js +0 -778
- package/dist/test/unit/store/fileTreeMemoryStore.test.js.map +0 -1
- package/dist/test/unit/store/fragmentEmbedOnWrite.test.js +0 -255
- package/dist/test/unit/store/fragmentEmbedOnWrite.test.js.map +0 -1
- package/dist/test/unit/store/indexInjection.test.js +0 -432
- package/dist/test/unit/store/indexInjection.test.js.map +0 -1
- package/dist/test/unit/store/lenientOpen.test.js +0 -248
- package/dist/test/unit/store/lenientOpen.test.js.map +0 -1
- package/dist/test/unit/store/listScoped.test.js +0 -109
- package/dist/test/unit/store/listScoped.test.js.map +0 -1
- package/dist/test/unit/store/observations.test.js +0 -239
- package/dist/test/unit/store/observations.test.js.map +0 -1
- package/dist/test/unit/store/rankAxis.test.js +0 -254
- package/dist/test/unit/store/rankAxis.test.js.map +0 -1
- package/dist/test/unit/store/scopeEncoding.test.js +0 -24
- package/dist/test/unit/store/scopeEncoding.test.js.map +0 -1
- package/dist/test/unit/store/temporalStore.test.js +0 -398
- package/dist/test/unit/store/temporalStore.test.js.map +0 -1
- package/dist/test/unit/tools/memoryTools.test.js +0 -842
- package/dist/test/unit/tools/memoryTools.test.js.map +0 -1
- package/dist/test/unit/types/identityCodec.test.js +0 -187
- package/dist/test/unit/types/identityCodec.test.js.map +0 -1
- package/dist/test/unit/types/ids.test.js +0 -84
- package/dist/test/unit/types/ids.test.js.map +0 -1
- package/dist/test/unit/types/temporalCodec.test.js +0 -203
- package/dist/test/unit/types/temporalCodec.test.js.map +0 -1
- package/dist/test/unit/types/temporalPolicy.test.js +0 -83
- package/dist/test/unit/types/temporalPolicy.test.js.map +0 -1
- package/dist/test/unit/types/writePolicy.test.js +0 -331
- package/dist/test/unit/types/writePolicy.test.js.map +0 -1
- package/dist/test/unit/vector/fragmentConverters.test.js +0 -58
- package/dist/test/unit/vector/fragmentConverters.test.js.map +0 -1
- package/dist/test/unit/vector/inMemoryCosineIndex.test.js +0 -252
- package/dist/test/unit/vector/inMemoryCosineIndex.test.js.map +0 -1
- package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js +0 -362
- package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +0 -1
- package/dist/test/unit/vector/vectorIndex.test.js +0 -51
- package/dist/test/unit/vector/vectorIndex.test.js.map +0 -1
- package/eslint.config.js +0 -15
- package/etc/ts-agent-memory.api.md +0 -940
- package/lib/test/unit/converters/antagonistRoundTrip.test.d.ts +0 -10
- package/lib/test/unit/converters/antagonistRoundTrip.test.d.ts.map +0 -1
- package/lib/test/unit/converters/antagonistRoundTrip.test.js +0 -97
- package/lib/test/unit/converters/antagonistRoundTrip.test.js.map +0 -1
- package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts +0 -2
- package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts.map +0 -1
- package/lib/test/unit/converters/bodyConverterRegistry.test.js +0 -74
- package/lib/test/unit/converters/bodyConverterRegistry.test.js.map +0 -1
- package/lib/test/unit/converters/envelopeConverter.test.d.ts +0 -2
- package/lib/test/unit/converters/envelopeConverter.test.d.ts.map +0 -1
- package/lib/test/unit/converters/envelopeConverter.test.js +0 -315
- package/lib/test/unit/converters/envelopeConverter.test.js.map +0 -1
- package/lib/test/unit/index/memoryIndex.test.d.ts +0 -2
- package/lib/test/unit/index/memoryIndex.test.d.ts.map +0 -1
- package/lib/test/unit/index/memoryIndex.test.js +0 -216
- package/lib/test/unit/index/memoryIndex.test.js.map +0 -1
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.d.ts +0 -9
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.d.ts.map +0 -1
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.js +0 -279
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.js.map +0 -1
- package/lib/test/unit/ingest/cycleGuard.test.d.ts +0 -2
- package/lib/test/unit/ingest/cycleGuard.test.d.ts.map +0 -1
- package/lib/test/unit/ingest/cycleGuard.test.js +0 -83
- package/lib/test/unit/ingest/cycleGuard.test.js.map +0 -1
- package/lib/test/unit/ingest/dedupScope.test.d.ts +0 -2
- package/lib/test/unit/ingest/dedupScope.test.d.ts.map +0 -1
- package/lib/test/unit/ingest/dedupScope.test.js +0 -436
- package/lib/test/unit/ingest/dedupScope.test.js.map +0 -1
- package/lib/test/unit/ingest/orchestrator.test.d.ts +0 -2
- package/lib/test/unit/ingest/orchestrator.test.d.ts.map +0 -1
- package/lib/test/unit/ingest/orchestrator.test.js +0 -1060
- package/lib/test/unit/ingest/orchestrator.test.js.map +0 -1
- package/lib/test/unit/observe/memoryObservationStore.test.d.ts +0 -2
- package/lib/test/unit/observe/memoryObservationStore.test.d.ts.map +0 -1
- package/lib/test/unit/observe/memoryObservationStore.test.js +0 -120
- package/lib/test/unit/observe/memoryObservationStore.test.js.map +0 -1
- package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts +0 -2
- package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts.map +0 -1
- package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js +0 -118
- package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +0 -1
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts +0 -2
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts.map +0 -1
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.js +0 -259
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.js.map +0 -1
- package/lib/test/unit/retrieve/retrievers.test.d.ts +0 -2
- package/lib/test/unit/retrieve/retrievers.test.d.ts.map +0 -1
- package/lib/test/unit/retrieve/retrievers.test.js +0 -770
- package/lib/test/unit/retrieve/retrievers.test.js.map +0 -1
- package/lib/test/unit/retrieve/temporalRetrievers.test.d.ts +0 -2
- package/lib/test/unit/retrieve/temporalRetrievers.test.d.ts.map +0 -1
- package/lib/test/unit/retrieve/temporalRetrievers.test.js +0 -184
- package/lib/test/unit/retrieve/temporalRetrievers.test.js.map +0 -1
- package/lib/test/unit/store/antagonistTemporalBoundary.test.d.ts +0 -9
- package/lib/test/unit/store/antagonistTemporalBoundary.test.d.ts.map +0 -1
- package/lib/test/unit/store/antagonistTemporalBoundary.test.js +0 -122
- package/lib/test/unit/store/antagonistTemporalBoundary.test.js.map +0 -1
- package/lib/test/unit/store/embedOnWrite.test.d.ts +0 -2
- package/lib/test/unit/store/embedOnWrite.test.d.ts.map +0 -1
- package/lib/test/unit/store/embedOnWrite.test.js +0 -319
- package/lib/test/unit/store/embedOnWrite.test.js.map +0 -1
- package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts +0 -2
- package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts.map +0 -1
- package/lib/test/unit/store/fileTreeMemoryStore.test.js +0 -780
- package/lib/test/unit/store/fileTreeMemoryStore.test.js.map +0 -1
- package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts +0 -2
- package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts.map +0 -1
- package/lib/test/unit/store/fragmentEmbedOnWrite.test.js +0 -257
- package/lib/test/unit/store/fragmentEmbedOnWrite.test.js.map +0 -1
- package/lib/test/unit/store/indexInjection.test.d.ts +0 -2
- package/lib/test/unit/store/indexInjection.test.d.ts.map +0 -1
- package/lib/test/unit/store/indexInjection.test.js +0 -434
- package/lib/test/unit/store/indexInjection.test.js.map +0 -1
- package/lib/test/unit/store/lenientOpen.test.d.ts +0 -2
- package/lib/test/unit/store/lenientOpen.test.d.ts.map +0 -1
- package/lib/test/unit/store/lenientOpen.test.js +0 -250
- package/lib/test/unit/store/lenientOpen.test.js.map +0 -1
- package/lib/test/unit/store/listScoped.test.d.ts +0 -2
- package/lib/test/unit/store/listScoped.test.d.ts.map +0 -1
- package/lib/test/unit/store/listScoped.test.js +0 -111
- package/lib/test/unit/store/listScoped.test.js.map +0 -1
- package/lib/test/unit/store/observations.test.d.ts +0 -2
- package/lib/test/unit/store/observations.test.d.ts.map +0 -1
- package/lib/test/unit/store/observations.test.js +0 -241
- package/lib/test/unit/store/observations.test.js.map +0 -1
- package/lib/test/unit/store/rankAxis.test.d.ts +0 -2
- package/lib/test/unit/store/rankAxis.test.d.ts.map +0 -1
- package/lib/test/unit/store/rankAxis.test.js +0 -256
- package/lib/test/unit/store/rankAxis.test.js.map +0 -1
- package/lib/test/unit/store/scopeEncoding.test.d.ts +0 -2
- package/lib/test/unit/store/scopeEncoding.test.d.ts.map +0 -1
- package/lib/test/unit/store/scopeEncoding.test.js +0 -26
- package/lib/test/unit/store/scopeEncoding.test.js.map +0 -1
- package/lib/test/unit/store/temporalStore.test.d.ts +0 -2
- package/lib/test/unit/store/temporalStore.test.d.ts.map +0 -1
- package/lib/test/unit/store/temporalStore.test.js +0 -400
- package/lib/test/unit/store/temporalStore.test.js.map +0 -1
- package/lib/test/unit/tools/memoryTools.test.d.ts +0 -2
- package/lib/test/unit/tools/memoryTools.test.d.ts.map +0 -1
- package/lib/test/unit/tools/memoryTools.test.js +0 -844
- package/lib/test/unit/tools/memoryTools.test.js.map +0 -1
- package/lib/test/unit/types/identityCodec.test.d.ts +0 -2
- package/lib/test/unit/types/identityCodec.test.d.ts.map +0 -1
- package/lib/test/unit/types/identityCodec.test.js +0 -189
- package/lib/test/unit/types/identityCodec.test.js.map +0 -1
- package/lib/test/unit/types/ids.test.d.ts +0 -2
- package/lib/test/unit/types/ids.test.d.ts.map +0 -1
- package/lib/test/unit/types/ids.test.js +0 -86
- package/lib/test/unit/types/ids.test.js.map +0 -1
- package/lib/test/unit/types/temporalCodec.test.d.ts +0 -2
- package/lib/test/unit/types/temporalCodec.test.d.ts.map +0 -1
- package/lib/test/unit/types/temporalCodec.test.js +0 -205
- package/lib/test/unit/types/temporalCodec.test.js.map +0 -1
- package/lib/test/unit/types/temporalPolicy.test.d.ts +0 -2
- package/lib/test/unit/types/temporalPolicy.test.d.ts.map +0 -1
- package/lib/test/unit/types/temporalPolicy.test.js +0 -85
- package/lib/test/unit/types/temporalPolicy.test.js.map +0 -1
- package/lib/test/unit/types/writePolicy.test.d.ts +0 -2
- package/lib/test/unit/types/writePolicy.test.d.ts.map +0 -1
- package/lib/test/unit/types/writePolicy.test.js +0 -333
- package/lib/test/unit/types/writePolicy.test.js.map +0 -1
- package/lib/test/unit/vector/fragmentConverters.test.d.ts +0 -2
- package/lib/test/unit/vector/fragmentConverters.test.d.ts.map +0 -1
- package/lib/test/unit/vector/fragmentConverters.test.js +0 -60
- package/lib/test/unit/vector/fragmentConverters.test.js.map +0 -1
- package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts +0 -2
- package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts.map +0 -1
- package/lib/test/unit/vector/inMemoryCosineIndex.test.js +0 -254
- package/lib/test/unit/vector/inMemoryCosineIndex.test.js.map +0 -1
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts +0 -2
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts.map +0 -1
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js +0 -364
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +0 -1
- package/lib/test/unit/vector/vectorIndex.test.d.ts +0 -2
- package/lib/test/unit/vector/vectorIndex.test.d.ts.map +0 -1
- package/lib/test/unit/vector/vectorIndex.test.js +0 -53
- package/lib/test/unit/vector/vectorIndex.test.js.map +0 -1
- package/rush-logs/ts-agent-memory.build.cache.log +0 -3
- package/rush-logs/ts-agent-memory.build.log +0 -9
- package/src/index.ts +0 -14
- package/src/packlets/converters/bodyConverterRegistry.ts +0 -105
- package/src/packlets/converters/envelopeConverter.ts +0 -233
- package/src/packlets/converters/index.ts +0 -7
- package/src/packlets/index/index.ts +0 -6
- package/src/packlets/index/memoryIndex.ts +0 -332
- package/src/packlets/ingest/cycleGuard.ts +0 -153
- package/src/packlets/ingest/hostStages.ts +0 -111
- package/src/packlets/ingest/index.ts +0 -9
- package/src/packlets/ingest/model.ts +0 -195
- package/src/packlets/ingest/orchestrator.ts +0 -968
- package/src/packlets/observe/index.ts +0 -7
- package/src/packlets/observe/memoryObservationStore.ts +0 -153
- package/src/packlets/observe/observer.ts +0 -119
- package/src/packlets/retrieve/fragmentSemanticRetriever.ts +0 -138
- package/src/packlets/retrieve/hybridRetriever.ts +0 -194
- package/src/packlets/retrieve/index.ts +0 -14
- package/src/packlets/retrieve/linkTraversalRetriever.ts +0 -158
- package/src/packlets/retrieve/recencyRetriever.ts +0 -54
- package/src/packlets/retrieve/retriever.ts +0 -291
- package/src/packlets/retrieve/semanticRetriever.ts +0 -152
- package/src/packlets/retrieve/structuredFilterRetriever.ts +0 -58
- package/src/packlets/retrieve/tagRetriever.ts +0 -58
- package/src/packlets/retrieve/temporalRetrievers.ts +0 -210
- package/src/packlets/store/fileTreeMemoryStore.ts +0 -1872
- package/src/packlets/store/index.ts +0 -7
- package/src/packlets/store/scopeEncoding.ts +0 -36
- package/src/packlets/tools/index.ts +0 -6
- package/src/packlets/tools/memoryTools.ts +0 -706
- package/src/packlets/types/envelope.ts +0 -196
- package/src/packlets/types/filenameSafety.ts +0 -57
- package/src/packlets/types/identityCodec.ts +0 -447
- package/src/packlets/types/ids.ts +0 -124
- package/src/packlets/types/index.ts +0 -11
- package/src/packlets/types/temporal.ts +0 -96
- package/src/packlets/types/writePolicy.ts +0 -612
- package/src/packlets/vector/fragmentConverters.ts +0 -55
- package/src/packlets/vector/inMemoryCosineIndex.ts +0 -196
- package/src/packlets/vector/inMemoryFragmentCosineIndex.ts +0 -289
- package/src/packlets/vector/index.ts +0 -9
- package/src/packlets/vector/vectorIndex.ts +0 -273
- package/src/test/unit/converters/antagonistRoundTrip.test.ts +0 -110
- package/src/test/unit/converters/bodyConverterRegistry.test.ts +0 -89
- package/src/test/unit/converters/envelopeConverter.test.ts +0 -418
- package/src/test/unit/index/memoryIndex.test.ts +0 -272
- package/src/test/unit/ingest/antagonistCycleAndParity.test.ts +0 -367
- package/src/test/unit/ingest/cycleGuard.test.ts +0 -110
- package/src/test/unit/ingest/dedupScope.test.ts +0 -542
- package/src/test/unit/ingest/orchestrator.test.ts +0 -1355
- package/src/test/unit/observe/memoryObservationStore.test.ts +0 -158
- package/src/test/unit/retrieve/fragmentSemanticRetriever.test.ts +0 -163
- package/src/test/unit/retrieve/linkTraversalRetriever.test.ts +0 -329
- package/src/test/unit/retrieve/retrievers.test.ts +0 -1018
- package/src/test/unit/retrieve/temporalRetrievers.test.ts +0 -226
- package/src/test/unit/store/antagonistTemporalBoundary.test.ts +0 -158
- package/src/test/unit/store/embedOnWrite.test.ts +0 -418
- package/src/test/unit/store/fileTreeMemoryStore.test.ts +0 -1041
- package/src/test/unit/store/fragmentEmbedOnWrite.test.ts +0 -349
- package/src/test/unit/store/indexInjection.test.ts +0 -550
- package/src/test/unit/store/lenientOpen.test.ts +0 -292
- package/src/test/unit/store/listScoped.test.ts +0 -138
- package/src/test/unit/store/observations.test.ts +0 -290
- package/src/test/unit/store/rankAxis.test.ts +0 -349
- package/src/test/unit/store/scopeEncoding.test.ts +0 -37
- package/src/test/unit/store/temporalStore.test.ts +0 -469
- package/src/test/unit/tools/memoryTools.test.ts +0 -1121
- package/src/test/unit/types/identityCodec.test.ts +0 -266
- package/src/test/unit/types/ids.test.ts +0 -94
- package/src/test/unit/types/temporalCodec.test.ts +0 -259
- package/src/test/unit/types/temporalPolicy.test.ts +0 -124
- package/src/test/unit/types/writePolicy.test.ts +0 -446
- package/src/test/unit/vector/fragmentConverters.test.ts +0 -80
- package/src/test/unit/vector/inMemoryCosineIndex.test.ts +0 -318
- package/src/test/unit/vector/inMemoryFragmentCosineIndex.test.ts +0 -477
- package/src/test/unit/vector/vectorIndex.test.ts +0 -64
- package/temp/build/lint/_eslint-5eVG3S6w.json +0 -306
- package/temp/build/typescript/ts_8nwakTlr.json +0 -1
- package/temp/ts-agent-memory.api.json +0 -21030
- package/temp/ts-agent-memory.api.md +0 -940
- package/tsconfig.json +0 -8
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2026 Erik Fortune
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
require("@fgv/ts-utils-jest");
|
|
8
|
-
const ts_utils_1 = require("@fgv/ts-utils");
|
|
9
|
-
const ts_json_base_1 = require("@fgv/ts-json-base");
|
|
10
|
-
const index_1 = require("../../../index");
|
|
11
|
-
/**
|
|
12
|
-
* The incident: one vault holds every kind (mtm, ltm, conversation, knowledge,
|
|
13
|
-
* claim) in ONE store. A required field was added to the `claim` body; every
|
|
14
|
-
* pre-existing `claim` failed validation; and because the initial walk collapsed
|
|
15
|
-
* per-record results with `mapResults` (fail-the-whole-array on any element),
|
|
16
|
-
* every OTHER valid record became unreadable behind the failed open. These tests
|
|
17
|
-
* reproduce that shape (a poison-rejecting body converter standing in for the
|
|
18
|
-
* migrated converter) and pin the lenient (`onRecordError: 'skip'`) behavior.
|
|
19
|
-
*/
|
|
20
|
-
const noteKind = 'note';
|
|
21
|
-
const POISON = 'POISON';
|
|
22
|
-
/**
|
|
23
|
-
* A permissive identity codec that treats the full `<scope>/<stem>` path as the
|
|
24
|
-
* entity id, so records can live at any nesting depth (the shipped codecs pin a
|
|
25
|
-
* fixed scope shape; this test needs arbitrary-depth scopes to prove the
|
|
26
|
-
* recursion threads skips out of nested subtrees).
|
|
27
|
-
*/
|
|
28
|
-
class PathIdentityCodec {
|
|
29
|
-
encode(entityId) {
|
|
30
|
-
const value = String(entityId);
|
|
31
|
-
const cut = value.lastIndexOf('/');
|
|
32
|
-
const scope = (cut >= 0 ? value.slice(0, cut) : '');
|
|
33
|
-
const idStem = cut >= 0 ? value.slice(cut + 1) : value;
|
|
34
|
-
return (0, ts_utils_1.succeed)({ scope, idStem, isVersioned: false });
|
|
35
|
-
}
|
|
36
|
-
decode(scope, encodedStem) {
|
|
37
|
-
return (0, ts_utils_1.succeed)(`${scope}/${encodedStem}`);
|
|
38
|
-
}
|
|
39
|
-
verifyRoundTrip() {
|
|
40
|
-
return (0, ts_utils_1.succeed)(true);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/** A body converter that rejects any body containing the poison marker. */
|
|
44
|
-
const poisonRejectingConverter = ts_utils_1.Converters.string.map((body) => body.includes(POISON) ? (0, ts_utils_1.fail)(`note body rejected: contains ${POISON}`) : (0, ts_utils_1.succeed)(body));
|
|
45
|
-
function registry(bodyConverter) {
|
|
46
|
-
const created = index_1.BodyConverterRegistry.create().orThrow();
|
|
47
|
-
created.register(noteKind, bodyConverter);
|
|
48
|
-
return created;
|
|
49
|
-
}
|
|
50
|
-
const codecs = new Map([
|
|
51
|
-
[noteKind, new PathIdentityCodec()]
|
|
52
|
-
]);
|
|
53
|
-
/** Serialize a note record at `<scope>/<stem>.md` with the given body. */
|
|
54
|
-
function noteFile(scope, stem, body) {
|
|
55
|
-
const envelope = {
|
|
56
|
-
id: stem,
|
|
57
|
-
entityId: `${scope}/${stem}`,
|
|
58
|
-
kind: 'note',
|
|
59
|
-
tags: [],
|
|
60
|
-
links: [],
|
|
61
|
-
created: 1,
|
|
62
|
-
updated: 1,
|
|
63
|
-
seq: 4,
|
|
64
|
-
contentHash: 'seed',
|
|
65
|
-
provenance: { source: 'agent' }
|
|
66
|
-
};
|
|
67
|
-
const frontmatter = Object.entries(envelope)
|
|
68
|
-
.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)
|
|
69
|
-
.join('\n');
|
|
70
|
-
return { path: `${scope}/${stem}.md`, contents: (0, index_1.joinFrontmatter)(frontmatter, body) };
|
|
71
|
-
}
|
|
72
|
-
function mutableRoot(files) {
|
|
73
|
-
const tree = ts_json_base_1.FileTree.inMemory([...files], { mutable: true }).orThrow();
|
|
74
|
-
const root = tree.getDirectory('/').orThrow();
|
|
75
|
-
if (!ts_json_base_1.FileTree.isMutableDirectoryItem(root)) {
|
|
76
|
-
throw new Error('expected a mutable root directory');
|
|
77
|
-
}
|
|
78
|
-
return root;
|
|
79
|
-
}
|
|
80
|
-
describe('FileTreeMemoryStore lenient open (onRecordError)', () => {
|
|
81
|
-
test('incident: one bad record does not make the whole store unopenable in skip mode', async () => {
|
|
82
|
-
const files = [
|
|
83
|
-
noteFile('mtm', 'turn-1', 'valid mtm body'),
|
|
84
|
-
noteFile('ltm', 'summary', 'valid ltm body'),
|
|
85
|
-
noteFile('knowledge', 'doc-a', 'valid knowledge body'),
|
|
86
|
-
// The migrated `claim` converter now rejects the pre-existing record.
|
|
87
|
-
noteFile('claim', 'claim-1', `${POISON} missing required field`)
|
|
88
|
-
];
|
|
89
|
-
// Default (== 'fail') still fails the whole open, exactly as it did before.
|
|
90
|
-
expect(index_1.FileTreeMemoryStore.create({
|
|
91
|
-
root: mutableRoot(files),
|
|
92
|
-
registry: registry(poisonRejectingConverter),
|
|
93
|
-
codecs
|
|
94
|
-
})).toFailWith(/POISON/);
|
|
95
|
-
// 'skip' mode opens: every valid record loads; the bad one is quarantined.
|
|
96
|
-
const store = index_1.FileTreeMemoryStore.create({
|
|
97
|
-
root: mutableRoot(files),
|
|
98
|
-
registry: registry(poisonRejectingConverter),
|
|
99
|
-
codecs,
|
|
100
|
-
onRecordError: 'skip'
|
|
101
|
-
}).orThrow();
|
|
102
|
-
expect(await store.list()).toSucceedAndSatisfy((listed) => {
|
|
103
|
-
expect(listed.map((r) => r.envelope.id).sort()).toEqual(['doc-a', 'summary', 'turn-1']);
|
|
104
|
-
});
|
|
105
|
-
expect(store.skippedRecords).toHaveLength(1);
|
|
106
|
-
const skip = store.skippedRecords[0];
|
|
107
|
-
expect(skip.path).toBe('claim/claim-1.md');
|
|
108
|
-
expect(skip.scope).toBe('claim');
|
|
109
|
-
expect(skip.error).toContain('claim/claim-1.md');
|
|
110
|
-
expect(skip.error).toContain(POISON);
|
|
111
|
-
});
|
|
112
|
-
test('default mode is byte-identical to explicit fail mode', () => {
|
|
113
|
-
const files = [noteFile('note', 'good', 'ok'), noteFile('note', 'bad', POISON)];
|
|
114
|
-
const asDefault = index_1.FileTreeMemoryStore.create({
|
|
115
|
-
root: mutableRoot(files),
|
|
116
|
-
registry: registry(poisonRejectingConverter),
|
|
117
|
-
codecs
|
|
118
|
-
});
|
|
119
|
-
const asFail = index_1.FileTreeMemoryStore.create({
|
|
120
|
-
root: mutableRoot(files),
|
|
121
|
-
registry: registry(poisonRejectingConverter),
|
|
122
|
-
codecs,
|
|
123
|
-
onRecordError: 'fail'
|
|
124
|
-
});
|
|
125
|
-
expect(asDefault).toFail();
|
|
126
|
-
expect(asFail).toFail();
|
|
127
|
-
// Same exact failure message — the load path is untouched in fail mode.
|
|
128
|
-
expect(asDefault.isFailure() && asFail.isFailure() && asDefault.message === asFail.message).toBe(true);
|
|
129
|
-
expect(asDefault).toFailWith(/POISON/);
|
|
130
|
-
});
|
|
131
|
-
test('a bad record in a nested scope is skipped while valid siblings load', async () => {
|
|
132
|
-
const files = [
|
|
133
|
-
noteFile('alpha/beta', 'ok-1', 'valid'),
|
|
134
|
-
noteFile('alpha/beta', 'bad-1', POISON),
|
|
135
|
-
noteFile('alpha/beta/gamma', 'ok-2', 'valid deep')
|
|
136
|
-
];
|
|
137
|
-
const store = index_1.FileTreeMemoryStore.create({
|
|
138
|
-
root: mutableRoot(files),
|
|
139
|
-
registry: registry(poisonRejectingConverter),
|
|
140
|
-
codecs,
|
|
141
|
-
onRecordError: 'skip'
|
|
142
|
-
}).orThrow();
|
|
143
|
-
expect(await store.list()).toSucceedAndSatisfy((listed) => {
|
|
144
|
-
expect(listed.map((r) => r.envelope.id).sort()).toEqual(['ok-1', 'ok-2']);
|
|
145
|
-
});
|
|
146
|
-
expect(store.skippedRecords.map((s) => s.path)).toEqual(['alpha/beta/bad-1.md']);
|
|
147
|
-
expect(store.skippedRecords[0].scope).toBe('alpha/beta');
|
|
148
|
-
});
|
|
149
|
-
test('multiple skips across different scopes all surface; all valid records load', async () => {
|
|
150
|
-
const files = [
|
|
151
|
-
noteFile('scope-a', 'good-a', 'a-ok'),
|
|
152
|
-
noteFile('scope-a', 'bad-a', POISON),
|
|
153
|
-
noteFile('scope-b', 'good-b', 'b-ok'),
|
|
154
|
-
noteFile('scope-b', 'bad-b', POISON)
|
|
155
|
-
];
|
|
156
|
-
const store = index_1.FileTreeMemoryStore.create({
|
|
157
|
-
root: mutableRoot(files),
|
|
158
|
-
registry: registry(poisonRejectingConverter),
|
|
159
|
-
codecs,
|
|
160
|
-
onRecordError: 'skip'
|
|
161
|
-
}).orThrow();
|
|
162
|
-
expect(await store.list()).toSucceedAndSatisfy((listed) => {
|
|
163
|
-
expect(listed.map((r) => r.envelope.id).sort()).toEqual(['good-a', 'good-b']);
|
|
164
|
-
});
|
|
165
|
-
expect(store.skippedRecords.map((s) => s.path).sort()).toEqual(['scope-a/bad-a.md', 'scope-b/bad-b.md']);
|
|
166
|
-
});
|
|
167
|
-
test('an all-invalid subtree opens with everything skipped (mapSuccess orDefault edge)', async () => {
|
|
168
|
-
const files = [
|
|
169
|
-
noteFile('bad-scope', 'x', POISON),
|
|
170
|
-
noteFile('bad-scope', 'y', POISON),
|
|
171
|
-
noteFile('good-scope', 'z', 'fine')
|
|
172
|
-
];
|
|
173
|
-
const store = index_1.FileTreeMemoryStore.create({
|
|
174
|
-
root: mutableRoot(files),
|
|
175
|
-
registry: registry(poisonRejectingConverter),
|
|
176
|
-
codecs,
|
|
177
|
-
onRecordError: 'skip'
|
|
178
|
-
}).orThrow();
|
|
179
|
-
expect(await store.list()).toSucceedAndSatisfy((listed) => {
|
|
180
|
-
expect(listed.map((r) => r.envelope.id)).toEqual(['z']);
|
|
181
|
-
});
|
|
182
|
-
expect(store.skippedRecords.map((s) => s.path).sort()).toEqual(['bad-scope/x.md', 'bad-scope/y.md']);
|
|
183
|
-
});
|
|
184
|
-
test('an empty vault opens with no skips in either mode', async () => {
|
|
185
|
-
const skip = index_1.FileTreeMemoryStore.create({
|
|
186
|
-
root: mutableRoot([]),
|
|
187
|
-
registry: registry(poisonRejectingConverter),
|
|
188
|
-
codecs,
|
|
189
|
-
onRecordError: 'skip'
|
|
190
|
-
}).orThrow();
|
|
191
|
-
expect(await skip.list()).toSucceedWith([]);
|
|
192
|
-
expect(skip.skippedRecords).toEqual([]);
|
|
193
|
-
const strict = index_1.FileTreeMemoryStore.create({
|
|
194
|
-
root: mutableRoot([]),
|
|
195
|
-
registry: registry(poisonRejectingConverter),
|
|
196
|
-
codecs
|
|
197
|
-
}).orThrow();
|
|
198
|
-
expect(strict.skippedRecords).toEqual([]);
|
|
199
|
-
});
|
|
200
|
-
test('each skip is logged at warn; with the default NoOpLogger skippedRecords is still populated', async () => {
|
|
201
|
-
const files = [noteFile('note', 'good', 'ok'), noteFile('note', 'bad', POISON)];
|
|
202
|
-
const logger = new ts_utils_1.Logging.InMemoryLogger('warning');
|
|
203
|
-
const withLogger = index_1.FileTreeMemoryStore.create({
|
|
204
|
-
root: mutableRoot(files),
|
|
205
|
-
registry: registry(poisonRejectingConverter),
|
|
206
|
-
codecs,
|
|
207
|
-
onRecordError: 'skip',
|
|
208
|
-
logger
|
|
209
|
-
}).orThrow();
|
|
210
|
-
expect(withLogger.skippedRecords).toHaveLength(1);
|
|
211
|
-
expect(logger.logged.some((m) => m.includes('note/bad.md') && m.includes(POISON))).toBe(true);
|
|
212
|
-
// No logger wired (default NoOpLogger): create still succeeds and the
|
|
213
|
-
// structured collection is still populated (observable without a logger).
|
|
214
|
-
const silent = index_1.FileTreeMemoryStore.create({
|
|
215
|
-
root: mutableRoot(files),
|
|
216
|
-
registry: registry(poisonRejectingConverter),
|
|
217
|
-
codecs,
|
|
218
|
-
onRecordError: 'skip'
|
|
219
|
-
}).orThrow();
|
|
220
|
-
expect(silent.skippedRecords.map((s) => s.path)).toEqual(['note/bad.md']);
|
|
221
|
-
});
|
|
222
|
-
test('re-open after the converter is fixed re-indexes the quarantined record (non-destructive)', async () => {
|
|
223
|
-
const files = [noteFile('note', 'good', 'ok'), noteFile('note', 'later', POISON)];
|
|
224
|
-
const root = mutableRoot(files);
|
|
225
|
-
// First open with the rejecting converter: the record is quarantined.
|
|
226
|
-
const before = index_1.FileTreeMemoryStore.create({
|
|
227
|
-
root,
|
|
228
|
-
registry: registry(poisonRejectingConverter),
|
|
229
|
-
codecs,
|
|
230
|
-
onRecordError: 'skip'
|
|
231
|
-
}).orThrow();
|
|
232
|
-
expect(before.skippedRecords).toHaveLength(1);
|
|
233
|
-
expect(await before.list()).toSucceedAndSatisfy((listed) => {
|
|
234
|
-
expect(listed.map((r) => r.envelope.id)).toEqual(['good']);
|
|
235
|
-
});
|
|
236
|
-
// The file was never deleted or mutated, so a fresh open with the fixed
|
|
237
|
-
// (accept-all) converter re-indexes it — quarantine is non-destructive.
|
|
238
|
-
const after = index_1.FileTreeMemoryStore.create({
|
|
239
|
-
root: mutableRoot(files),
|
|
240
|
-
registry: registry(ts_utils_1.Converters.string),
|
|
241
|
-
codecs,
|
|
242
|
-
onRecordError: 'skip'
|
|
243
|
-
}).orThrow();
|
|
244
|
-
expect(after.skippedRecords).toEqual([]);
|
|
245
|
-
expect(await after.list()).toSucceedAndSatisfy((listed) => {
|
|
246
|
-
expect(listed.map((r) => r.envelope.id).sort()).toEqual(['good', 'later']);
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
//# sourceMappingURL=lenientOpen.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lenientOpen.test.js","sourceRoot":"","sources":["../../../../src/test/unit/store/lenientOpen.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport '@fgv/ts-utils-jest';\nimport { Converter, Converters, Logging, Result, fail, succeed } from '@fgv/ts-utils';\nimport { FileTree } from '@fgv/ts-json-base';\nimport {\n BodyConverterRegistry,\n EntityId,\n FileTreeMemoryStore,\n IBodyConverterRegistry,\n IIdentityCodec,\n IIdentityCodecResult,\n IMemoryRecord,\n ISkippedRecord,\n Kind,\n MemoryScopeKey,\n joinFrontmatter\n} from '../../../index';\n\n/**\n * The incident: one vault holds every kind (mtm, ltm, conversation, knowledge,\n * claim) in ONE store. A required field was added to the `claim` body; every\n * pre-existing `claim` failed validation; and because the initial walk collapsed\n * per-record results with `mapResults` (fail-the-whole-array on any element),\n * every OTHER valid record became unreadable behind the failed open. These tests\n * reproduce that shape (a poison-rejecting body converter standing in for the\n * migrated converter) and pin the lenient (`onRecordError: 'skip'`) behavior.\n */\n\nconst noteKind: Kind = 'note' as Kind;\nconst POISON: string = 'POISON';\n\n/**\n * A permissive identity codec that treats the full `<scope>/<stem>` path as the\n * entity id, so records can live at any nesting depth (the shipped codecs pin a\n * fixed scope shape; this test needs arbitrary-depth scopes to prove the\n * recursion threads skips out of nested subtrees).\n */\nclass PathIdentityCodec implements IIdentityCodec {\n public encode(entityId: EntityId): Result<IIdentityCodecResult> {\n const value: string = String(entityId);\n const cut: number = value.lastIndexOf('/');\n const scope: MemoryScopeKey = (cut >= 0 ? value.slice(0, cut) : '') as MemoryScopeKey;\n const idStem: string = cut >= 0 ? value.slice(cut + 1) : value;\n return succeed({ scope, idStem, isVersioned: false });\n }\n public decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId> {\n return succeed(`${scope}/${encodedStem}` as EntityId);\n }\n public verifyRoundTrip(): Result<true> {\n return succeed(true);\n }\n}\n\n/** A body converter that rejects any body containing the poison marker. */\nconst poisonRejectingConverter: Converter<string> = Converters.string.map((body) =>\n body.includes(POISON) ? fail(`note body rejected: contains ${POISON}`) : succeed(body)\n);\n\nfunction registry(bodyConverter: Converter<string>): IBodyConverterRegistry {\n const created = BodyConverterRegistry.create().orThrow();\n created.register(noteKind, bodyConverter);\n return created;\n}\n\nconst codecs: ReadonlyMap<Kind, IIdentityCodec> = new Map<Kind, IIdentityCodec>([\n [noteKind, new PathIdentityCodec()]\n]);\n\n/** Serialize a note record at `<scope>/<stem>.md` with the given body. */\nfunction noteFile(scope: string, stem: string, body: string): { path: string; contents: string } {\n const envelope = {\n id: stem,\n entityId: `${scope}/${stem}`,\n kind: 'note',\n tags: [],\n links: [],\n created: 1,\n updated: 1,\n seq: 4,\n contentHash: 'seed',\n provenance: { source: 'agent' }\n };\n const frontmatter = Object.entries(envelope)\n .map(([k, v]) => `${k}: ${JSON.stringify(v)}`)\n .join('\\n');\n return { path: `${scope}/${stem}.md`, contents: joinFrontmatter(frontmatter, body) };\n}\n\nfunction mutableRoot(\n files: ReadonlyArray<{ path: string; contents: string }>\n): FileTree.IMutableFileTreeDirectoryItem {\n const tree = FileTree.inMemory([...files], { mutable: true }).orThrow();\n const root = tree.getDirectory('/').orThrow();\n if (!FileTree.isMutableDirectoryItem(root)) {\n throw new Error('expected a mutable root directory');\n }\n return root;\n}\n\ndescribe('FileTreeMemoryStore lenient open (onRecordError)', () => {\n test('incident: one bad record does not make the whole store unopenable in skip mode', async () => {\n const files = [\n noteFile('mtm', 'turn-1', 'valid mtm body'),\n noteFile('ltm', 'summary', 'valid ltm body'),\n noteFile('knowledge', 'doc-a', 'valid knowledge body'),\n // The migrated `claim` converter now rejects the pre-existing record.\n noteFile('claim', 'claim-1', `${POISON} missing required field`)\n ];\n\n // Default (== 'fail') still fails the whole open, exactly as it did before.\n expect(\n FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(poisonRejectingConverter),\n codecs\n })\n ).toFailWith(/POISON/);\n\n // 'skip' mode opens: every valid record loads; the bad one is quarantined.\n const store = FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(poisonRejectingConverter),\n codecs,\n onRecordError: 'skip'\n }).orThrow();\n\n expect(await store.list()).toSucceedAndSatisfy((listed: ReadonlyArray<IMemoryRecord<unknown>>) => {\n expect(listed.map((r) => r.envelope.id).sort()).toEqual(['doc-a', 'summary', 'turn-1']);\n });\n expect(store.skippedRecords).toHaveLength(1);\n const skip: ISkippedRecord = store.skippedRecords[0];\n expect(skip.path).toBe('claim/claim-1.md');\n expect(skip.scope).toBe('claim');\n expect(skip.error).toContain('claim/claim-1.md');\n expect(skip.error).toContain(POISON);\n });\n\n test('default mode is byte-identical to explicit fail mode', () => {\n const files = [noteFile('note', 'good', 'ok'), noteFile('note', 'bad', POISON)];\n const asDefault = FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(poisonRejectingConverter),\n codecs\n });\n const asFail = FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(poisonRejectingConverter),\n codecs,\n onRecordError: 'fail'\n });\n expect(asDefault).toFail();\n expect(asFail).toFail();\n // Same exact failure message — the load path is untouched in fail mode.\n expect(asDefault.isFailure() && asFail.isFailure() && asDefault.message === asFail.message).toBe(true);\n expect(asDefault).toFailWith(/POISON/);\n });\n\n test('a bad record in a nested scope is skipped while valid siblings load', async () => {\n const files = [\n noteFile('alpha/beta', 'ok-1', 'valid'),\n noteFile('alpha/beta', 'bad-1', POISON),\n noteFile('alpha/beta/gamma', 'ok-2', 'valid deep')\n ];\n const store = FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(poisonRejectingConverter),\n codecs,\n onRecordError: 'skip'\n }).orThrow();\n\n expect(await store.list()).toSucceedAndSatisfy((listed: ReadonlyArray<IMemoryRecord<unknown>>) => {\n expect(listed.map((r) => r.envelope.id).sort()).toEqual(['ok-1', 'ok-2']);\n });\n expect(store.skippedRecords.map((s) => s.path)).toEqual(['alpha/beta/bad-1.md']);\n expect(store.skippedRecords[0].scope).toBe('alpha/beta');\n });\n\n test('multiple skips across different scopes all surface; all valid records load', async () => {\n const files = [\n noteFile('scope-a', 'good-a', 'a-ok'),\n noteFile('scope-a', 'bad-a', POISON),\n noteFile('scope-b', 'good-b', 'b-ok'),\n noteFile('scope-b', 'bad-b', POISON)\n ];\n const store = FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(poisonRejectingConverter),\n codecs,\n onRecordError: 'skip'\n }).orThrow();\n\n expect(await store.list()).toSucceedAndSatisfy((listed: ReadonlyArray<IMemoryRecord<unknown>>) => {\n expect(listed.map((r) => r.envelope.id).sort()).toEqual(['good-a', 'good-b']);\n });\n expect(store.skippedRecords.map((s) => s.path).sort()).toEqual(['scope-a/bad-a.md', 'scope-b/bad-b.md']);\n });\n\n test('an all-invalid subtree opens with everything skipped (mapSuccess orDefault edge)', async () => {\n const files = [\n noteFile('bad-scope', 'x', POISON),\n noteFile('bad-scope', 'y', POISON),\n noteFile('good-scope', 'z', 'fine')\n ];\n const store = FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(poisonRejectingConverter),\n codecs,\n onRecordError: 'skip'\n }).orThrow();\n\n expect(await store.list()).toSucceedAndSatisfy((listed: ReadonlyArray<IMemoryRecord<unknown>>) => {\n expect(listed.map((r) => r.envelope.id)).toEqual(['z']);\n });\n expect(store.skippedRecords.map((s) => s.path).sort()).toEqual(['bad-scope/x.md', 'bad-scope/y.md']);\n });\n\n test('an empty vault opens with no skips in either mode', async () => {\n const skip = FileTreeMemoryStore.create({\n root: mutableRoot([]),\n registry: registry(poisonRejectingConverter),\n codecs,\n onRecordError: 'skip'\n }).orThrow();\n expect(await skip.list()).toSucceedWith([]);\n expect(skip.skippedRecords).toEqual([]);\n\n const strict = FileTreeMemoryStore.create({\n root: mutableRoot([]),\n registry: registry(poisonRejectingConverter),\n codecs\n }).orThrow();\n expect(strict.skippedRecords).toEqual([]);\n });\n\n test('each skip is logged at warn; with the default NoOpLogger skippedRecords is still populated', async () => {\n const files = [noteFile('note', 'good', 'ok'), noteFile('note', 'bad', POISON)];\n const logger = new Logging.InMemoryLogger('warning');\n const withLogger = FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(poisonRejectingConverter),\n codecs,\n onRecordError: 'skip',\n logger\n }).orThrow();\n expect(withLogger.skippedRecords).toHaveLength(1);\n expect(logger.logged.some((m) => m.includes('note/bad.md') && m.includes(POISON))).toBe(true);\n\n // No logger wired (default NoOpLogger): create still succeeds and the\n // structured collection is still populated (observable without a logger).\n const silent = FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(poisonRejectingConverter),\n codecs,\n onRecordError: 'skip'\n }).orThrow();\n expect(silent.skippedRecords.map((s) => s.path)).toEqual(['note/bad.md']);\n });\n\n test('re-open after the converter is fixed re-indexes the quarantined record (non-destructive)', async () => {\n const files = [noteFile('note', 'good', 'ok'), noteFile('note', 'later', POISON)];\n const root = mutableRoot(files);\n\n // First open with the rejecting converter: the record is quarantined.\n const before = FileTreeMemoryStore.create({\n root,\n registry: registry(poisonRejectingConverter),\n codecs,\n onRecordError: 'skip'\n }).orThrow();\n expect(before.skippedRecords).toHaveLength(1);\n expect(await before.list()).toSucceedAndSatisfy((listed: ReadonlyArray<IMemoryRecord<unknown>>) => {\n expect(listed.map((r) => r.envelope.id)).toEqual(['good']);\n });\n\n // The file was never deleted or mutated, so a fresh open with the fixed\n // (accept-all) converter re-indexes it — quarantine is non-destructive.\n const after = FileTreeMemoryStore.create({\n root: mutableRoot(files),\n registry: registry(Converters.string),\n codecs,\n onRecordError: 'skip'\n }).orThrow();\n expect(after.skippedRecords).toEqual([]);\n expect(await after.list()).toSucceedAndSatisfy((listed: ReadonlyArray<IMemoryRecord<unknown>>) => {\n expect(listed.map((r) => r.envelope.id).sort()).toEqual(['good', 'later']);\n });\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"listScoped.test.d.ts","sourceRoot":"","sources":["../../../../src/test/unit/store/listScoped.test.ts"],"names":[],"mappings":"AAKA,OAAO,oBAAoB,CAAC"}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2026 Erik Fortune
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
require("@fgv/ts-utils-jest");
|
|
8
|
-
const ts_utils_1 = require("@fgv/ts-utils");
|
|
9
|
-
const ts_json_base_1 = require("@fgv/ts-json-base");
|
|
10
|
-
const index_1 = require("../../../index");
|
|
11
|
-
const mtmKind = 'mtm';
|
|
12
|
-
function mutableRoot() {
|
|
13
|
-
const tree = ts_json_base_1.FileTree.inMemory([], { mutable: true }).orThrow();
|
|
14
|
-
const root = tree.getDirectory('/').orThrow();
|
|
15
|
-
if (!ts_json_base_1.FileTree.isMutableDirectoryItem(root)) {
|
|
16
|
-
throw new Error('expected a mutable root directory');
|
|
17
|
-
}
|
|
18
|
-
return root;
|
|
19
|
-
}
|
|
20
|
-
function mtmRecord(entityId, idStem, body) {
|
|
21
|
-
return {
|
|
22
|
-
envelope: index_1.envelopeConverter
|
|
23
|
-
.convert({
|
|
24
|
-
id: idStem,
|
|
25
|
-
entityId,
|
|
26
|
-
kind: 'mtm',
|
|
27
|
-
tags: [],
|
|
28
|
-
links: [],
|
|
29
|
-
created: 0,
|
|
30
|
-
updated: 0,
|
|
31
|
-
seq: 0,
|
|
32
|
-
contentHash: '',
|
|
33
|
-
provenance: { source: 'agent' }
|
|
34
|
-
})
|
|
35
|
-
.orThrow(),
|
|
36
|
-
body
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
// Deterministic keyword-count embedder (no network): the record's vector and a
|
|
40
|
-
// query's vector live in the same space so cosine ordering is predictable.
|
|
41
|
-
const MARKERS = ['cat', 'dog', 'fish'];
|
|
42
|
-
function featureVector(text) {
|
|
43
|
-
const lower = text.toLowerCase();
|
|
44
|
-
return Float32Array.from(MARKERS.map((m) => lower.split(m).length - 1));
|
|
45
|
-
}
|
|
46
|
-
const recordEmbed = (r) => Promise.resolve(ts_utils_1.Converters.string.convert(r.body).onSuccess((body) => (0, ts_utils_1.succeed)(featureVector(body))));
|
|
47
|
-
function mtmStore() {
|
|
48
|
-
const registry = index_1.BodyConverterRegistry.create().orThrow();
|
|
49
|
-
registry.register(mtmKind, ts_utils_1.Converters.string);
|
|
50
|
-
return index_1.FileTreeMemoryStore.create({
|
|
51
|
-
root: mutableRoot(),
|
|
52
|
-
registry,
|
|
53
|
-
codecs: new Map([[mtmKind, new index_1.MtmIdentityCodec()]])
|
|
54
|
-
}).orThrow();
|
|
55
|
-
}
|
|
56
|
-
describe('FileTreeMemoryStore.listScoped', () => {
|
|
57
|
-
test('yields an empty list for an empty store', async () => {
|
|
58
|
-
expect(await mtmStore().listScoped()).toSucceedWith([]);
|
|
59
|
-
});
|
|
60
|
-
test('pairs each record with its scope-qualified (scope, id) address', async () => {
|
|
61
|
-
const store = mtmStore();
|
|
62
|
-
(await store.put(mtmRecord('conv-1:3', 'turn-3', 'cat cat'))).orThrow();
|
|
63
|
-
expect(await store.listScoped()).toSucceedAndSatisfy((scoped) => {
|
|
64
|
-
expect(scoped).toHaveLength(1);
|
|
65
|
-
expect(scoped[0].target).toEqual({ scope: 'conversations/conv-1', id: 'turn-3' });
|
|
66
|
-
expect(scoped[0].record.envelope.id).toBe('turn-3');
|
|
67
|
-
expect(scoped[0].record.body).toBe('cat cat');
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
test('lists two same-stem records in different scopes as distinct entries', async () => {
|
|
71
|
-
// conv-1:3 and conv-2:3 both mint the idStem 'turn-3' but under different
|
|
72
|
-
// scopes — exactly the ambiguity a bare MemoryId could not disambiguate.
|
|
73
|
-
const store = mtmStore();
|
|
74
|
-
(await store.put(mtmRecord('conv-1:3', 'turn-3', 'cat'))).orThrow();
|
|
75
|
-
(await store.put(mtmRecord('conv-2:3', 'turn-3', 'dog'))).orThrow();
|
|
76
|
-
expect(await store.listScoped()).toSucceedAndSatisfy((scoped) => {
|
|
77
|
-
expect(scoped).toHaveLength(2);
|
|
78
|
-
const byScope = new Map(scoped.map((s) => [s.target.scope, s.target]));
|
|
79
|
-
expect(byScope.get('conversations/conv-1')).toEqual({
|
|
80
|
-
scope: 'conversations/conv-1',
|
|
81
|
-
id: 'turn-3'
|
|
82
|
-
});
|
|
83
|
-
expect(byScope.get('conversations/conv-2')).toEqual({
|
|
84
|
-
scope: 'conversations/conv-2',
|
|
85
|
-
id: 'turn-3'
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
describe('FileTreeMemoryStore.asRecordSource — drives an IVectorIndex rebuild', () => {
|
|
91
|
-
test('a real store re-indexes an InMemoryCosineIndex on the scoped key', async () => {
|
|
92
|
-
const store = mtmStore();
|
|
93
|
-
(await store.put(mtmRecord('conv-1:3', 'turn-3', 'cat'))).orThrow();
|
|
94
|
-
(await store.put(mtmRecord('conv-2:3', 'turn-3', 'dog'))).orThrow();
|
|
95
|
-
const index = index_1.InMemoryCosineIndex.create().orThrow();
|
|
96
|
-
// The store satisfies IMemoryRecordSource via asRecordSource(); rebuild
|
|
97
|
-
// re-embeds every record and keys each vector on the scoped (scope, id).
|
|
98
|
-
expect(await index.rebuild(store.asRecordSource(), recordEmbed)).toSucceedWith(2);
|
|
99
|
-
expect(index.size).toBe(2);
|
|
100
|
-
// The two same-stem records occupy DISTINCT vector entries: a query for 'cat'
|
|
101
|
-
// resolves the conv-1 record; a query for 'dog' resolves conv-2 — each hit
|
|
102
|
-
// carries the full scoped target, not a bare (colliding) id.
|
|
103
|
-
expect(await index.query(featureVector('cat'), 1)).toSucceedAndSatisfy((hits) => {
|
|
104
|
-
expect(hits[0].target).toEqual({ scope: 'conversations/conv-1', id: 'turn-3' });
|
|
105
|
-
});
|
|
106
|
-
expect(await index.query(featureVector('dog'), 1)).toSucceedAndSatisfy((hits) => {
|
|
107
|
-
expect(hits[0].target).toEqual({ scope: 'conversations/conv-2', id: 'turn-3' });
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
//# sourceMappingURL=listScoped.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"listScoped.test.js","sourceRoot":"","sources":["../../../../src/test/unit/store/listScoped.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport '@fgv/ts-utils-jest';\nimport { Converters, Result, succeed } from '@fgv/ts-utils';\nimport { FileTree } from '@fgv/ts-json-base';\nimport {\n BodyConverterRegistry,\n FileTreeMemoryStore,\n IBodyConverterRegistry,\n IIdentityCodec,\n IMemoryRecord,\n IScopedMemoryRecord,\n IVectorQueryHit,\n InMemoryCosineIndex,\n Kind,\n MemoryScopeKey,\n MtmIdentityCodec,\n envelopeConverter\n} from '../../../index';\n\nconst mtmKind: Kind = 'mtm' as Kind;\n\nfunction mutableRoot(): FileTree.IMutableFileTreeDirectoryItem {\n const tree = FileTree.inMemory([], { mutable: true }).orThrow();\n const root = tree.getDirectory('/').orThrow();\n if (!FileTree.isMutableDirectoryItem(root)) {\n throw new Error('expected a mutable root directory');\n }\n return root;\n}\n\nfunction mtmRecord(entityId: string, idStem: string, body: string): IMemoryRecord<unknown> {\n return {\n envelope: envelopeConverter\n .convert({\n id: idStem,\n entityId,\n kind: 'mtm',\n tags: [],\n links: [],\n created: 0,\n updated: 0,\n seq: 0,\n contentHash: '',\n provenance: { source: 'agent' }\n })\n .orThrow(),\n body\n };\n}\n\n// Deterministic keyword-count embedder (no network): the record's vector and a\n// query's vector live in the same space so cosine ordering is predictable.\nconst MARKERS: ReadonlyArray<string> = ['cat', 'dog', 'fish'];\nfunction featureVector(text: string): Float32Array {\n const lower: string = text.toLowerCase();\n return Float32Array.from(MARKERS.map((m) => lower.split(m).length - 1));\n}\nconst recordEmbed = (r: IMemoryRecord<unknown>): Promise<Result<Float32Array>> =>\n Promise.resolve(Converters.string.convert(r.body).onSuccess((body) => succeed(featureVector(body))));\n\nfunction mtmStore(): FileTreeMemoryStore {\n const registry: IBodyConverterRegistry = BodyConverterRegistry.create().orThrow();\n registry.register(mtmKind, Converters.string);\n return FileTreeMemoryStore.create({\n root: mutableRoot(),\n registry,\n codecs: new Map<Kind, IIdentityCodec>([[mtmKind, new MtmIdentityCodec()]])\n }).orThrow();\n}\n\ndescribe('FileTreeMemoryStore.listScoped', () => {\n test('yields an empty list for an empty store', async () => {\n expect(await mtmStore().listScoped()).toSucceedWith([]);\n });\n\n test('pairs each record with its scope-qualified (scope, id) address', async () => {\n const store = mtmStore();\n (await store.put(mtmRecord('conv-1:3', 'turn-3', 'cat cat'))).orThrow();\n expect(await store.listScoped()).toSucceedAndSatisfy((scoped: ReadonlyArray<IScopedMemoryRecord>) => {\n expect(scoped).toHaveLength(1);\n expect(scoped[0].target).toEqual({ scope: 'conversations/conv-1', id: 'turn-3' });\n expect(scoped[0].record.envelope.id).toBe('turn-3');\n expect(scoped[0].record.body).toBe('cat cat');\n });\n });\n\n test('lists two same-stem records in different scopes as distinct entries', async () => {\n // conv-1:3 and conv-2:3 both mint the idStem 'turn-3' but under different\n // scopes — exactly the ambiguity a bare MemoryId could not disambiguate.\n const store = mtmStore();\n (await store.put(mtmRecord('conv-1:3', 'turn-3', 'cat'))).orThrow();\n (await store.put(mtmRecord('conv-2:3', 'turn-3', 'dog'))).orThrow();\n expect(await store.listScoped()).toSucceedAndSatisfy((scoped: ReadonlyArray<IScopedMemoryRecord>) => {\n expect(scoped).toHaveLength(2);\n const byScope = new Map(scoped.map((s) => [s.target.scope, s.target]));\n expect(byScope.get('conversations/conv-1' as MemoryScopeKey)).toEqual({\n scope: 'conversations/conv-1',\n id: 'turn-3'\n });\n expect(byScope.get('conversations/conv-2' as MemoryScopeKey)).toEqual({\n scope: 'conversations/conv-2',\n id: 'turn-3'\n });\n });\n });\n});\n\ndescribe('FileTreeMemoryStore.asRecordSource — drives an IVectorIndex rebuild', () => {\n test('a real store re-indexes an InMemoryCosineIndex on the scoped key', async () => {\n const store = mtmStore();\n (await store.put(mtmRecord('conv-1:3', 'turn-3', 'cat'))).orThrow();\n (await store.put(mtmRecord('conv-2:3', 'turn-3', 'dog'))).orThrow();\n\n const index = InMemoryCosineIndex.create().orThrow();\n // The store satisfies IMemoryRecordSource via asRecordSource(); rebuild\n // re-embeds every record and keys each vector on the scoped (scope, id).\n expect(await index.rebuild(store.asRecordSource(), recordEmbed)).toSucceedWith(2);\n expect(index.size).toBe(2);\n\n // The two same-stem records occupy DISTINCT vector entries: a query for 'cat'\n // resolves the conv-1 record; a query for 'dog' resolves conv-2 — each hit\n // carries the full scoped target, not a bare (colliding) id.\n expect(await index.query(featureVector('cat'), 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits[0].target).toEqual({ scope: 'conversations/conv-1', id: 'turn-3' });\n }\n );\n expect(await index.query(featureVector('dog'), 1)).toSucceedAndSatisfy(\n (hits: ReadonlyArray<IVectorQueryHit>) => {\n expect(hits[0].target).toEqual({ scope: 'conversations/conv-2', id: 'turn-3' });\n }\n );\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observations.test.d.ts","sourceRoot":"","sources":["../../../../src/test/unit/store/observations.test.ts"],"names":[],"mappings":"AAKA,OAAO,oBAAoB,CAAC"}
|