@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.
Files changed (82) hide show
  1. package/.rush/temp/{cbbdbe09515171b4eba8f2592be2dace1e4e8142.tar.log → 285f03271c27ef724d49e730c0db58d9e4ac1a44.tar.log} +38 -2
  2. package/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +2 -2
  3. package/.rush/temp/operation/build/all.log +2 -2
  4. package/.rush/temp/operation/build/log-chunks.jsonl +2 -2
  5. package/.rush/temp/operation/build/state.json +1 -1
  6. package/dist/packlets/retrieve/fragmentSemanticRetriever.js +78 -0
  7. package/dist/packlets/retrieve/fragmentSemanticRetriever.js.map +1 -0
  8. package/dist/packlets/retrieve/index.js +1 -0
  9. package/dist/packlets/retrieve/index.js.map +1 -1
  10. package/dist/packlets/store/fileTreeMemoryStore.js +105 -14
  11. package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
  12. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js +200 -0
  13. package/dist/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -0
  14. package/dist/packlets/vector/index.js +1 -0
  15. package/dist/packlets/vector/index.js.map +1 -1
  16. package/dist/packlets/vector/vectorIndex.js.map +1 -1
  17. package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js +116 -0
  18. package/dist/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +1 -0
  19. package/dist/test/unit/store/fragmentEmbedOnWrite.test.js +255 -0
  20. package/dist/test/unit/store/fragmentEmbedOnWrite.test.js.map +1 -0
  21. package/dist/test/unit/store/lenientOpen.test.js +248 -0
  22. package/dist/test/unit/store/lenientOpen.test.js.map +1 -0
  23. package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js +297 -0
  24. package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +1 -0
  25. package/dist/ts-agent-memory.d.ts +367 -4
  26. package/etc/ts-agent-memory.api.md +78 -0
  27. package/lib/packlets/retrieve/fragmentSemanticRetriever.d.ts +90 -0
  28. package/lib/packlets/retrieve/fragmentSemanticRetriever.d.ts.map +1 -0
  29. package/lib/packlets/retrieve/fragmentSemanticRetriever.js +82 -0
  30. package/lib/packlets/retrieve/fragmentSemanticRetriever.js.map +1 -0
  31. package/lib/packlets/retrieve/index.d.ts +1 -0
  32. package/lib/packlets/retrieve/index.d.ts.map +1 -1
  33. package/lib/packlets/retrieve/index.js +1 -0
  34. package/lib/packlets/retrieve/index.js.map +1 -1
  35. package/lib/packlets/store/fileTreeMemoryStore.d.ts +115 -1
  36. package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
  37. package/lib/packlets/store/fileTreeMemoryStore.js +104 -13
  38. package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
  39. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts +74 -0
  40. package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts.map +1 -0
  41. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js +204 -0
  42. package/lib/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -0
  43. package/lib/packlets/vector/index.d.ts +1 -0
  44. package/lib/packlets/vector/index.d.ts.map +1 -1
  45. package/lib/packlets/vector/index.js +1 -0
  46. package/lib/packlets/vector/index.js.map +1 -1
  47. package/lib/packlets/vector/vectorIndex.d.ts +85 -4
  48. package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
  49. package/lib/packlets/vector/vectorIndex.js.map +1 -1
  50. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts +2 -0
  51. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.d.ts.map +1 -0
  52. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js +118 -0
  53. package/lib/test/unit/retrieve/fragmentSemanticRetriever.test.js.map +1 -0
  54. package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts +2 -0
  55. package/lib/test/unit/store/fragmentEmbedOnWrite.test.d.ts.map +1 -0
  56. package/lib/test/unit/store/fragmentEmbedOnWrite.test.js +257 -0
  57. package/lib/test/unit/store/fragmentEmbedOnWrite.test.js.map +1 -0
  58. package/lib/test/unit/store/lenientOpen.test.d.ts +2 -0
  59. package/lib/test/unit/store/lenientOpen.test.d.ts.map +1 -0
  60. package/lib/test/unit/store/lenientOpen.test.js +250 -0
  61. package/lib/test/unit/store/lenientOpen.test.js.map +1 -0
  62. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts +2 -0
  63. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.d.ts.map +1 -0
  64. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js +299 -0
  65. package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +1 -0
  66. package/package.json +7 -7
  67. package/rush-logs/ts-agent-memory.build.cache.log +1 -1
  68. package/rush-logs/ts-agent-memory.build.log +2 -2
  69. package/src/packlets/retrieve/fragmentSemanticRetriever.ts +135 -0
  70. package/src/packlets/retrieve/index.ts +1 -0
  71. package/src/packlets/store/fileTreeMemoryStore.ts +208 -16
  72. package/src/packlets/vector/inMemoryFragmentCosineIndex.ts +262 -0
  73. package/src/packlets/vector/index.ts +1 -0
  74. package/src/packlets/vector/vectorIndex.ts +97 -4
  75. package/src/test/unit/retrieve/fragmentSemanticRetriever.test.ts +163 -0
  76. package/src/test/unit/store/fragmentEmbedOnWrite.test.ts +349 -0
  77. package/src/test/unit/store/lenientOpen.test.ts +292 -0
  78. package/src/test/unit/vector/inMemoryFragmentCosineIndex.test.ts +389 -0
  79. package/temp/build/lint/_eslint-5eVG3S6w.json +29 -5
  80. package/temp/build/typescript/ts_8nwakTlr.json +1 -1
  81. package/temp/ts-agent-memory.api.json +4584 -2859
  82. package/temp/ts-agent-memory.api.md +78 -0
