@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/react/index.mjs
CHANGED
|
@@ -11098,6 +11098,20 @@ var ENTITY_KINDS = [
|
|
|
11098
11098
|
function normalizeEntityName(name) {
|
|
11099
11099
|
return name.trim().toLowerCase();
|
|
11100
11100
|
}
|
|
11101
|
+
var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
|
|
11102
|
+
function topicWeight(topic) {
|
|
11103
|
+
return topic.source === "user" ? 1 : topic.weight ?? 1;
|
|
11104
|
+
}
|
|
11105
|
+
function primaryTopic(topics) {
|
|
11106
|
+
let best = null;
|
|
11107
|
+
for (const topic of topics ?? []) {
|
|
11108
|
+
if (best === null || topicWeight(topic) > topicWeight(best)) best = topic;
|
|
11109
|
+
}
|
|
11110
|
+
return best;
|
|
11111
|
+
}
|
|
11112
|
+
function parseTopicWeight(value) {
|
|
11113
|
+
return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
|
|
11114
|
+
}
|
|
11101
11115
|
function serializeTopics(topics) {
|
|
11102
11116
|
return JSON.stringify(topics);
|
|
11103
11117
|
}
|
|
@@ -11113,12 +11127,14 @@ function parseTopics(value) {
|
|
|
11113
11127
|
const out = [];
|
|
11114
11128
|
for (const raw of parsed) {
|
|
11115
11129
|
if (typeof raw !== "object" || raw === null) continue;
|
|
11116
|
-
const { name, kind, source } = raw;
|
|
11130
|
+
const { name, kind, source, weight } = raw;
|
|
11117
11131
|
if (typeof name !== "string" || name.trim().length === 0) continue;
|
|
11132
|
+
const parsedWeight = parseTopicWeight(weight);
|
|
11118
11133
|
out.push({
|
|
11119
11134
|
name,
|
|
11120
11135
|
...typeof kind === "string" && kind.length > 0 ? { kind } : {},
|
|
11121
|
-
source: source === "user" ? "user" : "auto"
|
|
11136
|
+
source: source === "user" ? "user" : "auto",
|
|
11137
|
+
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
11122
11138
|
});
|
|
11123
11139
|
}
|
|
11124
11140
|
return out;
|
|
@@ -11205,21 +11221,47 @@ function displayNamesOf(entities) {
|
|
|
11205
11221
|
}
|
|
11206
11222
|
function topicsEqual(stored2, computed) {
|
|
11207
11223
|
if (stored2 === null || stored2.length !== computed.length) return false;
|
|
11208
|
-
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
|
|
11224
|
+
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source, t.weight ?? null]);
|
|
11209
11225
|
const storedKeys = stored2.map(key).sort();
|
|
11210
11226
|
const computedKeys = computed.map(key).sort();
|
|
11211
11227
|
return storedKeys.every((k, i) => k === computedKeys[i]);
|
|
11212
11228
|
}
|
|
11213
|
-
function resolveTopicsWrite(row, linked,
|
|
11229
|
+
function resolveTopicsWrite(row, linked, inputs, source, mode) {
|
|
11214
11230
|
if (row === null || source === null) return null;
|
|
11215
|
-
const
|
|
11216
|
-
|
|
11231
|
+
const stored2 = parseTopics(row.topics);
|
|
11232
|
+
const carried = mode === "merge" ? stored2 : null;
|
|
11233
|
+
const weights = source === "auto" ? weightsOf(carried, inputs) : null;
|
|
11234
|
+
const displayNames = displayNamesOf([...inputs, ...carried ?? []]);
|
|
11235
|
+
const topics = topicsForEntities(linked, displayNames, source, weights);
|
|
11236
|
+
if (topicsEqual(stored2, topics)) return null;
|
|
11217
11237
|
return { row, topics };
|
|
11218
11238
|
}
|
|
11219
|
-
function
|
|
11239
|
+
function weightsOf(stored2, inputs) {
|
|
11240
|
+
const out = /* @__PURE__ */ new Map();
|
|
11241
|
+
for (const topic of stored2 ?? []) out.set(normalizeEntityName(topic.name), topic.weight);
|
|
11242
|
+
for (const input of inputs) {
|
|
11243
|
+
const weight = parseTopicWeight(input.weight);
|
|
11244
|
+
if (weight === void 0) continue;
|
|
11245
|
+
const name = normalizeEntityName(input.name);
|
|
11246
|
+
if (!out.has(name)) {
|
|
11247
|
+
out.set(name, weight);
|
|
11248
|
+
continue;
|
|
11249
|
+
}
|
|
11250
|
+
const current = out.get(name);
|
|
11251
|
+
if (current !== void 0 && weight > current) out.set(name, weight);
|
|
11252
|
+
}
|
|
11253
|
+
return out;
|
|
11254
|
+
}
|
|
11255
|
+
function topicsForEntities(entities, displayNames, source, weights) {
|
|
11220
11256
|
return entities.map((e) => {
|
|
11221
11257
|
const name = displayNames.get(e.canonicalName) ?? e.canonicalName;
|
|
11222
|
-
|
|
11258
|
+
const weight = weights?.get(e.canonicalName);
|
|
11259
|
+
return {
|
|
11260
|
+
name,
|
|
11261
|
+
...e.kind ? { kind: e.kind } : {},
|
|
11262
|
+
source,
|
|
11263
|
+
...weight !== void 0 ? { weight } : {}
|
|
11264
|
+
};
|
|
11223
11265
|
});
|
|
11224
11266
|
}
|
|
11225
11267
|
function toEntityObjects(entityInputs) {
|
|
@@ -11227,7 +11269,7 @@ function toEntityObjects(entityInputs) {
|
|
|
11227
11269
|
}
|
|
11228
11270
|
async function resolveMemoryTopicsWrite(ctx, memoryId, linked, inputs, source) {
|
|
11229
11271
|
const row = await findVaultRowInWrite(ctx, memoryId);
|
|
11230
|
-
return resolveTopicsWrite(row, linked,
|
|
11272
|
+
return resolveTopicsWrite(row, linked, toEntityObjects(inputs), source, "replace");
|
|
11231
11273
|
}
|
|
11232
11274
|
function prepareMemoryTopicsUpdate(write) {
|
|
11233
11275
|
return prepareTopicsUpdate(write.row, write.topics, Date.now());
|
|
@@ -11265,8 +11307,9 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
11265
11307
|
const topicsWrite = resolveTopicsWrite(
|
|
11266
11308
|
vaultRow,
|
|
11267
11309
|
[...carriedOver, ...entities],
|
|
11268
|
-
|
|
11269
|
-
options?.topicsSource ?? "auto"
|
|
11310
|
+
normalized,
|
|
11311
|
+
options?.topicsSource ?? "auto",
|
|
11312
|
+
"merge"
|
|
11270
11313
|
);
|
|
11271
11314
|
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && topicsWrite === null) {
|
|
11272
11315
|
return;
|
|
@@ -11332,8 +11375,9 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
11332
11375
|
const topicsWrite = resolveTopicsWrite(
|
|
11333
11376
|
vaultRow,
|
|
11334
11377
|
entities,
|
|
11335
|
-
|
|
11336
|
-
options.topicsSource
|
|
11378
|
+
normalized,
|
|
11379
|
+
options.topicsSource,
|
|
11380
|
+
"replace"
|
|
11337
11381
|
);
|
|
11338
11382
|
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
|
|
11339
11383
|
return;
|
|
@@ -18839,9 +18883,9 @@ For each durable fact, output:
|
|
|
18839
18883
|
- type: one of identity | preference | relationship | plan | ongoing_context | constraint | other
|
|
18840
18884
|
- confidence: 0.0-1.0; how sure you are this is durable AND true. Only include facts >= 0.7.
|
|
18841
18885
|
- sourceMessageIds: which message IDs from the conversation contained the evidence
|
|
18842
|
-
- 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:
|
|
18843
|
-
- "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" }]
|
|
18844
|
-
- "running the Berlin Half in May and I track workouts in Whoop" \u2192 entities: [{ "name": "Berlin Half", "kind": "event" }, { "name": "Whoop", "kind": "product" }]
|
|
18886
|
+
- 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:
|
|
18887
|
+
- "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" }]
|
|
18888
|
+
- "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" }]
|
|
18845
18889
|
- 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:
|
|
18846
18890
|
- { "kind": "point", "start": "YYYY-MM-DD" } for a single date ("met Sara on March 14, 2026")
|
|
18847
18891
|
- { "kind": "range", "start": "YYYY-MM-DD", "end": "YYYY-MM-DD" } for a span ("Japan trip May 4\u201315, 2026")
|
|
@@ -18922,9 +18966,10 @@ function restoreCandidates(candidates, redactor, ownNames) {
|
|
|
18922
18966
|
candidate: {
|
|
18923
18967
|
...c,
|
|
18924
18968
|
content: content.text,
|
|
18925
|
-
entities: c.entities.
|
|
18926
|
-
|
|
18927
|
-
|
|
18969
|
+
entities: c.entities.flatMap((e) => {
|
|
18970
|
+
const restored = redactor.restoreForStorage(e.name);
|
|
18971
|
+
return restored.unresolved ? [] : [{ ...e, name: restored.text }];
|
|
18972
|
+
})
|
|
18928
18973
|
},
|
|
18929
18974
|
unresolved: content.unresolved
|
|
18930
18975
|
};
|
|
@@ -19153,7 +19198,12 @@ function parseEntities(raw) {
|
|
|
19153
19198
|
const name = typeof obj.name === "string" ? obj.name.trim() : "";
|
|
19154
19199
|
if (name.length === 0 || isGenericEntityName(name)) continue;
|
|
19155
19200
|
const kind = typeof obj.kind === "string" && ENTITY_KINDS.includes(obj.kind) ? obj.kind : void 0;
|
|
19156
|
-
|
|
19201
|
+
const weight = typeof obj.salience === "string" && Object.keys(TOPIC_SALIENCE_WEIGHTS).includes(obj.salience) ? TOPIC_SALIENCE_WEIGHTS[obj.salience] : void 0;
|
|
19202
|
+
out.push({
|
|
19203
|
+
name,
|
|
19204
|
+
...kind !== void 0 ? { kind } : {},
|
|
19205
|
+
...weight !== void 0 ? { weight } : {}
|
|
19206
|
+
});
|
|
19157
19207
|
}
|
|
19158
19208
|
return out;
|
|
19159
19209
|
}
|
|
@@ -21112,7 +21162,13 @@ Include only NAMED entities, skip generic/common nouns. A topic must identify a
|
|
|
21112
21162
|
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
21113
21163
|
${ENTITY_KIND_GUIDELINES}
|
|
21114
21164
|
|
|
21115
|
-
|
|
21165
|
+
Give each entity a "salience" \u2014 how central it is to the memory:
|
|
21166
|
+
- "primary": the memory is ABOUT it. A memory with entities usually has exactly one primary; never more than two.
|
|
21167
|
+
- "secondary": a meaningful part of the memory, but not its subject.
|
|
21168
|
+
- "mention": named in passing; the memory would say much the same without it.
|
|
21169
|
+
Example: "Ran the Chicago Marathon with my sister Ana in 3:41" \u2192 Chicago Marathon primary, Ana secondary.
|
|
21170
|
+
|
|
21171
|
+
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string, "salience": "primary" | "secondary" | "mention"}]}]}
|
|
21116
21172
|
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
21117
21173
|
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
21118
21174
|
No prose.`;
|
|
@@ -21183,9 +21239,10 @@ List each memory's named entities.`,
|
|
|
21183
21239
|
return out;
|
|
21184
21240
|
}
|
|
21185
21241
|
function restoreEntities(entities, redactor) {
|
|
21186
|
-
return entities.
|
|
21187
|
-
|
|
21188
|
-
|
|
21242
|
+
return entities.flatMap((e) => {
|
|
21243
|
+
const restored = redactor.restoreForStorage(e.name);
|
|
21244
|
+
return restored.unresolved ? [] : [{ ...e, name: restored.text }];
|
|
21245
|
+
});
|
|
21189
21246
|
}
|
|
21190
21247
|
function parseTopicResponse(parsed, validIds) {
|
|
21191
21248
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
@@ -21346,6 +21403,14 @@ function createLocalMemoryStore(options) {
|
|
|
21346
21403
|
getLogger().warn("[memory/store] Failed to embed memory:", err);
|
|
21347
21404
|
});
|
|
21348
21405
|
};
|
|
21406
|
+
const maintenance = {
|
|
21407
|
+
createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...sweeperOptions, vaultCtx }),
|
|
21408
|
+
getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
|
|
21409
|
+
extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
|
|
21410
|
+
stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
|
|
21411
|
+
relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
|
|
21412
|
+
backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
|
|
21413
|
+
};
|
|
21349
21414
|
return {
|
|
21350
21415
|
masksEmbeddingInput: options.embeddingOptions.maskInput !== void 0,
|
|
21351
21416
|
list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
|
|
@@ -21359,21 +21424,22 @@ function createLocalMemoryStore(options) {
|
|
|
21359
21424
|
memoriesByTopics: (names) => getMemoriesByEntityNamesOp(entityCtx, names),
|
|
21360
21425
|
topicsByMemories: (memoryIds) => getEntitiesByMemoryIdsOp(entityCtx, memoryIds),
|
|
21361
21426
|
listTopics: async () => {
|
|
21362
|
-
const links = await entityCtx.memoryEntityCollection.query(...linksOwnedBy).
|
|
21427
|
+
const links = await entityCtx.memoryEntityCollection.query(...linksOwnedBy).unsafeFetchRaw();
|
|
21363
21428
|
const members = /* @__PURE__ */ new Map();
|
|
21364
21429
|
for (const link of links) {
|
|
21365
|
-
const entityId = String(link.
|
|
21430
|
+
const entityId = String(link.entity_id);
|
|
21366
21431
|
const set = members.get(entityId) ?? /* @__PURE__ */ new Set();
|
|
21367
|
-
set.add(String(link.
|
|
21432
|
+
set.add(String(link.memory_id));
|
|
21368
21433
|
members.set(entityId, set);
|
|
21369
21434
|
}
|
|
21370
|
-
const entities = userId === void 0 ? await entityCtx.entityCollection.query().
|
|
21435
|
+
const entities = userId === void 0 ? await entityCtx.entityCollection.query().unsafeFetchRaw() : members.size ? await entityCtx.entityCollection.query(Q15.where("id", Q15.oneOf([...members.keys()]))).unsafeFetchRaw() : [];
|
|
21371
21436
|
const byName = /* @__PURE__ */ new Map();
|
|
21372
21437
|
for (const entity of entities) {
|
|
21373
|
-
const
|
|
21374
|
-
const
|
|
21375
|
-
byName.
|
|
21376
|
-
|
|
21438
|
+
const name = String(entity.canonical_name);
|
|
21439
|
+
const count2 = members.get(String(entity.id))?.size ?? 0;
|
|
21440
|
+
const existing = byName.get(name);
|
|
21441
|
+
byName.set(name, {
|
|
21442
|
+
name,
|
|
21377
21443
|
kind: existing?.kind ?? entity.kind ?? null,
|
|
21378
21444
|
memoryCount: (existing?.memoryCount ?? 0) + count2
|
|
21379
21445
|
});
|
|
@@ -21464,14 +21530,8 @@ function createLocalMemoryStore(options) {
|
|
|
21464
21530
|
}
|
|
21465
21531
|
return () => subscriptions.forEach((s) => s.unsubscribe());
|
|
21466
21532
|
},
|
|
21467
|
-
maintenance
|
|
21468
|
-
|
|
21469
|
-
getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
|
|
21470
|
-
extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
|
|
21471
|
-
stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
|
|
21472
|
-
relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
|
|
21473
|
-
backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
|
|
21474
|
-
}
|
|
21533
|
+
maintenance,
|
|
21534
|
+
topicMaintenance: maintenance
|
|
21475
21535
|
};
|
|
21476
21536
|
}
|
|
21477
21537
|
|
|
@@ -22255,7 +22315,7 @@ function createRemoteMemoryPipeline(options) {
|
|
|
22255
22315
|
const memory = {
|
|
22256
22316
|
...snapshot.memory,
|
|
22257
22317
|
content: patch.content,
|
|
22258
|
-
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Date.now()
|
|
22318
|
+
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Math.max(Date.now(), (snapshot.memory.topics_extracted_at ?? 0) + 1)
|
|
22259
22319
|
};
|
|
22260
22320
|
if (patch.scope !== void 0) memory.scope = patch.scope;
|
|
22261
22321
|
if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
|
|
@@ -22388,6 +22448,7 @@ function projection({ memory }) {
|
|
|
22388
22448
|
};
|
|
22389
22449
|
}
|
|
22390
22450
|
function relevant(change, options) {
|
|
22451
|
+
if (change === "metadata") return false;
|
|
22391
22452
|
return options.includeDeleted ? change === "membership" : change !== "embedding" || !!options.embeddings;
|
|
22392
22453
|
}
|
|
22393
22454
|
function safely(onChange) {
|
|
@@ -22468,17 +22529,32 @@ function topicInputs(topics, source) {
|
|
|
22468
22529
|
return topics.flatMap((topic) => {
|
|
22469
22530
|
const name = (typeof topic === "string" ? topic : topic.name).trim();
|
|
22470
22531
|
const kind = typeof topic === "string" ? void 0 : topic.kind;
|
|
22471
|
-
|
|
22532
|
+
const weight = typeof topic === "string" || source === "user" ? void 0 : parseTopicWeight(topic.weight);
|
|
22533
|
+
return name ? [{ name, ...kind && { kind }, source, ...weight && { weight } }] : [];
|
|
22472
22534
|
});
|
|
22473
22535
|
}
|
|
22474
22536
|
function mergeTopics(existing, added) {
|
|
22475
22537
|
const byName = /* @__PURE__ */ new Map();
|
|
22476
22538
|
for (const topic of [...existing, ...added]) {
|
|
22477
22539
|
const key = normalizeEntityName(topic.name);
|
|
22478
|
-
|
|
22540
|
+
const kept = byName.get(key);
|
|
22541
|
+
if (!kept) byName.set(key, topic);
|
|
22542
|
+
else if (kept.weight !== void 0 && topic.weight !== void 0 && topic.weight > kept.weight)
|
|
22543
|
+
byName.set(key, { ...kept, weight: topic.weight });
|
|
22479
22544
|
}
|
|
22480
22545
|
return [...byName.values()];
|
|
22481
22546
|
}
|
|
22547
|
+
function sameTopics(stored2, next) {
|
|
22548
|
+
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source, t.weight ?? null]);
|
|
22549
|
+
if (stored2 === null || stored2.length !== next.length) return false;
|
|
22550
|
+
const keys = new Set(stored2.map(key));
|
|
22551
|
+
return next.every((t) => keys.has(key(t)));
|
|
22552
|
+
}
|
|
22553
|
+
function extractionDue(memory) {
|
|
22554
|
+
const stamp = memory.topics_extracted_at;
|
|
22555
|
+
if (stamp === void 0 || stamp === null) return "fresh";
|
|
22556
|
+
return memory.updated_at > stamp || (memory.topics_extracted_version ?? 0) < TOPICS_EXTRACTION_VERSION ? "stale" : null;
|
|
22557
|
+
}
|
|
22482
22558
|
function canonicalTopics(row) {
|
|
22483
22559
|
return new Set((parseTopics(row.topics) ?? []).map((topic) => normalizeEntityName(topic.name)));
|
|
22484
22560
|
}
|
|
@@ -22491,7 +22567,12 @@ function createRemoteMemoryStore(options) {
|
|
|
22491
22567
|
const seen = /* @__PURE__ */ new Map();
|
|
22492
22568
|
let timer;
|
|
22493
22569
|
const notify = (change, records = []) => {
|
|
22494
|
-
if (timer)
|
|
22570
|
+
if (timer)
|
|
22571
|
+
for (const record2 of records) {
|
|
22572
|
+
const previous = seen.get(record2.memory.memory_id);
|
|
22573
|
+
if ((previous?.version ?? 0) + 1 === record2.version)
|
|
22574
|
+
seen.set(record2.memory.memory_id, record2);
|
|
22575
|
+
}
|
|
22495
22576
|
for (const subscriber of [...subscribers])
|
|
22496
22577
|
if (relevant(change, subscriber.options)) safely(subscriber.onChange);
|
|
22497
22578
|
};
|
|
@@ -22552,15 +22633,72 @@ function createRemoteMemoryStore(options) {
|
|
|
22552
22633
|
const record2 = await persistence.get(id);
|
|
22553
22634
|
return record2 && !record2.memory.is_deleted ? record2 : null;
|
|
22554
22635
|
};
|
|
22555
|
-
const
|
|
22636
|
+
const mutateLocked = async (id, change, edit) => {
|
|
22556
22637
|
const record2 = await live(id);
|
|
22557
22638
|
if (!record2) return null;
|
|
22558
22639
|
const next = edit(structuredClone(record2.memory));
|
|
22559
22640
|
if (!next) return null;
|
|
22560
22641
|
const saved = await persistence.put(next, record2);
|
|
22561
|
-
notify(change, [saved]);
|
|
22642
|
+
notify(typeof change === "function" ? change(record2.memory) : change, [saved]);
|
|
22562
22643
|
return saved;
|
|
22563
|
-
}
|
|
22644
|
+
};
|
|
22645
|
+
const mutate = (id, change, edit) => serialized(id, () => mutateLocked(id, change, edit));
|
|
22646
|
+
const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id) => () => serialized(id, inner), task)();
|
|
22647
|
+
const mutateMany = async (ids, change, edit) => {
|
|
22648
|
+
const saved = /* @__PURE__ */ new Map();
|
|
22649
|
+
const failed = /* @__PURE__ */ new Map();
|
|
22650
|
+
for (const slice of chunks([...new Set(ids)], MAX_BATCH)) {
|
|
22651
|
+
await serializedAll(slice, async () => {
|
|
22652
|
+
const writes = [];
|
|
22653
|
+
let read;
|
|
22654
|
+
try {
|
|
22655
|
+
read = await readEveryState(slice);
|
|
22656
|
+
} catch (error) {
|
|
22657
|
+
for (const id of slice) failed.set(id, error);
|
|
22658
|
+
return;
|
|
22659
|
+
}
|
|
22660
|
+
const { records, unreadable } = read;
|
|
22661
|
+
for (const id of slice) {
|
|
22662
|
+
const record2 = records.get(id);
|
|
22663
|
+
if (unreadable.has(id)) failed.set(id, new Error(`Memory ${id} could not be decrypted`));
|
|
22664
|
+
else if (!record2) failed.set(id, new Error(`Memory ${id} was not found`));
|
|
22665
|
+
else if (!record2.memory.is_deleted) {
|
|
22666
|
+
const memory = edit(structuredClone(record2.memory));
|
|
22667
|
+
if (memory) writes.push({ before: record2, memory });
|
|
22668
|
+
}
|
|
22669
|
+
}
|
|
22670
|
+
if (writes.length === 0) return;
|
|
22671
|
+
try {
|
|
22672
|
+
const written = await persistence.putMany(
|
|
22673
|
+
writes.map(({ before, memory }) => ({ memory, expectedVersion: before }))
|
|
22674
|
+
);
|
|
22675
|
+
const byChange = /* @__PURE__ */ new Map();
|
|
22676
|
+
written.forEach((record2, i) => {
|
|
22677
|
+
saved.set(record2.memory.memory_id, record2);
|
|
22678
|
+
const kind = change(writes[i].before.memory);
|
|
22679
|
+
byChange.set(kind, [...byChange.get(kind) ?? [], record2]);
|
|
22680
|
+
});
|
|
22681
|
+
for (const [kind, changed] of byChange) notify(kind, changed);
|
|
22682
|
+
} catch (error) {
|
|
22683
|
+
const perRow = error instanceof RemoteMemoryError && (error.code === "version_conflict" || error.status === 429);
|
|
22684
|
+
for (const { before } of writes) {
|
|
22685
|
+
const id = before.memory.memory_id;
|
|
22686
|
+
if (!perRow) {
|
|
22687
|
+
failed.set(id, error);
|
|
22688
|
+
continue;
|
|
22689
|
+
}
|
|
22690
|
+
try {
|
|
22691
|
+
const record2 = await mutateLocked(id, change, edit);
|
|
22692
|
+
if (record2) saved.set(id, record2);
|
|
22693
|
+
} catch (rowError) {
|
|
22694
|
+
failed.set(id, rowError);
|
|
22695
|
+
}
|
|
22696
|
+
}
|
|
22697
|
+
}
|
|
22698
|
+
});
|
|
22699
|
+
}
|
|
22700
|
+
return { saved, failed };
|
|
22701
|
+
};
|
|
22564
22702
|
const embedInBackground = ({ memory: { memory_id: id, content } }) => {
|
|
22565
22703
|
generateEmbedding(content, embeddingOptions).then(
|
|
22566
22704
|
(vector) => serialized(id, async () => {
|
|
@@ -22616,11 +22754,10 @@ function createRemoteMemoryStore(options) {
|
|
|
22616
22754
|
return records.map((record2) => stored(record2.memory));
|
|
22617
22755
|
};
|
|
22618
22756
|
const asStored = (record2) => record2 ? stored(record2.memory) : null;
|
|
22619
|
-
const
|
|
22757
|
+
const knownKinds = async (topics) => {
|
|
22620
22758
|
const unkinded = [
|
|
22621
22759
|
...new Set(topics.filter((t) => !t.kind).map((t) => normalizeEntityName(t.name)))
|
|
22622
22760
|
];
|
|
22623
|
-
if (unkinded.length === 0) return topics;
|
|
22624
22761
|
const kinds = /* @__PURE__ */ new Map();
|
|
22625
22762
|
for (const names of chunks(unkinded, MAX_QUERY_TOPICS)) {
|
|
22626
22763
|
for (const { memory } of await pages(metadata, {
|
|
@@ -22635,10 +22772,136 @@ function createRemoteMemoryStore(options) {
|
|
|
22635
22772
|
}
|
|
22636
22773
|
}
|
|
22637
22774
|
}
|
|
22638
|
-
return
|
|
22775
|
+
return (topic) => {
|
|
22639
22776
|
const kind = topic.kind ?? kinds.get(normalizeEntityName(topic.name));
|
|
22640
22777
|
return kind ? { ...topic, kind } : topic;
|
|
22641
|
-
}
|
|
22778
|
+
};
|
|
22779
|
+
};
|
|
22780
|
+
const withKnownKinds = async (topics) => topics.map(await knownKinds(topics));
|
|
22781
|
+
const readEveryState = async (ids) => {
|
|
22782
|
+
const records = /* @__PURE__ */ new Map();
|
|
22783
|
+
const unreadable = /* @__PURE__ */ new Set();
|
|
22784
|
+
for (const memory_ids of chunks(ids, MAX_QUERY_IDS)) {
|
|
22785
|
+
let cursor2;
|
|
22786
|
+
do {
|
|
22787
|
+
const page = await persistence.query({
|
|
22788
|
+
memory_ids,
|
|
22789
|
+
include_deleted: true,
|
|
22790
|
+
include_archived: true,
|
|
22791
|
+
include_quarantined: true,
|
|
22792
|
+
include_superseded: true,
|
|
22793
|
+
limit: 200,
|
|
22794
|
+
...cursor2 && { cursor: cursor2 }
|
|
22795
|
+
});
|
|
22796
|
+
warnFailed(page.failed);
|
|
22797
|
+
for (const record2 of page.items) records.set(record2.memory.memory_id, record2);
|
|
22798
|
+
for (const failure of page.failed) unreadable.add(failure.memory_id);
|
|
22799
|
+
cursor2 = page.next_cursor;
|
|
22800
|
+
} while (cursor2);
|
|
22801
|
+
}
|
|
22802
|
+
return { records, unreadable };
|
|
22803
|
+
};
|
|
22804
|
+
const topicMaintenance = {
|
|
22805
|
+
getTopicBacklog: async (backlogOptions = {}) => {
|
|
22806
|
+
const stale = [];
|
|
22807
|
+
const fresh = [];
|
|
22808
|
+
for (const { memory } of await pages(metadata, { order: "created" })) {
|
|
22809
|
+
if (memory.topics_user_managed) continue;
|
|
22810
|
+
const due = extractionDue(memory);
|
|
22811
|
+
if (due === "stale") stale.push(memory.memory_id);
|
|
22812
|
+
else if (due === "fresh") fresh.push(memory.memory_id);
|
|
22813
|
+
}
|
|
22814
|
+
const limit = backlogOptions.limit !== void 0 && backlogOptions.limit > 0 ? backlogOptions.limit : Infinity;
|
|
22815
|
+
return {
|
|
22816
|
+
pending: [...stale, ...fresh].slice(0, limit).map((uniqueId) => ({ uniqueId })),
|
|
22817
|
+
linkedUnstamped: [],
|
|
22818
|
+
topicsToRelink: [],
|
|
22819
|
+
topicsBackfill: []
|
|
22820
|
+
};
|
|
22821
|
+
},
|
|
22822
|
+
extractTopics: async (memoryIds, extractOptions) => {
|
|
22823
|
+
const extractedAt = extractOptions.now ?? Date.now();
|
|
22824
|
+
const skippedIds = [];
|
|
22825
|
+
const skippedReasons = /* @__PURE__ */ new Map();
|
|
22826
|
+
const skip = (id, reason) => {
|
|
22827
|
+
if (skippedReasons.has(id)) return;
|
|
22828
|
+
skippedIds.push(id);
|
|
22829
|
+
skippedReasons.set(id, reason);
|
|
22830
|
+
};
|
|
22831
|
+
const ids = [...new Set(memoryIds)];
|
|
22832
|
+
const { records, unreadable } = await readEveryState(ids);
|
|
22833
|
+
const inputs = [];
|
|
22834
|
+
for (const id of ids) {
|
|
22835
|
+
const memory = records.get(id)?.memory;
|
|
22836
|
+
if (unreadable.has(id)) skip(id, "unreadable");
|
|
22837
|
+
else if (!memory) skip(id, "not-found");
|
|
22838
|
+
else if (memory.is_deleted || memory.topics_user_managed) skip(id, "excluded");
|
|
22839
|
+
else inputs.push({ id, content: memory.content });
|
|
22840
|
+
}
|
|
22841
|
+
const entitiesByMemory = await extractEntitiesForMemories(inputs, extractOptions);
|
|
22842
|
+
const answered = /* @__PURE__ */ new Map();
|
|
22843
|
+
for (const input of inputs) {
|
|
22844
|
+
const entities = entitiesByMemory.get(input.id);
|
|
22845
|
+
if (entities === void 0) skip(input.id, "llm-unanswered");
|
|
22846
|
+
else
|
|
22847
|
+
answered.set(input.id, { content: input.content, topics: topicInputs(entities, "auto") });
|
|
22848
|
+
}
|
|
22849
|
+
const stampedIds = [];
|
|
22850
|
+
const fail = (id, reason) => {
|
|
22851
|
+
skip(id, reason);
|
|
22852
|
+
entitiesByMemory.delete(id);
|
|
22853
|
+
};
|
|
22854
|
+
try {
|
|
22855
|
+
const kinded = await knownKinds([...answered.values()].flatMap((a) => a.topics));
|
|
22856
|
+
const topics = new Map(
|
|
22857
|
+
[...answered].map(([id, a]) => [id, mergeTopics([], a.topics.map(kinded))])
|
|
22858
|
+
);
|
|
22859
|
+
const unchanged = (memory) => sameTopics(parseTopics(memory.topics), topics.get(memory.memory_id));
|
|
22860
|
+
const { saved, failed } = await mutateMany(
|
|
22861
|
+
[...answered.keys()],
|
|
22862
|
+
(before) => sameTopics(parseTopics(before.topics) ?? [], topics.get(before.memory_id)) ? "metadata" : "edit",
|
|
22863
|
+
(memory) => {
|
|
22864
|
+
if (memory.topics_user_managed || memory.content !== answered.get(memory.memory_id).content)
|
|
22865
|
+
return null;
|
|
22866
|
+
return {
|
|
22867
|
+
...memory,
|
|
22868
|
+
...!unchanged(memory) && {
|
|
22869
|
+
topics: serializeTopics(topics.get(memory.memory_id)),
|
|
22870
|
+
topics_updated_at: Date.now()
|
|
22871
|
+
},
|
|
22872
|
+
topics_extracted_at: Math.max(extractedAt, memory.updated_at),
|
|
22873
|
+
topics_extracted_version: TOPICS_EXTRACTION_VERSION
|
|
22874
|
+
};
|
|
22875
|
+
}
|
|
22876
|
+
);
|
|
22877
|
+
for (const id of answered.keys()) {
|
|
22878
|
+
if (saved.has(id)) stampedIds.push(id);
|
|
22879
|
+
else fail(id, failed.has(id) ? "link-failed" : "link-declined");
|
|
22880
|
+
}
|
|
22881
|
+
if (failed.size)
|
|
22882
|
+
getLogger().warn(
|
|
22883
|
+
"[memory/remote-store] Failed to write extracted topics:",
|
|
22884
|
+
failed.values().next().value
|
|
22885
|
+
);
|
|
22886
|
+
} catch (error) {
|
|
22887
|
+
getLogger().warn("[memory/remote-store] Failed to write extracted topics:", error);
|
|
22888
|
+
for (const id of answered.keys()) fail(id, "link-failed");
|
|
22889
|
+
}
|
|
22890
|
+
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
22891
|
+
},
|
|
22892
|
+
stampTopicsExtracted: async (memoryIds, extractedAt, version = TOPICS_EXTRACTION_VERSION) => {
|
|
22893
|
+
const ids = [...new Set(memoryIds)];
|
|
22894
|
+
const { saved, failed } = await mutateMany(
|
|
22895
|
+
ids,
|
|
22896
|
+
() => "metadata",
|
|
22897
|
+
(memory) => memory.topics_user_managed ? null : { ...memory, topics_extracted_at: extractedAt, topics_extracted_version: version }
|
|
22898
|
+
);
|
|
22899
|
+
if (failed.size)
|
|
22900
|
+
getLogger().warn("[memory/remote-store] Failed to stamp topics:", [...failed.values()]);
|
|
22901
|
+
return ids.filter((id) => saved.has(id));
|
|
22902
|
+
},
|
|
22903
|
+
relinkTopics: () => Promise.resolve([]),
|
|
22904
|
+
backfillTopics: () => Promise.resolve([])
|
|
22642
22905
|
};
|
|
22643
22906
|
const everyState = {
|
|
22644
22907
|
include_deleted: true,
|
|
@@ -22717,6 +22980,7 @@ function createRemoteMemoryStore(options) {
|
|
|
22717
22980
|
};
|
|
22718
22981
|
return {
|
|
22719
22982
|
masksEmbeddingInput: embeddingOptions.maskInput !== void 0,
|
|
22983
|
+
topicMaintenance,
|
|
22720
22984
|
list: async (listOptions = {}) => (await listRows(decrypted, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
|
|
22721
22985
|
(r) => stored(r.memory)
|
|
22722
22986
|
),
|
|
@@ -22801,7 +23065,7 @@ function createRemoteMemoryStore(options) {
|
|
|
22801
23065
|
const kind = patch.kind !== void 0 ? patch.kind : memory.kind;
|
|
22802
23066
|
assertValidKindLevel(kind, level);
|
|
22803
23067
|
memory.content = patch.content;
|
|
22804
|
-
memory.updated_at = Date.now();
|
|
23068
|
+
memory.updated_at = Math.max(Date.now(), (memory.topics_extracted_at ?? 0) + 1);
|
|
22805
23069
|
if (patch.level !== void 0) {
|
|
22806
23070
|
memory.level = level;
|
|
22807
23071
|
memory.scope = scopeForLevel(level);
|
|
@@ -37137,6 +37401,7 @@ export {
|
|
|
37137
37401
|
TOOL_RESULT_ORIGIN,
|
|
37138
37402
|
TOPICS_EXTRACTION_VERSION,
|
|
37139
37403
|
TOPIC_EXTRACTION_BATCH_SIZE,
|
|
37404
|
+
TOPIC_SALIENCE_WEIGHTS,
|
|
37140
37405
|
TREND_RECENT_WINDOW_DAYS,
|
|
37141
37406
|
TREND_STALE_WINDOW_DAYS,
|
|
37142
37407
|
TextProcessor,
|
|
@@ -37399,6 +37664,7 @@ export {
|
|
|
37399
37664
|
preEmbedVaultMemories,
|
|
37400
37665
|
preprocessFiles,
|
|
37401
37666
|
previewToolSelection,
|
|
37667
|
+
primaryTopic,
|
|
37402
37668
|
projectToStored,
|
|
37403
37669
|
putAppFileOp,
|
|
37404
37670
|
quantizeEmbedding,
|
|
@@ -37472,6 +37738,7 @@ export {
|
|
|
37472
37738
|
summarizeObservationTrends,
|
|
37473
37739
|
supersedeVaultMemoryOp,
|
|
37474
37740
|
synthesizeProfile,
|
|
37741
|
+
topicWeight,
|
|
37475
37742
|
traverseGraphLane,
|
|
37476
37743
|
ttlForType,
|
|
37477
37744
|
updateAttrs,
|