@fgv/ts-agent-memory 5.1.0-41 → 5.1.0-43
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/{cbbdbe09515171b4eba8f2592be2dace1e4e8142.tar.log → 285f03271c27ef724d49e730c0db58d9e4ac1a44.tar.log} +38 -2
- package/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +2 -2
- package/.rush/temp/operation/build/all.log +2 -2
- package/.rush/temp/operation/build/log-chunks.jsonl +2 -2
- package/.rush/temp/operation/build/state.json +1 -1
- package/dist/packlets/retrieve/fragmentSemanticRetriever.js +78 -0
- package/dist/packlets/retrieve/fragmentSemanticRetriever.js.map +1 -0
- package/dist/packlets/retrieve/index.js +1 -0
- package/dist/packlets/retrieve/index.js.map +1 -1
- package/dist/packlets/store/fileTreeMemoryStore.js +105 -14
- package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/dist/packlets/vector/inMemoryFragmentCosineIndex.js +200 -0
- package/dist/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -0
- package/dist/packlets/vector/index.js +1 -0
- package/dist/packlets/vector/index.js.map +1 -1
- package/dist/packlets/vector/vectorIndex.js.map +1 -1
- package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js +116 -0
- package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +1 -0
- package/dist/test/unit/store/fragmentEmbedOnWrite.test.js +255 -0
- package/dist/test/unit/store/fragmentEmbedOnWrite.test.js.map +1 -0
- package/dist/test/unit/store/lenientOpen.test.js +248 -0
- package/dist/test/unit/store/lenientOpen.test.js.map +1 -0
- package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js +297 -0
- package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +1 -0
- package/dist/ts-agent-memory.d.ts +367 -4
- package/etc/ts-agent-memory.api.md +78 -0
- package/lib/packlets/retrieve/fragmentSemanticRetriever.d.ts +90 -0
- package/lib/packlets/retrieve/fragmentSemanticRetriever.d.ts.map +1 -0
- package/lib/packlets/retrieve/fragmentSemanticRetriever.js +82 -0
- package/lib/packlets/retrieve/fragmentSemanticRetriever.js.map +1 -0
- package/lib/packlets/retrieve/index.d.ts +1 -0
- package/lib/packlets/retrieve/index.d.ts.map +1 -1
- package/lib/packlets/retrieve/index.js +1 -0
- package/lib/packlets/retrieve/index.js.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.d.ts +115 -1
- package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.js +104 -13
- package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts +74 -0
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts.map +1 -0
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.js +204 -0
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -0
- package/lib/packlets/vector/index.d.ts +1 -0
- package/lib/packlets/vector/index.d.ts.map +1 -1
- package/lib/packlets/vector/index.js +1 -0
- package/lib/packlets/vector/index.js.map +1 -1
- package/lib/packlets/vector/vectorIndex.d.ts +85 -4
- package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
- package/lib/packlets/vector/vectorIndex.js.map +1 -1
- package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts +2 -0
- package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts.map +1 -0
- package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js +118 -0
- package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +1 -0
- package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts +2 -0
- package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts.map +1 -0
- package/lib/test/unit/store/fragmentEmbedOnWrite.test.js +257 -0
- package/lib/test/unit/store/fragmentEmbedOnWrite.test.js.map +1 -0
- package/lib/test/unit/store/lenientOpen.test.d.ts +2 -0
- package/lib/test/unit/store/lenientOpen.test.d.ts.map +1 -0
- package/lib/test/unit/store/lenientOpen.test.js +250 -0
- package/lib/test/unit/store/lenientOpen.test.js.map +1 -0
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts +2 -0
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts.map +1 -0
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js +299 -0
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +1 -0
- package/package.json +7 -7
- package/rush-logs/ts-agent-memory.build.cache.log +1 -1
- package/rush-logs/ts-agent-memory.build.log +2 -2
- package/src/packlets/retrieve/fragmentSemanticRetriever.ts +135 -0
- package/src/packlets/retrieve/index.ts +1 -0
- package/src/packlets/store/fileTreeMemoryStore.ts +208 -16
- package/src/packlets/vector/inMemoryFragmentCosineIndex.ts +262 -0
- package/src/packlets/vector/index.ts +1 -0
- package/src/packlets/vector/vectorIndex.ts +97 -4
- package/src/test/unit/retrieve/fragmentSemanticRetriever.test.ts +163 -0
- package/src/test/unit/store/fragmentEmbedOnWrite.test.ts +349 -0
- package/src/test/unit/store/lenientOpen.test.ts +292 -0
- package/src/test/unit/vector/inMemoryFragmentCosineIndex.test.ts +389 -0
- package/temp/build/lint/_eslint-5eVG3S6w.json +29 -5
- package/temp/build/typescript/ts_8nwakTlr.json +1 -1
- package/temp/ts-agent-memory.api.json +4584 -2859
- package/temp/ts-agent-memory.api.md +78 -0
|
@@ -323,6 +323,13 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
|
323
323
|
private readonly _logger;
|
|
324
324
|
private readonly _vectorIndex;
|
|
325
325
|
private readonly _embed;
|
|
326
|
+
private readonly _fragmentIndex;
|
|
327
|
+
private readonly _fragmentEmbedder;
|
|
328
|
+
/**
|
|
329
|
+
* Records the initial walk could not load. Populated during `create()` in
|
|
330
|
+
* {@link MemoryRecordErrorMode | `'skip'` mode}; empty otherwise.
|
|
331
|
+
*/
|
|
332
|
+
private readonly _skippedRecords;
|
|
326
333
|
/** Monotonic write counter; incremented inside the write-lock on each put. */
|
|
327
334
|
private _seq;
|
|
328
335
|
/**
|
|
@@ -343,6 +350,15 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
|
343
350
|
*/
|
|
344
351
|
private static readonly _mutableFieldAccessors;
|
|
345
352
|
private constructor();
|
|
353
|
+
/**
|
|
354
|
+
* Records the initial vault walk could not parse or validate and quarantined
|
|
355
|
+
* (not indexed). Non-empty only when the store was opened with
|
|
356
|
+
* {@link MemoryRecordErrorMode | `onRecordError: 'skip'`} AND at least one
|
|
357
|
+
* record failed to load. Each entry identifies the offending file so a host
|
|
358
|
+
* can repair it; the file itself is never deleted or mutated, so a later open
|
|
359
|
+
* (after the body converter is fixed) re-indexes it.
|
|
360
|
+
*/
|
|
361
|
+
get skippedRecords(): ReadonlyArray<ISkippedRecord>;
|
|
346
362
|
/**
|
|
347
363
|
* Family-convention factory. Builds the derived index and a default LWW
|
|
348
364
|
* policy, then performs an initial FileTree walk so an existing vault is
|
|
@@ -430,6 +446,26 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
|
430
446
|
* failure).
|
|
431
447
|
*/
|
|
432
448
|
private _embedOnWrite;
|
|
449
|
+
/**
|
|
450
|
+
* Best-effort fragment-embed-on-write. When a fragment index AND a fragment
|
|
451
|
+
* embedder are wired, chunks + embeds the built record and replaces its
|
|
452
|
+
* fragments in the index (`addFragments` is whole-record-replace, so a re-authored
|
|
453
|
+
* document never leaves stale fragments behind — no explicit remove needed). A
|
|
454
|
+
* failure (returned `fail` OR a thrown/rejected hook) is logged and the record is
|
|
455
|
+
* returned unchanged — the put still persists, and the fragment index is a derived
|
|
456
|
+
* view a later `rebuild` reconciles. Unlike {@link FileTreeMemoryStore._embedOnWrite}
|
|
457
|
+
* it stamps nothing on the record (fragments have no per-record `embeddingRef`
|
|
458
|
+
* analog). A pass-through no-op when unwired (byte-identical record).
|
|
459
|
+
*/
|
|
460
|
+
private _embedFragmentsOnWrite;
|
|
461
|
+
/**
|
|
462
|
+
* Best-effort fragment removal. A no-op unless the full fragment lifecycle is
|
|
463
|
+
* wired (both an index AND an embedder), so an unwired store does no fragment
|
|
464
|
+
* work and behaves byte-identically. Failures are logged, never surfaced — a
|
|
465
|
+
* committed delete/eviction must not fail because a derived fragment index could
|
|
466
|
+
* not be pruned.
|
|
467
|
+
*/
|
|
468
|
+
private _removeFragmentsBestEffort;
|
|
433
469
|
/**
|
|
434
470
|
* Evict the records named by a `cull-oldest` decision, best-effort. Runs only
|
|
435
471
|
* after the authoritative `_persist`, so a failed eviction is logged (never
|
|
@@ -625,10 +661,83 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
|
625
661
|
/**
|
|
626
662
|
* Walk the FileTree once and rebuild the index. Also resumes the `seq`
|
|
627
663
|
* counter past the highest persisted `seq` so new writes stay monotonic.
|
|
664
|
+
*
|
|
665
|
+
* In `'skip'` mode each per-record failure is captured structurally on
|
|
666
|
+
* `this._skippedRecords` (path + scope + path-tagged error) at its failure
|
|
667
|
+
* site and logged at `warn`; the walk keeps every record that loaded.
|
|
628
668
|
*/
|
|
629
669
|
private _initialIndex;
|
|
630
670
|
/** Recursively collect every `.md` record under `dir` (scope = path segments). */
|
|
631
671
|
private _collectEntries;
|
|
672
|
+
/**
|
|
673
|
+
* Load and verify one record file. On failure in `'skip'` mode, records the
|
|
674
|
+
* structured {@link ISkippedRecord} identity (path + scope + path-tagged
|
|
675
|
+
* error) and logs the skip at `warn`; the failure is still returned so the
|
|
676
|
+
* caller's `mapSuccess` drops it from the loaded set. In `'fail'` mode the
|
|
677
|
+
* failure passes through untouched so the historical error is byte-identical.
|
|
678
|
+
*/
|
|
679
|
+
private _loadRecordFile;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* The loud-degradation message a {@link FragmentSemanticRetriever} returns when a
|
|
684
|
+
* fragment query is issued but no {@link IFragmentSemanticBackend | backend} is
|
|
685
|
+
* wired — the discovery surface NEVER answers a fragment query with a silent empty.
|
|
686
|
+
* @public
|
|
687
|
+
*/
|
|
688
|
+
export declare const FRAGMENT_SEMANTIC_UNWIRED_MESSAGE: string;
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* The fragment-granular sibling of {@link MemoryEmbedder}: chunks a record's body
|
|
692
|
+
* and embeds each chunk, returning one {@link IEmbeddedFragment} per chunk. The
|
|
693
|
+
* chunking policy (window size, overlap) lives entirely in the consumer's embedder
|
|
694
|
+
* — the core stays chunking-agnostic, exactly as it stays embedder-agnostic for
|
|
695
|
+
* the record-granular path. Used by the store's fragment-embed-on-write hook.
|
|
696
|
+
* @public
|
|
697
|
+
*/
|
|
698
|
+
export declare type FragmentEmbedder = (record: IMemoryRecord<unknown>) => Promise<Result<ReadonlyArray<IEmbeddedFragment>>>;
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* The sub-document semantic-search retriever — the "discovery" half of a
|
|
702
|
+
* search-then-read contract. It embeds a fragment query, queries the
|
|
703
|
+
* {@link IFragmentVectorIndex}, and returns the raw per-fragment
|
|
704
|
+
* {@link IVectorQueryHit | hits} (each carrying a record `target` AND the matched
|
|
705
|
+
* `locator`), NOT resolved records: the consumer re-reads each record and slices it
|
|
706
|
+
* by the locator on its own read side.
|
|
707
|
+
*
|
|
708
|
+
* @remarks
|
|
709
|
+
* Deliberately NOT an {@link IMemoryRetriever}: memory recall is record-granular and
|
|
710
|
+
* returns records; fragment discovery is span-granular and returns locators. Keeping
|
|
711
|
+
* it a distinct surface matches the consumer contract (memory stays record-granular;
|
|
712
|
+
* sub-document knowledge uses a separate fragment index) and avoids overloading the
|
|
713
|
+
* record retriever's return type with a locator that only makes sense here.
|
|
714
|
+
*
|
|
715
|
+
* When no backend is wired, `supportsFragmentRecall` is `false` and any fragment
|
|
716
|
+
* query degrades loudly ({@link FRAGMENT_SEMANTIC_UNWIRED_MESSAGE}) — it NEVER
|
|
717
|
+
* returns a silent empty. A consumer-supplied backend that rejects (throws) is
|
|
718
|
+
* normalized into a `Failure`.
|
|
719
|
+
* @public
|
|
720
|
+
*/
|
|
721
|
+
export declare class FragmentSemanticRetriever {
|
|
722
|
+
private readonly _backend;
|
|
723
|
+
private constructor();
|
|
724
|
+
/** What this retriever can do given its wiring. */
|
|
725
|
+
get capabilities(): IFragmentRetrieverCapabilities;
|
|
726
|
+
/** Family-convention factory. */
|
|
727
|
+
static create(params: {
|
|
728
|
+
readonly backend?: IFragmentSemanticBackend;
|
|
729
|
+
}): Result<FragmentSemanticRetriever>;
|
|
730
|
+
/**
|
|
731
|
+
* Embed `query.semantic`, query the fragment index, and return the per-fragment
|
|
732
|
+
* hits in descending score order. Fails loudly when no backend is wired.
|
|
733
|
+
*/
|
|
734
|
+
retrieve(query: IFragmentQuery): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
|
|
735
|
+
/**
|
|
736
|
+
* Invoke a consumer-supplied backend hook, normalizing both a returned `fail`
|
|
737
|
+
* and a thrown/rejected promise into a single `fragment recall: <label> failed`
|
|
738
|
+
* `Failure`.
|
|
739
|
+
*/
|
|
740
|
+
private static _callBackend;
|
|
632
741
|
}
|
|
633
742
|
|
|
634
743
|
/**
|
|
@@ -906,6 +1015,19 @@ export declare interface IEdgeTarget {
|
|
|
906
1015
|
readonly id: MemoryId;
|
|
907
1016
|
}
|
|
908
1017
|
|
|
1018
|
+
/**
|
|
1019
|
+
* One embedded fragment of a record: its in-record {@link IFragmentLocator | span}
|
|
1020
|
+
* and the vector for that span. Produced by a {@link FragmentEmbedder} and stored
|
|
1021
|
+
* via {@link IFragmentVectorIndex.addFragments}.
|
|
1022
|
+
* @public
|
|
1023
|
+
*/
|
|
1024
|
+
export declare interface IEmbeddedFragment {
|
|
1025
|
+
/** The fragment's in-record span. */
|
|
1026
|
+
readonly locator: IFragmentLocator;
|
|
1027
|
+
/** The embedding vector for that span. */
|
|
1028
|
+
readonly vector: Float32Array;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
909
1031
|
/**
|
|
910
1032
|
* A near-duplicate candidate surfaced to the {@link IEntityResolver} by stage-4
|
|
911
1033
|
* layer-2 similarity search: an existing record whose embedding is within the
|
|
@@ -1031,6 +1153,136 @@ export declare interface IFileTreeMemoryStoreCreateParams {
|
|
|
1031
1153
|
* `rebuild` reconciles, so a vector failure never fails an authoritative write.
|
|
1032
1154
|
*/
|
|
1033
1155
|
readonly embed?: MemoryEmbedder;
|
|
1156
|
+
/**
|
|
1157
|
+
* Optional fragment-granular vector index for sub-document semantic search.
|
|
1158
|
+
* Wired together with
|
|
1159
|
+
* {@link IFileTreeMemoryStoreCreateParams.fragmentEmbedder | fragmentEmbedder}:
|
|
1160
|
+
* when both are present the store chunks + embeds each written record and
|
|
1161
|
+
* maintains the fragment index on `put` / `delete` / cap-cull eviction — the
|
|
1162
|
+
* "discovery" half of a search-then-read contract, queried through a
|
|
1163
|
+
* {@link FragmentSemanticRetriever}. Independent of the record-granular
|
|
1164
|
+
* {@link IFileTreeMemoryStoreCreateParams.vectorIndex | vectorIndex} pair: a
|
|
1165
|
+
* store may wire record vectors, fragment vectors, both, or neither. Absent (or
|
|
1166
|
+
* `fragmentEmbedder` absent) → no fragment work happens and the store behaves
|
|
1167
|
+
* byte-identically (the additive, zero-overhead-when-unwired default).
|
|
1168
|
+
*/
|
|
1169
|
+
readonly fragmentIndex?: IFragmentVectorIndex;
|
|
1170
|
+
/**
|
|
1171
|
+
* Optional fragment embedder applied to each record on write, wired together
|
|
1172
|
+
* with {@link IFileTreeMemoryStoreCreateParams.fragmentIndex | fragmentIndex}.
|
|
1173
|
+
* The consumer owns the chunking policy (window size, overlap) and the embedding
|
|
1174
|
+
* call; the store stays chunking- and embedder-agnostic. Fragment index
|
|
1175
|
+
* maintenance is **best-effort**, exactly like the record-vector path: a failed
|
|
1176
|
+
* (or throwing) `fragmentEmbedder` / `addFragments` / `remove` is logged at
|
|
1177
|
+
* `warn` and the record operation still succeeds — the fragment index is a
|
|
1178
|
+
* derived view a later `rebuild` reconciles.
|
|
1179
|
+
*/
|
|
1180
|
+
readonly fragmentEmbedder?: FragmentEmbedder;
|
|
1181
|
+
/**
|
|
1182
|
+
* How the initial vault walk reacts to a record that fails to parse or
|
|
1183
|
+
* validate. Defaults to `'fail'` — one bad record fails the whole open, the
|
|
1184
|
+
* historical behavior, preserved byte-for-byte. Set `'skip'` to quarantine
|
|
1185
|
+
* unreadable records instead: valid records still load, each skip is logged
|
|
1186
|
+
* at `warn` and surfaced on {@link FileTreeMemoryStore.skippedRecords}, and
|
|
1187
|
+
* the offending file is left untouched for a later (post-fix) re-index. See
|
|
1188
|
+
* {@link MemoryRecordErrorMode}.
|
|
1189
|
+
*/
|
|
1190
|
+
readonly onRecordError?: MemoryRecordErrorMode;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* A half-open `[start, end)` span into a record's body — the in-record locator a
|
|
1195
|
+
* {@link IFragmentVectorIndex} carries on each fragment hit. `start` is inclusive,
|
|
1196
|
+
* `end` exclusive. The unit (character / byte / token offsets) is the consumer's
|
|
1197
|
+
* choice: the index stores the two integers opaquely and never interprets them,
|
|
1198
|
+
* so they line up with whatever locator the consumer's own read side uses.
|
|
1199
|
+
* @public
|
|
1200
|
+
*/
|
|
1201
|
+
export declare interface IFragmentLocator {
|
|
1202
|
+
/** Inclusive start offset into the record body. */
|
|
1203
|
+
readonly start: number;
|
|
1204
|
+
/** Exclusive end offset into the record body. */
|
|
1205
|
+
readonly end: number;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* A sub-document semantic-search request: the natural-language `semantic` text to
|
|
1210
|
+
* match, an optional `topK` result cap (default 10), and an optional
|
|
1211
|
+
* `maxPerRecord` cap that keeps one long document from monopolizing the result.
|
|
1212
|
+
* @public
|
|
1213
|
+
*/
|
|
1214
|
+
export declare interface IFragmentQuery {
|
|
1215
|
+
/** The natural-language text to embed and match against stored fragments. */
|
|
1216
|
+
readonly semantic: string;
|
|
1217
|
+
/** Maximum number of fragment hits to return. Defaults to 10. */
|
|
1218
|
+
readonly topK?: number;
|
|
1219
|
+
/**
|
|
1220
|
+
* Maximum number of fragments any single record may contribute to the result.
|
|
1221
|
+
* Applied during selection (before the `topK` cut). Omit for uncapped.
|
|
1222
|
+
*/
|
|
1223
|
+
readonly maxPerRecord?: number;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
/**
|
|
1227
|
+
* What a {@link FragmentSemanticRetriever} can do given its wiring.
|
|
1228
|
+
* @public
|
|
1229
|
+
*/
|
|
1230
|
+
export declare interface IFragmentRetrieverCapabilities {
|
|
1231
|
+
/** `true` when a fragment backend is wired and fragment recall is operational. */
|
|
1232
|
+
readonly supportsFragmentRecall: boolean;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
/**
|
|
1236
|
+
* The fragment backend wired into a {@link FragmentSemanticRetriever}: the fragment
|
|
1237
|
+
* index to query and the embedder that turns the query text into a vector. Both are
|
|
1238
|
+
* required together — a fragment index is useless without a way to embed the query.
|
|
1239
|
+
* @public
|
|
1240
|
+
*/
|
|
1241
|
+
export declare interface IFragmentSemanticBackend {
|
|
1242
|
+
/** The fragment-granular vector index to query. */
|
|
1243
|
+
readonly fragmentIndex: IFragmentVectorIndex;
|
|
1244
|
+
/** Turns the query text into a vector. */
|
|
1245
|
+
readonly embedQuery: QueryEmbedder;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* The fragment-granular sibling of {@link IVectorIndex}: instead of one vector per
|
|
1250
|
+
* record it holds many vectors per record, each tagged with an in-record
|
|
1251
|
+
* {@link IFragmentLocator}, and its `query` returns per-fragment hits carrying that
|
|
1252
|
+
* locator. This is the seam behind sub-document semantic search — the "discovery"
|
|
1253
|
+
* half of a search-then-read contract, where a hit's `(target, locator)` tells the
|
|
1254
|
+
* consumer which record AND which span to read.
|
|
1255
|
+
*
|
|
1256
|
+
* @remarks
|
|
1257
|
+
* Deliberately NOT `extends IVectorIndex`: an index keyed by `(target, locator)`
|
|
1258
|
+
* has no well-defined single-vector `add(target, vector)`. It is a parallel
|
|
1259
|
+
* contract with three operations — `addFragments`, `remove`, `query` — reusing
|
|
1260
|
+
* {@link IVectorQueryHit} (whose `locator` is always populated here). Kept distinct
|
|
1261
|
+
* from the record-granular index per the consumer contract: memory recall stays
|
|
1262
|
+
* record-granular; sub-document knowledge uses a separate fragment index.
|
|
1263
|
+
* @public
|
|
1264
|
+
*/
|
|
1265
|
+
export declare interface IFragmentVectorIndex {
|
|
1266
|
+
/**
|
|
1267
|
+
* Add (or replace) all fragments for the scope-qualified `target`. Whole-record
|
|
1268
|
+
* semantics: every fragment previously held for `target` is dropped and replaced
|
|
1269
|
+
* by `fragments`, so a re-authored document never leaves stale fragments behind.
|
|
1270
|
+
* Returns the number of fragments now held for the record.
|
|
1271
|
+
*/
|
|
1272
|
+
addFragments(target: IEdgeTarget, fragments: ReadonlyArray<IEmbeddedFragment>): Promise<Result<number>>;
|
|
1273
|
+
/**
|
|
1274
|
+
* Remove every fragment for the scope-qualified `target`. Returns the removed
|
|
1275
|
+
* target. Idempotent — removing a target with no fragments still succeeds.
|
|
1276
|
+
*/
|
|
1277
|
+
remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>>;
|
|
1278
|
+
/**
|
|
1279
|
+
* Return the `topK` nearest fragments to `vector`, in descending score order,
|
|
1280
|
+
* each hit carrying its record `target` and fragment `locator`. When
|
|
1281
|
+
* `maxPerRecord` is supplied, no more than that many fragments of any single
|
|
1282
|
+
* record appear in the result — the cap is applied during selection (before the
|
|
1283
|
+
* `topK` cut) so one long document cannot crowd out others.
|
|
1284
|
+
*/
|
|
1285
|
+
query(vector: Float32Array, topK: number, maxPerRecord?: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
|
|
1034
1286
|
}
|
|
1035
1287
|
|
|
1036
1288
|
/**
|
|
@@ -1867,6 +2119,77 @@ export declare class InMemoryCosineIndex implements IVectorIndex {
|
|
|
1867
2119
|
private static _cosine;
|
|
1868
2120
|
}
|
|
1869
2121
|
|
|
2122
|
+
/**
|
|
2123
|
+
* The brute-force, in-memory cosine {@link IFragmentVectorIndex} — the
|
|
2124
|
+
* fragment-granular sibling of {@link InMemoryCosineIndex}. Stores many
|
|
2125
|
+
* `Float32Array`s per record (one per in-record {@link IFragmentLocator | span})
|
|
2126
|
+
* and answers a query by computing cosine similarity against every stored
|
|
2127
|
+
* fragment, returning the top-k fragment hits by descending score.
|
|
2128
|
+
*
|
|
2129
|
+
* @remarks
|
|
2130
|
+
* Same regime and same non-goals as {@link InMemoryCosineIndex}: no external
|
|
2131
|
+
* dependency, no ANN structure, a linear scan over the stored fragments — the seam
|
|
2132
|
+
* ({@link IFragmentVectorIndex}) stays open for a consumer to swap a persistent /
|
|
2133
|
+
* ANN backend once N grows. `addFragments` is whole-record-replace, so re-authoring
|
|
2134
|
+
* a document never leaves stale fragments behind. The index has a single dimension
|
|
2135
|
+
* established by the first fragment added; every subsequent fragment and every
|
|
2136
|
+
* `query` vector must match it or fail loudly — a mismatched dimension is an
|
|
2137
|
+
* embedder-wiring bug, never a silent zero-similarity result.
|
|
2138
|
+
* {@link InMemoryFragmentCosineIndex.rebuild | rebuild} clears the index (and the
|
|
2139
|
+
* established dimension), so a re-embed with a different model is supported.
|
|
2140
|
+
*
|
|
2141
|
+
* The optional `maxPerRecord` cap on `query` is applied **during selection**, before
|
|
2142
|
+
* the `topK` cut, so one long document with many strong fragments cannot crowd every
|
|
2143
|
+
* other record out of the result.
|
|
2144
|
+
* @public
|
|
2145
|
+
*/
|
|
2146
|
+
export declare class InMemoryFragmentCosineIndex implements IFragmentVectorIndex {
|
|
2147
|
+
/**
|
|
2148
|
+
* Stored fragments keyed by the canonical {@link edgeTargetKey} of the record's
|
|
2149
|
+
* scope-qualified address, so two records that share a filename stem across
|
|
2150
|
+
* scopes occupy distinct entries and never overwrite each other's fragments.
|
|
2151
|
+
*/
|
|
2152
|
+
private readonly _records;
|
|
2153
|
+
/** The dimension of every stored fragment vector; `undefined` until the first `add`. */
|
|
2154
|
+
private _dimension;
|
|
2155
|
+
private constructor();
|
|
2156
|
+
/** The number of records that currently have at least one stored fragment. */
|
|
2157
|
+
get recordCount(): number;
|
|
2158
|
+
/** The total number of fragments currently held across all records. */
|
|
2159
|
+
get fragmentCount(): number;
|
|
2160
|
+
/** Family-convention factory. */
|
|
2161
|
+
static create(): Result<InMemoryFragmentCosineIndex>;
|
|
2162
|
+
/** {@inheritDoc IFragmentVectorIndex.addFragments} */
|
|
2163
|
+
addFragments(target: IEdgeTarget, fragments: ReadonlyArray<IEmbeddedFragment>): Promise<Result<number>>;
|
|
2164
|
+
/** {@inheritDoc IFragmentVectorIndex.remove} */
|
|
2165
|
+
remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>>;
|
|
2166
|
+
/** {@inheritDoc IFragmentVectorIndex.query} */
|
|
2167
|
+
query(vector: Float32Array, topK: number, maxPerRecord?: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
|
|
2168
|
+
/**
|
|
2169
|
+
* Re-embed every record from `source` and rebuild the fragment index from
|
|
2170
|
+
* scratch. Clears the current contents (and the established dimension) first, so
|
|
2171
|
+
* a re-embed with a different model is supported. Returns the total number of
|
|
2172
|
+
* fragments indexed.
|
|
2173
|
+
*
|
|
2174
|
+
* On any failure (list, embed, or add) the index is rolled back to empty rather
|
|
2175
|
+
* than left in a partially-rebuilt state.
|
|
2176
|
+
*
|
|
2177
|
+
* @param source - The scope-qualified record source to re-embed.
|
|
2178
|
+
* @param embed - The fragment embedder applied to each record.
|
|
2179
|
+
*/
|
|
2180
|
+
rebuild(source: IMemoryRecordSource, embed: FragmentEmbedder): Promise<Result<number>>;
|
|
2181
|
+
/** Empty the index and forget the established dimension. */
|
|
2182
|
+
private _reset;
|
|
2183
|
+
/** The Euclidean magnitude (L2 norm) of a vector. */
|
|
2184
|
+
private static _magnitude;
|
|
2185
|
+
/**
|
|
2186
|
+
* Cosine similarity between the query (whose magnitude is precomputed once and
|
|
2187
|
+
* reused across the scan) and a stored fragment vector. A zero-magnitude vector
|
|
2188
|
+
* on either side yields `0` rather than `NaN`.
|
|
2189
|
+
*/
|
|
2190
|
+
private static _cosine;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
1870
2193
|
/**
|
|
1871
2194
|
* Structured provenance for a record or an edge. Never a flat enum — the
|
|
1872
2195
|
* `[key: string]: unknown` index signature lets a consumer attach an opaque
|
|
@@ -1981,6 +2304,21 @@ export declare interface ISemanticRetrieverCreateParams {
|
|
|
1981
2304
|
readonly backend?: ISemanticBackend;
|
|
1982
2305
|
}
|
|
1983
2306
|
|
|
2307
|
+
/**
|
|
2308
|
+
* A record that {@link FileTreeMemoryStore.create} could not load and
|
|
2309
|
+
* quarantined (only produced in {@link MemoryRecordErrorMode | `'skip'` mode}).
|
|
2310
|
+
* The `path` identifies WHICH record was skipped so a host can repair it.
|
|
2311
|
+
* @public
|
|
2312
|
+
*/
|
|
2313
|
+
export declare interface ISkippedRecord {
|
|
2314
|
+
/** The record file's path within the vault (`<scope>/<filename>.md`). */
|
|
2315
|
+
readonly path: string;
|
|
2316
|
+
/** The scope the record lives under (its parent directory path). */
|
|
2317
|
+
readonly scope: MemoryScopeKey;
|
|
2318
|
+
/** The parse/validation failure message (includes the record path). */
|
|
2319
|
+
readonly error: string;
|
|
2320
|
+
}
|
|
2321
|
+
|
|
1984
2322
|
/**
|
|
1985
2323
|
* Narrow an {@link IIdentityCodec} to {@link ITemporalIdentityCodec} by probing
|
|
1986
2324
|
* for the versioned methods. Used by the store when an `encode` result reports
|
|
@@ -2101,10 +2439,11 @@ export declare interface IVectorIndex {
|
|
|
2101
2439
|
}
|
|
2102
2440
|
|
|
2103
2441
|
/**
|
|
2104
|
-
* A single hit returned by {@link IVectorIndex.query}
|
|
2105
|
-
*
|
|
2106
|
-
*
|
|
2107
|
-
* returned in descending
|
|
2442
|
+
* A single hit returned by {@link IVectorIndex.query} (or
|
|
2443
|
+
* {@link IFragmentVectorIndex.query}): the matched record's scope-qualified
|
|
2444
|
+
* {@link IEdgeTarget | address} and the backend's similarity score (higher = more
|
|
2445
|
+
* similar; the exact scale is backend-defined). Hits are returned in descending
|
|
2446
|
+
* score order.
|
|
2108
2447
|
*
|
|
2109
2448
|
* @remarks
|
|
2110
2449
|
* The address is a `(scope, id)` pair, NOT a bare {@link MemoryId} — per-scope
|
|
@@ -2112,6 +2451,10 @@ export declare interface IVectorIndex {
|
|
|
2112
2451
|
* stem under different scopes, so a bare id could not disambiguate two records
|
|
2113
2452
|
* that share a stem. The caller re-resolves the hit against the record index by
|
|
2114
2453
|
* the same scoped address.
|
|
2454
|
+
*
|
|
2455
|
+
* `locator` is present only on hits from a {@link IFragmentVectorIndex} — it
|
|
2456
|
+
* identifies WHICH fragment of the record matched. Record-granular
|
|
2457
|
+
* {@link IVectorIndex} hits omit it.
|
|
2115
2458
|
* @public
|
|
2116
2459
|
*/
|
|
2117
2460
|
export declare interface IVectorQueryHit {
|
|
@@ -2119,6 +2462,8 @@ export declare interface IVectorQueryHit {
|
|
|
2119
2462
|
readonly target: IEdgeTarget;
|
|
2120
2463
|
/** Backend similarity score; higher is more similar. */
|
|
2121
2464
|
readonly score: number;
|
|
2465
|
+
/** The matched fragment's in-record span; present only for fragment-index hits. */
|
|
2466
|
+
readonly locator?: IFragmentLocator;
|
|
2122
2467
|
}
|
|
2123
2468
|
|
|
2124
2469
|
/**
|
|
@@ -2761,6 +3106,24 @@ export declare class MemoryObservationStore implements IMemoryObserver {
|
|
|
2761
3106
|
private static _matches;
|
|
2762
3107
|
}
|
|
2763
3108
|
|
|
3109
|
+
/**
|
|
3110
|
+
* Policy for how {@link FileTreeMemoryStore.create}'s initial vault walk reacts
|
|
3111
|
+
* to a record that fails to parse or validate.
|
|
3112
|
+
*
|
|
3113
|
+
* - `'fail'` (the default) — one unreadable record fails the whole open. The
|
|
3114
|
+
* walk collapses per-record results with `mapResults`, so any single failure
|
|
3115
|
+
* aborts `create()`. This is the historical behavior, preserved byte-for-byte.
|
|
3116
|
+
* - `'skip'` — an unreadable record is quarantined (not indexed) rather than
|
|
3117
|
+
* failing the open. Every record that DOES parse loads normally; each skip is
|
|
3118
|
+
* logged at `warn` and surfaced structurally on
|
|
3119
|
+
* {@link FileTreeMemoryStore.skippedRecords}. The offending file is never
|
|
3120
|
+
* deleted or mutated, so a later open (after the body converter is fixed)
|
|
3121
|
+
* re-indexes it. A vault holds every kind in one store, so a required-field
|
|
3122
|
+
* migration on one kind must not make every other record unreadable.
|
|
3123
|
+
* @public
|
|
3124
|
+
*/
|
|
3125
|
+
export declare type MemoryRecordErrorMode = 'skip' | 'fail';
|
|
3126
|
+
|
|
2764
3127
|
/**
|
|
2765
3128
|
* Scope path segment. May be multi-segment (`/`-separated) for kinds whose
|
|
2766
3129
|
* codec maps an entity into a sub-tree (e.g. MTM: `conversations/<id>`). The
|
|
@@ -121,6 +121,22 @@ export class FileTreeMemoryStore implements IMemoryStore {
|
|
|
121
121
|
list(filter?: IMemoryStoreListFilter): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
122
122
|
listScoped(): Promise<Result<ReadonlyArray<IScopedMemoryRecord>>>;
|
|
123
123
|
put(record: IMemoryRecord<unknown>): Promise<Result<IMemoryRecord<unknown>>>;
|
|
124
|
+
get skippedRecords(): ReadonlyArray<ISkippedRecord>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// @public
|
|
128
|
+
export const FRAGMENT_SEMANTIC_UNWIRED_MESSAGE: string;
|
|
129
|
+
|
|
130
|
+
// @public
|
|
131
|
+
export type FragmentEmbedder = (record: IMemoryRecord<unknown>) => Promise<Result<ReadonlyArray<IEmbeddedFragment>>>;
|
|
132
|
+
|
|
133
|
+
// @public
|
|
134
|
+
export class FragmentSemanticRetriever {
|
|
135
|
+
get capabilities(): IFragmentRetrieverCapabilities;
|
|
136
|
+
static create(params: {
|
|
137
|
+
readonly backend?: IFragmentSemanticBackend;
|
|
138
|
+
}): Result<FragmentSemanticRetriever>;
|
|
139
|
+
retrieve(query: IFragmentQuery): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
|
|
124
140
|
}
|
|
125
141
|
|
|
126
142
|
// @public
|
|
@@ -203,6 +219,12 @@ export interface IEdgeTarget {
|
|
|
203
219
|
readonly scope: MemoryScopeKey;
|
|
204
220
|
}
|
|
205
221
|
|
|
222
|
+
// @public
|
|
223
|
+
export interface IEmbeddedFragment {
|
|
224
|
+
readonly locator: IFragmentLocator;
|
|
225
|
+
readonly vector: Float32Array;
|
|
226
|
+
}
|
|
227
|
+
|
|
206
228
|
// @public
|
|
207
229
|
export interface IEntityResolutionCandidate {
|
|
208
230
|
readonly record: IMemoryRecord<unknown>;
|
|
@@ -226,8 +248,11 @@ export interface IFileTreeMemoryStoreCreateParams {
|
|
|
226
248
|
readonly codecs?: ReadonlyMap<Kind, IIdentityCodec>;
|
|
227
249
|
readonly defaultCodec?: IIdentityCodec;
|
|
228
250
|
readonly embed?: MemoryEmbedder;
|
|
251
|
+
readonly fragmentEmbedder?: FragmentEmbedder;
|
|
252
|
+
readonly fragmentIndex?: IFragmentVectorIndex;
|
|
229
253
|
readonly logger?: Logging.ILogger;
|
|
230
254
|
readonly observers?: ReadonlyArray<IMemoryObserver>;
|
|
255
|
+
readonly onRecordError?: MemoryRecordErrorMode;
|
|
231
256
|
readonly rankProjectors?: ReadonlyMap<Kind, RankProjector>;
|
|
232
257
|
readonly registry: IBodyConverterRegistry;
|
|
233
258
|
readonly root: FileTree.IMutableFileTreeDirectoryItem;
|
|
@@ -236,6 +261,37 @@ export interface IFileTreeMemoryStoreCreateParams {
|
|
|
236
261
|
readonly writePolicies?: ReadonlyMap<Kind, IWritePolicy>;
|
|
237
262
|
}
|
|
238
263
|
|
|
264
|
+
// @public
|
|
265
|
+
export interface IFragmentLocator {
|
|
266
|
+
readonly end: number;
|
|
267
|
+
readonly start: number;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// @public
|
|
271
|
+
export interface IFragmentQuery {
|
|
272
|
+
readonly maxPerRecord?: number;
|
|
273
|
+
readonly semantic: string;
|
|
274
|
+
readonly topK?: number;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// @public
|
|
278
|
+
export interface IFragmentRetrieverCapabilities {
|
|
279
|
+
readonly supportsFragmentRecall: boolean;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// @public
|
|
283
|
+
export interface IFragmentSemanticBackend {
|
|
284
|
+
readonly embedQuery: QueryEmbedder;
|
|
285
|
+
readonly fragmentIndex: IFragmentVectorIndex;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// @public
|
|
289
|
+
export interface IFragmentVectorIndex {
|
|
290
|
+
addFragments(target: IEdgeTarget, fragments: ReadonlyArray<IEmbeddedFragment>): Promise<Result<number>>;
|
|
291
|
+
query(vector: Float32Array, topK: number, maxPerRecord?: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
|
|
292
|
+
remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>>;
|
|
293
|
+
}
|
|
294
|
+
|
|
239
295
|
// @public
|
|
240
296
|
export interface IIdentityCodec {
|
|
241
297
|
decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId>;
|
|
@@ -495,6 +551,17 @@ export class InMemoryCosineIndex implements IVectorIndex {
|
|
|
495
551
|
get size(): number;
|
|
496
552
|
}
|
|
497
553
|
|
|
554
|
+
// @public
|
|
555
|
+
export class InMemoryFragmentCosineIndex implements IFragmentVectorIndex {
|
|
556
|
+
addFragments(target: IEdgeTarget, fragments: ReadonlyArray<IEmbeddedFragment>): Promise<Result<number>>;
|
|
557
|
+
static create(): Result<InMemoryFragmentCosineIndex>;
|
|
558
|
+
get fragmentCount(): number;
|
|
559
|
+
query(vector: Float32Array, topK: number, maxPerRecord?: number): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
|
|
560
|
+
rebuild(source: IMemoryRecordSource, embed: FragmentEmbedder): Promise<Result<number>>;
|
|
561
|
+
get recordCount(): number;
|
|
562
|
+
remove(target: IEdgeTarget): Promise<Result<IEdgeTarget>>;
|
|
563
|
+
}
|
|
564
|
+
|
|
498
565
|
// @public
|
|
499
566
|
export interface IProvenance {
|
|
500
567
|
readonly [key: string]: unknown;
|
|
@@ -540,6 +607,13 @@ export interface ISemanticRetrieverCreateParams {
|
|
|
540
607
|
readonly index: IMemoryIndex;
|
|
541
608
|
}
|
|
542
609
|
|
|
610
|
+
// @public
|
|
611
|
+
export interface ISkippedRecord {
|
|
612
|
+
readonly error: string;
|
|
613
|
+
readonly path: string;
|
|
614
|
+
readonly scope: MemoryScopeKey;
|
|
615
|
+
}
|
|
616
|
+
|
|
543
617
|
// @public
|
|
544
618
|
export function isTemporalIdentityCodec(codec: IIdentityCodec): codec is ITemporalIdentityCodec;
|
|
545
619
|
|
|
@@ -579,6 +653,7 @@ export interface IVectorIndex {
|
|
|
579
653
|
|
|
580
654
|
// @public
|
|
581
655
|
export interface IVectorQueryHit {
|
|
656
|
+
readonly locator?: IFragmentLocator;
|
|
582
657
|
readonly score: number;
|
|
583
658
|
readonly target: IEdgeTarget;
|
|
584
659
|
}
|
|
@@ -698,6 +773,9 @@ export class MemoryObservationStore implements IMemoryObserver {
|
|
|
698
773
|
get size(): number;
|
|
699
774
|
}
|
|
700
775
|
|
|
776
|
+
// @public
|
|
777
|
+
export type MemoryRecordErrorMode = 'skip' | 'fail';
|
|
778
|
+
|
|
701
779
|
// @public
|
|
702
780
|
export type MemoryScopeKey = Brand<string, 'MemoryScopeKey'>;
|
|
703
781
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { IFragmentVectorIndex, IVectorQueryHit } from '../vector';
|
|
3
|
+
import { QueryEmbedder } from './semanticRetriever';
|
|
4
|
+
/**
|
|
5
|
+
* The loud-degradation message a {@link FragmentSemanticRetriever} returns when a
|
|
6
|
+
* fragment query is issued but no {@link IFragmentSemanticBackend | backend} is
|
|
7
|
+
* wired — the discovery surface NEVER answers a fragment query with a silent empty.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export declare const FRAGMENT_SEMANTIC_UNWIRED_MESSAGE: string;
|
|
11
|
+
/**
|
|
12
|
+
* The fragment backend wired into a {@link FragmentSemanticRetriever}: the fragment
|
|
13
|
+
* index to query and the embedder that turns the query text into a vector. Both are
|
|
14
|
+
* required together — a fragment index is useless without a way to embed the query.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export interface IFragmentSemanticBackend {
|
|
18
|
+
/** The fragment-granular vector index to query. */
|
|
19
|
+
readonly fragmentIndex: IFragmentVectorIndex;
|
|
20
|
+
/** Turns the query text into a vector. */
|
|
21
|
+
readonly embedQuery: QueryEmbedder;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A sub-document semantic-search request: the natural-language `semantic` text to
|
|
25
|
+
* match, an optional `topK` result cap (default 10), and an optional
|
|
26
|
+
* `maxPerRecord` cap that keeps one long document from monopolizing the result.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export interface IFragmentQuery {
|
|
30
|
+
/** The natural-language text to embed and match against stored fragments. */
|
|
31
|
+
readonly semantic: string;
|
|
32
|
+
/** Maximum number of fragment hits to return. Defaults to 10. */
|
|
33
|
+
readonly topK?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Maximum number of fragments any single record may contribute to the result.
|
|
36
|
+
* Applied during selection (before the `topK` cut). Omit for uncapped.
|
|
37
|
+
*/
|
|
38
|
+
readonly maxPerRecord?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* What a {@link FragmentSemanticRetriever} can do given its wiring.
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
export interface IFragmentRetrieverCapabilities {
|
|
45
|
+
/** `true` when a fragment backend is wired and fragment recall is operational. */
|
|
46
|
+
readonly supportsFragmentRecall: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The sub-document semantic-search retriever — the "discovery" half of a
|
|
50
|
+
* search-then-read contract. It embeds a fragment query, queries the
|
|
51
|
+
* {@link IFragmentVectorIndex}, and returns the raw per-fragment
|
|
52
|
+
* {@link IVectorQueryHit | hits} (each carrying a record `target` AND the matched
|
|
53
|
+
* `locator`), NOT resolved records: the consumer re-reads each record and slices it
|
|
54
|
+
* by the locator on its own read side.
|
|
55
|
+
*
|
|
56
|
+
* @remarks
|
|
57
|
+
* Deliberately NOT an {@link IMemoryRetriever}: memory recall is record-granular and
|
|
58
|
+
* returns records; fragment discovery is span-granular and returns locators. Keeping
|
|
59
|
+
* it a distinct surface matches the consumer contract (memory stays record-granular;
|
|
60
|
+
* sub-document knowledge uses a separate fragment index) and avoids overloading the
|
|
61
|
+
* record retriever's return type with a locator that only makes sense here.
|
|
62
|
+
*
|
|
63
|
+
* When no backend is wired, `supportsFragmentRecall` is `false` and any fragment
|
|
64
|
+
* query degrades loudly ({@link FRAGMENT_SEMANTIC_UNWIRED_MESSAGE}) — it NEVER
|
|
65
|
+
* returns a silent empty. A consumer-supplied backend that rejects (throws) is
|
|
66
|
+
* normalized into a `Failure`.
|
|
67
|
+
* @public
|
|
68
|
+
*/
|
|
69
|
+
export declare class FragmentSemanticRetriever {
|
|
70
|
+
private readonly _backend;
|
|
71
|
+
private constructor();
|
|
72
|
+
/** What this retriever can do given its wiring. */
|
|
73
|
+
get capabilities(): IFragmentRetrieverCapabilities;
|
|
74
|
+
/** Family-convention factory. */
|
|
75
|
+
static create(params: {
|
|
76
|
+
readonly backend?: IFragmentSemanticBackend;
|
|
77
|
+
}): Result<FragmentSemanticRetriever>;
|
|
78
|
+
/**
|
|
79
|
+
* Embed `query.semantic`, query the fragment index, and return the per-fragment
|
|
80
|
+
* hits in descending score order. Fails loudly when no backend is wired.
|
|
81
|
+
*/
|
|
82
|
+
retrieve(query: IFragmentQuery): Promise<Result<ReadonlyArray<IVectorQueryHit>>>;
|
|
83
|
+
/**
|
|
84
|
+
* Invoke a consumer-supplied backend hook, normalizing both a returned `fail`
|
|
85
|
+
* and a thrown/rejected promise into a single `fragment recall: <label> failed`
|
|
86
|
+
* `Failure`.
|
|
87
|
+
*/
|
|
88
|
+
private static _callBackend;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=fragmentSemanticRetriever.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragmentSemanticRetriever.d.ts","sourceRoot":"","sources":["../../../src/packlets/retrieve/fragmentSemanticRetriever.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,iCAAiC,EAAE,MAC+D,CAAC;AAEhH;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,mDAAmD;IACnD,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAAC;IAC7C,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;CACpC;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,kFAAkF;IAClF,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;IAEhE,OAAO;IAIP,mDAAmD;IACnD,IAAW,YAAY,IAAI,8BAA8B,CAExD;IAED,iCAAiC;WACnB,MAAM,CAAC,MAAM,EAAE;QAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAAC;KAC7C,GAAG,MAAM,CAAC,yBAAyB,CAAC;IAIrC;;;OAGG;IACU,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;IAoB7F;;;;OAIG;mBACkB,YAAY;CAOlC"}
|