@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,196 +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 { IEdgeTarget, edgeTargetKey } from '../types';
|
|
8
|
-
import {
|
|
9
|
-
IMemoryRecordSource,
|
|
10
|
-
IScopedMemoryRecord,
|
|
11
|
-
IVectorIndex,
|
|
12
|
-
IVectorQueryHit,
|
|
13
|
-
MemoryEmbedder
|
|
14
|
-
} from './vectorIndex';
|
|
15
|
-
|
|
16
|
-
/** One stored embedding: the scope-qualified address plus its vector. */
|
|
17
|
-
interface IStoredVector {
|
|
18
|
-
readonly target: IEdgeTarget;
|
|
19
|
-
readonly vector: Float32Array;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* The brute-force, in-memory cosine {@link IVectorIndex}. Stores one
|
|
24
|
-
* `Float32Array` per record and answers a query by computing cosine similarity
|
|
25
|
-
* against every stored vector, returning the top-k by descending score.
|
|
26
|
-
*
|
|
27
|
-
* @remarks
|
|
28
|
-
* This is the **complete** vector implementation for the fgv regime — large-N is
|
|
29
|
-
* explicitly out of scope (the seam stays open for a consumer to swap an external
|
|
30
|
-
* ANN backend once N grows beyond "thousands of records"). No external dependency
|
|
31
|
-
* and no ANN structure: a linear scan over a few thousand vectors is well within
|
|
32
|
-
* an interactive budget.
|
|
33
|
-
*
|
|
34
|
-
* The index has a single dimension established by the first vector added; every
|
|
35
|
-
* subsequent `add` and every `query` vector must match that dimension or fail
|
|
36
|
-
* loudly — a mismatched dimension is an embedder-wiring bug, never a silent
|
|
37
|
-
* zero-similarity result. {@link InMemoryCosineIndex.rebuild | rebuild} clears
|
|
38
|
-
* the index, so a re-embed with a different model (hence dimension) is supported.
|
|
39
|
-
*
|
|
40
|
-
* Persistence (a JSON sidecar) is deliberately out of scope for this layer — the
|
|
41
|
-
* index is in-memory and rebuilt from the store via `rebuild`; a sidecar is a
|
|
42
|
-
* future nicety.
|
|
43
|
-
* @public
|
|
44
|
-
*/
|
|
45
|
-
export class InMemoryCosineIndex implements IVectorIndex {
|
|
46
|
-
/**
|
|
47
|
-
* Stored embeddings keyed by the canonical {@link edgeTargetKey} of the
|
|
48
|
-
* record's scope-qualified address, so two records that share a filename stem
|
|
49
|
-
* across scopes occupy distinct entries and never overwrite each other.
|
|
50
|
-
*/
|
|
51
|
-
private readonly _vectors: Map<string, IStoredVector>;
|
|
52
|
-
/** The dimension of every stored vector; `undefined` until the first `add`. */
|
|
53
|
-
private _dimension: number | undefined;
|
|
54
|
-
|
|
55
|
-
private constructor() {
|
|
56
|
-
this._vectors = new Map<string, IStoredVector>();
|
|
57
|
-
this._dimension = undefined;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** The number of vectors currently held. */
|
|
61
|
-
public get size(): number {
|
|
62
|
-
return this._vectors.size;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Family-convention factory. */
|
|
66
|
-
public static create(): Result<InMemoryCosineIndex> {
|
|
67
|
-
return succeed(new InMemoryCosineIndex());
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** {@inheritDoc IVectorIndex.add} */
|
|
71
|
-
public add(target: IEdgeTarget, vector: Float32Array): Promise<Result<string>> {
|
|
72
|
-
const key: string = edgeTargetKey(target);
|
|
73
|
-
if (vector.length === 0) {
|
|
74
|
-
return Promise.resolve(fail(`vector index: cannot add '${key}': empty vector`));
|
|
75
|
-
}
|
|
76
|
-
if (this._dimension === undefined) {
|
|
77
|
-
this._dimension = vector.length;
|
|
78
|
-
} else if (vector.length !== this._dimension) {
|
|
79
|
-
return Promise.resolve(
|
|
80
|
-
fail(
|
|
81
|
-
`vector index: cannot add '${key}': dimension ${vector.length} does not match index dimension ${this._dimension}`
|
|
82
|
-
)
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
// Defensive copy: the caller may reuse or mutate the buffer after `add`, and
|
|
86
|
-
// the index must keep serving the embedding it was given.
|
|
87
|
-
this._vectors.set(key, { target, vector: Float32Array.from(vector) });
|
|
88
|
-
// The in-memory index keys entries by the canonical scoped-target string, so
|
|
89
|
-
// that key IS the entry reference.
|
|
90
|
-
return Promise.resolve(succeed(key));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** {@inheritDoc IVectorIndex.remove} */
|
|
94
|
-
public remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>> {
|
|
95
|
-
this._vectors.delete(edgeTargetKey(target));
|
|
96
|
-
return Promise.resolve(succeed(target));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** {@inheritDoc IVectorIndex.query} */
|
|
100
|
-
public query(vector: Float32Array, topK: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>> {
|
|
101
|
-
if (topK <= 0 || this._vectors.size === 0) {
|
|
102
|
-
return Promise.resolve(succeed([]));
|
|
103
|
-
}
|
|
104
|
-
if (vector.length !== this._dimension) {
|
|
105
|
-
return Promise.resolve(
|
|
106
|
-
fail(
|
|
107
|
-
`vector index: query dimension ${vector.length} does not match index dimension ${this._dimension}`
|
|
108
|
-
)
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
const queryMagnitude: number = InMemoryCosineIndex._magnitude(vector);
|
|
112
|
-
const hits: IVectorQueryHit[] = [];
|
|
113
|
-
for (const stored of this._vectors.values()) {
|
|
114
|
-
hits.push({
|
|
115
|
-
target: stored.target,
|
|
116
|
-
score: InMemoryCosineIndex._cosine(vector, queryMagnitude, stored.vector)
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
// Descending by score; a `seq`-free tiebreak is unnecessary here because the
|
|
120
|
-
// caller (SemanticRetriever) re-resolves hits against the record index.
|
|
121
|
-
hits.sort((a, b) => b.score - a.score);
|
|
122
|
-
return Promise.resolve(succeed(hits.length > topK ? hits.slice(0, topK) : hits));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Re-embed every record from `source` and rebuild the index from scratch.
|
|
127
|
-
* Clears the current contents (and the established dimension) first, so a
|
|
128
|
-
* re-embed with a different model is supported. Returns the number of vectors
|
|
129
|
-
* indexed.
|
|
130
|
-
*
|
|
131
|
-
* On any failure (list, embed, or add) the index is rolled back to empty
|
|
132
|
-
* rather than left in a partially-rebuilt state — a caller that retries a query
|
|
133
|
-
* after a failed rebuild sees a clean empty index, never a half-populated one.
|
|
134
|
-
*
|
|
135
|
-
* @param source - The scope-qualified record source to re-embed.
|
|
136
|
-
* @param embed - The embedder applied to each record.
|
|
137
|
-
*/
|
|
138
|
-
public async rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder): Promise<Result<number>> {
|
|
139
|
-
// Reset up front so the "any failure leaves the index empty" contract holds
|
|
140
|
-
// even when the listing itself fails (no stale vectors survive a failed
|
|
141
|
-
// rebuild).
|
|
142
|
-
this._reset();
|
|
143
|
-
const listed: Result<ReadonlyArray<IScopedMemoryRecord>> = await source.list();
|
|
144
|
-
if (listed.isFailure()) {
|
|
145
|
-
return fail(`vector index rebuild: failed to list records: ${listed.message}`);
|
|
146
|
-
}
|
|
147
|
-
for (const scoped of listed.value) {
|
|
148
|
-
const embedded: Result<Float32Array> = await embed(scoped.record);
|
|
149
|
-
if (embedded.isFailure()) {
|
|
150
|
-
this._reset();
|
|
151
|
-
return fail(
|
|
152
|
-
`vector index rebuild: embedding '${edgeTargetKey(scoped.target)}' failed: ${embedded.message}`
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
const added: Result<string> = await this.add(scoped.target, embedded.value);
|
|
156
|
-
if (added.isFailure()) {
|
|
157
|
-
this._reset();
|
|
158
|
-
return fail(`vector index rebuild: ${added.message}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return succeed(this._vectors.size);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/** Empty the index and forget the established dimension. */
|
|
165
|
-
private _reset(): void {
|
|
166
|
-
this._vectors.clear();
|
|
167
|
-
this._dimension = undefined;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/** The Euclidean magnitude (L2 norm) of a vector. */
|
|
171
|
-
private static _magnitude(vector: Float32Array): number {
|
|
172
|
-
let sum: number = 0;
|
|
173
|
-
for (let i: number = 0; i < vector.length; i++) {
|
|
174
|
-
sum += vector[i] * vector[i];
|
|
175
|
-
}
|
|
176
|
-
return Math.sqrt(sum);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Cosine similarity between the query (whose magnitude is precomputed once and
|
|
181
|
-
* reused across the scan) and a stored vector. A zero-magnitude vector on
|
|
182
|
-
* either side yields `0` rather than `NaN` — a degenerate vector is simply
|
|
183
|
-
* maximally dissimilar, not an error.
|
|
184
|
-
*/
|
|
185
|
-
private static _cosine(query: Float32Array, queryMagnitude: number, stored: Float32Array): number {
|
|
186
|
-
const storedMagnitude: number = InMemoryCosineIndex._magnitude(stored);
|
|
187
|
-
if (queryMagnitude === 0 || storedMagnitude === 0) {
|
|
188
|
-
return 0;
|
|
189
|
-
}
|
|
190
|
-
let dot: number = 0;
|
|
191
|
-
for (let i: number = 0; i < query.length; i++) {
|
|
192
|
-
dot += query[i] * stored[i];
|
|
193
|
-
}
|
|
194
|
-
return dot / (queryMagnitude * storedMagnitude);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
@@ -1,289 +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 { IEdgeTarget, edgeTargetKey } from '../types';
|
|
8
|
-
import {
|
|
9
|
-
FragmentEmbedder,
|
|
10
|
-
IEmbeddedFragment,
|
|
11
|
-
IFragmentVectorIndex,
|
|
12
|
-
IMemoryRecordSource,
|
|
13
|
-
IScopedMemoryRecord,
|
|
14
|
-
IVectorQueryHit
|
|
15
|
-
} from './vectorIndex';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* The identity fields a fragment was added with, already in query-hit shape: a field
|
|
19
|
-
* the fragment did not carry is *absent*, never present-but-`undefined`, so a hit
|
|
20
|
-
* for a fragment added without a `fragmentId` is structurally identical to one
|
|
21
|
-
* produced before `fragmentId` existed.
|
|
22
|
-
*/
|
|
23
|
-
type FragmentIdentity = Pick<IVectorQueryHit, 'locator' | 'fragmentId'>;
|
|
24
|
-
|
|
25
|
-
/** Project an incoming fragment's identity fields, dropping the ones it did not carry. */
|
|
26
|
-
function fragmentIdentity(fragment: IEmbeddedFragment): FragmentIdentity {
|
|
27
|
-
return {
|
|
28
|
-
...(fragment.locator !== undefined ? { locator: fragment.locator } : {}),
|
|
29
|
-
...(fragment.fragmentId !== undefined ? { fragmentId: fragment.fragmentId } : {})
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** One stored fragment: the identity it was added with plus its vector. */
|
|
34
|
-
interface IStoredFragment {
|
|
35
|
-
readonly identity: FragmentIdentity;
|
|
36
|
-
readonly vector: Float32Array;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Every stored fragment for one record, tagged with the record's scoped address. */
|
|
40
|
-
interface IStoredRecordFragments {
|
|
41
|
-
readonly target: IEdgeTarget;
|
|
42
|
-
readonly fragments: IStoredFragment[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** A candidate hit carried through selection: the fragment's key, hit, and score. */
|
|
46
|
-
interface IScoredFragment {
|
|
47
|
-
readonly key: string;
|
|
48
|
-
readonly hit: IVectorQueryHit;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* The brute-force, in-memory cosine {@link IFragmentVectorIndex} — the
|
|
53
|
-
* fragment-granular sibling of {@link InMemoryCosineIndex}. Stores many
|
|
54
|
-
* `Float32Array`s per record (one per {@link IEmbeddedFragment | fragment}) and
|
|
55
|
-
* answers a query by computing cosine similarity against every stored fragment,
|
|
56
|
-
* returning the top-k fragment hits by descending score. Each hit carries back
|
|
57
|
-
* whichever of {@link IFragmentLocator | locator} / `fragmentId` its fragment was
|
|
58
|
-
* added with; a fragment must carry at least one of the two.
|
|
59
|
-
*
|
|
60
|
-
* @remarks
|
|
61
|
-
* Same regime and same non-goals as {@link InMemoryCosineIndex}: no external
|
|
62
|
-
* dependency, no ANN structure, a linear scan over the stored fragments — the seam
|
|
63
|
-
* ({@link IFragmentVectorIndex}) stays open for a consumer to swap a persistent /
|
|
64
|
-
* ANN backend once N grows. `addFragments` is whole-record-replace, so re-authoring
|
|
65
|
-
* a document never leaves stale fragments behind. The index has a single dimension
|
|
66
|
-
* established by the first fragment added; every subsequent fragment and every
|
|
67
|
-
* `query` vector must match it or fail loudly — a mismatched dimension is an
|
|
68
|
-
* embedder-wiring bug, never a silent zero-similarity result.
|
|
69
|
-
* {@link InMemoryFragmentCosineIndex.rebuild | rebuild} clears the index (and the
|
|
70
|
-
* established dimension), so a re-embed with a different model is supported.
|
|
71
|
-
*
|
|
72
|
-
* The optional `maxPerRecord` cap on `query` is applied **during selection**, before
|
|
73
|
-
* the `topK` cut, so one long document with many strong fragments cannot crowd every
|
|
74
|
-
* other record out of the result.
|
|
75
|
-
* @public
|
|
76
|
-
*/
|
|
77
|
-
export class InMemoryFragmentCosineIndex implements IFragmentVectorIndex {
|
|
78
|
-
/**
|
|
79
|
-
* Stored fragments keyed by the canonical {@link edgeTargetKey} of the record's
|
|
80
|
-
* scope-qualified address, so two records that share a filename stem across
|
|
81
|
-
* scopes occupy distinct entries and never overwrite each other's fragments.
|
|
82
|
-
*/
|
|
83
|
-
private readonly _records: Map<string, IStoredRecordFragments>;
|
|
84
|
-
/** The dimension of every stored fragment vector; `undefined` until the first `add`. */
|
|
85
|
-
private _dimension: number | undefined;
|
|
86
|
-
|
|
87
|
-
private constructor() {
|
|
88
|
-
this._records = new Map<string, IStoredRecordFragments>();
|
|
89
|
-
this._dimension = undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** The number of records that currently have at least one stored fragment. */
|
|
93
|
-
public get recordCount(): number {
|
|
94
|
-
return this._records.size;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** The total number of fragments currently held across all records. */
|
|
98
|
-
public get fragmentCount(): number {
|
|
99
|
-
let total: number = 0;
|
|
100
|
-
for (const record of this._records.values()) {
|
|
101
|
-
total += record.fragments.length;
|
|
102
|
-
}
|
|
103
|
-
return total;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Family-convention factory. */
|
|
107
|
-
public static create(): Result<InMemoryFragmentCosineIndex> {
|
|
108
|
-
return succeed(new InMemoryFragmentCosineIndex());
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** {@inheritDoc IFragmentVectorIndex.addFragments} */
|
|
112
|
-
public addFragments(
|
|
113
|
-
target: IEdgeTarget,
|
|
114
|
-
fragments: ReadonlyArray<IEmbeddedFragment>
|
|
115
|
-
): Promise<Result<number>> {
|
|
116
|
-
const key: string = edgeTargetKey(target);
|
|
117
|
-
// Validate every fragment before mutating any state, so a bad fragment never
|
|
118
|
-
// leaves the record half-replaced OR the index dimension half-established
|
|
119
|
-
// (whole-record-replace must be all-or-nothing). The effective dimension is the
|
|
120
|
-
// established one, or — on a still-dimensionless index — the first fragment's
|
|
121
|
-
// length; it is only committed to `this._dimension` once the whole batch passes.
|
|
122
|
-
const stored: IStoredFragment[] = [];
|
|
123
|
-
let dimension: number | undefined = this._dimension;
|
|
124
|
-
for (const fragment of fragments) {
|
|
125
|
-
if (fragment.vector.length === 0) {
|
|
126
|
-
return Promise.resolve(fail(`fragment index: cannot add '${key}': empty fragment vector`));
|
|
127
|
-
}
|
|
128
|
-
// A fragment carrying neither identity cannot be resolved back to anything by a
|
|
129
|
-
// consumer holding the hit — the same invariant `embeddedFragmentConverter`
|
|
130
|
-
// enforces at the untyped boundary, re-checked here at the index seam.
|
|
131
|
-
if (fragment.locator === undefined && fragment.fragmentId === undefined) {
|
|
132
|
-
return Promise.resolve(
|
|
133
|
-
fail(
|
|
134
|
-
`fragment index: cannot add '${key}': fragment requires at least one of 'locator' or 'fragmentId'`
|
|
135
|
-
)
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
if (dimension === undefined) {
|
|
139
|
-
dimension = fragment.vector.length;
|
|
140
|
-
} else if (fragment.vector.length !== dimension) {
|
|
141
|
-
return Promise.resolve(
|
|
142
|
-
fail(
|
|
143
|
-
`fragment index: cannot add '${key}': fragment dimension ${fragment.vector.length} does not match index dimension ${dimension}`
|
|
144
|
-
)
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
// Defensive copy: the caller may reuse or mutate the buffer after `addFragments`.
|
|
148
|
-
stored.push({ identity: fragmentIdentity(fragment), vector: Float32Array.from(fragment.vector) });
|
|
149
|
-
}
|
|
150
|
-
// Whole-record replace: an empty `fragments` array drops the record entirely
|
|
151
|
-
// rather than leaving an empty shell behind. Commit the (possibly newly-derived)
|
|
152
|
-
// dimension only alongside a successful, non-empty store.
|
|
153
|
-
if (stored.length === 0) {
|
|
154
|
-
this._records.delete(key);
|
|
155
|
-
} else {
|
|
156
|
-
this._dimension = dimension;
|
|
157
|
-
this._records.set(key, { target, fragments: stored });
|
|
158
|
-
}
|
|
159
|
-
return Promise.resolve(succeed(stored.length));
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/** {@inheritDoc IFragmentVectorIndex.remove} */
|
|
163
|
-
public remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>> {
|
|
164
|
-
this._records.delete(edgeTargetKey(target));
|
|
165
|
-
return Promise.resolve(succeed(target));
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/** {@inheritDoc IFragmentVectorIndex.query} */
|
|
169
|
-
public query(
|
|
170
|
-
vector: Float32Array,
|
|
171
|
-
topK: number,
|
|
172
|
-
maxPerRecord?: number
|
|
173
|
-
): Promise<Result<ReadonlyArray<IVectorQueryHit>>> {
|
|
174
|
-
if (topK <= 0 || this._records.size === 0) {
|
|
175
|
-
return Promise.resolve(succeed([]));
|
|
176
|
-
}
|
|
177
|
-
if (vector.length !== this._dimension) {
|
|
178
|
-
return Promise.resolve(
|
|
179
|
-
fail(
|
|
180
|
-
`fragment index: query dimension ${vector.length} does not match index dimension ${this._dimension}`
|
|
181
|
-
)
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
const queryMagnitude: number = InMemoryFragmentCosineIndex._magnitude(vector);
|
|
185
|
-
const scored: IScoredFragment[] = [];
|
|
186
|
-
for (const record of this._records.values()) {
|
|
187
|
-
for (const fragment of record.fragments) {
|
|
188
|
-
scored.push({
|
|
189
|
-
key: edgeTargetKey(record.target),
|
|
190
|
-
hit: {
|
|
191
|
-
target: record.target,
|
|
192
|
-
score: InMemoryFragmentCosineIndex._cosine(vector, queryMagnitude, fragment.vector),
|
|
193
|
-
...fragment.identity
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// Descending by score; the caller re-resolves each `(target, locator)` hit.
|
|
199
|
-
scored.sort((a, b) => b.hit.score - a.hit.score);
|
|
200
|
-
|
|
201
|
-
const hits: IVectorQueryHit[] = [];
|
|
202
|
-
// Apply the per-record cap during selection (before the topK cut) so a single
|
|
203
|
-
// long document cannot monopolize the result. `undefined` maxPerRecord means
|
|
204
|
-
// uncapped; the counter map is always allocated (tiny) so the guard narrows
|
|
205
|
-
// `maxPerRecord` directly without a non-null assertion.
|
|
206
|
-
const perRecord: Map<string, number> = new Map<string, number>();
|
|
207
|
-
for (const candidate of scored) {
|
|
208
|
-
if (hits.length >= topK) {
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
|
-
if (maxPerRecord !== undefined) {
|
|
212
|
-
const used: number = perRecord.get(candidate.key) ?? 0;
|
|
213
|
-
if (used >= maxPerRecord) {
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
perRecord.set(candidate.key, used + 1);
|
|
217
|
-
}
|
|
218
|
-
hits.push(candidate.hit);
|
|
219
|
-
}
|
|
220
|
-
return Promise.resolve(succeed(hits));
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Re-embed every record from `source` and rebuild the fragment index from
|
|
225
|
-
* scratch. Clears the current contents (and the established dimension) first, so
|
|
226
|
-
* a re-embed with a different model is supported. Returns the total number of
|
|
227
|
-
* fragments indexed.
|
|
228
|
-
*
|
|
229
|
-
* On any failure (list, embed, or add) the index is rolled back to empty rather
|
|
230
|
-
* than left in a partially-rebuilt state.
|
|
231
|
-
*
|
|
232
|
-
* @param source - The scope-qualified record source to re-embed.
|
|
233
|
-
* @param embed - The fragment embedder applied to each record.
|
|
234
|
-
*/
|
|
235
|
-
public async rebuild(source: IMemoryRecordSource, embed: FragmentEmbedder): Promise<Result<number>> {
|
|
236
|
-
this._reset();
|
|
237
|
-
const listed: Result<ReadonlyArray<IScopedMemoryRecord>> = await source.list();
|
|
238
|
-
if (listed.isFailure()) {
|
|
239
|
-
return fail(`fragment index rebuild: failed to list records: ${listed.message}`);
|
|
240
|
-
}
|
|
241
|
-
for (const scoped of listed.value) {
|
|
242
|
-
const embedded: Result<ReadonlyArray<IEmbeddedFragment>> = await embed(scoped.record);
|
|
243
|
-
if (embedded.isFailure()) {
|
|
244
|
-
this._reset();
|
|
245
|
-
return fail(
|
|
246
|
-
`fragment index rebuild: embedding '${edgeTargetKey(scoped.target)}' failed: ${embedded.message}`
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
const added: Result<number> = await this.addFragments(scoped.target, embedded.value);
|
|
250
|
-
if (added.isFailure()) {
|
|
251
|
-
this._reset();
|
|
252
|
-
return fail(`fragment index rebuild: ${added.message}`);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return succeed(this.fragmentCount);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/** Empty the index and forget the established dimension. */
|
|
259
|
-
private _reset(): void {
|
|
260
|
-
this._records.clear();
|
|
261
|
-
this._dimension = undefined;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/** The Euclidean magnitude (L2 norm) of a vector. */
|
|
265
|
-
private static _magnitude(vector: Float32Array): number {
|
|
266
|
-
let sum: number = 0;
|
|
267
|
-
for (let i: number = 0; i < vector.length; i++) {
|
|
268
|
-
sum += vector[i] * vector[i];
|
|
269
|
-
}
|
|
270
|
-
return Math.sqrt(sum);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Cosine similarity between the query (whose magnitude is precomputed once and
|
|
275
|
-
* reused across the scan) and a stored fragment vector. A zero-magnitude vector
|
|
276
|
-
* on either side yields `0` rather than `NaN`.
|
|
277
|
-
*/
|
|
278
|
-
private static _cosine(query: Float32Array, queryMagnitude: number, stored: Float32Array): number {
|
|
279
|
-
const storedMagnitude: number = InMemoryFragmentCosineIndex._magnitude(stored);
|
|
280
|
-
if (queryMagnitude === 0 || storedMagnitude === 0) {
|
|
281
|
-
return 0;
|
|
282
|
-
}
|
|
283
|
-
let dot: number = 0;
|
|
284
|
-
for (let i: number = 0; i < query.length; i++) {
|
|
285
|
-
dot += query[i] * stored[i];
|
|
286
|
-
}
|
|
287
|
-
return dot / (queryMagnitude * storedMagnitude);
|
|
288
|
-
}
|
|
289
|
-
}
|