@fgv/ts-agent-memory 5.1.0-47 → 5.1.0-48
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/store/fileTreeMemoryStore.js +52 -131
- 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/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 +297 -66
- 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/store/fileTreeMemoryStore.d.ts +66 -59
- package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.js +52 -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/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
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { MemoryEmbedOutcome } from '../observe';
|
|
3
|
+
import { IEdgeTarget, IMemoryRecord, Kind, MemoryId, MemoryScopeKey } from '../types';
|
|
4
|
+
import { FragmentEmbedder, IFragmentVectorIndex, IVectorIndex, MemoryEmbedder } from '../vector';
|
|
5
|
+
/**
|
|
6
|
+
* The internal outcome of record-level embed-on-write: the record to persist,
|
|
7
|
+
* plus — only when the embedder declined a record that already carried an
|
|
8
|
+
* `embeddingRef` — the index entry that reference superseded.
|
|
9
|
+
*
|
|
10
|
+
* `stale` is carried out to the caller rather than acted on in place because the
|
|
11
|
+
* prune belongs on the far side of `_persist`: a persist that fails leaves the
|
|
12
|
+
* PREVIOUS content on disk, and the superseded vector is still an accurate
|
|
13
|
+
* embedding of that content.
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export interface IEmbedOnWriteOutcome {
|
|
17
|
+
readonly record: IMemoryRecord<string>;
|
|
18
|
+
readonly stale?: {
|
|
19
|
+
readonly index: IVectorIndex;
|
|
20
|
+
readonly target: IEdgeTarget;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* What the record-granular index did, surfaced on the write observation.
|
|
24
|
+
* `undefined` when the question does not apply (nothing wired).
|
|
25
|
+
*/
|
|
26
|
+
readonly embed?: MemoryEmbedOutcome;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* What {@link VectorMaintenance} needs from the store it serves. Every field is
|
|
30
|
+
* the store's own, passed in rather than reached for, so this collaborator holds
|
|
31
|
+
* no reference back to the store and cannot quietly grow one.
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
export interface IVectorMaintenanceParams {
|
|
35
|
+
readonly vectorIndex?: IVectorIndex;
|
|
36
|
+
readonly embed?: MemoryEmbedder;
|
|
37
|
+
readonly fragmentIndex?: IFragmentVectorIndex;
|
|
38
|
+
readonly fragmentEmbedder?: FragmentEmbedder;
|
|
39
|
+
/** The store's swallowed-failure logger; every vector fault is best-effort. */
|
|
40
|
+
readonly warn: (message: string) => void;
|
|
41
|
+
/**
|
|
42
|
+
* The store's per-kind record-index participation predicate
|
|
43
|
+
* (`IMemoryStore.embedsKind`). Passed in rather than re-derived so the store's
|
|
44
|
+
* declaration and the gate that enforces it cannot disagree.
|
|
45
|
+
*/
|
|
46
|
+
readonly embedsKind: (kind: Kind) => boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The store's record- and fragment-vector maintenance, extracted from
|
|
50
|
+
* {@link FileTreeMemoryStore} as a collaborator.
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* Everything here is **best-effort by contract**: the durable record store is
|
|
54
|
+
* authoritative and both indexes are derived, rebuildable views, so a failed
|
|
55
|
+
* embed, add or remove is logged and the write still succeeds. Nothing in this
|
|
56
|
+
* class can turn a committed write into a `Failure` — which is exactly why it
|
|
57
|
+
* separates cleanly from the store's write path, where every step is fallible
|
|
58
|
+
* and fatal.
|
|
59
|
+
*
|
|
60
|
+
* The split is behavior-preserving: these are the same methods the store used to
|
|
61
|
+
* carry as privates, with the same call order and the same logging. What moved is
|
|
62
|
+
* where they live, not what they do.
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
export declare class VectorMaintenance {
|
|
66
|
+
private readonly _vectorIndex;
|
|
67
|
+
private readonly _embed;
|
|
68
|
+
private readonly _fragmentIndex;
|
|
69
|
+
private readonly _fragmentEmbedder;
|
|
70
|
+
private readonly _warn;
|
|
71
|
+
private readonly _embedsKind;
|
|
72
|
+
constructor(params: IVectorMaintenanceParams);
|
|
73
|
+
/**
|
|
74
|
+
* Best-effort removal of everything the two indexes hold for one record. Used
|
|
75
|
+
* by the delete path and by cull-oldest eviction, both of which have already
|
|
76
|
+
* committed by the time they call it.
|
|
77
|
+
*/
|
|
78
|
+
removeAll(target: IEdgeTarget): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Best-effort embed-on-write. When a vector index AND an embedder are wired,
|
|
81
|
+
* embeds the built record, `add`s the vector (replace semantics handle a same-id
|
|
82
|
+
* re-embed — no explicit remove), and stamps the returned `embeddingRef`. A
|
|
83
|
+
* failure (returned `fail` OR a thrown/rejected hook) is logged and the
|
|
84
|
+
* unembedded record is returned unchanged — the put still persists, and the
|
|
85
|
+
* derived index is reconciled by a later `rebuild`. A pass-through no-op when
|
|
86
|
+
* unwired (byte-identical record).
|
|
87
|
+
*
|
|
88
|
+
* A **decline** is not a failure and is handled differently: see
|
|
89
|
+
* `declineEmbedding`.
|
|
90
|
+
*
|
|
91
|
+
* Always succeeds (`Result` is the chain's shape, never a vector-induced
|
|
92
|
+
* failure).
|
|
93
|
+
*/
|
|
94
|
+
embedOnWrite(built: IMemoryRecord<string>, scope: MemoryScopeKey): Promise<Result<IEmbedOnWriteOutcome>>;
|
|
95
|
+
/**
|
|
96
|
+
* Prune the vector a decline superseded. Best-effort like the rest of the
|
|
97
|
+
* vector path: a failed `remove` is logged and the (already-persisted) record
|
|
98
|
+
* still carries no `embeddingRef`, because the record's own claim about itself
|
|
99
|
+
* should be true even when the derived index is momentarily stale — that is
|
|
100
|
+
* exactly what a later `rebuild` reconciles.
|
|
101
|
+
*
|
|
102
|
+
* The index travels with the target rather than being re-read from the instance
|
|
103
|
+
* so the prune lands on the same index the decline was made against, and so
|
|
104
|
+
* there is no second "is a vector index wired?" check whose false branch cannot
|
|
105
|
+
* be reached.
|
|
106
|
+
*/
|
|
107
|
+
pruneStaleVector(stale: IEmbedOnWriteOutcome['stale']): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Best-effort fragment-embed-on-write. When a fragment index AND a fragment
|
|
110
|
+
* embedder are wired, chunks + embeds the built record and replaces its
|
|
111
|
+
* fragments in the index (`addFragments` is whole-record-replace, so a re-authored
|
|
112
|
+
* document never leaves stale fragments behind — no explicit remove needed). A
|
|
113
|
+
* failure (returned `fail` OR a thrown/rejected hook) is logged and the record is
|
|
114
|
+
* returned unchanged — the put still persists, and the fragment index is a derived
|
|
115
|
+
* view a later `rebuild` reconciles. Unlike `embedOnWrite`
|
|
116
|
+
* it stamps nothing on the record (fragments have no per-record `embeddingRef`
|
|
117
|
+
* analog). A pass-through no-op when unwired (byte-identical record).
|
|
118
|
+
*/
|
|
119
|
+
embedFragmentsOnWrite(built: IMemoryRecord<string>, scope: MemoryScopeKey): Promise<Result<IMemoryRecord<string>>>;
|
|
120
|
+
/**
|
|
121
|
+
* Best-effort fragment removal. A no-op unless the full fragment lifecycle is
|
|
122
|
+
* wired (both an index AND an embedder), so an unwired store does no fragment
|
|
123
|
+
* work and behaves byte-identically. Failures are logged, never surfaced — a
|
|
124
|
+
* committed delete/eviction must not fail because a derived fragment index could
|
|
125
|
+
* not be pruned.
|
|
126
|
+
*/
|
|
127
|
+
private _removeFragmentsBestEffort;
|
|
128
|
+
/**
|
|
129
|
+
* Best-effort vector removal for each evicted record (never fails the put).
|
|
130
|
+
* Every evicted record is in the same `scope` as the incoming write (the
|
|
131
|
+
* cull-oldest cohort is the incoming record's `(scope, kind)` cohort), so that
|
|
132
|
+
* scope qualifies each removal target.
|
|
133
|
+
*/
|
|
134
|
+
removeEvictedVectors(evicted: ReadonlyArray<MemoryId>, scope: MemoryScopeKey): Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* Run a consumer-supplied vector hook, normalizing a thrown/rejected hook into a
|
|
137
|
+
* `Failure` and logging any failure at `warn`. Best-effort: the caller proceeds
|
|
138
|
+
* regardless, since the index is rebuildable.
|
|
139
|
+
*/
|
|
140
|
+
private _tryVectorOp;
|
|
141
|
+
/**
|
|
142
|
+
* Best-effort vector removal. A no-op unless the full vector lifecycle is wired
|
|
143
|
+
* (both an index AND an embedder), so an unwired store does no vector work and
|
|
144
|
+
* behaves byte-identically. Failures are logged, never surfaced — a committed
|
|
145
|
+
* delete/eviction must not fail because a derived index could not be pruned.
|
|
146
|
+
*/
|
|
147
|
+
private _removeVectorBestEffort;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=vectorMaintenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vectorMaintenance.d.ts","sourceRoot":"","sources":["../../../src/packlets/store/vectorMaintenance.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EACL,gBAAgB,EAEhB,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACf,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;KAAE,CAAC;IAChF;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAC;CACrC;AA4CD;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,oBAAoB,CAAC;IAC9C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2B;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmC;IAClE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA+B;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA0B;gBAEnC,MAAM,EAAE,wBAAwB;IASnD;;;;OAIG;IACU,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1D;;;;;;;;;;;;;;OAcG;IACU,YAAY,CACvB,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAC5B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAuDxC;;;;;;;;;;;OAWG;IACU,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlF;;;;;;;;;;OAUG;IACU,qBAAqB,CAChC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAC5B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IAqBzC;;;;;;OAMG;YACW,0BAA0B;IAQxC;;;;;OAKG;IACU,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzG;;;;OAIG;YACW,YAAY;IAa1B;;;;;OAKG;YACW,uBAAuB;CAOtC"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2026 Erik Fortune
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
7
|
+
var t = {};
|
|
8
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
9
|
+
t[p] = s[p];
|
|
10
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
11
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
12
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
13
|
+
t[p[i]] = s[p[i]];
|
|
14
|
+
}
|
|
15
|
+
return t;
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.VectorMaintenance = void 0;
|
|
19
|
+
const ts_utils_1 = require("@fgv/ts-utils");
|
|
20
|
+
/**
|
|
21
|
+
* Project a record the embedder **declined** into its written form: the same
|
|
22
|
+
* record with no `embeddingRef`, plus the vector (if any) that reference
|
|
23
|
+
* superseded, for the caller to prune after the commit.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* A decline says "this record is intentionally not embedded". A re-put of a
|
|
27
|
+
* record that *was* embedded (or a caller who supplied an `embeddingRef` — the
|
|
28
|
+
* field is store-derived by contract but nothing strips it) arrives here
|
|
29
|
+
* carrying an inherited reference, so returning it unchanged would persist
|
|
30
|
+
* `embeddingRef` on a record the store just decided not to embed.
|
|
31
|
+
*
|
|
32
|
+
* Clearing the reference alone would be cosmetic and arguably worse: the index
|
|
33
|
+
* entry keyed on this target would survive, so a semantic query would keep
|
|
34
|
+
* returning the record — scored on its **previous** content — while the record
|
|
35
|
+
* itself claimed not to be indexed. So the vector goes too, via
|
|
36
|
+
* `pruneStaleVector` once the write has committed.
|
|
37
|
+
* `stale` is set only when a reference was actually inherited, which keeps the
|
|
38
|
+
* common decline (a record that was never embedded) free of an index round
|
|
39
|
+
* trip.
|
|
40
|
+
*
|
|
41
|
+
* Pure and static: the decision needs nothing from the instance, and deferring
|
|
42
|
+
* the index call to the caller is what lets it run on the far side of
|
|
43
|
+
* `_persist`.
|
|
44
|
+
*/
|
|
45
|
+
function declineEmbedding(built, index, target, embed) {
|
|
46
|
+
if (built.envelope.embeddingRef === undefined) {
|
|
47
|
+
return { record: built, embed };
|
|
48
|
+
}
|
|
49
|
+
// Rest-spread rather than `embeddingRef: undefined`: the envelope is YAML-
|
|
50
|
+
// serialized, and an explicitly-undefined key is a serializer-dependent way
|
|
51
|
+
// to say "absent" where dropping the key is not.
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
53
|
+
const _a = built.envelope, { embeddingRef } = _a, envelope = __rest(_a, ["embeddingRef"]);
|
|
54
|
+
return { record: { envelope, body: built.body }, stale: { index, target }, embed };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The store's record- and fragment-vector maintenance, extracted from
|
|
58
|
+
* {@link FileTreeMemoryStore} as a collaborator.
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
* Everything here is **best-effort by contract**: the durable record store is
|
|
62
|
+
* authoritative and both indexes are derived, rebuildable views, so a failed
|
|
63
|
+
* embed, add or remove is logged and the write still succeeds. Nothing in this
|
|
64
|
+
* class can turn a committed write into a `Failure` — which is exactly why it
|
|
65
|
+
* separates cleanly from the store's write path, where every step is fallible
|
|
66
|
+
* and fatal.
|
|
67
|
+
*
|
|
68
|
+
* The split is behavior-preserving: these are the same methods the store used to
|
|
69
|
+
* carry as privates, with the same call order and the same logging. What moved is
|
|
70
|
+
* where they live, not what they do.
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
class VectorMaintenance {
|
|
74
|
+
constructor(params) {
|
|
75
|
+
this._vectorIndex = params.vectorIndex;
|
|
76
|
+
this._embed = params.embed;
|
|
77
|
+
this._fragmentIndex = params.fragmentIndex;
|
|
78
|
+
this._fragmentEmbedder = params.fragmentEmbedder;
|
|
79
|
+
this._warn = params.warn;
|
|
80
|
+
this._embedsKind = params.embedsKind;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Best-effort removal of everything the two indexes hold for one record. Used
|
|
84
|
+
* by the delete path and by cull-oldest eviction, both of which have already
|
|
85
|
+
* committed by the time they call it.
|
|
86
|
+
*/
|
|
87
|
+
async removeAll(target) {
|
|
88
|
+
await this._removeVectorBestEffort(target);
|
|
89
|
+
await this._removeFragmentsBestEffort(target);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Best-effort embed-on-write. When a vector index AND an embedder are wired,
|
|
93
|
+
* embeds the built record, `add`s the vector (replace semantics handle a same-id
|
|
94
|
+
* re-embed — no explicit remove), and stamps the returned `embeddingRef`. A
|
|
95
|
+
* failure (returned `fail` OR a thrown/rejected hook) is logged and the
|
|
96
|
+
* unembedded record is returned unchanged — the put still persists, and the
|
|
97
|
+
* derived index is reconciled by a later `rebuild`. A pass-through no-op when
|
|
98
|
+
* unwired (byte-identical record).
|
|
99
|
+
*
|
|
100
|
+
* A **decline** is not a failure and is handled differently: see
|
|
101
|
+
* `declineEmbedding`.
|
|
102
|
+
*
|
|
103
|
+
* Always succeeds (`Result` is the chain's shape, never a vector-induced
|
|
104
|
+
* failure).
|
|
105
|
+
*/
|
|
106
|
+
async embedOnWrite(built, scope) {
|
|
107
|
+
if (this._vectorIndex === undefined || this._embed === undefined) {
|
|
108
|
+
// No outcome: with nothing wired there is no index for the record to be
|
|
109
|
+
// absent from, so reporting one would invent a coverage question the
|
|
110
|
+
// deployment has not asked.
|
|
111
|
+
return (0, ts_utils_1.succeed)({ record: built });
|
|
112
|
+
}
|
|
113
|
+
const vectorIndex = this._vectorIndex;
|
|
114
|
+
const embed = this._embed;
|
|
115
|
+
const target = { scope, id: built.envelope.id };
|
|
116
|
+
// Gate BEFORE the embedder call, which is the whole point: a `MemoryEmbedder`
|
|
117
|
+
// decline still pays the round trip, and on a locally-hosted model that round
|
|
118
|
+
// trip IS the cost. A kind excluded here is never handed to the embedder.
|
|
119
|
+
//
|
|
120
|
+
// An exclusion reaches the same conclusion as a decline — this record is
|
|
121
|
+
// intentionally not embedded — so it takes the same path: an inherited
|
|
122
|
+
// `embeddingRef` is dropped and the vector it named is pruned after the
|
|
123
|
+
// commit. Otherwise narrowing `embedKinds` on an existing vault would leave
|
|
124
|
+
// every previously-embedded record of the excluded kind claiming an
|
|
125
|
+
// embedding the store no longer maintains.
|
|
126
|
+
if (!this._embedsKind(built.envelope.kind)) {
|
|
127
|
+
return (0, ts_utils_1.succeed)(declineEmbedding(built, vectorIndex, target, 'excluded'));
|
|
128
|
+
}
|
|
129
|
+
const embedded = await this._tryVectorOp(() => embed(built), `embedding '${built.envelope.id}'`);
|
|
130
|
+
if (embedded.isFailure()) {
|
|
131
|
+
return (0, ts_utils_1.succeed)({ record: built, embed: 'failed' });
|
|
132
|
+
}
|
|
133
|
+
// A deliberate decline (`undefined`) stores the record with no embedding
|
|
134
|
+
// reference. Deliberately NOT logged, unlike the failure path above: a warning
|
|
135
|
+
// per write would make routine policy look like a recurring fault, which is
|
|
136
|
+
// the confusion this return value exists to end. It is still *reported* — as
|
|
137
|
+
// `embed: 'declined'` on the write observation — because saying nothing at all
|
|
138
|
+
// is what left `embeddingRef` absence three-ways ambiguous.
|
|
139
|
+
if (embedded.value === undefined) {
|
|
140
|
+
return (0, ts_utils_1.succeed)(declineEmbedding(built, vectorIndex, target, 'declined'));
|
|
141
|
+
}
|
|
142
|
+
// Hoisted: the `undefined` check above does not narrow across the callback
|
|
143
|
+
// boundary below, and a local keeps the non-null assertion out of the code.
|
|
144
|
+
const vector = embedded.value;
|
|
145
|
+
const added = await this._tryVectorOp(() => vectorIndex.add(target, vector), `vector add for '${built.envelope.id}'`);
|
|
146
|
+
if (added.isFailure()) {
|
|
147
|
+
return (0, ts_utils_1.succeed)({ record: built, embed: 'failed' });
|
|
148
|
+
}
|
|
149
|
+
return (0, ts_utils_1.succeed)({
|
|
150
|
+
record: { envelope: Object.assign(Object.assign({}, built.envelope), { embeddingRef: added.value }), body: built.body },
|
|
151
|
+
embed: 'embedded'
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Prune the vector a decline superseded. Best-effort like the rest of the
|
|
156
|
+
* vector path: a failed `remove` is logged and the (already-persisted) record
|
|
157
|
+
* still carries no `embeddingRef`, because the record's own claim about itself
|
|
158
|
+
* should be true even when the derived index is momentarily stale — that is
|
|
159
|
+
* exactly what a later `rebuild` reconciles.
|
|
160
|
+
*
|
|
161
|
+
* The index travels with the target rather than being re-read from the instance
|
|
162
|
+
* so the prune lands on the same index the decline was made against, and so
|
|
163
|
+
* there is no second "is a vector index wired?" check whose false branch cannot
|
|
164
|
+
* be reached.
|
|
165
|
+
*/
|
|
166
|
+
async pruneStaleVector(stale) {
|
|
167
|
+
if (stale === undefined) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
await this._tryVectorOp(() => stale.index.remove(stale.target), `vector remove for declined '${stale.target.id}'`);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Best-effort fragment-embed-on-write. When a fragment index AND a fragment
|
|
174
|
+
* embedder are wired, chunks + embeds the built record and replaces its
|
|
175
|
+
* fragments in the index (`addFragments` is whole-record-replace, so a re-authored
|
|
176
|
+
* document never leaves stale fragments behind — no explicit remove needed). A
|
|
177
|
+
* failure (returned `fail` OR a thrown/rejected hook) is logged and the record is
|
|
178
|
+
* returned unchanged — the put still persists, and the fragment index is a derived
|
|
179
|
+
* view a later `rebuild` reconciles. Unlike `embedOnWrite`
|
|
180
|
+
* it stamps nothing on the record (fragments have no per-record `embeddingRef`
|
|
181
|
+
* analog). A pass-through no-op when unwired (byte-identical record).
|
|
182
|
+
*/
|
|
183
|
+
async embedFragmentsOnWrite(built, scope) {
|
|
184
|
+
if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {
|
|
185
|
+
return (0, ts_utils_1.succeed)(built);
|
|
186
|
+
}
|
|
187
|
+
const fragmentIndex = this._fragmentIndex;
|
|
188
|
+
const fragmentEmbedder = this._fragmentEmbedder;
|
|
189
|
+
const target = { scope, id: built.envelope.id };
|
|
190
|
+
const embedded = await this._tryVectorOp(() => fragmentEmbedder(built), `fragment embedding '${built.envelope.id}'`);
|
|
191
|
+
if (embedded.isFailure()) {
|
|
192
|
+
return (0, ts_utils_1.succeed)(built);
|
|
193
|
+
}
|
|
194
|
+
await this._tryVectorOp(() => fragmentIndex.addFragments(target, embedded.value), `fragment add for '${built.envelope.id}'`);
|
|
195
|
+
return (0, ts_utils_1.succeed)(built);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Best-effort fragment removal. A no-op unless the full fragment lifecycle is
|
|
199
|
+
* wired (both an index AND an embedder), so an unwired store does no fragment
|
|
200
|
+
* work and behaves byte-identically. Failures are logged, never surfaced — a
|
|
201
|
+
* committed delete/eviction must not fail because a derived fragment index could
|
|
202
|
+
* not be pruned.
|
|
203
|
+
*/
|
|
204
|
+
async _removeFragmentsBestEffort(target) {
|
|
205
|
+
if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const fragmentIndex = this._fragmentIndex;
|
|
209
|
+
await this._tryVectorOp(() => fragmentIndex.remove(target), `fragment removal for '${target.id}'`);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Best-effort vector removal for each evicted record (never fails the put).
|
|
213
|
+
* Every evicted record is in the same `scope` as the incoming write (the
|
|
214
|
+
* cull-oldest cohort is the incoming record's `(scope, kind)` cohort), so that
|
|
215
|
+
* scope qualifies each removal target.
|
|
216
|
+
*/
|
|
217
|
+
async removeEvictedVectors(evicted, scope) {
|
|
218
|
+
for (const id of evicted) {
|
|
219
|
+
await this.removeAll({ scope, id });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Run a consumer-supplied vector hook, normalizing a thrown/rejected hook into a
|
|
224
|
+
* `Failure` and logging any failure at `warn`. Best-effort: the caller proceeds
|
|
225
|
+
* regardless, since the index is rebuildable.
|
|
226
|
+
*/
|
|
227
|
+
async _tryVectorOp(op, label) {
|
|
228
|
+
let result;
|
|
229
|
+
try {
|
|
230
|
+
result = await op();
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
result = (0, ts_utils_1.fail)(`${label} threw: ${String(err)}`);
|
|
234
|
+
}
|
|
235
|
+
if (result.isFailure()) {
|
|
236
|
+
this._warn(`memory: ${label} failed (best-effort; derived index left for rebuild): ${result.message}`);
|
|
237
|
+
}
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Best-effort vector removal. A no-op unless the full vector lifecycle is wired
|
|
242
|
+
* (both an index AND an embedder), so an unwired store does no vector work and
|
|
243
|
+
* behaves byte-identically. Failures are logged, never surfaced — a committed
|
|
244
|
+
* delete/eviction must not fail because a derived index could not be pruned.
|
|
245
|
+
*/
|
|
246
|
+
async _removeVectorBestEffort(target) {
|
|
247
|
+
if (this._vectorIndex === undefined || this._embed === undefined) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const vectorIndex = this._vectorIndex;
|
|
251
|
+
await this._tryVectorOp(() => vectorIndex.remove(target), `vector removal for '${target.id}'`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
exports.VectorMaintenance = VectorMaintenance;
|
|
255
|
+
//# sourceMappingURL=vectorMaintenance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vectorMaintenance.js","sourceRoot":"","sources":["../../../src/packlets/store/vectorMaintenance.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, fail, succeed } from '@fgv/ts-utils';\nimport { MemoryEmbedOutcome } from '../observe';\nimport { IEdgeTarget, IMemoryRecord, Kind, MemoryId, MemoryScopeKey } from '../types';\nimport {\n FragmentEmbedder,\n IEmbeddedFragment,\n IFragmentVectorIndex,\n IVectorIndex,\n MemoryEmbedder\n} from '../vector';\n\n/**\n * The internal outcome of record-level embed-on-write: the record to persist,\n * plus — only when the embedder declined a record that already carried an\n * `embeddingRef` — the index entry that reference superseded.\n *\n * `stale` is carried out to the caller rather than acted on in place because the\n * prune belongs on the far side of `_persist`: a persist that fails leaves the\n * PREVIOUS content on disk, and the superseded vector is still an accurate\n * embedding of that content.\n * @internal\n */\nexport interface IEmbedOnWriteOutcome {\n readonly record: IMemoryRecord<string>;\n readonly stale?: { readonly index: IVectorIndex; readonly target: IEdgeTarget };\n /**\n * What the record-granular index did, surfaced on the write observation.\n * `undefined` when the question does not apply (nothing wired).\n */\n readonly embed?: MemoryEmbedOutcome;\n}\n\n/**\n * Project a record the embedder **declined** into its written form: the same\n * record with no `embeddingRef`, plus the vector (if any) that reference\n * superseded, for the caller to prune after the commit.\n *\n * @remarks\n * A decline says \"this record is intentionally not embedded\". A re-put of a\n * record that *was* embedded (or a caller who supplied an `embeddingRef` — the\n * field is store-derived by contract but nothing strips it) arrives here\n * carrying an inherited reference, so returning it unchanged would persist\n * `embeddingRef` on a record the store just decided not to embed.\n *\n * Clearing the reference alone would be cosmetic and arguably worse: the index\n * entry keyed on this target would survive, so a semantic query would keep\n * returning the record — scored on its **previous** content — while the record\n * itself claimed not to be indexed. So the vector goes too, via\n * `pruneStaleVector` once the write has committed.\n * `stale` is set only when a reference was actually inherited, which keeps the\n * common decline (a record that was never embedded) free of an index round\n * trip.\n *\n * Pure and static: the decision needs nothing from the instance, and deferring\n * the index call to the caller is what lets it run on the far side of\n * `_persist`.\n */\nfunction declineEmbedding(\n built: IMemoryRecord<string>,\n index: IVectorIndex,\n target: IEdgeTarget,\n embed: MemoryEmbedOutcome\n): IEmbedOnWriteOutcome {\n if (built.envelope.embeddingRef === undefined) {\n return { record: built, embed };\n }\n // Rest-spread rather than `embeddingRef: undefined`: the envelope is YAML-\n // serialized, and an explicitly-undefined key is a serializer-dependent way\n // to say \"absent\" where dropping the key is not.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { embeddingRef, ...envelope } = built.envelope;\n return { record: { envelope, body: built.body }, stale: { index, target }, embed };\n}\n\n/**\n * What {@link VectorMaintenance} needs from the store it serves. Every field is\n * the store's own, passed in rather than reached for, so this collaborator holds\n * no reference back to the store and cannot quietly grow one.\n * @internal\n */\nexport interface IVectorMaintenanceParams {\n readonly vectorIndex?: IVectorIndex;\n readonly embed?: MemoryEmbedder;\n readonly fragmentIndex?: IFragmentVectorIndex;\n readonly fragmentEmbedder?: FragmentEmbedder;\n /** The store's swallowed-failure logger; every vector fault is best-effort. */\n readonly warn: (message: string) => void;\n /**\n * The store's per-kind record-index participation predicate\n * (`IMemoryStore.embedsKind`). Passed in rather than re-derived so the store's\n * declaration and the gate that enforces it cannot disagree.\n */\n readonly embedsKind: (kind: Kind) => boolean;\n}\n\n/**\n * The store's record- and fragment-vector maintenance, extracted from\n * {@link FileTreeMemoryStore} as a collaborator.\n *\n * @remarks\n * Everything here is **best-effort by contract**: the durable record store is\n * authoritative and both indexes are derived, rebuildable views, so a failed\n * embed, add or remove is logged and the write still succeeds. Nothing in this\n * class can turn a committed write into a `Failure` — which is exactly why it\n * separates cleanly from the store's write path, where every step is fallible\n * and fatal.\n *\n * The split is behavior-preserving: these are the same methods the store used to\n * carry as privates, with the same call order and the same logging. What moved is\n * where they live, not what they do.\n * @internal\n */\nexport class VectorMaintenance {\n private readonly _vectorIndex: IVectorIndex | undefined;\n private readonly _embed: MemoryEmbedder | undefined;\n private readonly _fragmentIndex: IFragmentVectorIndex | undefined;\n private readonly _fragmentEmbedder: FragmentEmbedder | undefined;\n private readonly _warn: (message: string) => void;\n private readonly _embedsKind: (kind: Kind) => boolean;\n\n public constructor(params: IVectorMaintenanceParams) {\n this._vectorIndex = params.vectorIndex;\n this._embed = params.embed;\n this._fragmentIndex = params.fragmentIndex;\n this._fragmentEmbedder = params.fragmentEmbedder;\n this._warn = params.warn;\n this._embedsKind = params.embedsKind;\n }\n\n /**\n * Best-effort removal of everything the two indexes hold for one record. Used\n * by the delete path and by cull-oldest eviction, both of which have already\n * committed by the time they call it.\n */\n public async removeAll(target: IEdgeTarget): Promise<void> {\n await this._removeVectorBestEffort(target);\n await this._removeFragmentsBestEffort(target);\n }\n\n /**\n * Best-effort embed-on-write. When a vector index AND an embedder are wired,\n * embeds the built record, `add`s the vector (replace semantics handle a same-id\n * re-embed — no explicit remove), and stamps the returned `embeddingRef`. A\n * failure (returned `fail` OR a thrown/rejected hook) is logged and the\n * unembedded record is returned unchanged — the put still persists, and the\n * derived index is reconciled by a later `rebuild`. A pass-through no-op when\n * unwired (byte-identical record).\n *\n * A **decline** is not a failure and is handled differently: see\n * `declineEmbedding`.\n *\n * Always succeeds (`Result` is the chain's shape, never a vector-induced\n * failure).\n */\n public async embedOnWrite(\n built: IMemoryRecord<string>,\n scope: MemoryScopeKey\n ): Promise<Result<IEmbedOnWriteOutcome>> {\n if (this._vectorIndex === undefined || this._embed === undefined) {\n // No outcome: with nothing wired there is no index for the record to be\n // absent from, so reporting one would invent a coverage question the\n // deployment has not asked.\n return succeed({ record: built });\n }\n const vectorIndex: IVectorIndex = this._vectorIndex;\n const embed: MemoryEmbedder = this._embed;\n const target: IEdgeTarget = { scope, id: built.envelope.id };\n // Gate BEFORE the embedder call, which is the whole point: a `MemoryEmbedder`\n // decline still pays the round trip, and on a locally-hosted model that round\n // trip IS the cost. A kind excluded here is never handed to the embedder.\n //\n // An exclusion reaches the same conclusion as a decline — this record is\n // intentionally not embedded — so it takes the same path: an inherited\n // `embeddingRef` is dropped and the vector it named is pruned after the\n // commit. Otherwise narrowing `embedKinds` on an existing vault would leave\n // every previously-embedded record of the excluded kind claiming an\n // embedding the store no longer maintains.\n if (!this._embedsKind(built.envelope.kind)) {\n return succeed(declineEmbedding(built, vectorIndex, target, 'excluded'));\n }\n const embedded: Result<Float32Array | undefined> = await this._tryVectorOp(\n () => embed(built),\n `embedding '${built.envelope.id}'`\n );\n if (embedded.isFailure()) {\n return succeed({ record: built, embed: 'failed' });\n }\n // A deliberate decline (`undefined`) stores the record with no embedding\n // reference. Deliberately NOT logged, unlike the failure path above: a warning\n // per write would make routine policy look like a recurring fault, which is\n // the confusion this return value exists to end. It is still *reported* — as\n // `embed: 'declined'` on the write observation — because saying nothing at all\n // is what left `embeddingRef` absence three-ways ambiguous.\n if (embedded.value === undefined) {\n return succeed(declineEmbedding(built, vectorIndex, target, 'declined'));\n }\n // Hoisted: the `undefined` check above does not narrow across the callback\n // boundary below, and a local keeps the non-null assertion out of the code.\n const vector: Float32Array = embedded.value;\n const added: Result<string> = await this._tryVectorOp(\n () => vectorIndex.add(target, vector),\n `vector add for '${built.envelope.id}'`\n );\n if (added.isFailure()) {\n return succeed({ record: built, embed: 'failed' });\n }\n return succeed({\n record: { envelope: { ...built.envelope, embeddingRef: added.value }, body: built.body },\n embed: 'embedded'\n });\n }\n\n /**\n * Prune the vector a decline superseded. Best-effort like the rest of the\n * vector path: a failed `remove` is logged and the (already-persisted) record\n * still carries no `embeddingRef`, because the record's own claim about itself\n * should be true even when the derived index is momentarily stale — that is\n * exactly what a later `rebuild` reconciles.\n *\n * The index travels with the target rather than being re-read from the instance\n * so the prune lands on the same index the decline was made against, and so\n * there is no second \"is a vector index wired?\" check whose false branch cannot\n * be reached.\n */\n public async pruneStaleVector(stale: IEmbedOnWriteOutcome['stale']): Promise<void> {\n if (stale === undefined) {\n return;\n }\n await this._tryVectorOp(\n () => stale.index.remove(stale.target),\n `vector remove for declined '${stale.target.id}'`\n );\n }\n\n /**\n * Best-effort fragment-embed-on-write. When a fragment index AND a fragment\n * embedder are wired, chunks + embeds the built record and replaces its\n * fragments in the index (`addFragments` is whole-record-replace, so a re-authored\n * document never leaves stale fragments behind — no explicit remove needed). A\n * failure (returned `fail` OR a thrown/rejected hook) is logged and the record is\n * returned unchanged — the put still persists, and the fragment index is a derived\n * view a later `rebuild` reconciles. Unlike `embedOnWrite`\n * it stamps nothing on the record (fragments have no per-record `embeddingRef`\n * analog). A pass-through no-op when unwired (byte-identical record).\n */\n public async embedFragmentsOnWrite(\n built: IMemoryRecord<string>,\n scope: MemoryScopeKey\n ): Promise<Result<IMemoryRecord<string>>> {\n if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {\n return succeed(built);\n }\n const fragmentIndex: IFragmentVectorIndex = this._fragmentIndex;\n const fragmentEmbedder: FragmentEmbedder = this._fragmentEmbedder;\n const target: IEdgeTarget = { scope, id: built.envelope.id };\n const embedded: Result<ReadonlyArray<IEmbeddedFragment>> = await this._tryVectorOp(\n () => fragmentEmbedder(built),\n `fragment embedding '${built.envelope.id}'`\n );\n if (embedded.isFailure()) {\n return succeed(built);\n }\n await this._tryVectorOp(\n () => fragmentIndex.addFragments(target, embedded.value),\n `fragment add for '${built.envelope.id}'`\n );\n return succeed(built);\n }\n\n /**\n * Best-effort fragment removal. A no-op unless the full fragment lifecycle is\n * wired (both an index AND an embedder), so an unwired store does no fragment\n * work and behaves byte-identically. Failures are logged, never surfaced — a\n * committed delete/eviction must not fail because a derived fragment index could\n * not be pruned.\n */\n private async _removeFragmentsBestEffort(target: IEdgeTarget): Promise<void> {\n if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {\n return;\n }\n const fragmentIndex: IFragmentVectorIndex = this._fragmentIndex;\n await this._tryVectorOp(() => fragmentIndex.remove(target), `fragment removal for '${target.id}'`);\n }\n\n /**\n * Best-effort vector removal for each evicted record (never fails the put).\n * Every evicted record is in the same `scope` as the incoming write (the\n * cull-oldest cohort is the incoming record's `(scope, kind)` cohort), so that\n * scope qualifies each removal target.\n */\n public async removeEvictedVectors(evicted: ReadonlyArray<MemoryId>, scope: MemoryScopeKey): Promise<void> {\n for (const id of evicted) {\n await this.removeAll({ scope, id });\n }\n }\n\n /**\n * Run a consumer-supplied vector hook, normalizing a thrown/rejected hook into a\n * `Failure` and logging any failure at `warn`. Best-effort: the caller proceeds\n * regardless, since the index is rebuildable.\n */\n private async _tryVectorOp<T>(op: () => Promise<Result<T>>, label: string): Promise<Result<T>> {\n let result: Result<T>;\n try {\n result = await op();\n } catch (err) {\n result = fail(`${label} threw: ${String(err)}`);\n }\n if (result.isFailure()) {\n this._warn(`memory: ${label} failed (best-effort; derived index left for rebuild): ${result.message}`);\n }\n return result;\n }\n\n /**\n * Best-effort vector removal. A no-op unless the full vector lifecycle is wired\n * (both an index AND an embedder), so an unwired store does no vector work and\n * behaves byte-identically. Failures are logged, never surfaced — a committed\n * delete/eviction must not fail because a derived index could not be pruned.\n */\n private async _removeVectorBestEffort(target: IEdgeTarget): Promise<void> {\n if (this._vectorIndex === undefined || this._embed === undefined) {\n return;\n }\n const vectorIndex: IVectorIndex = this._vectorIndex;\n await this._tryVectorOp(() => vectorIndex.remove(target), `vector removal for '${target.id}'`);\n }\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Result } from '@fgv/ts-utils';
|
|
2
2
|
import { IEdgeTarget } from '../types';
|
|
3
|
-
import { IMemoryRecordSource, IVectorIndex, IVectorQueryHit, MemoryEmbedder } from './vectorIndex';
|
|
3
|
+
import { IMemoryRecordSource, IVectorIndex, IVectorQueryHit, IVectorRebuildOptions, IVectorRebuildReport, MemoryEmbedder } from './vectorIndex';
|
|
4
4
|
/**
|
|
5
5
|
* The brute-force, in-memory cosine {@link IVectorIndex}. Stores one
|
|
6
6
|
* `Float32Array` per record and answers a query by computing cosine similarity
|
|
@@ -47,17 +47,40 @@ export declare class InMemoryCosineIndex implements IVectorIndex {
|
|
|
47
47
|
/**
|
|
48
48
|
* Re-embed every record from `source` and rebuild the index from scratch.
|
|
49
49
|
* Clears the current contents (and the established dimension) first, so a
|
|
50
|
-
* re-embed with a different model is supported. Returns
|
|
51
|
-
* indexed.
|
|
50
|
+
* re-embed with a different model is supported. Returns an
|
|
51
|
+
* {@link IVectorRebuildReport} describing what was indexed, declined and skipped.
|
|
52
52
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
53
|
+
* @remarks
|
|
54
|
+
* **A failure to LIST is always fatal**, under either mode — and **leaves the
|
|
55
|
+
* existing index untouched**: an unreadable source says nothing about which
|
|
56
|
+
* records exist, so there is neither an honest partial to report nor any reason
|
|
57
|
+
* to discard what is already held.
|
|
58
|
+
*
|
|
59
|
+
* Per-record embed/add failures are governed by
|
|
60
|
+
* {@link IVectorRebuildOptions.onRecordError}, which defaults to `'fail'` —
|
|
61
|
+
* **the historical all-or-nothing contract, unchanged**: the index is rolled back
|
|
62
|
+
* to empty rather than left partially rebuilt, so a caller that retries a query
|
|
63
|
+
* sees a clean empty index it can reason about.
|
|
64
|
+
*
|
|
65
|
+
* `'skip'` opts into the lenient shape the store's own open already uses: the
|
|
66
|
+
* rebuild continues and every casualty is returned structurally on
|
|
67
|
+
* {@link IVectorRebuildReport.skipped}. **It reports more, it does not report
|
|
68
|
+
* less** — the point is to stop one bad record emptying an entire index, not to
|
|
69
|
+
* make failures quieter. A caller that ignores `skipped` under `'skip'` has
|
|
70
|
+
* chosen to, rather than been given no way to know.
|
|
71
|
+
*
|
|
72
|
+
* A {@link MemoryEmbedder} decline is not a failure under either mode: it is
|
|
73
|
+
* counted on {@link IVectorRebuildReport.declined} and never appears in `skipped`.
|
|
74
|
+
*
|
|
75
|
+
* Both consumer-supplied hooks are capture-wrapped, so a `source` or `embed`
|
|
76
|
+
* that throws or rejects becomes a `Failure` on the path above rather than an
|
|
77
|
+
* exception escaping mid-rebuild — which would bypass the rollback entirely.
|
|
56
78
|
*
|
|
57
79
|
* @param source - The scope-qualified record source to re-embed.
|
|
58
80
|
* @param embed - The embedder applied to each record.
|
|
81
|
+
* @param options - Rebuild options; omit for the historical `'fail'` behavior.
|
|
59
82
|
*/
|
|
60
|
-
rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder): Promise<Result<
|
|
83
|
+
rebuild(source: IMemoryRecordSource, embed: MemoryEmbedder, options?: IVectorRebuildOptions): Promise<Result<IVectorRebuildReport>>;
|
|
61
84
|
/** Empty the index and forget the established dimension. */
|
|
62
85
|
private _reset;
|
|
63
86
|
/** The Euclidean magnitude (L2 norm) of a vector. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inMemoryCosineIndex.d.ts","sourceRoot":"","sources":["../../../src/packlets/vector/inMemoryCosineIndex.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"inMemoryCosineIndex.d.ts","sourceRoot":"","sources":["../../../src/packlets/vector/inMemoryCosineIndex.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAqC,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAiB,MAAM,UAAU,CAAC;AACtD,OAAO,EACL,mBAAmB,EAGnB,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACf,MAAM,eAAe,CAAC;AAkBvB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,mBAAoB,YAAW,YAAY;IACtD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,+EAA+E;IAC/E,OAAO,CAAC,UAAU,CAAqB;IAEvC,OAAO;IAKP,4CAA4C;IAC5C,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,iCAAiC;WACnB,MAAM,IAAI,MAAM,CAAC,mBAAmB,CAAC;IAInD,qCAAqC;IAC9B,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAsB9E,wCAAwC;IACjC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAKhE,uCAAuC;IAChC,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;IAyBjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACU,OAAO,CAClB,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAwDxC,4DAA4D;IAC5D,OAAO,CAAC,MAAM;IAKd,qDAAqD;IACrD,OAAO,CAAC,MAAM,CAAC,UAAU;IAQzB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,OAAO;CAWvB"}
|
|
@@ -7,6 +7,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.InMemoryCosineIndex = void 0;
|
|
8
8
|
const ts_utils_1 = require("@fgv/ts-utils");
|
|
9
9
|
const types_1 = require("../types");
|
|
10
|
+
/**
|
|
11
|
+
* Invoke a consumer-supplied hook that already returns a `Result`, converting a
|
|
12
|
+
* synchronous throw or a promise rejection into a `Failure` rather than letting
|
|
13
|
+
* it escape. `captureAsyncResult` wraps the hook's own `Result`, so the outcome
|
|
14
|
+
* is flattened back to one level.
|
|
15
|
+
*/
|
|
16
|
+
async function invokeHook(hook) {
|
|
17
|
+
return (await (0, ts_utils_1.captureAsyncResult)(hook)).onSuccess((inner) => inner);
|
|
18
|
+
}
|
|
10
19
|
/**
|
|
11
20
|
* The brute-force, in-memory cosine {@link IVectorIndex}. Stores one
|
|
12
21
|
* `Float32Array` per record and answers a query by computing cosine similarity
|
|
@@ -91,38 +100,92 @@ class InMemoryCosineIndex {
|
|
|
91
100
|
/**
|
|
92
101
|
* Re-embed every record from `source` and rebuild the index from scratch.
|
|
93
102
|
* Clears the current contents (and the established dimension) first, so a
|
|
94
|
-
* re-embed with a different model is supported. Returns
|
|
95
|
-
* indexed.
|
|
103
|
+
* re-embed with a different model is supported. Returns an
|
|
104
|
+
* {@link IVectorRebuildReport} describing what was indexed, declined and skipped.
|
|
105
|
+
*
|
|
106
|
+
* @remarks
|
|
107
|
+
* **A failure to LIST is always fatal**, under either mode — and **leaves the
|
|
108
|
+
* existing index untouched**: an unreadable source says nothing about which
|
|
109
|
+
* records exist, so there is neither an honest partial to report nor any reason
|
|
110
|
+
* to discard what is already held.
|
|
111
|
+
*
|
|
112
|
+
* Per-record embed/add failures are governed by
|
|
113
|
+
* {@link IVectorRebuildOptions.onRecordError}, which defaults to `'fail'` —
|
|
114
|
+
* **the historical all-or-nothing contract, unchanged**: the index is rolled back
|
|
115
|
+
* to empty rather than left partially rebuilt, so a caller that retries a query
|
|
116
|
+
* sees a clean empty index it can reason about.
|
|
96
117
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
118
|
+
* `'skip'` opts into the lenient shape the store's own open already uses: the
|
|
119
|
+
* rebuild continues and every casualty is returned structurally on
|
|
120
|
+
* {@link IVectorRebuildReport.skipped}. **It reports more, it does not report
|
|
121
|
+
* less** — the point is to stop one bad record emptying an entire index, not to
|
|
122
|
+
* make failures quieter. A caller that ignores `skipped` under `'skip'` has
|
|
123
|
+
* chosen to, rather than been given no way to know.
|
|
124
|
+
*
|
|
125
|
+
* A {@link MemoryEmbedder} decline is not a failure under either mode: it is
|
|
126
|
+
* counted on {@link IVectorRebuildReport.declined} and never appears in `skipped`.
|
|
127
|
+
*
|
|
128
|
+
* Both consumer-supplied hooks are capture-wrapped, so a `source` or `embed`
|
|
129
|
+
* that throws or rejects becomes a `Failure` on the path above rather than an
|
|
130
|
+
* exception escaping mid-rebuild — which would bypass the rollback entirely.
|
|
100
131
|
*
|
|
101
132
|
* @param source - The scope-qualified record source to re-embed.
|
|
102
133
|
* @param embed - The embedder applied to each record.
|
|
134
|
+
* @param options - Rebuild options; omit for the historical `'fail'` behavior.
|
|
103
135
|
*/
|
|
104
|
-
async rebuild(source, embed) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
this._reset();
|
|
109
|
-
const listed = await source.list();
|
|
136
|
+
async rebuild(source, embed, options) {
|
|
137
|
+
var _a;
|
|
138
|
+
const lenient = ((_a = options === null || options === void 0 ? void 0 : options.onRecordError) !== null && _a !== void 0 ? _a : 'fail') === 'skip';
|
|
139
|
+
const listed = await invokeHook(() => source.list());
|
|
110
140
|
if (listed.isFailure()) {
|
|
141
|
+
// Deliberately BEFORE the reset. This used to reset first, on the reasoning
|
|
142
|
+
// that no stale vectors should survive a failed rebuild — but a failed list
|
|
143
|
+
// is no evidence about the vectors already held, and nothing has been
|
|
144
|
+
// re-embedded yet, so there is no half-rebuilt state to guard against.
|
|
145
|
+
// Leaving the prior contents intact is the more correct answer, and on the
|
|
146
|
+
// durable sibling (`SqliteVecVectorIndex`) resetting here was data loss.
|
|
111
147
|
return (0, ts_utils_1.fail)(`vector index rebuild: failed to list records: ${listed.message}`);
|
|
112
148
|
}
|
|
149
|
+
// From here a rebuild is genuinely starting, so clear. A mid-loop failure
|
|
150
|
+
// under `'fail'` still resets, which is what keeps that contract honest.
|
|
151
|
+
this._reset();
|
|
152
|
+
let declined = 0;
|
|
153
|
+
const skipped = [];
|
|
113
154
|
for (const scoped of listed.value) {
|
|
114
|
-
|
|
155
|
+
// Both hooks are consumer-supplied, so a throw or rejection is captured
|
|
156
|
+
// into a `Failure` rather than escaping as an exception — otherwise a
|
|
157
|
+
// badly-behaved embedder would reject out of `rebuild` mid-loop and leave
|
|
158
|
+
// the index half-populated, which is precisely what the rollback below
|
|
159
|
+
// exists to prevent.
|
|
160
|
+
const embedded = await invokeHook(() => embed(scoped.record));
|
|
115
161
|
if (embedded.isFailure()) {
|
|
116
|
-
|
|
117
|
-
|
|
162
|
+
const error = `vector index rebuild: embedding '${(0, types_1.edgeTargetKey)(scoped.target)}' failed: ${embedded.message}`;
|
|
163
|
+
// `'fail'` keeps the historical all-or-nothing contract EXACTLY: reset and
|
|
164
|
+
// abort, so a caller that retries a query sees a clean empty index rather
|
|
165
|
+
// than a partially-rebuilt one it cannot reason about.
|
|
166
|
+
if (!lenient) {
|
|
167
|
+
this._reset();
|
|
168
|
+
return (0, ts_utils_1.fail)(error);
|
|
169
|
+
}
|
|
170
|
+
skipped.push({ target: scoped.target, error });
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
// A decline is not an error under either mode — it is counted, never skipped.
|
|
174
|
+
if (embedded.value === undefined) {
|
|
175
|
+
declined++;
|
|
176
|
+
continue;
|
|
118
177
|
}
|
|
119
178
|
const added = await this.add(scoped.target, embedded.value);
|
|
120
179
|
if (added.isFailure()) {
|
|
121
|
-
|
|
122
|
-
|
|
180
|
+
const error = `vector index rebuild: ${added.message}`;
|
|
181
|
+
if (!lenient) {
|
|
182
|
+
this._reset();
|
|
183
|
+
return (0, ts_utils_1.fail)(error);
|
|
184
|
+
}
|
|
185
|
+
skipped.push({ target: scoped.target, error });
|
|
123
186
|
}
|
|
124
187
|
}
|
|
125
|
-
return (0, ts_utils_1.succeed)(this._vectors.size);
|
|
188
|
+
return (0, ts_utils_1.succeed)({ indexed: this._vectors.size, declined, skipped });
|
|
126
189
|
}
|
|
127
190
|
/** Empty the index and forget the established dimension. */
|
|
128
191
|
_reset() {
|