@fgv/ts-agent-memory 5.1.0-45 → 5.1.0-47
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/{bc5b0f2098f7df2a5c498ea77b0de13316349b96.tar.log → 5667e36f1c0cc503a5c20a3ebff76e7b9a702d41.tar.log} +26 -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/README.md +134 -4
- package/dist/packlets/ingest/orchestrator.js +104 -19
- package/dist/packlets/ingest/orchestrator.js.map +1 -1
- package/dist/packlets/retrieve/fragmentSemanticRetriever.js +10 -7
- package/dist/packlets/retrieve/fragmentSemanticRetriever.js.map +1 -1
- package/dist/packlets/store/fileTreeMemoryStore.js +31 -8
- package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/dist/packlets/types/writePolicy.js +10 -2
- package/dist/packlets/types/writePolicy.js.map +1 -1
- package/dist/packlets/vector/fragmentConverters.js +41 -0
- package/dist/packlets/vector/fragmentConverters.js.map +1 -0
- package/dist/packlets/vector/inMemoryFragmentCosineIndex.js +17 -9
- package/dist/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
- 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/ingest/dedupScope.test.js +434 -0
- package/dist/test/unit/ingest/dedupScope.test.js.map +1 -0
- package/dist/test/unit/ingest/orchestrator.test.js +7 -4
- package/dist/test/unit/ingest/orchestrator.test.js.map +1 -1
- package/dist/test/unit/store/fileTreeMemoryStore.test.js +64 -0
- package/dist/test/unit/store/fileTreeMemoryStore.test.js.map +1 -1
- package/dist/test/unit/store/indexInjection.test.js +432 -0
- package/dist/test/unit/store/indexInjection.test.js.map +1 -0
- package/dist/test/unit/tools/memoryTools.test.js +1 -0
- package/dist/test/unit/tools/memoryTools.test.js.map +1 -1
- package/dist/test/unit/types/temporalPolicy.test.js +21 -0
- package/dist/test/unit/types/temporalPolicy.test.js.map +1 -1
- package/dist/test/unit/types/writePolicy.test.js +83 -0
- package/dist/test/unit/types/writePolicy.test.js.map +1 -1
- package/dist/test/unit/vector/fragmentConverters.test.js +58 -0
- package/dist/test/unit/vector/fragmentConverters.test.js.map +1 -0
- package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js +65 -0
- package/dist/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +1 -1
- package/dist/ts-agent-memory.d.ts +332 -42
- package/etc/ts-agent-memory.api.md +12 -1
- package/lib/packlets/ingest/orchestrator.d.ts +62 -5
- package/lib/packlets/ingest/orchestrator.d.ts.map +1 -1
- package/lib/packlets/ingest/orchestrator.js +104 -19
- package/lib/packlets/ingest/orchestrator.js.map +1 -1
- package/lib/packlets/retrieve/fragmentSemanticRetriever.d.ts +10 -7
- package/lib/packlets/retrieve/fragmentSemanticRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/fragmentSemanticRetriever.js +10 -7
- package/lib/packlets/retrieve/fragmentSemanticRetriever.js.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.d.ts +96 -4
- package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.js +31 -8
- package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/lib/packlets/types/writePolicy.d.ts +40 -2
- package/lib/packlets/types/writePolicy.d.ts.map +1 -1
- package/lib/packlets/types/writePolicy.js +10 -2
- package/lib/packlets/types/writePolicy.js.map +1 -1
- package/lib/packlets/vector/fragmentConverters.d.ts +25 -0
- package/lib/packlets/vector/fragmentConverters.d.ts.map +1 -0
- package/lib/packlets/vector/fragmentConverters.js +44 -0
- package/lib/packlets/vector/fragmentConverters.js.map +1 -0
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts +5 -3
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts.map +1 -1
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.js +17 -9
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
- 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 +97 -22
- package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
- package/lib/packlets/vector/vectorIndex.js.map +1 -1
- package/lib/test/unit/ingest/dedupScope.test.d.ts +2 -0
- package/lib/test/unit/ingest/dedupScope.test.d.ts.map +1 -0
- package/lib/test/unit/ingest/dedupScope.test.js +436 -0
- package/lib/test/unit/ingest/dedupScope.test.js.map +1 -0
- package/lib/test/unit/ingest/orchestrator.test.js +7 -4
- package/lib/test/unit/ingest/orchestrator.test.js.map +1 -1
- package/lib/test/unit/store/fileTreeMemoryStore.test.js +64 -0
- package/lib/test/unit/store/fileTreeMemoryStore.test.js.map +1 -1
- package/lib/test/unit/store/indexInjection.test.d.ts +2 -0
- package/lib/test/unit/store/indexInjection.test.d.ts.map +1 -0
- package/lib/test/unit/store/indexInjection.test.js +434 -0
- package/lib/test/unit/store/indexInjection.test.js.map +1 -0
- package/lib/test/unit/tools/memoryTools.test.js +1 -0
- package/lib/test/unit/tools/memoryTools.test.js.map +1 -1
- package/lib/test/unit/types/temporalPolicy.test.js +21 -0
- package/lib/test/unit/types/temporalPolicy.test.js.map +1 -1
- package/lib/test/unit/types/writePolicy.test.js +83 -0
- package/lib/test/unit/types/writePolicy.test.js.map +1 -1
- package/lib/test/unit/vector/fragmentConverters.test.d.ts +2 -0
- package/lib/test/unit/vector/fragmentConverters.test.d.ts.map +1 -0
- package/lib/test/unit/vector/fragmentConverters.test.js +60 -0
- package/lib/test/unit/vector/fragmentConverters.test.js.map +1 -0
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js +65 -0
- package/lib/test/unit/vector/inMemoryFragmentCosineIndex.test.js.map +1 -1
- 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/ingest/orchestrator.ts +116 -21
- package/src/packlets/retrieve/fragmentSemanticRetriever.ts +10 -7
- package/src/packlets/store/fileTreeMemoryStore.ts +114 -6
- package/src/packlets/types/writePolicy.ts +40 -2
- package/src/packlets/vector/fragmentConverters.ts +55 -0
- package/src/packlets/vector/inMemoryFragmentCosineIndex.ts +35 -8
- package/src/packlets/vector/index.ts +1 -0
- package/src/packlets/vector/vectorIndex.ts +97 -22
- package/src/test/unit/ingest/dedupScope.test.ts +542 -0
- package/src/test/unit/ingest/orchestrator.test.ts +4 -0
- package/src/test/unit/store/fileTreeMemoryStore.test.ts +75 -0
- package/src/test/unit/store/indexInjection.test.ts +550 -0
- package/src/test/unit/tools/memoryTools.test.ts +1 -0
- package/src/test/unit/types/temporalPolicy.test.ts +28 -0
- package/src/test/unit/types/writePolicy.test.ts +112 -0
- package/src/test/unit/vector/fragmentConverters.test.ts +80 -0
- package/src/test/unit/vector/inMemoryFragmentCosineIndex.test.ts +88 -0
- package/temp/build/lint/_eslint-5eVG3S6w.json +30 -14
- package/temp/build/typescript/ts_8nwakTlr.json +1 -1
- package/temp/ts-agent-memory.api.json +274 -21
- package/temp/ts-agent-memory.api.md +12 -1
|
@@ -1814,6 +1814,43 @@
|
|
|
1814
1814
|
],
|
|
1815
1815
|
"name": "edgeTargetKey"
|
|
1816
1816
|
},
|
|
1817
|
+
{
|
|
1818
|
+
"kind": "Variable",
|
|
1819
|
+
"canonicalReference": "@fgv/ts-agent-memory!embeddedFragmentConverter:var",
|
|
1820
|
+
"docComment": "/**\n * Converter for an {@link IEmbeddedFragment}, and the boundary that enforces the fragment-identifiability invariant: **at least one of `locator` / `fragmentId` must be present.**\n *\n * @remarks\n *\n * The invariant lives here rather than in the type. A conditional-required union (`{ locator; fragmentId? } | { locator?; fragmentId }`) was considered and declined: it costs at every construction site and buys nothing at the read site, where each field reads as `… | undefined` either way. What it must not cost is identifiability — a fragment carrying neither identity cannot be resolved back to anything by a consumer holding the query hit, so it is rejected here.\n *\n * @public\n */\n",
|
|
1821
|
+
"excerptTokens": [
|
|
1822
|
+
{
|
|
1823
|
+
"kind": "Content",
|
|
1824
|
+
"text": "embeddedFragmentConverter: "
|
|
1825
|
+
},
|
|
1826
|
+
{
|
|
1827
|
+
"kind": "Reference",
|
|
1828
|
+
"text": "Converter",
|
|
1829
|
+
"canonicalReference": "@fgv/ts-utils!Converter:interface"
|
|
1830
|
+
},
|
|
1831
|
+
{
|
|
1832
|
+
"kind": "Content",
|
|
1833
|
+
"text": "<"
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
"kind": "Reference",
|
|
1837
|
+
"text": "IEmbeddedFragment",
|
|
1838
|
+
"canonicalReference": "@fgv/ts-agent-memory!IEmbeddedFragment:interface"
|
|
1839
|
+
},
|
|
1840
|
+
{
|
|
1841
|
+
"kind": "Content",
|
|
1842
|
+
"text": ">"
|
|
1843
|
+
}
|
|
1844
|
+
],
|
|
1845
|
+
"fileUrlPath": "src/packlets/vector/fragmentConverters.ts",
|
|
1846
|
+
"isReadonly": true,
|
|
1847
|
+
"releaseTag": "Public",
|
|
1848
|
+
"name": "embeddedFragmentConverter",
|
|
1849
|
+
"variableTypeTokenRange": {
|
|
1850
|
+
"startIndex": 1,
|
|
1851
|
+
"endIndex": 5
|
|
1852
|
+
}
|
|
1853
|
+
},
|
|
1817
1854
|
{
|
|
1818
1855
|
"kind": "TypeAlias",
|
|
1819
1856
|
"canonicalReference": "@fgv/ts-agent-memory!EntityId:type",
|
|
@@ -1979,7 +2016,7 @@
|
|
|
1979
2016
|
{
|
|
1980
2017
|
"kind": "Method",
|
|
1981
2018
|
"canonicalReference": "@fgv/ts-agent-memory!FileTreeMemoryStore.create:member(1)",
|
|
1982
|
-
"docComment": "/**\n * Family-convention factory.
|
|
2019
|
+
"docComment": "/**\n * Family-convention factory. Resolves the derived index (the caller's {@link IFileTreeMemoryStoreCreateParams.index | index} when supplied, a fresh {@link MemoryIndex} otherwise) and a default LWW policy, then performs an initial FileTree walk so an existing vault is indexed (and the `seq` counter resumes past the highest persisted `seq`).\n */\n",
|
|
1983
2020
|
"excerptTokens": [
|
|
1984
2021
|
{
|
|
1985
2022
|
"kind": "Content",
|
|
@@ -2039,6 +2076,56 @@
|
|
|
2039
2076
|
"isAbstract": false,
|
|
2040
2077
|
"name": "create"
|
|
2041
2078
|
},
|
|
2079
|
+
{
|
|
2080
|
+
"kind": "Method",
|
|
2081
|
+
"canonicalReference": "@fgv/ts-agent-memory!FileTreeMemoryStore#dedupScopeFor:member(1)",
|
|
2082
|
+
"docComment": "/**\n * The EFFECTIVE {@link DedupScope} for `kind` — the granularity at which a write for this kind deduplicates against the existing vault.\n *\n * @remarks\n *\n * This is a **read accessor over the store's already-injected write policies**, and it is the single place any caller — the store's own write path included — asks what a kind's dedup granularity is. It resolves the full chain the store applies on write: the kind's registered {@link IWritePolicy}, falling back to the store's default policy, then that policy's {@link IWritePolicy.dedupScope | dedupScope}, falling back to {@link DEFAULT_DEDUP_SCOPE}. Note the store's default policy is a {@link KnowledgeLwwPolicy}, which declares `'content'` — so a kind with NO registered policy resolves to `'content'`, not to `DEFAULT_DEDUP_SCOPE`.\n *\n * It exists so a caller that must agree with the store about dedup granularity — notably the ingest orchestrator's stage-4 layer-1 exact match — can read the declaration through this seam instead of being handed a second copy of the policy map. A second declaration site is precisely the defect this accessor was added to remove.\n *\n * Deliberately synchronous, total, and NOT `Result`-returning: it reads constructor-injected configuration, touches no I/O, and cannot fail (every link in the fallback chain has a total default). It exposes only the scope, never the {@link IWritePolicy} itself, so it can never become a back door for invoking admission or merge logic out of band.\n */\n",
|
|
2083
|
+
"excerptTokens": [
|
|
2084
|
+
{
|
|
2085
|
+
"kind": "Content",
|
|
2086
|
+
"text": "dedupScopeFor(kind: "
|
|
2087
|
+
},
|
|
2088
|
+
{
|
|
2089
|
+
"kind": "Reference",
|
|
2090
|
+
"text": "Kind",
|
|
2091
|
+
"canonicalReference": "@fgv/ts-agent-memory!Kind:type"
|
|
2092
|
+
},
|
|
2093
|
+
{
|
|
2094
|
+
"kind": "Content",
|
|
2095
|
+
"text": "): "
|
|
2096
|
+
},
|
|
2097
|
+
{
|
|
2098
|
+
"kind": "Reference",
|
|
2099
|
+
"text": "DedupScope",
|
|
2100
|
+
"canonicalReference": "@fgv/ts-agent-memory!DedupScope:type"
|
|
2101
|
+
},
|
|
2102
|
+
{
|
|
2103
|
+
"kind": "Content",
|
|
2104
|
+
"text": ";"
|
|
2105
|
+
}
|
|
2106
|
+
],
|
|
2107
|
+
"isStatic": false,
|
|
2108
|
+
"returnTypeTokenRange": {
|
|
2109
|
+
"startIndex": 3,
|
|
2110
|
+
"endIndex": 4
|
|
2111
|
+
},
|
|
2112
|
+
"releaseTag": "Public",
|
|
2113
|
+
"isProtected": false,
|
|
2114
|
+
"overloadIndex": 1,
|
|
2115
|
+
"parameters": [
|
|
2116
|
+
{
|
|
2117
|
+
"parameterName": "kind",
|
|
2118
|
+
"parameterTypeTokenRange": {
|
|
2119
|
+
"startIndex": 1,
|
|
2120
|
+
"endIndex": 2
|
|
2121
|
+
},
|
|
2122
|
+
"isOptional": false
|
|
2123
|
+
}
|
|
2124
|
+
],
|
|
2125
|
+
"isOptional": false,
|
|
2126
|
+
"isAbstract": false,
|
|
2127
|
+
"name": "dedupScopeFor"
|
|
2128
|
+
},
|
|
2042
2129
|
{
|
|
2043
2130
|
"kind": "Method",
|
|
2044
2131
|
"canonicalReference": "@fgv/ts-agent-memory!FileTreeMemoryStore#delete:member(1)",
|
|
@@ -2672,10 +2759,47 @@
|
|
|
2672
2759
|
"endIndex": 12
|
|
2673
2760
|
}
|
|
2674
2761
|
},
|
|
2762
|
+
{
|
|
2763
|
+
"kind": "Variable",
|
|
2764
|
+
"canonicalReference": "@fgv/ts-agent-memory!fragmentLocatorConverter:var",
|
|
2765
|
+
"docComment": "/**\n * Converter for an {@link IFragmentLocator}. Validates the two offsets only — the span's *meaning* (character / byte / token unit) is the consumer's, and the index never interprets it. Note the span is advisory: see {@link IFragmentLocator}.\n *\n * @public\n */\n",
|
|
2766
|
+
"excerptTokens": [
|
|
2767
|
+
{
|
|
2768
|
+
"kind": "Content",
|
|
2769
|
+
"text": "fragmentLocatorConverter: "
|
|
2770
|
+
},
|
|
2771
|
+
{
|
|
2772
|
+
"kind": "Reference",
|
|
2773
|
+
"text": "Converter",
|
|
2774
|
+
"canonicalReference": "@fgv/ts-utils!Converter:interface"
|
|
2775
|
+
},
|
|
2776
|
+
{
|
|
2777
|
+
"kind": "Content",
|
|
2778
|
+
"text": "<"
|
|
2779
|
+
},
|
|
2780
|
+
{
|
|
2781
|
+
"kind": "Reference",
|
|
2782
|
+
"text": "IFragmentLocator",
|
|
2783
|
+
"canonicalReference": "@fgv/ts-agent-memory!IFragmentLocator:interface"
|
|
2784
|
+
},
|
|
2785
|
+
{
|
|
2786
|
+
"kind": "Content",
|
|
2787
|
+
"text": ">"
|
|
2788
|
+
}
|
|
2789
|
+
],
|
|
2790
|
+
"fileUrlPath": "src/packlets/vector/fragmentConverters.ts",
|
|
2791
|
+
"isReadonly": true,
|
|
2792
|
+
"releaseTag": "Public",
|
|
2793
|
+
"name": "fragmentLocatorConverter",
|
|
2794
|
+
"variableTypeTokenRange": {
|
|
2795
|
+
"startIndex": 1,
|
|
2796
|
+
"endIndex": 5
|
|
2797
|
+
}
|
|
2798
|
+
},
|
|
2675
2799
|
{
|
|
2676
2800
|
"kind": "Class",
|
|
2677
2801
|
"canonicalReference": "@fgv/ts-agent-memory!FragmentSemanticRetriever:class",
|
|
2678
|
-
"docComment": "/**\n * The sub-document semantic-search retriever — the \"discovery\" half of a search-then-read contract. It embeds a fragment query, queries the {@link IFragmentVectorIndex}, and returns the raw per-fragment {@link IVectorQueryHit | hits} (each carrying a record `target` AND
|
|
2802
|
+
"docComment": "/**\n * The sub-document semantic-search retriever — the \"discovery\" half of a search-then-read contract. It embeds a fragment query, queries the {@link IFragmentVectorIndex}, and returns the raw per-fragment {@link IVectorQueryHit | hits} (each carrying a record `target` AND whichever of `locator` / `fragmentId` the stored fragment was indexed with), NOT resolved records: the consumer re-reads each record and resolves the fragment on its own read side. Note the `locator` span is advisory — see {@link IFragmentLocator}; it is not a slice guaranteed to reproduce the fragment's text.\n *\n * @remarks\n *\n * Deliberately NOT an {@link IMemoryRetriever}: memory recall is record-granular and returns records; fragment discovery is fragment-granular and returns fragment identities. Keeping it a distinct surface matches the consumer contract (memory stays record-granular; sub-document knowledge uses a separate fragment index) and avoids overloading the record retriever's return type with identity fields that only make sense here.\n *\n * When no backend is wired, `supportsFragmentRecall` is `false` and any fragment query degrades loudly ({@link FRAGMENT_SEMANTIC_UNWIRED_MESSAGE}) — it NEVER returns a silent empty. A consumer-supplied backend that rejects (throws) is normalized into a `Failure`.\n *\n * @public\n */\n",
|
|
2679
2803
|
"excerptTokens": [
|
|
2680
2804
|
{
|
|
2681
2805
|
"kind": "Content",
|
|
@@ -4641,7 +4765,7 @@
|
|
|
4641
4765
|
{
|
|
4642
4766
|
"kind": "Interface",
|
|
4643
4767
|
"canonicalReference": "@fgv/ts-agent-memory!IEmbeddedFragment:interface",
|
|
4644
|
-
"docComment": "/**\n * One embedded fragment of a record: its in-record {@link IFragmentLocator | span} and
|
|
4768
|
+
"docComment": "/**\n * One embedded fragment of a record: the fragment's vector, plus at least one of the two ways to identify it — its advisory in-record {@link IFragmentLocator | span} and/or an opaque consumer-minted {@link IEmbeddedFragment.fragmentId | fragmentId}. Produced by a {@link FragmentEmbedder} and stored via {@link IFragmentVectorIndex.addFragments}.\n *\n * @remarks\n *\n * Both identity fields are optional **in the type**, but the \"at least one\" requirement is real — a fragment carrying neither is unidentifiable at the read side. It is enforced by {@link embeddedFragmentConverter} (and re-checked by the in-package index implementations) rather than by a conditional-required union (`{ locator; fragmentId? } | { locator?; fragmentId }`), which was considered and declined: the union costs at every construction site and buys nothing at the read site, where each field reads as `… | undefined` either way.\n *\n * @public\n */\n",
|
|
4645
4769
|
"excerptTokens": [
|
|
4646
4770
|
{
|
|
4647
4771
|
"kind": "Content",
|
|
@@ -4653,14 +4777,41 @@
|
|
|
4653
4777
|
"name": "IEmbeddedFragment",
|
|
4654
4778
|
"preserveMemberOrder": false,
|
|
4655
4779
|
"members": [
|
|
4780
|
+
{
|
|
4781
|
+
"kind": "PropertySignature",
|
|
4782
|
+
"canonicalReference": "@fgv/ts-agent-memory!IEmbeddedFragment#fragmentId:member",
|
|
4783
|
+
"docComment": "/**\n * An opaque, consumer-minted identity for this fragment, carried verbatim through the index and returned on the corresponding {@link IVectorQueryHit}. The index **never parses it, never filters on it, and never assigns meaning to it** — it is a bytestring, not part of the query path. It exists so a fragment stays identifiable when its text is not re-derivable from the record body.\n *\n * The guarantee is \"we never parse it\", NOT \"we keep it stable\". Because `addFragments` is whole-record-replace, an updated record re-emits its entire fragment set, so **any stability of a fragment id across re-embeds is the consumer's responsibility**, not the index's.\n */\n",
|
|
4784
|
+
"excerptTokens": [
|
|
4785
|
+
{
|
|
4786
|
+
"kind": "Content",
|
|
4787
|
+
"text": "readonly fragmentId?: "
|
|
4788
|
+
},
|
|
4789
|
+
{
|
|
4790
|
+
"kind": "Content",
|
|
4791
|
+
"text": "string"
|
|
4792
|
+
},
|
|
4793
|
+
{
|
|
4794
|
+
"kind": "Content",
|
|
4795
|
+
"text": ";"
|
|
4796
|
+
}
|
|
4797
|
+
],
|
|
4798
|
+
"isReadonly": true,
|
|
4799
|
+
"isOptional": true,
|
|
4800
|
+
"releaseTag": "Public",
|
|
4801
|
+
"name": "fragmentId",
|
|
4802
|
+
"propertyTypeTokenRange": {
|
|
4803
|
+
"startIndex": 1,
|
|
4804
|
+
"endIndex": 2
|
|
4805
|
+
}
|
|
4806
|
+
},
|
|
4656
4807
|
{
|
|
4657
4808
|
"kind": "PropertySignature",
|
|
4658
4809
|
"canonicalReference": "@fgv/ts-agent-memory!IEmbeddedFragment#locator:member",
|
|
4659
|
-
"docComment": "/**\n * The fragment
|
|
4810
|
+
"docComment": "/**\n * The region of the record body this fragment was derived from, when one can be stated honestly. Advisory — see {@link IFragmentLocator}; it is NOT a slice that reproduces the fragment text. Omit it for a fragment with no honest body span (a rewriting segmenter), in which case `fragmentId` must be supplied.\n */\n",
|
|
4660
4811
|
"excerptTokens": [
|
|
4661
4812
|
{
|
|
4662
4813
|
"kind": "Content",
|
|
4663
|
-
"text": "readonly locator
|
|
4814
|
+
"text": "readonly locator?: "
|
|
4664
4815
|
},
|
|
4665
4816
|
{
|
|
4666
4817
|
"kind": "Reference",
|
|
@@ -4673,7 +4824,7 @@
|
|
|
4673
4824
|
}
|
|
4674
4825
|
],
|
|
4675
4826
|
"isReadonly": true,
|
|
4676
|
-
"isOptional":
|
|
4827
|
+
"isOptional": true,
|
|
4677
4828
|
"releaseTag": "Public",
|
|
4678
4829
|
"name": "locator",
|
|
4679
4830
|
"propertyTypeTokenRange": {
|
|
@@ -4684,7 +4835,7 @@
|
|
|
4684
4835
|
{
|
|
4685
4836
|
"kind": "PropertySignature",
|
|
4686
4837
|
"canonicalReference": "@fgv/ts-agent-memory!IEmbeddedFragment#vector:member",
|
|
4687
|
-
"docComment": "/**\n * The embedding vector for
|
|
4838
|
+
"docComment": "/**\n * The embedding vector for this fragment.\n */\n",
|
|
4688
4839
|
"excerptTokens": [
|
|
4689
4840
|
{
|
|
4690
4841
|
"kind": "Content",
|
|
@@ -5251,6 +5402,34 @@
|
|
|
5251
5402
|
"endIndex": 2
|
|
5252
5403
|
}
|
|
5253
5404
|
},
|
|
5405
|
+
{
|
|
5406
|
+
"kind": "PropertySignature",
|
|
5407
|
+
"canonicalReference": "@fgv/ts-agent-memory!IFileTreeMemoryStoreCreateParams#index:member",
|
|
5408
|
+
"docComment": "/**\n * Optional derived-index implementation. Defaults to a fresh {@link MemoryIndex} — omitting this parameter is byte-identical to the store's behavior before the parameter existed. When supplied, the store uses it for EVERY index operation it performs and never holds a second index, so an injected index is the store's only view of its own records:\n *\n * - `rebuild` — once, from the initial vault walk in `create()`. - `patch` — on every persisted write, delete, version invalidation, and cap-cull eviction. - `entries` — behind {@link IMemoryStore.list | list} / {@link IMemoryStore.listScoped | listScoped}, the keyed temporal reads, the write path's content-hash dedup and write-policy admission cohort, AND the temporal (versioned) write and delete paths, which resolve an entity's version history entirely from the index.\n *\n * That last group is the one to weigh before injecting anything other than a pass-through decorator: an index that filters, reorders, or otherwise reshapes `entries()` changes WRITE semantics, not just what reads return. Concretely, on a versioned kind the store derives an entity's whole version history from `entries()` filtered by scope, and that derivation decides which version a `put` treats as current (so what it dedups against and what it merges its patch over), which prior versions it stamps `invalid_at` on, what the admission cohort is, and which versions a `delete` tombstones. An index that hides a version makes it invisible to all of those — the FileTree still holds it, but the store will not supersede, invalidate, or tombstone it. On flat kinds the same reshaping changes what dedups and what a cap-cull policy evicts. A faithful delegating decorator — the intended use below — has no such effect. Note the store's keyed reads ({@link IMemoryStore.get | get} on a flat kind, and {@link IMemoryStore.getById | getById}) go to the FileTree, not the index; the FileTree remains the source of truth and the index stays a derived view.\n *\n * @remarks\n *\n * **This is an instrumentation seam, NOT a resident-memory fix.** The intended use is wrapping the shipped {@link MemoryIndex} in a decorator that counts and times the calls the store makes — resident bytes by kind, open cost against vault size, where the curve actually bends — so a decision about a partial-read redesign can be driven by measurements instead of estimates.\n *\n * It does NOT lower the store's resident-memory ceiling, and injecting a \"persisted\" or \"lazy\" index will not change that. {@link IMemoryIndex}'s read surface returns whole records by construction: `entries()` yields {@link IIndexedMemoryRecord}s and `byKind` / `byTag` / `byRecency` / `byRank` yield `IMemoryRecord<unknown>` — `{ envelope, body }` pairs with the body materialized. Any implementation satisfying the current contract must therefore be able to produce every body on demand. An injected index changes WHERE records come from; it does not change WHETHER bodies are held. Lowering the ceiling requires a partial-read (id-or-envelope-only) redesign of `IMemoryIndex` itself, which is separate, breaking, design-first work and is deliberately not part of this seam.\n */\n",
|
|
5409
|
+
"excerptTokens": [
|
|
5410
|
+
{
|
|
5411
|
+
"kind": "Content",
|
|
5412
|
+
"text": "readonly index?: "
|
|
5413
|
+
},
|
|
5414
|
+
{
|
|
5415
|
+
"kind": "Reference",
|
|
5416
|
+
"text": "IMemoryIndex",
|
|
5417
|
+
"canonicalReference": "@fgv/ts-agent-memory!IMemoryIndex:interface"
|
|
5418
|
+
},
|
|
5419
|
+
{
|
|
5420
|
+
"kind": "Content",
|
|
5421
|
+
"text": ";"
|
|
5422
|
+
}
|
|
5423
|
+
],
|
|
5424
|
+
"isReadonly": true,
|
|
5425
|
+
"isOptional": true,
|
|
5426
|
+
"releaseTag": "Public",
|
|
5427
|
+
"name": "index",
|
|
5428
|
+
"propertyTypeTokenRange": {
|
|
5429
|
+
"startIndex": 1,
|
|
5430
|
+
"endIndex": 2
|
|
5431
|
+
}
|
|
5432
|
+
},
|
|
5254
5433
|
{
|
|
5255
5434
|
"kind": "PropertySignature",
|
|
5256
5435
|
"canonicalReference": "@fgv/ts-agent-memory!IFileTreeMemoryStoreCreateParams#logger:member",
|
|
@@ -5583,7 +5762,7 @@
|
|
|
5583
5762
|
{
|
|
5584
5763
|
"kind": "Interface",
|
|
5585
5764
|
"canonicalReference": "@fgv/ts-agent-memory!IFragmentLocator:interface",
|
|
5586
|
-
"docComment": "/**\n * A half-open `[start, end)` span into a record's body — the in-record locator a {@link IFragmentVectorIndex}
|
|
5765
|
+
"docComment": "/**\n * A half-open `[start, end)` span into a record's body — the in-record locator a {@link IFragmentVectorIndex} may carry on a fragment. `start` is inclusive, `end` exclusive. The unit (character / byte / token offsets) is the consumer's choice: the index stores the two integers opaquely and never interprets them, so they line up with whatever locator the consumer's own read side uses.\n *\n * @remarks\n *\n * **The span is advisory.** It names the region of the body a fragment was *derived from*; it is NOT a slice guaranteed to reproduce the fragment's text. `body.slice(start, end)` round-trips only under a segmenter that merely chooses boundaries. Under a **rewriting** segmenter — one that turns a span into a curated block, an increasingly common ingestion shape when a model both selects and rewrites — the fragment text is not a substring of the body at all, and the fragmentation is not re-derivable from the body. Treat the span as a pointer for locating context, never as an extraction recipe.\n *\n * A fragment whose provenance cannot honestly be expressed as a body span should omit the locator entirely and carry an {@link IEmbeddedFragment.fragmentId} instead.\n *\n * @public\n */\n",
|
|
5587
5766
|
"excerptTokens": [
|
|
5588
5767
|
{
|
|
5589
5768
|
"kind": "Content",
|
|
@@ -5873,7 +6052,7 @@
|
|
|
5873
6052
|
{
|
|
5874
6053
|
"kind": "Interface",
|
|
5875
6054
|
"canonicalReference": "@fgv/ts-agent-memory!IFragmentVectorIndex:interface",
|
|
5876
|
-
"docComment": "/**\n * The fragment-granular sibling of {@link IVectorIndex}: instead of one vector per record it holds many vectors per record, each tagged with
|
|
6055
|
+
"docComment": "/**\n * The fragment-granular sibling of {@link IVectorIndex}: instead of one vector per record it holds many vectors per record, each tagged with the identity its {@link IEmbeddedFragment} carried, and its `query` returns per-fragment hits carrying that identity back. This is the seam behind sub-document semantic search — the \"discovery\" half of a search-then-read contract, where a hit tells the consumer which record AND which fragment of it to read.\n *\n * @remarks\n *\n * Deliberately NOT `extends IVectorIndex`: an index holding many vectors per record has no well-defined single-vector `add(target, vector)`. It is a parallel contract with three operations — `addFragments`, `remove`, `query` — reusing {@link IVectorQueryHit}, on which both `locator` and `fragmentId` are optional. A fragment hit populates whichever of the two its stored fragment carried; see {@link IVectorQueryHit} for why that is not a discriminator and why fragment-ness is determined by the index queried, not by field presence. Kept distinct from the record-granular index per the consumer contract: memory recall stays record-granular; sub-document knowledge uses a separate fragment index.\n *\n * @public\n */\n",
|
|
5877
6056
|
"excerptTokens": [
|
|
5878
6057
|
{
|
|
5879
6058
|
"kind": "Content",
|
|
@@ -5978,7 +6157,7 @@
|
|
|
5978
6157
|
{
|
|
5979
6158
|
"kind": "MethodSignature",
|
|
5980
6159
|
"canonicalReference": "@fgv/ts-agent-memory!IFragmentVectorIndex#query:member(1)",
|
|
5981
|
-
"docComment": "/**\n * Return the `topK` nearest fragments to `vector`, in descending score order, each hit carrying its record `target`
|
|
6160
|
+
"docComment": "/**\n * Return the `topK` nearest fragments to `vector`, in descending score order, each hit carrying its record `target` plus whichever of `locator` / `fragmentId` the stored fragment was added with. When `maxPerRecord` is supplied, no more than that many fragments of any single record appear in the result — the cap is applied during selection (before the `topK` cut) so one long document cannot crowd out others.\n */\n",
|
|
5982
6161
|
"excerptTokens": [
|
|
5983
6162
|
{
|
|
5984
6163
|
"kind": "Content",
|
|
@@ -7050,7 +7229,7 @@
|
|
|
7050
7229
|
{
|
|
7051
7230
|
"kind": "PropertySignature",
|
|
7052
7231
|
"canonicalReference": "@fgv/ts-agent-memory!IMemoryCapCullPolicyParams#mutableFields:member",
|
|
7053
|
-
"docComment": "/**\n * The fields a merge-patch update may touch (drawn from the record-level mutable vocabulary: `body` / `tags` / `links` / `provenance` / `embeddingRef`). Fields outside this list are immutable.\n */\n",
|
|
7232
|
+
"docComment": "/**\n * The fields a merge-patch update may touch (drawn from the record-level mutable vocabulary: `body` / `tags` / `links` / `provenance` / `embeddingRef`). Fields outside this list are immutable.\n *\n * @remarks\n *\n * This list — unlike {@link KnowledgeLwwPolicy}'s pinned surface — is caller-supplied, so it is what decides which fields get the RFC-7386 guarantees documented on {@link IWritePolicy.applyUpdate}. Declare `provenance` here to get per-key provenance merging and `null` sub-key clearing; omit it and every provenance patch key is inert (dropped before the merge, so the existing value is preserved verbatim and even a whole-block `null` is a silent no-op rather than an error).\n */\n",
|
|
7054
7233
|
"excerptTokens": [
|
|
7055
7234
|
{
|
|
7056
7235
|
"kind": "Content",
|
|
@@ -10433,6 +10612,53 @@
|
|
|
10433
10612
|
"parameters": [],
|
|
10434
10613
|
"name": "asRecordSource"
|
|
10435
10614
|
},
|
|
10615
|
+
{
|
|
10616
|
+
"kind": "MethodSignature",
|
|
10617
|
+
"canonicalReference": "@fgv/ts-agent-memory!IMemoryStore#dedupScopeFor:member(1)",
|
|
10618
|
+
"docComment": "/**\n * The EFFECTIVE {@link DedupScope} for `kind` — the granularity at which a write for this kind deduplicates against the existing vault.\n *\n * @remarks\n *\n * This is a **read accessor over the store's already-injected write policies**, and it is the single place any caller — the store's own write path included — asks what a kind's dedup granularity is. It resolves the full chain the store applies on write: the kind's registered {@link IWritePolicy}, falling back to the store's default policy, then that policy's {@link IWritePolicy.dedupScope | dedupScope}, falling back to {@link DEFAULT_DEDUP_SCOPE}. Note the store's default policy is a {@link KnowledgeLwwPolicy}, which declares `'content'` — so a kind with NO registered policy resolves to `'content'`, not to `DEFAULT_DEDUP_SCOPE`.\n *\n * It exists so a caller that must agree with the store about dedup granularity — notably the ingest orchestrator's stage-4 layer-1 exact match — can read the declaration through this seam instead of being handed a second copy of the policy map. A second declaration site is precisely the defect this accessor was added to remove.\n *\n * Deliberately synchronous, total, and NOT `Result`-returning: it reads constructor-injected configuration, touches no I/O, and cannot fail (every link in the fallback chain has a total default). It exposes only the scope, never the {@link IWritePolicy} itself, so it can never become a back door for invoking admission or merge logic out of band.\n */\n",
|
|
10619
|
+
"excerptTokens": [
|
|
10620
|
+
{
|
|
10621
|
+
"kind": "Content",
|
|
10622
|
+
"text": "dedupScopeFor(kind: "
|
|
10623
|
+
},
|
|
10624
|
+
{
|
|
10625
|
+
"kind": "Reference",
|
|
10626
|
+
"text": "Kind",
|
|
10627
|
+
"canonicalReference": "@fgv/ts-agent-memory!Kind:type"
|
|
10628
|
+
},
|
|
10629
|
+
{
|
|
10630
|
+
"kind": "Content",
|
|
10631
|
+
"text": "): "
|
|
10632
|
+
},
|
|
10633
|
+
{
|
|
10634
|
+
"kind": "Reference",
|
|
10635
|
+
"text": "DedupScope",
|
|
10636
|
+
"canonicalReference": "@fgv/ts-agent-memory!DedupScope:type"
|
|
10637
|
+
},
|
|
10638
|
+
{
|
|
10639
|
+
"kind": "Content",
|
|
10640
|
+
"text": ";"
|
|
10641
|
+
}
|
|
10642
|
+
],
|
|
10643
|
+
"isOptional": false,
|
|
10644
|
+
"returnTypeTokenRange": {
|
|
10645
|
+
"startIndex": 3,
|
|
10646
|
+
"endIndex": 4
|
|
10647
|
+
},
|
|
10648
|
+
"releaseTag": "Public",
|
|
10649
|
+
"overloadIndex": 1,
|
|
10650
|
+
"parameters": [
|
|
10651
|
+
{
|
|
10652
|
+
"parameterName": "kind",
|
|
10653
|
+
"parameterTypeTokenRange": {
|
|
10654
|
+
"startIndex": 1,
|
|
10655
|
+
"endIndex": 2
|
|
10656
|
+
},
|
|
10657
|
+
"isOptional": false
|
|
10658
|
+
}
|
|
10659
|
+
],
|
|
10660
|
+
"name": "dedupScopeFor"
|
|
10661
|
+
},
|
|
10436
10662
|
{
|
|
10437
10663
|
"kind": "MethodSignature",
|
|
10438
10664
|
"canonicalReference": "@fgv/ts-agent-memory!IMemoryStore#delete:member(1)",
|
|
@@ -11962,7 +12188,7 @@
|
|
|
11962
12188
|
{
|
|
11963
12189
|
"kind": "Class",
|
|
11964
12190
|
"canonicalReference": "@fgv/ts-agent-memory!InMemoryFragmentCosineIndex:class",
|
|
11965
|
-
"docComment": "/**\n * The brute-force, in-memory cosine {@link IFragmentVectorIndex} — the fragment-granular sibling of {@link InMemoryCosineIndex}. Stores many `Float32Array`s per record (one per
|
|
12191
|
+
"docComment": "/**\n * The brute-force, in-memory cosine {@link IFragmentVectorIndex} — the fragment-granular sibling of {@link InMemoryCosineIndex}. Stores many `Float32Array`s per record (one per {@link IEmbeddedFragment | fragment}) and answers a query by computing cosine similarity against every stored fragment, returning the top-k fragment hits by descending score. Each hit carries back whichever of {@link IFragmentLocator | locator} / `fragmentId` its fragment was added with; a fragment must carry at least one of the two.\n *\n * @remarks\n *\n * Same regime and same non-goals as {@link InMemoryCosineIndex}: no external dependency, no ANN structure, a linear scan over the stored fragments — the seam ({@link IFragmentVectorIndex}) stays open for a consumer to swap a persistent / ANN backend once N grows. `addFragments` is whole-record-replace, so re-authoring a document never leaves stale fragments behind. The index has a single dimension established by the first fragment added; every subsequent fragment and every `query` vector must match it or fail loudly — a mismatched dimension is an embedder-wiring bug, never a silent zero-similarity result. {@link InMemoryFragmentCosineIndex.rebuild | rebuild} clears the index (and the established dimension), so a re-embed with a different model is supported.\n *\n * The optional `maxPerRecord` cap on `query` is applied **during selection**, before the `topK` cut, so one long document with many strong fragments cannot crowd every other record out of the result.\n *\n * @public\n */\n",
|
|
11966
12192
|
"excerptTokens": [
|
|
11967
12193
|
{
|
|
11968
12194
|
"kind": "Content",
|
|
@@ -12155,7 +12381,7 @@
|
|
|
12155
12381
|
{
|
|
12156
12382
|
"kind": "Method",
|
|
12157
12383
|
"canonicalReference": "@fgv/ts-agent-memory!InMemoryFragmentCosineIndex#query:member(1)",
|
|
12158
|
-
"docComment": "/**\n * Return the `topK` nearest fragments to `vector`, in descending score order, each hit carrying its record `target`
|
|
12384
|
+
"docComment": "/**\n * Return the `topK` nearest fragments to `vector`, in descending score order, each hit carrying its record `target` plus whichever of `locator` / `fragmentId` the stored fragment was added with. When `maxPerRecord` is supplied, no more than that many fragments of any single record appear in the result — the cap is applied during selection (before the `topK` cut) so one long document cannot crowd out others.\n */\n",
|
|
12159
12385
|
"excerptTokens": [
|
|
12160
12386
|
{
|
|
12161
12387
|
"kind": "Content",
|
|
@@ -14040,7 +14266,7 @@
|
|
|
14040
14266
|
{
|
|
14041
14267
|
"kind": "Interface",
|
|
14042
14268
|
"canonicalReference": "@fgv/ts-agent-memory!IVectorQueryHit:interface",
|
|
14043
|
-
"docComment": "/**\n * A single hit returned by {@link IVectorIndex.query} (or {@link IFragmentVectorIndex.query}): the matched record's scope-qualified {@link IEdgeTarget | address} and the backend's similarity score (higher = more similar; the exact scale is backend-defined). Hits are returned in descending score order.\n *\n * @remarks\n *\n * The address is a `(scope, id)` pair, NOT a bare {@link MemoryId} — per-scope codecs (e.g. the medium-term codec's `turn-<n>` stems) legally mint the same stem under different scopes, so a bare id could not disambiguate two records that share a stem. The caller re-resolves the hit against the record index by the same scoped address.\n *\n * `locator`
|
|
14269
|
+
"docComment": "/**\n * A single hit returned by {@link IVectorIndex.query} (or {@link IFragmentVectorIndex.query}): the matched record's scope-qualified {@link IEdgeTarget | address} and the backend's similarity score (higher = more similar; the exact scale is backend-defined). Hits are returned in descending score order.\n *\n * @remarks\n *\n * The address is a `(scope, id)` pair, NOT a bare {@link MemoryId} — per-scope codecs (e.g. the medium-term codec's `turn-<n>` stems) legally mint the same stem under different scopes, so a bare id could not disambiguate two records that share a stem. The caller re-resolves the hit against the record index by the same scoped address.\n *\n * **No single field discriminates a fragment hit from a record-granular hit.** A record hit carries neither `locator` nor `fragmentId`; a fragment hit carries at least one of the two, but not necessarily any particular one — a fragment with a body span but no consumer-minted id, and a fragment with an id but no honest span, are both legal. Testing one field for presence therefore cannot tell you which kind of hit you hold.\n *\n * That \"at least one\" requirement is enforced on the upsert side by {@link embeddedFragmentConverter} — a different boundary from this type — and is deliberately NOT offered here as a discriminator either. A caller keyed off it would be coupled to an invariant this type does not own, and would fail silently if the invariant were ever relaxed.\n *\n * **The robust rule is that fragment-ness is determined by which index produced the hit**: {@link IFragmentVectorIndex.query} returns fragment hits and {@link IVectorIndex.query} returns record hits. The caller chose the index it queried, so it already knows which kind it is holding.\n *\n * Note in particular that an absent `locator` now carries **two** distinct meanings — a record-granular hit, or a fragment with no honest body span (see {@link IFragmentLocator}) — which is precisely why presence-branching is unsafe.\n *\n * @public\n */\n",
|
|
14044
14270
|
"excerptTokens": [
|
|
14045
14271
|
{
|
|
14046
14272
|
"kind": "Content",
|
|
@@ -14052,10 +14278,37 @@
|
|
|
14052
14278
|
"name": "IVectorQueryHit",
|
|
14053
14279
|
"preserveMemberOrder": false,
|
|
14054
14280
|
"members": [
|
|
14281
|
+
{
|
|
14282
|
+
"kind": "PropertySignature",
|
|
14283
|
+
"canonicalReference": "@fgv/ts-agent-memory!IVectorQueryHit#fragmentId:member",
|
|
14284
|
+
"docComment": "/**\n * The opaque identity the producing fragment was stored with, carried back verbatim. Absent on record-granular hits AND on fragment hits stored without one — see the remarks above; do not branch on its presence.\n */\n",
|
|
14285
|
+
"excerptTokens": [
|
|
14286
|
+
{
|
|
14287
|
+
"kind": "Content",
|
|
14288
|
+
"text": "readonly fragmentId?: "
|
|
14289
|
+
},
|
|
14290
|
+
{
|
|
14291
|
+
"kind": "Content",
|
|
14292
|
+
"text": "string"
|
|
14293
|
+
},
|
|
14294
|
+
{
|
|
14295
|
+
"kind": "Content",
|
|
14296
|
+
"text": ";"
|
|
14297
|
+
}
|
|
14298
|
+
],
|
|
14299
|
+
"isReadonly": true,
|
|
14300
|
+
"isOptional": true,
|
|
14301
|
+
"releaseTag": "Public",
|
|
14302
|
+
"name": "fragmentId",
|
|
14303
|
+
"propertyTypeTokenRange": {
|
|
14304
|
+
"startIndex": 1,
|
|
14305
|
+
"endIndex": 2
|
|
14306
|
+
}
|
|
14307
|
+
},
|
|
14055
14308
|
{
|
|
14056
14309
|
"kind": "PropertySignature",
|
|
14057
14310
|
"canonicalReference": "@fgv/ts-agent-memory!IVectorQueryHit#locator:member",
|
|
14058
|
-
"docComment": "/**\n * The
|
|
14311
|
+
"docComment": "/**\n * The advisory in-record span the matched fragment was derived from, when the producing fragment carried one. Absent on record-granular hits AND on fragment hits with no honest span — see the remarks above; do not branch on its presence.\n */\n",
|
|
14059
14312
|
"excerptTokens": [
|
|
14060
14313
|
{
|
|
14061
14314
|
"kind": "Content",
|
|
@@ -14250,7 +14503,7 @@
|
|
|
14250
14503
|
{
|
|
14251
14504
|
"kind": "MethodSignature",
|
|
14252
14505
|
"canonicalReference": "@fgv/ts-agent-memory!IWritePolicy#applyUpdate:member(1)",
|
|
14253
|
-
"docComment": "/**\n * Apply a JSON Merge Patch (RFC-7386) to the mutable fields of an existing record. Called when admission is `accept` AND a record with the same `entityId` already exists (an update, not a first write).\n *\n * @param existing - The current persisted record.\n *\n * @param patch - A partial JSON object in Merge Patch format. `null` deletes the corresponding key; arrays replace wholesale; nested objects deep-merge. Only keys in {@link IWritePolicy.mutableFields} are applied.\n *\n * @returns The updated record (envelope + body).\n */\n",
|
|
14506
|
+
"docComment": "/**\n * Apply a JSON Merge Patch (RFC-7386) to the mutable fields of an existing record. Called when admission is `accept` AND a record with the same `entityId` already exists (an update, not a first write).\n *\n * @remarks\n *\n * **RFC-7386 semantics are the contract here, not an artifact of the shipped policies' merge configuration.** Implementations are expected to honor them, and consumers may rely on them:\n *\n * - **Objects merge per key.** A supplied key overwrites; an omitted key is PRESERVED, not dropped. Patching one key of a nested object (e.g. one field of `provenance`) leaves its siblings intact. - **An explicit `null` on a sub-key clears exactly that sub-key.** This is the sanctioned way to remove a single key from a nested object. - **Arrays replace wholesale** — `tags` / `links` are never element-merged. - **A whole-block `null` that would delete a REQUIRED field is rejected loudly** (`Result.fail`), never silently accepted. `body` / `tags` / `links` / `provenance` are required; `embeddingRef` is optional and a `null` restores it to absent (NOT to `null`), so it stays hash-stable.\n *\n * Which fields these guarantees cover is **policy-dependent**: they apply to the fields the policy declares in {@link IWritePolicy.mutableFields}, and a field outside that list is inert — its patch key is dropped before the merge, so a `null` on it neither clears the value nor raises an error.\n *\n * @param existing - The current persisted record.\n *\n * @param patch - A partial JSON object in Merge Patch format. `null` deletes the corresponding key; arrays replace wholesale; nested objects deep-merge. Only keys in {@link IWritePolicy.mutableFields} are applied.\n *\n * @returns The updated record (envelope + body).\n */\n",
|
|
14254
14507
|
"excerptTokens": [
|
|
14255
14508
|
{
|
|
14256
14509
|
"kind": "Content",
|
|
@@ -14766,7 +15019,7 @@
|
|
|
14766
15019
|
{
|
|
14767
15020
|
"kind": "Class",
|
|
14768
15021
|
"canonicalReference": "@fgv/ts-agent-memory!KnowledgeLwwPolicy:class",
|
|
14769
|
-
"docComment": "/**\n * Last-write-wins write policy for the knowledge kind family. Admission always accepts (no cap, no cull); updates apply an RFC-7386 merge patch restricted to the knowledge mutable surface.\n *\n * @remarks\n *\n * **Merge-surface pin (resolves design-lock §5.3's body-vs-envelope muddle).** The declared `mutableFields` span both axes of a record: `body` is the per-kind body, while `tags` / `links` / `provenance` / `embeddingRef` live on the {@link IMemoryEnvelope}. `applyUpdate` projects exactly those fields — each read from its canonical location — into a single record-level JSON view, runs the merge over that view, then rebuilds a coherent record. The identity and transaction-time envelope fields (`id`, `entityId`, `kind`, `created`, `updated`, `seq`, `contentHash`) are NOT mutable and are preserved verbatim; the store stamps `updated` / `seq` on write.\n *\n * @public\n */\n",
|
|
15022
|
+
"docComment": "/**\n * Last-write-wins write policy for the knowledge kind family. Admission always accepts (no cap, no cull); updates apply an RFC-7386 merge patch restricted to the knowledge mutable surface.\n *\n * @remarks\n *\n * **Merge-surface pin (resolves design-lock §5.3's body-vs-envelope muddle).** The declared `mutableFields` span both axes of a record: `body` is the per-kind body, while `tags` / `links` / `provenance` / `embeddingRef` live on the {@link IMemoryEnvelope}. `applyUpdate` projects exactly those fields — each read from its canonical location — into a single record-level JSON view, runs the merge over that view, then rebuilds a coherent record. The identity and transaction-time envelope fields (`id`, `entityId`, `kind`, `created`, `updated`, `seq`, `contentHash`) are NOT mutable and are preserved verbatim; the store stamps `updated` / `seq` / `contentHash` on write.\n *\n * Because the surface is pinned rather than caller-supplied, the RFC-7386 guarantees documented on {@link IWritePolicy.applyUpdate} apply to every field listed above — in particular to `provenance`, whose keys merge individually, a `null` on any one of which clears that key alone, and a `null` on the whole block of which is rejected loudly (it is a required field). Consumers may depend on this; it is covered by tests.\n *\n * @public\n */\n",
|
|
14770
15023
|
"excerptTokens": [
|
|
14771
15024
|
{
|
|
14772
15025
|
"kind": "Content",
|
|
@@ -14888,7 +15141,7 @@
|
|
|
14888
15141
|
{
|
|
14889
15142
|
"kind": "Method",
|
|
14890
15143
|
"canonicalReference": "@fgv/ts-agent-memory!KnowledgeLwwPolicy#applyUpdate:member(1)",
|
|
14891
|
-
"docComment": "/**\n * Apply a JSON Merge Patch (RFC-7386) to the mutable fields of an existing record. Called when admission is `accept` AND a record with the same `entityId` already exists (an update, not a first write).\n *\n * @param existing - The current persisted record.\n *\n * @param patch - A partial JSON object in Merge Patch format. `null` deletes the corresponding key; arrays replace wholesale; nested objects deep-merge. Only keys in {@link IWritePolicy.mutableFields} are applied.\n *\n * @returns The updated record (envelope + body).\n */\n",
|
|
15144
|
+
"docComment": "/**\n * Apply a JSON Merge Patch (RFC-7386) to the mutable fields of an existing record. Called when admission is `accept` AND a record with the same `entityId` already exists (an update, not a first write).\n *\n * @remarks\n *\n * **RFC-7386 semantics are the contract here, not an artifact of the shipped policies' merge configuration.** Implementations are expected to honor them, and consumers may rely on them:\n *\n * - **Objects merge per key.** A supplied key overwrites; an omitted key is PRESERVED, not dropped. Patching one key of a nested object (e.g. one field of `provenance`) leaves its siblings intact. - **An explicit `null` on a sub-key clears exactly that sub-key.** This is the sanctioned way to remove a single key from a nested object. - **Arrays replace wholesale** — `tags` / `links` are never element-merged. - **A whole-block `null` that would delete a REQUIRED field is rejected loudly** (`Result.fail`), never silently accepted. `body` / `tags` / `links` / `provenance` are required; `embeddingRef` is optional and a `null` restores it to absent (NOT to `null`), so it stays hash-stable.\n *\n * Which fields these guarantees cover is **policy-dependent**: they apply to the fields the policy declares in {@link IWritePolicy.mutableFields}, and a field outside that list is inert — its patch key is dropped before the merge, so a `null` on it neither clears the value nor raises an error.\n *\n * @param existing - The current persisted record.\n *\n * @param patch - A partial JSON object in Merge Patch format. `null` deletes the corresponding key; arrays replace wholesale; nested objects deep-merge. Only keys in {@link IWritePolicy.mutableFields} are applied.\n *\n * @returns The updated record (envelope + body).\n */\n",
|
|
14892
15145
|
"excerptTokens": [
|
|
14893
15146
|
{
|
|
14894
15147
|
"kind": "Content",
|
|
@@ -15052,7 +15305,7 @@
|
|
|
15052
15305
|
{
|
|
15053
15306
|
"kind": "Property",
|
|
15054
15307
|
"canonicalReference": "@fgv/ts-agent-memory!KnowledgeLwwPolicy#mutableFields:member",
|
|
15055
|
-
"docComment": "/**\n * The knowledge mutable surface: the body plus the envelope metadata a consumer may revise without minting a new entity.\n */\n",
|
|
15308
|
+
"docComment": "/**\n * The knowledge mutable surface: the body plus the envelope metadata a consumer may revise without minting a new entity. Pinned, not caller-supplied — see the class remarks for what that guarantees.\n */\n",
|
|
15056
15309
|
"excerptTokens": [
|
|
15057
15310
|
{
|
|
15058
15311
|
"kind": "Content",
|
|
@@ -15883,7 +16136,7 @@
|
|
|
15883
16136
|
{
|
|
15884
16137
|
"kind": "Method",
|
|
15885
16138
|
"canonicalReference": "@fgv/ts-agent-memory!MemoryCapCullPolicy#applyUpdate:member(1)",
|
|
15886
|
-
"docComment": "/**\n * Apply a JSON Merge Patch (RFC-7386) to the mutable fields of an existing record. Called when admission is `accept` AND a record with the same `entityId` already exists (an update, not a first write).\n *\n * @param existing - The current persisted record.\n *\n * @param patch - A partial JSON object in Merge Patch format. `null` deletes the corresponding key; arrays replace wholesale; nested objects deep-merge. Only keys in {@link IWritePolicy.mutableFields} are applied.\n *\n * @returns The updated record (envelope + body).\n */\n",
|
|
16139
|
+
"docComment": "/**\n * Apply a JSON Merge Patch (RFC-7386) to the mutable fields of an existing record. Called when admission is `accept` AND a record with the same `entityId` already exists (an update, not a first write).\n *\n * @remarks\n *\n * **RFC-7386 semantics are the contract here, not an artifact of the shipped policies' merge configuration.** Implementations are expected to honor them, and consumers may rely on them:\n *\n * - **Objects merge per key.** A supplied key overwrites; an omitted key is PRESERVED, not dropped. Patching one key of a nested object (e.g. one field of `provenance`) leaves its siblings intact. - **An explicit `null` on a sub-key clears exactly that sub-key.** This is the sanctioned way to remove a single key from a nested object. - **Arrays replace wholesale** — `tags` / `links` are never element-merged. - **A whole-block `null` that would delete a REQUIRED field is rejected loudly** (`Result.fail`), never silently accepted. `body` / `tags` / `links` / `provenance` are required; `embeddingRef` is optional and a `null` restores it to absent (NOT to `null`), so it stays hash-stable.\n *\n * Which fields these guarantees cover is **policy-dependent**: they apply to the fields the policy declares in {@link IWritePolicy.mutableFields}, and a field outside that list is inert — its patch key is dropped before the merge, so a `null` on it neither clears the value nor raises an error.\n *\n * @param existing - The current persisted record.\n *\n * @param patch - A partial JSON object in Merge Patch format. `null` deletes the corresponding key; arrays replace wholesale; nested objects deep-merge. Only keys in {@link IWritePolicy.mutableFields} are applied.\n *\n * @returns The updated record (envelope + body).\n */\n",
|
|
15887
16140
|
"excerptTokens": [
|
|
15888
16141
|
{
|
|
15889
16142
|
"kind": "Content",
|
|
@@ -20567,7 +20820,7 @@
|
|
|
20567
20820
|
{
|
|
20568
20821
|
"kind": "Method",
|
|
20569
20822
|
"canonicalReference": "@fgv/ts-agent-memory!TemporalVersionedPolicy#applyUpdate:member(1)",
|
|
20570
|
-
"docComment": "/**\n * Apply a JSON Merge Patch (RFC-7386) to the mutable fields of an existing record. Called when admission is `accept` AND a record with the same `entityId` already exists (an update, not a first write).\n *\n * @param existing - The current persisted record.\n *\n * @param patch - A partial JSON object in Merge Patch format. `null` deletes the corresponding key; arrays replace wholesale; nested objects deep-merge. Only keys in {@link IWritePolicy.mutableFields} are applied.\n *\n * @returns The updated record (envelope + body).\n */\n",
|
|
20823
|
+
"docComment": "/**\n * Apply a JSON Merge Patch (RFC-7386) to the mutable fields of an existing record. Called when admission is `accept` AND a record with the same `entityId` already exists (an update, not a first write).\n *\n * @remarks\n *\n * **RFC-7386 semantics are the contract here, not an artifact of the shipped policies' merge configuration.** Implementations are expected to honor them, and consumers may rely on them:\n *\n * - **Objects merge per key.** A supplied key overwrites; an omitted key is PRESERVED, not dropped. Patching one key of a nested object (e.g. one field of `provenance`) leaves its siblings intact. - **An explicit `null` on a sub-key clears exactly that sub-key.** This is the sanctioned way to remove a single key from a nested object. - **Arrays replace wholesale** — `tags` / `links` are never element-merged. - **A whole-block `null` that would delete a REQUIRED field is rejected loudly** (`Result.fail`), never silently accepted. `body` / `tags` / `links` / `provenance` are required; `embeddingRef` is optional and a `null` restores it to absent (NOT to `null`), so it stays hash-stable.\n *\n * Which fields these guarantees cover is **policy-dependent**: they apply to the fields the policy declares in {@link IWritePolicy.mutableFields}, and a field outside that list is inert — its patch key is dropped before the merge, so a `null` on it neither clears the value nor raises an error.\n *\n * @param existing - The current persisted record.\n *\n * @param patch - A partial JSON object in Merge Patch format. `null` deletes the corresponding key; arrays replace wholesale; nested objects deep-merge. Only keys in {@link IWritePolicy.mutableFields} are applied.\n *\n * @returns The updated record (envelope + body).\n */\n",
|
|
20571
20824
|
"excerptTokens": [
|
|
20572
20825
|
{
|
|
20573
20826
|
"kind": "Content",
|
|
@@ -102,6 +102,9 @@ export const edgeTargetConverter: Converter<IEdgeTarget>;
|
|
|
102
102
|
// @public
|
|
103
103
|
export function edgeTargetKey(target: IEdgeTarget): string;
|
|
104
104
|
|
|
105
|
+
// @public
|
|
106
|
+
export const embeddedFragmentConverter: Converter<IEmbeddedFragment>;
|
|
107
|
+
|
|
105
108
|
// @public
|
|
106
109
|
export type EntityId = Brand<string, 'EntityId'>;
|
|
107
110
|
|
|
@@ -115,6 +118,7 @@ export const envelopeYamlConverter: Converter<IMemoryEnvelope>;
|
|
|
115
118
|
export class FileTreeMemoryStore implements IMemoryStore {
|
|
116
119
|
asRecordSource(): IMemoryRecordSource;
|
|
117
120
|
static create(params: IFileTreeMemoryStoreCreateParams): Result<FileTreeMemoryStore>;
|
|
121
|
+
dedupScopeFor(kind: Kind): DedupScope;
|
|
118
122
|
delete(kind: Kind, entityId: EntityId): Promise<Result<MemoryId>>;
|
|
119
123
|
get(kind: Kind, entityId: EntityId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
|
|
120
124
|
getById(scope: MemoryScopeKey, id: MemoryId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
|
|
@@ -130,6 +134,9 @@ export const FRAGMENT_SEMANTIC_UNWIRED_MESSAGE: string;
|
|
|
130
134
|
// @public
|
|
131
135
|
export type FragmentEmbedder = (record: IMemoryRecord<unknown>) => Promise<Result<ReadonlyArray<IEmbeddedFragment>>>;
|
|
132
136
|
|
|
137
|
+
// @public
|
|
138
|
+
export const fragmentLocatorConverter: Converter<IFragmentLocator>;
|
|
139
|
+
|
|
133
140
|
// @public
|
|
134
141
|
export class FragmentSemanticRetriever {
|
|
135
142
|
get capabilities(): IFragmentRetrieverCapabilities;
|
|
@@ -221,7 +228,8 @@ export interface IEdgeTarget {
|
|
|
221
228
|
|
|
222
229
|
// @public
|
|
223
230
|
export interface IEmbeddedFragment {
|
|
224
|
-
readonly
|
|
231
|
+
readonly fragmentId?: string;
|
|
232
|
+
readonly locator?: IFragmentLocator;
|
|
225
233
|
readonly vector: Float32Array;
|
|
226
234
|
}
|
|
227
235
|
|
|
@@ -250,6 +258,7 @@ export interface IFileTreeMemoryStoreCreateParams {
|
|
|
250
258
|
readonly embed?: MemoryEmbedder;
|
|
251
259
|
readonly fragmentEmbedder?: FragmentEmbedder;
|
|
252
260
|
readonly fragmentIndex?: IFragmentVectorIndex;
|
|
261
|
+
readonly index?: IMemoryIndex;
|
|
253
262
|
readonly logger?: Logging.ILogger;
|
|
254
263
|
readonly observers?: ReadonlyArray<IMemoryObserver>;
|
|
255
264
|
readonly onRecordError?: MemoryRecordErrorMode;
|
|
@@ -497,6 +506,7 @@ export interface IMemoryRetrieverCapabilities {
|
|
|
497
506
|
// @public
|
|
498
507
|
export interface IMemoryStore {
|
|
499
508
|
asRecordSource(): IMemoryRecordSource;
|
|
509
|
+
dedupScopeFor(kind: Kind): DedupScope;
|
|
500
510
|
delete(kind: Kind, entityId: EntityId): Promise<Result<MemoryId>>;
|
|
501
511
|
get(kind: Kind, entityId: EntityId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
|
|
502
512
|
getById(scope: MemoryScopeKey, id: MemoryId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
|
|
@@ -653,6 +663,7 @@ export interface IVectorIndex {
|
|
|
653
663
|
|
|
654
664
|
// @public
|
|
655
665
|
export interface IVectorQueryHit {
|
|
666
|
+
readonly fragmentId?: string;
|
|
656
667
|
readonly locator?: IFragmentLocator;
|
|
657
668
|
readonly score: number;
|
|
658
669
|
readonly target: IEdgeTarget;
|