dsh-mnemon-source-memory-spaces 0.5.15 → 0.5.17
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/lib/client.js +462 -88
- package/lib/contracts.d.ts +44 -2
- package/lib/contracts.js +8 -1
- package/lib/{definitions-DwiEZSE_.d.ts → definitions-CtjNSwBS.d.ts} +20 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.js +404 -58
- package/lib/provider-sdk.d.ts +2 -2
- package/lib/testing.d.ts +1 -1
- package/lib/types/client/api.d.ts +5 -1
- package/lib/types/contracts.d.ts +43 -1
- package/package.json +3 -3
- package/presentation/locales.json +28 -4
- package/presentation/page.module.css +20 -0
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findMnemonCommand, isMnemonExecutable, resolveMnemonInvocation } from "./native-cli.js";
|
|
2
|
-
import { CATEGORIES as CATEGORIES$1, EDGE_TYPES, INTENTS as INTENTS$1, MNEMON_EMBEDDING_PROTOCOLS, SOURCES as SOURCES$1 } from "./contracts.js";
|
|
2
|
+
import { CATEGORIES as CATEGORIES$1, EDGE_TYPES, INTENTS as INTENTS$1, MNEMON_EMBEDDING_PROTOCOLS, SOURCES as SOURCES$1, normalizeEntityKey } from "./contracts.js";
|
|
3
3
|
import { a as MemoryProviderCatalog, i as EMPTY_MEMORY_PROVIDER_CATALOG, n as PrivateMemorySpaceProviderHost, r as MemoryProviderAdapterRegistry, t as createMemorySpaceProviderPlugin } from "./plugin-DlsNeZbQ.js";
|
|
4
4
|
import { n as ProcessError, r as runProcess } from "./process-DIK9NnTg.js";
|
|
5
5
|
import { r as defineMemorySpaceProvider } from "./definitions-DfmOqJjR.js";
|
|
@@ -45,8 +45,11 @@ function modelStatus(status) {
|
|
|
45
45
|
const unhealthy = active.filter((body) => !body.healthy);
|
|
46
46
|
const relevantProviders = status.providerServices?.filter((provider) => provider.enabled || provider.configured || provider.memoryBodyCount > 0 || provider.status === "unhealthy") ?? [];
|
|
47
47
|
const providers = relevantProviders.slice(0, 16);
|
|
48
|
+
const providerReady = status.commandFound === true || (status.providerServices ?? []).some((provider) => provider.enabled && provider.configured);
|
|
49
|
+
const notice = status.memoryBodies.length > 0 ? void 0 : providerReady ? "No Memory Space exists yet, so durable memory has nowhere to go and a full MEMORY.md archives to a local file. Create and activate a Memory Space to keep durable memory." : "No Memory Space exists, and none can be created until a memory Provider is ready, so durable memory has nowhere to go and a full MEMORY.md archives to a local file. Install the Mnemon CLI for Mnemon Native, or connect another Provider on the dsh-mnemon page under Plugins, then create and activate a Memory Space.";
|
|
48
50
|
return {
|
|
49
51
|
healthy: status.healthy && unhealthy.length === 0,
|
|
52
|
+
...notice === void 0 ? {} : { notice },
|
|
50
53
|
...status.error === void 0 ? {} : { error: boundedToolText(status.error, 1e3) },
|
|
51
54
|
...status.version === void 0 ? {} : { version: boundedToolText(status.version, 120) },
|
|
52
55
|
commandFound: status.commandFound,
|
|
@@ -999,6 +1002,88 @@ function lexicalRequiredMatchCount(tokens) {
|
|
|
999
1002
|
return Math.max(2, Math.ceil(tokens.length / 4));
|
|
1000
1003
|
}
|
|
1001
1004
|
//#endregion
|
|
1005
|
+
//#region src/entity-index.ts
|
|
1006
|
+
/**
|
|
1007
|
+
* The most memories one space's derived index asks list() for. Mnemon Native
|
|
1008
|
+
* lists a whole store; a Provider that stops earlier reports what it listed.
|
|
1009
|
+
*/
|
|
1010
|
+
const ENTITY_INDEX_LIST_LIMIT = 1e5;
|
|
1011
|
+
/** The rail lists at most this many entities; the rest stay reachable by name. */
|
|
1012
|
+
const ENTITY_RAIL_LIMIT = 5e3;
|
|
1013
|
+
function buildSpaceEntityIndex(memories, memoryCount, complete) {
|
|
1014
|
+
const kept = [];
|
|
1015
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1016
|
+
const spellings = /* @__PURE__ */ new Map();
|
|
1017
|
+
for (const memory of memories) {
|
|
1018
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1019
|
+
let position;
|
|
1020
|
+
for (const raw of memory.entities ?? []) {
|
|
1021
|
+
if (typeof raw !== "string") continue;
|
|
1022
|
+
const key = normalizeEntityKey(raw);
|
|
1023
|
+
if (key === "" || seen.has(key)) continue;
|
|
1024
|
+
seen.add(key);
|
|
1025
|
+
if (position === void 0) {
|
|
1026
|
+
position = kept.length;
|
|
1027
|
+
kept.push(memory);
|
|
1028
|
+
}
|
|
1029
|
+
const positions = byKey.get(key);
|
|
1030
|
+
if (positions === void 0) byKey.set(key, [position]);
|
|
1031
|
+
else positions.push(position);
|
|
1032
|
+
const name = raw.normalize("NFKC").trim();
|
|
1033
|
+
const names = spellings.get(key);
|
|
1034
|
+
if (names === void 0) spellings.set(key, /* @__PURE__ */ new Map([[name, 1]]));
|
|
1035
|
+
else names.set(name, (names.get(name) ?? 0) + 1);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
return {
|
|
1039
|
+
memories: kept,
|
|
1040
|
+
byKey,
|
|
1041
|
+
spellings,
|
|
1042
|
+
memoryCount,
|
|
1043
|
+
complete
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
/** The spelling most memories use; the first one seen wins a tie. */
|
|
1047
|
+
function preferredSpelling(names) {
|
|
1048
|
+
let preferred = "";
|
|
1049
|
+
let most = 0;
|
|
1050
|
+
for (const [name, count] of names) if (count > most) {
|
|
1051
|
+
preferred = name;
|
|
1052
|
+
most = count;
|
|
1053
|
+
}
|
|
1054
|
+
return preferred;
|
|
1055
|
+
}
|
|
1056
|
+
/** Merge per-space indexes into one entity list, most frequent first. */
|
|
1057
|
+
function mergeEntityCounts(indexes) {
|
|
1058
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1059
|
+
const spellings = /* @__PURE__ */ new Map();
|
|
1060
|
+
for (const index of indexes) for (const [key, positions] of index.byKey) {
|
|
1061
|
+
counts.set(key, (counts.get(key) ?? 0) + positions.length);
|
|
1062
|
+
let totals = spellings.get(key);
|
|
1063
|
+
if (totals === void 0) spellings.set(key, totals = /* @__PURE__ */ new Map());
|
|
1064
|
+
for (const [name, count] of index.spellings.get(key) ?? []) totals.set(name, (totals.get(name) ?? 0) + count);
|
|
1065
|
+
}
|
|
1066
|
+
const names = /* @__PURE__ */ new Map();
|
|
1067
|
+
for (const [key, totals] of spellings) names.set(key, preferredSpelling(totals));
|
|
1068
|
+
return {
|
|
1069
|
+
items: [...counts].map(([key, count]) => ({
|
|
1070
|
+
entity: names.get(key),
|
|
1071
|
+
count
|
|
1072
|
+
})).sort((left, right) => right.count - left.count || left.entity.localeCompare(right.entity)),
|
|
1073
|
+
names
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
/** Importance first, then the newest; the order Mnemon Native lists a store in. */
|
|
1077
|
+
function compareEntityMemories(left, right) {
|
|
1078
|
+
return (right.importance ?? 0) - (left.importance ?? 0) || (right.createdAt ?? "").localeCompare(left.createdAt ?? "") || (left.memoryBodyName ?? "").localeCompare(right.memoryBodyName ?? "") || left.id.localeCompare(right.id);
|
|
1079
|
+
}
|
|
1080
|
+
/** Every memory across the indexes that carries the entity key. */
|
|
1081
|
+
function memoriesWithEntity(indexes, key) {
|
|
1082
|
+
const memories = [];
|
|
1083
|
+
for (const index of indexes) for (const position of index.byKey.get(key) ?? []) memories.push(index.memories[position]);
|
|
1084
|
+
return memories.sort(compareEntityMemories);
|
|
1085
|
+
}
|
|
1086
|
+
//#endregion
|
|
1002
1087
|
//#region src/recall-quality/policies.ts
|
|
1003
1088
|
function expandedLimit(context) {
|
|
1004
1089
|
return Math.min(50, Math.max(context.requestedLimit, Math.ceil(context.requestedLimit * context.config.candidateMultiplier)));
|
|
@@ -1208,6 +1293,39 @@ function text(value) {
|
|
|
1208
1293
|
function number(value) {
|
|
1209
1294
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1210
1295
|
}
|
|
1296
|
+
/**
|
|
1297
|
+
* How long a selection reuses the Provider health its index was checked with.
|
|
1298
|
+
* The rail always checks again; a write through this Source drops both at once.
|
|
1299
|
+
*/
|
|
1300
|
+
const ENTITY_SELECTION_STATUS_REUSE_MS = 1e4;
|
|
1301
|
+
/** How long an index that statistics cannot check is reused; a write through this Source still drops it. */
|
|
1302
|
+
const ENTITY_INDEX_UNCHECKED_REUSE_MS = 1e4;
|
|
1303
|
+
function entityName(entity) {
|
|
1304
|
+
const name = entity.trim();
|
|
1305
|
+
if (name.length > 200) throw new Error("entity is too long (max 200 characters)");
|
|
1306
|
+
return name;
|
|
1307
|
+
}
|
|
1308
|
+
function memoryKey(memoryBodyId, id) {
|
|
1309
|
+
return `${memoryBodyId}\u0000${id}`;
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* What must stay the same for a space's entity index to stay valid: its
|
|
1313
|
+
* Provider statistics (Mnemon counts every write in its operation log) and the
|
|
1314
|
+
* Source's own record of the space. Without statistics it cannot be checked.
|
|
1315
|
+
*/
|
|
1316
|
+
function entityIndexFingerprint(body, status) {
|
|
1317
|
+
const stats = status.stats;
|
|
1318
|
+
if (stats === void 0) return void 0;
|
|
1319
|
+
return JSON.stringify([
|
|
1320
|
+
body.provider.id,
|
|
1321
|
+
body.updatedAt,
|
|
1322
|
+
stats.totalInsights,
|
|
1323
|
+
stats.deletedInsights,
|
|
1324
|
+
stats.edgeCount,
|
|
1325
|
+
stats.oplogCount,
|
|
1326
|
+
stats.dbSizeBytes
|
|
1327
|
+
]);
|
|
1328
|
+
}
|
|
1211
1329
|
function readSource(body, mode, status, itemCount, options = {}) {
|
|
1212
1330
|
return {
|
|
1213
1331
|
memoryBodyId: body.id,
|
|
@@ -1377,6 +1495,12 @@ var MemorySpacesService = class {
|
|
|
1377
1495
|
providers;
|
|
1378
1496
|
recallQualityPolicy;
|
|
1379
1497
|
spacesInFlight;
|
|
1498
|
+
/** One entity index per active entity space, valid while its fingerprint holds. */
|
|
1499
|
+
entityIndexCache = /* @__PURE__ */ new Map();
|
|
1500
|
+
/** settledAt stays undefined while the read runs, which every caller shares. */
|
|
1501
|
+
entityStatusCache = /* @__PURE__ */ new Map();
|
|
1502
|
+
/** The related read each page view is waiting for; a newer selection cancels the older one. */
|
|
1503
|
+
entityRelatedViews = /* @__PURE__ */ new Map();
|
|
1380
1504
|
providersDisposed = false;
|
|
1381
1505
|
/** The CLI version a full status last read, and the binary it read it from. */
|
|
1382
1506
|
cliVersion;
|
|
@@ -1512,7 +1636,8 @@ var MemorySpacesService = class {
|
|
|
1512
1636
|
const all = this.memorySpaces.list();
|
|
1513
1637
|
const serviceItems = this.memorySpaces.providerServices().items;
|
|
1514
1638
|
const enabled = new Set(serviceItems.filter((service) => service.enabled).map((service) => service.providerId));
|
|
1515
|
-
const
|
|
1639
|
+
const commandFound = this.runner.commandFound;
|
|
1640
|
+
const active = all.filter((body) => body.active && (this.isNativeSpace(body) ? commandFound : enabled.has(body.provider.id))).sort((left, right) => left.id.localeCompare(right.id));
|
|
1516
1641
|
const spaces = [...all].sort((left, right) => left.id.localeCompare(right.id)).map((body) => ({
|
|
1517
1642
|
id: body.id,
|
|
1518
1643
|
name: body.name,
|
|
@@ -1527,13 +1652,16 @@ var MemorySpacesService = class {
|
|
|
1527
1652
|
enabled: service.enabled,
|
|
1528
1653
|
configured: service.configured
|
|
1529
1654
|
})).sort((left, right) => left.providerId.localeCompare(right.providerId));
|
|
1655
|
+
const revision = createHash("sha256").update(JSON.stringify({
|
|
1656
|
+
bodies: spaces,
|
|
1657
|
+
services,
|
|
1658
|
+
...commandFound ? {} : { nativeUnavailable: true }
|
|
1659
|
+
})).digest("hex");
|
|
1530
1660
|
return {
|
|
1531
1661
|
all,
|
|
1532
1662
|
active,
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
services
|
|
1536
|
-
})).digest("hex")
|
|
1663
|
+
providerReady: this.memorySpaces.defaultProviderId() !== void 0,
|
|
1664
|
+
revision
|
|
1537
1665
|
};
|
|
1538
1666
|
}
|
|
1539
1667
|
/** Return a usable system snapshot without waiting for any Provider I/O. */
|
|
@@ -1688,6 +1816,7 @@ var MemorySpacesService = class {
|
|
|
1688
1816
|
}
|
|
1689
1817
|
const provider = this.providerFor(body);
|
|
1690
1818
|
provider.invalidateStatus?.(body.id);
|
|
1819
|
+
this.invalidateEntityIndex(body.id);
|
|
1691
1820
|
const status = await provider.status(body, signal);
|
|
1692
1821
|
return {
|
|
1693
1822
|
...body,
|
|
@@ -1696,7 +1825,8 @@ var MemorySpacesService = class {
|
|
|
1696
1825
|
...status
|
|
1697
1826
|
};
|
|
1698
1827
|
}
|
|
1699
|
-
|
|
1828
|
+
/** exclude: memoryKey()s to leave out before the quality policy selects. */
|
|
1829
|
+
async search(request, signal, options = {}) {
|
|
1700
1830
|
const query = required(request.query, "query", 2e3);
|
|
1701
1831
|
const limit = memoryInputInteger(request.limit, this.config.defaultRecallLimit, 1, 50);
|
|
1702
1832
|
const qualityContext = {
|
|
@@ -1719,7 +1849,8 @@ var MemorySpacesService = class {
|
|
|
1719
1849
|
limit: preparedPolicy.candidateLimit,
|
|
1720
1850
|
...category === void 0 ? {} : { category },
|
|
1721
1851
|
...source === void 0 ? {} : { source },
|
|
1722
|
-
...intent === void 0 ? {} : { intent }
|
|
1852
|
+
...intent === void 0 ? {} : { intent },
|
|
1853
|
+
...request.inspect === true ? { inspect: true } : {}
|
|
1723
1854
|
};
|
|
1724
1855
|
let batches = await Promise.all(spaces.map(async (body) => {
|
|
1725
1856
|
if (!body.provider.capabilities.search) return {
|
|
@@ -1755,7 +1886,8 @@ var MemorySpacesService = class {
|
|
|
1755
1886
|
const hints = [];
|
|
1756
1887
|
for (const [bodyOrder, { body, result }] of selectedBatches.entries()) {
|
|
1757
1888
|
const scoreSemantics = this.providerFor(body).scoreSemantics;
|
|
1758
|
-
|
|
1889
|
+
const entries = options.exclude === void 0 ? result.results : result.results.filter((entry) => !options.exclude.has(memoryKey(body.id, entry.id)));
|
|
1890
|
+
candidates.push(...entries.map((entry, index) => ({
|
|
1759
1891
|
insight: this.annotate(entry, body),
|
|
1760
1892
|
memoryBodyId: body.id,
|
|
1761
1893
|
providerId: body.provider.id,
|
|
@@ -1782,7 +1914,8 @@ var MemorySpacesService = class {
|
|
|
1782
1914
|
const recovered = await this.providerFor(batch.body).search(batch.body, {
|
|
1783
1915
|
query: recoveryPlan.query,
|
|
1784
1916
|
mode: "keyword",
|
|
1785
|
-
limit: Math.min(limit, preparedPolicy.candidateLimit)
|
|
1917
|
+
limit: Math.min(limit, preparedPolicy.candidateLimit),
|
|
1918
|
+
...request.inspect === true ? { inspect: true } : {}
|
|
1786
1919
|
}, signal);
|
|
1787
1920
|
const admitted = recovered.results.some((insight) => recoveryMatchCount(insight.content, recoveryPlan) >= recoveryPlan.requiredMatches);
|
|
1788
1921
|
const results = mergeRecoveryResults(batch.result.results, recovered.results, recoveryPlan, preparedPolicy.candidateLimit);
|
|
@@ -2013,41 +2146,209 @@ var MemorySpacesService = class {
|
|
|
2013
2146
|
sources: batches.map((batch) => batch.source)
|
|
2014
2147
|
};
|
|
2015
2148
|
}
|
|
2149
|
+
/**
|
|
2150
|
+
* The entities of the active spaces, each counted once per memory that
|
|
2151
|
+
* carries it. With an entity, also the first page of those memories.
|
|
2152
|
+
*/
|
|
2016
2153
|
async entities(entity, limit, signal) {
|
|
2017
|
-
const
|
|
2018
|
-
const
|
|
2019
|
-
const
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
entity: name,
|
|
2023
|
-
count
|
|
2024
|
-
})).sort((left, right) => right.count - left.count);
|
|
2025
|
-
const sources = active.map((body) => {
|
|
2026
|
-
if (!body.provider.capabilities.entities) return readSource(body, "unsupported", "unsupported", 0, { hint: "This provider does not expose an entity index." });
|
|
2027
|
-
if (!body.healthy) return readSource(body, "entities", "unavailable", 0, { hint: body.error ?? "Provider unavailable." });
|
|
2028
|
-
const count = body.stats?.topEntities.length ?? 0;
|
|
2029
|
-
return readSource(body, "entities", count === 0 ? "empty" : "ready", count);
|
|
2030
|
-
});
|
|
2031
|
-
const selected = entity?.trim() ?? "";
|
|
2032
|
-
if (selected === "") return {
|
|
2033
|
-
items,
|
|
2154
|
+
const selected = entity === void 0 ? "" : entityName(entity);
|
|
2155
|
+
const read = await this.readEntityIndexes(signal, 0);
|
|
2156
|
+
const { items } = mergeEntityCounts(read.indexes);
|
|
2157
|
+
const view = {
|
|
2158
|
+
items: items.slice(0, ENTITY_RAIL_LIMIT),
|
|
2034
2159
|
insights: [],
|
|
2035
|
-
sources
|
|
2160
|
+
sources: read.sources,
|
|
2161
|
+
total: items.length,
|
|
2162
|
+
complete: read.complete
|
|
2036
2163
|
};
|
|
2037
|
-
if (selected
|
|
2038
|
-
const
|
|
2164
|
+
if (selected === "") return view;
|
|
2165
|
+
const page = this.entityPage(read, selected, 0, memoryInputInteger(limit, 20, 1, 50));
|
|
2039
2166
|
return {
|
|
2040
|
-
|
|
2041
|
-
selected,
|
|
2042
|
-
insights:
|
|
2167
|
+
...view,
|
|
2168
|
+
selected: page.entity,
|
|
2169
|
+
insights: page.items
|
|
2170
|
+
};
|
|
2171
|
+
}
|
|
2172
|
+
/** One page of the memories that carry an entity, by importance and then recency. */
|
|
2173
|
+
async entityMemories(entity, offset, limit, signal) {
|
|
2174
|
+
const selected = entityName(entity);
|
|
2175
|
+
if (selected === "") throw new Error("entity is required");
|
|
2176
|
+
const read = await this.readEntityIndexes(signal, ENTITY_SELECTION_STATUS_REUSE_MS);
|
|
2177
|
+
return this.entityPage(read, selected, memoryInputInteger(offset, 0, 0, 1e6), memoryInputInteger(limit, 50, 1, 200));
|
|
2178
|
+
}
|
|
2179
|
+
/**
|
|
2180
|
+
* What recall relates to an entity, without the memories that carry it.
|
|
2181
|
+
* Those are left out before the quality policy selects, so they cannot use up
|
|
2182
|
+
* its places and leave the related list empty.
|
|
2183
|
+
*/
|
|
2184
|
+
async entityRelated(entity, limit, signal, view) {
|
|
2185
|
+
const selected = entityName(entity);
|
|
2186
|
+
if (selected === "") throw new Error("entity is required");
|
|
2187
|
+
const superseding = view === void 0 ? void 0 : new AbortController();
|
|
2188
|
+
if (view !== void 0) {
|
|
2189
|
+
this.entityRelatedViews.get(view)?.abort(/* @__PURE__ */ new Error("superseded by a newer entity selection"));
|
|
2190
|
+
this.entityRelatedViews.set(view, superseding);
|
|
2191
|
+
}
|
|
2192
|
+
const combined = superseding === void 0 ? signal : signal === void 0 ? superseding.signal : AbortSignal.any([signal, superseding.signal]);
|
|
2193
|
+
try {
|
|
2194
|
+
const read = await this.readEntityIndexes(combined, ENTITY_SELECTION_STATUS_REUSE_MS);
|
|
2195
|
+
const key = normalizeEntityKey(selected);
|
|
2196
|
+
const carrying = /* @__PURE__ */ new Set();
|
|
2197
|
+
for (const [bodyId, index] of read.byBody) for (const position of index.byKey.get(key) ?? []) carrying.add(memoryKey(bodyId, index.memories[position].id));
|
|
2198
|
+
const display = mergeEntityCounts(read.indexes).names.get(key) ?? selected;
|
|
2199
|
+
const readableIds = read.readable.map((body) => body.id);
|
|
2200
|
+
if (readableIds.length === 0) return {
|
|
2201
|
+
entity: display,
|
|
2202
|
+
items: [],
|
|
2203
|
+
sources: []
|
|
2204
|
+
};
|
|
2205
|
+
const result = await this.search({
|
|
2043
2206
|
query: selected,
|
|
2044
2207
|
intent: "ENTITY",
|
|
2045
2208
|
limit: memoryInputInteger(limit, 20, 1, 50),
|
|
2046
|
-
memoryBodyIds: readableIds
|
|
2047
|
-
|
|
2048
|
-
|
|
2209
|
+
memoryBodyIds: readableIds,
|
|
2210
|
+
inspect: true
|
|
2211
|
+
}, combined, { exclude: carrying });
|
|
2212
|
+
combined?.throwIfAborted();
|
|
2213
|
+
return {
|
|
2214
|
+
entity: display,
|
|
2215
|
+
items: result.results,
|
|
2216
|
+
sources: result.sources
|
|
2217
|
+
};
|
|
2218
|
+
} finally {
|
|
2219
|
+
if (view !== void 0 && this.entityRelatedViews.get(view) === superseding) this.entityRelatedViews.delete(view);
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
entityPage(read, selected, offset, limit) {
|
|
2223
|
+
const key = normalizeEntityKey(selected);
|
|
2224
|
+
const memories = memoriesWithEntity(read.indexes, key);
|
|
2225
|
+
return {
|
|
2226
|
+
entity: mergeEntityCounts(read.indexes).names.get(key) ?? selected,
|
|
2227
|
+
total: memories.length,
|
|
2228
|
+
offset,
|
|
2229
|
+
items: memories.slice(offset, offset + limit),
|
|
2230
|
+
complete: read.complete,
|
|
2231
|
+
sources: read.sources
|
|
2049
2232
|
};
|
|
2050
2233
|
}
|
|
2234
|
+
/**
|
|
2235
|
+
* One entity index per active space that has an entity index, read
|
|
2236
|
+
* concurrently. A space keeps its index while its Provider statistics and
|
|
2237
|
+
* metadata stay the same; a write through this Source drops it.
|
|
2238
|
+
*/
|
|
2239
|
+
async readEntityIndexes(signal, statusMaxAgeMs) {
|
|
2240
|
+
signal?.throwIfAborted();
|
|
2241
|
+
const active = this.memorySpaces.active();
|
|
2242
|
+
const capable = new Set(active.filter((body) => body.provider.capabilities.entities).map((body) => body.id));
|
|
2243
|
+
for (const id of this.entityIndexCache.keys()) if (!capable.has(id)) this.entityIndexCache.delete(id);
|
|
2244
|
+
const reads = await Promise.all(active.map(async (body) => {
|
|
2245
|
+
if (!body.provider.capabilities.entities) return {
|
|
2246
|
+
body,
|
|
2247
|
+
recall: false,
|
|
2248
|
+
source: readSource(body, "unsupported", "unsupported", 0, { hint: "This provider does not expose an entity index." })
|
|
2249
|
+
};
|
|
2250
|
+
const status = await this.entitySpaceStatus(body, statusMaxAgeMs);
|
|
2251
|
+
if (!status.healthy) return {
|
|
2252
|
+
body,
|
|
2253
|
+
recall: false,
|
|
2254
|
+
source: readSource(body, "entities", "unavailable", 0, { hint: status.error ?? "Provider unavailable." })
|
|
2255
|
+
};
|
|
2256
|
+
const recall = body.provider.capabilities.search;
|
|
2257
|
+
if (this.providerFor(body).entityIndex === void 0 && !body.provider.capabilities.browse) return {
|
|
2258
|
+
body,
|
|
2259
|
+
recall,
|
|
2260
|
+
source: readSource(body, "query-only", "query-required", 0, { hint: "This provider can only be queried; its memories appear among related memories." })
|
|
2261
|
+
};
|
|
2262
|
+
try {
|
|
2263
|
+
const index = await this.entityIndexFor(body, status);
|
|
2264
|
+
const options = {
|
|
2265
|
+
memoryCount: index.memoryCount,
|
|
2266
|
+
complete: index.complete,
|
|
2267
|
+
...index.complete ? {} : { hint: "The Provider indexed only part of this space." }
|
|
2268
|
+
};
|
|
2269
|
+
return {
|
|
2270
|
+
body,
|
|
2271
|
+
index,
|
|
2272
|
+
recall,
|
|
2273
|
+
source: readSource(body, "entities", index.byKey.size === 0 ? "empty" : "ready", index.byKey.size, options)
|
|
2274
|
+
};
|
|
2275
|
+
} catch (error) {
|
|
2276
|
+
return {
|
|
2277
|
+
body,
|
|
2278
|
+
recall: false,
|
|
2279
|
+
source: readSource(body, "entities", "unavailable", 0, { hint: error instanceof Error ? error.message : String(error) })
|
|
2280
|
+
};
|
|
2281
|
+
}
|
|
2282
|
+
}));
|
|
2283
|
+
signal?.throwIfAborted();
|
|
2284
|
+
const byBody = /* @__PURE__ */ new Map();
|
|
2285
|
+
for (const read of reads) if (read.index !== void 0) byBody.set(read.body.id, read.index);
|
|
2286
|
+
const indexes = [...byBody.values()];
|
|
2287
|
+
return {
|
|
2288
|
+
byBody,
|
|
2289
|
+
indexes,
|
|
2290
|
+
readable: reads.filter((read) => read.recall).map((read) => read.body),
|
|
2291
|
+
sources: reads.map((read) => read.source),
|
|
2292
|
+
complete: indexes.every((index) => index.complete)
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
/** Provider health for the entity reads: a read in flight is shared, a finished one reused for less than maxAgeMs. */
|
|
2296
|
+
entitySpaceStatus(body, maxAgeMs) {
|
|
2297
|
+
const recent = this.entityStatusCache.get(body.id);
|
|
2298
|
+
if (recent !== void 0 && (recent.settledAt === void 0 || Date.now() - recent.settledAt < maxAgeMs)) return recent.status;
|
|
2299
|
+
const entry = {
|
|
2300
|
+
settledAt: void 0,
|
|
2301
|
+
status: Promise.resolve(void 0)
|
|
2302
|
+
};
|
|
2303
|
+
entry.status = this.providerFor(body).status(body).catch((error) => ({
|
|
2304
|
+
healthy: false,
|
|
2305
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2306
|
+
})).then((status) => {
|
|
2307
|
+
entry.settledAt = Date.now();
|
|
2308
|
+
return status;
|
|
2309
|
+
});
|
|
2310
|
+
this.entityStatusCache.set(body.id, entry);
|
|
2311
|
+
return entry.status;
|
|
2312
|
+
}
|
|
2313
|
+
entityIndexFor(body, status) {
|
|
2314
|
+
const fingerprint = entityIndexFingerprint(body, status);
|
|
2315
|
+
const cached = this.entityIndexCache.get(body.id);
|
|
2316
|
+
if (cached !== void 0 && cached.fingerprint === fingerprint) {
|
|
2317
|
+
if (fingerprint !== void 0 || cached.settledAt === void 0 || Date.now() - cached.settledAt < ENTITY_INDEX_UNCHECKED_REUSE_MS) return cached.index;
|
|
2318
|
+
}
|
|
2319
|
+
const entry = {
|
|
2320
|
+
fingerprint,
|
|
2321
|
+
settledAt: void 0,
|
|
2322
|
+
index: Promise.resolve(void 0)
|
|
2323
|
+
};
|
|
2324
|
+
entry.index = this.buildEntityIndex(body).then((index) => {
|
|
2325
|
+
entry.settledAt = Date.now();
|
|
2326
|
+
return index;
|
|
2327
|
+
}, (error) => {
|
|
2328
|
+
if (this.entityIndexCache.get(body.id) === entry) this.entityIndexCache.delete(body.id);
|
|
2329
|
+
throw error;
|
|
2330
|
+
});
|
|
2331
|
+
this.entityIndexCache.set(body.id, entry);
|
|
2332
|
+
return entry.index;
|
|
2333
|
+
}
|
|
2334
|
+
async buildEntityIndex(body) {
|
|
2335
|
+
const provider = this.providerFor(body);
|
|
2336
|
+
if (provider.entityIndex !== void 0) {
|
|
2337
|
+
const owned = await provider.entityIndex(body);
|
|
2338
|
+
return buildSpaceEntityIndex(owned.memories.map((memory) => this.entityMemory(memory, body)), owned.memories.length, owned.complete);
|
|
2339
|
+
}
|
|
2340
|
+
const listed = await provider.list(body, { limit: ENTITY_INDEX_LIST_LIMIT });
|
|
2341
|
+
return buildSpaceEntityIndex(listed.map((memory) => this.entityMemory(memory, body)), listed.length, listed.length < ENTITY_INDEX_LIST_LIMIT);
|
|
2342
|
+
}
|
|
2343
|
+
/** A listed memory, not a query result: no relevance fields. */
|
|
2344
|
+
entityMemory(memory, body) {
|
|
2345
|
+
const { score: _score, normalizedScore: _normalized, relevanceTier: _tier, federatedScore: _federated, confidence: _confidence, intent: _intent, matchedVia: _matchedVia, depth: _depth, edgeType: _edgeType, ...listed } = memory;
|
|
2346
|
+
return this.annotate(listed, body);
|
|
2347
|
+
}
|
|
2348
|
+
invalidateEntityIndex(memoryBodyId) {
|
|
2349
|
+
this.entityIndexCache.delete(memoryBodyId);
|
|
2350
|
+
this.entityStatusCache.delete(memoryBodyId);
|
|
2351
|
+
}
|
|
2051
2352
|
async remember(request, signal) {
|
|
2052
2353
|
this.assertWritable();
|
|
2053
2354
|
const prepared = this.prepareRemember(request);
|
|
@@ -2103,6 +2404,24 @@ var MemorySpacesService = class {
|
|
|
2103
2404
|
}
|
|
2104
2405
|
return results;
|
|
2105
2406
|
}
|
|
2407
|
+
/**
|
|
2408
|
+
* The memories held under an exact id among the given spaces that can be
|
|
2409
|
+
* read now, asked of the Providers that can look ids up.
|
|
2410
|
+
*/
|
|
2411
|
+
async locate(id, memoryBodyIds, signal) {
|
|
2412
|
+
const exact = required(id, "id", 2e3);
|
|
2413
|
+
const readable = new Map(this.memorySpaces.active().filter((body) => this.isNativeSpace(body) || this.memorySpaces.providerServiceEnabled(body.provider.id)).map((body) => [body.id, body]));
|
|
2414
|
+
const found = [];
|
|
2415
|
+
for (const memoryBodyId of new Set(memoryBodyIds)) {
|
|
2416
|
+
const body = readable.get(memoryBodyId);
|
|
2417
|
+
if (body === void 0) continue;
|
|
2418
|
+
const provider = this.providerFor(body);
|
|
2419
|
+
if (provider.get === void 0) continue;
|
|
2420
|
+
const insight = await provider.get(body, exact, signal);
|
|
2421
|
+
if (insight !== void 0 && insight.id === exact) found.push(this.annotate(insight, body));
|
|
2422
|
+
}
|
|
2423
|
+
return found;
|
|
2424
|
+
}
|
|
2106
2425
|
async related(id, depth = 2, edge, signal, memoryBodyId) {
|
|
2107
2426
|
const body = this.readSpace(memoryBodyId);
|
|
2108
2427
|
const selectedEdge = allowed(edge, EDGE_TYPES, "edge");
|
|
@@ -2378,6 +2697,7 @@ var MemorySpacesService = class {
|
|
|
2378
2697
|
};
|
|
2379
2698
|
}
|
|
2380
2699
|
activateAfterWrite(body, providerChanged) {
|
|
2700
|
+
this.invalidateEntityIndex(body.id);
|
|
2381
2701
|
if (!providerChanged) return;
|
|
2382
2702
|
if (!body.active) this.memorySpaces.setActive(body.id, true);
|
|
2383
2703
|
else this.memorySpaces.touch(body.id);
|
|
@@ -2408,7 +2728,9 @@ const EMBEDDING_ENVIRONMENT_KEYS = /* @__PURE__ */ new Set([
|
|
|
2408
2728
|
function processFailureMessage(error, args) {
|
|
2409
2729
|
const detail = error instanceof Error ? error.message : String(error);
|
|
2410
2730
|
const reason = error instanceof ProcessError ? error.reason : "launch";
|
|
2411
|
-
|
|
2731
|
+
const command = args.find((arg) => !arg.startsWith("-"));
|
|
2732
|
+
if (reason === "output-limit") return `mnemon ${command ?? "command"} stopped: ${detail.replace(/^mnemon /u, "")}`;
|
|
2733
|
+
if (reason === "timeout" && command !== void 0) return detail.replace(/^mnemon /u, `mnemon ${command} `);
|
|
2412
2734
|
if (reason !== "launch") return detail;
|
|
2413
2735
|
return `${detail}. ${process.platform === "win32" ? "Install the official Mnemon Windows release, ensure mnemon.exe is on PATH or under %LOCALAPPDATA%\\Programs\\mnemon, or set MNEMON_CLI_PATH or mnemon.cliPath to its absolute path." : "Install Mnemon and ensure \"mnemon\" is on PATH, or set MNEMON_CLI_PATH or mnemon.cliPath."}`;
|
|
2414
2736
|
}
|
|
@@ -2774,6 +3096,8 @@ async function manageMemorySpaces(service, request) {
|
|
|
2774
3096
|
...memoryInputStringArray(input.memoryBodyIds, "memoryBodyIds", 1e4) === void 0 ? {} : { memoryBodyIds: memoryInputStringArray(input.memoryBodyIds, "memoryBodyIds", 1e4) }
|
|
2775
3097
|
}, request.signal));
|
|
2776
3098
|
case "entities": return managementResult(service, await service.entities(memoryInputText(input.entity, "entity", 500, false), input.limit === void 0 ? void 0 : memoryInputInteger(input.limit, 100, 1, 1e4), request.signal));
|
|
3099
|
+
case "entity-memories": return managementResult(service, await service.entityMemories(memoryInputText(input.entity, "entity", 500), input.offset === void 0 ? void 0 : memoryInputInteger(input.offset, 0, 0, 1e6), input.limit === void 0 ? void 0 : memoryInputInteger(input.limit, 50, 1, 200), request.signal));
|
|
3100
|
+
case "entity-related": return managementResult(service, await service.entityRelated(memoryInputText(input.entity, "entity", 500), input.limit === void 0 ? void 0 : memoryInputInteger(input.limit, 20, 1, 50), request.signal, memoryInputText(input.view, "view", 200, false)));
|
|
2777
3101
|
case "search": return managementResult(service, await service.search({
|
|
2778
3102
|
query: memoryInputText(input.query, "query", 2e3),
|
|
2779
3103
|
...memoryInputText(input.mode, "mode", 20, false) === void 0 ? {} : { mode: memoryInputText(input.mode, "mode", 20, false) },
|
|
@@ -2781,7 +3105,8 @@ async function manageMemorySpaces(service, request) {
|
|
|
2781
3105
|
...memoryInputText(input.category, "category", 30, false) === void 0 ? {} : { category: memoryInputText(input.category, "category", 30, false) },
|
|
2782
3106
|
...memoryInputText(input.source, "source", 30, false) === void 0 ? {} : { source: memoryInputText(input.source, "source", 30, false) },
|
|
2783
3107
|
...memoryInputText(input.intent, "intent", 30, false) === void 0 ? {} : { intent: memoryInputText(input.intent, "intent", 30, false) },
|
|
2784
|
-
...memoryInputStringArray(input.memoryBodyIds, "memoryBodyIds", 1e4) === void 0 ? {} : { memoryBodyIds: memoryInputStringArray(input.memoryBodyIds, "memoryBodyIds", 1e4) }
|
|
3108
|
+
...memoryInputStringArray(input.memoryBodyIds, "memoryBodyIds", 1e4) === void 0 ? {} : { memoryBodyIds: memoryInputStringArray(input.memoryBodyIds, "memoryBodyIds", 1e4) },
|
|
3109
|
+
...input.inspect === true ? { inspect: true } : {}
|
|
2785
3110
|
}, request.signal));
|
|
2786
3111
|
case "related": return managementResult(service, await service.related(memoryInputText(input.id, "id", 2e3), memoryInputInteger(input.depth, 2, 1, 5), memoryInputText(input.edge, "edge", 30, false), request.signal, memoryInputText(input.memoryBodyId, "memoryBodyId", 300, false)));
|
|
2787
3112
|
case "body-reconnect": return managementResult(service, await service.reconnectSpace(memoryInputText(input.memoryBodyId, "memoryBodyId", 300), request.signal));
|
|
@@ -3059,6 +3384,34 @@ function createMemorySpacesSource(providerSnapshot, config = {}) {
|
|
|
3059
3384
|
admittedByView.set(viewId, current);
|
|
3060
3385
|
while (admittedByView.size > 128) admittedByView.delete(admittedByView.keys().next().value);
|
|
3061
3386
|
};
|
|
3387
|
+
/**
|
|
3388
|
+
* The Memory Space an exact id belongs to, for an action or traversal that
|
|
3389
|
+
* names a memory by id. Evidence this View returned decides first, as
|
|
3390
|
+
* before. Otherwise the Providers that can look an id up are asked among
|
|
3391
|
+
* the spaces in `scope`, and a found memory is admitted to this View. An
|
|
3392
|
+
* Agent can so forget what it just wrote, and a delegated worker can act on
|
|
3393
|
+
* an id from its parent's turn (#337). A Provider that cannot look ids up
|
|
3394
|
+
* keeps to evidence: its own call may reach beyond the space named.
|
|
3395
|
+
*/
|
|
3396
|
+
const ownerOf = async (viewId, id, requestedSpace, scope, signal) => {
|
|
3397
|
+
const entries = admittedByView.get(viewId);
|
|
3398
|
+
if (requestedSpace !== void 0) {
|
|
3399
|
+
if (entries?.has(requestedSpace + "/" + id) === true) return requestedSpace;
|
|
3400
|
+
} else {
|
|
3401
|
+
const owners = [...entries?.entries() ?? []].filter(([reference]) => reference.endsWith("/" + id)).map(([, owner]) => owner);
|
|
3402
|
+
if (owners.length > 0) return owners.length === 1 ? owners[0] : void 0;
|
|
3403
|
+
}
|
|
3404
|
+
const candidates = requestedSpace === void 0 ? scope : scope.includes(requestedSpace) ? [requestedSpace] : [];
|
|
3405
|
+
if (candidates.length === 0) return void 0;
|
|
3406
|
+
const found = await service.locate(id, candidates, signal);
|
|
3407
|
+
const owners = [...new Set(found.flatMap((item) => item.memoryBodyId === void 0 ? [] : [item.memoryBodyId]))];
|
|
3408
|
+
if (owners.length !== 1) return void 0;
|
|
3409
|
+
admit(viewId, [{
|
|
3410
|
+
id,
|
|
3411
|
+
memoryBodyId: owners[0]
|
|
3412
|
+
}]);
|
|
3413
|
+
return owners[0];
|
|
3414
|
+
};
|
|
3062
3415
|
const evidence = (request, items, unavailable) => {
|
|
3063
3416
|
const catalog = request.route.sourceRouteId === "inspect";
|
|
3064
3417
|
let remaining = request.route.maxCharacters ?? 16e3;
|
|
@@ -3116,15 +3469,15 @@ function createMemorySpacesSource(providerSnapshot, config = {}) {
|
|
|
3116
3469
|
};
|
|
3117
3470
|
return {
|
|
3118
3471
|
facts(request) {
|
|
3119
|
-
const { active, revision } = sourceState(request.scope);
|
|
3472
|
+
const { active, providerReady, revision } = sourceState(request.scope);
|
|
3120
3473
|
const routeIds = [
|
|
3121
3474
|
"inspect",
|
|
3122
3475
|
...active.some((body) => body.provider.capabilities.search) ? ["recall"] : [],
|
|
3123
3476
|
...active.some((body) => body.provider.capabilities.related) ? ["related"] : []
|
|
3124
3477
|
];
|
|
3125
3478
|
const actionIds = service.config.writeEnabled ? [
|
|
3126
|
-
"manage-spaces",
|
|
3127
|
-
...canRemember ? ["remember"] : [],
|
|
3479
|
+
...providerReady ? ["manage-spaces"] : [],
|
|
3480
|
+
...canRemember && providerReady ? ["remember"] : [],
|
|
3128
3481
|
...active.some((body) => body.provider.capabilities.link) ? ["link"] : [],
|
|
3129
3482
|
...active.some((body) => body.provider.capabilities.forget) ? ["forget"] : []
|
|
3130
3483
|
] : [];
|
|
@@ -3145,7 +3498,8 @@ function createMemorySpacesSource(providerSnapshot, config = {}) {
|
|
|
3145
3498
|
actionIds,
|
|
3146
3499
|
hints: {
|
|
3147
3500
|
activeCount: active.length,
|
|
3148
|
-
providerCount: new Set(active.map((body) => body.provider.id)).size
|
|
3501
|
+
providerCount: new Set(active.map((body) => body.provider.id)).size,
|
|
3502
|
+
archivableCount: active.filter((body) => body.provider.capabilities.remember && body.provider.capabilities.forget && body.provider.capabilities.writeMode === "exact").length
|
|
3149
3503
|
}
|
|
3150
3504
|
};
|
|
3151
3505
|
},
|
|
@@ -3229,10 +3583,8 @@ function createMemorySpacesSource(providerSnapshot, config = {}) {
|
|
|
3229
3583
|
if (request.route.sourceRouteId === "related") {
|
|
3230
3584
|
const id = memoryInputText(input.id, "id", 2e3);
|
|
3231
3585
|
const requestedSpace = memoryInputText(input.memoryBodyId, "memoryBodyId", 300, false);
|
|
3232
|
-
const
|
|
3233
|
-
|
|
3234
|
-
const owner = requestedSpace === void 0 ? owners.length === 1 ? owners[0] : void 0 : admitted?.get(requestedSpace + "/" + id);
|
|
3235
|
-
if (owner === void 0) throw new Error("related-memory traversal requires evidence already admitted by this View");
|
|
3586
|
+
const owner = await ownerOf(request.view.id, id, requestedSpace, allowedBodies, request.signal);
|
|
3587
|
+
if (owner === void 0) throw new Error("related-memory traversal requires evidence already admitted by this View, or an id found in a Memory Space it can read");
|
|
3236
3588
|
if (!allowedBodies.includes(owner)) throw new Error("related-memory owner is outside this View ReadGrant");
|
|
3237
3589
|
const edge = memoryInputText(input.edge, "edge", 30, false);
|
|
3238
3590
|
if (edge !== void 0 && !EDGES.has(edge)) throw new Error(`unsupported edge: ${edge}`);
|
|
@@ -3249,13 +3601,7 @@ function createMemorySpacesSource(providerSnapshot, config = {}) {
|
|
|
3249
3601
|
const allowedBodies = grantIds(grant);
|
|
3250
3602
|
const created = createdByView.get(request.view.id) ?? /* @__PURE__ */ new Set();
|
|
3251
3603
|
const writableBodies = writeBodies(request.view.id, grant);
|
|
3252
|
-
const admittedOwner = (id) =>
|
|
3253
|
-
const requestedSpace = memoryInputText(input.memoryBodyId, "memoryBodyId", 300, false);
|
|
3254
|
-
const entries = admittedByView.get(request.view.id);
|
|
3255
|
-
if (requestedSpace !== void 0) return entries?.get(requestedSpace + "/" + id);
|
|
3256
|
-
const owners = [...entries?.entries() ?? []].filter(([reference]) => reference.endsWith("/" + id)).map(([, owner]) => owner);
|
|
3257
|
-
return owners.length === 1 ? owners[0] : void 0;
|
|
3258
|
-
};
|
|
3604
|
+
const admittedOwner = (id) => ownerOf(request.view.id, id, memoryInputText(input.memoryBodyId, "memoryBodyId", 300, false), allowedBodies, request.signal);
|
|
3259
3605
|
let result;
|
|
3260
3606
|
let bodyId;
|
|
3261
3607
|
if (request.offer.sourceActionId === "manage-spaces") {
|
|
@@ -3322,9 +3668,9 @@ function createMemorySpacesSource(providerSnapshot, config = {}) {
|
|
|
3322
3668
|
} else if (request.offer.sourceActionId === "link") {
|
|
3323
3669
|
const sourceId = memoryInputText(input.sourceId, "sourceId", 2e3);
|
|
3324
3670
|
const targetId = memoryInputText(input.targetId, "targetId", 2e3);
|
|
3325
|
-
const sourceSpace = admittedOwner(sourceId);
|
|
3326
|
-
const targetSpace = admittedOwner(targetId);
|
|
3327
|
-
if (sourceSpace === void 0 || targetSpace === void 0 || sourceSpace !== targetSpace || !allowedBodies.includes(sourceSpace)) throw new Error("link requires two evidence items admitted by this View from the same Memory Space");
|
|
3671
|
+
const sourceSpace = await admittedOwner(sourceId);
|
|
3672
|
+
const targetSpace = await admittedOwner(targetId);
|
|
3673
|
+
if (sourceSpace === void 0 || targetSpace === void 0 || sourceSpace !== targetSpace || !allowedBodies.includes(sourceSpace)) throw new Error("link requires two evidence items admitted by this View from the same Memory Space, or two ids found in one Memory Space it can read");
|
|
3328
3674
|
bodyId = sourceSpace;
|
|
3329
3675
|
const edge = memoryInputText(input.type, "type", 30, false);
|
|
3330
3676
|
if (edge !== void 0 && !EDGES.has(edge)) throw new Error(`unsupported edge: ${edge}`);
|
|
@@ -3332,8 +3678,8 @@ function createMemorySpacesSource(providerSnapshot, config = {}) {
|
|
|
3332
3678
|
result = await service.link(sourceId, targetId, edge, weight, memoryInputText(input.reason, "reason", 1e3, false), request.signal, bodyId);
|
|
3333
3679
|
} else if (request.offer.sourceActionId === "forget") {
|
|
3334
3680
|
const id = memoryInputText(input.id, "id", 2e3);
|
|
3335
|
-
bodyId = admittedOwner(id);
|
|
3336
|
-
if (bodyId === void 0 || !allowedBodies.includes(bodyId)) throw new Error("forget requires evidence already admitted by this View");
|
|
3681
|
+
bodyId = await admittedOwner(id);
|
|
3682
|
+
if (bodyId === void 0 || !allowedBodies.includes(bodyId)) throw new Error("forget requires evidence already admitted by this View, or an id found in one Memory Space it can read; name the space (memoryBodyId) when several hold it");
|
|
3337
3683
|
result = await service.forget(id, request.signal, bodyId);
|
|
3338
3684
|
} else throw new Error(`unsupported Memory Spaces action: ${request.offer.sourceActionId}`);
|
|
3339
3685
|
return createMemoryMutationReceipt(request.view.id, request.offer.id, context.sourceInstanceKey, service.memoryRevision(), {
|