@anuma/sdk 6.39.3 → 6.41.0
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/expo/index.cjs +360 -92
- package/dist/expo/index.d.mts +49 -2
- package/dist/expo/index.d.ts +49 -2
- package/dist/expo/index.mjs +357 -92
- package/dist/memory/context.d.mts +2 -0
- package/dist/memory/context.d.ts +2 -0
- package/dist/react/index.cjs +322 -52
- package/dist/react/index.d.mts +49 -2
- package/dist/react/index.d.ts +49 -2
- package/dist/react/index.mjs +319 -52
- package/dist/server/index.cjs +90 -40
- package/dist/server/index.d.mts +28 -2
- package/dist/server/index.d.ts +28 -2
- package/dist/server/index.mjs +90 -40
- package/package.json +1 -1
package/dist/memory/context.d.ts
CHANGED
|
@@ -157,6 +157,8 @@ interface StoredTopic {
|
|
|
157
157
|
name: string;
|
|
158
158
|
kind?: string;
|
|
159
159
|
source: TopicSource;
|
|
160
|
+
/** How central the topic is to the memory, in (0, 1]; read it with {@link topicWeight}. */
|
|
161
|
+
weight?: number;
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
interface EntityOperationsContext {
|
package/dist/react/index.cjs
CHANGED
|
@@ -1463,6 +1463,7 @@ __export(index_exports, {
|
|
|
1463
1463
|
TOOL_RESULT_ORIGIN: () => TOOL_RESULT_ORIGIN,
|
|
1464
1464
|
TOPICS_EXTRACTION_VERSION: () => TOPICS_EXTRACTION_VERSION,
|
|
1465
1465
|
TOPIC_EXTRACTION_BATCH_SIZE: () => TOPIC_EXTRACTION_BATCH_SIZE,
|
|
1466
|
+
TOPIC_SALIENCE_WEIGHTS: () => TOPIC_SALIENCE_WEIGHTS,
|
|
1466
1467
|
TREND_RECENT_WINDOW_DAYS: () => TREND_RECENT_WINDOW_DAYS,
|
|
1467
1468
|
TREND_STALE_WINDOW_DAYS: () => TREND_STALE_WINDOW_DAYS,
|
|
1468
1469
|
TextProcessor: () => TextProcessor,
|
|
@@ -1725,6 +1726,7 @@ __export(index_exports, {
|
|
|
1725
1726
|
preEmbedVaultMemories: () => preEmbedVaultMemories,
|
|
1726
1727
|
preprocessFiles: () => preprocessFiles,
|
|
1727
1728
|
previewToolSelection: () => previewToolSelection,
|
|
1729
|
+
primaryTopic: () => primaryTopic,
|
|
1728
1730
|
projectToStored: () => projectToStored,
|
|
1729
1731
|
putAppFileOp: () => putAppFileOp,
|
|
1730
1732
|
quantizeEmbedding: () => quantizeEmbedding,
|
|
@@ -1798,6 +1800,7 @@ __export(index_exports, {
|
|
|
1798
1800
|
summarizeObservationTrends: () => summarizeObservationTrends,
|
|
1799
1801
|
supersedeVaultMemoryOp: () => supersedeVaultMemoryOp,
|
|
1800
1802
|
synthesizeProfile: () => synthesizeProfile,
|
|
1803
|
+
topicWeight: () => topicWeight,
|
|
1801
1804
|
traverseGraphLane: () => traverseGraphLane,
|
|
1802
1805
|
ttlForType: () => ttlForType,
|
|
1803
1806
|
updateAttrs: () => updateAttrs,
|
|
@@ -12951,6 +12954,20 @@ var ENTITY_KINDS = [
|
|
|
12951
12954
|
function normalizeEntityName(name) {
|
|
12952
12955
|
return name.trim().toLowerCase();
|
|
12953
12956
|
}
|
|
12957
|
+
var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
|
|
12958
|
+
function topicWeight(topic) {
|
|
12959
|
+
return topic.source === "user" ? 1 : topic.weight ?? 1;
|
|
12960
|
+
}
|
|
12961
|
+
function primaryTopic(topics) {
|
|
12962
|
+
let best = null;
|
|
12963
|
+
for (const topic of topics ?? []) {
|
|
12964
|
+
if (best === null || topicWeight(topic) > topicWeight(best)) best = topic;
|
|
12965
|
+
}
|
|
12966
|
+
return best;
|
|
12967
|
+
}
|
|
12968
|
+
function parseTopicWeight(value) {
|
|
12969
|
+
return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
|
|
12970
|
+
}
|
|
12954
12971
|
function serializeTopics(topics) {
|
|
12955
12972
|
return JSON.stringify(topics);
|
|
12956
12973
|
}
|
|
@@ -12966,12 +12983,14 @@ function parseTopics(value) {
|
|
|
12966
12983
|
const out = [];
|
|
12967
12984
|
for (const raw of parsed) {
|
|
12968
12985
|
if (typeof raw !== "object" || raw === null) continue;
|
|
12969
|
-
const { name, kind, source } = raw;
|
|
12986
|
+
const { name, kind, source, weight } = raw;
|
|
12970
12987
|
if (typeof name !== "string" || name.trim().length === 0) continue;
|
|
12988
|
+
const parsedWeight = parseTopicWeight(weight);
|
|
12971
12989
|
out.push({
|
|
12972
12990
|
name,
|
|
12973
12991
|
...typeof kind === "string" && kind.length > 0 ? { kind } : {},
|
|
12974
|
-
source: source === "user" ? "user" : "auto"
|
|
12992
|
+
source: source === "user" ? "user" : "auto",
|
|
12993
|
+
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
12975
12994
|
});
|
|
12976
12995
|
}
|
|
12977
12996
|
return out;
|
|
@@ -13058,21 +13077,47 @@ function displayNamesOf(entities) {
|
|
|
13058
13077
|
}
|
|
13059
13078
|
function topicsEqual(stored2, computed) {
|
|
13060
13079
|
if (stored2 === null || stored2.length !== computed.length) return false;
|
|
13061
|
-
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
|
|
13080
|
+
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source, t.weight ?? null]);
|
|
13062
13081
|
const storedKeys = stored2.map(key).sort();
|
|
13063
13082
|
const computedKeys = computed.map(key).sort();
|
|
13064
13083
|
return storedKeys.every((k, i) => k === computedKeys[i]);
|
|
13065
13084
|
}
|
|
13066
|
-
function resolveTopicsWrite(row, linked,
|
|
13085
|
+
function resolveTopicsWrite(row, linked, inputs, source, mode) {
|
|
13067
13086
|
if (row === null || source === null) return null;
|
|
13068
|
-
const
|
|
13069
|
-
|
|
13087
|
+
const stored2 = parseTopics(row.topics);
|
|
13088
|
+
const carried = mode === "merge" ? stored2 : null;
|
|
13089
|
+
const weights = source === "auto" ? weightsOf(carried, inputs) : null;
|
|
13090
|
+
const displayNames = displayNamesOf([...inputs, ...carried ?? []]);
|
|
13091
|
+
const topics = topicsForEntities(linked, displayNames, source, weights);
|
|
13092
|
+
if (topicsEqual(stored2, topics)) return null;
|
|
13070
13093
|
return { row, topics };
|
|
13071
13094
|
}
|
|
13072
|
-
function
|
|
13095
|
+
function weightsOf(stored2, inputs) {
|
|
13096
|
+
const out = /* @__PURE__ */ new Map();
|
|
13097
|
+
for (const topic of stored2 ?? []) out.set(normalizeEntityName(topic.name), topic.weight);
|
|
13098
|
+
for (const input of inputs) {
|
|
13099
|
+
const weight = parseTopicWeight(input.weight);
|
|
13100
|
+
if (weight === void 0) continue;
|
|
13101
|
+
const name = normalizeEntityName(input.name);
|
|
13102
|
+
if (!out.has(name)) {
|
|
13103
|
+
out.set(name, weight);
|
|
13104
|
+
continue;
|
|
13105
|
+
}
|
|
13106
|
+
const current = out.get(name);
|
|
13107
|
+
if (current !== void 0 && weight > current) out.set(name, weight);
|
|
13108
|
+
}
|
|
13109
|
+
return out;
|
|
13110
|
+
}
|
|
13111
|
+
function topicsForEntities(entities, displayNames, source, weights) {
|
|
13073
13112
|
return entities.map((e) => {
|
|
13074
13113
|
const name = displayNames.get(e.canonicalName) ?? e.canonicalName;
|
|
13075
|
-
|
|
13114
|
+
const weight = weights?.get(e.canonicalName);
|
|
13115
|
+
return {
|
|
13116
|
+
name,
|
|
13117
|
+
...e.kind ? { kind: e.kind } : {},
|
|
13118
|
+
source,
|
|
13119
|
+
...weight !== void 0 ? { weight } : {}
|
|
13120
|
+
};
|
|
13076
13121
|
});
|
|
13077
13122
|
}
|
|
13078
13123
|
function toEntityObjects(entityInputs) {
|
|
@@ -13080,7 +13125,7 @@ function toEntityObjects(entityInputs) {
|
|
|
13080
13125
|
}
|
|
13081
13126
|
async function resolveMemoryTopicsWrite(ctx, memoryId, linked, inputs, source) {
|
|
13082
13127
|
const row = await findVaultRowInWrite(ctx, memoryId);
|
|
13083
|
-
return resolveTopicsWrite(row, linked,
|
|
13128
|
+
return resolveTopicsWrite(row, linked, toEntityObjects(inputs), source, "replace");
|
|
13084
13129
|
}
|
|
13085
13130
|
function prepareMemoryTopicsUpdate(write) {
|
|
13086
13131
|
return prepareTopicsUpdate(write.row, write.topics, Date.now());
|
|
@@ -13118,8 +13163,9 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
13118
13163
|
const topicsWrite = resolveTopicsWrite(
|
|
13119
13164
|
vaultRow,
|
|
13120
13165
|
[...carriedOver, ...entities],
|
|
13121
|
-
|
|
13122
|
-
options?.topicsSource ?? "auto"
|
|
13166
|
+
normalized,
|
|
13167
|
+
options?.topicsSource ?? "auto",
|
|
13168
|
+
"merge"
|
|
13123
13169
|
);
|
|
13124
13170
|
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && topicsWrite === null) {
|
|
13125
13171
|
return;
|
|
@@ -13185,8 +13231,9 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
13185
13231
|
const topicsWrite = resolveTopicsWrite(
|
|
13186
13232
|
vaultRow,
|
|
13187
13233
|
entities,
|
|
13188
|
-
|
|
13189
|
-
options.topicsSource
|
|
13234
|
+
normalized,
|
|
13235
|
+
options.topicsSource,
|
|
13236
|
+
"replace"
|
|
13190
13237
|
);
|
|
13191
13238
|
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
|
|
13192
13239
|
return;
|
|
@@ -20719,9 +20766,9 @@ For each durable fact, output:
|
|
|
20719
20766
|
- type: one of identity | preference | relationship | plan | ongoing_context | constraint | other
|
|
20720
20767
|
- confidence: 0.0-1.0; how sure you are this is durable AND true. Only include facts >= 0.7.
|
|
20721
20768
|
- sourceMessageIds: which message IDs from the conversation contained the evidence
|
|
20722
|
-
- entities: named entities mentioned, each as an object { "name": string, "kind": one of "person" | "organization" | "place" | "event" | "product" | "thing" | "concept" | "other" }. Optional \u2014 include only NAMED entities, skip generic/common nouns. ${ENTITY_KIND_GUIDELINES} Examples:
|
|
20723
|
-
- "started a new job at Hollowpoint Labs and I'm learning Haskell for it" \u2192 entities: [{ "name": "Hollowpoint Labs", "kind": "organization" }, { "name": "Haskell", "kind": "concept" }]
|
|
20724
|
-
- "running the Berlin Half in May and I track workouts in Whoop" \u2192 entities: [{ "name": "Berlin Half", "kind": "event" }, { "name": "Whoop", "kind": "product" }]
|
|
20769
|
+
- entities: named entities mentioned, each as an object { "name": string, "kind": one of "person" | "organization" | "place" | "event" | "product" | "thing" | "concept" | "other", "salience": one of "primary" | "secondary" | "mention" }. Optional \u2014 include only NAMED entities, skip generic/common nouns. ${ENTITY_KIND_GUIDELINES} Salience is how central the entity is to the fact: "primary" = the fact is ABOUT it (usually exactly one per fact), "secondary" = a meaningful part of it, "mention" = named in passing. Examples:
|
|
20770
|
+
- "started a new job at Hollowpoint Labs and I'm learning Haskell for it" \u2192 entities: [{ "name": "Hollowpoint Labs", "kind": "organization", "salience": "primary" }, { "name": "Haskell", "kind": "concept", "salience": "secondary" }]
|
|
20771
|
+
- "running the Berlin Half in May and I track workouts in Whoop" \u2192 entities: [{ "name": "Berlin Half", "kind": "event", "salience": "primary" }, { "name": "Whoop", "kind": "product", "salience": "mention" }]
|
|
20725
20772
|
- eventTime: when the event in this fact occurs/occurred. Resolve relative phrases ("yesterday", "next week") against the current date given in the user message. Output one of:
|
|
20726
20773
|
- { "kind": "point", "start": "YYYY-MM-DD" } for a single date ("met Sara on March 14, 2026")
|
|
20727
20774
|
- { "kind": "range", "start": "YYYY-MM-DD", "end": "YYYY-MM-DD" } for a span ("Japan trip May 4\u201315, 2026")
|
|
@@ -20802,9 +20849,10 @@ function restoreCandidates(candidates, redactor, ownNames) {
|
|
|
20802
20849
|
candidate: {
|
|
20803
20850
|
...c,
|
|
20804
20851
|
content: content.text,
|
|
20805
|
-
entities: c.entities.
|
|
20806
|
-
|
|
20807
|
-
|
|
20852
|
+
entities: c.entities.flatMap((e) => {
|
|
20853
|
+
const restored = redactor.restoreForStorage(e.name);
|
|
20854
|
+
return restored.unresolved ? [] : [{ ...e, name: restored.text }];
|
|
20855
|
+
})
|
|
20808
20856
|
},
|
|
20809
20857
|
unresolved: content.unresolved
|
|
20810
20858
|
};
|
|
@@ -21033,7 +21081,12 @@ function parseEntities(raw) {
|
|
|
21033
21081
|
const name = typeof obj.name === "string" ? obj.name.trim() : "";
|
|
21034
21082
|
if (name.length === 0 || isGenericEntityName(name)) continue;
|
|
21035
21083
|
const kind = typeof obj.kind === "string" && ENTITY_KINDS.includes(obj.kind) ? obj.kind : void 0;
|
|
21036
|
-
|
|
21084
|
+
const weight = typeof obj.salience === "string" && Object.keys(TOPIC_SALIENCE_WEIGHTS).includes(obj.salience) ? TOPIC_SALIENCE_WEIGHTS[obj.salience] : void 0;
|
|
21085
|
+
out.push({
|
|
21086
|
+
name,
|
|
21087
|
+
...kind !== void 0 ? { kind } : {},
|
|
21088
|
+
...weight !== void 0 ? { weight } : {}
|
|
21089
|
+
});
|
|
21037
21090
|
}
|
|
21038
21091
|
return out;
|
|
21039
21092
|
}
|
|
@@ -23013,7 +23066,13 @@ Include only NAMED entities, skip generic/common nouns. A topic must identify a
|
|
|
23013
23066
|
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
23014
23067
|
${ENTITY_KIND_GUIDELINES}
|
|
23015
23068
|
|
|
23016
|
-
|
|
23069
|
+
Give each entity a "salience" \u2014 how central it is to the memory:
|
|
23070
|
+
- "primary": the memory is ABOUT it. A memory with entities usually has exactly one primary; never more than two.
|
|
23071
|
+
- "secondary": a meaningful part of the memory, but not its subject.
|
|
23072
|
+
- "mention": named in passing; the memory would say much the same without it.
|
|
23073
|
+
Example: "Ran the Chicago Marathon with my sister Ana in 3:41" \u2192 Chicago Marathon primary, Ana secondary.
|
|
23074
|
+
|
|
23075
|
+
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string, "salience": "primary" | "secondary" | "mention"}]}]}
|
|
23017
23076
|
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
23018
23077
|
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
23019
23078
|
No prose.`;
|
|
@@ -23084,9 +23143,10 @@ List each memory's named entities.`,
|
|
|
23084
23143
|
return out;
|
|
23085
23144
|
}
|
|
23086
23145
|
function restoreEntities(entities, redactor) {
|
|
23087
|
-
return entities.
|
|
23088
|
-
|
|
23089
|
-
|
|
23146
|
+
return entities.flatMap((e) => {
|
|
23147
|
+
const restored = redactor.restoreForStorage(e.name);
|
|
23148
|
+
return restored.unresolved ? [] : [{ ...e, name: restored.text }];
|
|
23149
|
+
});
|
|
23090
23150
|
}
|
|
23091
23151
|
function parseTopicResponse(parsed, validIds) {
|
|
23092
23152
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
@@ -23247,6 +23307,14 @@ function createLocalMemoryStore(options) {
|
|
|
23247
23307
|
getLogger().warn("[memory/store] Failed to embed memory:", err);
|
|
23248
23308
|
});
|
|
23249
23309
|
};
|
|
23310
|
+
const maintenance = {
|
|
23311
|
+
createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...sweeperOptions, vaultCtx }),
|
|
23312
|
+
getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
|
|
23313
|
+
extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
|
|
23314
|
+
stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
|
|
23315
|
+
relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
|
|
23316
|
+
backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
|
|
23317
|
+
};
|
|
23250
23318
|
return {
|
|
23251
23319
|
masksEmbeddingInput: options.embeddingOptions.maskInput !== void 0,
|
|
23252
23320
|
list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
|
|
@@ -23260,21 +23328,22 @@ function createLocalMemoryStore(options) {
|
|
|
23260
23328
|
memoriesByTopics: (names) => getMemoriesByEntityNamesOp(entityCtx, names),
|
|
23261
23329
|
topicsByMemories: (memoryIds) => getEntitiesByMemoryIdsOp(entityCtx, memoryIds),
|
|
23262
23330
|
listTopics: async () => {
|
|
23263
|
-
const links = await entityCtx.memoryEntityCollection.query(...linksOwnedBy).
|
|
23331
|
+
const links = await entityCtx.memoryEntityCollection.query(...linksOwnedBy).unsafeFetchRaw();
|
|
23264
23332
|
const members = /* @__PURE__ */ new Map();
|
|
23265
23333
|
for (const link of links) {
|
|
23266
|
-
const entityId = String(link.
|
|
23334
|
+
const entityId = String(link.entity_id);
|
|
23267
23335
|
const set = members.get(entityId) ?? /* @__PURE__ */ new Set();
|
|
23268
|
-
set.add(String(link.
|
|
23336
|
+
set.add(String(link.memory_id));
|
|
23269
23337
|
members.set(entityId, set);
|
|
23270
23338
|
}
|
|
23271
|
-
const entities = userId === void 0 ? await entityCtx.entityCollection.query().
|
|
23339
|
+
const entities = userId === void 0 ? await entityCtx.entityCollection.query().unsafeFetchRaw() : members.size ? await entityCtx.entityCollection.query(import_watermelondb32.Q.where("id", import_watermelondb32.Q.oneOf([...members.keys()]))).unsafeFetchRaw() : [];
|
|
23272
23340
|
const byName = /* @__PURE__ */ new Map();
|
|
23273
23341
|
for (const entity of entities) {
|
|
23274
|
-
const
|
|
23275
|
-
const
|
|
23276
|
-
byName.
|
|
23277
|
-
|
|
23342
|
+
const name = String(entity.canonical_name);
|
|
23343
|
+
const count2 = members.get(String(entity.id))?.size ?? 0;
|
|
23344
|
+
const existing = byName.get(name);
|
|
23345
|
+
byName.set(name, {
|
|
23346
|
+
name,
|
|
23278
23347
|
kind: existing?.kind ?? entity.kind ?? null,
|
|
23279
23348
|
memoryCount: (existing?.memoryCount ?? 0) + count2
|
|
23280
23349
|
});
|
|
@@ -23365,14 +23434,8 @@ function createLocalMemoryStore(options) {
|
|
|
23365
23434
|
}
|
|
23366
23435
|
return () => subscriptions.forEach((s) => s.unsubscribe());
|
|
23367
23436
|
},
|
|
23368
|
-
maintenance
|
|
23369
|
-
|
|
23370
|
-
getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
|
|
23371
|
-
extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
|
|
23372
|
-
stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
|
|
23373
|
-
relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
|
|
23374
|
-
backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
|
|
23375
|
-
}
|
|
23437
|
+
maintenance,
|
|
23438
|
+
topicMaintenance: maintenance
|
|
23376
23439
|
};
|
|
23377
23440
|
}
|
|
23378
23441
|
|
|
@@ -24157,7 +24220,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
24157
24220
|
const memory = {
|
|
24158
24221
|
...snapshot.memory,
|
|
24159
24222
|
content: patch.content,
|
|
24160
|
-
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Date.now()
|
|
24223
|
+
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Math.max(Date.now(), (snapshot.memory.topics_extracted_at ?? 0) + 1)
|
|
24161
24224
|
};
|
|
24162
24225
|
if (patch.scope !== void 0) memory.scope = patch.scope;
|
|
24163
24226
|
if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
|
|
@@ -24291,6 +24354,7 @@ function projection({ memory }) {
|
|
|
24291
24354
|
};
|
|
24292
24355
|
}
|
|
24293
24356
|
function relevant(change, options) {
|
|
24357
|
+
if (change === "metadata") return false;
|
|
24294
24358
|
return options.includeDeleted ? change === "membership" : change !== "embedding" || !!options.embeddings;
|
|
24295
24359
|
}
|
|
24296
24360
|
function safely(onChange) {
|
|
@@ -24371,17 +24435,32 @@ function topicInputs(topics, source) {
|
|
|
24371
24435
|
return topics.flatMap((topic) => {
|
|
24372
24436
|
const name = (typeof topic === "string" ? topic : topic.name).trim();
|
|
24373
24437
|
const kind = typeof topic === "string" ? void 0 : topic.kind;
|
|
24374
|
-
|
|
24438
|
+
const weight = typeof topic === "string" || source === "user" ? void 0 : parseTopicWeight(topic.weight);
|
|
24439
|
+
return name ? [{ name, ...kind && { kind }, source, ...weight && { weight } }] : [];
|
|
24375
24440
|
});
|
|
24376
24441
|
}
|
|
24377
24442
|
function mergeTopics(existing, added) {
|
|
24378
24443
|
const byName = /* @__PURE__ */ new Map();
|
|
24379
24444
|
for (const topic of [...existing, ...added]) {
|
|
24380
24445
|
const key = normalizeEntityName(topic.name);
|
|
24381
|
-
|
|
24446
|
+
const kept = byName.get(key);
|
|
24447
|
+
if (!kept) byName.set(key, topic);
|
|
24448
|
+
else if (kept.weight !== void 0 && topic.weight !== void 0 && topic.weight > kept.weight)
|
|
24449
|
+
byName.set(key, { ...kept, weight: topic.weight });
|
|
24382
24450
|
}
|
|
24383
24451
|
return [...byName.values()];
|
|
24384
24452
|
}
|
|
24453
|
+
function sameTopics(stored2, next) {
|
|
24454
|
+
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source, t.weight ?? null]);
|
|
24455
|
+
if (stored2 === null || stored2.length !== next.length) return false;
|
|
24456
|
+
const keys = new Set(stored2.map(key));
|
|
24457
|
+
return next.every((t) => keys.has(key(t)));
|
|
24458
|
+
}
|
|
24459
|
+
function extractionDue(memory) {
|
|
24460
|
+
const stamp = memory.topics_extracted_at;
|
|
24461
|
+
if (stamp === void 0 || stamp === null) return "fresh";
|
|
24462
|
+
return memory.updated_at > stamp || (memory.topics_extracted_version ?? 0) < TOPICS_EXTRACTION_VERSION ? "stale" : null;
|
|
24463
|
+
}
|
|
24385
24464
|
function canonicalTopics(row) {
|
|
24386
24465
|
return new Set((parseTopics(row.topics) ?? []).map((topic) => normalizeEntityName(topic.name)));
|
|
24387
24466
|
}
|
|
@@ -24394,7 +24473,12 @@ function createRemoteMemoryStore(options) {
|
|
|
24394
24473
|
const seen = /* @__PURE__ */ new Map();
|
|
24395
24474
|
let timer;
|
|
24396
24475
|
const notify = (change, records = []) => {
|
|
24397
|
-
if (timer)
|
|
24476
|
+
if (timer)
|
|
24477
|
+
for (const record2 of records) {
|
|
24478
|
+
const previous = seen.get(record2.memory.memory_id);
|
|
24479
|
+
if ((previous?.version ?? 0) + 1 === record2.version)
|
|
24480
|
+
seen.set(record2.memory.memory_id, record2);
|
|
24481
|
+
}
|
|
24398
24482
|
for (const subscriber of [...subscribers])
|
|
24399
24483
|
if (relevant(change, subscriber.options)) safely(subscriber.onChange);
|
|
24400
24484
|
};
|
|
@@ -24455,15 +24539,72 @@ function createRemoteMemoryStore(options) {
|
|
|
24455
24539
|
const record2 = await persistence.get(id);
|
|
24456
24540
|
return record2 && !record2.memory.is_deleted ? record2 : null;
|
|
24457
24541
|
};
|
|
24458
|
-
const
|
|
24542
|
+
const mutateLocked = async (id, change, edit) => {
|
|
24459
24543
|
const record2 = await live(id);
|
|
24460
24544
|
if (!record2) return null;
|
|
24461
24545
|
const next = edit(structuredClone(record2.memory));
|
|
24462
24546
|
if (!next) return null;
|
|
24463
24547
|
const saved = await persistence.put(next, record2);
|
|
24464
|
-
notify(change, [saved]);
|
|
24548
|
+
notify(typeof change === "function" ? change(record2.memory) : change, [saved]);
|
|
24465
24549
|
return saved;
|
|
24466
|
-
}
|
|
24550
|
+
};
|
|
24551
|
+
const mutate = (id, change, edit) => serialized(id, () => mutateLocked(id, change, edit));
|
|
24552
|
+
const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id) => () => serialized(id, inner), task)();
|
|
24553
|
+
const mutateMany = async (ids, change, edit) => {
|
|
24554
|
+
const saved = /* @__PURE__ */ new Map();
|
|
24555
|
+
const failed = /* @__PURE__ */ new Map();
|
|
24556
|
+
for (const slice of chunks([...new Set(ids)], MAX_BATCH)) {
|
|
24557
|
+
await serializedAll(slice, async () => {
|
|
24558
|
+
const writes = [];
|
|
24559
|
+
let read;
|
|
24560
|
+
try {
|
|
24561
|
+
read = await readEveryState(slice);
|
|
24562
|
+
} catch (error) {
|
|
24563
|
+
for (const id of slice) failed.set(id, error);
|
|
24564
|
+
return;
|
|
24565
|
+
}
|
|
24566
|
+
const { records, unreadable } = read;
|
|
24567
|
+
for (const id of slice) {
|
|
24568
|
+
const record2 = records.get(id);
|
|
24569
|
+
if (unreadable.has(id)) failed.set(id, new Error(`Memory ${id} could not be decrypted`));
|
|
24570
|
+
else if (!record2) failed.set(id, new Error(`Memory ${id} was not found`));
|
|
24571
|
+
else if (!record2.memory.is_deleted) {
|
|
24572
|
+
const memory = edit(structuredClone(record2.memory));
|
|
24573
|
+
if (memory) writes.push({ before: record2, memory });
|
|
24574
|
+
}
|
|
24575
|
+
}
|
|
24576
|
+
if (writes.length === 0) return;
|
|
24577
|
+
try {
|
|
24578
|
+
const written = await persistence.putMany(
|
|
24579
|
+
writes.map(({ before, memory }) => ({ memory, expectedVersion: before }))
|
|
24580
|
+
);
|
|
24581
|
+
const byChange = /* @__PURE__ */ new Map();
|
|
24582
|
+
written.forEach((record2, i) => {
|
|
24583
|
+
saved.set(record2.memory.memory_id, record2);
|
|
24584
|
+
const kind = change(writes[i].before.memory);
|
|
24585
|
+
byChange.set(kind, [...byChange.get(kind) ?? [], record2]);
|
|
24586
|
+
});
|
|
24587
|
+
for (const [kind, changed] of byChange) notify(kind, changed);
|
|
24588
|
+
} catch (error) {
|
|
24589
|
+
const perRow = error instanceof RemoteMemoryError && (error.code === "version_conflict" || error.status === 429);
|
|
24590
|
+
for (const { before } of writes) {
|
|
24591
|
+
const id = before.memory.memory_id;
|
|
24592
|
+
if (!perRow) {
|
|
24593
|
+
failed.set(id, error);
|
|
24594
|
+
continue;
|
|
24595
|
+
}
|
|
24596
|
+
try {
|
|
24597
|
+
const record2 = await mutateLocked(id, change, edit);
|
|
24598
|
+
if (record2) saved.set(id, record2);
|
|
24599
|
+
} catch (rowError) {
|
|
24600
|
+
failed.set(id, rowError);
|
|
24601
|
+
}
|
|
24602
|
+
}
|
|
24603
|
+
}
|
|
24604
|
+
});
|
|
24605
|
+
}
|
|
24606
|
+
return { saved, failed };
|
|
24607
|
+
};
|
|
24467
24608
|
const embedInBackground = ({ memory: { memory_id: id, content } }) => {
|
|
24468
24609
|
generateEmbedding(content, embeddingOptions).then(
|
|
24469
24610
|
(vector) => serialized(id, async () => {
|
|
@@ -24519,11 +24660,10 @@ function createRemoteMemoryStore(options) {
|
|
|
24519
24660
|
return records.map((record2) => stored(record2.memory));
|
|
24520
24661
|
};
|
|
24521
24662
|
const asStored = (record2) => record2 ? stored(record2.memory) : null;
|
|
24522
|
-
const
|
|
24663
|
+
const knownKinds = async (topics) => {
|
|
24523
24664
|
const unkinded = [
|
|
24524
24665
|
...new Set(topics.filter((t) => !t.kind).map((t) => normalizeEntityName(t.name)))
|
|
24525
24666
|
];
|
|
24526
|
-
if (unkinded.length === 0) return topics;
|
|
24527
24667
|
const kinds = /* @__PURE__ */ new Map();
|
|
24528
24668
|
for (const names of chunks(unkinded, MAX_QUERY_TOPICS)) {
|
|
24529
24669
|
for (const { memory } of await pages(metadata, {
|
|
@@ -24538,10 +24678,136 @@ function createRemoteMemoryStore(options) {
|
|
|
24538
24678
|
}
|
|
24539
24679
|
}
|
|
24540
24680
|
}
|
|
24541
|
-
return
|
|
24681
|
+
return (topic) => {
|
|
24542
24682
|
const kind = topic.kind ?? kinds.get(normalizeEntityName(topic.name));
|
|
24543
24683
|
return kind ? { ...topic, kind } : topic;
|
|
24544
|
-
}
|
|
24684
|
+
};
|
|
24685
|
+
};
|
|
24686
|
+
const withKnownKinds = async (topics) => topics.map(await knownKinds(topics));
|
|
24687
|
+
const readEveryState = async (ids) => {
|
|
24688
|
+
const records = /* @__PURE__ */ new Map();
|
|
24689
|
+
const unreadable = /* @__PURE__ */ new Set();
|
|
24690
|
+
for (const memory_ids of chunks(ids, MAX_QUERY_IDS)) {
|
|
24691
|
+
let cursor2;
|
|
24692
|
+
do {
|
|
24693
|
+
const page = await persistence.query({
|
|
24694
|
+
memory_ids,
|
|
24695
|
+
include_deleted: true,
|
|
24696
|
+
include_archived: true,
|
|
24697
|
+
include_quarantined: true,
|
|
24698
|
+
include_superseded: true,
|
|
24699
|
+
limit: 200,
|
|
24700
|
+
...cursor2 && { cursor: cursor2 }
|
|
24701
|
+
});
|
|
24702
|
+
warnFailed(page.failed);
|
|
24703
|
+
for (const record2 of page.items) records.set(record2.memory.memory_id, record2);
|
|
24704
|
+
for (const failure of page.failed) unreadable.add(failure.memory_id);
|
|
24705
|
+
cursor2 = page.next_cursor;
|
|
24706
|
+
} while (cursor2);
|
|
24707
|
+
}
|
|
24708
|
+
return { records, unreadable };
|
|
24709
|
+
};
|
|
24710
|
+
const topicMaintenance = {
|
|
24711
|
+
getTopicBacklog: async (backlogOptions = {}) => {
|
|
24712
|
+
const stale = [];
|
|
24713
|
+
const fresh = [];
|
|
24714
|
+
for (const { memory } of await pages(metadata, { order: "created" })) {
|
|
24715
|
+
if (memory.topics_user_managed) continue;
|
|
24716
|
+
const due = extractionDue(memory);
|
|
24717
|
+
if (due === "stale") stale.push(memory.memory_id);
|
|
24718
|
+
else if (due === "fresh") fresh.push(memory.memory_id);
|
|
24719
|
+
}
|
|
24720
|
+
const limit = backlogOptions.limit !== void 0 && backlogOptions.limit > 0 ? backlogOptions.limit : Infinity;
|
|
24721
|
+
return {
|
|
24722
|
+
pending: [...stale, ...fresh].slice(0, limit).map((uniqueId) => ({ uniqueId })),
|
|
24723
|
+
linkedUnstamped: [],
|
|
24724
|
+
topicsToRelink: [],
|
|
24725
|
+
topicsBackfill: []
|
|
24726
|
+
};
|
|
24727
|
+
},
|
|
24728
|
+
extractTopics: async (memoryIds, extractOptions) => {
|
|
24729
|
+
const extractedAt = extractOptions.now ?? Date.now();
|
|
24730
|
+
const skippedIds = [];
|
|
24731
|
+
const skippedReasons = /* @__PURE__ */ new Map();
|
|
24732
|
+
const skip = (id, reason) => {
|
|
24733
|
+
if (skippedReasons.has(id)) return;
|
|
24734
|
+
skippedIds.push(id);
|
|
24735
|
+
skippedReasons.set(id, reason);
|
|
24736
|
+
};
|
|
24737
|
+
const ids = [...new Set(memoryIds)];
|
|
24738
|
+
const { records, unreadable } = await readEveryState(ids);
|
|
24739
|
+
const inputs = [];
|
|
24740
|
+
for (const id of ids) {
|
|
24741
|
+
const memory = records.get(id)?.memory;
|
|
24742
|
+
if (unreadable.has(id)) skip(id, "unreadable");
|
|
24743
|
+
else if (!memory) skip(id, "not-found");
|
|
24744
|
+
else if (memory.is_deleted || memory.topics_user_managed) skip(id, "excluded");
|
|
24745
|
+
else inputs.push({ id, content: memory.content });
|
|
24746
|
+
}
|
|
24747
|
+
const entitiesByMemory = await extractEntitiesForMemories(inputs, extractOptions);
|
|
24748
|
+
const answered = /* @__PURE__ */ new Map();
|
|
24749
|
+
for (const input of inputs) {
|
|
24750
|
+
const entities = entitiesByMemory.get(input.id);
|
|
24751
|
+
if (entities === void 0) skip(input.id, "llm-unanswered");
|
|
24752
|
+
else
|
|
24753
|
+
answered.set(input.id, { content: input.content, topics: topicInputs(entities, "auto") });
|
|
24754
|
+
}
|
|
24755
|
+
const stampedIds = [];
|
|
24756
|
+
const fail = (id, reason) => {
|
|
24757
|
+
skip(id, reason);
|
|
24758
|
+
entitiesByMemory.delete(id);
|
|
24759
|
+
};
|
|
24760
|
+
try {
|
|
24761
|
+
const kinded = await knownKinds([...answered.values()].flatMap((a) => a.topics));
|
|
24762
|
+
const topics = new Map(
|
|
24763
|
+
[...answered].map(([id, a]) => [id, mergeTopics([], a.topics.map(kinded))])
|
|
24764
|
+
);
|
|
24765
|
+
const unchanged = (memory) => sameTopics(parseTopics(memory.topics), topics.get(memory.memory_id));
|
|
24766
|
+
const { saved, failed } = await mutateMany(
|
|
24767
|
+
[...answered.keys()],
|
|
24768
|
+
(before) => sameTopics(parseTopics(before.topics) ?? [], topics.get(before.memory_id)) ? "metadata" : "edit",
|
|
24769
|
+
(memory) => {
|
|
24770
|
+
if (memory.topics_user_managed || memory.content !== answered.get(memory.memory_id).content)
|
|
24771
|
+
return null;
|
|
24772
|
+
return {
|
|
24773
|
+
...memory,
|
|
24774
|
+
...!unchanged(memory) && {
|
|
24775
|
+
topics: serializeTopics(topics.get(memory.memory_id)),
|
|
24776
|
+
topics_updated_at: Date.now()
|
|
24777
|
+
},
|
|
24778
|
+
topics_extracted_at: Math.max(extractedAt, memory.updated_at),
|
|
24779
|
+
topics_extracted_version: TOPICS_EXTRACTION_VERSION
|
|
24780
|
+
};
|
|
24781
|
+
}
|
|
24782
|
+
);
|
|
24783
|
+
for (const id of answered.keys()) {
|
|
24784
|
+
if (saved.has(id)) stampedIds.push(id);
|
|
24785
|
+
else fail(id, failed.has(id) ? "link-failed" : "link-declined");
|
|
24786
|
+
}
|
|
24787
|
+
if (failed.size)
|
|
24788
|
+
getLogger().warn(
|
|
24789
|
+
"[memory/remote-store] Failed to write extracted topics:",
|
|
24790
|
+
failed.values().next().value
|
|
24791
|
+
);
|
|
24792
|
+
} catch (error) {
|
|
24793
|
+
getLogger().warn("[memory/remote-store] Failed to write extracted topics:", error);
|
|
24794
|
+
for (const id of answered.keys()) fail(id, "link-failed");
|
|
24795
|
+
}
|
|
24796
|
+
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
24797
|
+
},
|
|
24798
|
+
stampTopicsExtracted: async (memoryIds, extractedAt, version = TOPICS_EXTRACTION_VERSION) => {
|
|
24799
|
+
const ids = [...new Set(memoryIds)];
|
|
24800
|
+
const { saved, failed } = await mutateMany(
|
|
24801
|
+
ids,
|
|
24802
|
+
() => "metadata",
|
|
24803
|
+
(memory) => memory.topics_user_managed ? null : { ...memory, topics_extracted_at: extractedAt, topics_extracted_version: version }
|
|
24804
|
+
);
|
|
24805
|
+
if (failed.size)
|
|
24806
|
+
getLogger().warn("[memory/remote-store] Failed to stamp topics:", [...failed.values()]);
|
|
24807
|
+
return ids.filter((id) => saved.has(id));
|
|
24808
|
+
},
|
|
24809
|
+
relinkTopics: () => Promise.resolve([]),
|
|
24810
|
+
backfillTopics: () => Promise.resolve([])
|
|
24545
24811
|
};
|
|
24546
24812
|
const everyState = {
|
|
24547
24813
|
include_deleted: true,
|
|
@@ -24620,6 +24886,7 @@ function createRemoteMemoryStore(options) {
|
|
|
24620
24886
|
};
|
|
24621
24887
|
return {
|
|
24622
24888
|
masksEmbeddingInput: embeddingOptions.maskInput !== void 0,
|
|
24889
|
+
topicMaintenance,
|
|
24623
24890
|
list: async (listOptions = {}) => (await listRows(decrypted, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
|
|
24624
24891
|
(r) => stored(r.memory)
|
|
24625
24892
|
),
|
|
@@ -24704,7 +24971,7 @@ function createRemoteMemoryStore(options) {
|
|
|
24704
24971
|
const kind = patch.kind !== void 0 ? patch.kind : memory.kind;
|
|
24705
24972
|
assertValidKindLevel(kind, level);
|
|
24706
24973
|
memory.content = patch.content;
|
|
24707
|
-
memory.updated_at = Date.now();
|
|
24974
|
+
memory.updated_at = Math.max(Date.now(), (memory.topics_extracted_at ?? 0) + 1);
|
|
24708
24975
|
if (patch.level !== void 0) {
|
|
24709
24976
|
memory.level = level;
|
|
24710
24977
|
memory.scope = scopeForLevel(level);
|
|
@@ -39041,6 +39308,7 @@ function useWalletBinding(options = {}) {
|
|
|
39041
39308
|
TOOL_RESULT_ORIGIN,
|
|
39042
39309
|
TOPICS_EXTRACTION_VERSION,
|
|
39043
39310
|
TOPIC_EXTRACTION_BATCH_SIZE,
|
|
39311
|
+
TOPIC_SALIENCE_WEIGHTS,
|
|
39044
39312
|
TREND_RECENT_WINDOW_DAYS,
|
|
39045
39313
|
TREND_STALE_WINDOW_DAYS,
|
|
39046
39314
|
TextProcessor,
|
|
@@ -39303,6 +39571,7 @@ function useWalletBinding(options = {}) {
|
|
|
39303
39571
|
preEmbedVaultMemories,
|
|
39304
39572
|
preprocessFiles,
|
|
39305
39573
|
previewToolSelection,
|
|
39574
|
+
primaryTopic,
|
|
39306
39575
|
projectToStored,
|
|
39307
39576
|
putAppFileOp,
|
|
39308
39577
|
quantizeEmbedding,
|
|
@@ -39376,6 +39645,7 @@ function useWalletBinding(options = {}) {
|
|
|
39376
39645
|
summarizeObservationTrends,
|
|
39377
39646
|
supersedeVaultMemoryOp,
|
|
39378
39647
|
synthesizeProfile,
|
|
39648
|
+
topicWeight,
|
|
39379
39649
|
traverseGraphLane,
|
|
39380
39650
|
ttlForType,
|
|
39381
39651
|
updateAttrs,
|