@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/expo/index.mjs
CHANGED
|
@@ -11576,6 +11576,51 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11576
11576
|
return null;
|
|
11577
11577
|
}
|
|
11578
11578
|
}
|
|
11579
|
+
async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
11580
|
+
const entityCtx = ctx.entityCtx;
|
|
11581
|
+
if (!entityCtx) {
|
|
11582
|
+
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
11583
|
+
}
|
|
11584
|
+
let record;
|
|
11585
|
+
try {
|
|
11586
|
+
record = await ctx.vaultMemoryCollection.find(memoryId);
|
|
11587
|
+
} catch {
|
|
11588
|
+
return null;
|
|
11589
|
+
}
|
|
11590
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
|
|
11591
|
+
let stale = false;
|
|
11592
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
11593
|
+
await ctx.database.write(async (writer) => {
|
|
11594
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
|
|
11595
|
+
stale = true;
|
|
11596
|
+
return;
|
|
11597
|
+
}
|
|
11598
|
+
await record.update((r) => {
|
|
11599
|
+
r._setRaw("topics_user_managed", true);
|
|
11600
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
11601
|
+
});
|
|
11602
|
+
const linked = entities.length > 0 ? await writer.callWriter(
|
|
11603
|
+
() => linkMemoryEntitiesOp(entityCtx, memoryId, entities, { topicsSource: "user" })
|
|
11604
|
+
) : [];
|
|
11605
|
+
const keep = new Set(linked.map((e) => e.uniqueId));
|
|
11606
|
+
const existing = await entityCtx.memoryEntityCollection.query(Q5.where("memory_id", memoryId)).fetch();
|
|
11607
|
+
const staleLinks = existing.filter((l) => !keep.has(String(l.entityId)));
|
|
11608
|
+
if (staleLinks.length === 0 && entities.length > 0) return;
|
|
11609
|
+
const topicsWrite = await resolveMemoryTopicsWrite(
|
|
11610
|
+
entityCtx,
|
|
11611
|
+
memoryId,
|
|
11612
|
+
linked,
|
|
11613
|
+
entities,
|
|
11614
|
+
"user"
|
|
11615
|
+
);
|
|
11616
|
+
await ctx.database.batch(
|
|
11617
|
+
...staleLinks.map((l) => l.prepareDestroyPermanently()),
|
|
11618
|
+
...topicsWrite ? [prepareMemoryTopicsUpdate(topicsWrite)] : []
|
|
11619
|
+
);
|
|
11620
|
+
});
|
|
11621
|
+
if (stale) return null;
|
|
11622
|
+
return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
11623
|
+
}
|
|
11579
11624
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
11580
11625
|
let record;
|
|
11581
11626
|
try {
|
|
@@ -14129,7 +14174,10 @@ async function eagerEmbedContent(content, embeddingOptions, cache, vaultCtx, mem
|
|
|
14129
14174
|
if (memoryId) cacheRowVector(cache, memoryId, Float32Array.from(embedding), updatedAt, content);
|
|
14130
14175
|
if (vaultCtx && memoryId) {
|
|
14131
14176
|
const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
14132
|
-
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel
|
|
14177
|
+
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel, {
|
|
14178
|
+
content,
|
|
14179
|
+
...updatedAt !== void 0 && { updatedAt: updatedAt.getTime() }
|
|
14180
|
+
}).catch(
|
|
14133
14181
|
// Silently swallow – SDK must not use console.*; embedding will be retried on next search
|
|
14134
14182
|
() => {
|
|
14135
14183
|
}
|
|
@@ -17650,6 +17698,349 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
17650
17698
|
};
|
|
17651
17699
|
}
|
|
17652
17700
|
|
|
17701
|
+
// src/lib/memory/store/local.ts
|
|
17702
|
+
import { Q as Q7 } from "@nozbe/watermelondb";
|
|
17703
|
+
|
|
17704
|
+
// src/lib/memory/topicExtract.ts
|
|
17705
|
+
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
17706
|
+
var MAX_CHARS_PER_MEMORY = 300;
|
|
17707
|
+
var MAX_VOCABULARY_NAMES = 100;
|
|
17708
|
+
var MAX_COMPLETION_TOKENS = 8192;
|
|
17709
|
+
var SYSTEM_PROMPT5 = `You assign topics to saved memories for a personal memory system.
|
|
17710
|
+
|
|
17711
|
+
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.
|
|
17712
|
+
|
|
17713
|
+
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:
|
|
17714
|
+
- 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.
|
|
17715
|
+
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
17716
|
+
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
17717
|
+
${ENTITY_KIND_GUIDELINES}
|
|
17718
|
+
|
|
17719
|
+
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
17720
|
+
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
17721
|
+
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
17722
|
+
No prose.`;
|
|
17723
|
+
async function extractEntitiesForMemories(memories, options) {
|
|
17724
|
+
const out = /* @__PURE__ */ new Map();
|
|
17725
|
+
if (memories.length === 0) return out;
|
|
17726
|
+
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
17727
|
+
const vocabulary = [];
|
|
17728
|
+
for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
|
|
17729
|
+
vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
|
|
17730
|
+
}
|
|
17731
|
+
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
17732
|
+
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".
|
|
17733
|
+
|
|
17734
|
+
` : "";
|
|
17735
|
+
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
17736
|
+
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
17737
|
+
const rows = [];
|
|
17738
|
+
for (const m of batch) {
|
|
17739
|
+
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
|
|
17740
|
+
rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
|
|
17741
|
+
}
|
|
17742
|
+
const listing = rows.join("\n");
|
|
17743
|
+
const parsed = await callPortalJsonCompletion({
|
|
17744
|
+
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
17745
|
+
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
17746
|
+
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
17747
|
+
taskType: "memory_topic",
|
|
17748
|
+
...options.endpointOverride !== void 0 && {
|
|
17749
|
+
endpointOverride: options.endpointOverride
|
|
17750
|
+
},
|
|
17751
|
+
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
17752
|
+
systemPrompt: SYSTEM_PROMPT5,
|
|
17753
|
+
userMessage: `${vocabularyNote}Memories:
|
|
17754
|
+
${listing}
|
|
17755
|
+
|
|
17756
|
+
List each memory's named entities.`,
|
|
17757
|
+
tag: "memory/topics",
|
|
17758
|
+
extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
|
|
17759
|
+
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
17760
|
+
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
17761
|
+
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
17762
|
+
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
17763
|
+
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
17764
|
+
});
|
|
17765
|
+
if (parsed === null) {
|
|
17766
|
+
getLogger().warn(
|
|
17767
|
+
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
17768
|
+
);
|
|
17769
|
+
continue;
|
|
17770
|
+
}
|
|
17771
|
+
const validIds = new Set(batch.map((m) => m.id));
|
|
17772
|
+
const byId = parseTopicResponse(parsed, validIds);
|
|
17773
|
+
if (byId === null) {
|
|
17774
|
+
getLogger().warn(
|
|
17775
|
+
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
17776
|
+
);
|
|
17777
|
+
continue;
|
|
17778
|
+
}
|
|
17779
|
+
for (const m of batch) {
|
|
17780
|
+
const entities = byId.get(m.id);
|
|
17781
|
+
if (entities === void 0) {
|
|
17782
|
+
continue;
|
|
17783
|
+
}
|
|
17784
|
+
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
17785
|
+
}
|
|
17786
|
+
}
|
|
17787
|
+
return out;
|
|
17788
|
+
}
|
|
17789
|
+
function restoreEntities(entities, redactor) {
|
|
17790
|
+
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
17791
|
+
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
17792
|
+
);
|
|
17793
|
+
}
|
|
17794
|
+
function parseTopicResponse(parsed, validIds) {
|
|
17795
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
17796
|
+
const list = parsed.memories;
|
|
17797
|
+
if (!Array.isArray(list)) return null;
|
|
17798
|
+
const out = /* @__PURE__ */ new Map();
|
|
17799
|
+
for (const raw of list) {
|
|
17800
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
17801
|
+
const obj = raw;
|
|
17802
|
+
if (typeof obj.id !== "string") continue;
|
|
17803
|
+
const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
|
|
17804
|
+
if (!validIds.has(id) || out.has(id)) continue;
|
|
17805
|
+
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
17806
|
+
out.set(id, entities);
|
|
17807
|
+
}
|
|
17808
|
+
return out;
|
|
17809
|
+
}
|
|
17810
|
+
var DEGRADED_TOPIC_SKIP = {
|
|
17811
|
+
excluded: false,
|
|
17812
|
+
"link-declined": false,
|
|
17813
|
+
"stamp-declined": false,
|
|
17814
|
+
"llm-unanswered": true,
|
|
17815
|
+
unreadable: true,
|
|
17816
|
+
"not-found": true,
|
|
17817
|
+
"link-failed": true
|
|
17818
|
+
};
|
|
17819
|
+
function isDegradedTopicSkip(reason) {
|
|
17820
|
+
return DEGRADED_TOPIC_SKIP[reason] === true;
|
|
17821
|
+
}
|
|
17822
|
+
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
17823
|
+
const entityCtx = ctx.entityCtx;
|
|
17824
|
+
if (!entityCtx) {
|
|
17825
|
+
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
17826
|
+
}
|
|
17827
|
+
const log = getLogger();
|
|
17828
|
+
const extractedAt = options.now ?? Date.now();
|
|
17829
|
+
const skippedIds = [];
|
|
17830
|
+
const skippedReasons = /* @__PURE__ */ new Map();
|
|
17831
|
+
const skip = (id, reason) => {
|
|
17832
|
+
if (skippedReasons.has(id)) return;
|
|
17833
|
+
skippedIds.push(id);
|
|
17834
|
+
skippedReasons.set(id, reason);
|
|
17835
|
+
};
|
|
17836
|
+
const inputs = [];
|
|
17837
|
+
for (const id of new Set(memoryIds)) {
|
|
17838
|
+
let record;
|
|
17839
|
+
try {
|
|
17840
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
17841
|
+
} catch (err) {
|
|
17842
|
+
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
17843
|
+
skip(id, "not-found");
|
|
17844
|
+
continue;
|
|
17845
|
+
}
|
|
17846
|
+
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
17847
|
+
skip(id, "excluded");
|
|
17848
|
+
continue;
|
|
17849
|
+
}
|
|
17850
|
+
try {
|
|
17851
|
+
const stored = await vaultMemoryToStored(
|
|
17852
|
+
record,
|
|
17853
|
+
ctx.walletAddress,
|
|
17854
|
+
ctx.signMessage,
|
|
17855
|
+
ctx.embeddedWalletSigner
|
|
17856
|
+
);
|
|
17857
|
+
inputs.push({ id, content: stored.content });
|
|
17858
|
+
} catch (err) {
|
|
17859
|
+
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
17860
|
+
skip(id, "unreadable");
|
|
17861
|
+
}
|
|
17862
|
+
}
|
|
17863
|
+
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
17864
|
+
const toStamp = [];
|
|
17865
|
+
for (const input of inputs) {
|
|
17866
|
+
const entities = entitiesByMemory.get(input.id);
|
|
17867
|
+
if (entities === void 0) {
|
|
17868
|
+
skip(input.id, "llm-unanswered");
|
|
17869
|
+
continue;
|
|
17870
|
+
}
|
|
17871
|
+
try {
|
|
17872
|
+
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
17873
|
+
if (linked === null) {
|
|
17874
|
+
skip(input.id, "link-declined");
|
|
17875
|
+
entitiesByMemory.delete(input.id);
|
|
17876
|
+
continue;
|
|
17877
|
+
}
|
|
17878
|
+
} catch (err) {
|
|
17879
|
+
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
17880
|
+
skip(input.id, "link-failed");
|
|
17881
|
+
entitiesByMemory.delete(input.id);
|
|
17882
|
+
continue;
|
|
17883
|
+
}
|
|
17884
|
+
toStamp.push(input.id);
|
|
17885
|
+
}
|
|
17886
|
+
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
17887
|
+
const stampedSet = new Set(stampedIds);
|
|
17888
|
+
for (const id of toStamp) {
|
|
17889
|
+
if (!stampedSet.has(id)) {
|
|
17890
|
+
skip(id, "stamp-declined");
|
|
17891
|
+
entitiesByMemory.delete(id);
|
|
17892
|
+
}
|
|
17893
|
+
}
|
|
17894
|
+
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
17895
|
+
}
|
|
17896
|
+
|
|
17897
|
+
// src/lib/memory/store/local.ts
|
|
17898
|
+
function createLocalMemoryStore(options) {
|
|
17899
|
+
const { database, userId } = options;
|
|
17900
|
+
const entityCtx = {
|
|
17901
|
+
database,
|
|
17902
|
+
entityCollection: database.get("entity"),
|
|
17903
|
+
memoryEntityCollection: database.get("memory_entity"),
|
|
17904
|
+
...userId !== void 0 && { userId },
|
|
17905
|
+
...options.allowUnscopedRows !== void 0 && {
|
|
17906
|
+
allowUnscopedRows: options.allowUnscopedRows
|
|
17907
|
+
}
|
|
17908
|
+
};
|
|
17909
|
+
const vaultCtx = {
|
|
17910
|
+
database,
|
|
17911
|
+
vaultMemoryCollection: database.get("memory_vault"),
|
|
17912
|
+
walletAddress: options.walletAddress,
|
|
17913
|
+
signMessage: options.signMessage,
|
|
17914
|
+
embeddedWalletSigner: options.embeddedWalletSigner,
|
|
17915
|
+
...userId !== void 0 && { userId },
|
|
17916
|
+
...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
|
|
17917
|
+
// Deletes cascade to memory_entity, so the graph lane never serves a
|
|
17918
|
+
// deleted memory's id.
|
|
17919
|
+
entityCtx
|
|
17920
|
+
};
|
|
17921
|
+
const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
|
|
17922
|
+
const ownedBy = userId !== void 0 ? [Q7.where("user_id", userId)] : [];
|
|
17923
|
+
const watchedColumns = [
|
|
17924
|
+
"content",
|
|
17925
|
+
"scope",
|
|
17926
|
+
"updated_at",
|
|
17927
|
+
"fact_type",
|
|
17928
|
+
"event_time_start",
|
|
17929
|
+
"event_time_end",
|
|
17930
|
+
"event_time_kind",
|
|
17931
|
+
"archived_at",
|
|
17932
|
+
"trust_tier",
|
|
17933
|
+
"superseded_by",
|
|
17934
|
+
"visibility",
|
|
17935
|
+
"published_at",
|
|
17936
|
+
"geohash",
|
|
17937
|
+
"topics",
|
|
17938
|
+
"topics_user_managed",
|
|
17939
|
+
"media",
|
|
17940
|
+
"source"
|
|
17941
|
+
];
|
|
17942
|
+
const embedInBackground = (memory) => {
|
|
17943
|
+
eagerEmbedContent(
|
|
17944
|
+
memory.content,
|
|
17945
|
+
options.embeddingOptions,
|
|
17946
|
+
vaultCache,
|
|
17947
|
+
vaultCtx,
|
|
17948
|
+
memory.uniqueId,
|
|
17949
|
+
memory.updatedAt
|
|
17950
|
+
).catch((err) => {
|
|
17951
|
+
getLogger().warn("[memory/store] Failed to embed memory:", err);
|
|
17952
|
+
});
|
|
17953
|
+
};
|
|
17954
|
+
return {
|
|
17955
|
+
list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
|
|
17956
|
+
get: (id) => getVaultMemoryOp(vaultCtx, id),
|
|
17957
|
+
listArchived: async () => {
|
|
17958
|
+
const ids = await vaultCtx.vaultMemoryCollection.query(Q7.where("is_deleted", false), Q7.where("archived_at", Q7.notEq(null)), ...ownedBy).fetchIds();
|
|
17959
|
+
if (ids.length === 0) return [];
|
|
17960
|
+
const rows = await getAllVaultMemoriesOp(vaultCtx, { memoryIds: ids, includeArchived: true });
|
|
17961
|
+
return rows.sort((a, b) => (b.archivedAt ?? 0) - (a.archivedAt ?? 0));
|
|
17962
|
+
},
|
|
17963
|
+
memoriesByTopics: (names) => getMemoriesByEntityNamesOp(entityCtx, names),
|
|
17964
|
+
topicsByMemories: (memoryIds) => getEntitiesByMemoryIdsOp(entityCtx, memoryIds),
|
|
17965
|
+
create: async (input) => {
|
|
17966
|
+
const created = await createVaultMemoryOp(vaultCtx, input);
|
|
17967
|
+
if (input.embedding === void 0) embedInBackground(created);
|
|
17968
|
+
return created;
|
|
17969
|
+
},
|
|
17970
|
+
createMany: async (inputs) => {
|
|
17971
|
+
const created = await createVaultMemoriesBatchOp(vaultCtx, inputs);
|
|
17972
|
+
created.forEach((memory, i) => {
|
|
17973
|
+
if (inputs[i].embedding === void 0) embedInBackground(memory);
|
|
17974
|
+
});
|
|
17975
|
+
return created;
|
|
17976
|
+
},
|
|
17977
|
+
update: async (id, patch) => {
|
|
17978
|
+
const reembed = patch.embedding === void 0;
|
|
17979
|
+
const updated = await updateVaultMemoryOp(
|
|
17980
|
+
vaultCtx,
|
|
17981
|
+
id,
|
|
17982
|
+
reembed ? { ...patch, embedding: null } : patch
|
|
17983
|
+
);
|
|
17984
|
+
if (!updated) return null;
|
|
17985
|
+
vaultCache.delete(id);
|
|
17986
|
+
if (reembed) embedInBackground(updated);
|
|
17987
|
+
return updated;
|
|
17988
|
+
},
|
|
17989
|
+
delete: async (id) => {
|
|
17990
|
+
const deleted = await deleteVaultMemoryOp(vaultCtx, id);
|
|
17991
|
+
if (deleted) vaultCache.delete(id);
|
|
17992
|
+
return deleted;
|
|
17993
|
+
},
|
|
17994
|
+
supersede: (id, supersededById) => supersedeVaultMemoryOp(vaultCtx, id, supersededById),
|
|
17995
|
+
archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
|
|
17996
|
+
restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
|
|
17997
|
+
setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
|
|
17998
|
+
addTopics: (memoryId, topics) => database.write(async (writer) => {
|
|
17999
|
+
const owned = await vaultCtx.vaultMemoryCollection.query(Q7.where("id", memoryId), Q7.where("is_deleted", false), ...ownedBy).fetchCount();
|
|
18000
|
+
return owned > 0 ? writer.callWriter(() => linkMemoryEntitiesOp(entityCtx, memoryId, topics)) : [];
|
|
18001
|
+
}),
|
|
18002
|
+
setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
|
|
18003
|
+
recall: (query, recallOptions) => recall(
|
|
18004
|
+
query,
|
|
18005
|
+
{ vaultCtx, entityCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
18006
|
+
{ ...recallOptions, types: ["fact"] }
|
|
18007
|
+
),
|
|
18008
|
+
retain: (content, retainOptions) => retain(
|
|
18009
|
+
content,
|
|
18010
|
+
{ vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
18011
|
+
retainOptions
|
|
18012
|
+
),
|
|
18013
|
+
subscribe: (onChange, subscribeOptions) => {
|
|
18014
|
+
const afterFirst = () => {
|
|
18015
|
+
let first = true;
|
|
18016
|
+
return () => {
|
|
18017
|
+
if (first) first = false;
|
|
18018
|
+
else onChange();
|
|
18019
|
+
};
|
|
18020
|
+
};
|
|
18021
|
+
const memories = subscribeOptions?.includeDeleted ? vaultCtx.vaultMemoryCollection.query(...ownedBy).observe() : vaultCtx.vaultMemoryCollection.query(Q7.where("is_deleted", false), ...ownedBy).observeWithColumns(
|
|
18022
|
+
subscribeOptions?.embeddings ? [...watchedColumns, "embedding", "embedding_model"] : watchedColumns
|
|
18023
|
+
);
|
|
18024
|
+
const subscriptions = [memories.subscribe(afterFirst())];
|
|
18025
|
+
if (subscribeOptions?.topics) {
|
|
18026
|
+
const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [Q7.or(Q7.where("user_id", userId), Q7.where("user_id", null))] : [Q7.where("user_id", userId)];
|
|
18027
|
+
subscriptions.push(
|
|
18028
|
+
entityCtx.memoryEntityCollection.query(...linksOwnedBy).observe().subscribe(afterFirst())
|
|
18029
|
+
);
|
|
18030
|
+
}
|
|
18031
|
+
return () => subscriptions.forEach((s) => s.unsubscribe());
|
|
18032
|
+
},
|
|
18033
|
+
maintenance: {
|
|
18034
|
+
createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...sweeperOptions, vaultCtx }),
|
|
18035
|
+
getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
|
|
18036
|
+
extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
|
|
18037
|
+
stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
|
|
18038
|
+
relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
|
|
18039
|
+
backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
|
|
18040
|
+
}
|
|
18041
|
+
};
|
|
18042
|
+
}
|
|
18043
|
+
|
|
17653
18044
|
// src/lib/memory/synthesizeProfile.ts
|
|
17654
18045
|
var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
|
|
17655
18046
|
var DEFAULT_FACET_RECALL_LIMIT = 20;
|
|
@@ -18177,199 +18568,6 @@ function normalizeInterests(values) {
|
|
|
18177
18568
|
return out.length > 0 ? out : void 0;
|
|
18178
18569
|
}
|
|
18179
18570
|
|
|
18180
|
-
// src/lib/memory/topicExtract.ts
|
|
18181
|
-
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
18182
|
-
var MAX_CHARS_PER_MEMORY = 300;
|
|
18183
|
-
var MAX_VOCABULARY_NAMES = 100;
|
|
18184
|
-
var MAX_COMPLETION_TOKENS = 8192;
|
|
18185
|
-
var SYSTEM_PROMPT5 = `You assign topics to saved memories for a personal memory system.
|
|
18186
|
-
|
|
18187
|
-
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.
|
|
18188
|
-
|
|
18189
|
-
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:
|
|
18190
|
-
- 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.
|
|
18191
|
-
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
18192
|
-
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
18193
|
-
${ENTITY_KIND_GUIDELINES}
|
|
18194
|
-
|
|
18195
|
-
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
18196
|
-
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
18197
|
-
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
18198
|
-
No prose.`;
|
|
18199
|
-
async function extractEntitiesForMemories(memories, options) {
|
|
18200
|
-
const out = /* @__PURE__ */ new Map();
|
|
18201
|
-
if (memories.length === 0) return out;
|
|
18202
|
-
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
18203
|
-
const vocabulary = [];
|
|
18204
|
-
for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
|
|
18205
|
-
vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
|
|
18206
|
-
}
|
|
18207
|
-
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
18208
|
-
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".
|
|
18209
|
-
|
|
18210
|
-
` : "";
|
|
18211
|
-
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
18212
|
-
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
18213
|
-
const rows = [];
|
|
18214
|
-
for (const m of batch) {
|
|
18215
|
-
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
|
|
18216
|
-
rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
|
|
18217
|
-
}
|
|
18218
|
-
const listing = rows.join("\n");
|
|
18219
|
-
const parsed = await callPortalJsonCompletion({
|
|
18220
|
-
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
18221
|
-
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
18222
|
-
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
18223
|
-
taskType: "memory_topic",
|
|
18224
|
-
...options.endpointOverride !== void 0 && {
|
|
18225
|
-
endpointOverride: options.endpointOverride
|
|
18226
|
-
},
|
|
18227
|
-
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
18228
|
-
systemPrompt: SYSTEM_PROMPT5,
|
|
18229
|
-
userMessage: `${vocabularyNote}Memories:
|
|
18230
|
-
${listing}
|
|
18231
|
-
|
|
18232
|
-
List each memory's named entities.`,
|
|
18233
|
-
tag: "memory/topics",
|
|
18234
|
-
extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
|
|
18235
|
-
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
18236
|
-
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
18237
|
-
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
18238
|
-
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
18239
|
-
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
18240
|
-
});
|
|
18241
|
-
if (parsed === null) {
|
|
18242
|
-
getLogger().warn(
|
|
18243
|
-
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
18244
|
-
);
|
|
18245
|
-
continue;
|
|
18246
|
-
}
|
|
18247
|
-
const validIds = new Set(batch.map((m) => m.id));
|
|
18248
|
-
const byId = parseTopicResponse(parsed, validIds);
|
|
18249
|
-
if (byId === null) {
|
|
18250
|
-
getLogger().warn(
|
|
18251
|
-
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
18252
|
-
);
|
|
18253
|
-
continue;
|
|
18254
|
-
}
|
|
18255
|
-
for (const m of batch) {
|
|
18256
|
-
const entities = byId.get(m.id);
|
|
18257
|
-
if (entities === void 0) {
|
|
18258
|
-
continue;
|
|
18259
|
-
}
|
|
18260
|
-
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
18261
|
-
}
|
|
18262
|
-
}
|
|
18263
|
-
return out;
|
|
18264
|
-
}
|
|
18265
|
-
function restoreEntities(entities, redactor) {
|
|
18266
|
-
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
18267
|
-
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
18268
|
-
);
|
|
18269
|
-
}
|
|
18270
|
-
function parseTopicResponse(parsed, validIds) {
|
|
18271
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
18272
|
-
const list = parsed.memories;
|
|
18273
|
-
if (!Array.isArray(list)) return null;
|
|
18274
|
-
const out = /* @__PURE__ */ new Map();
|
|
18275
|
-
for (const raw of list) {
|
|
18276
|
-
if (typeof raw !== "object" || raw === null) continue;
|
|
18277
|
-
const obj = raw;
|
|
18278
|
-
if (typeof obj.id !== "string") continue;
|
|
18279
|
-
const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
|
|
18280
|
-
if (!validIds.has(id) || out.has(id)) continue;
|
|
18281
|
-
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
18282
|
-
out.set(id, entities);
|
|
18283
|
-
}
|
|
18284
|
-
return out;
|
|
18285
|
-
}
|
|
18286
|
-
var DEGRADED_TOPIC_SKIP = {
|
|
18287
|
-
excluded: false,
|
|
18288
|
-
"link-declined": false,
|
|
18289
|
-
"stamp-declined": false,
|
|
18290
|
-
"llm-unanswered": true,
|
|
18291
|
-
unreadable: true,
|
|
18292
|
-
"not-found": true,
|
|
18293
|
-
"link-failed": true
|
|
18294
|
-
};
|
|
18295
|
-
function isDegradedTopicSkip(reason) {
|
|
18296
|
-
return DEGRADED_TOPIC_SKIP[reason] === true;
|
|
18297
|
-
}
|
|
18298
|
-
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
18299
|
-
const entityCtx = ctx.entityCtx;
|
|
18300
|
-
if (!entityCtx) {
|
|
18301
|
-
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
18302
|
-
}
|
|
18303
|
-
const log = getLogger();
|
|
18304
|
-
const extractedAt = options.now ?? Date.now();
|
|
18305
|
-
const skippedIds = [];
|
|
18306
|
-
const skippedReasons = /* @__PURE__ */ new Map();
|
|
18307
|
-
const skip = (id, reason) => {
|
|
18308
|
-
if (skippedReasons.has(id)) return;
|
|
18309
|
-
skippedIds.push(id);
|
|
18310
|
-
skippedReasons.set(id, reason);
|
|
18311
|
-
};
|
|
18312
|
-
const inputs = [];
|
|
18313
|
-
for (const id of new Set(memoryIds)) {
|
|
18314
|
-
let record;
|
|
18315
|
-
try {
|
|
18316
|
-
record = await ctx.vaultMemoryCollection.find(id);
|
|
18317
|
-
} catch (err) {
|
|
18318
|
-
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
18319
|
-
skip(id, "not-found");
|
|
18320
|
-
continue;
|
|
18321
|
-
}
|
|
18322
|
-
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
18323
|
-
skip(id, "excluded");
|
|
18324
|
-
continue;
|
|
18325
|
-
}
|
|
18326
|
-
try {
|
|
18327
|
-
const stored = await vaultMemoryToStored(
|
|
18328
|
-
record,
|
|
18329
|
-
ctx.walletAddress,
|
|
18330
|
-
ctx.signMessage,
|
|
18331
|
-
ctx.embeddedWalletSigner
|
|
18332
|
-
);
|
|
18333
|
-
inputs.push({ id, content: stored.content });
|
|
18334
|
-
} catch (err) {
|
|
18335
|
-
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
18336
|
-
skip(id, "unreadable");
|
|
18337
|
-
}
|
|
18338
|
-
}
|
|
18339
|
-
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
18340
|
-
const toStamp = [];
|
|
18341
|
-
for (const input of inputs) {
|
|
18342
|
-
const entities = entitiesByMemory.get(input.id);
|
|
18343
|
-
if (entities === void 0) {
|
|
18344
|
-
skip(input.id, "llm-unanswered");
|
|
18345
|
-
continue;
|
|
18346
|
-
}
|
|
18347
|
-
try {
|
|
18348
|
-
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
18349
|
-
if (linked === null) {
|
|
18350
|
-
skip(input.id, "link-declined");
|
|
18351
|
-
entitiesByMemory.delete(input.id);
|
|
18352
|
-
continue;
|
|
18353
|
-
}
|
|
18354
|
-
} catch (err) {
|
|
18355
|
-
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
18356
|
-
skip(input.id, "link-failed");
|
|
18357
|
-
entitiesByMemory.delete(input.id);
|
|
18358
|
-
continue;
|
|
18359
|
-
}
|
|
18360
|
-
toStamp.push(input.id);
|
|
18361
|
-
}
|
|
18362
|
-
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
18363
|
-
const stampedSet = new Set(stampedIds);
|
|
18364
|
-
for (const id of toStamp) {
|
|
18365
|
-
if (!stampedSet.has(id)) {
|
|
18366
|
-
skip(id, "stamp-declined");
|
|
18367
|
-
entitiesByMemory.delete(id);
|
|
18368
|
-
}
|
|
18369
|
-
}
|
|
18370
|
-
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
18371
|
-
}
|
|
18372
|
-
|
|
18373
18571
|
// src/lib/memory/verifySupport.ts
|
|
18374
18572
|
var DEFAULT_MODEL5 = "inclusionai/ling-2.6-flash";
|
|
18375
18573
|
var DEFAULT_ATTEMPTS3 = 2;
|
|
@@ -18760,7 +18958,7 @@ async function assembleMemoryContext(options) {
|
|
|
18760
18958
|
}
|
|
18761
18959
|
|
|
18762
18960
|
// src/lib/memory/durableExtraction.ts
|
|
18763
|
-
import { Q as
|
|
18961
|
+
import { Q as Q8 } from "@nozbe/watermelondb";
|
|
18764
18962
|
var MAX_JOBS_PER_PASS = 3;
|
|
18765
18963
|
var MAX_ATTEMPTS = 3;
|
|
18766
18964
|
var MAX_FAILED_SESSIONS = 3;
|
|
@@ -18907,7 +19105,7 @@ function createDurableAutoExtractor(options) {
|
|
|
18907
19105
|
...options.retainCtx,
|
|
18908
19106
|
vaultCtx: {
|
|
18909
19107
|
...vault,
|
|
18910
|
-
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(
|
|
19108
|
+
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(Q8.where("conversation_id", conversationId), Q8.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(Q8.where("conversation_id", conversationId), Q8.where("id", Q8.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
18911
19109
|
}
|
|
18912
19110
|
},
|
|
18913
19111
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -19049,7 +19247,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19049
19247
|
let scheduleAfterSuccess = false;
|
|
19050
19248
|
try {
|
|
19051
19249
|
await writes;
|
|
19052
|
-
const pending = await jobs.query(
|
|
19250
|
+
const pending = await jobs.query(Q8.where("owner_key", owner), Q8.where("message_ids", Q8.notEq("[]"))).fetch();
|
|
19053
19251
|
storeFailures = 0;
|
|
19054
19252
|
let processed = 0;
|
|
19055
19253
|
for (const job of pending) {
|
|
@@ -19065,7 +19263,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19065
19263
|
let ids = [];
|
|
19066
19264
|
let loaded = [];
|
|
19067
19265
|
try {
|
|
19068
|
-
const conversations = await storage.conversationsCollection.query(
|
|
19266
|
+
const conversations = await storage.conversationsCollection.query(Q8.where("conversation_id", conversationId), Q8.where("is_deleted", false)).fetchCount();
|
|
19069
19267
|
if (!conversations) {
|
|
19070
19268
|
await database.write(() => job.destroyPermanently());
|
|
19071
19269
|
continue;
|
|
@@ -19182,12 +19380,12 @@ function createDurableAutoExtractor(options) {
|
|
|
19182
19380
|
const scope = currentScope();
|
|
19183
19381
|
writes = writes.then(
|
|
19184
19382
|
() => database.write(async () => {
|
|
19185
|
-
const existing = await jobs.query(
|
|
19383
|
+
const existing = await jobs.query(Q8.where("owner_key", owner), Q8.where("conversation_id", conversationId)).fetch();
|
|
19186
19384
|
const job = existing.find(
|
|
19187
19385
|
(candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
|
|
19188
19386
|
);
|
|
19189
19387
|
const positions = new Map(ids.map((id, index) => [id, index]));
|
|
19190
|
-
const rows = await storage.messagesCollection.query(
|
|
19388
|
+
const rows = await storage.messagesCollection.query(Q8.where("id", Q8.oneOf(ids))).fetch();
|
|
19191
19389
|
const sequences = /* @__PURE__ */ new Map();
|
|
19192
19390
|
for (const row of rows) {
|
|
19193
19391
|
const sequence = Number(row._getRaw("message_id"));
|
|
@@ -23340,7 +23538,7 @@ var DatabaseManager = class {
|
|
|
23340
23538
|
};
|
|
23341
23539
|
|
|
23342
23540
|
// src/lib/db/conversationMemory/operations.ts
|
|
23343
|
-
import { Q as
|
|
23541
|
+
import { Q as Q9 } from "@nozbe/watermelondb";
|
|
23344
23542
|
var MAX_PER_CONVERSATION = 200;
|
|
23345
23543
|
function conversationMemoryToStored(row) {
|
|
23346
23544
|
return {
|
|
@@ -23355,7 +23553,7 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
|
|
|
23355
23553
|
if (!conversationId || items.length === 0) return;
|
|
23356
23554
|
const now = Date.now();
|
|
23357
23555
|
await ctx.database.write(async () => {
|
|
23358
|
-
const existing = await ctx.conversationMemoryCollection.query(
|
|
23556
|
+
const existing = await ctx.conversationMemoryCollection.query(Q9.where("conversation_id", conversationId), Q9.sortBy("created_at", Q9.asc)).fetch();
|
|
23359
23557
|
const seen = new Set(existing.map((r) => r.memoryId));
|
|
23360
23558
|
const batchSeen = /* @__PURE__ */ new Set();
|
|
23361
23559
|
const deduped = [];
|
|
@@ -23390,20 +23588,20 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
|
|
|
23390
23588
|
}
|
|
23391
23589
|
async function getConversationMemoriesOp(ctx, conversationId) {
|
|
23392
23590
|
if (!conversationId) return [];
|
|
23393
|
-
const rows = await ctx.conversationMemoryCollection.query(
|
|
23591
|
+
const rows = await ctx.conversationMemoryCollection.query(Q9.where("conversation_id", conversationId), Q9.sortBy("created_at", Q9.asc)).fetch();
|
|
23394
23592
|
return rows.map(conversationMemoryToStored);
|
|
23395
23593
|
}
|
|
23396
23594
|
async function clearConversationMemoriesOp(ctx, conversationId) {
|
|
23397
23595
|
if (!conversationId) return;
|
|
23398
23596
|
await ctx.database.write(async () => {
|
|
23399
|
-
const rows = await ctx.conversationMemoryCollection.query(
|
|
23597
|
+
const rows = await ctx.conversationMemoryCollection.query(Q9.where("conversation_id", conversationId)).fetch();
|
|
23400
23598
|
if (rows.length === 0) return;
|
|
23401
23599
|
await ctx.database.batch(...rows.map((r) => r.prepareDestroyPermanently()));
|
|
23402
23600
|
});
|
|
23403
23601
|
}
|
|
23404
23602
|
|
|
23405
23603
|
// src/lib/db/vaultFolders/operations.ts
|
|
23406
|
-
import { Q as
|
|
23604
|
+
import { Q as Q10 } from "@nozbe/watermelondb";
|
|
23407
23605
|
function folderToStored(folder) {
|
|
23408
23606
|
return {
|
|
23409
23607
|
uniqueId: folder.id,
|
|
@@ -23428,7 +23626,7 @@ async function createVaultFolderOp(ctx, opts) {
|
|
|
23428
23626
|
return folderToStored(created);
|
|
23429
23627
|
}
|
|
23430
23628
|
async function getAllVaultFoldersOp(ctx) {
|
|
23431
|
-
const results = await ctx.vaultFolderCollection.query(
|
|
23629
|
+
const results = await ctx.vaultFolderCollection.query(Q10.where("is_deleted", false), Q10.sortBy("created_at", Q10.desc)).fetch();
|
|
23432
23630
|
return results.map(folderToStored);
|
|
23433
23631
|
}
|
|
23434
23632
|
async function updateVaultFolderOp(ctx, id, opts) {
|
|
@@ -23437,7 +23635,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
23437
23635
|
if (record.isDeleted) return null;
|
|
23438
23636
|
const scopeChanged = opts.scope !== void 0 && opts.scope !== record.scope;
|
|
23439
23637
|
const updated = await ctx.database.write(async () => {
|
|
23440
|
-
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(
|
|
23638
|
+
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(Q10.where("folder_id", id), Q10.where("is_deleted", false)).fetch() : [];
|
|
23441
23639
|
const updates = [];
|
|
23442
23640
|
updates.push(
|
|
23443
23641
|
record.prepareUpdate((r) => {
|
|
@@ -23465,7 +23663,7 @@ async function deleteVaultFolderOp(ctx, id) {
|
|
|
23465
23663
|
const record = await ctx.vaultFolderCollection.find(id);
|
|
23466
23664
|
if (record.isDeleted) return false;
|
|
23467
23665
|
await ctx.database.write(async () => {
|
|
23468
|
-
const memories = await ctx.vaultMemoryCollection.query(
|
|
23666
|
+
const memories = await ctx.vaultMemoryCollection.query(Q10.where("folder_id", id), Q10.where("is_deleted", false)).fetch();
|
|
23469
23667
|
const preparedMemories = memories.map(
|
|
23470
23668
|
(memory) => memory.prepareUpdate((r) => {
|
|
23471
23669
|
r._setRaw("folder_id", null);
|
|
@@ -23534,7 +23732,7 @@ async function updateVaultFolderContextOp(ctx, id, context) {
|
|
|
23534
23732
|
}
|
|
23535
23733
|
}
|
|
23536
23734
|
async function getVaultFolderMemoryCountOp(ctx, folderId) {
|
|
23537
|
-
return await ctx.vaultMemoryCollection.query(
|
|
23735
|
+
return await ctx.vaultMemoryCollection.query(Q10.where("folder_id", folderId), Q10.where("is_deleted", false)).fetchCount();
|
|
23538
23736
|
}
|
|
23539
23737
|
|
|
23540
23738
|
// src/lib/db/vaultFolders/defaults.ts
|
|
@@ -24567,6 +24765,7 @@ export {
|
|
|
24567
24765
|
createDurableAutoExtractor,
|
|
24568
24766
|
createLlmDecayClassifier,
|
|
24569
24767
|
createLlmNeighborRefiner,
|
|
24768
|
+
createLocalMemoryStore,
|
|
24570
24769
|
createMemoryEngineTool,
|
|
24571
24770
|
createMemoryVaultSearchTool,
|
|
24572
24771
|
createMemoryVaultTool,
|