@anuma/sdk 6.31.4 → 6.33.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 +449 -248
- package/dist/expo/index.d.mts +433 -169
- package/dist/expo/index.d.ts +433 -169
- package/dist/expo/index.mjs +408 -209
- package/dist/memory/context.d.mts +1 -0
- package/dist/memory/context.d.ts +1 -0
- package/dist/react/index.cjs +513 -313
- package/dist/react/index.d.mts +480 -169
- package/dist/react/index.d.ts +480 -169
- package/dist/react/index.mjs +464 -268
- package/dist/server/index.cjs +416 -215
- package/dist/server/index.d.mts +431 -169
- package/dist/server/index.d.ts +431 -169
- package/dist/server/index.mjs +411 -212
- package/package.json +1 -1
package/dist/server/index.cjs
CHANGED
|
@@ -12352,7 +12352,7 @@ var require_Query = __commonJS({
|
|
|
12352
12352
|
var _subscribeToCount = _interopRequireDefault(require_subscribeToCount());
|
|
12353
12353
|
var _subscribeToQuery = _interopRequireDefault(require_subscribeToQuery());
|
|
12354
12354
|
var _subscribeToQueryWithColumns = _interopRequireDefault(require_subscribeToQueryWithColumns());
|
|
12355
|
-
var
|
|
12355
|
+
var Q12 = _interopRequireWildcard(require_QueryDescription());
|
|
12356
12356
|
var _helpers = require_helpers2();
|
|
12357
12357
|
var _class;
|
|
12358
12358
|
var _descriptor;
|
|
@@ -12384,8 +12384,8 @@ var require_Query = __commonJS({
|
|
|
12384
12384
|
(0, _initializerDefineProperty2.default)(this, "_cachedCountSubscribable", _descriptor2, this);
|
|
12385
12385
|
(0, _initializerDefineProperty2.default)(this, "_cachedCountThrottledSubscribable", _descriptor3, this);
|
|
12386
12386
|
this.collection = collection;
|
|
12387
|
-
this._rawDescription =
|
|
12388
|
-
this.description =
|
|
12387
|
+
this._rawDescription = Q12.buildQueryDescription(clauses);
|
|
12388
|
+
this.description = Q12.queryWithoutDeleted(this._rawDescription);
|
|
12389
12389
|
}
|
|
12390
12390
|
var _proto = Query2.prototype;
|
|
12391
12391
|
_proto.extend = function(...args) {
|
|
@@ -12404,12 +12404,12 @@ var require_Query = __commonJS({
|
|
|
12404
12404
|
sql
|
|
12405
12405
|
} = this._rawDescription;
|
|
12406
12406
|
(0, _invariant.default)(!sql, "Cannot extend an unsafe SQL query");
|
|
12407
|
-
return new Query2(collection, [
|
|
12407
|
+
return new Query2(collection, [Q12.experimentalJoinTables(joinTables)].concat((0, _toConsumableArray2.default)(nestedJoinTables.map(function({
|
|
12408
12408
|
from,
|
|
12409
12409
|
to
|
|
12410
12410
|
}) {
|
|
12411
|
-
return
|
|
12412
|
-
})), (0, _toConsumableArray2.default)(where), (0, _toConsumableArray2.default)(sortBy), (0, _toConsumableArray2.default)(take ? [
|
|
12411
|
+
return Q12.experimentalNestedJoin(from, to);
|
|
12412
|
+
})), (0, _toConsumableArray2.default)(where), (0, _toConsumableArray2.default)(sortBy), (0, _toConsumableArray2.default)(take ? [Q12.take(take)] : []), (0, _toConsumableArray2.default)(skip ? [Q12.skip(skip)] : []), (0, _toConsumableArray2.default)(lokiTransform ? [Q12.unsafeLokiTransform(lokiTransform)] : []), (0, _toConsumableArray2.default)(clauses)));
|
|
12413
12413
|
};
|
|
12414
12414
|
_proto.pipe = function(transform) {
|
|
12415
12415
|
return transform(this);
|
|
@@ -13851,7 +13851,7 @@ var require_helpers5 = __commonJS({
|
|
|
13851
13851
|
exports2.createTimestampsFor = void 0;
|
|
13852
13852
|
exports2.fetchDescendants = fetchDescendants;
|
|
13853
13853
|
var _fp = require_fp();
|
|
13854
|
-
var
|
|
13854
|
+
var Q12 = _interopRequireWildcard(require_QueryDescription());
|
|
13855
13855
|
function _getRequireWildcardCache(e) {
|
|
13856
13856
|
if ("function" != typeof WeakMap) return null;
|
|
13857
13857
|
var r = /* @__PURE__ */ new WeakMap(), t = /* @__PURE__ */ new WeakMap();
|
|
@@ -13889,7 +13889,7 @@ var require_helpers5 = __commonJS({
|
|
|
13889
13889
|
});
|
|
13890
13890
|
var childrenQueries = hasManyAssociations.map(function([key, value]) {
|
|
13891
13891
|
var childCollection = model.collections.get(key);
|
|
13892
|
-
return childCollection.query(
|
|
13892
|
+
return childCollection.query(Q12.where(value.foreignKey, model.id));
|
|
13893
13893
|
});
|
|
13894
13894
|
return childrenQueries;
|
|
13895
13895
|
}
|
|
@@ -14270,8 +14270,8 @@ var require_watermelondb = __commonJS({
|
|
|
14270
14270
|
var _interopRequireDefault = require_interopRequireDefault();
|
|
14271
14271
|
exports2.__esModule = true;
|
|
14272
14272
|
exports2.tableSchema = exports2.tableName = exports2.localStorageKey = exports2.columnName = exports2.associations = exports2.appSchema = exports2.Relation = exports2.Query = exports2.Q = exports2.Model = exports2.Database = exports2.Collection = void 0;
|
|
14273
|
-
var
|
|
14274
|
-
exports2.Q =
|
|
14273
|
+
var Q12 = _interopRequireWildcard(require_QueryDescription());
|
|
14274
|
+
exports2.Q = Q12;
|
|
14275
14275
|
var _Collection = _interopRequireDefault(require_Collection());
|
|
14276
14276
|
exports2.Collection = _Collection.default;
|
|
14277
14277
|
var _Database = _interopRequireDefault(require_Database());
|
|
@@ -14475,7 +14475,7 @@ var require_children = __commonJS({
|
|
|
14475
14475
|
var _makeDecorator = _interopRequireDefault(require_makeDecorator());
|
|
14476
14476
|
var _logError = _interopRequireDefault(require_logError());
|
|
14477
14477
|
var _invariant = _interopRequireDefault(require_invariant());
|
|
14478
|
-
var
|
|
14478
|
+
var Q12 = _interopRequireWildcard(require_QueryDescription());
|
|
14479
14479
|
function _getRequireWildcardCache(e) {
|
|
14480
14480
|
if ("function" != typeof WeakMap) return null;
|
|
14481
14481
|
var r = /* @__PURE__ */ new WeakMap(), t = /* @__PURE__ */ new WeakMap();
|
|
@@ -14509,7 +14509,7 @@ var require_children = __commonJS({
|
|
|
14509
14509
|
var childCollection = model.collections.get(childTable);
|
|
14510
14510
|
var association = model.constructor.associations[childTable];
|
|
14511
14511
|
(0, _invariant.default)(association && "has_many" === association.type, "@children decorator used for a table that's not has_many");
|
|
14512
|
-
var query = childCollection.query(
|
|
14512
|
+
var query = childCollection.query(Q12.where(association.foreignKey, model.id));
|
|
14513
14513
|
that._childrenQueryCache[childTable] = query;
|
|
14514
14514
|
return query;
|
|
14515
14515
|
},
|
|
@@ -16453,6 +16453,7 @@ __export(index_exports, {
|
|
|
16453
16453
|
createDurableAutoExtractor: () => createDurableAutoExtractor,
|
|
16454
16454
|
createLlmDecayClassifier: () => createLlmDecayClassifier,
|
|
16455
16455
|
createLlmNeighborRefiner: () => createLlmNeighborRefiner,
|
|
16456
|
+
createLocalMemoryStore: () => createLocalMemoryStore,
|
|
16456
16457
|
createMediaBatchOp: () => createMediaBatchOp,
|
|
16457
16458
|
createMediaOp: () => createMediaOp,
|
|
16458
16459
|
createMemoryEngineTool: () => createMemoryEngineTool,
|
|
@@ -22738,6 +22739,51 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
22738
22739
|
return null;
|
|
22739
22740
|
}
|
|
22740
22741
|
}
|
|
22742
|
+
async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
22743
|
+
const entityCtx = ctx.entityCtx;
|
|
22744
|
+
if (!entityCtx) {
|
|
22745
|
+
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
22746
|
+
}
|
|
22747
|
+
let record;
|
|
22748
|
+
try {
|
|
22749
|
+
record = await ctx.vaultMemoryCollection.find(memoryId);
|
|
22750
|
+
} catch {
|
|
22751
|
+
return null;
|
|
22752
|
+
}
|
|
22753
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
|
|
22754
|
+
let stale = false;
|
|
22755
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
22756
|
+
await ctx.database.write(async (writer) => {
|
|
22757
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
|
|
22758
|
+
stale = true;
|
|
22759
|
+
return;
|
|
22760
|
+
}
|
|
22761
|
+
await record.update((r) => {
|
|
22762
|
+
r._setRaw("topics_user_managed", true);
|
|
22763
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
22764
|
+
});
|
|
22765
|
+
const linked = entities.length > 0 ? await writer.callWriter(
|
|
22766
|
+
() => linkMemoryEntitiesOp(entityCtx, memoryId, entities, { topicsSource: "user" })
|
|
22767
|
+
) : [];
|
|
22768
|
+
const keep = new Set(linked.map((e) => e.uniqueId));
|
|
22769
|
+
const existing = await entityCtx.memoryEntityCollection.query(import_watermelondb18.Q.where("memory_id", memoryId)).fetch();
|
|
22770
|
+
const staleLinks = existing.filter((l) => !keep.has(String(l.entityId)));
|
|
22771
|
+
if (staleLinks.length === 0 && entities.length > 0) return;
|
|
22772
|
+
const topicsWrite = await resolveMemoryTopicsWrite(
|
|
22773
|
+
entityCtx,
|
|
22774
|
+
memoryId,
|
|
22775
|
+
linked,
|
|
22776
|
+
entities,
|
|
22777
|
+
"user"
|
|
22778
|
+
);
|
|
22779
|
+
await ctx.database.batch(
|
|
22780
|
+
...staleLinks.map((l) => l.prepareDestroyPermanently()),
|
|
22781
|
+
...topicsWrite ? [prepareMemoryTopicsUpdate(topicsWrite)] : []
|
|
22782
|
+
);
|
|
22783
|
+
});
|
|
22784
|
+
if (stale) return null;
|
|
22785
|
+
return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
22786
|
+
}
|
|
22741
22787
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
22742
22788
|
let record;
|
|
22743
22789
|
try {
|
|
@@ -27246,7 +27292,10 @@ async function eagerEmbedContent(content, embeddingOptions, cache, vaultCtx, mem
|
|
|
27246
27292
|
if (memoryId) cacheRowVector(cache, memoryId, Float32Array.from(embedding), updatedAt, content);
|
|
27247
27293
|
if (vaultCtx && memoryId) {
|
|
27248
27294
|
const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
27249
|
-
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel
|
|
27295
|
+
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel, {
|
|
27296
|
+
content,
|
|
27297
|
+
...updatedAt !== void 0 && { updatedAt: updatedAt.getTime() }
|
|
27298
|
+
}).catch(
|
|
27250
27299
|
// Silently swallow – SDK must not use console.*; embedding will be retried on next search
|
|
27251
27300
|
() => {
|
|
27252
27301
|
}
|
|
@@ -31556,6 +31605,353 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
31556
31605
|
};
|
|
31557
31606
|
}
|
|
31558
31607
|
|
|
31608
|
+
// src/lib/memory/store/local.ts
|
|
31609
|
+
var import_watermelondb24 = __toESM(require_watermelondb());
|
|
31610
|
+
init_logger();
|
|
31611
|
+
|
|
31612
|
+
// src/lib/memory/topicExtract.ts
|
|
31613
|
+
init_logger();
|
|
31614
|
+
init_redactor();
|
|
31615
|
+
init_portalLlm();
|
|
31616
|
+
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
31617
|
+
var MAX_CHARS_PER_MEMORY = 300;
|
|
31618
|
+
var MAX_VOCABULARY_NAMES = 100;
|
|
31619
|
+
var MAX_COMPLETION_TOKENS = 8192;
|
|
31620
|
+
var SYSTEM_PROMPT6 = `You assign topics to saved memories for a personal memory system.
|
|
31621
|
+
|
|
31622
|
+
Each memory is a short statement about the user. For each memory, list the NAMED entities it mentions \u2014 these become the memory's topics, used to connect related memories in a knowledge graph.
|
|
31623
|
+
|
|
31624
|
+
Include only NAMED entities, skip generic/common nouns. A topic must identify a specific thing the user could recognize by name; if it would be equally true of thousands of unrelated memories, leave it out:
|
|
31625
|
+
- SKIP bare generic nouns even when the memory capitalizes them or a calendar entry is titled that way \u2014 "Home", "Work", "Meeting", "Lunch", "Birthday", "Appointment", "Trip", "Today", "Friday", "March" are NOT topics.
|
|
31626
|
+
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
31627
|
+
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
31628
|
+
${ENTITY_KIND_GUIDELINES}
|
|
31629
|
+
|
|
31630
|
+
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
31631
|
+
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
31632
|
+
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
31633
|
+
No prose.`;
|
|
31634
|
+
async function extractEntitiesForMemories(memories, options) {
|
|
31635
|
+
const out = /* @__PURE__ */ new Map();
|
|
31636
|
+
if (memories.length === 0) return out;
|
|
31637
|
+
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
31638
|
+
const vocabulary = [];
|
|
31639
|
+
for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
|
|
31640
|
+
vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
|
|
31641
|
+
}
|
|
31642
|
+
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
31643
|
+
When a memory refers to one of these, reuse the EXACT existing name (same spelling, casing, spacing and punctuation) instead of a variant \u2014 if "Foo.ai" is listed, never emit "Foo ai" or "Foo AI", and if "Jane Roe" is listed, emit that rather than a bare "Jane".
|
|
31644
|
+
|
|
31645
|
+
` : "";
|
|
31646
|
+
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
31647
|
+
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
31648
|
+
const rows = [];
|
|
31649
|
+
for (const m of batch) {
|
|
31650
|
+
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
|
|
31651
|
+
rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
|
|
31652
|
+
}
|
|
31653
|
+
const listing = rows.join("\n");
|
|
31654
|
+
const parsed = await callPortalJsonCompletion({
|
|
31655
|
+
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
31656
|
+
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
31657
|
+
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
31658
|
+
taskType: "memory_topic",
|
|
31659
|
+
...options.endpointOverride !== void 0 && {
|
|
31660
|
+
endpointOverride: options.endpointOverride
|
|
31661
|
+
},
|
|
31662
|
+
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
31663
|
+
systemPrompt: SYSTEM_PROMPT6,
|
|
31664
|
+
userMessage: `${vocabularyNote}Memories:
|
|
31665
|
+
${listing}
|
|
31666
|
+
|
|
31667
|
+
List each memory's named entities.`,
|
|
31668
|
+
tag: "memory/topics",
|
|
31669
|
+
extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
|
|
31670
|
+
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
31671
|
+
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
31672
|
+
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
31673
|
+
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
31674
|
+
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
31675
|
+
});
|
|
31676
|
+
if (parsed === null) {
|
|
31677
|
+
getLogger().warn(
|
|
31678
|
+
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
31679
|
+
);
|
|
31680
|
+
continue;
|
|
31681
|
+
}
|
|
31682
|
+
const validIds = new Set(batch.map((m) => m.id));
|
|
31683
|
+
const byId = parseTopicResponse(parsed, validIds);
|
|
31684
|
+
if (byId === null) {
|
|
31685
|
+
getLogger().warn(
|
|
31686
|
+
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
31687
|
+
);
|
|
31688
|
+
continue;
|
|
31689
|
+
}
|
|
31690
|
+
for (const m of batch) {
|
|
31691
|
+
const entities = byId.get(m.id);
|
|
31692
|
+
if (entities === void 0) {
|
|
31693
|
+
continue;
|
|
31694
|
+
}
|
|
31695
|
+
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
31696
|
+
}
|
|
31697
|
+
}
|
|
31698
|
+
return out;
|
|
31699
|
+
}
|
|
31700
|
+
function restoreEntities(entities, redactor) {
|
|
31701
|
+
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
31702
|
+
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
31703
|
+
);
|
|
31704
|
+
}
|
|
31705
|
+
function parseTopicResponse(parsed, validIds) {
|
|
31706
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
31707
|
+
const list = parsed.memories;
|
|
31708
|
+
if (!Array.isArray(list)) return null;
|
|
31709
|
+
const out = /* @__PURE__ */ new Map();
|
|
31710
|
+
for (const raw of list) {
|
|
31711
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
31712
|
+
const obj = raw;
|
|
31713
|
+
if (typeof obj.id !== "string") continue;
|
|
31714
|
+
const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
|
|
31715
|
+
if (!validIds.has(id) || out.has(id)) continue;
|
|
31716
|
+
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
31717
|
+
out.set(id, entities);
|
|
31718
|
+
}
|
|
31719
|
+
return out;
|
|
31720
|
+
}
|
|
31721
|
+
var DEGRADED_TOPIC_SKIP = {
|
|
31722
|
+
excluded: false,
|
|
31723
|
+
"link-declined": false,
|
|
31724
|
+
"stamp-declined": false,
|
|
31725
|
+
"llm-unanswered": true,
|
|
31726
|
+
unreadable: true,
|
|
31727
|
+
"not-found": true,
|
|
31728
|
+
"link-failed": true
|
|
31729
|
+
};
|
|
31730
|
+
function isDegradedTopicSkip(reason) {
|
|
31731
|
+
return DEGRADED_TOPIC_SKIP[reason] === true;
|
|
31732
|
+
}
|
|
31733
|
+
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
31734
|
+
const entityCtx = ctx.entityCtx;
|
|
31735
|
+
if (!entityCtx) {
|
|
31736
|
+
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
31737
|
+
}
|
|
31738
|
+
const log = getLogger();
|
|
31739
|
+
const extractedAt = options.now ?? Date.now();
|
|
31740
|
+
const skippedIds = [];
|
|
31741
|
+
const skippedReasons = /* @__PURE__ */ new Map();
|
|
31742
|
+
const skip = (id, reason) => {
|
|
31743
|
+
if (skippedReasons.has(id)) return;
|
|
31744
|
+
skippedIds.push(id);
|
|
31745
|
+
skippedReasons.set(id, reason);
|
|
31746
|
+
};
|
|
31747
|
+
const inputs = [];
|
|
31748
|
+
for (const id of new Set(memoryIds)) {
|
|
31749
|
+
let record;
|
|
31750
|
+
try {
|
|
31751
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
31752
|
+
} catch (err) {
|
|
31753
|
+
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
31754
|
+
skip(id, "not-found");
|
|
31755
|
+
continue;
|
|
31756
|
+
}
|
|
31757
|
+
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
31758
|
+
skip(id, "excluded");
|
|
31759
|
+
continue;
|
|
31760
|
+
}
|
|
31761
|
+
try {
|
|
31762
|
+
const stored = await vaultMemoryToStored(
|
|
31763
|
+
record,
|
|
31764
|
+
ctx.walletAddress,
|
|
31765
|
+
ctx.signMessage,
|
|
31766
|
+
ctx.embeddedWalletSigner
|
|
31767
|
+
);
|
|
31768
|
+
inputs.push({ id, content: stored.content });
|
|
31769
|
+
} catch (err) {
|
|
31770
|
+
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
31771
|
+
skip(id, "unreadable");
|
|
31772
|
+
}
|
|
31773
|
+
}
|
|
31774
|
+
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
31775
|
+
const toStamp = [];
|
|
31776
|
+
for (const input of inputs) {
|
|
31777
|
+
const entities = entitiesByMemory.get(input.id);
|
|
31778
|
+
if (entities === void 0) {
|
|
31779
|
+
skip(input.id, "llm-unanswered");
|
|
31780
|
+
continue;
|
|
31781
|
+
}
|
|
31782
|
+
try {
|
|
31783
|
+
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
31784
|
+
if (linked === null) {
|
|
31785
|
+
skip(input.id, "link-declined");
|
|
31786
|
+
entitiesByMemory.delete(input.id);
|
|
31787
|
+
continue;
|
|
31788
|
+
}
|
|
31789
|
+
} catch (err) {
|
|
31790
|
+
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
31791
|
+
skip(input.id, "link-failed");
|
|
31792
|
+
entitiesByMemory.delete(input.id);
|
|
31793
|
+
continue;
|
|
31794
|
+
}
|
|
31795
|
+
toStamp.push(input.id);
|
|
31796
|
+
}
|
|
31797
|
+
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
31798
|
+
const stampedSet = new Set(stampedIds);
|
|
31799
|
+
for (const id of toStamp) {
|
|
31800
|
+
if (!stampedSet.has(id)) {
|
|
31801
|
+
skip(id, "stamp-declined");
|
|
31802
|
+
entitiesByMemory.delete(id);
|
|
31803
|
+
}
|
|
31804
|
+
}
|
|
31805
|
+
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
31806
|
+
}
|
|
31807
|
+
|
|
31808
|
+
// src/lib/memory/store/local.ts
|
|
31809
|
+
function createLocalMemoryStore(options) {
|
|
31810
|
+
const { database, userId } = options;
|
|
31811
|
+
const entityCtx = {
|
|
31812
|
+
database,
|
|
31813
|
+
entityCollection: database.get("entity"),
|
|
31814
|
+
memoryEntityCollection: database.get("memory_entity"),
|
|
31815
|
+
...userId !== void 0 && { userId },
|
|
31816
|
+
...options.allowUnscopedRows !== void 0 && {
|
|
31817
|
+
allowUnscopedRows: options.allowUnscopedRows
|
|
31818
|
+
}
|
|
31819
|
+
};
|
|
31820
|
+
const vaultCtx = {
|
|
31821
|
+
database,
|
|
31822
|
+
vaultMemoryCollection: database.get("memory_vault"),
|
|
31823
|
+
walletAddress: options.walletAddress,
|
|
31824
|
+
signMessage: options.signMessage,
|
|
31825
|
+
embeddedWalletSigner: options.embeddedWalletSigner,
|
|
31826
|
+
...userId !== void 0 && { userId },
|
|
31827
|
+
...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
|
|
31828
|
+
// Deletes cascade to memory_entity, so the graph lane never serves a
|
|
31829
|
+
// deleted memory's id.
|
|
31830
|
+
entityCtx
|
|
31831
|
+
};
|
|
31832
|
+
const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
|
|
31833
|
+
const ownedBy = userId !== void 0 ? [import_watermelondb24.Q.where("user_id", userId)] : [];
|
|
31834
|
+
const watchedColumns = [
|
|
31835
|
+
"content",
|
|
31836
|
+
"scope",
|
|
31837
|
+
"updated_at",
|
|
31838
|
+
"fact_type",
|
|
31839
|
+
"event_time_start",
|
|
31840
|
+
"event_time_end",
|
|
31841
|
+
"event_time_kind",
|
|
31842
|
+
"archived_at",
|
|
31843
|
+
"trust_tier",
|
|
31844
|
+
"superseded_by",
|
|
31845
|
+
"visibility",
|
|
31846
|
+
"published_at",
|
|
31847
|
+
"geohash",
|
|
31848
|
+
"topics",
|
|
31849
|
+
"topics_user_managed",
|
|
31850
|
+
"media",
|
|
31851
|
+
"source"
|
|
31852
|
+
];
|
|
31853
|
+
const embedInBackground = (memory) => {
|
|
31854
|
+
eagerEmbedContent(
|
|
31855
|
+
memory.content,
|
|
31856
|
+
options.embeddingOptions,
|
|
31857
|
+
vaultCache,
|
|
31858
|
+
vaultCtx,
|
|
31859
|
+
memory.uniqueId,
|
|
31860
|
+
memory.updatedAt
|
|
31861
|
+
).catch((err) => {
|
|
31862
|
+
getLogger().warn("[memory/store] Failed to embed memory:", err);
|
|
31863
|
+
});
|
|
31864
|
+
};
|
|
31865
|
+
return {
|
|
31866
|
+
list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
|
|
31867
|
+
get: (id) => getVaultMemoryOp(vaultCtx, id),
|
|
31868
|
+
listArchived: async () => {
|
|
31869
|
+
const ids = await vaultCtx.vaultMemoryCollection.query(import_watermelondb24.Q.where("is_deleted", false), import_watermelondb24.Q.where("archived_at", import_watermelondb24.Q.notEq(null)), ...ownedBy).fetchIds();
|
|
31870
|
+
if (ids.length === 0) return [];
|
|
31871
|
+
const rows = await getAllVaultMemoriesOp(vaultCtx, { memoryIds: ids, includeArchived: true });
|
|
31872
|
+
return rows.sort((a, b) => (b.archivedAt ?? 0) - (a.archivedAt ?? 0));
|
|
31873
|
+
},
|
|
31874
|
+
memoriesByTopics: (names) => getMemoriesByEntityNamesOp(entityCtx, names),
|
|
31875
|
+
topicsByMemories: (memoryIds) => getEntitiesByMemoryIdsOp(entityCtx, memoryIds),
|
|
31876
|
+
create: async (input) => {
|
|
31877
|
+
const created = await createVaultMemoryOp(vaultCtx, input);
|
|
31878
|
+
if (input.embedding === void 0) embedInBackground(created);
|
|
31879
|
+
return created;
|
|
31880
|
+
},
|
|
31881
|
+
createMany: async (inputs) => {
|
|
31882
|
+
const created = await createVaultMemoriesBatchOp(vaultCtx, inputs);
|
|
31883
|
+
created.forEach((memory, i) => {
|
|
31884
|
+
if (inputs[i].embedding === void 0) embedInBackground(memory);
|
|
31885
|
+
});
|
|
31886
|
+
return created;
|
|
31887
|
+
},
|
|
31888
|
+
update: async (id, patch) => {
|
|
31889
|
+
const reembed = patch.embedding === void 0;
|
|
31890
|
+
const updated = await updateVaultMemoryOp(
|
|
31891
|
+
vaultCtx,
|
|
31892
|
+
id,
|
|
31893
|
+
reembed ? { ...patch, embedding: null } : patch
|
|
31894
|
+
);
|
|
31895
|
+
if (!updated) return null;
|
|
31896
|
+
vaultCache.delete(id);
|
|
31897
|
+
if (reembed) embedInBackground(updated);
|
|
31898
|
+
return updated;
|
|
31899
|
+
},
|
|
31900
|
+
delete: async (id) => {
|
|
31901
|
+
const deleted = await deleteVaultMemoryOp(vaultCtx, id);
|
|
31902
|
+
if (deleted) vaultCache.delete(id);
|
|
31903
|
+
return deleted;
|
|
31904
|
+
},
|
|
31905
|
+
supersede: (id, supersededById) => supersedeVaultMemoryOp(vaultCtx, id, supersededById),
|
|
31906
|
+
archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
|
|
31907
|
+
restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
|
|
31908
|
+
setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
|
|
31909
|
+
addTopics: (memoryId, topics) => database.write(async (writer) => {
|
|
31910
|
+
const owned = await vaultCtx.vaultMemoryCollection.query(import_watermelondb24.Q.where("id", memoryId), import_watermelondb24.Q.where("is_deleted", false), ...ownedBy).fetchCount();
|
|
31911
|
+
return owned > 0 ? writer.callWriter(() => linkMemoryEntitiesOp(entityCtx, memoryId, topics)) : [];
|
|
31912
|
+
}),
|
|
31913
|
+
setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
|
|
31914
|
+
recall: (query, recallOptions) => recall(
|
|
31915
|
+
query,
|
|
31916
|
+
{ vaultCtx, entityCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
31917
|
+
{ ...recallOptions, types: ["fact"] }
|
|
31918
|
+
),
|
|
31919
|
+
retain: (content, retainOptions) => retain(
|
|
31920
|
+
content,
|
|
31921
|
+
{ vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
31922
|
+
retainOptions
|
|
31923
|
+
),
|
|
31924
|
+
subscribe: (onChange, subscribeOptions) => {
|
|
31925
|
+
const afterFirst = () => {
|
|
31926
|
+
let first = true;
|
|
31927
|
+
return () => {
|
|
31928
|
+
if (first) first = false;
|
|
31929
|
+
else onChange();
|
|
31930
|
+
};
|
|
31931
|
+
};
|
|
31932
|
+
const memories = subscribeOptions?.includeDeleted ? vaultCtx.vaultMemoryCollection.query(...ownedBy).observe() : vaultCtx.vaultMemoryCollection.query(import_watermelondb24.Q.where("is_deleted", false), ...ownedBy).observeWithColumns(
|
|
31933
|
+
subscribeOptions?.embeddings ? [...watchedColumns, "embedding", "embedding_model"] : watchedColumns
|
|
31934
|
+
);
|
|
31935
|
+
const subscriptions = [memories.subscribe(afterFirst())];
|
|
31936
|
+
if (subscribeOptions?.topics) {
|
|
31937
|
+
const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [import_watermelondb24.Q.or(import_watermelondb24.Q.where("user_id", userId), import_watermelondb24.Q.where("user_id", null))] : [import_watermelondb24.Q.where("user_id", userId)];
|
|
31938
|
+
subscriptions.push(
|
|
31939
|
+
entityCtx.memoryEntityCollection.query(...linksOwnedBy).observe().subscribe(afterFirst())
|
|
31940
|
+
);
|
|
31941
|
+
}
|
|
31942
|
+
return () => subscriptions.forEach((s) => s.unsubscribe());
|
|
31943
|
+
},
|
|
31944
|
+
maintenance: {
|
|
31945
|
+
createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...sweeperOptions, vaultCtx }),
|
|
31946
|
+
getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
|
|
31947
|
+
extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
|
|
31948
|
+
stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
|
|
31949
|
+
relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
|
|
31950
|
+
backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
|
|
31951
|
+
}
|
|
31952
|
+
};
|
|
31953
|
+
}
|
|
31954
|
+
|
|
31559
31955
|
// src/lib/memory/synthesizeProfile.ts
|
|
31560
31956
|
init_internalFlowMarker();
|
|
31561
31957
|
init_logger();
|
|
@@ -32085,202 +32481,6 @@ function normalizeInterests(values) {
|
|
|
32085
32481
|
return out.length > 0 ? out : void 0;
|
|
32086
32482
|
}
|
|
32087
32483
|
|
|
32088
|
-
// src/lib/memory/topicExtract.ts
|
|
32089
|
-
init_logger();
|
|
32090
|
-
init_redactor();
|
|
32091
|
-
init_portalLlm();
|
|
32092
|
-
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
32093
|
-
var MAX_CHARS_PER_MEMORY = 300;
|
|
32094
|
-
var MAX_VOCABULARY_NAMES = 100;
|
|
32095
|
-
var MAX_COMPLETION_TOKENS = 8192;
|
|
32096
|
-
var SYSTEM_PROMPT6 = `You assign topics to saved memories for a personal memory system.
|
|
32097
|
-
|
|
32098
|
-
Each memory is a short statement about the user. For each memory, list the NAMED entities it mentions \u2014 these become the memory's topics, used to connect related memories in a knowledge graph.
|
|
32099
|
-
|
|
32100
|
-
Include only NAMED entities, skip generic/common nouns. A topic must identify a specific thing the user could recognize by name; if it would be equally true of thousands of unrelated memories, leave it out:
|
|
32101
|
-
- SKIP bare generic nouns even when the memory capitalizes them or a calendar entry is titled that way \u2014 "Home", "Work", "Meeting", "Lunch", "Birthday", "Appointment", "Trip", "Today", "Friday", "March" are NOT topics.
|
|
32102
|
-
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
32103
|
-
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
32104
|
-
${ENTITY_KIND_GUIDELINES}
|
|
32105
|
-
|
|
32106
|
-
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
32107
|
-
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
32108
|
-
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
32109
|
-
No prose.`;
|
|
32110
|
-
async function extractEntitiesForMemories(memories, options) {
|
|
32111
|
-
const out = /* @__PURE__ */ new Map();
|
|
32112
|
-
if (memories.length === 0) return out;
|
|
32113
|
-
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
32114
|
-
const vocabulary = [];
|
|
32115
|
-
for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
|
|
32116
|
-
vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
|
|
32117
|
-
}
|
|
32118
|
-
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
32119
|
-
When a memory refers to one of these, reuse the EXACT existing name (same spelling, casing, spacing and punctuation) instead of a variant \u2014 if "Foo.ai" is listed, never emit "Foo ai" or "Foo AI", and if "Jane Roe" is listed, emit that rather than a bare "Jane".
|
|
32120
|
-
|
|
32121
|
-
` : "";
|
|
32122
|
-
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
32123
|
-
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
32124
|
-
const rows = [];
|
|
32125
|
-
for (const m of batch) {
|
|
32126
|
-
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
|
|
32127
|
-
rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
|
|
32128
|
-
}
|
|
32129
|
-
const listing = rows.join("\n");
|
|
32130
|
-
const parsed = await callPortalJsonCompletion({
|
|
32131
|
-
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
32132
|
-
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
32133
|
-
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
32134
|
-
taskType: "memory_topic",
|
|
32135
|
-
...options.endpointOverride !== void 0 && {
|
|
32136
|
-
endpointOverride: options.endpointOverride
|
|
32137
|
-
},
|
|
32138
|
-
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
32139
|
-
systemPrompt: SYSTEM_PROMPT6,
|
|
32140
|
-
userMessage: `${vocabularyNote}Memories:
|
|
32141
|
-
${listing}
|
|
32142
|
-
|
|
32143
|
-
List each memory's named entities.`,
|
|
32144
|
-
tag: "memory/topics",
|
|
32145
|
-
extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
|
|
32146
|
-
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
32147
|
-
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
32148
|
-
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
32149
|
-
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
32150
|
-
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
32151
|
-
});
|
|
32152
|
-
if (parsed === null) {
|
|
32153
|
-
getLogger().warn(
|
|
32154
|
-
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
32155
|
-
);
|
|
32156
|
-
continue;
|
|
32157
|
-
}
|
|
32158
|
-
const validIds = new Set(batch.map((m) => m.id));
|
|
32159
|
-
const byId = parseTopicResponse(parsed, validIds);
|
|
32160
|
-
if (byId === null) {
|
|
32161
|
-
getLogger().warn(
|
|
32162
|
-
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
32163
|
-
);
|
|
32164
|
-
continue;
|
|
32165
|
-
}
|
|
32166
|
-
for (const m of batch) {
|
|
32167
|
-
const entities = byId.get(m.id);
|
|
32168
|
-
if (entities === void 0) {
|
|
32169
|
-
continue;
|
|
32170
|
-
}
|
|
32171
|
-
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
32172
|
-
}
|
|
32173
|
-
}
|
|
32174
|
-
return out;
|
|
32175
|
-
}
|
|
32176
|
-
function restoreEntities(entities, redactor) {
|
|
32177
|
-
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
32178
|
-
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
32179
|
-
);
|
|
32180
|
-
}
|
|
32181
|
-
function parseTopicResponse(parsed, validIds) {
|
|
32182
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
32183
|
-
const list = parsed.memories;
|
|
32184
|
-
if (!Array.isArray(list)) return null;
|
|
32185
|
-
const out = /* @__PURE__ */ new Map();
|
|
32186
|
-
for (const raw of list) {
|
|
32187
|
-
if (typeof raw !== "object" || raw === null) continue;
|
|
32188
|
-
const obj = raw;
|
|
32189
|
-
if (typeof obj.id !== "string") continue;
|
|
32190
|
-
const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
|
|
32191
|
-
if (!validIds.has(id) || out.has(id)) continue;
|
|
32192
|
-
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
32193
|
-
out.set(id, entities);
|
|
32194
|
-
}
|
|
32195
|
-
return out;
|
|
32196
|
-
}
|
|
32197
|
-
var DEGRADED_TOPIC_SKIP = {
|
|
32198
|
-
excluded: false,
|
|
32199
|
-
"link-declined": false,
|
|
32200
|
-
"stamp-declined": false,
|
|
32201
|
-
"llm-unanswered": true,
|
|
32202
|
-
unreadable: true,
|
|
32203
|
-
"not-found": true,
|
|
32204
|
-
"link-failed": true
|
|
32205
|
-
};
|
|
32206
|
-
function isDegradedTopicSkip(reason) {
|
|
32207
|
-
return DEGRADED_TOPIC_SKIP[reason] === true;
|
|
32208
|
-
}
|
|
32209
|
-
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
32210
|
-
const entityCtx = ctx.entityCtx;
|
|
32211
|
-
if (!entityCtx) {
|
|
32212
|
-
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
32213
|
-
}
|
|
32214
|
-
const log = getLogger();
|
|
32215
|
-
const extractedAt = options.now ?? Date.now();
|
|
32216
|
-
const skippedIds = [];
|
|
32217
|
-
const skippedReasons = /* @__PURE__ */ new Map();
|
|
32218
|
-
const skip = (id, reason) => {
|
|
32219
|
-
if (skippedReasons.has(id)) return;
|
|
32220
|
-
skippedIds.push(id);
|
|
32221
|
-
skippedReasons.set(id, reason);
|
|
32222
|
-
};
|
|
32223
|
-
const inputs = [];
|
|
32224
|
-
for (const id of new Set(memoryIds)) {
|
|
32225
|
-
let record;
|
|
32226
|
-
try {
|
|
32227
|
-
record = await ctx.vaultMemoryCollection.find(id);
|
|
32228
|
-
} catch (err) {
|
|
32229
|
-
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
32230
|
-
skip(id, "not-found");
|
|
32231
|
-
continue;
|
|
32232
|
-
}
|
|
32233
|
-
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
32234
|
-
skip(id, "excluded");
|
|
32235
|
-
continue;
|
|
32236
|
-
}
|
|
32237
|
-
try {
|
|
32238
|
-
const stored = await vaultMemoryToStored(
|
|
32239
|
-
record,
|
|
32240
|
-
ctx.walletAddress,
|
|
32241
|
-
ctx.signMessage,
|
|
32242
|
-
ctx.embeddedWalletSigner
|
|
32243
|
-
);
|
|
32244
|
-
inputs.push({ id, content: stored.content });
|
|
32245
|
-
} catch (err) {
|
|
32246
|
-
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
32247
|
-
skip(id, "unreadable");
|
|
32248
|
-
}
|
|
32249
|
-
}
|
|
32250
|
-
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
32251
|
-
const toStamp = [];
|
|
32252
|
-
for (const input of inputs) {
|
|
32253
|
-
const entities = entitiesByMemory.get(input.id);
|
|
32254
|
-
if (entities === void 0) {
|
|
32255
|
-
skip(input.id, "llm-unanswered");
|
|
32256
|
-
continue;
|
|
32257
|
-
}
|
|
32258
|
-
try {
|
|
32259
|
-
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
32260
|
-
if (linked === null) {
|
|
32261
|
-
skip(input.id, "link-declined");
|
|
32262
|
-
entitiesByMemory.delete(input.id);
|
|
32263
|
-
continue;
|
|
32264
|
-
}
|
|
32265
|
-
} catch (err) {
|
|
32266
|
-
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
32267
|
-
skip(input.id, "link-failed");
|
|
32268
|
-
entitiesByMemory.delete(input.id);
|
|
32269
|
-
continue;
|
|
32270
|
-
}
|
|
32271
|
-
toStamp.push(input.id);
|
|
32272
|
-
}
|
|
32273
|
-
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
32274
|
-
const stampedSet = new Set(stampedIds);
|
|
32275
|
-
for (const id of toStamp) {
|
|
32276
|
-
if (!stampedSet.has(id)) {
|
|
32277
|
-
skip(id, "stamp-declined");
|
|
32278
|
-
entitiesByMemory.delete(id);
|
|
32279
|
-
}
|
|
32280
|
-
}
|
|
32281
|
-
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
32282
|
-
}
|
|
32283
|
-
|
|
32284
32484
|
// src/lib/memory/verifySupport.ts
|
|
32285
32485
|
init_logger();
|
|
32286
32486
|
init_redactor();
|
|
@@ -32674,7 +32874,7 @@ async function assembleMemoryContext(options) {
|
|
|
32674
32874
|
}
|
|
32675
32875
|
|
|
32676
32876
|
// src/lib/memory/durableExtraction.ts
|
|
32677
|
-
var
|
|
32877
|
+
var import_watermelondb25 = __toESM(require_watermelondb());
|
|
32678
32878
|
var MAX_JOBS_PER_PASS = 3;
|
|
32679
32879
|
var MAX_ATTEMPTS = 3;
|
|
32680
32880
|
var MAX_FAILED_SESSIONS = 3;
|
|
@@ -32821,7 +33021,7 @@ function createDurableAutoExtractor(options) {
|
|
|
32821
33021
|
...options.retainCtx,
|
|
32822
33022
|
vaultCtx: {
|
|
32823
33023
|
...vault,
|
|
32824
|
-
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(
|
|
33024
|
+
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(import_watermelondb25.Q.where("conversation_id", conversationId), import_watermelondb25.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb25.Q.where("conversation_id", conversationId), import_watermelondb25.Q.where("id", import_watermelondb25.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
32825
33025
|
}
|
|
32826
33026
|
},
|
|
32827
33027
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -32963,7 +33163,7 @@ function createDurableAutoExtractor(options) {
|
|
|
32963
33163
|
let scheduleAfterSuccess = false;
|
|
32964
33164
|
try {
|
|
32965
33165
|
await writes;
|
|
32966
|
-
const pending = await jobs.query(
|
|
33166
|
+
const pending = await jobs.query(import_watermelondb25.Q.where("owner_key", owner), import_watermelondb25.Q.where("message_ids", import_watermelondb25.Q.notEq("[]"))).fetch();
|
|
32967
33167
|
storeFailures = 0;
|
|
32968
33168
|
let processed = 0;
|
|
32969
33169
|
for (const job of pending) {
|
|
@@ -32979,7 +33179,7 @@ function createDurableAutoExtractor(options) {
|
|
|
32979
33179
|
let ids = [];
|
|
32980
33180
|
let loaded = [];
|
|
32981
33181
|
try {
|
|
32982
|
-
const conversations = await storage.conversationsCollection.query(
|
|
33182
|
+
const conversations = await storage.conversationsCollection.query(import_watermelondb25.Q.where("conversation_id", conversationId), import_watermelondb25.Q.where("is_deleted", false)).fetchCount();
|
|
32983
33183
|
if (!conversations) {
|
|
32984
33184
|
await database.write(() => job.destroyPermanently());
|
|
32985
33185
|
continue;
|
|
@@ -33096,12 +33296,12 @@ function createDurableAutoExtractor(options) {
|
|
|
33096
33296
|
const scope = currentScope();
|
|
33097
33297
|
writes = writes.then(
|
|
33098
33298
|
() => database.write(async () => {
|
|
33099
|
-
const existing = await jobs.query(
|
|
33299
|
+
const existing = await jobs.query(import_watermelondb25.Q.where("owner_key", owner), import_watermelondb25.Q.where("conversation_id", conversationId)).fetch();
|
|
33100
33300
|
const job = existing.find(
|
|
33101
33301
|
(candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
|
|
33102
33302
|
);
|
|
33103
33303
|
const positions = new Map(ids.map((id, index) => [id, index]));
|
|
33104
|
-
const rows = await storage.messagesCollection.query(
|
|
33304
|
+
const rows = await storage.messagesCollection.query(import_watermelondb25.Q.where("id", import_watermelondb25.Q.oneOf(ids))).fetch();
|
|
33105
33305
|
const sequences = /* @__PURE__ */ new Map();
|
|
33106
33306
|
for (const row of rows) {
|
|
33107
33307
|
const sequence = Number(row._getRaw("message_id"));
|
|
@@ -39222,6 +39422,7 @@ function buildSystemPrompt(ctx, options) {
|
|
|
39222
39422
|
createDurableAutoExtractor,
|
|
39223
39423
|
createLlmDecayClassifier,
|
|
39224
39424
|
createLlmNeighborRefiner,
|
|
39425
|
+
createLocalMemoryStore,
|
|
39225
39426
|
createMediaBatchOp,
|
|
39226
39427
|
createMediaOp,
|
|
39227
39428
|
createMemoryEngineTool,
|