@@ -0,0 +1,82 @@
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.FragmentSemanticRetriever = exports.FRAGMENT_SEMANTIC_UNWIRED_MESSAGE = void 0;
8
+ const ts_utils_1 = require("@fgv/ts-utils");
9
+ /**
10
+ * The loud-degradation message a {@link FragmentSemanticRetriever} returns when a
11
+ * fragment query is issued but no {@link IFragmentSemanticBackend | backend} is
12
+ * wired — the discovery surface NEVER answers a fragment query with a silent empty.
13
+ * @public
14
+ */
15
+ exports.FRAGMENT_SEMANTIC_UNWIRED_MESSAGE = 'fragment recall: no fragment index is wired; wire an IFragmentSemanticBackend to enable sub-document search';
16
+ /**
17
+ * The sub-document semantic-search retriever — the "discovery" half of a
18
+ * search-then-read contract. It embeds a fragment query, queries the
19
+ * {@link IFragmentVectorIndex}, and returns the raw per-fragment
20
+ * {@link IVectorQueryHit | hits} (each carrying a record `target` AND the matched
21
+ * `locator`), NOT resolved records: the consumer re-reads each record and slices it
22
+ * by the locator on its own read side.
23
+ *
24
+ * @remarks
25
+ * Deliberately NOT an {@link IMemoryRetriever}: memory recall is record-granular and
26
+ * returns records; fragment discovery is span-granular and returns locators. Keeping
27
+ * it a distinct surface matches the consumer contract (memory stays record-granular;
28
+ * sub-document knowledge uses a separate fragment index) and avoids overloading the
29
+ * record retriever's return type with a locator that only makes sense here.
30
+ *
31
+ * When no backend is wired, `supportsFragmentRecall` is `false` and any fragment
32
+ * query degrades loudly ({@link FRAGMENT_SEMANTIC_UNWIRED_MESSAGE}) — it NEVER
33
+ * returns a silent empty. A consumer-supplied backend that rejects (throws) is
34
+ * normalized into a `Failure`.
35
+ * @public
36
+ */
37
+ class FragmentSemanticRetriever {
38
+ constructor(backend) {
39
+ this._backend = backend;
40
+ }
41
+ /** What this retriever can do given its wiring. */
42
+ get capabilities() {
43
+ return { supportsFragmentRecall: this._backend !== undefined };
44
+ }
45
+ /** Family-convention factory. */
46
+ static create(params) {
47
+ return (0, ts_utils_1.succeed)(new FragmentSemanticRetriever(params.backend));
48
+ }
49
+ /**
50
+ * Embed `query.semantic`, query the fragment index, and return the per-fragment
51
+ * hits in descending score order. Fails loudly when no backend is wired.
52
+ */
53
+ async retrieve(query) {
54
+ if (this._backend === undefined) {
55
+ return (0, ts_utils_1.fail)(exports.FRAGMENT_SEMANTIC_UNWIRED_MESSAGE);
56
+ }
57
+ const backend = this._backend;
58
+ // Consumer-supplied hooks may throw; normalize both a returned `fail` and a
59
+ // rejection into a single `fragment recall: <label> failed` Failure so
60
+ // `retrieve` always honors its `Promise<Result<...>>` contract.
61
+ const embedded = await FragmentSemanticRetriever._callBackend('query embedding', () => backend.embedQuery(query.semantic));
62
+ if (embedded.isFailure()) {
63
+ return (0, ts_utils_1.fail)(embedded.message);
64
+ }
65
+ return FragmentSemanticRetriever._callBackend('fragment query', () => { var _a; return backend.fragmentIndex.query(embedded.value, (_a = query.topK) !== null && _a !== void 0 ? _a : 10, query.maxPerRecord); });
66
+ }
67
+ /**
68
+ * Invoke a consumer-supplied backend hook, normalizing both a returned `fail`
69
+ * and a thrown/rejected promise into a single `fragment recall: <label> failed`
70
+ * `Failure`.
71
+ */
72
+ static async _callBackend(label, op) {
73
+ try {
74
+ return (await op()).withErrorFormat((msg) => `fragment recall: ${label} failed: ${msg}`);
75
+ }
76
+ catch (err) {
77
+ return (0, ts_utils_1.fail)(`fragment recall: ${label} failed: ${String(err)}`);
78
+ }
79
+ }
80
+ }
81
+ exports.FragmentSemanticRetriever = FragmentSemanticRetriever;
82
+ //# sourceMappingURL=fragmentSemanticRetriever.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragmentSemanticRetriever.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/fragmentSemanticRetriever.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,4CAAsD;AAItD;;;;;GAKG;AACU,QAAA,iCAAiC,GAC5C,6GAA6G,CAAC;AA0ChH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAa,yBAAyB;IAGpC,YAAoB,OAA6C;QAC/D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED,mDAAmD;IACnD,IAAW,YAAY;QACrB,OAAO,EAAE,sBAAsB,EAAE,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;IACjE,CAAC;IAED,iCAAiC;IAC1B,MAAM,CAAC,MAAM,CAAC,MAEpB;QACC,OAAO,IAAA,kBAAO,EAAC,IAAI,yBAAyB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,QAAQ,CAAC,KAAqB;QACzC,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,IAAA,eAAI,EAAC,yCAAiC,CAAC,CAAC;QACjD,CAAC;QACD,MAAM,OAAO,GAA6B,IAAI,CAAC,QAAQ,CAAC;QACxD,4EAA4E;QAC5E,uEAAuE;QACvE,gEAAgE;QAChE,MAAM,QAAQ,GAAyB,MAAM,yBAAyB,CAAC,YAAY,CACjF,iBAAiB,EACjB,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CACzC,CAAC;QACF,IAAI,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;YACzB,OAAO,IAAA,eAAI,EAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,yBAAyB,CAAC,YAAY,CAAC,gBAAgB,EAAE,GAAG,EAAE,WACnE,OAAA,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAA,KAAK,CAAC,IAAI,mCAAI,EAAE,EAAE,KAAK,CAAC,YAAY,CAAC,CAAA,EAAA,CAClF,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACK,MAAM,CAAC,KAAK,CAAC,YAAY,CAAI,KAAa,EAAE,EAA4B;QAC9E,IAAI,CAAC;YACH,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,oBAAoB,KAAK,YAAY,GAAG,EAAE,CAAC,CAAC;QAC3F,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAA,eAAI,EAAC,oBAAoB,KAAK,YAAY,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;CACF;AAvDD,8DAuDC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, fail, succeed } from '@fgv/ts-utils';\nimport { IFragmentVectorIndex, IVectorQueryHit } from '../vector';\nimport { QueryEmbedder } from './semanticRetriever';\n\n/**\n * The loud-degradation message a {@link FragmentSemanticRetriever} returns when a\n * fragment query is issued but no {@link IFragmentSemanticBackend | backend} is\n * wired — the discovery surface NEVER answers a fragment query with a silent empty.\n * @public\n */\nexport const FRAGMENT_SEMANTIC_UNWIRED_MESSAGE: string =\n 'fragment recall: no fragment index is wired; wire an IFragmentSemanticBackend to enable sub-document search';\n\n/**\n * The fragment backend wired into a {@link FragmentSemanticRetriever}: the fragment\n * index to query and the embedder that turns the query text into a vector. Both are\n * required together — a fragment index is useless without a way to embed the query.\n * @public\n */\nexport interface IFragmentSemanticBackend {\n /** The fragment-granular vector index to query. */\n readonly fragmentIndex: IFragmentVectorIndex;\n /** Turns the query text into a vector. */\n readonly embedQuery: QueryEmbedder;\n}\n\n/**\n * A sub-document semantic-search request: the natural-language `semantic` text to\n * match, an optional `topK` result cap (default 10), and an optional\n * `maxPerRecord` cap that keeps one long document from monopolizing the result.\n * @public\n */\nexport interface IFragmentQuery {\n /** The natural-language text to embed and match against stored fragments. */\n readonly semantic: string;\n /** Maximum number of fragment hits to return. Defaults to 10. */\n readonly topK?: number;\n /**\n * Maximum number of fragments any single record may contribute to the result.\n * Applied during selection (before the `topK` cut). Omit for uncapped.\n */\n readonly maxPerRecord?: number;\n}\n\n/**\n * What a {@link FragmentSemanticRetriever} can do given its wiring.\n * @public\n */\nexport interface IFragmentRetrieverCapabilities {\n /** `true` when a fragment backend is wired and fragment recall is operational. */\n readonly supportsFragmentRecall: boolean;\n}\n\n/**\n * The sub-document semantic-search retriever — the \"discovery\" half of a\n * search-then-read contract. It embeds a fragment query, queries the\n * {@link IFragmentVectorIndex}, and returns the raw per-fragment\n * {@link IVectorQueryHit | hits} (each carrying a record `target` AND the matched\n * `locator`), NOT resolved records: the consumer re-reads each record and slices it\n * by the locator on its own read side.\n *\n * @remarks\n * Deliberately NOT an {@link IMemoryRetriever}: memory recall is record-granular and\n * returns records; fragment discovery is span-granular and returns locators. Keeping\n * it a distinct surface matches the consumer contract (memory stays record-granular;\n * sub-document knowledge uses a separate fragment index) and avoids overloading the\n * record retriever's return type with a locator that only makes sense here.\n *\n * When no backend is wired, `supportsFragmentRecall` is `false` and any fragment\n * query degrades loudly ({@link FRAGMENT_SEMANTIC_UNWIRED_MESSAGE}) — it NEVER\n * returns a silent empty. A consumer-supplied backend that rejects (throws) is\n * normalized into a `Failure`.\n * @public\n */\nexport class FragmentSemanticRetriever {\n private readonly _backend: IFragmentSemanticBackend | undefined;\n\n private constructor(backend: IFragmentSemanticBackend | undefined) {\n this._backend = backend;\n }\n\n /** What this retriever can do given its wiring. */\n public get capabilities(): IFragmentRetrieverCapabilities {\n return { supportsFragmentRecall: this._backend !== undefined };\n }\n\n /** Family-convention factory. */\n public static create(params: {\n readonly backend?: IFragmentSemanticBackend;\n }): Result<FragmentSemanticRetriever> {\n return succeed(new FragmentSemanticRetriever(params.backend));\n }\n\n /**\n * Embed `query.semantic`, query the fragment index, and return the per-fragment\n * hits in descending score order. Fails loudly when no backend is wired.\n */\n public async retrieve(query: IFragmentQuery): Promise<Result<ReadonlyArray<IVectorQueryHit>>> {\n if (this._backend === undefined) {\n return fail(FRAGMENT_SEMANTIC_UNWIRED_MESSAGE);\n }\n const backend: IFragmentSemanticBackend = this._backend;\n // Consumer-supplied hooks may throw; normalize both a returned `fail` and a\n // rejection into a single `fragment recall: <label> failed` Failure so\n // `retrieve` always honors its `Promise<Result<...>>` contract.\n const embedded: Result<Float32Array> = await FragmentSemanticRetriever._callBackend(\n 'query embedding',\n () => backend.embedQuery(query.semantic)\n );\n if (embedded.isFailure()) {\n return fail(embedded.message);\n }\n return FragmentSemanticRetriever._callBackend('fragment query', () =>\n backend.fragmentIndex.query(embedded.value, query.topK ?? 10, query.maxPerRecord)\n );\n }\n\n /**\n * Invoke a consumer-supplied backend hook, normalizing both a returned `fail`\n * and a thrown/rejected promise into a single `fragment recall: <label> failed`\n * `Failure`.\n */\n private static async _callBackend<T>(label: string, op: () => Promise<Result<T>>): Promise<Result<T>> {\n try {\n return (await op()).withErrorFormat((msg) => `fragment recall: ${label} failed: ${msg}`);\n } catch (err) {\n return fail(`fragment recall: ${label} failed: ${String(err)}`);\n }\n }\n}\n"]}
@@ -4,6 +4,7 @@ export * from './linkTraversalRetriever';
4
4
  export * from './tagRetriever';
