@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.mjs
CHANGED
|
@@ -12324,7 +12324,7 @@ var require_Query = __commonJS({
|
|
|
12324
12324
|
var _subscribeToCount = _interopRequireDefault(require_subscribeToCount());
|
|
12325
12325
|
var _subscribeToQuery = _interopRequireDefault(require_subscribeToQuery());
|
|
12326
12326
|
var _subscribeToQueryWithColumns = _interopRequireDefault(require_subscribeToQueryWithColumns());
|
|
12327
|
-
var
|
|
12327
|
+
var Q12 = _interopRequireWildcard(require_QueryDescription());
|
|
12328
12328
|
var _helpers = require_helpers2();
|
|
12329
12329
|
var _class;
|
|
12330
12330
|
var _descriptor;
|
|
@@ -12356,8 +12356,8 @@ var require_Query = __commonJS({
|
|
|
12356
12356
|
(0, _initializerDefineProperty2.default)(this, "_cachedCountSubscribable", _descriptor2, this);
|
|
12357
12357
|
(0, _initializerDefineProperty2.default)(this, "_cachedCountThrottledSubscribable", _descriptor3, this);
|
|
12358
12358
|
this.collection = collection;
|
|
12359
|
-
this._rawDescription =
|
|
12360
|
-
this.description =
|
|
12359
|
+
this._rawDescription = Q12.buildQueryDescription(clauses);
|
|
12360
|
+
this.description = Q12.queryWithoutDeleted(this._rawDescription);
|
|
12361
12361
|
}
|
|
12362
12362
|
var _proto = Query2.prototype;
|
|
12363
12363
|
_proto.extend = function(...args) {
|
|
@@ -12376,12 +12376,12 @@ var require_Query = __commonJS({
|
|
|
12376
12376
|
sql
|
|
12377
12377
|
} = this._rawDescription;
|
|
12378
12378
|
(0, _invariant.default)(!sql, "Cannot extend an unsafe SQL query");
|
|
12379
|
-
return new Query2(collection, [
|
|
12379
|
+
return new Query2(collection, [Q12.experimentalJoinTables(joinTables)].concat((0, _toConsumableArray2.default)(nestedJoinTables.map(function({
|
|
12380
12380
|
from,
|
|
12381
12381
|
to
|
|
12382
12382
|
}) {
|
|
12383
|
-
return
|
|
12384
|
-
})), (0, _toConsumableArray2.default)(where), (0, _toConsumableArray2.default)(sortBy), (0, _toConsumableArray2.default)(take ? [
|
|
12383
|
+
return Q12.experimentalNestedJoin(from, to);
|
|
12384
|
+
})), (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)));
|
|
12385
12385
|
};
|
|
12386
12386
|
_proto.pipe = function(transform) {
|
|
12387
12387
|
return transform(this);
|
|
@@ -13823,7 +13823,7 @@ var require_helpers5 = __commonJS({
|
|
|
13823
13823
|
exports.createTimestampsFor = void 0;
|
|
13824
13824
|
exports.fetchDescendants = fetchDescendants;
|
|
13825
13825
|
var _fp = require_fp();
|
|
13826
|
-
var
|
|
13826
|
+
var Q12 = _interopRequireWildcard(require_QueryDescription());
|
|
13827
13827
|
function _getRequireWildcardCache(e) {
|
|
13828
13828
|
if ("function" != typeof WeakMap) return null;
|
|
13829
13829
|
var r = /* @__PURE__ */ new WeakMap(), t = /* @__PURE__ */ new WeakMap();
|
|
@@ -13861,7 +13861,7 @@ var require_helpers5 = __commonJS({
|
|
|
13861
13861
|
});
|
|
13862
13862
|
var childrenQueries = hasManyAssociations.map(function([key, value]) {
|
|
13863
13863
|
var childCollection = model.collections.get(key);
|
|
13864
|
-
return childCollection.query(
|
|
13864
|
+
return childCollection.query(Q12.where(value.foreignKey, model.id));
|
|
13865
13865
|
});
|
|
13866
13866
|
return childrenQueries;
|
|
13867
13867
|
}
|
|
@@ -14242,8 +14242,8 @@ var require_watermelondb = __commonJS({
|
|
|
14242
14242
|
var _interopRequireDefault = require_interopRequireDefault();
|
|
14243
14243
|
exports.__esModule = true;
|
|
14244
14244
|
exports.tableSchema = exports.tableName = exports.localStorageKey = exports.columnName = exports.associations = exports.appSchema = exports.Relation = exports.Query = exports.Q = exports.Model = exports.Database = exports.Collection = void 0;
|
|
14245
|
-
var
|
|
14246
|
-
exports.Q =
|
|
14245
|
+
var Q12 = _interopRequireWildcard(require_QueryDescription());
|
|
14246
|
+
exports.Q = Q12;
|
|
14247
14247
|
var _Collection = _interopRequireDefault(require_Collection());
|
|
14248
14248
|
exports.Collection = _Collection.default;
|
|
14249
14249
|
var _Database = _interopRequireDefault(require_Database());
|
|
@@ -14447,7 +14447,7 @@ var require_children = __commonJS({
|
|
|
14447
14447
|
var _makeDecorator = _interopRequireDefault(require_makeDecorator());
|
|
14448
14448
|
var _logError = _interopRequireDefault(require_logError());
|
|
14449
14449
|
var _invariant = _interopRequireDefault(require_invariant());
|
|
14450
|
-
var
|
|
14450
|
+
var Q12 = _interopRequireWildcard(require_QueryDescription());
|
|
14451
14451
|
function _getRequireWildcardCache(e) {
|
|
14452
14452
|
if ("function" != typeof WeakMap) return null;
|
|
14453
14453
|
var r = /* @__PURE__ */ new WeakMap(), t = /* @__PURE__ */ new WeakMap();
|
|
@@ -14481,7 +14481,7 @@ var require_children = __commonJS({
|
|
|
14481
14481
|
var childCollection = model.collections.get(childTable);
|
|
14482
14482
|
var association = model.constructor.associations[childTable];
|
|
14483
14483
|
(0, _invariant.default)(association && "has_many" === association.type, "@children decorator used for a table that's not has_many");
|
|
14484
|
-
var query = childCollection.query(
|
|
14484
|
+
var query = childCollection.query(Q12.where(association.foreignKey, model.id));
|
|
14485
14485
|
that._childrenQueryCache[childTable] = query;
|
|
14486
14486
|
return query;
|
|
14487
14487
|
},
|
|
@@ -21009,6 +21009,51 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
21009
21009
|
return null;
|
|
21010
21010
|
}
|
|
21011
21011
|
}
|
|
21012
|
+
async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
21013
|
+
const entityCtx = ctx.entityCtx;
|
|
21014
|
+
if (!entityCtx) {
|
|
21015
|
+
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
21016
|
+
}
|
|
21017
|
+
let record;
|
|
21018
|
+
try {
|
|
21019
|
+
record = await ctx.vaultMemoryCollection.find(memoryId);
|
|
21020
|
+
} catch {
|
|
21021
|
+
return null;
|
|
21022
|
+
}
|
|
21023
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
|
|
21024
|
+
let stale = false;
|
|
21025
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
21026
|
+
await ctx.database.write(async (writer) => {
|
|
21027
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
|
|
21028
|
+
stale = true;
|
|
21029
|
+
return;
|
|
21030
|
+
}
|
|
21031
|
+
await record.update((r) => {
|
|
21032
|
+
r._setRaw("topics_user_managed", true);
|
|
21033
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
21034
|
+
});
|
|
21035
|
+
const linked = entities.length > 0 ? await writer.callWriter(
|
|
21036
|
+
() => linkMemoryEntitiesOp(entityCtx, memoryId, entities, { topicsSource: "user" })
|
|
21037
|
+
) : [];
|
|
21038
|
+
const keep = new Set(linked.map((e) => e.uniqueId));
|
|
21039
|
+
const existing = await entityCtx.memoryEntityCollection.query(import_watermelondb18.Q.where("memory_id", memoryId)).fetch();
|
|
21040
|
+
const staleLinks = existing.filter((l) => !keep.has(String(l.entityId)));
|
|
21041
|
+
if (staleLinks.length === 0 && entities.length > 0) return;
|
|
21042
|
+
const topicsWrite = await resolveMemoryTopicsWrite(
|
|
21043
|
+
entityCtx,
|
|
21044
|
+
memoryId,
|
|
21045
|
+
linked,
|
|
21046
|
+
entities,
|
|
21047
|
+
"user"
|
|
21048
|
+
);
|
|
21049
|
+
await ctx.database.batch(
|
|
21050
|
+
...staleLinks.map((l) => l.prepareDestroyPermanently()),
|
|
21051
|
+
...topicsWrite ? [prepareMemoryTopicsUpdate(topicsWrite)] : []
|
|
21052
|
+
);
|
|
21053
|
+
});
|
|
21054
|
+
if (stale) return null;
|
|
21055
|
+
return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
21056
|
+
}
|
|
21012
21057
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
21013
21058
|
let record;
|
|
21014
21059
|
try {
|
|
@@ -25502,7 +25547,10 @@ async function eagerEmbedContent(content, embeddingOptions, cache, vaultCtx, mem
|
|
|
25502
25547
|
if (memoryId) cacheRowVector(cache, memoryId, Float32Array.from(embedding), updatedAt, content);
|
|
25503
25548
|
if (vaultCtx && memoryId) {
|
|
25504
25549
|
const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
25505
|
-
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel
|
|
25550
|
+
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel, {
|
|
25551
|
+
content,
|
|
25552
|
+
...updatedAt !== void 0 && { updatedAt: updatedAt.getTime() }
|
|
25553
|
+
}).catch(
|
|
25506
25554
|
// Silently swallow – SDK must not use console.*; embedding will be retried on next search
|
|
25507
25555
|
() => {
|
|
25508
25556
|
}
|
|
@@ -29785,6 +29833,349 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
29785
29833
|
};
|
|
29786
29834
|
}
|
|
29787
29835
|
|
|
29836
|
+
// src/lib/memory/store/local.ts
|
|
29837
|
+
var import_watermelondb24 = __toESM(require_watermelondb());
|
|
29838
|
+
|
|
29839
|
+
// src/lib/memory/topicExtract.ts
|
|
29840
|
+
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
29841
|
+
var MAX_CHARS_PER_MEMORY = 300;
|
|
29842
|
+
var MAX_VOCABULARY_NAMES = 100;
|
|
29843
|
+
var MAX_COMPLETION_TOKENS = 8192;
|
|
29844
|
+
var SYSTEM_PROMPT5 = `You assign topics to saved memories for a personal memory system.
|
|
29845
|
+
|
|
29846
|
+
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.
|
|
29847
|
+
|
|
29848
|
+
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:
|
|
29849
|
+
- 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.
|
|
29850
|
+
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
29851
|
+
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
29852
|
+
${ENTITY_KIND_GUIDELINES}
|
|
29853
|
+
|
|
29854
|
+
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
29855
|
+
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
29856
|
+
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
29857
|
+
No prose.`;
|
|
29858
|
+
async function extractEntitiesForMemories(memories, options) {
|
|
29859
|
+
const out = /* @__PURE__ */ new Map();
|
|
29860
|
+
if (memories.length === 0) return out;
|
|
29861
|
+
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
29862
|
+
const vocabulary = [];
|
|
29863
|
+
for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
|
|
29864
|
+
vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
|
|
29865
|
+
}
|
|
29866
|
+
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
29867
|
+
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".
|
|
29868
|
+
|
|
29869
|
+
` : "";
|
|
29870
|
+
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
29871
|
+
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
29872
|
+
const rows = [];
|
|
29873
|
+
for (const m of batch) {
|
|
29874
|
+
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
|
|
29875
|
+
rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
|
|
29876
|
+
}
|
|
29877
|
+
const listing = rows.join("\n");
|
|
29878
|
+
const parsed = await callPortalJsonCompletion({
|
|
29879
|
+
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
29880
|
+
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
29881
|
+
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
29882
|
+
taskType: "memory_topic",
|
|
29883
|
+
...options.endpointOverride !== void 0 && {
|
|
29884
|
+
endpointOverride: options.endpointOverride
|
|
29885
|
+
},
|
|
29886
|
+
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
29887
|
+
systemPrompt: SYSTEM_PROMPT5,
|
|
29888
|
+
userMessage: `${vocabularyNote}Memories:
|
|
29889
|
+
${listing}
|
|
29890
|
+
|
|
29891
|
+
List each memory's named entities.`,
|
|
29892
|
+
tag: "memory/topics",
|
|
29893
|
+
extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
|
|
29894
|
+
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
29895
|
+
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
29896
|
+
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
29897
|
+
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
29898
|
+
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
29899
|
+
});
|
|
29900
|
+
if (parsed === null) {
|
|
29901
|
+
getLogger().warn(
|
|
29902
|
+
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
29903
|
+
);
|
|
29904
|
+
continue;
|
|
29905
|
+
}
|
|
29906
|
+
const validIds = new Set(batch.map((m) => m.id));
|
|
29907
|
+
const byId = parseTopicResponse(parsed, validIds);
|
|
29908
|
+
if (byId === null) {
|
|
29909
|
+
getLogger().warn(
|
|
29910
|
+
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
29911
|
+
);
|
|
29912
|
+
continue;
|
|
29913
|
+
}
|
|
29914
|
+
for (const m of batch) {
|
|
29915
|
+
const entities = byId.get(m.id);
|
|
29916
|
+
if (entities === void 0) {
|
|
29917
|
+
continue;
|
|
29918
|
+
}
|
|
29919
|
+
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
29920
|
+
}
|
|
29921
|
+
}
|
|
29922
|
+
return out;
|
|
29923
|
+
}
|
|
29924
|
+
function restoreEntities(entities, redactor) {
|
|
29925
|
+
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
29926
|
+
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
29927
|
+
);
|
|
29928
|
+
}
|
|
29929
|
+
function parseTopicResponse(parsed, validIds) {
|
|
29930
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
29931
|
+
const list = parsed.memories;
|
|
29932
|
+
if (!Array.isArray(list)) return null;
|
|
29933
|
+
const out = /* @__PURE__ */ new Map();
|
|
29934
|
+
for (const raw of list) {
|
|
29935
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
29936
|
+
const obj = raw;
|
|
29937
|
+
if (typeof obj.id !== "string") continue;
|
|
29938
|
+
const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
|
|
29939
|
+
if (!validIds.has(id) || out.has(id)) continue;
|
|
29940
|
+
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
29941
|
+
out.set(id, entities);
|
|
29942
|
+
}
|
|
29943
|
+
return out;
|
|
29944
|
+
}
|
|
29945
|
+
var DEGRADED_TOPIC_SKIP = {
|
|
29946
|
+
excluded: false,
|
|
29947
|
+
"link-declined": false,
|
|
29948
|
+
"stamp-declined": false,
|
|
29949
|
+
"llm-unanswered": true,
|
|
29950
|
+
unreadable: true,
|
|
29951
|
+
"not-found": true,
|
|
29952
|
+
"link-failed": true
|
|
29953
|
+
};
|
|
29954
|
+
function isDegradedTopicSkip(reason) {
|
|
29955
|
+
return DEGRADED_TOPIC_SKIP[reason] === true;
|
|
29956
|
+
}
|
|
29957
|
+
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
29958
|
+
const entityCtx = ctx.entityCtx;
|
|
29959
|
+
if (!entityCtx) {
|
|
29960
|
+
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
29961
|
+
}
|
|
29962
|
+
const log = getLogger();
|
|
29963
|
+
const extractedAt = options.now ?? Date.now();
|
|
29964
|
+
const skippedIds = [];
|
|
29965
|
+
const skippedReasons = /* @__PURE__ */ new Map();
|
|
29966
|
+
const skip = (id, reason) => {
|
|
29967
|
+
if (skippedReasons.has(id)) return;
|
|
29968
|
+
skippedIds.push(id);
|
|
29969
|
+
skippedReasons.set(id, reason);
|
|
29970
|
+
};
|
|
29971
|
+
const inputs = [];
|
|
29972
|
+
for (const id of new Set(memoryIds)) {
|
|
29973
|
+
let record;
|
|
29974
|
+
try {
|
|
29975
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
29976
|
+
} catch (err) {
|
|
29977
|
+
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
29978
|
+
skip(id, "not-found");
|
|
29979
|
+
continue;
|
|
29980
|
+
}
|
|
29981
|
+
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
29982
|
+
skip(id, "excluded");
|
|
29983
|
+
continue;
|
|
29984
|
+
}
|
|
29985
|
+
try {
|
|
29986
|
+
const stored = await vaultMemoryToStored(
|
|
29987
|
+
record,
|
|
29988
|
+
ctx.walletAddress,
|
|
29989
|
+
ctx.signMessage,
|
|
29990
|
+
ctx.embeddedWalletSigner
|
|
29991
|
+
);
|
|
29992
|
+
inputs.push({ id, content: stored.content });
|
|
29993
|
+
} catch (err) {
|
|
29994
|
+
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
29995
|
+
skip(id, "unreadable");
|
|
29996
|
+
}
|
|
29997
|
+
}
|
|
29998
|
+
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
29999
|
+
const toStamp = [];
|
|
30000
|
+
for (const input of inputs) {
|
|
30001
|
+
const entities = entitiesByMemory.get(input.id);
|
|
30002
|
+
if (entities === void 0) {
|
|
30003
|
+
skip(input.id, "llm-unanswered");
|
|
30004
|
+
continue;
|
|
30005
|
+
}
|
|
30006
|
+
try {
|
|
30007
|
+
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
30008
|
+
if (linked === null) {
|
|
30009
|
+
skip(input.id, "link-declined");
|
|
30010
|
+
entitiesByMemory.delete(input.id);
|
|
30011
|
+
continue;
|
|
30012
|
+
}
|
|
30013
|
+
} catch (err) {
|
|
30014
|
+
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
30015
|
+
skip(input.id, "link-failed");
|
|
30016
|
+
entitiesByMemory.delete(input.id);
|
|
30017
|
+
continue;
|
|
30018
|
+
}
|
|
30019
|
+
toStamp.push(input.id);
|
|
30020
|
+
}
|
|
30021
|
+
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
30022
|
+
const stampedSet = new Set(stampedIds);
|
|
30023
|
+
for (const id of toStamp) {
|
|
30024
|
+
if (!stampedSet.has(id)) {
|
|
30025
|
+
skip(id, "stamp-declined");
|
|
30026
|
+
entitiesByMemory.delete(id);
|
|
30027
|
+
}
|
|
30028
|
+
}
|
|
30029
|
+
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
30030
|
+
}
|
|
30031
|
+
|
|
30032
|
+
// src/lib/memory/store/local.ts
|
|
30033
|
+
function createLocalMemoryStore(options) {
|
|
30034
|
+
const { database, userId } = options;
|
|
30035
|
+
const entityCtx = {
|
|
30036
|
+
database,
|
|
30037
|
+
entityCollection: database.get("entity"),
|
|
30038
|
+
memoryEntityCollection: database.get("memory_entity"),
|
|
30039
|
+
...userId !== void 0 && { userId },
|
|
30040
|
+
...options.allowUnscopedRows !== void 0 && {
|
|
30041
|
+
allowUnscopedRows: options.allowUnscopedRows
|
|
30042
|
+
}
|
|
30043
|
+
};
|
|
30044
|
+
const vaultCtx = {
|
|
30045
|
+
database,
|
|
30046
|
+
vaultMemoryCollection: database.get("memory_vault"),
|
|
30047
|
+
walletAddress: options.walletAddress,
|
|
30048
|
+
signMessage: options.signMessage,
|
|
30049
|
+
embeddedWalletSigner: options.embeddedWalletSigner,
|
|
30050
|
+
...userId !== void 0 && { userId },
|
|
30051
|
+
...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
|
|
30052
|
+
// Deletes cascade to memory_entity, so the graph lane never serves a
|
|
30053
|
+
// deleted memory's id.
|
|
30054
|
+
entityCtx
|
|
30055
|
+
};
|
|
30056
|
+
const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
|
|
30057
|
+
const ownedBy = userId !== void 0 ? [import_watermelondb24.Q.where("user_id", userId)] : [];
|
|
30058
|
+
const watchedColumns = [
|
|
30059
|
+
"content",
|
|
30060
|
+
"scope",
|
|
30061
|
+
"updated_at",
|
|
30062
|
+
"fact_type",
|
|
30063
|
+
"event_time_start",
|
|
30064
|
+
"event_time_end",
|
|
30065
|
+
"event_time_kind",
|
|
30066
|
+
"archived_at",
|
|
30067
|
+
"trust_tier",
|
|
30068
|
+
"superseded_by",
|
|
30069
|
+
"visibility",
|
|
30070
|
+
"published_at",
|
|
30071
|
+
"geohash",
|
|
30072
|
+
"topics",
|
|
30073
|
+
"topics_user_managed",
|
|
30074
|
+
"media",
|
|
30075
|
+
"source"
|
|
30076
|
+
];
|
|
30077
|
+
const embedInBackground = (memory) => {
|
|
30078
|
+
eagerEmbedContent(
|
|
30079
|
+
memory.content,
|
|
30080
|
+
options.embeddingOptions,
|
|
30081
|
+
vaultCache,
|
|
30082
|
+
vaultCtx,
|
|
30083
|
+
memory.uniqueId,
|
|
30084
|
+
memory.updatedAt
|
|
30085
|
+
).catch((err) => {
|
|
30086
|
+
getLogger().warn("[memory/store] Failed to embed memory:", err);
|
|
30087
|
+
});
|
|
30088
|
+
};
|
|
30089
|
+
return {
|
|
30090
|
+
list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
|
|
30091
|
+
get: (id) => getVaultMemoryOp(vaultCtx, id),
|
|
30092
|
+
listArchived: async () => {
|
|
30093
|
+
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();
|
|
30094
|
+
if (ids.length === 0) return [];
|
|
30095
|
+
const rows = await getAllVaultMemoriesOp(vaultCtx, { memoryIds: ids, includeArchived: true });
|
|
30096
|
+
return rows.sort((a, b) => (b.archivedAt ?? 0) - (a.archivedAt ?? 0));
|
|
30097
|
+
},
|
|
30098
|
+
memoriesByTopics: (names) => getMemoriesByEntityNamesOp(entityCtx, names),
|
|
30099
|
+
topicsByMemories: (memoryIds) => getEntitiesByMemoryIdsOp(entityCtx, memoryIds),
|
|
30100
|
+
create: async (input) => {
|
|
30101
|
+
const created = await createVaultMemoryOp(vaultCtx, input);
|
|
30102
|
+
if (input.embedding === void 0) embedInBackground(created);
|
|
30103
|
+
return created;
|
|
30104
|
+
},
|
|
30105
|
+
createMany: async (inputs) => {
|
|
30106
|
+
const created = await createVaultMemoriesBatchOp(vaultCtx, inputs);
|
|
30107
|
+
created.forEach((memory, i) => {
|
|
30108
|
+
if (inputs[i].embedding === void 0) embedInBackground(memory);
|
|
30109
|
+
});
|
|
30110
|
+
return created;
|
|
30111
|
+
},
|
|
30112
|
+
update: async (id, patch) => {
|
|
30113
|
+
const reembed = patch.embedding === void 0;
|
|
30114
|
+
const updated = await updateVaultMemoryOp(
|
|
30115
|
+
vaultCtx,
|
|
30116
|
+
id,
|
|
30117
|
+
reembed ? { ...patch, embedding: null } : patch
|
|
30118
|
+
);
|
|
30119
|
+
if (!updated) return null;
|
|
30120
|
+
vaultCache.delete(id);
|
|
30121
|
+
if (reembed) embedInBackground(updated);
|
|
30122
|
+
return updated;
|
|
30123
|
+
},
|
|
30124
|
+
delete: async (id) => {
|
|
30125
|
+
const deleted = await deleteVaultMemoryOp(vaultCtx, id);
|
|
30126
|
+
if (deleted) vaultCache.delete(id);
|
|
30127
|
+
return deleted;
|
|
30128
|
+
},
|
|
30129
|
+
supersede: (id, supersededById) => supersedeVaultMemoryOp(vaultCtx, id, supersededById),
|
|
30130
|
+
archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
|
|
30131
|
+
restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
|
|
30132
|
+
setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
|
|
30133
|
+
addTopics: (memoryId, topics) => database.write(async (writer) => {
|
|
30134
|
+
const owned = await vaultCtx.vaultMemoryCollection.query(import_watermelondb24.Q.where("id", memoryId), import_watermelondb24.Q.where("is_deleted", false), ...ownedBy).fetchCount();
|
|
30135
|
+
return owned > 0 ? writer.callWriter(() => linkMemoryEntitiesOp(entityCtx, memoryId, topics)) : [];
|
|
30136
|
+
}),
|
|
30137
|
+
setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
|
|
30138
|
+
recall: (query, recallOptions) => recall(
|
|
30139
|
+
query,
|
|
30140
|
+
{ vaultCtx, entityCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
30141
|
+
{ ...recallOptions, types: ["fact"] }
|
|
30142
|
+
),
|
|
30143
|
+
retain: (content, retainOptions) => retain(
|
|
30144
|
+
content,
|
|
30145
|
+
{ vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
30146
|
+
retainOptions
|
|
30147
|
+
),
|
|
30148
|
+
subscribe: (onChange, subscribeOptions) => {
|
|
30149
|
+
const afterFirst = () => {
|
|
30150
|
+
let first = true;
|
|
30151
|
+
return () => {
|
|
30152
|
+
if (first) first = false;
|
|
30153
|
+
else onChange();
|
|
30154
|
+
};
|
|
30155
|
+
};
|
|
30156
|
+
const memories = subscribeOptions?.includeDeleted ? vaultCtx.vaultMemoryCollection.query(...ownedBy).observe() : vaultCtx.vaultMemoryCollection.query(import_watermelondb24.Q.where("is_deleted", false), ...ownedBy).observeWithColumns(
|
|
30157
|
+
subscribeOptions?.embeddings ? [...watchedColumns, "embedding", "embedding_model"] : watchedColumns
|
|
30158
|
+
);
|
|
30159
|
+
const subscriptions = [memories.subscribe(afterFirst())];
|
|
30160
|
+
if (subscribeOptions?.topics) {
|
|
30161
|
+
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)];
|
|
30162
|
+
subscriptions.push(
|
|
30163
|
+
entityCtx.memoryEntityCollection.query(...linksOwnedBy).observe().subscribe(afterFirst())
|
|
30164
|
+
);
|
|
30165
|
+
}
|
|
30166
|
+
return () => subscriptions.forEach((s) => s.unsubscribe());
|
|
30167
|
+
},
|
|
30168
|
+
maintenance: {
|
|
30169
|
+
createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...sweeperOptions, vaultCtx }),
|
|
30170
|
+
getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
|
|
30171
|
+
extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
|
|
30172
|
+
stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
|
|
30173
|
+
relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
|
|
30174
|
+
backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
|
|
30175
|
+
}
|
|
30176
|
+
};
|
|
30177
|
+
}
|
|
30178
|
+
|
|
29788
30179
|
// src/lib/memory/synthesizeProfile.ts
|
|
29789
30180
|
var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
|
|
29790
30181
|
var DEFAULT_FACET_RECALL_LIMIT = 20;
|
|
@@ -30312,199 +30703,6 @@ function normalizeInterests(values) {
|
|
|
30312
30703
|
return out.length > 0 ? out : void 0;
|
|
30313
30704
|
}
|
|
30314
30705
|
|
|
30315
|
-
// src/lib/memory/topicExtract.ts
|
|
30316
|
-
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
30317
|
-
var MAX_CHARS_PER_MEMORY = 300;
|
|
30318
|
-
var MAX_VOCABULARY_NAMES = 100;
|
|
30319
|
-
var MAX_COMPLETION_TOKENS = 8192;
|
|
30320
|
-
var SYSTEM_PROMPT5 = `You assign topics to saved memories for a personal memory system.
|
|
30321
|
-
|
|
30322
|
-
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.
|
|
30323
|
-
|
|
30324
|
-
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:
|
|
30325
|
-
- 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.
|
|
30326
|
-
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
30327
|
-
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
30328
|
-
${ENTITY_KIND_GUIDELINES}
|
|
30329
|
-
|
|
30330
|
-
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
30331
|
-
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
30332
|
-
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
30333
|
-
No prose.`;
|
|
30334
|
-
async function extractEntitiesForMemories(memories, options) {
|
|
30335
|
-
const out = /* @__PURE__ */ new Map();
|
|
30336
|
-
if (memories.length === 0) return out;
|
|
30337
|
-
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
30338
|
-
const vocabulary = [];
|
|
30339
|
-
for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
|
|
30340
|
-
vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
|
|
30341
|
-
}
|
|
30342
|
-
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
30343
|
-
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".
|
|
30344
|
-
|
|
30345
|
-
` : "";
|
|
30346
|
-
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
30347
|
-
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
30348
|
-
const rows = [];
|
|
30349
|
-
for (const m of batch) {
|
|
30350
|
-
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
|
|
30351
|
-
rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
|
|
30352
|
-
}
|
|
30353
|
-
const listing = rows.join("\n");
|
|
30354
|
-
const parsed = await callPortalJsonCompletion({
|
|
30355
|
-
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
30356
|
-
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
30357
|
-
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
30358
|
-
taskType: "memory_topic",
|
|
30359
|
-
...options.endpointOverride !== void 0 && {
|
|
30360
|
-
endpointOverride: options.endpointOverride
|
|
30361
|
-
},
|
|
30362
|
-
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
30363
|
-
systemPrompt: SYSTEM_PROMPT5,
|
|
30364
|
-
userMessage: `${vocabularyNote}Memories:
|
|
30365
|
-
${listing}
|
|
30366
|
-
|
|
30367
|
-
List each memory's named entities.`,
|
|
30368
|
-
tag: "memory/topics",
|
|
30369
|
-
extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
|
|
30370
|
-
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
30371
|
-
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
30372
|
-
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
30373
|
-
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
30374
|
-
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
30375
|
-
});
|
|
30376
|
-
if (parsed === null) {
|
|
30377
|
-
getLogger().warn(
|
|
30378
|
-
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
30379
|
-
);
|
|
30380
|
-
continue;
|
|
30381
|
-
}
|
|
30382
|
-
const validIds = new Set(batch.map((m) => m.id));
|
|
30383
|
-
const byId = parseTopicResponse(parsed, validIds);
|
|
30384
|
-
if (byId === null) {
|
|
30385
|
-
getLogger().warn(
|
|
30386
|
-
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
30387
|
-
);
|
|
30388
|
-
continue;
|
|
30389
|
-
}
|
|
30390
|
-
for (const m of batch) {
|
|
30391
|
-
const entities = byId.get(m.id);
|
|
30392
|
-
if (entities === void 0) {
|
|
30393
|
-
continue;
|
|
30394
|
-
}
|
|
30395
|
-
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
30396
|
-
}
|
|
30397
|
-
}
|
|
30398
|
-
return out;
|
|
30399
|
-
}
|
|
30400
|
-
function restoreEntities(entities, redactor) {
|
|
30401
|
-
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
30402
|
-
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
30403
|
-
);
|
|
30404
|
-
}
|
|
30405
|
-
function parseTopicResponse(parsed, validIds) {
|
|
30406
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
30407
|
-
const list = parsed.memories;
|
|
30408
|
-
if (!Array.isArray(list)) return null;
|
|
30409
|
-
const out = /* @__PURE__ */ new Map();
|
|
30410
|
-
for (const raw of list) {
|
|
30411
|
-
if (typeof raw !== "object" || raw === null) continue;
|
|
30412
|
-
const obj = raw;
|
|
30413
|
-
if (typeof obj.id !== "string") continue;
|
|
30414
|
-
const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
|
|
30415
|
-
if (!validIds.has(id) || out.has(id)) continue;
|
|
30416
|
-
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
30417
|
-
out.set(id, entities);
|
|
30418
|
-
}
|
|
30419
|
-
return out;
|
|
30420
|
-
}
|
|
30421
|
-
var DEGRADED_TOPIC_SKIP = {
|
|
30422
|
-
excluded: false,
|
|
30423
|
-
"link-declined": false,
|
|
30424
|
-
"stamp-declined": false,
|
|
30425
|
-
"llm-unanswered": true,
|
|
30426
|
-
unreadable: true,
|
|
30427
|
-
"not-found": true,
|
|
30428
|
-
"link-failed": true
|
|
30429
|
-
};
|
|
30430
|
-
function isDegradedTopicSkip(reason) {
|
|
30431
|
-
return DEGRADED_TOPIC_SKIP[reason] === true;
|
|
30432
|
-
}
|
|
30433
|
-
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
30434
|
-
const entityCtx = ctx.entityCtx;
|
|
30435
|
-
if (!entityCtx) {
|
|
30436
|
-
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
30437
|
-
}
|
|
30438
|
-
const log = getLogger();
|
|
30439
|
-
const extractedAt = options.now ?? Date.now();
|
|
30440
|
-
const skippedIds = [];
|
|
30441
|
-
const skippedReasons = /* @__PURE__ */ new Map();
|
|
30442
|
-
const skip = (id, reason) => {
|
|
30443
|
-
if (skippedReasons.has(id)) return;
|
|
30444
|
-
skippedIds.push(id);
|
|
30445
|
-
skippedReasons.set(id, reason);
|
|
30446
|
-
};
|
|
30447
|
-
const inputs = [];
|
|
30448
|
-
for (const id of new Set(memoryIds)) {
|
|
30449
|
-
let record;
|
|
30450
|
-
try {
|
|
30451
|
-
record = await ctx.vaultMemoryCollection.find(id);
|
|
30452
|
-
} catch (err) {
|
|
30453
|
-
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
30454
|
-
skip(id, "not-found");
|
|
30455
|
-
continue;
|
|
30456
|
-
}
|
|
30457
|
-
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
30458
|
-
skip(id, "excluded");
|
|
30459
|
-
continue;
|
|
30460
|
-
}
|
|
30461
|
-
try {
|
|
30462
|
-
const stored = await vaultMemoryToStored(
|
|
30463
|
-
record,
|
|
30464
|
-
ctx.walletAddress,
|
|
30465
|
-
ctx.signMessage,
|
|
30466
|
-
ctx.embeddedWalletSigner
|
|
30467
|
-
);
|
|
30468
|
-
inputs.push({ id, content: stored.content });
|
|
30469
|
-
} catch (err) {
|
|
30470
|
-
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
30471
|
-
skip(id, "unreadable");
|
|
30472
|
-
}
|
|
30473
|
-
}
|
|
30474
|
-
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
30475
|
-
const toStamp = [];
|
|
30476
|
-
for (const input of inputs) {
|
|
30477
|
-
const entities = entitiesByMemory.get(input.id);
|
|
30478
|
-
if (entities === void 0) {
|
|
30479
|
-
skip(input.id, "llm-unanswered");
|
|
30480
|
-
continue;
|
|
30481
|
-
}
|
|
30482
|
-
try {
|
|
30483
|
-
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
30484
|
-
if (linked === null) {
|
|
30485
|
-
skip(input.id, "link-declined");
|
|
30486
|
-
entitiesByMemory.delete(input.id);
|
|
30487
|
-
continue;
|
|
30488
|
-
}
|
|
30489
|
-
} catch (err) {
|
|
30490
|
-
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
30491
|
-
skip(input.id, "link-failed");
|
|
30492
|
-
entitiesByMemory.delete(input.id);
|
|
30493
|
-
continue;
|
|
30494
|
-
}
|
|
30495
|
-
toStamp.push(input.id);
|
|
30496
|
-
}
|
|
30497
|
-
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
30498
|
-
const stampedSet = new Set(stampedIds);
|
|
30499
|
-
for (const id of toStamp) {
|
|
30500
|
-
if (!stampedSet.has(id)) {
|
|
30501
|
-
skip(id, "stamp-declined");
|
|
30502
|
-
entitiesByMemory.delete(id);
|
|
30503
|
-
}
|
|
30504
|
-
}
|
|
30505
|
-
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
30506
|
-
}
|
|
30507
|
-
|
|
30508
30706
|
// src/lib/memory/verifySupport.ts
|
|
30509
30707
|
var DEFAULT_MODEL5 = "inclusionai/ling-2.6-flash";
|
|
30510
30708
|
var DEFAULT_ATTEMPTS3 = 2;
|
|
@@ -30895,7 +31093,7 @@ async function assembleMemoryContext(options) {
|
|
|
30895
31093
|
}
|
|
30896
31094
|
|
|
30897
31095
|
// src/lib/memory/durableExtraction.ts
|
|
30898
|
-
var
|
|
31096
|
+
var import_watermelondb25 = __toESM(require_watermelondb());
|
|
30899
31097
|
var MAX_JOBS_PER_PASS = 3;
|
|
30900
31098
|
var MAX_ATTEMPTS = 3;
|
|
30901
31099
|
var MAX_FAILED_SESSIONS = 3;
|
|
@@ -31042,7 +31240,7 @@ function createDurableAutoExtractor(options) {
|
|
|
31042
31240
|
...options.retainCtx,
|
|
31043
31241
|
vaultCtx: {
|
|
31044
31242
|
...vault,
|
|
31045
|
-
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(
|
|
31243
|
+
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
|
|
31046
31244
|
}
|
|
31047
31245
|
},
|
|
31048
31246
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -31184,7 +31382,7 @@ function createDurableAutoExtractor(options) {
|
|
|
31184
31382
|
let scheduleAfterSuccess = false;
|
|
31185
31383
|
try {
|
|
31186
31384
|
await writes;
|
|
31187
|
-
const pending = await jobs.query(
|
|
31385
|
+
const pending = await jobs.query(import_watermelondb25.Q.where("owner_key", owner), import_watermelondb25.Q.where("message_ids", import_watermelondb25.Q.notEq("[]"))).fetch();
|
|
31188
31386
|
storeFailures = 0;
|
|
31189
31387
|
let processed = 0;
|
|
31190
31388
|
for (const job of pending) {
|
|
@@ -31200,7 +31398,7 @@ function createDurableAutoExtractor(options) {
|
|
|
31200
31398
|
let ids = [];
|
|
31201
31399
|
let loaded = [];
|
|
31202
31400
|
try {
|
|
31203
|
-
const conversations = await storage.conversationsCollection.query(
|
|
31401
|
+
const conversations = await storage.conversationsCollection.query(import_watermelondb25.Q.where("conversation_id", conversationId), import_watermelondb25.Q.where("is_deleted", false)).fetchCount();
|
|
31204
31402
|
if (!conversations) {
|
|
31205
31403
|
await database.write(() => job.destroyPermanently());
|
|
31206
31404
|
continue;
|
|
@@ -31317,12 +31515,12 @@ function createDurableAutoExtractor(options) {
|
|
|
31317
31515
|
const scope = currentScope();
|
|
31318
31516
|
writes = writes.then(
|
|
31319
31517
|
() => database.write(async () => {
|
|
31320
|
-
const existing = await jobs.query(
|
|
31518
|
+
const existing = await jobs.query(import_watermelondb25.Q.where("owner_key", owner), import_watermelondb25.Q.where("conversation_id", conversationId)).fetch();
|
|
31321
31519
|
const job = existing.find(
|
|
31322
31520
|
(candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
|
|
31323
31521
|
);
|
|
31324
31522
|
const positions = new Map(ids.map((id, index) => [id, index]));
|
|
31325
|
-
const rows = await storage.messagesCollection.query(
|
|
31523
|
+
const rows = await storage.messagesCollection.query(import_watermelondb25.Q.where("id", import_watermelondb25.Q.oneOf(ids))).fetch();
|
|
31326
31524
|
const sequences = /* @__PURE__ */ new Map();
|
|
31327
31525
|
for (const row of rows) {
|
|
31328
31526
|
const sequence = Number(row._getRaw("message_id"));
|
|
@@ -37423,6 +37621,7 @@ export {
|
|
|
37423
37621
|
createDurableAutoExtractor,
|
|
37424
37622
|
createLlmDecayClassifier,
|
|
37425
37623
|
createLlmNeighborRefiner,
|
|
37624
|
+
createLocalMemoryStore,
|
|
37426
37625
|
createMediaBatchOp,
|
|
37427
37626
|
createMediaOp,
|
|
37428
37627
|
createMemoryEngineTool,
|