@fgv/ts-agent-memory 5.1.0-49 → 5.1.0-50
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/dist/packlets/index/memoryIndex.js +23 -16
- package/dist/packlets/index/memoryIndex.js.map +1 -1
- package/dist/packlets/ingest/orchestrator.js +13 -1
- package/dist/packlets/ingest/orchestrator.js.map +1 -1
- package/dist/packlets/retrieve/linkTraversalRetriever.js +12 -26
- package/dist/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
- package/dist/packlets/retrieve/recencyRetriever.js +7 -7
- package/dist/packlets/retrieve/recencyRetriever.js.map +1 -1
- package/dist/packlets/retrieve/retriever.js +91 -10
- package/dist/packlets/retrieve/retriever.js.map +1 -1
- package/dist/packlets/retrieve/semanticRetriever.js +16 -16
- package/dist/packlets/retrieve/semanticRetriever.js.map +1 -1
- package/dist/packlets/retrieve/structuredFilterRetriever.js +7 -7
- package/dist/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
- package/dist/packlets/retrieve/tagRetriever.js +7 -7
- package/dist/packlets/retrieve/tagRetriever.js.map +1 -1
- package/dist/packlets/retrieve/temporalRetrievers.js +23 -20
- package/dist/packlets/retrieve/temporalRetrievers.js.map +1 -1
- package/dist/packlets/store/coverage.js +6 -0
- package/dist/packlets/store/coverage.js.map +1 -0
- package/dist/packlets/store/fileTreeMemoryStore.js +221 -79
- package/dist/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/dist/packlets/store/index.js +4 -0
- package/dist/packlets/store/index.js.map +1 -1
- package/dist/packlets/store/listSelection.js +36 -0
- package/dist/packlets/store/listSelection.js.map +1 -0
- package/dist/packlets/store/memoryStore.js +6 -0
- package/dist/packlets/store/memoryStore.js.map +1 -0
- package/dist/packlets/store/reconcile.js +6 -0
- package/dist/packlets/store/reconcile.js.map +1 -0
- package/dist/packlets/store/storeCoverage.js +102 -0
- package/dist/packlets/store/storeCoverage.js.map +1 -0
- package/dist/packlets/store/storeReconcile.js +122 -0
- package/dist/packlets/store/storeReconcile.js.map +1 -0
- package/dist/packlets/store/vectorMaintenance.js +116 -8
- package/dist/packlets/store/vectorMaintenance.js.map +1 -1
- package/dist/packlets/store/vectorRecordSource.js +44 -0
- package/dist/packlets/store/vectorRecordSource.js.map +1 -0
- package/dist/packlets/tools/memoryTools.js +25 -2
- package/dist/packlets/tools/memoryTools.js.map +1 -1
- package/dist/packlets/types/envelope.js +25 -0
- package/dist/packlets/types/envelope.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/recordResolver.js +6 -0
- package/dist/packlets/types/recordResolver.js.map +1 -0
- package/dist/packlets/types/temporal.js.map +1 -1
- package/dist/packlets/vector/inMemoryCosineIndex.js +39 -18
- package/dist/packlets/vector/inMemoryCosineIndex.js.map +1 -1
- package/dist/packlets/vector/inMemoryFragmentCosineIndex.js +67 -12
- package/dist/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
- package/dist/packlets/vector/rebuildHelpers.js +38 -0
- package/dist/packlets/vector/rebuildHelpers.js.map +1 -0
- package/dist/packlets/vector/vectorIndex.js.map +1 -1
- package/dist/ts-agent-memory.d.ts +1035 -106
- package/lib/packlets/index/memoryIndex.d.ts +118 -27
- package/lib/packlets/index/memoryIndex.d.ts.map +1 -1
- package/lib/packlets/index/memoryIndex.js +23 -16
- package/lib/packlets/index/memoryIndex.js.map +1 -1
- package/lib/packlets/ingest/orchestrator.d.ts.map +1 -1
- package/lib/packlets/ingest/orchestrator.js +13 -1
- package/lib/packlets/ingest/orchestrator.js.map +1 -1
- package/lib/packlets/retrieve/linkTraversalRetriever.d.ts +3 -10
- package/lib/packlets/retrieve/linkTraversalRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/linkTraversalRetriever.js +11 -25
- package/lib/packlets/retrieve/linkTraversalRetriever.js.map +1 -1
- package/lib/packlets/retrieve/recencyRetriever.d.ts +3 -3
- package/lib/packlets/retrieve/recencyRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/recencyRetriever.js +6 -6
- package/lib/packlets/retrieve/recencyRetriever.js.map +1 -1
- package/lib/packlets/retrieve/retriever.d.ts +88 -7
- package/lib/packlets/retrieve/retriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/retriever.js +94 -9
- package/lib/packlets/retrieve/retriever.js.map +1 -1
- package/lib/packlets/retrieve/semanticRetriever.d.ts +3 -5
- package/lib/packlets/retrieve/semanticRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/semanticRetriever.js +15 -15
- package/lib/packlets/retrieve/semanticRetriever.js.map +1 -1
- package/lib/packlets/retrieve/structuredFilterRetriever.d.ts +3 -3
- package/lib/packlets/retrieve/structuredFilterRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/structuredFilterRetriever.js +6 -6
- package/lib/packlets/retrieve/structuredFilterRetriever.js.map +1 -1
- package/lib/packlets/retrieve/tagRetriever.d.ts +3 -3
- package/lib/packlets/retrieve/tagRetriever.d.ts.map +1 -1
- package/lib/packlets/retrieve/tagRetriever.js +6 -6
- package/lib/packlets/retrieve/tagRetriever.js.map +1 -1
- package/lib/packlets/retrieve/temporalRetrievers.d.ts +7 -5
- package/lib/packlets/retrieve/temporalRetrievers.d.ts.map +1 -1
- package/lib/packlets/retrieve/temporalRetrievers.js +22 -19
- package/lib/packlets/retrieve/temporalRetrievers.js.map +1 -1
- package/lib/packlets/store/coverage.d.ts +102 -0
- package/lib/packlets/store/coverage.d.ts.map +1 -0
- package/lib/packlets/store/coverage.js +7 -0
- package/lib/packlets/store/coverage.js.map +1 -0
- package/lib/packlets/store/fileTreeMemoryStore.d.ts +53 -166
- package/lib/packlets/store/fileTreeMemoryStore.d.ts.map +1 -1
- package/lib/packlets/store/fileTreeMemoryStore.js +221 -79
- package/lib/packlets/store/fileTreeMemoryStore.js.map +1 -1
- package/lib/packlets/store/index.d.ts +4 -0
- package/lib/packlets/store/index.d.ts.map +1 -1
- package/lib/packlets/store/index.js +4 -0
- package/lib/packlets/store/index.js.map +1 -1
- package/lib/packlets/store/listSelection.d.ts +101 -0
- package/lib/packlets/store/listSelection.d.ts.map +1 -0
- package/lib/packlets/store/listSelection.js +40 -0
- package/lib/packlets/store/listSelection.js.map +1 -0
- package/lib/packlets/store/memoryStore.d.ts +237 -0
- package/lib/packlets/store/memoryStore.d.ts.map +1 -0
- package/lib/packlets/store/memoryStore.js +7 -0
- package/lib/packlets/store/memoryStore.js.map +1 -0
- package/lib/packlets/store/reconcile.d.ts +82 -0
- package/lib/packlets/store/reconcile.d.ts.map +1 -0
- package/lib/packlets/store/reconcile.js +7 -0
- package/lib/packlets/store/reconcile.js.map +1 -0
- package/lib/packlets/store/storeCoverage.d.ts +45 -0
- package/lib/packlets/store/storeCoverage.d.ts.map +1 -0
- package/lib/packlets/store/storeCoverage.js +105 -0
- package/lib/packlets/store/storeCoverage.js.map +1 -0
- package/lib/packlets/store/storeReconcile.d.ts +41 -0
- package/lib/packlets/store/storeReconcile.d.ts.map +1 -0
- package/lib/packlets/store/storeReconcile.js +125 -0
- package/lib/packlets/store/storeReconcile.js.map +1 -0
- package/lib/packlets/store/vectorMaintenance.d.ts +74 -0
- package/lib/packlets/store/vectorMaintenance.d.ts.map +1 -1
- package/lib/packlets/store/vectorMaintenance.js +117 -8
- package/lib/packlets/store/vectorMaintenance.js.map +1 -1
- package/lib/packlets/store/vectorRecordSource.d.ts +36 -0
- package/lib/packlets/store/vectorRecordSource.d.ts.map +1 -0
- package/lib/packlets/store/vectorRecordSource.js +47 -0
- package/lib/packlets/store/vectorRecordSource.js.map +1 -0
- package/lib/packlets/tools/memoryTools.d.ts.map +1 -1
- package/lib/packlets/tools/memoryTools.js +25 -2
- package/lib/packlets/tools/memoryTools.js.map +1 -1
- package/lib/packlets/types/envelope.d.ts +24 -2
- package/lib/packlets/types/envelope.d.ts.map +1 -1
- package/lib/packlets/types/envelope.js +26 -0
- package/lib/packlets/types/envelope.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/recordResolver.d.ts +39 -0
- package/lib/packlets/types/recordResolver.d.ts.map +1 -0
- package/lib/packlets/types/recordResolver.js +7 -0
- package/lib/packlets/types/recordResolver.js.map +1 -0
- package/lib/packlets/types/temporal.d.ts +26 -6
- package/lib/packlets/types/temporal.d.ts.map +1 -1
- package/lib/packlets/types/temporal.js.map +1 -1
- package/lib/packlets/vector/inMemoryCosineIndex.d.ts +9 -2
- package/lib/packlets/vector/inMemoryCosineIndex.d.ts.map +1 -1
- package/lib/packlets/vector/inMemoryCosineIndex.js +40 -19
- package/lib/packlets/vector/inMemoryCosineIndex.js.map +1 -1
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts +6 -3
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.d.ts.map +1 -1
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.js +66 -11
- package/lib/packlets/vector/inMemoryFragmentCosineIndex.js.map +1 -1
- package/lib/packlets/vector/rebuildHelpers.d.ts +30 -0
- package/lib/packlets/vector/rebuildHelpers.d.ts.map +1 -0
- package/lib/packlets/vector/rebuildHelpers.js +42 -0
- package/lib/packlets/vector/rebuildHelpers.js.map +1 -0
- package/lib/packlets/vector/vectorIndex.d.ts +270 -15
- package/lib/packlets/vector/vectorIndex.d.ts.map +1 -1
- package/lib/packlets/vector/vectorIndex.js.map +1 -1
- package/package.json +7 -7
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MIT
|
|
4
4
|
*/
|
|
5
5
|
import { succeed } from '@fgv/ts-utils';
|
|
6
|
-
import { NON_SEMANTIC_CAPABILITIES, guardRetrieverCapabilities,
|
|
6
|
+
import { NON_SEMANTIC_CAPABILITIES, guardRetrieverCapabilities, resolveQuery } from './retriever';
|
|
7
7
|
/**
|
|
8
8
|
* Returns records carrying `query.tag`, recency-ordered within the tag and
|
|
9
9
|
* narrowed by any scope / kind / provenance-source / predicate filters. Tag is this retriever's
|
|
@@ -12,16 +12,17 @@ import { NON_SEMANTIC_CAPABILITIES, guardRetrieverCapabilities, limitRecords, or
|
|
|
12
12
|
* @public
|
|
13
13
|
*/
|
|
14
14
|
export class TagRetriever {
|
|
15
|
-
constructor(
|
|
16
|
-
this._index = index;
|
|
15
|
+
constructor(params) {
|
|
16
|
+
this._index = params.index;
|
|
17
|
+
this._resolver = params.resolver;
|
|
17
18
|
}
|
|
18
19
|
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
19
20
|
get capabilities() {
|
|
20
21
|
return NON_SEMANTIC_CAPABILITIES;
|
|
21
22
|
}
|
|
22
23
|
/** Family-convention factory. */
|
|
23
|
-
static create(
|
|
24
|
-
return succeed(new TagRetriever(
|
|
24
|
+
static create(params) {
|
|
25
|
+
return succeed(new TagRetriever(params));
|
|
25
26
|
}
|
|
26
27
|
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
27
28
|
retrieve(query) {
|
|
@@ -29,8 +30,7 @@ export class TagRetriever {
|
|
|
29
30
|
if (query.tag === undefined) {
|
|
30
31
|
return succeed([]);
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
-
return succeed(limitRecords(ordered, query.limit, query.offset));
|
|
33
|
+
return resolveQuery(this._index.entries(), query, this._resolver);
|
|
34
34
|
}));
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tagRetriever.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/tagRetriever.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAU,OAAO,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,
|
|
1
|
+
{"version":3,"file":"tagRetriever.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/tagRetriever.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAU,OAAO,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAKL,yBAAyB,EACzB,0BAA0B,EAC1B,YAAY,EACb,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,MAAM,OAAO,YAAY;IAIvB,YAAoB,MAA8B;QAChD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC;IACnC,CAAC;IAED,kDAAkD;IAClD,IAAW,YAAY;QACrB,OAAO,yBAAyB,CAAC;IACnC,CAAC;IAED,iCAAiC;IAC1B,MAAM,CAAC,MAAM,CAAC,MAA8B;QACjD,OAAO,OAAO,CAAC,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,8CAA8C;IACvC,QAAQ,CAAC,KAAmB;QACjC,OAAO,OAAO,CAAC,OAAO,CACpB,0BAA0B,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE;YAClE,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC;YACrB,CAAC;YACD,OAAO,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACpE,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;CACF","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, succeed } from '@fgv/ts-utils';\nimport { IMemoryRecord, IMemoryRecordResolver } from '../types';\nimport { IMemoryIndex } from '../index';\nimport {\n IMemoryQuery,\n IMemoryRetriever,\n IMemoryRetrieverCapabilities,\n IRetrieverCreateParams,\n NON_SEMANTIC_CAPABILITIES,\n guardRetrieverCapabilities,\n resolveQuery\n} from './retriever';\n\n/**\n * Returns records carrying `query.tag`, recency-ordered within the tag and\n * narrowed by any scope / kind / provenance-source / predicate filters. Tag is this retriever's\n * axis: a query without a `tag` is not its concern and yields an empty success\n * (so it contributes nothing to a {@link HybridRetriever}, rather than failing).\n * @public\n */\nexport class TagRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n private readonly _resolver: IMemoryRecordResolver;\n\n private constructor(params: IRetrieverCreateParams) {\n this._index = params.index;\n this._resolver = params.resolver;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return NON_SEMANTIC_CAPABILITIES;\n }\n\n /** Family-convention factory. */\n public static create(params: IRetrieverCreateParams): Result<TagRetriever> {\n return succeed(new TagRetriever(params));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n return Promise.resolve(\n guardRetrieverCapabilities(query, this.capabilities).onSuccess(() => {\n if (query.tag === undefined) {\n return succeed([]);\n }\n return resolveQuery(this._index.entries(), query, this._resolver);\n })\n );\n }\n}\n"]}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { succeed } from '@fgv/ts-utils';
|
|
6
6
|
import { isTemporalRecord, selectCurrentVersion, selectVersionAsOf } from '../types';
|
|
7
|
-
import { guardRetrieverCapabilities, indexedRecordMatchesQuery,
|
|
7
|
+
import { guardRetrieverCapabilities, indexedRecordMatchesQuery, materializePage, recencyCompare } from './retriever';
|
|
8
8
|
/**
|
|
9
9
|
* The capabilities every temporal retriever exposes: temporal "as-of" queries
|
|
10
10
|
* are operational (semantic recall and link traversal are not this retriever's
|
|
@@ -25,16 +25,16 @@ export const TEMPORAL_CAPABILITIES = {
|
|
|
25
25
|
function groupTemporalVersionsByEntity(index, query) {
|
|
26
26
|
const groups = new Map();
|
|
27
27
|
for (const entry of index.entries()) {
|
|
28
|
-
if (!isTemporalRecord(entry
|
|
28
|
+
if (!isTemporalRecord(entry) || !indexedRecordMatchesQuery(entry, query)) {
|
|
29
29
|
continue;
|
|
30
30
|
}
|
|
31
|
-
const key = `${entry.
|
|
31
|
+
const key = `${entry.envelope.kind}\0${entry.envelope.entityId}`;
|
|
32
32
|
const existing = groups.get(key);
|
|
33
33
|
if (existing === undefined) {
|
|
34
|
-
groups.set(key, [entry
|
|
34
|
+
groups.set(key, [entry]);
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
|
-
existing.push(entry
|
|
37
|
+
existing.push(entry);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
return groups;
|
|
@@ -47,16 +47,17 @@ function groupTemporalVersionsByEntity(index, query) {
|
|
|
47
47
|
* @public
|
|
48
48
|
*/
|
|
49
49
|
export class CurrentValidRetriever {
|
|
50
|
-
constructor(
|
|
51
|
-
this._index = index;
|
|
50
|
+
constructor(params) {
|
|
51
|
+
this._index = params.index;
|
|
52
|
+
this._resolver = params.resolver;
|
|
52
53
|
}
|
|
53
54
|
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
54
55
|
get capabilities() {
|
|
55
56
|
return TEMPORAL_CAPABILITIES;
|
|
56
57
|
}
|
|
57
58
|
/** Family-convention factory. */
|
|
58
|
-
static create(
|
|
59
|
-
return succeed(new CurrentValidRetriever(
|
|
59
|
+
static create(params) {
|
|
60
|
+
return succeed(new CurrentValidRetriever(params));
|
|
60
61
|
}
|
|
61
62
|
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
62
63
|
retrieve(query) {
|
|
@@ -69,7 +70,7 @@ export class CurrentValidRetriever {
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
selected.sort(recencyCompare);
|
|
72
|
-
return
|
|
73
|
+
return materializePage(selected, query, this._resolver);
|
|
73
74
|
}));
|
|
74
75
|
}
|
|
75
76
|
}
|
|
@@ -82,16 +83,17 @@ export class CurrentValidRetriever {
|
|
|
82
83
|
* @public
|
|
83
84
|
*/
|
|
84
85
|
export class AsOfRetriever {
|
|
85
|
-
constructor(
|
|
86
|
-
this._index = index;
|
|
86
|
+
constructor(params) {
|
|
87
|
+
this._index = params.index;
|
|
88
|
+
this._resolver = params.resolver;
|
|
87
89
|
}
|
|
88
90
|
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
89
91
|
get capabilities() {
|
|
90
92
|
return TEMPORAL_CAPABILITIES;
|
|
91
93
|
}
|
|
92
94
|
/** Family-convention factory. */
|
|
93
|
-
static create(
|
|
94
|
-
return succeed(new AsOfRetriever(
|
|
95
|
+
static create(params) {
|
|
96
|
+
return succeed(new AsOfRetriever(params));
|
|
95
97
|
}
|
|
96
98
|
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
97
99
|
retrieve(query) {
|
|
@@ -108,7 +110,7 @@ export class AsOfRetriever {
|
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
selected.sort(recencyCompare);
|
|
111
|
-
return
|
|
113
|
+
return materializePage(selected, query, this._resolver);
|
|
112
114
|
}));
|
|
113
115
|
}
|
|
114
116
|
}
|
|
@@ -126,16 +128,17 @@ export class AsOfRetriever {
|
|
|
126
128
|
* @public
|
|
127
129
|
*/
|
|
128
130
|
export class HistoryRetriever {
|
|
129
|
-
constructor(
|
|
130
|
-
this._index = index;
|
|
131
|
+
constructor(params) {
|
|
132
|
+
this._index = params.index;
|
|
133
|
+
this._resolver = params.resolver;
|
|
131
134
|
}
|
|
132
135
|
/** {@inheritDoc IMemoryRetriever.capabilities} */
|
|
133
136
|
get capabilities() {
|
|
134
137
|
return TEMPORAL_CAPABILITIES;
|
|
135
138
|
}
|
|
136
139
|
/** Family-convention factory. */
|
|
137
|
-
static create(
|
|
138
|
-
return succeed(new HistoryRetriever(
|
|
140
|
+
static create(params) {
|
|
141
|
+
return succeed(new HistoryRetriever(params));
|
|
139
142
|
}
|
|
140
143
|
/** {@inheritDoc IMemoryRetriever.retrieve} */
|
|
141
144
|
retrieve(query) {
|
|
@@ -145,7 +148,7 @@ export class HistoryRetriever {
|
|
|
145
148
|
history.push(...versions);
|
|
146
149
|
}
|
|
147
150
|
history.sort(HistoryRetriever._byValidAtAscending);
|
|
148
|
-
return
|
|
151
|
+
return materializePage(history, query, this._resolver);
|
|
149
152
|
}));
|
|
150
153
|
}
|
|
151
154
|
/** A version's world-truth start: its `valid_at`, defaulting to `created` when absent. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temporalRetrievers.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/temporalRetrievers.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, succeed } from '@fgv/ts-utils';\nimport { IMemoryRecord, isTemporalRecord, selectCurrentVersion, selectVersionAsOf } from '../types';\nimport { IMemoryIndex } from '../index';\nimport {\n IMemoryQuery,\n IMemoryRetriever,\n IMemoryRetrieverCapabilities,\n guardRetrieverCapabilities,\n indexedRecordMatchesQuery,\n limitRecords,\n recencyCompare\n} from './retriever';\n\n/**\n * The capabilities every temporal retriever exposes: temporal \"as-of\" queries\n * are operational (semantic recall and link traversal are not this retriever's\n * concern).\n * @public\n */\nexport const TEMPORAL_CAPABILITIES: IMemoryRetrieverCapabilities = {\n supportsSemanticRecall: false,\n supportsTemporalQuery: true,\n supportsLinkTraversal: false\n};\n\n/**\n * Group the temporal records surviving a query's scope / kind / tag / provenance-source / predicate\n * pre-filter by entity (`kind` + `entityId`). Non-temporal records are excluded —\n * the temporal retrievers operate only over versioned entities. The map values\n * are each entity's versions (unordered).\n */\nfunction groupTemporalVersionsByEntity(\n index: IMemoryIndex,\n query: IMemoryQuery\n): Map<string, IMemoryRecord<unknown>[]> {\n const groups: Map<string, IMemoryRecord<unknown>[]> = new Map<string, IMemoryRecord<unknown>[]>();\n for (const entry of index.entries()) {\n if (!isTemporalRecord(entry.record) || !indexedRecordMatchesQuery(entry, query)) {\n continue;\n }\n const key: string = `${entry.record.envelope.kind}\\0${entry.record.envelope.entityId}`;\n const existing: IMemoryRecord<unknown>[] | undefined = groups.get(key);\n if (existing === undefined) {\n groups.set(key, [entry.record]);\n } else {\n existing.push(entry.record);\n }\n }\n return groups;\n}\n\n/**\n * Temporal retriever returning the **current** version of each temporal entity\n * matching the query (the newest version whose `invalid_at` is null/absent),\n * recency-ordered and limited. A fully-invalidated (soft-deleted) entity\n * contributes nothing. Non-temporal records are not this retriever's concern.\n * @public\n */\nexport class CurrentValidRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n\n private constructor(index: IMemoryIndex) {\n this._index = index;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return TEMPORAL_CAPABILITIES;\n }\n\n /** Family-convention factory. */\n public static create(index: IMemoryIndex): Result<CurrentValidRetriever> {\n return succeed(new CurrentValidRetriever(index));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n return Promise.resolve(\n guardRetrieverCapabilities(query, this.capabilities).onSuccess(() => {\n const selected: IMemoryRecord<unknown>[] = [];\n for (const versions of groupTemporalVersionsByEntity(this._index, query).values()) {\n const current: IMemoryRecord<unknown> | undefined = selectCurrentVersion(versions);\n if (current !== undefined) {\n selected.push(current);\n }\n }\n selected.sort(recencyCompare);\n return succeed(limitRecords(selected, query.limit, query.offset));\n })\n );\n }\n}\n\n/**\n * Temporal retriever returning, for each temporal entity matching the query, the\n * version valid at `query.asOf` (epoch ms). `asOf` is this retriever's axis: a\n * query without it yields an empty success (a no-op contribution to a\n * {@link HybridRetriever}, not a failure). Results are recency-ordered and\n * limited.\n * @public\n */\nexport class AsOfRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n\n private constructor(index: IMemoryIndex) {\n this._index = index;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return TEMPORAL_CAPABILITIES;\n }\n\n /** Family-convention factory. */\n public static create(index: IMemoryIndex): Result<AsOfRetriever> {\n return succeed(new AsOfRetriever(index));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n return Promise.resolve(\n guardRetrieverCapabilities(query, this.capabilities).onSuccess(() => {\n if (query.asOf === undefined) {\n return succeed([]);\n }\n const asOf: number = query.asOf;\n const selected: IMemoryRecord<unknown>[] = [];\n for (const versions of groupTemporalVersionsByEntity(this._index, query).values()) {\n const valid: IMemoryRecord<unknown> | undefined = selectVersionAsOf(versions, asOf);\n if (valid !== undefined) {\n selected.push(valid);\n }\n }\n selected.sort(recencyCompare);\n return succeed(limitRecords(selected, query.limit, query.offset));\n })\n );\n }\n}\n\n/**\n * Temporal retriever returning **every** version of each temporal entity matching\n * the query, ordered ascending by `valid_at` (then `seq` as a stable tiebreak) —\n * the entity's full history. Limited after ordering.\n *\n * @remarks\n * When the query matches more than one entity, the result is a single\n * CROSS-entity list globally sorted by `valid_at` — versions of different\n * entities interleave, NOT grouped per entity — so `limit` truncates that\n * globally-sorted list. Constrain to one entity (e.g. via `query.scope`) for a\n * single entity's contiguous history.\n * @public\n */\nexport class HistoryRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n\n private constructor(index: IMemoryIndex) {\n this._index = index;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return TEMPORAL_CAPABILITIES;\n }\n\n /** Family-convention factory. */\n public static create(index: IMemoryIndex): Result<HistoryRetriever> {\n return succeed(new HistoryRetriever(index));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n return Promise.resolve(\n guardRetrieverCapabilities(query, this.capabilities).onSuccess(() => {\n const history: IMemoryRecord<unknown>[] = [];\n for (const versions of groupTemporalVersionsByEntity(this._index, query).values()) {\n history.push(...versions);\n }\n history.sort(HistoryRetriever._byValidAtAscending);\n return succeed(limitRecords(history, query.limit, query.offset));\n })\n );\n }\n\n /** A version's world-truth start: its `valid_at`, defaulting to `created` when absent. */\n private static _startOf(record: IMemoryRecord<unknown>): number {\n const temporal: IMemoryRecord<unknown>['envelope']['temporal'] = record.envelope.temporal;\n /* c8 ignore next 3 -- unreachable: HistoryRetriever orders only temporal records (pre-filtered by isTemporalRecord), so `temporal` is always present; the guard keeps the type honest */\n if (temporal === undefined) {\n return record.envelope.created;\n }\n return temporal.valid_at ?? record.envelope.created;\n }\n\n /**\n * Ascending-by-`valid_at` comparator (a version's `valid_at` defaults to its\n * `created` when absent), with `seq` as a stable ascending tiebreak so\n * same-instant versions order by write sequence.\n */\n private static _byValidAtAscending(a: IMemoryRecord<unknown>, b: IMemoryRecord<unknown>): number {\n const aStart: number = HistoryRetriever._startOf(a);\n const bStart: number = HistoryRetriever._startOf(b);\n return aStart !== bStart ? aStart - bStart : a.envelope.seq - b.envelope.seq;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"temporalRetrievers.js","sourceRoot":"","sources":["../../../src/packlets/retrieve/temporalRetrievers.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Result, succeed } from '@fgv/ts-utils';\nimport {\n IMemoryRecord,\n IMemoryRecordResolver,\n isTemporalRecord,\n selectCurrentVersion,\n selectVersionAsOf\n} from '../types';\nimport { IIndexedMemoryEntry, IMemoryIndex } from '../index';\nimport {\n IMemoryQuery,\n IMemoryRetriever,\n IMemoryRetrieverCapabilities,\n IRetrieverCreateParams,\n guardRetrieverCapabilities,\n indexedRecordMatchesQuery,\n materializePage,\n recencyCompare\n} from './retriever';\n\n/**\n * The capabilities every temporal retriever exposes: temporal \"as-of\" queries\n * are operational (semantic recall and link traversal are not this retriever's\n * concern).\n * @public\n */\nexport const TEMPORAL_CAPABILITIES: IMemoryRetrieverCapabilities = {\n supportsSemanticRecall: false,\n supportsTemporalQuery: true,\n supportsLinkTraversal: false\n};\n\n/**\n * Group the temporal records surviving a query's scope / kind / tag / provenance-source / predicate\n * pre-filter by entity (`kind` + `entityId`). Non-temporal records are excluded —\n * the temporal retrievers operate only over versioned entities. The map values\n * are each entity's versions (unordered).\n */\nfunction groupTemporalVersionsByEntity(\n index: IMemoryIndex,\n query: IMemoryQuery\n): Map<string, IIndexedMemoryEntry[]> {\n const groups: Map<string, IIndexedMemoryEntry[]> = new Map<string, IIndexedMemoryEntry[]>();\n for (const entry of index.entries()) {\n if (!isTemporalRecord(entry) || !indexedRecordMatchesQuery(entry, query)) {\n continue;\n }\n const key: string = `${entry.envelope.kind}\\0${entry.envelope.entityId}`;\n const existing: IIndexedMemoryEntry[] | undefined = groups.get(key);\n if (existing === undefined) {\n groups.set(key, [entry]);\n } else {\n existing.push(entry);\n }\n }\n return groups;\n}\n\n/**\n * Temporal retriever returning the **current** version of each temporal entity\n * matching the query (the newest version whose `invalid_at` is null/absent),\n * recency-ordered and limited. A fully-invalidated (soft-deleted) entity\n * contributes nothing. Non-temporal records are not this retriever's concern.\n * @public\n */\nexport class CurrentValidRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n private readonly _resolver: IMemoryRecordResolver;\n\n private constructor(params: IRetrieverCreateParams) {\n this._index = params.index;\n this._resolver = params.resolver;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return TEMPORAL_CAPABILITIES;\n }\n\n /** Family-convention factory. */\n public static create(params: IRetrieverCreateParams): Result<CurrentValidRetriever> {\n return succeed(new CurrentValidRetriever(params));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n return Promise.resolve(\n guardRetrieverCapabilities(query, this.capabilities).onSuccess(() => {\n const selected: IIndexedMemoryEntry[] = [];\n for (const versions of groupTemporalVersionsByEntity(this._index, query).values()) {\n const current: IIndexedMemoryEntry | undefined = selectCurrentVersion(versions);\n if (current !== undefined) {\n selected.push(current);\n }\n }\n selected.sort(recencyCompare);\n return materializePage(selected, query, this._resolver);\n })\n );\n }\n}\n\n/**\n * Temporal retriever returning, for each temporal entity matching the query, the\n * version valid at `query.asOf` (epoch ms). `asOf` is this retriever's axis: a\n * query without it yields an empty success (a no-op contribution to a\n * {@link HybridRetriever}, not a failure). Results are recency-ordered and\n * limited.\n * @public\n */\nexport class AsOfRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n private readonly _resolver: IMemoryRecordResolver;\n\n private constructor(params: IRetrieverCreateParams) {\n this._index = params.index;\n this._resolver = params.resolver;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return TEMPORAL_CAPABILITIES;\n }\n\n /** Family-convention factory. */\n public static create(params: IRetrieverCreateParams): Result<AsOfRetriever> {\n return succeed(new AsOfRetriever(params));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n return Promise.resolve(\n guardRetrieverCapabilities(query, this.capabilities).onSuccess(() => {\n if (query.asOf === undefined) {\n return succeed([]);\n }\n const asOf: number = query.asOf;\n const selected: IIndexedMemoryEntry[] = [];\n for (const versions of groupTemporalVersionsByEntity(this._index, query).values()) {\n const valid: IIndexedMemoryEntry | undefined = selectVersionAsOf(versions, asOf);\n if (valid !== undefined) {\n selected.push(valid);\n }\n }\n selected.sort(recencyCompare);\n return materializePage(selected, query, this._resolver);\n })\n );\n }\n}\n\n/**\n * Temporal retriever returning **every** version of each temporal entity matching\n * the query, ordered ascending by `valid_at` (then `seq` as a stable tiebreak) —\n * the entity's full history. Limited after ordering.\n *\n * @remarks\n * When the query matches more than one entity, the result is a single\n * CROSS-entity list globally sorted by `valid_at` — versions of different\n * entities interleave, NOT grouped per entity — so `limit` truncates that\n * globally-sorted list. Constrain to one entity (e.g. via `query.scope`) for a\n * single entity's contiguous history.\n * @public\n */\nexport class HistoryRetriever implements IMemoryRetriever {\n private readonly _index: IMemoryIndex;\n private readonly _resolver: IMemoryRecordResolver;\n\n private constructor(params: IRetrieverCreateParams) {\n this._index = params.index;\n this._resolver = params.resolver;\n }\n\n /** {@inheritDoc IMemoryRetriever.capabilities} */\n public get capabilities(): IMemoryRetrieverCapabilities {\n return TEMPORAL_CAPABILITIES;\n }\n\n /** Family-convention factory. */\n public static create(params: IRetrieverCreateParams): Result<HistoryRetriever> {\n return succeed(new HistoryRetriever(params));\n }\n\n /** {@inheritDoc IMemoryRetriever.retrieve} */\n public retrieve(query: IMemoryQuery): Promise<Result<ReadonlyArray<IMemoryRecord<unknown>>>> {\n return Promise.resolve(\n guardRetrieverCapabilities(query, this.capabilities).onSuccess(() => {\n const history: IIndexedMemoryEntry[] = [];\n for (const versions of groupTemporalVersionsByEntity(this._index, query).values()) {\n history.push(...versions);\n }\n history.sort(HistoryRetriever._byValidAtAscending);\n return materializePage(history, query, this._resolver);\n })\n );\n }\n\n /** A version's world-truth start: its `valid_at`, defaulting to `created` when absent. */\n private static _startOf(record: IIndexedMemoryEntry): number {\n const temporal: IMemoryRecord<unknown>['envelope']['temporal'] = record.envelope.temporal;\n /* c8 ignore next 3 -- unreachable: HistoryRetriever orders only temporal records (pre-filtered by isTemporalRecord), so `temporal` is always present; the guard keeps the type honest */\n if (temporal === undefined) {\n return record.envelope.created;\n }\n return temporal.valid_at ?? record.envelope.created;\n }\n\n /**\n * Ascending-by-`valid_at` comparator (a version's `valid_at` defaults to its\n * `created` when absent), with `seq` as a stable ascending tiebreak so\n * same-instant versions order by write sequence.\n */\n private static _byValidAtAscending(a: IIndexedMemoryEntry, b: IIndexedMemoryEntry): number {\n const aStart: number = HistoryRetriever._startOf(a);\n const bStart: number = HistoryRetriever._startOf(b);\n return aStart !== bStart ? aStart - bStart : a.envelope.seq - b.envelope.seq;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../../src/packlets/store/coverage.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*\n * Copyright (c) 2026 Erik Fortune\n * SPDX-License-Identifier: MIT\n */\n\nimport { Kind } from '../types';\n\n/**\n * How much of one derived artifact exists, for one {@link Kind}.\n *\n * @remarks\n * Two numbers rather than a percentage, deliberately: a ratio cannot express\n * *\"nothing was expected\"*, and a kind that is intentionally not derived (an\n * excluded kind, a kind with no projector) is a normal and healthy state that a\n * `0%` would render as an alarm.\n * @public\n */\nexport interface IArtifactCoverage {\n /**\n * Records of this kind the store would derive this artifact for, **after** any\n * exclusion. Read against {@link IDerivedStateCoverage.records} for the same\n * kind: `records: 40, expected: 0` is the exclusion story, stated rather than\n * inferred.\n */\n readonly expected: number;\n /**\n * Of those, how many the **store believes** are covered. See\n * {@link IIndexCoverage.indexSize} for why the word \"believes\" is load-bearing.\n */\n readonly covered: number;\n}\n\n/**\n * Coverage of the record-granular vector index.\n * @public\n */\nexport interface IIndexCoverage {\n /** Per-kind expected/covered, derived from the envelope walk. */\n readonly perKind: ReadonlyMap<Kind, IArtifactCoverage>;\n /**\n * What the index **actually holds**, whole-index.\n *\n * @remarks\n * **This is a fact and {@link IArtifactCoverage.covered} is a belief, and the\n * two are reported separately because their disagreement is the only free\n * signal that distinguishes a persistent index from a fresh one.** `covered`\n * counts envelopes carrying an `embeddingRef`; `indexSize` counts vectors. With\n * a persistent index they agree. With an in-memory index at open they do not —\n * the envelopes still claim references from previous sessions while the index\n * holds nothing, so `covered` **lies, in the confident direction**.\n *\n * Collapsing them into one \"coverage %\" would destroy that signal, which is why\n * this type does not offer one.\n */\n readonly indexSize: number;\n}\n\n/**\n * Coverage of the fragment-granular vector index.\n *\n * @remarks\n * **Aggregate only, and the reason is structural rather than an omission.** The\n * record lane has a per-record marker on the envelope (`embeddingRef`), so its\n * numerator falls out of the same free walk that produces the denominator. The\n * fragment lane has **no envelope marker at all** — nothing on a record says\n * whether it has fragments — so a per-kind numerator would cost one\n * `IFragmentVectorIndex.has` call per record, and coverage is contractually\n * cheap (see {@link IMemoryStore.coverage}).\n *\n * The per-kind **denominator** is still available on\n * {@link IDerivedStateCoverage.records}. A caller who needs the per-kind\n * numerator runs `reconcile(kind, 'fragment-vector')`, which reports it because\n * it is already paying for the walk.\n * @public\n */\nexport interface IFragmentIndexCoverage {\n /** Records with at least one fragment held. Mirrors `IFragmentVectorIndex.recordCount`. */\n readonly indexRecordCount: number;\n /** Total fragments held — the fan-out. Mirrors `IFragmentVectorIndex.fragmentCount`. */\n readonly indexFragmentCount: number;\n}\n\n/**\n * A snapshot of how much of the store's **derived state** exists, resolved by\n * {@link Kind} — the answer to *\"is my derived state consistent with my\n * records?\"*.\n *\n * @remarks\n * **Absent is not zero.** Each artifact member is optional, and `undefined` means\n * *this artifact is not derived here at all* — no rank projector is registered,\n * or that index lane is not wired. It never means *nothing is covered*. Folding\n * the two would make a health surface render a confident `0%` for a feature the\n * deployment deliberately did not turn on, which is the same defect as\n * `embeddingRef`'s three-way ambiguity one level up.\n *\n * So: `fragmentVectors: undefined` is a store with no fragment index and is not a\n * problem. `fragmentVectors: { indexRecordCount: 0, indexFragmentCount: 0 }` is a\n * wired fragment index holding nothing, and probably is.\n * @public\n */\nexport interface IDerivedStateCoverage {\n /** Records per kind — the denominator every other number is read against. */\n readonly records: ReadonlyMap<Kind, number>;\n /** Absent when no kind has a registered {@link RankProjector}. */\n readonly rank?: ReadonlyMap<Kind, IArtifactCoverage>;\n /** Absent when the record-vector lane is not wired. */\n readonly recordVectors?: IIndexCoverage;\n /** Absent when the fragment lane is not wired. */\n readonly fragmentVectors?: IFragmentIndexCoverage;\n}\n"]}
|