5
5
  export * from './structuredFilterRetriever';
6
6
  export * from './semanticRetriever';
7
+ export * from './fragmentSemanticRetriever';
7
8
  export * from './temporalRetrievers';
8
9
  export * from './hybridRetriever';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/retrieve/index.ts"],"names":[],"mappings":"AAKA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/retrieve/index.ts"],"names":[],"mappings":"AAKA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC"}
@@ -24,6 +24,7 @@ __exportStar(require("./linkTraversalRetriever"), exports);
24
24
  __exportStar(require("./tagRetriever"), exports);
25
25
  __exportStar(require("./structuredFilterRetriever"), exports);
26
26
  __exportStar(require("./semanticRetriever"), exports);
27
+ __exportStar(require("./fragmentSemanticRetriever"), exports);
27
28
  __exportStar(require("./temporalRetrievers"), exports);
28
29
  __exportStar(require("./hybridRetriever"), exports);
29
30
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;AAEH,8CAA4B;AAC5B,qDAAmC;AACnC,2DAAyC;AACzC,iDAA+B;AAC/B,8DAA4C;AAC5C,sDAAoC;AACpC,uDAAqC;AACrC,oDAAkC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './retriever';\nexport * from './recencyRetriever';\nexport * from './linkTraversalRetriever';\nexport * from './tagRetriever';\nexport * from './structuredFilterRetriever';\nexport * from './semanticRetriever';\nexport * from './temporalRetrievers';\nexport * from './hybridRetriever';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;AAEH,8CAA4B;AAC5B,qDAAmC;AACnC,2DAAyC;AACzC,iDAA+B;AAC/B,8DAA4C;AAC5C,sDAAoC;AACpC,8DAA4C;AAC5C,uDAAqC;AACrC,oDAAkC","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './retriever';\nexport * from './recencyRetriever';\nexport * from './linkTraversalRetriever';\nexport * from './tagRetriever';\nexport * from './structuredFilterRetriever';\nexport * from './semanticRetriever';\nexport * from './fragmentSemanticRetriever';\nexport * from './temporalRetrievers';\nexport * from './hybridRetriever';\n"]}
@@ -3,7 +3,7 @@ import { FileTree } from '@fgv/ts-json-base';
3
3
  import { EntityId, IIdentityCodec, IMemoryRecord, IWritePolicy, Kind, MemoryId, MemoryScopeKey, RankProjector, Tag } from '../types';
