@fgv/ts-agent-memory 5.1.0-37 → 5.1.0-39
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/{6dfc331ddf74dc2db0d4483d0c96ea971f351c83.tar.log → b82cf6bdece20481260e6bab946179eeec9d7b46.tar.log} +116 -2
- package/.rush/temp/chunked-rush-logs/ts-agent-memory.build.chunks.jsonl +4 -4
- package/.rush/temp/operation/build/all.log +4 -4
- package/.rush/temp/operation/build/log-chunks.jsonl +4 -4
- package/.rush/temp/operation/build/state.json +1 -1
- package/.rush/temp/shrinkwrap-deps.json +222 -221
- package/config/jest.config.json +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/packlets/ingest/cycleGuard.js +111 -0
- package/dist/packlets/ingest/cycleGuard.js.map +1 -0
- package/dist/packlets/ingest/hostStages.js +6 -0
- package/dist/packlets/ingest/hostStages.js.map +1 -0
- package/dist/packlets/ingest/index.js +9 -0
- package/dist/packlets/ingest/index.js.map +1 -0
- package/dist/packlets/ingest/model.js +6 -0
- package/dist/packlets/ingest/model.js.map +1 -0
- package/dist/packlets/ingest/orchestrator.js +438 -0
- package/dist/packlets/ingest/orchestrator.js.map +1 -0
- package/dist/packlets/retrieve/index.js +1 -0
- package/dist/packlets/retrieve/index.js.map +1 -1
- package/dist/packlets/retrieve/temporalRetrievers.js +172 -0
- package/dist/packlets/retrieve/temporalRetrievers.js.map +1 -0
- package/dist/packlets/store/fileTreeMemoryStore.js +323 -41
- package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/dist/packlets/tools/index.js +6 -0
- package/dist/packlets/tools/index.js.map +1 -0
- package/dist/packlets/tools/memoryTools.js +337 -0
- package/dist/packlets/tools/memoryTools.js.map +1 -0
- package/dist/packlets/types/identityCodec.js +115 -0
- package/dist/packlets/types/identityCodec.js.map +1 -1
- package/dist/packlets/types/index.js +1 -0
- package/dist/packlets/types/index.js.map +1 -1
- package/dist/packlets/types/temporal.js +85 -0
- package/dist/packlets/types/temporal.js.map +1 -0
- package/dist/packlets/types/writePolicy.js +96 -0
- package/dist/packlets/types/writePolicy.js.map +1 -1
- package/dist/test/unit/converters/antagonistRoundTrip.test.js +95 -0
- package/dist/test/unit/converters/antagonistRoundTrip.test.js.map +1 -0
- package/dist/test/unit/ingest/antagonistCycleAndParity.test.js +273 -0
- package/dist/test/unit/ingest/antagonistCycleAndParity.test.js.map +1 -0
- package/dist/test/unit/ingest/cycleGuard.test.js +54 -0
- package/dist/test/unit/ingest/cycleGuard.test.js.map +1 -0
- package/dist/test/unit/ingest/orchestrator.test.js +913 -0
- package/dist/test/unit/ingest/orchestrator.test.js.map +1 -0
- package/dist/test/unit/retrieve/temporalRetrievers.test.js +182 -0
- package/dist/test/unit/retrieve/temporalRetrievers.test.js.map +1 -0
- package/dist/test/unit/store/antagonistTemporalBoundary.test.js +120 -0
- package/dist/test/unit/store/antagonistTemporalBoundary.test.js.map +1 -0
- package/dist/test/unit/store/fileTreeMemoryStore.test.js +74 -7
- package/dist/test/unit/store/fileTreeMemoryStore.test.js.map +1 -1
- package/dist/test/unit/store/temporalStore.test.js +398 -0
- package/dist/test/unit/store/temporalStore.test.js.map +1 -0
- package/dist/test/unit/tools/memoryTools.test.js +572 -0
- package/dist/test/unit/tools/memoryTools.test.js.map +1 -0
- package/dist/test/unit/types/temporalCodec.test.js +203 -0
- package/dist/test/unit/types/temporalCodec.test.js.map +1 -0
- package/dist/test/unit/types/temporalPolicy.test.js +62 -0
- package/dist/test/unit/types/temporalPolicy.test.js.map +1 -0
- package/dist/ts-agent-memory.d.ts +1042 -10
- package/dist/tsdoc-metadata.json +1 -1
- package/etc/ts-agent-memory.api.md +284 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/packlets/ingest/cycleGuard.d.ts +41 -0
- package/lib/packlets/ingest/cycleGuard.d.ts.map +1 -0
- package/lib/packlets/ingest/cycleGuard.js +115 -0
- package/lib/packlets/ingest/cycleGuard.js.map +1 -0
- package/lib/packlets/ingest/hostStages.d.ts +88 -0
- package/lib/packlets/ingest/hostStages.d.ts.map +1 -0
- package/lib/packlets/ingest/hostStages.js +7 -0
- package/lib/packlets/ingest/hostStages.js.map +1 -0
- package/lib/packlets/ingest/index.d.ts +5 -0
- package/lib/packlets/ingest/index.d.ts.map +1 -0
- package/lib/packlets/ingest/index.js +25 -0
- package/lib/packlets/ingest/index.js.map +1 -0
- package/lib/packlets/ingest/model.d.ts +177 -0
- package/lib/packlets/ingest/model.d.ts.map +1 -0
- package/lib/packlets/ingest/model.js +7 -0
- package/lib/packlets/ingest/model.js.map +1 -0
- package/lib/packlets/ingest/orchestrator.d.ts +206 -0
- package/lib/packlets/ingest/orchestrator.d.ts.map +1 -0
- package/lib/packlets/ingest/orchestrator.js +442 -0
- package/lib/packlets/ingest/orchestrator.js.map +1 -0
- package/lib/packlets/retrieve/index.d.ts +1 -0
- package/lib/packlets/retrieve/index.d.ts.map +1 -1
- package/lib/packlets/retrieve/index.js +1 -0
- package/lib/packlets/retrieve/index.js.map +1 -1
- package/lib/packlets/retrieve/temporalRetrievers.d.ts +78 -0
- package/lib/packlets/retrieve/temporalRetrievers.d.ts.map +1 -0
- package/lib/packlets/retrieve/temporalRetrievers.js +178 -0
- package/lib/packlets/retrieve/temporalRetrievers.js.map +1 -0
- package/lib/packlets/store/fileTreeMemoryStore.d.ts +118 -9
- package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.js +322 -40
- package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/lib/packlets/tools/index.d.ts +2 -0
- package/lib/packlets/tools/index.d.ts.map +1 -0
- package/lib/packlets/tools/index.js +22 -0
- package/lib/packlets/tools/index.js.map +1 -0
- package/lib/packlets/tools/memoryTools.d.ts +139 -0
- package/lib/packlets/tools/memoryTools.d.ts.map +1 -0
- package/lib/packlets/tools/memoryTools.js +341 -0
- package/lib/packlets/tools/memoryTools.js.map +1 -0
- package/lib/packlets/types/identityCodec.d.ts +86 -0
- package/lib/packlets/types/identityCodec.d.ts.map +1 -1
- package/lib/packlets/types/identityCodec.js +118 -1
- package/lib/packlets/types/identityCodec.js.map +1 -1
- package/lib/packlets/types/index.d.ts +1 -0
- package/lib/packlets/types/index.d.ts.map +1 -1
- package/lib/packlets/types/index.js +1 -0
- package/lib/packlets/types/index.js.map +1 -1
- package/lib/packlets/types/temporal.d.ts +40 -0
- package/lib/packlets/types/temporal.d.ts.map +1 -0
- package/lib/packlets/types/temporal.js +92 -0
- package/lib/packlets/types/temporal.js.map +1 -0
- package/lib/packlets/types/writePolicy.d.ts +49 -0
- package/lib/packlets/types/writePolicy.d.ts.map +1 -1
- package/lib/packlets/types/writePolicy.js +98 -1
- package/lib/packlets/types/writePolicy.js.map +1 -1
- package/lib/test/unit/converters/antagonistRoundTrip.test.d.ts +10 -0
- package/lib/test/unit/converters/antagonistRoundTrip.test.d.ts.map +1 -0
- package/lib/test/unit/converters/antagonistRoundTrip.test.js +97 -0
- package/lib/test/unit/converters/antagonistRoundTrip.test.js.map +1 -0
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.d.ts +9 -0
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.d.ts.map +1 -0
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.js +275 -0
- package/lib/test/unit/ingest/antagonistCycleAndParity.test.js.map +1 -0
- package/lib/test/unit/ingest/cycleGuard.test.d.ts +2 -0
- package/lib/test/unit/ingest/cycleGuard.test.d.ts.map +1 -0
- package/lib/test/unit/ingest/cycleGuard.test.js +56 -0
- package/lib/test/unit/ingest/cycleGuard.test.js.map +1 -0
- package/lib/test/unit/ingest/orchestrator.test.d.ts +2 -0
- package/lib/test/unit/ingest/orchestrator.test.d.ts.map +1 -0
- package/lib/test/unit/ingest/orchestrator.test.js +915 -0
- package/lib/test/unit/ingest/orchestrator.test.js.map +1 -0
- package/lib/test/unit/retrieve/temporalRetrievers.test.d.ts +2 -0
- package/lib/test/unit/retrieve/temporalRetrievers.test.d.ts.map +1 -0
- package/lib/test/unit/retrieve/temporalRetrievers.test.js +184 -0
- package/lib/test/unit/retrieve/temporalRetrievers.test.js.map +1 -0
- package/lib/test/unit/store/antagonistTemporalBoundary.test.d.ts +9 -0
- package/lib/test/unit/store/antagonistTemporalBoundary.test.d.ts.map +1 -0
- package/lib/test/unit/store/antagonistTemporalBoundary.test.js +122 -0
- package/lib/test/unit/store/antagonistTemporalBoundary.test.js.map +1 -0
- package/lib/test/unit/store/fileTreeMemoryStore.test.js +74 -7
- package/lib/test/unit/store/fileTreeMemoryStore.test.js.map +1 -1
- package/lib/test/unit/store/temporalStore.test.d.ts +2 -0
- package/lib/test/unit/store/temporalStore.test.d.ts.map +1 -0
- package/lib/test/unit/store/temporalStore.test.js +400 -0
- package/lib/test/unit/store/temporalStore.test.js.map +1 -0
- package/lib/test/unit/tools/memoryTools.test.d.ts +2 -0
- package/lib/test/unit/tools/memoryTools.test.d.ts.map +1 -0
- package/lib/test/unit/tools/memoryTools.test.js +574 -0
- package/lib/test/unit/tools/memoryTools.test.js.map +1 -0
- package/lib/test/unit/types/temporalCodec.test.d.ts +2 -0
- package/lib/test/unit/types/temporalCodec.test.d.ts.map +1 -0
- package/lib/test/unit/types/temporalCodec.test.js +205 -0
- package/lib/test/unit/types/temporalCodec.test.js.map +1 -0
- package/lib/test/unit/types/temporalPolicy.test.d.ts +2 -0
- package/lib/test/unit/types/temporalPolicy.test.d.ts.map +1 -0
- package/lib/test/unit/types/temporalPolicy.test.js +64 -0
- package/lib/test/unit/types/temporalPolicy.test.js.map +1 -0
- package/package.json +7 -7
- package/rush-logs/ts-agent-memory.build.cache.log +1 -1
- package/rush-logs/ts-agent-memory.build.log +4 -4
- package/src/index.ts +2 -0
- package/src/packlets/ingest/cycleGuard.ts +142 -0
- package/src/packlets/ingest/hostStages.ts +111 -0
- package/src/packlets/ingest/index.ts +9 -0
- package/src/packlets/ingest/model.ts +184 -0
- package/src/packlets/ingest/orchestrator.ts +797 -0
- package/src/packlets/retrieve/index.ts +1 -0
- package/src/packlets/retrieve/temporalRetrievers.ts +210 -0
- package/src/packlets/store/fileTreeMemoryStore.ts +460 -66
- package/src/packlets/tools/index.ts +6 -0
- package/src/packlets/tools/memoryTools.ts +579 -0
- package/src/packlets/types/identityCodec.ts +184 -0
- package/src/packlets/types/index.ts +1 -0
- package/src/packlets/types/temporal.ts +96 -0
- package/src/packlets/types/writePolicy.ts +127 -0
- package/src/test/unit/converters/antagonistRoundTrip.test.ts +110 -0
- package/src/test/unit/ingest/antagonistCycleAndParity.test.ts +362 -0
- package/src/test/unit/ingest/cycleGuard.test.ts +68 -0
- package/src/test/unit/ingest/orchestrator.test.ts +1158 -0
- package/src/test/unit/retrieve/temporalRetrievers.test.ts +226 -0
- package/src/test/unit/store/antagonistTemporalBoundary.test.ts +158 -0
- package/src/test/unit/store/fileTreeMemoryStore.test.ts +98 -7
- package/src/test/unit/store/temporalStore.test.ts +469 -0
- package/src/test/unit/tools/memoryTools.test.ts +771 -0
- package/src/test/unit/types/temporalCodec.test.ts +259 -0
- package/src/test/unit/types/temporalPolicy.test.ts +96 -0
- package/temp/build/lint/_eslint-5eVG3S6w.json +85 -9
- package/temp/build/typescript/ts_8nwakTlr.json +1 -1
- package/temp/ts-agent-memory.api.json +11984 -6314
- package/temp/ts-agent-memory.api.md +284 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AiAssist } from '@fgv/ts-extras';
|
|
1
2
|
import { Brand } from '@fgv/ts-utils';
|
|
2
3
|
import { Converter } from '@fgv/ts-utils';
|
|
3
4
|
import { FileTree } from '@fgv/ts-json-base';
|
|
@@ -20,6 +21,46 @@ export declare type AdmissionDecision = {
|
|
|
20
21
|
readonly evict: ReadonlyArray<MemoryId>;
|
|
21
22
|
};
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Temporal retriever returning, for each temporal entity matching the query, the
|
|
26
|
+
* version valid at `query.asOf` (epoch ms). `asOf` is this retriever's axis: a
|
|
27
|
+
* query without it yields an empty success (a no-op contribution to a
|
|
28
|
+
* {@link HybridRetriever}, not a failure). Results are recency-ordered and
|
|
29
|
+
* limited.
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export declare class AsOfRetriever implements IMemoryRetriever {
|
|
33
|
+
private readonly _index;
|
|
34
|
+
private constructor();
|
|
35
|
+
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
36
|
+
get capabilities(): IMemoryRetrieverCapabilities;
|
|
37
|
+
/** Family-convention factory. */
|
|
38
|
+
static create(index: IMemoryIndex): Result<AsOfRetriever>;
|
|
39
|
+
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
40
|
+
retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Write-time cycle guard. Given the graph's EXISTING directed edges plus a set of
|
|
45
|
+
* PROPOSED edges, verify that adding the proposed edges keeps the union graph a
|
|
46
|
+
* DAG. Fails loudly, naming the first proposed edge that would close a directed
|
|
47
|
+
* cycle.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* Distinct from the read-time BFS in `LinkTraversalRetriever` (which tolerates
|
|
51
|
+
* cycles via a visited-set): this is a WRITE-time admission check. Cycle
|
|
52
|
+
* detection is DFS reachability — a proposed `source -> target` edge closes a
|
|
53
|
+
* cycle iff `target` already reaches `source` in the graph built so far. Proposed
|
|
54
|
+
* edges are folded in one at a time (in order), so an intra-batch cycle
|
|
55
|
+
* (`A->B`, `B->A` both proposed) is caught as well as a batch-vs-existing cycle.
|
|
56
|
+
*
|
|
57
|
+
* See the design note §4: this enforces GLOBAL directed-acyclicity over all link
|
|
58
|
+
* types (conservative — a mutual associative pair is rejected). Callers that need
|
|
59
|
+
* mutual links disable the guard.
|
|
60
|
+
* @public
|
|
61
|
+
*/
|
|
62
|
+
export declare function assertNoCycles(existing: ReadonlyArray<ICycleGuardEdge>, proposed: ReadonlyArray<ICycleGuardEdge>): Result<true>;
|
|
63
|
+
|
|
23
64
|
/**
|
|
24
65
|
* Validates a single filename stem against the POSIX portable filename set
|
|
25
66
|
* (`[A-Za-z0-9._-]`), rejecting a leading or trailing `.` and reserved Windows
|
|
@@ -64,6 +105,22 @@ export declare class BodyConverterRegistry implements IBodyConverterRegistry {
|
|
|
64
105
|
convert(kind: Kind, body: unknown): Result<unknown>;
|
|
65
106
|
}
|
|
66
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Build the design's `buildCycleKey` — a deterministic, canonical (RFC-8785,
|
|
110
|
+
* via `Crc32Normalizer` from `@fgv/ts-utils`) identity for a directed edge. Used
|
|
111
|
+
* to de-duplicate proposed edges so a repeated `(source, target, type)` proposal
|
|
112
|
+
* contributes a single graph edge (and never spuriously "re-closes" a cycle).
|
|
113
|
+
* @public
|
|
114
|
+
*/
|
|
115
|
+
export declare function buildCycleKey(edge: ICycleGuardEdge): Result<string>;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The link type whose presence on a temporal-kind candidate fires the
|
|
119
|
+
* contradicts→temporal-versioned interlock.
|
|
120
|
+
* @public
|
|
121
|
+
*/
|
|
122
|
+
export declare const CONTRADICTS_LINK_TYPE: LinkType;
|
|
123
|
+
|
|
67
124
|
/**
|
|
68
125
|
* Converters for the branded identifier scalars. Each validates an `unknown`
|
|
69
126
|
* value into the corresponding brand, enforcing the shared hygiene
|
|
@@ -79,6 +136,51 @@ export declare const Convert: {
|
|
|
79
136
|
readonly linkType: Converter<LinkType>;
|
|
80
137
|
};
|
|
81
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Build the selected suite of memory `AiAssist.IAiClientTool`s over a
|
|
141
|
+
* pre-scoped store — ready to hand to `AiAssist.executeClientToolTurn` (and, via
|
|
142
|
+
* the shared `JsonSchema.object(...)` schemas, `@fgv/ts-extras-mcp`).
|
|
143
|
+
*
|
|
144
|
+
* @remarks
|
|
145
|
+
* **Scope isolation is make-or-break.** The returned tools close over the
|
|
146
|
+
* pre-scoped {@link ICreateMemoryToolsParams.store | store}; no tool's
|
|
147
|
+
* `parametersSchema` declares a `scope` (or any scope-widening) property, so an
|
|
148
|
+
* LLM cannot steer a tool at another actor's memory. The store instance is the
|
|
149
|
+
* sole scope authority.
|
|
150
|
+
*
|
|
151
|
+
* The default selection is {@link DEFAULT_MEMORY_TOOLS} (the read-only set) —
|
|
152
|
+
* `memory_write` / `memory_delete` are included only when named in
|
|
153
|
+
* {@link ICreateMemoryToolsParams.tools | tools}.
|
|
154
|
+
* @public
|
|
155
|
+
*/
|
|
156
|
+
export declare function createMemoryTools(params: ICreateMemoryToolsParams): ReadonlyArray<AiAssist.IAiClientTool>;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Temporal retriever returning the **current** version of each temporal entity
|
|
160
|
+
* matching the query (the newest version whose `invalid_at` is null/absent),
|
|
161
|
+
* recency-ordered and limited. A fully-invalidated (soft-deleted) entity
|
|
162
|
+
* contributes nothing. Non-temporal records are not this retriever's concern.
|
|
163
|
+
* @public
|
|
164
|
+
*/
|
|
165
|
+
export declare class CurrentValidRetriever implements IMemoryRetriever {
|
|
166
|
+
private readonly _index;
|
|
167
|
+
private constructor();
|
|
168
|
+
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
169
|
+
get capabilities(): IMemoryRetrieverCapabilities;
|
|
170
|
+
/** Family-convention factory. */
|
|
171
|
+
static create(index: IMemoryIndex): Result<CurrentValidRetriever>;
|
|
172
|
+
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
173
|
+
retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* How the write-time cycle guard behaves: `'reject'` (default — a cycle-inducing
|
|
178
|
+
* edge fails the ingest) or `'off'` (no acyclicity constraint, for deployments
|
|
179
|
+
* whose link graphs are legitimately cyclic — e.g. mutual associative links).
|
|
180
|
+
* @public
|
|
181
|
+
*/
|
|
182
|
+
export declare type CycleGuardMode = 'reject' | 'off';
|
|
183
|
+
|
|
82
184
|
/**
|
|
83
185
|
* The granularity at which the store deduplicates an incoming write against the
|
|
84
186
|
* existing vault, declared per kind via {@link IWritePolicy.dedupScope}.
|
|
@@ -103,6 +205,29 @@ export declare type DedupScope = 'content' | 'entity';
|
|
|
103
205
|
*/
|
|
104
206
|
export declare const DEFAULT_DEDUP_SCOPE: DedupScope;
|
|
105
207
|
|
|
208
|
+
/**
|
|
209
|
+
* The default tool subset when {@link ICreateMemoryToolsParams.tools | tools} is
|
|
210
|
+
* omitted: the read-only set. Mutating tools (`memory_write` / `memory_delete`)
|
|
211
|
+
* are **off by default** and must be named explicitly — writes stay
|
|
212
|
+
* curation-mediated unless the host opts in.
|
|
213
|
+
* @public
|
|
214
|
+
*/
|
|
215
|
+
export declare const DEFAULT_MEMORY_TOOLS: ReadonlyArray<MemoryToolName>;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The default stage-4 layer-2 cosine similarity threshold (design note §2). A
|
|
219
|
+
* near-duplicate candidate is surfaced to the {@link IEntityResolver} only when
|
|
220
|
+
* its nearest neighbor scores `>= 0.85`.
|
|
221
|
+
* @public
|
|
222
|
+
*/
|
|
223
|
+
export declare const DEFAULT_SIMILARITY_THRESHOLD: number;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* The default top-K for stage-4 layer-2 similarity candidate generation.
|
|
227
|
+
* @public
|
|
228
|
+
*/
|
|
229
|
+
export declare const DEFAULT_SIMILARITY_TOP_K: number;
|
|
230
|
+
|
|
106
231
|
/**
|
|
107
232
|
* Encode a {@link MemoryScopeKey} to its on-disk directory path. The scope may
|
|
108
233
|
* be multi-segment (`/`-separated) — each component is validated independently
|
|
@@ -155,9 +280,11 @@ export declare const envelopeYamlConverter: Converter<IMemoryEnvelope>;
|
|
|
155
280
|
* write-lock so the index and the on-disk files never interleave.
|
|
156
281
|
*
|
|
157
282
|
* @remarks
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
283
|
+
* Bodies are string (markdown). Both layouts are supported: flat
|
|
284
|
+
* (one-file-per-entity, non-versioned) and versioned (subtree-per-entity,
|
|
285
|
+
* invalidate-don't-delete), dispatched per kind by the codec's `isVersioned`
|
|
286
|
+
* flag. A kind is flat with zero behavioral impact unless it opts into a
|
|
287
|
+
* {@link ITemporalIdentityCodec}.
|
|
161
288
|
* @public
|
|
162
289
|
*/
|
|
163
290
|
export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
@@ -207,6 +334,14 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
|
207
334
|
getById(scope: MemoryScopeKey, id: MemoryId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
|
|
208
335
|
/** {@inheritDoc IMemoryStore.list} */
|
|
209
336
|
list(filter?: IMemoryStoreListFilter): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
337
|
+
/**
|
|
338
|
+
* Collapse temporal records to the single version valid at `asOf` per entity;
|
|
339
|
+
* non-temporal records are timeless and pass through unchanged (valid-time
|
|
340
|
+
* `asOf` applies only to versioned kinds; transaction-time / full bi-temporal
|
|
341
|
+
* filtering is deferred — OQ-9). An entity with no version valid at `asOf`
|
|
342
|
+
* contributes nothing.
|
|
343
|
+
*/
|
|
344
|
+
private static _projectAsOf;
|
|
210
345
|
/** {@inheritDoc IMemoryStore.put} */
|
|
211
346
|
put(record: IMemoryRecord<unknown>): Promise<Result<IMemoryRecord<unknown>>>;
|
|
212
347
|
/** {@inheritDoc IMemoryStore.delete} */
|
|
@@ -308,6 +443,73 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
|
308
443
|
/** Serialize and write a fully-stamped record, then patch the index. */
|
|
309
444
|
private _persist;
|
|
310
445
|
private _deleteLocked;
|
|
446
|
+
/**
|
|
447
|
+
* Flat (non-versioned) delete: physically remove the record file + index
|
|
448
|
+
* entry, then prune the vector best-effort. Structurally unchanged from the
|
|
449
|
+
* pre-temporal delete path.
|
|
450
|
+
*/
|
|
451
|
+
private _deleteFlat;
|
|
452
|
+
/**
|
|
453
|
+
* Resolve the current version of a temporal entity from the derived index: the
|
|
454
|
+
* highest-`seq` version under the entity subtree `scope` whose `invalid_at` is
|
|
455
|
+
* null/absent. `undefined` when the entity has no current version (never
|
|
456
|
+
* written, or fully invalidated / soft-deleted).
|
|
457
|
+
*/
|
|
458
|
+
private _readVersionedCurrent;
|
|
459
|
+
/**
|
|
460
|
+
* Every persisted version of the entity whose subtree is `scope`. All version
|
|
461
|
+
* files for one entity live under exactly that scope (which encodes the
|
|
462
|
+
* entityId), so a scope filter over the index isolates one entity's versions.
|
|
463
|
+
*/
|
|
464
|
+
private _versionsForEntity;
|
|
465
|
+
/**
|
|
466
|
+
* Versioned write (invalidate-don't-delete). Builds the new version's content
|
|
467
|
+
* (a first version from the incoming record, or a merge of the incoming patch
|
|
468
|
+
* over the current version), persists it as a NEW version file, then sets
|
|
469
|
+
* `invalid_at` on the prior current version.
|
|
470
|
+
*
|
|
471
|
+
* Durability order: the new version is persisted FIRST. It carries the highest
|
|
472
|
+
* `seq`, so a crash before the prior-version invalidation completes still
|
|
473
|
+
* resolves the new version as current (`selectCurrentVersion` breaks a
|
|
474
|
+
* two-current tie by highest `seq`), and `asOf` reads stay correct because each
|
|
475
|
+
* version's `valid_at` lower-bounds its interval.
|
|
476
|
+
*/
|
|
477
|
+
private _putVersioned;
|
|
478
|
+
/**
|
|
479
|
+
* Invalidate a set of still-current versions (close each world-truth interval at
|
|
480
|
+
* `invalidAt`; stamp transaction-time `updated` = `now`). Chained so a mid-list
|
|
481
|
+
* failure propagates. Invalidating every prior current — not just the
|
|
482
|
+
* highest-`seq` pick — self-heals a state where a previous write's invalidation
|
|
483
|
+
* only partially completed (P2-7).
|
|
484
|
+
*/
|
|
485
|
+
private _invalidateCurrents;
|
|
486
|
+
/**
|
|
487
|
+
* Build the new version to persist. A first version takes the incoming
|
|
488
|
+
* content verbatim (its dedup `hash` is reused); a subsequent version projects
|
|
489
|
+
* the incoming record's mutable fields into a merge-patch and lets the policy
|
|
490
|
+
* merge them over the CURRENT version (the merge-patch-under-versioning
|
|
491
|
+
* contract), recomputing the content hash from the policy's output. Each
|
|
492
|
+
* version is its own record with its own transaction time (`created` = `now`)
|
|
493
|
+
* and a store-minted `id` = the version stem, so `id === filename stem` holds.
|
|
494
|
+
*/
|
|
495
|
+
private _buildVersionedRecord;
|
|
496
|
+
/**
|
|
497
|
+
* Set `invalid_at` on a prior current version (invalidate-don't-delete) and
|
|
498
|
+
* rewrite its file + index entry. The content hash is unchanged — `invalid_at`
|
|
499
|
+
* is temporal metadata, not part of `{ kind, body, links }` — so the version's
|
|
500
|
+
* identity is stable.
|
|
501
|
+
*/
|
|
502
|
+
private _invalidateVersion;
|
|
503
|
+
/**
|
|
504
|
+
* Versioned delete: SOFT delete (invalidate-don't-delete). Sets `invalid_at` on
|
|
505
|
+
* the current version, leaving the entity's history intact and the entity with
|
|
506
|
+
* no current version. Returns the invalidated version's {@link MemoryId}. Fails
|
|
507
|
+
* with "no record found" when there is no current version — matching the flat
|
|
508
|
+
* delete's not-found semantics. History is retained deliberately: temporal
|
|
509
|
+
* kinds exist to preserve the audit trail (and the L3 `contradicts` interlock
|
|
510
|
+
* builds on it), so a hard delete would defeat the purpose.
|
|
511
|
+
*/
|
|
512
|
+
private _deleteVersioned;
|
|
311
513
|
/** Evict (physically delete) a single record file by id, patching the index. */
|
|
312
514
|
private _evict;
|
|
313
515
|
/** Project the incoming record's mutable fields into a merge-patch. */
|
|
@@ -321,8 +523,26 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
|
321
523
|
* across first-writes and updates.
|
|
322
524
|
*/
|
|
323
525
|
private _admissionCohort;
|
|
324
|
-
/**
|
|
526
|
+
/**
|
|
527
|
+
* Find a record in `scope` whose `contentHash` equals `hash`, if any,
|
|
528
|
+
* optionally excluding a specific id. `excludeId` lets the content-scoped
|
|
529
|
+
* dedup skip the same-id record so it does not shadow the LWW update path.
|
|
530
|
+
*/
|
|
325
531
|
private _findByContentHash;
|
|
532
|
+
/**
|
|
533
|
+
* True when `incoming`'s caller-authored mutable metadata (`tags` / `provenance`)
|
|
534
|
+
* canonically equals `existing`'s. `body` and `links` are covered by the content
|
|
535
|
+
* hash; `embeddingRef` is store-derived (not caller metadata) and is deliberately
|
|
536
|
+
* excluded so a same-content re-put is not treated as changed merely because the
|
|
537
|
+
* store already stamped an embedding. Used to keep an identical re-put a no-op
|
|
538
|
+
* without swallowing a genuine metadata revision.
|
|
539
|
+
*
|
|
540
|
+
* Canonicalization never fails for a validated record (`tags`/`provenance` are
|
|
541
|
+
* always plain JSON); a failure is defaulted to a non-matching sentinel so the
|
|
542
|
+
* write flows to `applyUpdate` (which re-validates) rather than silently
|
|
543
|
+
* no-op-ing on an un-canonicalizable value.
|
|
544
|
+
*/
|
|
545
|
+
private _isMutableMetadataUnchanged;
|
|
326
546
|
private _contentHash;
|
|
327
547
|
private _codecFor;
|
|
328
548
|
private _policyFor;
|
|
@@ -332,7 +552,15 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
|
332
552
|
* filename round-trip on every load.
|
|
333
553
|
*/
|
|
334
554
|
private _readRecord;
|
|
335
|
-
/**
|
|
555
|
+
/**
|
|
556
|
+
* Enforce `envelope.id === filename stem`, the codec round-trip, AND that the
|
|
557
|
+
* envelope's own `entityId` agrees with the id decoded from the subtree scope.
|
|
558
|
+
* The round-trip only validates (scope, stem) consistency; the codec derives
|
|
559
|
+
* `entityId` from the scope path and never reads the envelope's `entityId`
|
|
560
|
+
* field, so a tampered/corrupt file whose frontmatter declares a foreign
|
|
561
|
+
* `entityId` would otherwise load undetected — and `entityId` is trusted
|
|
562
|
+
* verbatim downstream (e.g. merge-into re-addressing). Cross-check it here.
|
|
563
|
+
*/
|
|
336
564
|
private _verifyLoaded;
|
|
337
565
|
/**
|
|
338
566
|
* Resolve the directory for a scope, returning `undefined` when it does not
|
|
@@ -368,6 +596,44 @@ export declare class FileTreeMemoryStore implements IMemoryStore {
|
|
|
368
596
|
*/
|
|
369
597
|
export declare function guardRetrieverCapabilities(query: IMemoryQuery, capabilities: IMemoryRetrieverCapabilities): Result<true>;
|
|
370
598
|
|
|
599
|
+
/**
|
|
600
|
+
* Temporal retriever returning **every** version of each temporal entity matching
|
|
601
|
+
* the query, ordered ascending by `valid_at` (then `seq` as a stable tiebreak) —
|
|
602
|
+
* the entity's full history. Limited after ordering.
|
|
603
|
+
*
|
|
604
|
+
* @remarks
|
|
605
|
+
* When the query matches more than one entity, the result is a single
|
|
606
|
+
* CROSS-entity list globally sorted by `valid_at` — versions of different
|
|
607
|
+
* entities interleave, NOT grouped per entity — so `limit` truncates that
|
|
608
|
+
* globally-sorted list. Constrain to one entity (e.g. via `query.scope`) for a
|
|
609
|
+
* single entity's contiguous history.
|
|
610
|
+
* @public
|
|
611
|
+
*/
|
|
612
|
+
export declare class HistoryRetriever implements IMemoryRetriever {
|
|
613
|
+
private readonly _index;
|
|
614
|
+
private constructor();
|
|
615
|
+
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
616
|
+
get capabilities(): IMemoryRetrieverCapabilities;
|
|
617
|
+
/** Family-convention factory. */
|
|
618
|
+
static create(index: IMemoryIndex): Result<HistoryRetriever>;
|
|
619
|
+
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
620
|
+
retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
621
|
+
/** A version's world-truth start: its `valid_at`, defaulting to `created` when absent. */
|
|
622
|
+
private static _startOf;
|
|
623
|
+
/**
|
|
624
|
+
* Ascending-by-`valid_at` comparator (a version's `valid_at` defaults to its
|
|
625
|
+
* `created` when absent), with `seq` as a stable ascending tiebreak so
|
|
626
|
+
* same-instant versions order by write sequence.
|
|
627
|
+
*/
|
|
628
|
+
private static _byValidAtAscending;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* The provenance source stamped on every record the ingest pipeline writes.
|
|
633
|
+
* @public
|
|
634
|
+
*/
|
|
635
|
+
export declare const HOST_INGEST_PROVENANCE_SOURCE: string;
|
|
636
|
+
|
|
371
637
|
/**
|
|
372
638
|
* Composes several retrievers, dispatches a query to each, and merges their
|
|
373
639
|
* results via an injectable {@link IMergeStrategy}. Its capabilities are the
|
|
@@ -445,6 +711,100 @@ export declare interface IBodyConverterRegistry {
|
|
|
445
711
|
convert(kind: Kind, body: unknown): Result<unknown>;
|
|
446
712
|
}
|
|
447
713
|
|
|
714
|
+
/**
|
|
715
|
+
* A stage-5 attributed edge proposal: the {@link ICandidateEdge.edge | edge} to
|
|
716
|
+
* add, sourced from {@link ICandidateEdge.source | source}. The source MUST be a
|
|
717
|
+
* candidate being written in this ingest (edges land on the source record's
|
|
718
|
+
* `envelope.links`); the edge's `target` must resolve to a sibling candidate or
|
|
719
|
+
* an existing store record.
|
|
720
|
+
* @public
|
|
721
|
+
*/
|
|
722
|
+
export declare interface ICandidateEdge {
|
|
723
|
+
/** The reference id (codec `idStem`) of the candidate the edge originates from. */
|
|
724
|
+
readonly source: MemoryId;
|
|
725
|
+
/** The attributed edge (type / target / optional confidence / provenance). */
|
|
726
|
+
readonly edge: IEdge;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* A host-extracted candidate record (stage 3 output). The host supplies the
|
|
731
|
+
* full envelope MINUS the {@link StoreStampedEnvelopeField | store-stamped
|
|
732
|
+
* fields} (fgv derives `id` from the codec; the store stamps the rest) plus the
|
|
733
|
+
* typed body. Every candidate body is validated against the kind's registered
|
|
734
|
+
* Converter before it can reach the store (the typed validation boundary).
|
|
735
|
+
* @public
|
|
736
|
+
*/
|
|
737
|
+
export declare interface ICandidateRecord {
|
|
738
|
+
/** The host-supplied envelope, minus the store-stamped fields. */
|
|
739
|
+
readonly envelope: Omit<IMemoryEnvelope, StoreStampedEnvelopeField>;
|
|
740
|
+
/** The per-kind body (a markdown string in v1), validated on ingest. */
|
|
741
|
+
readonly body: unknown;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Parameters for {@link createMemoryTools}.
|
|
746
|
+
*
|
|
747
|
+
* @remarks
|
|
748
|
+
* **Scope isolation is constructor-fixed.** The {@link
|
|
749
|
+
* ICreateMemoryToolsParams.store | store} is the sole scope authority — it is the
|
|
750
|
+
* actor's own, pre-scoped memory root. No tool's `parametersSchema` declares a
|
|
751
|
+
* `scope` (or any scope-widening) property, so an LLM cannot steer a tool at
|
|
752
|
+
* another actor's memory.
|
|
753
|
+
* @public
|
|
754
|
+
*/
|
|
755
|
+
export declare interface ICreateMemoryToolsParams {
|
|
756
|
+
/**
|
|
757
|
+
* The pre-scoped memory store (the actor's own memory root). Sole scope
|
|
758
|
+
* authority — backs `memory_write` / `memory_read` / `memory_delete`.
|
|
759
|
+
*/
|
|
760
|
+
readonly store: IMemoryStore;
|
|
761
|
+
/** Retriever backing `memory_search` (and `memory_context` via link traversal). */
|
|
762
|
+
readonly retriever: IMemoryRetriever;
|
|
763
|
+
/** Body converter registry — gates the toolable kinds via `has(kind)`. */
|
|
764
|
+
readonly registry: IBodyConverterRegistry;
|
|
765
|
+
/**
|
|
766
|
+
* The per-tool enable subset. Defaults to {@link DEFAULT_MEMORY_TOOLS} (the
|
|
767
|
+
* read-only set). Name `memory_write` / `memory_delete` here to opt into the
|
|
768
|
+
* mutating tools.
|
|
769
|
+
*/
|
|
770
|
+
readonly tools?: ReadonlyArray<MemoryToolName>;
|
|
771
|
+
/**
|
|
772
|
+
* Optional whitelist of toolable kinds. When present, a tool `kind` argument
|
|
773
|
+
* outside this set is rejected. When absent, {@link
|
|
774
|
+
* IBodyConverterRegistry.has | registry.has} is the sole kind gate.
|
|
775
|
+
*/
|
|
776
|
+
readonly kinds?: ReadonlyArray<Kind>;
|
|
777
|
+
/**
|
|
778
|
+
* Per-kind identity codecs, used by `memory_write` to map the domain
|
|
779
|
+
* {@link EntityId} to the record's storage id (the store resolves codecs
|
|
780
|
+
* internally for `get` / `delete`, so read / delete do not need them). Absent
|
|
781
|
+
* → `memory_write` uses {@link ICreateMemoryToolsParams.defaultCodec |
|
|
782
|
+
* defaultCodec}, and fails loudly for a kind with no resolvable codec. The
|
|
783
|
+
* read-only default tool set needs no codecs.
|
|
784
|
+
*/
|
|
785
|
+
readonly codecs?: ReadonlyMap<Kind, IIdentityCodec>;
|
|
786
|
+
/** Default identity codec for kinds without an explicit {@link ICreateMemoryToolsParams.codecs | codecs} entry. */
|
|
787
|
+
readonly defaultCodec?: IIdentityCodec;
|
|
788
|
+
/**
|
|
789
|
+
* Optional host hook mapping a record to its agent-visible handle (an evocative
|
|
790
|
+
* mnemonic tag). When supplied, `memory_search` / `memory_context` results use
|
|
791
|
+
* the returned handle as the agent-visible key; when absent the raw
|
|
792
|
+
* {@link MemoryId} is used.
|
|
793
|
+
*/
|
|
794
|
+
readonly handleFor?: (record: IMemoryRecord<unknown>) => string;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* A directed edge in the link graph the cycle guard reasons over: `source` links
|
|
799
|
+
* to `target` under relation `type`.
|
|
800
|
+
* @public
|
|
801
|
+
*/
|
|
802
|
+
export declare interface ICycleGuardEdge {
|
|
803
|
+
readonly source: MemoryId;
|
|
804
|
+
readonly target: MemoryId;
|
|
805
|
+
readonly type: LinkType;
|
|
806
|
+
}
|
|
807
|
+
|
|
448
808
|
/**
|
|
449
809
|
* An attributed link between two records. Carries the relation type, the
|
|
450
810
|
* target id, and optional confidence / provenance / world-truth validity.
|
|
@@ -470,6 +830,54 @@ export declare interface IEdge {
|
|
|
470
830
|
readonly invalid_at?: number | null;
|
|
471
831
|
}
|
|
472
832
|
|
|
833
|
+
/**
|
|
834
|
+
* A near-duplicate candidate surfaced to the {@link IEntityResolver} by stage-4
|
|
835
|
+
* layer-2 similarity search: an existing record whose embedding is within the
|
|
836
|
+
* similarity threshold of the incoming candidate.
|
|
837
|
+
* @public
|
|
838
|
+
*/
|
|
839
|
+
export declare interface IEntityResolutionCandidate {
|
|
840
|
+
/** The existing record's id. */
|
|
841
|
+
readonly id: MemoryId;
|
|
842
|
+
/** The existing record. */
|
|
843
|
+
readonly record: IMemoryRecord<unknown>;
|
|
844
|
+
/** The backend similarity score (higher = more similar). */
|
|
845
|
+
readonly score: number;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* Stage 4 (optional) — the host's entity resolver (OQ-13, LOCKED OPTIONAL). When
|
|
850
|
+
* supplied, fgv surfaces near-duplicate {@link IEntityResolutionCandidate}s (from
|
|
851
|
+
* layer-2 similarity search) and the resolver returns a
|
|
852
|
+
* {@link ResolutionVerdict}. When ABSENT, stage-4 dedup falls back to
|
|
853
|
+
* exact-`{ kind, body }`-hash only — the deterministic-identity host path.
|
|
854
|
+
* @public
|
|
855
|
+
*/
|
|
856
|
+
export declare interface IEntityResolver {
|
|
857
|
+
/**
|
|
858
|
+
* Decide whether `candidate` is new, a duplicate of / supersedes / merges into
|
|
859
|
+
* one of the surfaced `similar` records. `similar` is non-empty and ordered by
|
|
860
|
+
* descending score when the resolver is invoked (fgv only calls it when
|
|
861
|
+
* layer-2 surfaces at least one over-threshold neighbor).
|
|
862
|
+
*/
|
|
863
|
+
resolve(candidate: ICandidateRecord, similar: ReadonlyArray<IEntityResolutionCandidate>): Promise<Result<ResolutionVerdict>>;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* Stage 3 — the host's fact extractor. Turns a classified item into zero or more
|
|
868
|
+
* {@link ICandidateRecord}s. Each candidate's body is validated against the
|
|
869
|
+
* kind's registered Converter by fgv before it can reach the store (the typed
|
|
870
|
+
* validation boundary — no unchecked host data is persisted).
|
|
871
|
+
* @public
|
|
872
|
+
*/
|
|
873
|
+
export declare interface IFactExtractor {
|
|
874
|
+
/**
|
|
875
|
+
* Extract candidate records from a classified item. An empty array is a valid
|
|
876
|
+
* result (the item yielded nothing memorable).
|
|
877
|
+
*/
|
|
878
|
+
extract(item: IIngestItem, classification: IMemoryClassification): Promise<Result<ReadonlyArray<ICandidateRecord>>>;
|
|
879
|
+
}
|
|
880
|
+
|
|
473
881
|
/**
|
|
474
882
|
* Parameters for {@link FileTreeMemoryStore.create}.
|
|
475
883
|
* @public
|
|
@@ -587,6 +995,87 @@ export declare interface IIndexedMemoryRecord {
|
|
|
587
995
|
readonly record: IMemoryRecord<unknown>;
|
|
588
996
|
}
|
|
589
997
|
|
|
998
|
+
/**
|
|
999
|
+
* Per-candidate outcome of an ingest run.
|
|
1000
|
+
* @public
|
|
1001
|
+
*/
|
|
1002
|
+
export declare interface IIngestedRecordResult {
|
|
1003
|
+
/** The candidate the outcome is for. */
|
|
1004
|
+
readonly candidate: ICandidateRecord;
|
|
1005
|
+
/** The resolution verdict fgv reached (or the resolver returned). */
|
|
1006
|
+
readonly resolution: ResolutionVerdict;
|
|
1007
|
+
/** What the write ultimately did. */
|
|
1008
|
+
readonly disposition: IngestDisposition;
|
|
1009
|
+
/**
|
|
1010
|
+
* The stored record's id: the newly-written id (`written` / `merged`), or the
|
|
1011
|
+
* existing target's id (`deduped`).
|
|
1012
|
+
*/
|
|
1013
|
+
readonly id: MemoryId;
|
|
1014
|
+
/** The persisted record, when a write happened (`written` / `merged`). */
|
|
1015
|
+
readonly record?: IMemoryRecord<unknown>;
|
|
1016
|
+
/** The stage-5 edges attached to this candidate before the write. */
|
|
1017
|
+
readonly edges: ReadonlyArray<ICandidateEdge>;
|
|
1018
|
+
/**
|
|
1019
|
+
* Informational diagnostic, set to `'temporal-versioned'` when the
|
|
1020
|
+
* contradicts→temporal interlock is recognized: a `contradicts` edge was
|
|
1021
|
+
* attached to a candidate of a temporal kind.
|
|
1022
|
+
*
|
|
1023
|
+
* @remarks
|
|
1024
|
+
* A temporal kind ALWAYS writes through the store's versioned put path (that is
|
|
1025
|
+
* the codec's `isVersioned` behavior — the prior version is invalidated and a
|
|
1026
|
+
* new version written on every write, contradicts edge or not). This flag does
|
|
1027
|
+
* NOT cause that routing; it is a diagnostic marker that the contradicts-driven
|
|
1028
|
+
* scenario occurred, so callers can distinguish a contradiction-superseding
|
|
1029
|
+
* version from an ordinary revision.
|
|
1030
|
+
*/
|
|
1031
|
+
readonly interlock?: 'temporal-versioned';
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* A single unit of raw source material handed to the ingest pipeline. The host
|
|
1036
|
+
* owns the shape of {@link IIngestItem.content | content} — fgv never interprets
|
|
1037
|
+
* it; it flows opaquely into the host's classifier and extractor (stages 2-3).
|
|
1038
|
+
*
|
|
1039
|
+
* Single-item ingest is FIRST-CLASS: the orchestrator's primary entry point
|
|
1040
|
+
* takes one `IIngestItem` (per-turn streaming), and the batch entry point is a
|
|
1041
|
+
* convenience loop over it.
|
|
1042
|
+
* @public
|
|
1043
|
+
*/
|
|
1044
|
+
export declare interface IIngestItem {
|
|
1045
|
+
/**
|
|
1046
|
+
* Host-owned identity for this source item. Opaque to fgv; used only in
|
|
1047
|
+
* diagnostics and echoed back on the {@link IIngestItemResult}.
|
|
1048
|
+
*/
|
|
1049
|
+
readonly id: string;
|
|
1050
|
+
/**
|
|
1051
|
+
* The opaque source payload the host's classifier / extractor understand
|
|
1052
|
+
* (e.g. a raw turn, a document, a tool-call transcript). Never interpreted by
|
|
1053
|
+
* fgv.
|
|
1054
|
+
*/
|
|
1055
|
+
readonly content: unknown;
|
|
1056
|
+
/**
|
|
1057
|
+
* Optional back-link to the memory record this item was derived from (e.g. the
|
|
1058
|
+
* MTM turn an extracted fact came from). When present, fgv stamps it as
|
|
1059
|
+
* {@link IProvenance.derivedFrom | provenance.derivedFrom} on every record
|
|
1060
|
+
* ingested from this item (stage 6) — the cross-kind provenance spine.
|
|
1061
|
+
*/
|
|
1062
|
+
readonly sourceId?: MemoryId;
|
|
1063
|
+
/** Optional opaque metadata carried alongside the item; never interpreted by fgv. */
|
|
1064
|
+
readonly metadata?: Record<string, unknown>;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* The result of ingesting a single {@link IIngestItem}: the item plus the
|
|
1069
|
+
* per-candidate outcomes (one item can yield zero or many candidate records).
|
|
1070
|
+
* @public
|
|
1071
|
+
*/
|
|
1072
|
+
export declare interface IIngestItemResult {
|
|
1073
|
+
/** The item that was ingested. */
|
|
1074
|
+
readonly item: IIngestItem;
|
|
1075
|
+
/** The per-candidate outcomes, in extraction order. */
|
|
1076
|
+
readonly records: ReadonlyArray<IIngestedRecordResult>;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
590
1079
|
/**
|
|
591
1080
|
* Parameters for {@link MemoryCapCullPolicy.create}.
|
|
592
1081
|
* @public
|
|
@@ -606,6 +1095,41 @@ export declare interface IMemoryCapCullPolicyParams {
|
|
|
606
1095
|
readonly mutableFields: ReadonlyArray<string>;
|
|
607
1096
|
}
|
|
608
1097
|
|
|
1098
|
+
/**
|
|
1099
|
+
* The host classifier's verdict for an {@link IIngestItem} (stage 2). Guides the
|
|
1100
|
+
* host's own extractor (stage 3) and supplies the default `kind` / `tags` /
|
|
1101
|
+
* `confidence` fgv stamps when the extractor does not override them.
|
|
1102
|
+
*
|
|
1103
|
+
* Extensible: the `[key: string]: unknown` arm lets the host attach an opaque
|
|
1104
|
+
* classification payload without changing this interface.
|
|
1105
|
+
* @public
|
|
1106
|
+
*/
|
|
1107
|
+
export declare interface IMemoryClassification {
|
|
1108
|
+
/** The record kind the item classifies as. */
|
|
1109
|
+
readonly kind: Kind;
|
|
1110
|
+
/** Optional tags the classifier assigns. */
|
|
1111
|
+
readonly tags?: ReadonlyArray<Tag>;
|
|
1112
|
+
/** Optional classifier confidence in `[0, 1]`; flows to `provenance.confidence`. */
|
|
1113
|
+
readonly confidence?: number;
|
|
1114
|
+
/** Opaque, host-owned extension payload — never interpreted by fgv. */
|
|
1115
|
+
readonly [key: string]: unknown;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/**
|
|
1119
|
+
* Stage 2 — the host's classifier. Decides what {@link IIngestItem} maps to
|
|
1120
|
+
* which memory {@link Kind} (and optional tags / confidence). LOCKED as a
|
|
1121
|
+
* separate staged interface (OQ-10): the host plugs its existing classifier
|
|
1122
|
+
* machinery in here rather than surrendering to an opaque ingestor.
|
|
1123
|
+
* @public
|
|
1124
|
+
*/
|
|
1125
|
+
export declare interface IMemoryClassifier {
|
|
1126
|
+
/**
|
|
1127
|
+
* Classify one item. A `fail` aborts the item's ingest loudly (fgv never
|
|
1128
|
+
* guesses a kind).
|
|
1129
|
+
*/
|
|
1130
|
+
classify(item: IIngestItem): Promise<Result<IMemoryClassification>>;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
609
1133
|
/**
|
|
610
1134
|
* The invariant identity + transaction-time envelope carried by every memory
|
|
611
1135
|
* record, independent of the per-kind body.
|
|
@@ -700,6 +1224,75 @@ export declare interface IMemoryIndex {
|
|
|
700
1224
|
backlinks(target: MemoryId): ReadonlyArray<MemoryId>;
|
|
701
1225
|
}
|
|
702
1226
|
|
|
1227
|
+
/**
|
|
1228
|
+
* The fgv-owned six-stage ingest orchestrator. Composes the host's staged
|
|
1229
|
+
* classify / extract / (optional) resolve / relate machinery around fgv's owned
|
|
1230
|
+
* validation boundary, dedup, edge + cycle safety, provenance stamping, and the
|
|
1231
|
+
* contradicts→temporal interlock.
|
|
1232
|
+
* @public
|
|
1233
|
+
*/
|
|
1234
|
+
export declare interface IMemoryIngestOrchestrator {
|
|
1235
|
+
/**
|
|
1236
|
+
* Ingest a SINGLE item end-to-end (the first-class per-turn streaming path).
|
|
1237
|
+
*/
|
|
1238
|
+
ingestItem(item: IIngestItem): Promise<Result<IIngestItemResult>>;
|
|
1239
|
+
/**
|
|
1240
|
+
* Ingest a batch of items. A convenience loop over {@link
|
|
1241
|
+
* IMemoryIngestOrchestrator.ingestItem | ingestItem} — items are processed in
|
|
1242
|
+
* order and the first failure aborts the batch.
|
|
1243
|
+
*/
|
|
1244
|
+
ingestBatch(items: ReadonlyArray<IIngestItem>): Promise<Result<ReadonlyArray<IIngestItemResult>>>;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* Parameters for {@link MemoryIngestOrchestrator.create}.
|
|
1249
|
+
* @public
|
|
1250
|
+
*/
|
|
1251
|
+
export declare interface IMemoryIngestOrchestratorCreateParams {
|
|
1252
|
+
/** The store every write bottoms out in (stage 6). */
|
|
1253
|
+
readonly store: IMemoryStore;
|
|
1254
|
+
/** Per-kind body converter registry — the stage-3 typed validation boundary. */
|
|
1255
|
+
readonly registry: IBodyConverterRegistry;
|
|
1256
|
+
/** Per-kind identity codecs (maps a candidate `entityId` to its storage address). */
|
|
1257
|
+
readonly codecs?: ReadonlyMap<Kind, IIdentityCodec>;
|
|
1258
|
+
/** Default identity codec for kinds without an explicit entry. */
|
|
1259
|
+
readonly defaultCodec?: IIdentityCodec;
|
|
1260
|
+
/** Stage 2 — the host's classifier. */
|
|
1261
|
+
readonly classifier: IMemoryClassifier;
|
|
1262
|
+
/** Stage 3 — the host's fact extractor. */
|
|
1263
|
+
readonly extractor: IFactExtractor;
|
|
1264
|
+
/** Stage 5 — the host's relation extractor. */
|
|
1265
|
+
readonly relationExtractor: IRelationExtractor;
|
|
1266
|
+
/**
|
|
1267
|
+
* Stage 4 (optional, OQ-13) — the host's entity resolver. Absent → stage-4
|
|
1268
|
+
* dedup is exact-`{ kind, body }`-hash only (the deterministic-identity path).
|
|
1269
|
+
*/
|
|
1270
|
+
readonly entityResolver?: IEntityResolver;
|
|
1271
|
+
/**
|
|
1272
|
+
* Optional vector index for stage-4 layer-2 similarity candidate-gen. Wired
|
|
1273
|
+
* together with {@link IMemoryIngestOrchestratorCreateParams.embed | embed} AND
|
|
1274
|
+
* {@link IMemoryIngestOrchestratorCreateParams.entityResolver | entityResolver};
|
|
1275
|
+
* absent (or either co-requisite absent) → layer-2 is skipped and dedup is
|
|
1276
|
+
* exact-only.
|
|
1277
|
+
*/
|
|
1278
|
+
readonly vectorIndex?: IVectorIndex;
|
|
1279
|
+
/** Optional embedder used to embed a candidate for layer-2 similarity search. */
|
|
1280
|
+
readonly embed?: MemoryEmbedder;
|
|
1281
|
+
/**
|
|
1282
|
+
* Stage-4 layer-2 cosine threshold. Defaults to {@link
|
|
1283
|
+
* DEFAULT_SIMILARITY_THRESHOLD} (`0.85`).
|
|
1284
|
+
*/
|
|
1285
|
+
readonly similarityThreshold?: number;
|
|
1286
|
+
/**
|
|
1287
|
+
* Stage-4 layer-2 top-K. Defaults to {@link DEFAULT_SIMILARITY_TOP_K} (`5`).
|
|
1288
|
+
*/
|
|
1289
|
+
readonly similarityTopK?: number;
|
|
1290
|
+
/** Write-time cycle guard mode. Defaults to `'reject'`. */
|
|
1291
|
+
readonly cycleGuard?: CycleGuardMode;
|
|
1292
|
+
/** Diagnostic logger (defaults to a no-op). */
|
|
1293
|
+
readonly logger?: Logging.ILogger;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
703
1296
|
/**
|
|
704
1297
|
* Query criteria for {@link MemoryObservationStore.query}. All supplied criteria
|
|
705
1298
|
* are AND-combined.
|
|
@@ -913,7 +1506,9 @@ export declare interface IMemoryStore {
|
|
|
913
1506
|
/**
|
|
914
1507
|
* Keyed read by entity id. Resolves `entityId` to a storage address via the
|
|
915
1508
|
* registered {@link IIdentityCodec} for `kind`. Returns `undefined` when no
|
|
916
|
-
* record exists.
|
|
1509
|
+
* record exists. For a versioned (temporal) kind this returns the current
|
|
1510
|
+
* version, resolved from the derived in-memory index (not re-read/re-verified
|
|
1511
|
+
* from disk per call — the index is kept in sync with every write).
|
|
917
1512
|
*/
|
|
918
1513
|
get(kind: Kind, entityId: EntityId): Promise<Result<IMemoryRecord<unknown> | undefined>>;
|
|
919
1514
|
/**
|
|
@@ -934,7 +1529,10 @@ export declare interface IMemoryStore {
|
|
|
934
1529
|
put(record: IMemoryRecord<unknown>): Promise<Result<IMemoryRecord<unknown>>>;
|
|
935
1530
|
/**
|
|
936
1531
|
* Delete a record by `(kind, entityId)`. Non-temporal kinds physically delete
|
|
937
|
-
* the file
|
|
1532
|
+
* the file and return the deleted record's {@link MemoryId}. Temporal
|
|
1533
|
+
* (versioned) kinds SOFT-delete: the current version is invalidated
|
|
1534
|
+
* (`invalid_at` set), history is retained, and the invalidated version's
|
|
1535
|
+
* {@link MemoryId} is returned.
|
|
938
1536
|
*/
|
|
939
1537
|
delete(kind: Kind, entityId: EntityId): Promise<Result<MemoryId>>;
|
|
940
1538
|
}
|
|
@@ -951,12 +1549,48 @@ export declare interface IMemoryStoreListFilter {
|
|
|
951
1549
|
/** Restrict to records carrying this tag (exact match). */
|
|
952
1550
|
readonly tag?: Tag;
|
|
953
1551
|
/**
|
|
954
|
-
* For temporal kinds:
|
|
955
|
-
*
|
|
1552
|
+
* For temporal (versioned) kinds: collapse each entity to the single version
|
|
1553
|
+
* valid at this epoch ms. Non-temporal records are timeless and pass through
|
|
1554
|
+
* unchanged. Absent = no temporal projection (every version is returned).
|
|
956
1555
|
*/
|
|
957
1556
|
readonly asOf?: number;
|
|
958
1557
|
}
|
|
959
1558
|
|
|
1559
|
+
/**
|
|
1560
|
+
* A single agent-visible search / context result item. The agent-facing key is
|
|
1561
|
+
* {@link IMemoryToolResultItem.handle | handle}: the host mnemonic when a
|
|
1562
|
+
* {@link ICreateMemoryToolsParams.handleFor | handleFor} hook is supplied, else
|
|
1563
|
+
* the raw {@link MemoryId}.
|
|
1564
|
+
* @public
|
|
1565
|
+
*/
|
|
1566
|
+
export declare interface IMemoryToolResultItem {
|
|
1567
|
+
/** The agent-visible key (host handle when supplied, raw {@link MemoryId} otherwise). */
|
|
1568
|
+
readonly handle: string;
|
|
1569
|
+
/** The record's {@link Kind}. */
|
|
1570
|
+
readonly kind: Kind;
|
|
1571
|
+
/** The record's domain {@link EntityId}. */
|
|
1572
|
+
readonly entityId: EntityId;
|
|
1573
|
+
/** The record's tags. */
|
|
1574
|
+
readonly tags: ReadonlyArray<string>;
|
|
1575
|
+
/** The record body (a markdown string in B1). */
|
|
1576
|
+
readonly body: unknown;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* The success value returned by `memory_write.execute`.
|
|
1581
|
+
* @public
|
|
1582
|
+
*/
|
|
1583
|
+
export declare interface IMemoryWriteResult {
|
|
1584
|
+
/** What the write did — see {@link MemoryWriteOutcome}. */
|
|
1585
|
+
readonly outcome: MemoryWriteOutcome;
|
|
1586
|
+
/** The stored record's {@link MemoryId}. */
|
|
1587
|
+
readonly id: MemoryId;
|
|
1588
|
+
/** The domain {@link EntityId} the write targeted. */
|
|
1589
|
+
readonly entityId: EntityId;
|
|
1590
|
+
/** The record's {@link Kind}. */
|
|
1591
|
+
readonly kind: Kind;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
960
1594
|
/**
|
|
961
1595
|
* Strategy for combining the result sets of the retrievers a
|
|
962
1596
|
* {@link HybridRetriever} composes. Injectable so a consumer can weight,
|
|
@@ -979,6 +1613,18 @@ export declare interface IMergeStrategy {
|
|
|
979
1613
|
*/
|
|
980
1614
|
export declare function indexedRecordMatchesQuery(entry: IIndexedMemoryRecord, query: IMemoryQuery): boolean;
|
|
981
1615
|
|
|
1616
|
+
/**
|
|
1617
|
+
* How a candidate was ultimately written (or not) after resolution.
|
|
1618
|
+
*
|
|
1619
|
+
* - `written` — persisted as a fresh record (verdict `new`), or as a superseding
|
|
1620
|
+
* record (verdict `supersede`).
|
|
1621
|
+
* - `deduped` — not written; an existing record satisfied it (verdict
|
|
1622
|
+
* `duplicate-of`, incl. every layer-1 exact `{ kind, body }` match).
|
|
1623
|
+
* - `merged` — merged into an existing target entity (verdict `merge-into`).
|
|
1624
|
+
* @public
|
|
1625
|
+
*/
|
|
1626
|
+
export declare type IngestDisposition = 'written' | 'deduped' | 'merged';
|
|
1627
|
+
|
|
982
1628
|
/**
|
|
983
1629
|
* The brute-force, in-memory cosine {@link IVectorIndex}. Stores one
|
|
984
1630
|
* `Float32Array` per record and answers a query by computing cosine similarity
|
|
@@ -1067,6 +1713,48 @@ export declare interface IProvenance {
|
|
|
1067
1713
|
readonly [key: string]: unknown;
|
|
1068
1714
|
}
|
|
1069
1715
|
|
|
1716
|
+
/**
|
|
1717
|
+
* A candidate paired with its resolved reference id, handed to the relation
|
|
1718
|
+
* extractor so it can source edges from it.
|
|
1719
|
+
* @public
|
|
1720
|
+
*/
|
|
1721
|
+
export declare interface IRelationCandidate {
|
|
1722
|
+
/** The candidate about to be written. */
|
|
1723
|
+
readonly candidate: ICandidateRecord;
|
|
1724
|
+
/** Its resolved reference id (codec `idStem` — the stable entity reference). */
|
|
1725
|
+
readonly id: MemoryId;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
/**
|
|
1729
|
+
* The context fgv hands the host's relation extractor (stage 5): the source item
|
|
1730
|
+
* plus the candidates fgv is about to write, each paired with its resolved
|
|
1731
|
+
* reference id (the codec `idStem`). The extractor proposes attributed edges over
|
|
1732
|
+
* these ids and existing store records.
|
|
1733
|
+
* @public
|
|
1734
|
+
*/
|
|
1735
|
+
export declare interface IRelationContext {
|
|
1736
|
+
/** The item being ingested. */
|
|
1737
|
+
readonly item: IIngestItem;
|
|
1738
|
+
/** The candidates fgv is about to write, each with its resolved reference id. */
|
|
1739
|
+
readonly candidates: ReadonlyArray<IRelationCandidate>;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
/**
|
|
1743
|
+
* Stage 5 — the host's relation extractor. Proposes attributed edges among the
|
|
1744
|
+
* candidates and existing records. fgv owns the validation, the write-time cycle
|
|
1745
|
+
* guard, and the actual persistence of the edges (the host brings only the
|
|
1746
|
+
* relationship judgment).
|
|
1747
|
+
* @public
|
|
1748
|
+
*/
|
|
1749
|
+
export declare interface IRelationExtractor {
|
|
1750
|
+
/**
|
|
1751
|
+
* Propose the edges to attach for this ingest. An empty array is valid (no
|
|
1752
|
+
* relations). Every proposed {@link ICandidateEdge.source | source} must be one
|
|
1753
|
+
* of the context's candidate reference ids.
|
|
1754
|
+
*/
|
|
1755
|
+
relate(context: IRelationContext): Promise<Result<ReadonlyArray<ICandidateEdge>>>;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1070
1758
|
/**
|
|
1071
1759
|
* The semantic backend wired into a {@link SemanticRetriever}: the vector index
|
|
1072
1760
|
* to query and the embedder that turns the query text into a vector. Both are
|
|
@@ -1096,6 +1784,41 @@ export declare interface ISemanticRetrieverCreateParams {
|
|
|
1096
1784
|
readonly backend?: ISemanticBackend;
|
|
1097
1785
|
}
|
|
1098
1786
|
|
|
1787
|
+
/**
|
|
1788
|
+
* Narrow an {@link IIdentityCodec} to {@link ITemporalIdentityCodec} by probing
|
|
1789
|
+
* for the versioned methods. Used by the store when an `encode` result reports
|
|
1790
|
+
* `isVersioned: true`.
|
|
1791
|
+
* @public
|
|
1792
|
+
*/
|
|
1793
|
+
export declare function isTemporalIdentityCodec(codec: IIdentityCodec): codec is ITemporalIdentityCodec;
|
|
1794
|
+
|
|
1795
|
+
/**
|
|
1796
|
+
* Whether a record participates in the versioned (temporal) layout. A temporal
|
|
1797
|
+
* record always carries a {@link ITemporalBlock | temporal} block (the store
|
|
1798
|
+
* stamps `valid_at` on every versioned write); an atemporal record never does,
|
|
1799
|
+
* so presence of `temporal` is the discriminator. Independent of `id`/`entityId`
|
|
1800
|
+
* divergence (MTM is flat yet has `entityId !== id`).
|
|
1801
|
+
* @public
|
|
1802
|
+
*/
|
|
1803
|
+
export declare function isTemporalRecord(record: IMemoryRecord<unknown>): boolean;
|
|
1804
|
+
|
|
1805
|
+
/**
|
|
1806
|
+
* Whether a temporal record is a *current* version — its `temporal.invalid_at`
|
|
1807
|
+
* is `null` or absent (the still-valid sentinel). A non-temporal record is never
|
|
1808
|
+
* current in this sense (returns `false`).
|
|
1809
|
+
* @public
|
|
1810
|
+
*/
|
|
1811
|
+
export declare function isVersionCurrent(record: IMemoryRecord<unknown>): boolean;
|
|
1812
|
+
|
|
1813
|
+
/**
|
|
1814
|
+
* Whether a temporal record's validity interval contains `asOf` (epoch ms):
|
|
1815
|
+
* `valid_at <= asOf` and (`invalid_at` is null/absent OR `asOf < invalid_at`).
|
|
1816
|
+
* The version's `valid_at` defaults to its `created` when absent; a non-temporal
|
|
1817
|
+
* record is never "valid at" a point (returns `false`).
|
|
1818
|
+
* @public
|
|
1819
|
+
*/
|
|
1820
|
+
export declare function isVersionValidAt(record: IMemoryRecord<unknown>, asOf: number): boolean;
|
|
1821
|
+
|
|
1099
1822
|
/**
|
|
1100
1823
|
* Optional bi-temporal validity block on an envelope. Present only on
|
|
1101
1824
|
* temporal kinds; absent = zero cost for atemporal kinds.
|
|
@@ -1108,6 +1831,42 @@ export declare interface ITemporalBlock {
|
|
|
1108
1831
|
readonly invalid_at?: number | null;
|
|
1109
1832
|
}
|
|
1110
1833
|
|
|
1834
|
+
/**
|
|
1835
|
+
* Additive extension of {@link IIdentityCodec} for versioned (temporal) kinds. A
|
|
1836
|
+
* codec whose {@link IIdentityCodec.encode | encode} reports `isVersioned: true`
|
|
1837
|
+
* implements this so the store can form and parse per-version filenames without
|
|
1838
|
+
* knowing the layout. Non-versioned codecs do NOT implement it (probe with
|
|
1839
|
+
* {@link isTemporalIdentityCodec}).
|
|
1840
|
+
* @public
|
|
1841
|
+
*/
|
|
1842
|
+
export declare interface ITemporalIdentityCodec extends IIdentityCodec {
|
|
1843
|
+
/**
|
|
1844
|
+
* Form the version filename stem for a specific `(entityId, seq)`. The store
|
|
1845
|
+
* appends the extension and writes it under the entity subtree returned by
|
|
1846
|
+
* {@link IIdentityCodec.encode | encode}.
|
|
1847
|
+
*/
|
|
1848
|
+
encodeVersion(entityId: EntityId, seq: number): Result<string>;
|
|
1849
|
+
/**
|
|
1850
|
+
* Parse a `(subtree scope, version stem)` back to its
|
|
1851
|
+
* {@link ITemporalVersionAddress}. The subtree scope is authoritative for the
|
|
1852
|
+
* `entityId`, disambiguating a stem whose `entityId` itself ends in
|
|
1853
|
+
* `-v<digits>`.
|
|
1854
|
+
*/
|
|
1855
|
+
decodeVersion(scope: MemoryScopeKey, stem: string): Result<ITemporalVersionAddress>;
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
/**
|
|
1859
|
+
* The `(entityId, version seq)` an {@link ITemporalIdentityCodec.decodeVersion}
|
|
1860
|
+
* recovers from a version file address.
|
|
1861
|
+
* @public
|
|
1862
|
+
*/
|
|
1863
|
+
export declare interface ITemporalVersionAddress {
|
|
1864
|
+
/** The stable consumer-supplied domain key. */
|
|
1865
|
+
readonly entityId: EntityId;
|
|
1866
|
+
/** The version's monotonic `seq` (the `v<seq>` component of the file stem). */
|
|
1867
|
+
readonly seq: number;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1111
1870
|
/**
|
|
1112
1871
|
* The vector-index seam an embedding backend implements to make
|
|
1113
1872
|
* {@link SemanticRetriever | semantic recall} operational.
|
|
@@ -1216,7 +1975,6 @@ export declare function joinFrontmatter(frontmatter: string, body: string): stri
|
|
|
1216
1975
|
export declare type Kind = Brand<string, 'Kind'>;
|
|
1217
1976
|
|
|
1218
1977
|
/**
|
|
1219
|
-
/**
|
|
1220
1978
|
* Identity codec for the knowledge kind family. A knowledge entity is keyed
|
|
1221
1979
|
* by its consumer-supplied `docId`, which is used verbatim as the filename
|
|
1222
1980
|
* stem under the flat `knowledge` scope.
|
|
@@ -1547,6 +2305,108 @@ export declare class MemoryIndex implements IMemoryIndex {
|
|
|
1547
2305
|
*/
|
|
1548
2306
|
export declare type MemoryIndexPatchOp = 'put' | 'delete';
|
|
1549
2307
|
|
|
2308
|
+
/**
|
|
2309
|
+
* Default {@link IMemoryIngestOrchestrator}.
|
|
2310
|
+
* @public
|
|
2311
|
+
*/
|
|
2312
|
+
export declare class MemoryIngestOrchestrator implements IMemoryIngestOrchestrator {
|
|
2313
|
+
private readonly _store;
|
|
2314
|
+
private readonly _registry;
|
|
2315
|
+
private readonly _codecs;
|
|
2316
|
+
private readonly _defaultCodec;
|
|
2317
|
+
private readonly _classifier;
|
|
2318
|
+
private readonly _extractor;
|
|
2319
|
+
private readonly _relationExtractor;
|
|
2320
|
+
private readonly _similarity;
|
|
2321
|
+
private readonly _similarityThreshold;
|
|
2322
|
+
private readonly _similarityTopK;
|
|
2323
|
+
private readonly _cycleGuard;
|
|
2324
|
+
private readonly _logger;
|
|
2325
|
+
private readonly _hasher;
|
|
2326
|
+
private constructor();
|
|
2327
|
+
/** Family-convention factory. */
|
|
2328
|
+
static create(params: IMemoryIngestOrchestratorCreateParams): Result<MemoryIngestOrchestrator>;
|
|
2329
|
+
/** {@inheritDoc IMemoryIngestOrchestrator.ingestItem} */
|
|
2330
|
+
ingestItem(item: IIngestItem): Promise<Result<IIngestItemResult>>;
|
|
2331
|
+
/** {@inheritDoc IMemoryIngestOrchestrator.ingestBatch} */
|
|
2332
|
+
ingestBatch(items: ReadonlyArray<IIngestItem>): Promise<Result<ReadonlyArray<IIngestItemResult>>>;
|
|
2333
|
+
/** Stage 2 — classify (host), normalizing a rejected promise into a Failure. */
|
|
2334
|
+
private _classify;
|
|
2335
|
+
/** Stage 3 — extract (host), normalizing a rejected promise into a Failure. */
|
|
2336
|
+
private _extract;
|
|
2337
|
+
/**
|
|
2338
|
+
* Stages 3b-6 over the extracted candidates: validate bodies, resolve/dedup
|
|
2339
|
+
* (stage 4), relate + cycle guard (stage 5), and load-with-provenance (stage 6).
|
|
2340
|
+
*/
|
|
2341
|
+
private _processCandidates;
|
|
2342
|
+
/** Stage 3b + 4 for one candidate: validate body, resolve address, resolve verdict. */
|
|
2343
|
+
private _planCandidate;
|
|
2344
|
+
/**
|
|
2345
|
+
* Turn a resolved verdict into a candidate plan. A `new` verdict writes under the
|
|
2346
|
+
* candidate's own address. Every TARGET-bearing verdict
|
|
2347
|
+
* (`duplicate-of` / `supersede` / `merge-into`) is validated uniformly: the
|
|
2348
|
+
* target must be a real store record (fgv owns validation — a non-compliant host
|
|
2349
|
+
* resolver never smuggles a bogus id through) AND its kind must equal the
|
|
2350
|
+
* candidate's kind (a cross-kind target would write to the wrong scope). Only
|
|
2351
|
+
* `merge-into` re-addresses the write to the target's entity.
|
|
2352
|
+
*/
|
|
2353
|
+
private _planFromVerdict;
|
|
2354
|
+
/**
|
|
2355
|
+
* Stage 4 — resolve a dedup verdict. Layer 1: an exact `{ kind, body }` match in
|
|
2356
|
+
* the candidate's scope is a `duplicate-of` (design note §1). Layer 2 (only when
|
|
2357
|
+
* a resolver + vector index + embedder are all wired): embed the candidate,
|
|
2358
|
+
* surface over-threshold neighbors, and dispatch to the {@link IEntityResolver}.
|
|
2359
|
+
* Otherwise the verdict is `new` (the exact-only fall-back path).
|
|
2360
|
+
*/
|
|
2361
|
+
private _resolveVerdict;
|
|
2362
|
+
/** Layer-2 similarity candidate-gen + resolver dispatch. */
|
|
2363
|
+
private _resolveViaSimilarity;
|
|
2364
|
+
/** Layer-2 continuation once the candidate has a provisional record to embed. */
|
|
2365
|
+
private _resolveViaSimilarityEmbedded;
|
|
2366
|
+
/**
|
|
2367
|
+
* Find an existing record in `scope` whose `{ kind, body }` hash matches the
|
|
2368
|
+
* candidate's (layer-1 exact dedup). Invalidated temporal versions are excluded
|
|
2369
|
+
* — only a live (non-temporal or current) record deduplicates a candidate.
|
|
2370
|
+
*/
|
|
2371
|
+
private _findExactMatch;
|
|
2372
|
+
/**
|
|
2373
|
+
* The body of a persisted record, required to be a string (the store persists
|
|
2374
|
+
* only string bodies). Fails loudly rather than blind-casting an `unknown` body
|
|
2375
|
+
* into the exact-dedup hash — a non-string existing body is a store-integrity
|
|
2376
|
+
* fault, surfaced with context, not a silent miscompute.
|
|
2377
|
+
*/
|
|
2378
|
+
private static _recordBodyString;
|
|
2379
|
+
/** The stage-4 exact-dedup key over `{ kind, body }` (design note §1). */
|
|
2380
|
+
private _exactKey;
|
|
2381
|
+
/** Stage 5 — relate (host), validate edges, and run the write-time cycle guard. */
|
|
2382
|
+
private _relate;
|
|
2383
|
+
/**
|
|
2384
|
+
* Validate stage-5 edges: each `source` must be a candidate being written; each
|
|
2385
|
+
* `target` must resolve to a sibling candidate or an existing store record.
|
|
2386
|
+
*/
|
|
2387
|
+
private _validateEdges;
|
|
2388
|
+
/** Stage 6 — stamp provenance + edges, admit through the store, record the outcome. */
|
|
2389
|
+
private _loadCandidate;
|
|
2390
|
+
/** Build the fully-stamped record to persist (provenance + edges + placeholder txn fields). */
|
|
2391
|
+
private _buildRecord;
|
|
2392
|
+
/** Union two tag lists, de-duplicated, preserving first-occurrence order. */
|
|
2393
|
+
private static _unionTags;
|
|
2394
|
+
/** De-duplicate a link list by canonical edge hash, preserving first-occurrence order. */
|
|
2395
|
+
private _dedupEdges;
|
|
2396
|
+
/** Resolve a `(kind, entityId)` to its storage address via the registered codec. */
|
|
2397
|
+
private _resolveAddress;
|
|
2398
|
+
/** Run a host hook, normalizing a thrown/rejected hook into a Failure (never throws across the seam). */
|
|
2399
|
+
private _capture;
|
|
2400
|
+
/** Index a record snapshot by id (last write wins on an id collision across scopes). */
|
|
2401
|
+
private static _indexById;
|
|
2402
|
+
/** Every existing outbound edge in the snapshot, as cycle-guard edges. */
|
|
2403
|
+
private static _existingEdges;
|
|
2404
|
+
/** A provisional record for embedding a candidate (placeholder txn-time fields). */
|
|
2405
|
+
private static _provisionalRecord;
|
|
2406
|
+
/** Require a candidate body to be a string (the store persists only string bodies). */
|
|
2407
|
+
private static _asStringBody;
|
|
2408
|
+
}
|
|
2409
|
+
|
|
1550
2410
|
/**
|
|
1551
2411
|
* The outcome of the observed operation.
|
|
1552
2412
|
* @public
|
|
@@ -1655,6 +2515,30 @@ export declare class MemoryObservationStore implements IMemoryObserver {
|
|
|
1655
2515
|
*/
|
|
1656
2516
|
export declare type MemoryScopeKey = Brand<string, 'MemoryScopeKey'>;
|
|
1657
2517
|
|
|
2518
|
+
/**
|
|
2519
|
+
* The names of the five proof-set memory tools. A caller selects a subset via
|
|
2520
|
+
* {@link ICreateMemoryToolsParams.tools | tools}.
|
|
2521
|
+
* @public
|
|
2522
|
+
*/
|
|
2523
|
+
export declare type MemoryToolName = 'memory_write' | 'memory_read' | 'memory_search' | 'memory_context' | 'memory_delete';
|
|
2524
|
+
|
|
2525
|
+
/**
|
|
2526
|
+
* Discriminates the outcome of a {@link createMemoryTools | memory_write} call so
|
|
2527
|
+
* the agent can reason about what its write actually did.
|
|
2528
|
+
*
|
|
2529
|
+
* @remarks
|
|
2530
|
+
* - `written` — a new record was persisted, or an existing entity was updated.
|
|
2531
|
+
* - `deduped` — the content already existed (content-hash dedup no-op); the
|
|
2532
|
+
* store returned the existing record unchanged.
|
|
2533
|
+
*
|
|
2534
|
+
* The store's public `put` return does not surface cap-cull evictions, so a
|
|
2535
|
+
* `culled` outcome is not distinguishable at this layer without an L1 change or
|
|
2536
|
+
* observer wiring (both out of scope for L2). The writer's own record is always
|
|
2537
|
+
* `written` even when the write triggers a cull of older siblings.
|
|
2538
|
+
* @public
|
|
2539
|
+
*/
|
|
2540
|
+
export declare type MemoryWriteOutcome = 'written' | 'deduped';
|
|
2541
|
+
|
|
1658
2542
|
/**
|
|
1659
2543
|
* Identity codec for the medium-term-memory (MTM) kind family. An MTM entity is
|
|
1660
2544
|
* keyed by the colon-composite `<conversationId>:<turnIndex>` and maps into a
|
|
@@ -1763,6 +2647,25 @@ export declare class RecencyRetriever implements IMemoryRetriever {
|
|
|
1763
2647
|
retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
1764
2648
|
}
|
|
1765
2649
|
|
|
2650
|
+
/**
|
|
2651
|
+
* The four dedup verdicts a {@link IEntityResolver} (or fgv's exact-match layer)
|
|
2652
|
+
* returns for a candidate. See the design note §3 for the verdict → write
|
|
2653
|
+
* disposition mapping.
|
|
2654
|
+
* @public
|
|
2655
|
+
*/
|
|
2656
|
+
export declare type ResolutionVerdict = {
|
|
2657
|
+
readonly verdict: 'new';
|
|
2658
|
+
} | {
|
|
2659
|
+
readonly verdict: 'duplicate-of';
|
|
2660
|
+
readonly target: MemoryId;
|
|
2661
|
+
} | {
|
|
2662
|
+
readonly verdict: 'supersede';
|
|
2663
|
+
readonly target: MemoryId;
|
|
2664
|
+
} | {
|
|
2665
|
+
readonly verdict: 'merge-into';
|
|
2666
|
+
readonly target: MemoryId;
|
|
2667
|
+
};
|
|
2668
|
+
|
|
1766
2669
|
/**
|
|
1767
2670
|
* The reference {@link IMergeStrategy}: a score-union. Every record is scored by
|
|
1768
2671
|
* the number of composed result sets it appears in (deduplicated by
|
|
@@ -1790,6 +2693,22 @@ export declare class ScoreUnionMergeStrategy implements IMergeStrategy {
|
|
|
1790
2693
|
*/
|
|
1791
2694
|
export declare function selectByQuery(entries: ReadonlyArray<IIndexedMemoryRecord>, query: IMemoryQuery): IMemoryRecord<unknown>[];
|
|
1792
2695
|
|
|
2696
|
+
/**
|
|
2697
|
+
* Select the current version from a set of an entity's versions: the newest
|
|
2698
|
+
* (highest `seq`) version whose `invalid_at` is null/absent. `undefined` when the
|
|
2699
|
+
* entity has no current version (fully invalidated / soft-deleted, or empty).
|
|
2700
|
+
* @public
|
|
2701
|
+
*/
|
|
2702
|
+
export declare function selectCurrentVersion(versions: ReadonlyArray<IMemoryRecord<unknown>>): IMemoryRecord<unknown> | undefined;
|
|
2703
|
+
|
|
2704
|
+
/**
|
|
2705
|
+
* Select the version of an entity valid at `asOf` (epoch ms): the newest
|
|
2706
|
+
* (highest `seq`) version whose validity interval contains `asOf`. `undefined`
|
|
2707
|
+
* when no version was valid at that instant.
|
|
2708
|
+
* @public
|
|
2709
|
+
*/
|
|
2710
|
+
export declare function selectVersionAsOf(versions: ReadonlyArray<IMemoryRecord<unknown>>, asOf: number): IMemoryRecord<unknown> | undefined;
|
|
2711
|
+
|
|
1793
2712
|
/**
|
|
1794
2713
|
* The loud-degradation message a retriever returns when `query.semantic` is set
|
|
1795
2714
|
* but no {@link IVectorIndex} is wired.
|
|
@@ -1843,6 +2762,14 @@ export declare function serializeMemoryFile(envelope: IMemoryEnvelope, body: str
|
|
|
1843
2762
|
*/
|
|
1844
2763
|
export declare function splitFrontmatter(raw: string): Result<IMemoryFileParts>;
|
|
1845
2764
|
|
|
2765
|
+
/**
|
|
2766
|
+
* The store-owned envelope fields fgv derives or stamps: `id` (from the codec),
|
|
2767
|
+
* and the transaction-time metadata (`seq` / `contentHash` / `created` /
|
|
2768
|
+
* `updated`). A {@link ICandidateRecord} supplies everything EXCEPT these.
|
|
2769
|
+
* @public
|
|
2770
|
+
*/
|
|
2771
|
+
export declare type StoreStampedEnvelopeField = 'id' | 'seq' | 'contentHash' | 'created' | 'updated';
|
|
2772
|
+
|
|
1846
2773
|
/**
|
|
1847
2774
|
* Returns records matching `query.filter`, narrowed by any scope / kind / tag
|
|
1848
2775
|
* pre-filter and recency-ordered. The predicate is this retriever's axis: a
|
|
@@ -1885,12 +2812,67 @@ export declare class TagRetriever implements IMemoryRetriever {
|
|
|
1885
2812
|
retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>>;
|
|
1886
2813
|
}
|
|
1887
2814
|
|
|
2815
|
+
/**
|
|
2816
|
+
* The capabilities every temporal retriever exposes: temporal "as-of" queries
|
|
2817
|
+
* are operational (semantic recall and link traversal are not this retriever's
|
|
2818
|
+
* concern).
|
|
2819
|
+
* @public
|
|
2820
|
+
*/
|
|
2821
|
+
export declare const TEMPORAL_CAPABILITIES: IMemoryRetrieverCapabilities;
|
|
2822
|
+
|
|
1888
2823
|
/**
|
|
1889
2824
|
* Converter for the optional {@link ITemporalBlock}.
|
|
1890
2825
|
* @public
|
|
1891
2826
|
*/
|
|
1892
2827
|
export declare const temporalConverter: Converter<ITemporalBlock>;
|
|
1893
2828
|
|
|
2829
|
+
/**
|
|
2830
|
+
* Identity codec for a versioned (temporal) kind family, resolving OQ-11 to the
|
|
2831
|
+
* subtree-per-entity layout: every version of an entity is a distinct file under
|
|
2832
|
+
* a per-entity subtree.
|
|
2833
|
+
*
|
|
2834
|
+
* @remarks
|
|
2835
|
+
* - `encode`: scope = `<baseScope>/entities/<entityId>`, idStem = `<entityId>`,
|
|
2836
|
+
* `isVersioned = true`. The idStem is the stable entity prefix; the store forms
|
|
2837
|
+
* each version's filename via {@link TemporalIdentityCodec.encodeVersion}.
|
|
2838
|
+
* - `encodeVersion`: version stem = `<entityId>-v<seq>`.
|
|
2839
|
+
* - `decode` / `decodeVersion`: recover `entityId` (and `seq`) from a
|
|
2840
|
+
* `(subtree scope, version stem)` pair; the scope is authoritative for the
|
|
2841
|
+
* `entityId`.
|
|
2842
|
+
* - Escaping: `baseScope` and `entityId` must each match the POSIX portable
|
|
2843
|
+
* filename set (they become path segments); `seq` is a non-negative integer.
|
|
2844
|
+
* - Layout: `vault/<baseScope>/entities/<entityId>/<entityId>-v<seq>.md`.
|
|
2845
|
+
* @public
|
|
2846
|
+
*/
|
|
2847
|
+
export declare class TemporalIdentityCodec implements ITemporalIdentityCodec {
|
|
2848
|
+
/** The fixed subtree segment separating an entity's versions from its scope. */
|
|
2849
|
+
static readonly entitiesSegment: string;
|
|
2850
|
+
/** The version-stem infix: `<entityId>` + this + `<seq>`. */
|
|
2851
|
+
static readonly versionInfix: string;
|
|
2852
|
+
/** A non-negative integer string (the version seq). */
|
|
2853
|
+
private static readonly _versionSeqRe;
|
|
2854
|
+
/** The base scope segment this codec's entities live under. */
|
|
2855
|
+
readonly baseScope: string;
|
|
2856
|
+
private constructor();
|
|
2857
|
+
/**
|
|
2858
|
+
* Family-convention factory. Validates that `baseScope` is a single portable
|
|
2859
|
+
* filename segment (it becomes the top-level path component).
|
|
2860
|
+
*/
|
|
2861
|
+
static create(baseScope: string): Result<TemporalIdentityCodec>;
|
|
2862
|
+
/** {@inheritDoc IIdentityCodec.encode} */
|
|
2863
|
+
encode(entityId: EntityId): Result<IIdentityCodecResult>;
|
|
2864
|
+
/** {@inheritDoc ITemporalIdentityCodec.encodeVersion} */
|
|
2865
|
+
encodeVersion(entityId: EntityId, seq: number): Result<string>;
|
|
2866
|
+
/** {@inheritDoc IIdentityCodec.decode} */
|
|
2867
|
+
decode(scope: MemoryScopeKey, encodedStem: string): Result<EntityId>;
|
|
2868
|
+
/** {@inheritDoc ITemporalIdentityCodec.decodeVersion} */
|
|
2869
|
+
decodeVersion(scope: MemoryScopeKey, stem: string): Result<ITemporalVersionAddress>;
|
|
2870
|
+
/** {@inheritDoc IIdentityCodec.verifyRoundTrip} */
|
|
2871
|
+
verifyRoundTrip(scope: MemoryScopeKey, stem: string): Result<true>;
|
|
2872
|
+
/** Validate and extract the `entityId` from a `<baseScope>/entities/<entityId>` scope. */
|
|
2873
|
+
private _entityIdFromScope;
|
|
2874
|
+
}
|
|
2875
|
+
|
|
1894
2876
|
/**
|
|
1895
2877
|
* Build the loud-degradation message a retriever returns when `query.asOf` is
|
|
1896
2878
|
* set but no temporal index is wired.
|
|
@@ -1898,4 +2880,54 @@ export declare const temporalConverter: Converter<ITemporalBlock>;
|
|
|
1898
2880
|
*/
|
|
1899
2881
|
export declare function temporalUnwiredMessage(kind?: Kind): string;
|
|
1900
2882
|
|
|
2883
|
+
/**
|
|
2884
|
+
* Write policy for a versioned (temporal) kind family, implementing
|
|
2885
|
+
* invalidate-don't-delete. Admission always accepts — history is retained, never
|
|
2886
|
+
* culled — and updates apply the same RFC-7386 merge patch as
|
|
2887
|
+
* {@link KnowledgeLwwPolicy}, restricted to the temporal mutable surface.
|
|
2888
|
+
*
|
|
2889
|
+
* @remarks
|
|
2890
|
+
* The policy does NOT perform the version file writes or set `invalid_at` — that
|
|
2891
|
+
* is the store's versioned write branch, driven by the kind's
|
|
2892
|
+
* {@link ITemporalIdentityCodec}. The policy's role is limited to admission and
|
|
2893
|
+
* the merge that forms the **new version's** content from the **current**
|
|
2894
|
+
* version plus the incoming patch (the merge-patch-under-versioning contract).
|
|
2895
|
+
*
|
|
2896
|
+
* - **Dedup scope.** `'entity'` — an identical re-put of the current content is a
|
|
2897
|
+
* no-op (the store compares the incoming content hash against the current
|
|
2898
|
+
* version), so identical writes do not spawn redundant versions.
|
|
2899
|
+
* - **Mutable surface.** `body` + the envelope metadata a consumer may revise
|
|
2900
|
+
* (`tags` / `links` / `provenance` / `embeddingRef`). `temporal` is NOT mutable
|
|
2901
|
+
* here — `valid_at` / `invalid_at` are set by the store's versioned branch.
|
|
2902
|
+
* @public
|
|
2903
|
+
*/
|
|
2904
|
+
export declare class TemporalVersionedPolicy implements IWritePolicy {
|
|
2905
|
+
/** The temporal mutable surface (mirrors {@link KnowledgeLwwPolicy}). */
|
|
2906
|
+
readonly mutableFields: ReadonlyArray<string>;
|
|
2907
|
+
/** Versioned kinds dedup per-entity against the current version (see the class remarks). */
|
|
2908
|
+
readonly dedupScope: DedupScope;
|
|
2909
|
+
/** Deep-clones the mutable view without RFC-7386 null-deletion semantics. */
|
|
2910
|
+
private readonly _cloneEditor;
|
|
2911
|
+
/** Applies the RFC-7386 merge patch. */
|
|
2912
|
+
private readonly _mergeEditor;
|
|
2913
|
+
private constructor();
|
|
2914
|
+
/**
|
|
2915
|
+
* Family-convention factory. Constructs the shared `JsonEditor` instances (one
|
|
2916
|
+
* for cloning, one for the RFC-7386 merge), rules disabled — the same merge
|
|
2917
|
+
* config as the shipped policies.
|
|
2918
|
+
*/
|
|
2919
|
+
static create(): Result<TemporalVersionedPolicy>;
|
|
2920
|
+
/** {@inheritDoc IWritePolicy.admit} */
|
|
2921
|
+
admit(__incoming: IMemoryRecord<unknown>, __existing: ReadonlyArray<IMemoryRecord<unknown>>): Result<AdmissionDecision>;
|
|
2922
|
+
/** {@inheritDoc IWritePolicy.applyUpdate} */
|
|
2923
|
+
applyUpdate(existing: IMemoryRecord<unknown>, patch: Record<string, unknown>): Result<IMemoryRecord<unknown>>;
|
|
2924
|
+
/**
|
|
2925
|
+
* Reassemble a record from the merged mutable view. `body` / `tags` / `links` /
|
|
2926
|
+
* `provenance` are required and may not be deleted by a patch; `embeddingRef`,
|
|
2927
|
+
* when dropped by the merge, is restored as `undefined` (absent) — the same
|
|
2928
|
+
* hash-stable semantics as {@link KnowledgeLwwPolicy}.
|
|
2929
|
+
*/
|
|
2930
|
+
private _rebuild;
|
|
2931
|
+
}
|
|
2932
|
+
|
|
1901
2933
|
export { }
|