@fgv/ts-agent-memory 5.1.0-36
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/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +9 -0
- package/.rush/temp/f6a88bfdd66517ccb98c2c7ae1be6e6fe9e15d38.tar.log +282 -0
- package/.rush/temp/operation/build/all.log +9 -0
- package/.rush/temp/operation/build/log-chunks.jsonl +9 -0
- package/.rush/temp/operation/build/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +688 -0
- package/LICENSE +21 -0
- package/README.md +45 -0
- package/config/api-extractor.json +343 -0
- package/config/jest.config.json +14 -0
- package/config/rig.json +4 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/packlets/converters/bodyConverterRegistry.js +51 -0
- package/dist/packlets/converters/bodyConverterRegistry.js.map +1 -0
- package/dist/packlets/converters/envelopeConverter.js +159 -0
- package/dist/packlets/converters/envelopeConverter.js.map +1 -0
- package/dist/packlets/converters/index.js +7 -0
- package/dist/packlets/converters/index.js.map +1 -0
- package/dist/packlets/index/index.js +6 -0
- package/dist/packlets/index/index.js.map +1 -0
- package/dist/packlets/index/memoryIndex.js +170 -0
- package/dist/packlets/index/memoryIndex.js.map +1 -0
- package/dist/packlets/observe/index.js +7 -0
- package/dist/packlets/observe/index.js.map +1 -0
- package/dist/packlets/observe/memoryObservationStore.js +119 -0
- package/dist/packlets/observe/memoryObservationStore.js.map +1 -0
- package/dist/packlets/observe/observer.js +6 -0
- package/dist/packlets/observe/observer.js.map +1 -0
- package/dist/packlets/retrieve/hybridRetriever.js +135 -0
- package/dist/packlets/retrieve/hybridRetriever.js.map +1 -0
- package/dist/packlets/retrieve/index.js +12 -0
- package/dist/packlets/retrieve/index.js.map +1 -0
- package/dist/packlets/retrieve/linkTraversalRetriever.js +143 -0
- package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -0
- package/dist/packlets/retrieve/recencyRetriever.js +33 -0
- package/dist/packlets/retrieve/recencyRetriever.js.map +1 -0
- package/dist/packlets/retrieve/retriever.js +110 -0
- package/dist/packlets/retrieve/retriever.js.map +1 -0
- package/dist/packlets/retrieve/semanticRetriever.js +86 -0
- package/dist/packlets/retrieve/semanticRetriever.js.map +1 -0
- package/dist/packlets/retrieve/structuredFilterRetriever.js +37 -0
- package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -0
- package/dist/packlets/retrieve/tagRetriever.js +37 -0
- package/dist/packlets/retrieve/tagRetriever.js.map +1 -0
- package/dist/packlets/store/fileTreeMemoryStore.js +698 -0
- package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -0
- package/dist/packlets/store/index.js +7 -0
- package/dist/packlets/store/index.js.map +1 -0
- package/dist/packlets/store/scopeEncoding.js +31 -0
- package/dist/packlets/store/scopeEncoding.js.map +1 -0
- package/dist/packlets/types/envelope.js +6 -0
- package/dist/packlets/types/envelope.js.map +1 -0
- package/dist/packlets/types/filenameSafety.js +52 -0
- package/dist/packlets/types/filenameSafety.js.map +1 -0
- package/dist/packlets/types/identityCodec.js +184 -0
- package/dist/packlets/types/identityCodec.js.map +1 -0
- package/dist/packlets/types/ids.js +67 -0
- package/dist/packlets/types/ids.js.map +1 -0
- package/dist/packlets/types/index.js +10 -0
- package/dist/packlets/types/index.js.map +1 -0
- package/dist/packlets/types/writePolicy.js +263 -0
- package/dist/packlets/types/writePolicy.js.map +1 -0
- package/dist/packlets/vector/inMemoryCosineIndex.js +150 -0
- package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -0
- package/dist/packlets/vector/index.js +7 -0
- package/dist/packlets/vector/index.js.map +1 -0
- package/dist/packlets/vector/vectorIndex.js +6 -0
- package/dist/packlets/vector/vectorIndex.js.map +1 -0
- package/dist/test/unit/converters/bodyConverterRegistry.test.js +72 -0
- package/dist/test/unit/converters/bodyConverterRegistry.test.js.map +1 -0
- package/dist/test/unit/converters/envelopeConverter.test.js +196 -0
- package/dist/test/unit/converters/envelopeConverter.test.js.map +1 -0
- package/dist/test/unit/index/memoryIndex.test.js +152 -0
- package/dist/test/unit/index/memoryIndex.test.js.map +1 -0
- package/dist/test/unit/observe/memoryObservationStore.test.js +118 -0
- package/dist/test/unit/observe/memoryObservationStore.test.js.map +1 -0
- package/dist/test/unit/retrieve/linkTraversalRetriever.test.js +182 -0
- package/dist/test/unit/retrieve/linkTraversalRetriever.test.js.map +1 -0
- package/dist/test/unit/retrieve/retrievers.test.js +506 -0
- package/dist/test/unit/retrieve/retrievers.test.js.map +1 -0
- package/dist/test/unit/store/embedOnWrite.test.js +260 -0
- package/dist/test/unit/store/embedOnWrite.test.js.map +1 -0
- package/dist/test/unit/store/fileTreeMemoryStore.test.js +647 -0
- package/dist/test/unit/store/fileTreeMemoryStore.test.js.map +1 -0
- package/dist/test/unit/store/observations.test.js +239 -0
- package/dist/test/unit/store/observations.test.js.map +1 -0
- package/dist/test/unit/store/scopeEncoding.test.js +24 -0
- package/dist/test/unit/store/scopeEncoding.test.js.map +1 -0
- package/dist/test/unit/types/identityCodec.test.js +187 -0
- package/dist/test/unit/types/identityCodec.test.js.map +1 -0
- package/dist/test/unit/types/ids.test.js +84 -0
- package/dist/test/unit/types/ids.test.js.map +1 -0
- package/dist/test/unit/types/writePolicy.test.js +241 -0
- package/dist/test/unit/types/writePolicy.test.js.map +1 -0
- package/dist/test/unit/vector/inMemoryCosineIndex.test.js +192 -0
- package/dist/test/unit/vector/inMemoryCosineIndex.test.js.map +1 -0
- package/dist/test/unit/vector/vectorIndex.test.js +42 -0
- package/dist/test/unit/vector/vectorIndex.test.js.map +1 -0
- package/dist/ts-agent-memory.d.ts +1901 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/eslint.config.js +15 -0
- package/etc/ts-agent-memory.api.md +525 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +28 -0
- package/lib/index.js.map +1 -0
- package/lib/packlets/converters/bodyConverterRegistry.d.ts +64 -0
- package/lib/packlets/converters/bodyConverterRegistry.d.ts.map +1 -0
- package/lib/packlets/converters/bodyConverterRegistry.js +55 -0
- package/lib/packlets/converters/bodyConverterRegistry.js.map +1 -0
- package/lib/packlets/converters/envelopeConverter.d.ts +70 -0
- package/lib/packlets/converters/envelopeConverter.d.ts.map +1 -0
- package/lib/packlets/converters/envelopeConverter.js +166 -0
- package/lib/packlets/converters/envelopeConverter.js.map +1 -0
- package/lib/packlets/converters/index.d.ts +3 -0
- package/lib/packlets/converters/index.d.ts.map +1 -0
- package/lib/packlets/converters/index.js +23 -0
- package/lib/packlets/converters/index.js.map +1 -0
- package/lib/packlets/index/index.d.ts +2 -0
- package/lib/packlets/index/index.d.ts.map +1 -0
- package/lib/packlets/index/index.js +22 -0
- package/lib/packlets/index/index.js.map +1 -0
- package/lib/packlets/index/memoryIndex.d.ts +127 -0
- package/lib/packlets/index/memoryIndex.d.ts.map +1 -0
- package/lib/packlets/index/memoryIndex.js +174 -0
- package/lib/packlets/index/memoryIndex.js.map +1 -0
- package/lib/packlets/observe/index.d.ts +3 -0
- package/lib/packlets/observe/index.d.ts.map +1 -0
- package/lib/packlets/observe/index.js +23 -0
- package/lib/packlets/observe/index.js.map +1 -0
- package/lib/packlets/observe/memoryObservationStore.d.ts +91 -0
- package/lib/packlets/observe/memoryObservationStore.d.ts.map +1 -0
- package/lib/packlets/observe/memoryObservationStore.js +123 -0
- package/lib/packlets/observe/memoryObservationStore.js.map +1 -0
- package/lib/packlets/observe/observer.d.ts +110 -0
- package/lib/packlets/observe/observer.d.ts.map +1 -0
- package/lib/packlets/observe/observer.js +7 -0
- package/lib/packlets/observe/observer.js.map +1 -0
- package/lib/packlets/retrieve/hybridRetriever.d.ts +79 -0
- package/lib/packlets/retrieve/hybridRetriever.d.ts.map +1 -0
- package/lib/packlets/retrieve/hybridRetriever.js +140 -0
- package/lib/packlets/retrieve/hybridRetriever.js.map +1 -0
- package/lib/packlets/retrieve/index.d.ts +8 -0
- package/lib/packlets/retrieve/index.d.ts.map +1 -0
- package/lib/packlets/retrieve/index.js +28 -0
- package/lib/packlets/retrieve/index.js.map +1 -0
- package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +61 -0
- package/lib/packlets/retrieve/linkTraversalRetriever.d.ts.map +1 -0
- package/lib/packlets/retrieve/linkTraversalRetriever.js +147 -0
- package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -0
- package/lib/packlets/retrieve/recencyRetriever.d.ts +21 -0
- package/lib/packlets/retrieve/recencyRetriever.d.ts.map +1 -0
- package/lib/packlets/retrieve/recencyRetriever.js +37 -0
- package/lib/packlets/retrieve/recencyRetriever.js.map +1 -0
- package/lib/packlets/retrieve/retriever.d.ts +133 -0
- package/lib/packlets/retrieve/retriever.d.ts.map +1 -0
- package/lib/packlets/retrieve/retriever.js +119 -0
- package/lib/packlets/retrieve/retriever.js.map +1 -0
- package/lib/packlets/retrieve/semanticRetriever.d.ts +69 -0
- package/lib/packlets/retrieve/semanticRetriever.d.ts.map +1 -0
- package/lib/packlets/retrieve/semanticRetriever.js +90 -0
- package/lib/packlets/retrieve/semanticRetriever.js.map +1 -0
- package/lib/packlets/retrieve/structuredFilterRetriever.d.ts +22 -0
- package/lib/packlets/retrieve/structuredFilterRetriever.d.ts.map +1 -0
- package/lib/packlets/retrieve/structuredFilterRetriever.js +41 -0
- package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -0
- package/lib/packlets/retrieve/tagRetriever.d.ts +22 -0
- package/lib/packlets/retrieve/tagRetriever.d.ts.map +1 -0
- package/lib/packlets/retrieve/tagRetriever.js +41 -0
- package/lib/packlets/retrieve/tagRetriever.js.map +1 -0
- package/lib/packlets/store/fileTreeMemoryStore.d.ts +327 -0
- package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -0
- package/lib/packlets/store/fileTreeMemoryStore.js +702 -0
- package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -0
- package/lib/packlets/store/index.d.ts +3 -0
- package/lib/packlets/store/index.d.ts.map +1 -0
- package/lib/packlets/store/index.js +23 -0
- package/lib/packlets/store/index.js.map +1 -0
- package/lib/packlets/store/scopeEncoding.d.ts +19 -0
- package/lib/packlets/store/scopeEncoding.d.ts.map +1 -0
- package/lib/packlets/store/scopeEncoding.js +34 -0
- package/lib/packlets/store/scopeEncoding.js.map +1 -0
- package/lib/packlets/types/envelope.d.ts +119 -0
- package/lib/packlets/types/envelope.d.ts.map +1 -0
- package/lib/packlets/types/envelope.js +7 -0
- package/lib/packlets/types/envelope.js.map +1 -0
- package/lib/packlets/types/filenameSafety.d.ts +16 -0
- package/lib/packlets/types/filenameSafety.d.ts.map +1 -0
- package/lib/packlets/types/filenameSafety.js +55 -0
- package/lib/packlets/types/filenameSafety.js.map +1 -0
- package/lib/packlets/types/identityCodec.d.ts +136 -0
- package/lib/packlets/types/identityCodec.d.ts.map +1 -0
- package/lib/packlets/types/identityCodec.js +190 -0
- package/lib/packlets/types/identityCodec.js.map +1 -0
- package/lib/packlets/types/ids.d.ts +55 -0
- package/lib/packlets/types/ids.d.ts.map +1 -0
- package/lib/packlets/types/ids.js +70 -0
- package/lib/packlets/types/ids.js.map +1 -0
- package/lib/packlets/types/index.d.ts +6 -0
- package/lib/packlets/types/index.d.ts.map +1 -0
- package/lib/packlets/types/index.js +26 -0
- package/lib/packlets/types/index.js.map +1 -0
- package/lib/packlets/types/writePolicy.d.ts +213 -0
- package/lib/packlets/types/writePolicy.d.ts.map +1 -0
- package/lib/packlets/types/writePolicy.js +268 -0
- package/lib/packlets/types/writePolicy.js.map +1 -0
- package/lib/packlets/vector/inMemoryCosineIndex.d.ts +69 -0
- package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -0
- package/lib/packlets/vector/inMemoryCosineIndex.js +154 -0
- package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -0
- package/lib/packlets/vector/index.d.ts +3 -0
- package/lib/packlets/vector/index.d.ts.map +1 -0
- package/lib/packlets/vector/index.js +23 -0
- package/lib/packlets/vector/index.js.map +1 -0
- package/lib/packlets/vector/vectorIndex.d.ts +68 -0
- package/lib/packlets/vector/vectorIndex.d.ts.map +1 -0
- package/lib/packlets/vector/vectorIndex.js +7 -0
- package/lib/packlets/vector/vectorIndex.js.map +1 -0
- package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts +2 -0
- package/lib/test/unit/converters/bodyConverterRegistry.test.d.ts.map +1 -0
- package/lib/test/unit/converters/bodyConverterRegistry.test.js +74 -0
- package/lib/test/unit/converters/bodyConverterRegistry.test.js.map +1 -0
- package/lib/test/unit/converters/envelopeConverter.test.d.ts +2 -0
- package/lib/test/unit/converters/envelopeConverter.test.d.ts.map +1 -0
- package/lib/test/unit/converters/envelopeConverter.test.js +198 -0
- package/lib/test/unit/converters/envelopeConverter.test.js.map +1 -0
- package/lib/test/unit/index/memoryIndex.test.d.ts +2 -0
- package/lib/test/unit/index/memoryIndex.test.d.ts.map +1 -0
- package/lib/test/unit/index/memoryIndex.test.js +154 -0
- package/lib/test/unit/index/memoryIndex.test.js.map +1 -0
- package/lib/test/unit/observe/memoryObservationStore.test.d.ts +2 -0
- package/lib/test/unit/observe/memoryObservationStore.test.d.ts.map +1 -0
- package/lib/test/unit/observe/memoryObservationStore.test.js +120 -0
- package/lib/test/unit/observe/memoryObservationStore.test.js.map +1 -0
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts +2 -0
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.d.ts.map +1 -0
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.js +184 -0
- package/lib/test/unit/retrieve/linkTraversalRetriever.test.js.map +1 -0
- package/lib/test/unit/retrieve/retrievers.test.d.ts +2 -0
- package/lib/test/unit/retrieve/retrievers.test.d.ts.map +1 -0
- package/lib/test/unit/retrieve/retrievers.test.js +508 -0
- package/lib/test/unit/retrieve/retrievers.test.js.map +1 -0
- package/lib/test/unit/store/embedOnWrite.test.d.ts +2 -0
- package/lib/test/unit/store/embedOnWrite.test.d.ts.map +1 -0
- package/lib/test/unit/store/embedOnWrite.test.js +262 -0
- package/lib/test/unit/store/embedOnWrite.test.js.map +1 -0
- package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts +2 -0
- package/lib/test/unit/store/fileTreeMemoryStore.test.d.ts.map +1 -0
- package/lib/test/unit/store/fileTreeMemoryStore.test.js +649 -0
- package/lib/test/unit/store/fileTreeMemoryStore.test.js.map +1 -0
- package/lib/test/unit/store/observations.test.d.ts +2 -0
- package/lib/test/unit/store/observations.test.d.ts.map +1 -0
- package/lib/test/unit/store/observations.test.js +241 -0
- package/lib/test/unit/store/observations.test.js.map +1 -0
- package/lib/test/unit/store/scopeEncoding.test.d.ts +2 -0
- package/lib/test/unit/store/scopeEncoding.test.d.ts.map +1 -0
- package/lib/test/unit/store/scopeEncoding.test.js +26 -0
- package/lib/test/unit/store/scopeEncoding.test.js.map +1 -0
- package/lib/test/unit/types/identityCodec.test.d.ts +2 -0
- package/lib/test/unit/types/identityCodec.test.d.ts.map +1 -0
- package/lib/test/unit/types/identityCodec.test.js +189 -0
- package/lib/test/unit/types/identityCodec.test.js.map +1 -0
- package/lib/test/unit/types/ids.test.d.ts +2 -0
- package/lib/test/unit/types/ids.test.d.ts.map +1 -0
- package/lib/test/unit/types/ids.test.js +86 -0
- package/lib/test/unit/types/ids.test.js.map +1 -0
- package/lib/test/unit/types/writePolicy.test.d.ts +2 -0
- package/lib/test/unit/types/writePolicy.test.d.ts.map +1 -0
- package/lib/test/unit/types/writePolicy.test.js +243 -0
- package/lib/test/unit/types/writePolicy.test.js.map +1 -0
- package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts +2 -0
- package/lib/test/unit/vector/inMemoryCosineIndex.test.d.ts.map +1 -0
- package/lib/test/unit/vector/inMemoryCosineIndex.test.js +194 -0
- package/lib/test/unit/vector/inMemoryCosineIndex.test.js.map +1 -0
- package/lib/test/unit/vector/vectorIndex.test.d.ts +2 -0
- package/lib/test/unit/vector/vectorIndex.test.d.ts.map +1 -0
- package/lib/test/unit/vector/vectorIndex.test.js +44 -0
- package/lib/test/unit/vector/vectorIndex.test.js.map +1 -0
- package/package.json +81 -0
- package/rush-logs/ts-agent-memory.build.cache.log +3 -0
- package/rush-logs/ts-agent-memory.build.log +9 -0
- package/src/index.ts +12 -0
- package/src/packlets/converters/bodyConverterRegistry.ts +105 -0
- package/src/packlets/converters/envelopeConverter.ts +210 -0
- package/src/packlets/converters/index.ts +7 -0
- package/src/packlets/index/index.ts +6 -0
- package/src/packlets/index/memoryIndex.ts +268 -0
- package/src/packlets/observe/index.ts +7 -0
- package/src/packlets/observe/memoryObservationStore.ts +153 -0
- package/src/packlets/observe/observer.ts +119 -0
- package/src/packlets/retrieve/hybridRetriever.ts +181 -0
- package/src/packlets/retrieve/index.ts +12 -0
- package/src/packlets/retrieve/linkTraversalRetriever.ts +169 -0
- package/src/packlets/retrieve/recencyRetriever.ts +54 -0
- package/src/packlets/retrieve/retriever.ts +207 -0
- package/src/packlets/retrieve/semanticRetriever.ts +147 -0
- package/src/packlets/retrieve/structuredFilterRetriever.ts +58 -0
- package/src/packlets/retrieve/tagRetriever.ts +58 -0
- package/src/packlets/store/fileTreeMemoryStore.ts +1073 -0
- package/src/packlets/store/index.ts +7 -0
- package/src/packlets/store/scopeEncoding.ts +36 -0
- package/src/packlets/types/envelope.ts +138 -0
- package/src/packlets/types/filenameSafety.ts +57 -0
- package/src/packlets/types/identityCodec.ts +263 -0
- package/src/packlets/types/ids.ts +124 -0
- package/src/packlets/types/index.ts +10 -0
- package/src/packlets/types/writePolicy.ts +447 -0
- package/src/packlets/vector/inMemoryCosineIndex.ts +173 -0
- package/src/packlets/vector/index.ts +7 -0
- package/src/packlets/vector/vectorIndex.ts +78 -0
- package/src/test/unit/converters/bodyConverterRegistry.test.ts +89 -0
- package/src/test/unit/converters/envelopeConverter.test.ts +261 -0
- package/src/test/unit/index/memoryIndex.test.ts +187 -0
- package/src/test/unit/observe/memoryObservationStore.test.ts +158 -0
- package/src/test/unit/retrieve/linkTraversalRetriever.test.ts +230 -0
- package/src/test/unit/retrieve/retrievers.test.ts +662 -0
- package/src/test/unit/store/embedOnWrite.test.ts +346 -0
- package/src/test/unit/store/fileTreeMemoryStore.test.ts +875 -0
- package/src/test/unit/store/observations.test.ts +290 -0
- package/src/test/unit/store/scopeEncoding.test.ts +37 -0
- package/src/test/unit/types/identityCodec.test.ts +266 -0
- package/src/test/unit/types/ids.test.ts +94 -0
- package/src/test/unit/types/writePolicy.test.ts +325 -0
- package/src/test/unit/vector/inMemoryCosineIndex.test.ts +242 -0
- package/src/test/unit/vector/vectorIndex.test.ts +48 -0
- package/temp/build/lint/_eslint-5eVG3S6w.json +182 -0
- package/temp/build/typescript/ts_8nwakTlr.json +1 -0
- package/temp/ts-agent-memory.api.json +12438 -0
- package/temp/ts-agent-memory.api.md +525 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { IMemoryRecord, Kind, MemoryId, MemoryScopeKey, Tag } from '../types';
|
|
3
|
+
import { IIndexedMemoryRecord } from '../index';
|
|
4
|
+
/**
|
|
5
|
+
* The capabilities a retriever exposes. A consumer probes these before
|
|
6
|
+
* dispatching a query so it never silently gets an empty result for a
|
|
7
|
+
* capability the retriever does not implement.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export interface IMemoryRetrieverCapabilities {
|
|
11
|
+
/** Semantic / vector recall is operational (an {@link IVectorIndex} is wired). */
|
|
12
|
+
readonly supportsSemanticRecall: boolean;
|
|
13
|
+
/** Temporal "as-of" queries are operational (a temporal index is wired). */
|
|
14
|
+
readonly supportsTemporalQuery: boolean;
|
|
15
|
+
/** Link traversal is supported (an in-memory backlink index is present). */
|
|
16
|
+
readonly supportsLinkTraversal: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A retrieval query. Every field is optional; an empty query is the "recency
|
|
20
|
+
* over everything" request. `semantic` and `asOf` are present from day one (the
|
|
21
|
+
* no-resignature guarantee): a backend that adds semantic or temporal recall
|
|
22
|
+
* sets the matching capability flag, with no interface change.
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export interface IMemoryQuery {
|
|
26
|
+
/** Restrict to records in this scope. */
|
|
27
|
+
readonly scope?: MemoryScopeKey;
|
|
28
|
+
/** Restrict to records carrying this tag (exact match). */
|
|
29
|
+
readonly tag?: Tag;
|
|
30
|
+
/** Restrict to records of this kind. */
|
|
31
|
+
readonly kind?: Kind;
|
|
32
|
+
/** Restrict to records linked FROM this id (outbound). */
|
|
33
|
+
readonly linkedFrom?: MemoryId;
|
|
34
|
+
/** Restrict to records linked TO this id (inbound / backlinks). */
|
|
35
|
+
readonly linkedTo?: MemoryId;
|
|
36
|
+
/** BFS hop count for link traversal. Default: 1. */
|
|
37
|
+
readonly hops?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Text query for semantic / vector recall. If set and the retriever's
|
|
40
|
+
* `supportsSemanticRecall` is `false`, the retriever returns a loud
|
|
41
|
+
* `Result.fail` ({@link SEMANTIC_UNWIRED_MESSAGE}) — never a silent empty.
|
|
42
|
+
*/
|
|
43
|
+
readonly semantic?: string;
|
|
44
|
+
/** Top-K for semantic recall. Default: 10. */
|
|
45
|
+
readonly topK?: number;
|
|
46
|
+
/**
|
|
47
|
+
* As-of epoch ms for temporal "valid at" queries. If set and the retriever's
|
|
48
|
+
* `supportsTemporalQuery` is `false`, the retriever returns a loud
|
|
49
|
+
* `Result.fail` — never a silent empty.
|
|
50
|
+
*/
|
|
51
|
+
readonly asOf?: number;
|
|
52
|
+
/** Maximum records to return. Applied after all other filters. */
|
|
53
|
+
readonly limit?: number;
|
|
54
|
+
/** Arbitrary predicate applied after the scope / kind / tag pre-filter. */
|
|
55
|
+
readonly filter?: (record: IMemoryRecord<unknown>) => boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The retrieval contract. A retriever exposes its {@link
|
|
59
|
+
* IMemoryRetrieverCapabilities | capabilities} and answers
|
|
60
|
+
* {@link IMemoryRetriever.retrieve | queries}, degrading loudly (never silently
|
|
61
|
+
* empty) when a requested capability is not wired.
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
export interface IMemoryRetriever {
|
|
65
|
+
/** The capabilities this retriever exposes. Probe before dispatch. */
|
|
66
|
+
readonly capabilities: IMemoryRetrieverCapabilities;
|
|
67
|
+
/**
|
|
68
|
+
* Retrieve records matching `query`. Returns a `Result.fail` with a
|
|
69
|
+
* diagnostic message when the query requests a capability this retriever does
|
|
70
|
+
* not support (never an empty success).
|
|
71
|
+
*/
|
|
72
|
+
retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The loud-degradation message a retriever returns when `query.semantic` is set
|
|
76
|
+
* but no {@link IVectorIndex} is wired.
|
|
77
|
+
* @public
|
|
78
|
+
*/
|
|
79
|
+
export declare const SEMANTIC_UNWIRED_MESSAGE: string;
|
|
80
|
+
/**
|
|
81
|
+
* The loud-degradation message a retriever returns when a link-traversal axis
|
|
82
|
+
* (`linkedFrom` / `linkedTo` / `hops`) is requested but no backlink index is
|
|
83
|
+
* wired.
|
|
84
|
+
* @public
|
|
85
|
+
*/
|
|
86
|
+
export declare const LINK_TRAVERSAL_UNWIRED_MESSAGE: string;
|
|
87
|
+
/**
|
|
88
|
+
* The capabilities every non-semantic, non-temporal, non-link v1 retriever
|
|
89
|
+
* exposes (all three flags `false`).
|
|
90
|
+
* @public
|
|
91
|
+
*/
|
|
92
|
+
export declare const NON_SEMANTIC_CAPABILITIES: IMemoryRetrieverCapabilities;
|
|
93
|
+
/**
|
|
94
|
+
* Build the loud-degradation message a retriever returns when `query.asOf` is
|
|
95
|
+
* set but no temporal index is wired.
|
|
96
|
+
* @public
|
|
97
|
+
*/
|
|
98
|
+
export declare function temporalUnwiredMessage(kind?: Kind): string;
|
|
99
|
+
/**
|
|
100
|
+
* Enforce the loud-degradation contract for the `semantic` and `asOf` axes
|
|
101
|
+
* against a retriever's `capabilities`: a requested capability the retriever
|
|
102
|
+
* does not support fails loudly rather than returning a silent empty result.
|
|
103
|
+
* @public
|
|
104
|
+
*/
|
|
105
|
+
export declare function guardRetrieverCapabilities(query: IMemoryQuery, capabilities: IMemoryRetrieverCapabilities): Result<true>;
|
|
106
|
+
/**
|
|
107
|
+
* Recency comparator: most-recently-updated first, with a `seq` tiebreak so
|
|
108
|
+
* equal-`updated` records sort deterministically. Mirrors the B1 index ordering.
|
|
109
|
+
* @public
|
|
110
|
+
*/
|
|
111
|
+
export declare function recencyCompare(a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>): number;
|
|
112
|
+
/**
|
|
113
|
+
* Whether an indexed entry satisfies a query's scope / kind / tag / predicate
|
|
114
|
+
* pre-filter (the axes shared by every v1 retriever). The `semantic` / `asOf` /
|
|
115
|
+
* link axes are NOT applied here — those are each retriever's own concern.
|
|
116
|
+
* @public
|
|
117
|
+
*/
|
|
118
|
+
export declare function indexedRecordMatchesQuery(entry: IIndexedMemoryRecord, query: IMemoryQuery): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Apply the shared scope / kind / tag / predicate pre-filter to a set of indexed
|
|
121
|
+
* entries, returning the surviving records (unordered, unlimited).
|
|
122
|
+
* @public
|
|
123
|
+
*/
|
|
124
|
+
export declare function selectByQuery(entries: ReadonlyArray<IIndexedMemoryRecord>, query: IMemoryQuery): IMemoryRecord<unknown>[];
|
|
125
|
+
/**
|
|
126
|
+
* Truncate to `query.limit` records (a no-op when `limit` is absent). Applied
|
|
127
|
+
* last, after ordering, so it always takes the top-N of the ordered result. A
|
|
128
|
+
* non-positive `limit` is public query input and means "no records" — it returns
|
|
129
|
+
* an empty array rather than letting a negative value slip into `slice`.
|
|
130
|
+
* @public
|
|
131
|
+
*/
|
|
132
|
+
export declare function limitRecords(records: ReadonlyArray<IMemoryRecord<unknown>>, limit?: number): ReadonlyArray<IMemoryRecord<unknown>>;
|
|
133
|
+
//# sourceMappingURL=retriever.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retriever.d.ts","sourceRoot":"","sources":["../../../src/packlets/retrieve/retriever.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2026 Erik Fortune
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.NON_SEMANTIC_CAPABILITIES = exports.LINK_TRAVERSAL_UNWIRED_MESSAGE = exports.SEMANTIC_UNWIRED_MESSAGE = void 0;
|
|
8
|
+
exports.temporalUnwiredMessage = temporalUnwiredMessage;
|
|
9
|
+
exports.guardRetrieverCapabilities = guardRetrieverCapabilities;
|
|
10
|
+
exports.recencyCompare = recencyCompare;
|
|
11
|
+
exports.indexedRecordMatchesQuery = indexedRecordMatchesQuery;
|
|
12
|
+
exports.selectByQuery = selectByQuery;
|
|
13
|
+
exports.limitRecords = limitRecords;
|
|
14
|
+
const ts_utils_1 = require("@fgv/ts-utils");
|
|
15
|
+
/**
|
|
16
|
+
* The loud-degradation message a retriever returns when `query.semantic` is set
|
|
17
|
+
* but no {@link IVectorIndex} is wired.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
exports.SEMANTIC_UNWIRED_MESSAGE = 'semantic recall requires a vector index; none configured';
|
|
21
|
+
/**
|
|
22
|
+
* The loud-degradation message a retriever returns when a link-traversal axis
|
|
23
|
+
* (`linkedFrom` / `linkedTo` / `hops`) is requested but no backlink index is
|
|
24
|
+
* wired.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
exports.LINK_TRAVERSAL_UNWIRED_MESSAGE = 'link traversal requires a backlink index; none configured';
|
|
28
|
+
/**
|
|
29
|
+
* The capabilities every non-semantic, non-temporal, non-link v1 retriever
|
|
30
|
+
* exposes (all three flags `false`).
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
exports.NON_SEMANTIC_CAPABILITIES = {
|
|
34
|
+
supportsSemanticRecall: false,
|
|
35
|
+
supportsTemporalQuery: false,
|
|
36
|
+
supportsLinkTraversal: false
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Build the loud-degradation message a retriever returns when `query.asOf` is
|
|
40
|
+
* set but no temporal index is wired.
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
function temporalUnwiredMessage(kind) {
|
|
44
|
+
return `temporal query requires temporal index; none configured${kind !== undefined ? ` for kind ${kind}` : ''}`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Enforce the loud-degradation contract for the `semantic` and `asOf` axes
|
|
48
|
+
* against a retriever's `capabilities`: a requested capability the retriever
|
|
49
|
+
* does not support fails loudly rather than returning a silent empty result.
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
function guardRetrieverCapabilities(query, capabilities) {
|
|
53
|
+
if (query.semantic !== undefined && !capabilities.supportsSemanticRecall) {
|
|
54
|
+
return (0, ts_utils_1.fail)(exports.SEMANTIC_UNWIRED_MESSAGE);
|
|
55
|
+
}
|
|
56
|
+
if (query.asOf !== undefined && !capabilities.supportsTemporalQuery) {
|
|
57
|
+
return (0, ts_utils_1.fail)(temporalUnwiredMessage(query.kind));
|
|
58
|
+
}
|
|
59
|
+
const requestsLinkTraversal = query.linkedFrom !== undefined || query.linkedTo !== undefined || query.hops !== undefined;
|
|
60
|
+
if (requestsLinkTraversal && !capabilities.supportsLinkTraversal) {
|
|
61
|
+
return (0, ts_utils_1.fail)(exports.LINK_TRAVERSAL_UNWIRED_MESSAGE);
|
|
62
|
+
}
|
|
63
|
+
return (0, ts_utils_1.succeed)(true);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Recency comparator: most-recently-updated first, with a `seq` tiebreak so
|
|
67
|
+
* equal-`updated` records sort deterministically. Mirrors the B1 index ordering.
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
70
|
+
function recencyCompare(a, b) {
|
|
71
|
+
const byUpdated = b.envelope.updated - a.envelope.updated;
|
|
72
|
+
return byUpdated !== 0 ? byUpdated : b.envelope.seq - a.envelope.seq;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Whether an indexed entry satisfies a query's scope / kind / tag / predicate
|
|
76
|
+
* pre-filter (the axes shared by every v1 retriever). The `semantic` / `asOf` /
|
|
77
|
+
* link axes are NOT applied here — those are each retriever's own concern.
|
|
78
|
+
* @public
|
|
79
|
+
*/
|
|
80
|
+
function indexedRecordMatchesQuery(entry, query) {
|
|
81
|
+
if (query.scope !== undefined && entry.scope !== query.scope) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
if (query.kind !== undefined && entry.record.envelope.kind !== query.kind) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (query.tag !== undefined && !entry.record.envelope.tags.includes(query.tag)) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (query.filter !== undefined && !query.filter(entry.record)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Apply the shared scope / kind / tag / predicate pre-filter to a set of indexed
|
|
97
|
+
* entries, returning the surviving records (unordered, unlimited).
|
|
98
|
+
* @public
|
|
99
|
+
*/
|
|
100
|
+
function selectByQuery(entries, query) {
|
|
101
|
+
return entries.filter((entry) => indexedRecordMatchesQuery(entry, query)).map((entry) => entry.record);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Truncate to `query.limit` records (a no-op when `limit` is absent). Applied
|
|
105
|
+
* last, after ordering, so it always takes the top-N of the ordered result. A
|
|
106
|
+
* non-positive `limit` is public query input and means "no records" — it returns
|
|
107
|
+
* an empty array rather than letting a negative value slip into `slice`.
|
|
108
|
+
* @public
|
|
109
|
+
*/
|
|
110
|
+
function limitRecords(records, limit) {
|
|
111
|
+
if (limit === undefined) {
|
|
112
|
+
return records;
|
|
113
|
+
}
|
|
114
|
+
if (limit <= 0) {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
return records.length > limit ? records.slice(0, limit) : records;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=retriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retriever.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/retriever.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 { IMemoryRecord, Kind, MemoryId, MemoryScopeKey, Tag } from '../types';\nimport { IIndexedMemoryRecord } from '../index';\n\n/**\n * The capabilities a retriever exposes. A consumer probes these before\n * dispatching a query so it never silently gets an empty result for a\n * capability the retriever does not implement.\n * @public\n */\nexport interface IMemoryRetrieverCapabilities {\n /** Semantic / vector recall is operational (an {@link IVectorIndex} is wired). */\n readonly supportsSemanticRecall: boolean;\n /** Temporal \"as-of\" queries are operational (a temporal index is wired). */\n readonly supportsTemporalQuery: boolean;\n /** Link traversal is supported (an in-memory backlink index is present). */\n readonly supportsLinkTraversal: boolean;\n}\n\n/**\n * A retrieval query. Every field is optional; an empty query is the \"recency\n * over everything\" request. `semantic` and `asOf` are present from day one (the\n * no-resignature guarantee): a backend that adds semantic or temporal recall\n * sets the matching capability flag, with no interface change.\n * @public\n */\nexport interface IMemoryQuery {\n /** Restrict to records in this scope. */\n readonly scope?: MemoryScopeKey;\n /** Restrict to records carrying this tag (exact match). */\n readonly tag?: Tag;\n /** Restrict to records of this kind. */\n readonly kind?: Kind;\n /** Restrict to records linked FROM this id (outbound). */\n readonly linkedFrom?: MemoryId;\n /** Restrict to records linked TO this id (inbound / backlinks). */\n readonly linkedTo?: MemoryId;\n /** BFS hop count for link traversal. Default: 1. */\n readonly hops?: number;\n /**\n * Text query for semantic / vector recall. If set and the retriever's\n * `supportsSemanticRecall` is `false`, the retriever returns a loud\n * `Result.fail` ({@link SEMANTIC_UNWIRED_MESSAGE}) — never a silent empty.\n */\n readonly semantic?: string;\n /** Top-K for semantic recall. Default: 10. */\n readonly topK?: number;\n /**\n * As-of epoch ms for temporal \"valid at\" queries. If set and the retriever's\n * `supportsTemporalQuery` is `false`, the retriever returns a loud\n * `Result.fail` — never a silent empty.\n */\n readonly asOf?: number;\n /** Maximum records to return. Applied after all other filters. */\n readonly limit?: number;\n /** Arbitrary predicate applied after the scope / kind / tag pre-filter. */\n readonly filter?: (record: IMemoryRecord<unknown>) => boolean;\n}\n\n/**\n * The retrieval contract. A retriever exposes its {@link\n * IMemoryRetrieverCapabilities | capabilities} and answers\n * {@link IMemoryRetriever.retrieve | queries}, degrading loudly (never silently\n * empty) when a requested capability is not wired.\n * @public\n */\nexport interface IMemoryRetriever {\n /** The capabilities this retriever exposes. Probe before dispatch. */\n readonly capabilities: IMemoryRetrieverCapabilities;\n /**\n * Retrieve records matching `query`. Returns a `Result.fail` with a\n * diagnostic message when the query requests a capability this retriever does\n * not support (never an empty success).\n */\n retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;\n}\n\n/**\n * The loud-degradation message a retriever returns when `query.semantic` is set\n * but no {@link IVectorIndex} is wired.\n * @public\n */\nexport const SEMANTIC_UNWIRED_MESSAGE: string = 'semantic recall requires a vector index; none configured';\n\n/**\n * The loud-degradation message a retriever returns when a link-traversal axis\n * (`linkedFrom` / `linkedTo` / `hops`) is requested but no backlink index is\n * wired.\n * @public\n */\nexport const LINK_TRAVERSAL_UNWIRED_MESSAGE: string =\n 'link traversal requires a backlink index; none configured';\n\n/**\n * The capabilities every non-semantic, non-temporal, non-link v1 retriever\n * exposes (all three flags `false`).\n * @public\n */\nexport const NON_SEMANTIC_CAPABILITIES: IMemoryRetrieverCapabilities = {\n supportsSemanticRecall: false,\n supportsTemporalQuery: false,\n supportsLinkTraversal: false\n};\n\n/**\n * Build the loud-degradation message a retriever returns when `query.asOf` is\n * set but no temporal index is wired.\n * @public\n */\nexport function temporalUnwiredMessage(kind?: Kind): string {\n return `temporal query requires temporal index; none configured${\n kind !== undefined ? ` for kind ${kind}` : ''\n }`;\n}\n\n/**\n * Enforce the loud-degradation contract for the `semantic` and `asOf` axes\n * against a retriever's `capabilities`: a requested capability the retriever\n * does not support fails loudly rather than returning a silent empty result.\n * @public\n */\nexport function guardRetrieverCapabilities(\n query: IMemoryQuery,\n capabilities: IMemoryRetrieverCapabilities\n): Result<true> {\n if (query.semantic !== undefined && !capabilities.supportsSemanticRecall) {\n return fail(SEMANTIC_UNWIRED_MESSAGE);\n }\n if (query.asOf !== undefined && !capabilities.supportsTemporalQuery) {\n return fail(temporalUnwiredMessage(query.kind));\n }\n const requestsLinkTraversal: boolean =\n query.linkedFrom !== undefined || query.linkedTo !== undefined || query.hops !== undefined;\n if (requestsLinkTraversal && !capabilities.supportsLinkTraversal) {\n return fail(LINK_TRAVERSAL_UNWIRED_MESSAGE);\n }\n return succeed(true);\n}\n\n/**\n * Recency comparator: most-recently-updated first, with a `seq` tiebreak so\n * equal-`updated` records sort deterministically. Mirrors the B1 index ordering.\n * @public\n */\nexport function recencyCompare(a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>): number {\n const byUpdated: number = b.envelope.updated - a.envelope.updated;\n return byUpdated !== 0 ? byUpdated : b.envelope.seq - a.envelope.seq;\n}\n\n/**\n * Whether an indexed entry satisfies a query's scope / kind / tag / predicate\n * pre-filter (the axes shared by every v1 retriever). The `semantic` / `asOf` /\n * link axes are NOT applied here — those are each retriever's own concern.\n * @public\n */\nexport function indexedRecordMatchesQuery(entry: IIndexedMemoryRecord, query: IMemoryQuery): boolean {\n if (query.scope !== undefined && entry.scope !== query.scope) {\n return false;\n }\n if (query.kind !== undefined && entry.record.envelope.kind !== query.kind) {\n return false;\n }\n if (query.tag !== undefined && !entry.record.envelope.tags.includes(query.tag)) {\n return false;\n }\n if (query.filter !== undefined && !query.filter(entry.record)) {\n return false;\n }\n return true;\n}\n\n/**\n * Apply the shared scope / kind / tag / predicate pre-filter to a set of indexed\n * entries, returning the surviving records (unordered, unlimited).\n * @public\n */\nexport function selectByQuery(\n entries: ReadonlyArray<IIndexedMemoryRecord>,\n query: IMemoryQuery\n): IMemoryRecord<unknown>[] {\n return entries.filter((entry) => indexedRecordMatchesQuery(entry, query)).map((entry) => entry.record);\n}\n\n/**\n * Truncate to `query.limit` records (a no-op when `limit` is absent). Applied\n * last, after ordering, so it always takes the top-N of the ordered result. A\n * non-positive `limit` is public query input and means \"no records\" — it returns\n * an empty array rather than letting a negative value slip into `slice`.\n * @public\n */\nexport function limitRecords(\n records: ReadonlyArray<IMemoryRecord<unknown>>,\n limit?: number\n): ReadonlyArray<IMemoryRecord<unknown>> {\n if (limit === undefined) {\n return records;\n }\n if (limit <= 0) {\n return [];\n }\n return records.length > limit ? records.slice(0, limit) : records;\n}\n"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { IMemoryRecord } from '../types';
|
|
3
|
+
import { IMemoryIndex } from '../index';
|
|
4
|
+
import { IVectorIndex } from '../vector';
|
|
5
|
+
import { IMemoryQuery, IMemoryRetriever, IMemoryRetrieverCapabilities } from './retriever';
|
|
6
|
+
/**
|
|
7
|
+
* Embeds a query string into a vector for {@link IVectorIndex.query}. Async and
|
|
8
|
+
* `Result`-returning, since a real embedder does a network call.
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
export type QueryEmbedder = (text: string) => Promise<Result<Float32Array>>;
|
|
12
|
+
/**
|
|
13
|
+
* The semantic backend wired into a {@link SemanticRetriever}: the vector index
|
|
14
|
+
* to query and the embedder that turns the query text into a vector. Both are
|
|
15
|
+
* required together — a vector index is useless without a way to embed the
|
|
16
|
+
* query, so {@link SemanticRetriever.create} treats them as one unit.
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
export interface ISemanticBackend {
|
|
20
|
+
/** The vector index to query. */
|
|
21
|
+
readonly vectorIndex: IVectorIndex;
|
|
22
|
+
/** Turns the query text into a vector. */
|
|
23
|
+
readonly embedQuery: QueryEmbedder;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Construction options for {@link SemanticRetriever.create}.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export interface ISemanticRetrieverCreateParams {
|
|
30
|
+
/** The record index, used to resolve vector hits back to full records. */
|
|
31
|
+
readonly index: IMemoryIndex;
|
|
32
|
+
/**
|
|
33
|
+
* The semantic backend. When absent, the retriever reports
|
|
34
|
+
* `supportsSemanticRecall: false` and a `query.semantic` request degrades
|
|
35
|
+
* loudly ({@link SEMANTIC_UNWIRED_MESSAGE}) rather than returning empty.
|
|
36
|
+
*/
|
|
37
|
+
readonly backend?: ISemanticBackend;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Vector-recall retriever. When a {@link ISemanticBackend | backend} is wired it
|
|
41
|
+
* embeds `query.semantic`, queries the vector index, and resolves the hits back
|
|
42
|
+
* to records (preserving vector score order). When no backend is wired,
|
|
43
|
+
* `supportsSemanticRecall` is `false` and any `query.semantic` request degrades
|
|
44
|
+
* loudly — it NEVER returns a silent empty.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* A consumer-supplied backend that rejects (throws) is normalized into a
|
|
48
|
+
* `Failure` — `retrieve` always honors its `Promise<Result<...>>` contract.
|
|
49
|
+
* @public
|
|
50
|
+
*/
|
|
51
|
+
export declare class SemanticRetriever implements IMemoryRetriever {
|
|
52
|
+
private readonly _index;
|
|
53
|
+
private readonly _backend;
|
|
54
|
+
private constructor();
|
|
55
|
+
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
56
|
+
get capabilities(): IMemoryRetrieverCapabilities;
|
|
57
|
+
/** Family-convention factory. */
|
|
58
|
+
static create(params: ISemanticRetrieverCreateParams): Result<SemanticRetriever>;
|
|
59
|
+
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
60
|
+
retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
61
|
+
/**
|
|
62
|
+
* Invoke a consumer-supplied backend hook, normalizing both a returned `fail`
|
|
63
|
+
* and a thrown/rejected promise into a single `semantic recall: <label> failed`
|
|
64
|
+
* `Failure`. Keeps `retrieve` within the `Promise<Result<...>>` contract even
|
|
65
|
+
* when the injected `embedQuery` / `vectorIndex` misbehaves.
|
|
66
|
+
*/
|
|
67
|
+
private static _callBackend;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=semanticRetriever.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semanticRetriever.d.ts","sourceRoot":"","sources":["../../../src/packlets/retrieve/semanticRetriever.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,aAAa,EAAY,MAAM,UAAU,CAAC;AACnD,OAAO,EAAwB,YAAY,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAmB,MAAM,WAAW,CAAC;AAC1D,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,4BAA4B,EAK7B,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;AAE5E;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC;IACnC,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAkB,YAAW,gBAAgB;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IAExD,OAAO;IAKP,kDAAkD;IAClD,IAAW,YAAY,IAAI,4BAA4B,CAMtD;IAED,iCAAiC;WACnB,MAAM,CAAC,MAAM,EAAE,8BAA8B,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAIvF,8CAA8C;IACjC,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IA0ClG;;;;;OAKG;mBACkB,YAAY;CAOlC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2026 Erik Fortune
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.SemanticRetriever = void 0;
|
|
8
|
+
const ts_utils_1 = require("@fgv/ts-utils");
|
|
9
|
+
const retriever_1 = require("./retriever");
|
|
10
|
+
/**
|
|
11
|
+
* Vector-recall retriever. When a {@link ISemanticBackend | backend} is wired it
|
|
12
|
+
* embeds `query.semantic`, queries the vector index, and resolves the hits back
|
|
13
|
+
* to records (preserving vector score order). When no backend is wired,
|
|
14
|
+
* `supportsSemanticRecall` is `false` and any `query.semantic` request degrades
|
|
15
|
+
* loudly — it NEVER returns a silent empty.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* A consumer-supplied backend that rejects (throws) is normalized into a
|
|
19
|
+
* `Failure` — `retrieve` always honors its `Promise<Result<...>>` contract.
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
class SemanticRetriever {
|
|
23
|
+
constructor(index, backend) {
|
|
24
|
+
this._index = index;
|
|
25
|
+
this._backend = backend;
|
|
26
|
+
}
|
|
27
|
+
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
28
|
+
get capabilities() {
|
|
29
|
+
return {
|
|
30
|
+
supportsSemanticRecall: this._backend !== undefined,
|
|
31
|
+
supportsTemporalQuery: false,
|
|
32
|
+
supportsLinkTraversal: false
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Family-convention factory. */
|
|
36
|
+
static create(params) {
|
|
37
|
+
return (0, ts_utils_1.succeed)(new SemanticRetriever(params.index, params.backend));
|
|
38
|
+
}
|
|
39
|
+
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
40
|
+
async retrieve(query) {
|
|
41
|
+
if (query.asOf !== undefined) {
|
|
42
|
+
return (0, ts_utils_1.fail)((0, retriever_1.temporalUnwiredMessage)(query.kind));
|
|
43
|
+
}
|
|
44
|
+
if (query.semantic === undefined) {
|
|
45
|
+
// The semantic term is this retriever's axis; without it there is nothing
|
|
46
|
+
// to recall (a no-op contribution to a HybridRetriever, not a failure).
|
|
47
|
+
return (0, ts_utils_1.succeed)([]);
|
|
48
|
+
}
|
|
49
|
+
if (this._backend === undefined) {
|
|
50
|
+
return (0, ts_utils_1.fail)(retriever_1.SEMANTIC_UNWIRED_MESSAGE);
|
|
51
|
+
}
|
|
52
|
+
const backend = this._backend;
|
|
53
|
+
// The backend hooks are consumer-supplied; a rejecting (throwing) impl must
|
|
54
|
+
// still surface as a `Failure`, never escape `retrieve` as a rejected
|
|
55
|
+
// promise. `_callBackend` normalizes both a returned `fail` and a rejection.
|
|
56
|
+
const embedded = await SemanticRetriever._callBackend('query embedding', () => backend.embedQuery(query.semantic));
|
|
57
|
+
if (embedded.isFailure()) {
|
|
58
|
+
return (0, ts_utils_1.fail)(embedded.message);
|
|
59
|
+
}
|
|
60
|
+
const hits = await SemanticRetriever._callBackend('vector query', () => { var _a; return backend.vectorIndex.query(embedded.value, (_a = query.topK) !== null && _a !== void 0 ? _a : 10); });
|
|
61
|
+
if (hits.isFailure()) {
|
|
62
|
+
return (0, ts_utils_1.fail)(hits.message);
|
|
63
|
+
}
|
|
64
|
+
const byId = new Map(this._index.entries().map((entry) => [entry.record.envelope.id, entry]));
|
|
65
|
+
const records = [];
|
|
66
|
+
for (const hit of hits.value) {
|
|
67
|
+
const entry = byId.get(hit.id);
|
|
68
|
+
if (entry !== undefined && (0, retriever_1.indexedRecordMatchesQuery)(entry, query)) {
|
|
69
|
+
records.push(entry.record);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return (0, ts_utils_1.succeed)((0, retriever_1.limitRecords)(records, query.limit));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Invoke a consumer-supplied backend hook, normalizing both a returned `fail`
|
|
76
|
+
* and a thrown/rejected promise into a single `semantic recall: <label> failed`
|
|
77
|
+
* `Failure`. Keeps `retrieve` within the `Promise<Result<...>>` contract even
|
|
78
|
+
* when the injected `embedQuery` / `vectorIndex` misbehaves.
|
|
79
|
+
*/
|
|
80
|
+
static async _callBackend(label, op) {
|
|
81
|
+
try {
|
|
82
|
+
return (await op()).withErrorFormat((msg) => `semantic recall: ${label} failed: ${msg}`);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
return (0, ts_utils_1.fail)(`semantic recall: ${label} failed: ${String(err)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.SemanticRetriever = SemanticRetriever;
|
|
90
|
+
//# sourceMappingURL=semanticRetriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semanticRetriever.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/semanticRetriever.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 { IMemoryRecord, MemoryId } from '../types';\nimport { IIndexedMemoryRecord, IMemoryIndex } from '../index';\nimport { IVectorIndex, IVectorQueryHit } from '../vector';\nimport {\n IMemoryQuery,\n IMemoryRetriever,\n IMemoryRetrieverCapabilities,\n SEMANTIC_UNWIRED_MESSAGE,\n indexedRecordMatchesQuery,\n limitRecords,\n temporalUnwiredMessage\n} from './retriever';\n\n/**\n * Embeds a query string into a vector for {@link IVectorIndex.query}. Async and\n * `Result`-returning, since a real embedder does a network call.\n * @public\n */\nexport type QueryEmbedder = (text: string) => Promise<Result<Float32Array>>;\n\n/**\n * The semantic backend wired into a {@link SemanticRetriever}: the vector index\n * to query and the embedder that turns the query text into a vector. Both are\n * required together — a vector index is useless without a way to embed the\n * query, so {@link SemanticRetriever.create} treats them as one unit.\n * @public\n */\nexport interface ISemanticBackend {\n /** The vector index to query. */\n readonly vectorIndex: IVectorIndex;\n /** Turns the query text into a vector. */\n readonly embedQuery: QueryEmbedder;\n}\n\n/**\n * Construction options for {@link SemanticRetriever.create}.\n * @public\n */\nexport interface ISemanticRetrieverCreateParams {\n /** The record index, used to resolve vector hits back to full records. */\n readonly index: IMemoryIndex;\n /**\n * The semantic backend. When absent, the retriever reports\n * `supportsSemanticRecall: false` and a `query.semantic` request degrades\n * loudly ({@link SEMANTIC_UNWIRED_MESSAGE}) rather than returning empty.\n */\n readonly backend?: ISemanticBackend;\n}\n\n/**\n * Vector-recall retriever. When a {@link ISemanticBackend | backend} is wired it\n * embeds `query.semantic`, queries the vector index, and resolves the hits back\n * to records (preserving vector score order). When no backend is wired,\n * `supportsSemanticRecall` is `false` and any `query.semantic` request degrades\n * loudly — it NEVER returns a silent empty.\n *\n * @remarks\n * A consumer-supplied backend that rejects (throws) is normalized into a\n * `Failure` — `retrieve` always honors its `Promise<Result<...>>` contract.\n * @public\n */\nexport class SemanticRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n private readonly _backend: ISemanticBackend | undefined;\n\n private constructor(index: IMemoryIndex, backend: ISemanticBackend | undefined) {\n this._index = index;\n this._backend = backend;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return {\n supportsSemanticRecall: this._backend !== undefined,\n supportsTemporalQuery: false,\n supportsLinkTraversal: false\n };\n }\n\n /** Family-convention factory. */\n public static create(params: ISemanticRetrieverCreateParams): Result<SemanticRetriever> {\n return succeed(new SemanticRetriever(params.index, params.backend));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public async retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n if (query.asOf !== undefined) {\n return fail(temporalUnwiredMessage(query.kind));\n }\n if (query.semantic === undefined) {\n // The semantic term is this retriever's axis; without it there is nothing\n // to recall (a no-op contribution to a HybridRetriever, not a failure).\n return succeed([]);\n }\n if (this._backend === undefined) {\n return fail(SEMANTIC_UNWIRED_MESSAGE);\n }\n const backend: ISemanticBackend = this._backend;\n // The backend hooks are consumer-supplied; a rejecting (throwing) impl must\n // still surface as a `Failure`, never escape `retrieve` as a rejected\n // promise. `_callBackend` normalizes both a returned `fail` and a rejection.\n const embedded: Result<Float32Array> = await SemanticRetriever._callBackend('query embedding', () =>\n backend.embedQuery(query.semantic as string)\n );\n if (embedded.isFailure()) {\n return fail(embedded.message);\n }\n const hits: Result<ReadonlyArray<IVectorQueryHit>> = await SemanticRetriever._callBackend(\n 'vector query',\n () => backend.vectorIndex.query(embedded.value, query.topK ?? 10)\n );\n if (hits.isFailure()) {\n return fail(hits.message);\n }\n const byId: Map<MemoryId, IIndexedMemoryRecord> = new Map(\n this._index.entries().map((entry) => [entry.record.envelope.id, entry])\n );\n const records: IMemoryRecord<unknown>[] = [];\n for (const hit of hits.value) {\n const entry: IIndexedMemoryRecord | undefined = byId.get(hit.id);\n if (entry !== undefined && indexedRecordMatchesQuery(entry, query)) {\n records.push(entry.record);\n }\n }\n return succeed(limitRecords(records, query.limit));\n }\n\n /**\n * Invoke a consumer-supplied backend hook, normalizing both a returned `fail`\n * and a thrown/rejected promise into a single `semantic recall: <label> failed`\n * `Failure`. Keeps `retrieve` within the `Promise<Result<...>>` contract even\n * when the injected `embedQuery` / `vectorIndex` misbehaves.\n */\n private static async _callBackend<T>(label: string, op: () => Promise<Result<T>>): Promise<Result<T>> {\n try {\n return (await op()).withErrorFormat((msg) => `semantic recall: ${label} failed: ${msg}`);\n } catch (err) {\n return fail(`semantic recall: ${label} failed: ${String(err)}`);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { IMemoryRecord } from '../types';
|
|
3
|
+
import { IMemoryIndex } from '../index';
|
|
4
|
+
import { IMemoryQuery, IMemoryRetriever, IMemoryRetrieverCapabilities } from './retriever';
|
|
5
|
+
/**
|
|
6
|
+
* Returns records matching `query.filter`, narrowed by any scope / kind / tag
|
|
7
|
+
* pre-filter and recency-ordered. The predicate is this retriever's axis: a
|
|
8
|
+
* query without a `filter` is not its concern and yields an empty success (so it
|
|
9
|
+
* contributes nothing to a {@link HybridRetriever}, rather than failing).
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export declare class StructuredFilterRetriever implements IMemoryRetriever {
|
|
13
|
+
private readonly _index;
|
|
14
|
+
private constructor();
|
|
15
|
+
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
16
|
+
get capabilities(): IMemoryRetrieverCapabilities;
|
|
17
|
+
/** Family-convention factory. */
|
|
18
|
+
static create(index: IMemoryIndex): Result<StructuredFilterRetriever>;
|
|
19
|
+
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
20
|
+
retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=structuredFilterRetriever.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structuredFilterRetriever.d.ts","sourceRoot":"","sources":["../../../src/packlets/retrieve/structuredFilterRetriever.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAW,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,4BAA4B,EAM7B,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,qBAAa,yBAA0B,YAAW,gBAAgB;IAChE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IAEtC,OAAO;IAIP,kDAAkD;IAClD,IAAW,YAAY,IAAI,4BAA4B,CAEtD;IAED,iCAAiC;WACnB,MAAM,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAAC,yBAAyB,CAAC;IAI5E,8CAA8C;IACvC,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAa7F"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2026 Erik Fortune
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.StructuredFilterRetriever = void 0;
|
|
8
|
+
const ts_utils_1 = require("@fgv/ts-utils");
|
|
9
|
+
const retriever_1 = require("./retriever");
|
|
10
|
+
/**
|
|
11
|
+
* Returns records matching `query.filter`, narrowed by any scope / kind / tag
|
|
12
|
+
* pre-filter and recency-ordered. The predicate is this retriever's axis: a
|
|
13
|
+
* query without a `filter` is not its concern and yields an empty success (so it
|
|
14
|
+
* contributes nothing to a {@link HybridRetriever}, rather than failing).
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
class StructuredFilterRetriever {
|
|
18
|
+
constructor(index) {
|
|
19
|
+
this._index = index;
|
|
20
|
+
}
|
|
21
|
+
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
22
|
+
get capabilities() {
|
|
23
|
+
return retriever_1.NON_SEMANTIC_CAPABILITIES;
|
|
24
|
+
}
|
|
25
|
+
/** Family-convention factory. */
|
|
26
|
+
static create(index) {
|
|
27
|
+
return (0, ts_utils_1.succeed)(new StructuredFilterRetriever(index));
|
|
28
|
+
}
|
|
29
|
+
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
30
|
+
retrieve(query) {
|
|
31
|
+
return Promise.resolve((0, retriever_1.guardRetrieverCapabilities)(query, this.capabilities).onSuccess(() => {
|
|
32
|
+
if (query.filter === undefined) {
|
|
33
|
+
return (0, ts_utils_1.succeed)([]);
|
|
34
|
+
}
|
|
35
|
+
const ordered = (0, retriever_1.selectByQuery)(this._index.entries(), query).sort(retriever_1.recencyCompare);
|
|
36
|
+
return (0, ts_utils_1.succeed)((0, retriever_1.limitRecords)(ordered, query.limit));
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.StructuredFilterRetriever = StructuredFilterRetriever;
|
|
41
|
+
//# sourceMappingURL=structuredFilterRetriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structuredFilterRetriever.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/structuredFilterRetriever.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,4CAAgD;AAGhD,2CASqB;AAErB;;;;;;GAMG;AACH,MAAa,yBAAyB;IAGpC,YAAoB,KAAmB;QACrC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,kDAAkD;IAClD,IAAW,YAAY;QACrB,OAAO,qCAAyB,CAAC;IACnC,CAAC;IAED,iCAAiC;IAC1B,MAAM,CAAC,MAAM,CAAC,KAAmB;QACtC,OAAO,IAAA,kBAAO,EAAC,IAAI,yBAAyB,CAAC,KAAK,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,8CAA8C;IACvC,QAAQ,CAAC,KAAmB;QACjC,OAAO,OAAO,CAAC,OAAO,CACpB,IAAA,sCAA0B,EAAC,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE;YAClE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC/B,OAAO,IAAA,kBAAO,EAAC,EAAE,CAAC,CAAC;YACrB,CAAC;YACD,MAAM,OAAO,GAA6B,IAAA,yBAAa,EAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC,IAAI,CACxF,0BAAc,CACf,CAAC;YACF,OAAO,IAAA,kBAAO,EAAC,IAAA,wBAAY,EAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QACrD,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;CACF;AA/BD,8DA+BC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, succeed } from '@fgv/ts-utils';\nimport { IMemoryRecord } from '../types';\nimport { IMemoryIndex } from '../index';\nimport {\n IMemoryQuery,\n IMemoryRetriever,\n IMemoryRetrieverCapabilities,\n NON_SEMANTIC_CAPABILITIES,\n guardRetrieverCapabilities,\n limitRecords,\n recencyCompare,\n selectByQuery\n} from './retriever';\n\n/**\n * Returns records matching `query.filter`, narrowed by any scope / kind / tag\n * pre-filter and recency-ordered. The predicate is this retriever's axis: a\n * query without a `filter` is not its concern and yields an empty success (so it\n * contributes nothing to a {@link HybridRetriever}, rather than failing).\n * @public\n */\nexport class StructuredFilterRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n\n private constructor(index: IMemoryIndex) {\n this._index = index;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return NON_SEMANTIC_CAPABILITIES;\n }\n\n /** Family-convention factory. */\n public static create(index: IMemoryIndex): Result<StructuredFilterRetriever> {\n return succeed(new StructuredFilterRetriever(index));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n return Promise.resolve(\n guardRetrieverCapabilities(query, this.capabilities).onSuccess(() => {\n if (query.filter === undefined) {\n return succeed([]);\n }\n const ordered: IMemoryRecord<unknown>[] = selectByQuery(this._index.entries(), query).sort(\n recencyCompare\n );\n return succeed(limitRecords(ordered, query.limit));\n })\n );\n }\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { IMemoryRecord } from '../types';
|
|
3
|
+
import { IMemoryIndex } from '../index';
|
|
4
|
+
import { IMemoryQuery, IMemoryRetriever, IMemoryRetrieverCapabilities } from './retriever';
|
|
5
|
+
/**
|
|
6
|
+
* Returns records carrying `query.tag`, recency-ordered within the tag and
|
|
7
|
+
* narrowed by any scope / kind / predicate filters. Tag is this retriever's
|
|
8
|
+
* axis: a query without a `tag` is not its concern and yields an empty success
|
|
9
|
+
* (so it contributes nothing to a {@link HybridRetriever}, rather than failing).
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export declare class TagRetriever implements IMemoryRetriever {
|
|
13
|
+
private readonly _index;
|
|
14
|
+
private constructor();
|
|
15
|
+
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
16
|
+
get capabilities(): IMemoryRetrieverCapabilities;
|
|
17
|
+
/** Family-convention factory. */
|
|
18
|
+
static create(index: IMemoryIndex): Result<TagRetriever>;
|
|
19
|
+
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
20
|
+
retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=tagRetriever.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tagRetriever.d.ts","sourceRoot":"","sources":["../../../src/packlets/retrieve/tagRetriever.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAW,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,4BAA4B,EAM7B,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,qBAAa,YAAa,YAAW,gBAAgB;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IAEtC,OAAO;IAIP,kDAAkD;IAClD,IAAW,YAAY,IAAI,4BAA4B,CAEtD;IAED,iCAAiC;WACnB,MAAM,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IAI/D,8CAA8C;IACvC,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAa7F"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2026 Erik Fortune
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.TagRetriever = void 0;
|
|
8
|
+
const ts_utils_1 = require("@fgv/ts-utils");
|
|
9
|
+
const retriever_1 = require("./retriever");
|
|
10
|
+
/**
|
|
11
|
+
* Returns records carrying `query.tag`, recency-ordered within the tag and
|
|
12
|
+
* narrowed by any scope / kind / predicate filters. Tag is this retriever's
|
|
13
|
+
* axis: a query without a `tag` is not its concern and yields an empty success
|
|
14
|
+
* (so it contributes nothing to a {@link HybridRetriever}, rather than failing).
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
class TagRetriever {
|
|
18
|
+
constructor(index) {
|
|
19
|
+
this._index = index;
|
|
20
|
+
}
|
|
21
|
+
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
22
|
+
get capabilities() {
|
|
23
|
+
return retriever_1.NON_SEMANTIC_CAPABILITIES;
|
|
24
|
+
}
|
|
25
|
+
/** Family-convention factory. */
|
|
26
|
+
static create(index) {
|
|
27
|
+
return (0, ts_utils_1.succeed)(new TagRetriever(index));
|
|
28
|
+
}
|
|
29
|
+
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
30
|
+
retrieve(query) {
|
|
31
|
+
return Promise.resolve((0, retriever_1.guardRetrieverCapabilities)(query, this.capabilities).onSuccess(() => {
|
|
32
|
+
if (query.tag === undefined) {
|
|
33
|
+
return (0, ts_utils_1.succeed)([]);
|
|
34
|
+
}
|
|
35
|
+
const ordered = (0, retriever_1.selectByQuery)(this._index.entries(), query).sort(retriever_1.recencyCompare);
|
|
36
|
+
return (0, ts_utils_1.succeed)((0, retriever_1.limitRecords)(ordered, query.limit));
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.TagRetriever = TagRetriever;
|
|
41
|
+
//# sourceMappingURL=tagRetriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tagRetriever.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/tagRetriever.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,4CAAgD;AAGhD,2CASqB;AAErB;;;;;;GAMG;AACH,MAAa,YAAY;IAGvB,YAAoB,KAAmB;QACrC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,kDAAkD;IAClD,IAAW,YAAY;QACrB,OAAO,qCAAyB,CAAC;IACnC,CAAC;IAED,iCAAiC;IAC1B,MAAM,CAAC,MAAM,CAAC,KAAmB;QACtC,OAAO,IAAA,kBAAO,EAAC,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,8CAA8C;IACvC,QAAQ,CAAC,KAAmB;QACjC,OAAO,OAAO,CAAC,OAAO,CACpB,IAAA,sCAA0B,EAAC,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE;YAClE,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,IAAA,kBAAO,EAAC,EAAE,CAAC,CAAC;YACrB,CAAC;YACD,MAAM,OAAO,GAA6B,IAAA,yBAAa,EAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC,IAAI,CACxF,0BAAc,CACf,CAAC;YACF,OAAO,IAAA,kBAAO,EAAC,IAAA,wBAAY,EAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QACrD,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;CACF;AA/BD,oCA+BC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, succeed } from '@fgv/ts-utils';\nimport { IMemoryRecord } from '../types';\nimport { IMemoryIndex } from '../index';\nimport {\n IMemoryQuery,\n IMemoryRetriever,\n IMemoryRetrieverCapabilities,\n NON_SEMANTIC_CAPABILITIES,\n guardRetrieverCapabilities,\n limitRecords,\n recencyCompare,\n selectByQuery\n} from './retriever';\n\n/**\n * Returns records carrying `query.tag`, recency-ordered within the tag and\n * narrowed by any scope / kind / predicate filters. Tag is this retriever's\n * axis: a query without a `tag` is not its concern and yields an empty success\n * (so it contributes nothing to a {@link HybridRetriever}, rather than failing).\n * @public\n */\nexport class TagRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n\n private constructor(index: IMemoryIndex) {\n this._index = index;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return NON_SEMANTIC_CAPABILITIES;\n }\n\n /** Family-convention factory. */\n public static create(index: IMemoryIndex): Result<TagRetriever> {\n return succeed(new TagRetriever(index));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n return Promise.resolve(\n guardRetrieverCapabilities(query, this.capabilities).onSuccess(() => {\n if (query.tag === undefined) {\n return succeed([]);\n }\n const ordered: IMemoryRecord<unknown>[] = selectByQuery(this._index.entries(), query).sort(\n recencyCompare\n );\n return succeed(limitRecords(ordered, query.limit));\n })\n );\n }\n}\n"]}
|