4
4
  import { IBodyConverterRegistry as IRegistry } from '../converters';
5
5
  import { IMemoryObserver } from '../observe';
6
- import { IMemoryRecordSource, IScopedMemoryRecord, IVectorIndex, MemoryEmbedder } from '../vector';
6
+ import { FragmentEmbedder, IFragmentVectorIndex, IMemoryRecordSource, IScopedMemoryRecord, IVectorIndex, MemoryEmbedder } from '../vector';
7
7
  /**
8
8
  * Filter for {@link IMemoryStore.list}. All present fields are ANDed together.
9
9
  * @public
@@ -22,6 +22,37 @@ export interface IMemoryStoreListFilter {
22
22
  */
23
23
  readonly asOf?: number;
24
24
  }
25
+ /**
26
+ * Policy for how {@link FileTreeMemoryStore.create}'s initial vault walk reacts
27
+ * to a record that fails to parse or validate.
28
+ *
29
+ * - `'fail'` (the default) — one unreadable record fails the whole open. The
30
+ * walk collapses per-record results with `mapResults`, so any single failure
31
+ * aborts `create()`. This is the historical behavior, preserved byte-for-byte.
32
+ * - `'skip'` — an unreadable record is quarantined (not indexed) rather than
33
+ * failing the open. Every record that DOES parse loads normally; each skip is
34
+ * logged at `warn` and surfaced structurally on
35
+ * {@link FileTreeMemoryStore.skippedRecords}. The offending file is never
36
+ * deleted or mutated, so a later open (after the body converter is fixed)
37
+ * re-indexes it. A vault holds every kind in one store, so a required-field
38
+ * migration on one kind must not make every other record unreadable.
39
+ * @public
40
+ */
41
+ export type MemoryRecordErrorMode = 'skip' | 'fail';
42
+ /**
43
+ * A record that {@link FileTreeMemoryStore.create} could not load and
44
+ * quarantined (only produced in {@link MemoryRecordErrorMode | `'skip'` mode}).
45
+ * The `path` identifies WHICH record was skipped so a host can repair it.
46
+ * @public
47
+ */
48
+ export interface ISkippedRecord {
49
+ /** The record file's path within the vault (`<scope>/<filename>.md`). */
50
+ readonly path: string;
51
+ /** The scope the record lives under (its parent directory path). */
52
+ readonly scope: MemoryScopeKey;
53
+ /** The parse/validation failure message (includes the record path). */
54
+ readonly error: string;
55
+ }
25
56
  /**
26
57
  * The writable, FileTree-backed, content-hash-deduped memory store.
27
58
  * @public
@@ -149,6 +180,41 @@ export interface IFileTreeMemoryStoreCreateParams {
149
180
  * `rebuild` reconciles, so a vector failure never fails an authoritative write.
150
181
  */
151
182
  readonly embed?: MemoryEmbedder;
183
+ /**
184
+ * Optional fragment-granular vector index for sub-document semantic search.
185
+ * Wired together with
186
+ * {@link IFileTreeMemoryStoreCreateParams.fragmentEmbedder | fragmentEmbedder}:
187
+ * when both are present the store chunks + embeds each written record and
188
+ * maintains the fragment index on `put` / `delete` / cap-cull eviction — the
189
+ * "discovery" half of a search-then-read contract, queried through a
190
+ * {@link FragmentSemanticRetriever}. Independent of the record-granular
191
+ * {@link IFileTreeMemoryStoreCreateParams.vectorIndex | vectorIndex} pair: a
192
+ * store may wire record vectors, fragment vectors, both, or neither. Absent (or
193
+ * `fragmentEmbedder` absent) → no fragment work happens and the store behaves
194
+ * byte-identically (the additive, zero-overhead-when-unwired default).
195
+ */
196
+ readonly fragmentIndex?: IFragmentVectorIndex;
197
+ /**
198
+ * Optional fragment embedder applied to each record on write, wired together
199
+ * with {@link IFileTreeMemoryStoreCreateParams.fragmentIndex | fragmentIndex}.
200
+ * The consumer owns the chunking policy (window size, overlap) and the embedding
201
+ * call; the store stays chunking- and embedder-agnostic. Fragment index
202
+ * maintenance is **best-effort**, exactly like the record-vector path: a failed
203
+ * (or throwing) `fragmentEmbedder` / `addFragments` / `remove` is logged at
204
+ * `warn` and the record operation still succeeds — the fragment index is a
205
+ * derived view a later `rebuild` reconciles.
206
+ */
207
+ readonly fragmentEmbedder?: FragmentEmbedder;
208
+ /**
209
+ * How the initial vault walk reacts to a record that fails to parse or
210
+ * validate. Defaults to `'fail'` — one bad record fails the whole open, the
211
+ * historical behavior, preserved byte-for-byte. Set `'skip'` to quarantine
212
+ * unreadable records instead: valid records still load, each skip is logged
213
+ * at `warn` and surfaced on {@link FileTreeMemoryStore.skippedRecords}, and
214
+ * the offending file is left untouched for a later (post-fix) re-index. See
215
+ * {@link MemoryRecordErrorMode}.
216
+ */
217
+ readonly onRecordError?: MemoryRecordErrorMode;
152
218
  }
153
219
  /**
154
220
  * Flat-layout, FileTree-backed {@link IMemoryStore}. The FileTree is the source
@@ -180,6 +246,13 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
180
246
  private readonly _logger;
181
247
  private readonly _vectorIndex;
182
248
  private readonly _embed;
249
+ private readonly _fragmentIndex;
250
+ private readonly _fragmentEmbedder;
251
+ /**
252
+ * Records the initial walk could not load. Populated during `create()` in
253
+ * {@link MemoryRecordErrorMode | `'skip'` mode}; empty otherwise.
254
+ */
255
+ private readonly _skippedRecords;
183
256
  /** Monotonic write counter; incremented inside the write-lock on each put. */
184
257
  private _seq;
185
258
  /**
@@ -200,6 +273,15 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
200
273
  */
201
274
  private static readonly _mutableFieldAccessors;
202
275
  private constructor();
276
+ /**
277
+ * Records the initial vault walk could not parse or validate and quarantined
278
+ * (not indexed). Non-empty only when the store was opened with
279
+ * {@link MemoryRecordErrorMode | `onRecordError: 'skip'`} AND at least one
280
+ * record failed to load. Each entry identifies the offending file so a host
281
+ * can repair it; the file itself is never deleted or mutated, so a later open
282
+ * (after the body converter is fixed) re-indexes it.
283
+ */
284
+ get skippedRecords(): ReadonlyArray<ISkippedRecord>;
203
285
  /**
204
286
  * Family-convention factory. Builds the derived index and a default LWW
205
287
  * policy, then performs an initial FileTree walk so an existing vault is
@@ -287,6 +369,26 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
287
369
  * failure).
288
370
  */
289
371
  private _embedOnWrite;
372
+ /**
373
+ * Best-effort fragment-embed-on-write. When a fragment index AND a fragment
374
+ * embedder are wired, chunks + embeds the built record and replaces its
375
+ * fragments in the index (`addFragments` is whole-record-replace, so a re-authored
376
+ * document never leaves stale fragments behind — no explicit remove needed). A
377
+ * failure (returned `fail` OR a thrown/rejected hook) is logged and the record is
378
+ * returned unchanged — the put still persists, and the fragment index is a derived
379
+ * view a later `rebuild` reconciles. Unlike {@link FileTreeMemoryStore._embedOnWrite}
380
+ * it stamps nothing on the record (fragments have no per-record `embeddingRef`
381
+ * analog). A pass-through no-op when unwired (byte-identical record).
382
+ */
383
+ private _embedFragmentsOnWrite;
384
+ /**
385
+ * Best-effort fragment removal. A no-op unless the full fragment lifecycle is
386
+ * wired (both an index AND an embedder), so an unwired store does no fragment
387
+ * work and behaves byte-identically. Failures are logged, never surfaced — a
388
+ * committed delete/eviction must not fail because a derived fragment index could
389
+ * not be pruned.
390
+ */
391
+ private _removeFragmentsBestEffort;
290
392
  /**
291
393
  * Evict the records named by a `cull-oldest` decision, best-effort. Runs only
292
394
  * after the authoritative `_persist`, so a failed eviction is logged (never
@@ -482,9 +584,21 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
482
584
  /**
483
585
  * Walk the FileTree once and rebuild the index. Also resumes the `seq`
484
586
  * counter past the highest persisted `seq` so new writes stay monotonic.
587
+ *
588
+ * In `'skip'` mode each per-record failure is captured structurally on
589
+ * `this._skippedRecords` (path + scope + path-tagged error) at its failure
590
+ * site and logged at `warn`; the walk keeps every record that loaded.
485
591
  */
486
592
  private _initialIndex;
487
593
  /** Recursively collect every `.md` record under `dir` (scope = path segments). */
488
594
  private _collectEntries;
595
+ /**
596
+ * Load and verify one record file. On failure in `'skip'` mode, records the
597
+ * structured {@link ISkippedRecord} identity (path + scope + path-tagged
598
+ * error) and logs the skip at `warn`; the failure is still returned so the
599
+ * caller's `mapSuccess` drops it from the loaded set. In `'fail'` mode the
600
+ * failure passes through untouched so the historical error is byte-identical.
601
+ */
602
+ private _loadRecordFile;
489
603
  }
490
604
  //# sourceMappingURL=fileTreeMemoryStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fileTreeMemoryStore.d.ts","sourceRoot":"","sources":["../../../src/packlets/store/fileTreeMemoryStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fileTreeMemoryStore.d.ts","sourceRoot":"","sources":["../../../src/packlets/store/fileTreeMemoryStore.ts"],"names":[],"mappings":"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"}
@@ -44,10 +44,24 @@ class FileTreeMemoryStore {
44
44
  this._logger = params.logger;
45
45
  this._vectorIndex = params.vectorIndex;
46
46
  this._embed = params.embed;
47
+ this._fragmentIndex = params.fragmentIndex;
48
+ this._fragmentEmbedder = params.fragmentEmbedder;
49
+ this._skippedRecords = [];
47
50
  this._seq = 0;
48
51
  this._observationSeq = 0;
49
52
  this._writeTail = Promise.resolve();
50
53
  }
54
+ /**
55
+ * Records the initial vault walk could not parse or validate and quarantined
56
+ * (not indexed). Non-empty only when the store was opened with
57
+ * {@link MemoryRecordErrorMode | `onRecordError: 'skip'`} AND at least one
58
+ * record failed to load. Each entry identifies the offending file so a host
59
+ * can repair it; the file itself is never deleted or mutated, so a later open
60
+ * (after the body converter is fixed) re-indexes it.
61
+ */
62
+ get skippedRecords() {
63
+ return this._skippedRecords;
64
+ }
51
65
  /**
52
66
  * Family-convention factory. Builds the derived index and a default LWW
53
67
  * policy, then performs an initial FileTree walk so an existing vault is
@@ -55,7 +69,7 @@ class FileTreeMemoryStore {
55
69
  */
56
70
  static create(params) {
57
71
  return types_1.KnowledgeLwwPolicy.create().onSuccess((defaultPolicy) => index_1.MemoryIndex.create().onSuccess((index) => {
58
- var _a, _b, _c, _d, _e, _f, _g;
72
+ var _a, _b, _c, _d, _e, _f, _g, _h;
59
73
  const store = new FileTreeMemoryStore({
60
74
  root: params.root,
61
75
  registry: params.registry,
@@ -70,9 +84,11 @@ class FileTreeMemoryStore {
70
84
  observers: (_f = params.observers) !== null && _f !== void 0 ? _f : [],
71
85
  logger: (_g = params.logger) !== null && _g !== void 0 ? _g : new ts_utils_1.Logging.NoOpLogger(),
72
86
  vectorIndex: params.vectorIndex,
73
- embed: params.embed
87
+ embed: params.embed,
88
+ fragmentIndex: params.fragmentIndex,
89
+ fragmentEmbedder: params.fragmentEmbedder
74
90
  });
75
- return store._initialIndex().onSuccess(() => (0, ts_utils_1.succeed)(store));
91
+ return store._initialIndex((_h = params.onRecordError) !== null && _h !== void 0 ? _h : 'fail').onSuccess(() => (0, ts_utils_1.succeed)(store));
76
92
  }));
77
93
  }
78
94
  /** {@inheritDoc IMemoryStore.get} */
@@ -389,6 +405,7 @@ class FileTreeMemoryStore {
389
405
  return this._buildRecord(record, body, existing, policy, hash)
390
406
  .onSuccess((built) => (0, ts_utils_1.succeed)(this._stampRank(built)))
391
407
  .thenOnSuccess((built) => this._embedOnWrite(built, scope))
408
+ .thenOnSuccess((built) => this._embedFragmentsOnWrite(built, scope))
392
409
  .onSuccess((embeddedBuilt) => this._persist(embeddedBuilt, scope, idStem))
393
410
  .thenOnSuccess(async (persisted) => {
394
411
  // Everything after the authoritative `_persist` commit is best-effort and
@@ -431,6 +448,45 @@ class FileTreeMemoryStore {
431
448
  }
432
449
  return (0, ts_utils_1.succeed)({ envelope: Object.assign(Object.assign({}, built.envelope), { embeddingRef: added.value }), body: built.body });
433
450
  }
451
+ /**
452
+ * Best-effort fragment-embed-on-write. When a fragment index AND a fragment
453
+ * embedder are wired, chunks + embeds the built record and replaces its
454
+ * fragments in the index (`addFragments` is whole-record-replace, so a re-authored
455
+ * document never leaves stale fragments behind — no explicit remove needed). A
456
+ * failure (returned `fail` OR a thrown/rejected hook) is logged and the record is
457
+ * returned unchanged — the put still persists, and the fragment index is a derived
458
+ * view a later `rebuild` reconciles. Unlike {@link FileTreeMemoryStore._embedOnWrite}
459
+ * it stamps nothing on the record (fragments have no per-record `embeddingRef`
460
+ * analog). A pass-through no-op when unwired (byte-identical record).
461
+ */
462
+ async _embedFragmentsOnWrite(built, scope) {
463
+ if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {
464
+ return (0, ts_utils_1.succeed)(built);
465
+ }
466
+ const fragmentIndex = this._fragmentIndex;
467
+ const fragmentEmbedder = this._fragmentEmbedder;
468
+ const target = { scope, id: built.envelope.id };
469
+ const embedded = await this._tryVectorOp(() => fragmentEmbedder(built), `fragment embedding '${built.envelope.id}'`);
470
+ if (embedded.isFailure()) {
471
+ return (0, ts_utils_1.succeed)(built);
472
+ }
473
+ await this._tryVectorOp(() => fragmentIndex.addFragments(target, embedded.value), `fragment add for '${built.envelope.id}'`);
474
+ return (0, ts_utils_1.succeed)(built);
475
+ }
476
+ /**
477
+ * Best-effort fragment removal. A no-op unless the full fragment lifecycle is
478
+ * wired (both an index AND an embedder), so an unwired store does no fragment
479
+ * work and behaves byte-identically. Failures are logged, never surfaced — a
480
+ * committed delete/eviction must not fail because a derived fragment index could
481
+ * not be pruned.
482
+ */
483
+ async _removeFragmentsBestEffort(target) {
484
+ if (this._fragmentIndex === undefined || this._fragmentEmbedder === undefined) {
485
+ return;
486
+ }
487
+ const fragmentIndex = this._fragmentIndex;
488
+ await this._tryVectorOp(() => fragmentIndex.remove(target), `fragment removal for '${target.id}'`);
489
+ }
434
490
  /**
435
491
  * Evict the records named by a `cull-oldest` decision, best-effort. Runs only
436
492
  * after the authoritative `_persist`, so a failed eviction is logged (never
@@ -463,6 +519,7 @@ class FileTreeMemoryStore {
463
519
  async _removeEvictedVectors(evicted, scope) {
464
520
  for (const id of evicted) {
465
521
  await this._removeVectorBestEffort({ scope, id });
522
+ await this._removeFragmentsBestEffort({ scope, id });
466
523
  }
467
524
  }
468
525
  /**
@@ -479,7 +536,7 @@ class FileTreeMemoryStore {
479
536
  result = (0, ts_utils_1.fail)(`${label} threw: ${String(err)}`);
480
537
  }
481
538
  if (result.isFailure()) {
482
- this._warnSwallowed(`memory: ${label} failed (best-effort; vector index left for rebuild): ${result.message}`);
539
+ this._warnSwallowed(`memory: ${label} failed (best-effort; derived index left for rebuild): ${result.message}`);
483
540
  }
484
541
  return result;
485
542
  }
@@ -566,6 +623,7 @@ class FileTreeMemoryStore {
566
623
  .onSuccess(() => this._index.patch('delete', { scope, record: existing }))
567
624
  .thenOnSuccess(async () => {
568
625
  await this._removeVectorBestEffort({ scope, id: existing.envelope.id });
626
+ await this._removeFragmentsBestEffort({ scope, id: existing.envelope.id });
569
627
  return (0, ts_utils_1.succeed)(existing.envelope.id);
570
628
  });
571
629
  });
@@ -652,6 +710,7 @@ class FileTreeMemoryStore {
652
710
  .thenOnSuccess((versionStem) => this._buildVersionedRecord(record, body, current, policy, hash, versionStem, validAt, now, seq)
653
711
  .onSuccess((built) => (0, ts_utils_1.succeed)(this._stampRank(built)))
654
712
  .thenOnSuccess((built) => this._embedOnWrite(built, scope))
713
+ .thenOnSuccess((built) => this._embedFragmentsOnWrite(built, scope))
655
714
  .onSuccess((embeddedBuilt) => this._persist(embeddedBuilt, scope, versionStem))
656
715
  .onSuccess((persisted) => this._invalidateCurrents(scope, priorCurrents, validAt, now).onSuccess(() => (0, ts_utils_1.succeed)(persisted)))
657
716
  .onSuccess((persisted) => (0, ts_utils_1.succeed)({ record: persisted, evicted: [] })));
@@ -988,9 +1047,13 @@ class FileTreeMemoryStore {
988
1047
  /**
989
1048
  * Walk the FileTree once and rebuild the index. Also resumes the `seq`
990
1049
  * counter past the highest persisted `seq` so new writes stay monotonic.
1050
+ *
1051
+ * In `'skip'` mode each per-record failure is captured structurally on
1052
+ * `this._skippedRecords` (path + scope + path-tagged error) at its failure
1053
+ * site and logged at `warn`; the walk keeps every record that loaded.
991
1054
  */
992
- _initialIndex() {
993
- return this._collectEntries(this._root, []).onSuccess((entries) => this._index.rebuild(entries).onSuccess(() => {
1055
+ _initialIndex(onRecordError) {
1056
+ return this._collectEntries(this._root, [], onRecordError).onSuccess((entries) => this._index.rebuild(entries).onSuccess(() => {
994
1057
  for (const entry of entries) {
995
1058
  if (entry.record.envelope.seq > this._seq) {
996
1059
  this._seq = entry.record.envelope.seq;
@@ -1000,11 +1063,11 @@ class FileTreeMemoryStore {
1000
1063
  }));
1001
1064
  }
1002
1065
  /** Recursively collect every `.md` record under `dir` (scope = path segments). */
1003
- _collectEntries(dir, scopeSegments) {
1066
+ _collectEntries(dir, scopeSegments, onRecordError) {
1004
1067
  return dir.getChildren().onSuccess((children) => {
1005
1068
  const results = children.map((child) => {
1006
1069
  if (child.type === 'directory') {
1007
- return this._collectEntries(child, [...scopeSegments, child.name]);
1070
+ return this._collectEntries(child, [...scopeSegments, child.name], onRecordError);
1008
1071
  }
1009
1072
  if (!child.name.endsWith(MEMORY_FILE_EXTENSION) || scopeSegments.length === 0) {
1010
1073
  // Skip non-record files and any record-shaped file sitting at the root
@@ -1012,15 +1075,43 @@ class FileTreeMemoryStore {
1012
1075
  return (0, ts_utils_1.succeed)([]);
1013
1076
  }
1014
1077
  const scope = scopeSegments.join('/');
1015
- return child
1016
- .getRawContents()
1017
- .onSuccess((raw) => (0, converters_1.parseMemoryFile)(raw, this._registry))
1018
- .onSuccess((parsedRecord) => this._verifyLoaded(scope, child, parsedRecord))
1019
- .onSuccess((verified) => (0, ts_utils_1.succeed)([{ scope, record: verified }]));
1078
+ return this._loadRecordFile(scope, child, onRecordError);
1020
1079
  });
1080
+ // `'skip'` mode: keep every record that parsed, drop the ones that failed
1081
+ // in a single pass (each failure is captured on `this._skippedRecords` and
1082
+ // warn-logged at its site in `_loadRecordFile`). `.orDefault([])` covers
1083
+ // the all-invalid-subtree edge where `mapSuccess` returns Failure because
1084
+ // no element succeeded. `'fail'` mode: `mapResults` fails the whole open on
1085
+ // any bad record — byte-identical to the historical load path.
1086
+ if (onRecordError === 'skip') {
1087
+ return (0, ts_utils_1.succeed)((0, ts_utils_1.mapSuccess)(results).orDefault([]).flat());
1088
+ }
1021
1089
  return (0, ts_utils_1.mapResults)(results).onSuccess((perChild) => (0, ts_utils_1.succeed)(perChild.flat()));
1022
1090
  });
1023
1091
  }
1092
+ /**
1093
+ * Load and verify one record file. On failure in `'skip'` mode, records the
1094
+ * structured {@link ISkippedRecord} identity (path + scope + path-tagged
1095
+ * error) and logs the skip at `warn`; the failure is still returned so the
1096
+ * caller's `mapSuccess` drops it from the loaded set. In `'fail'` mode the
1097
+ * failure passes through untouched so the historical error is byte-identical.
1098
+ */
1099
+ _loadRecordFile(scope, child, onRecordError) {
1100
+ return child
1101
+ .getRawContents()
1102
+ .onSuccess((raw) => (0, converters_1.parseMemoryFile)(raw, this._registry))
1103
+ .onSuccess((parsedRecord) => this._verifyLoaded(scope, child, parsedRecord))
1104
+ .onSuccess((verified) => (0, ts_utils_1.succeed)([{ scope, record: verified }]))
1105
+ .onFailure((message) => {
1106
+ if (onRecordError === 'skip') {
1107
+ const path = `${scope}/${child.name}`;
1108
+ const error = `memory record '${path}': ${message}`;
1109
+ this._skippedRecords.push({ path, scope, error });
1110
+ this._warnSwallowed(error);
1111
+ }
1112
+ return (0, ts_utils_1.fail)(message);
1113
+ });
1114
+ }
1024
1115
  }
1025
1116
  exports.FileTreeMemoryStore = FileTreeMemoryStore;
1026
1117
  /**