@anuma/sdk 6.32.0 → 6.33.1
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 +456 -249
- package/dist/expo/index.d.mts +434 -170
- package/dist/expo/index.d.ts +434 -170
- package/dist/expo/index.mjs +415 -210
- package/dist/memory/context.d.mts +1 -0
- package/dist/memory/context.d.ts +1 -0
- package/dist/react/index.cjs +465 -303
- package/dist/react/index.d.mts +425 -170
- package/dist/react/index.d.ts +425 -170
- package/dist/react/index.mjs +418 -258
- package/dist/server/index.cjs +423 -216
- package/dist/server/index.d.mts +433 -171
- package/dist/server/index.d.ts +433 -171
- package/dist/server/index.mjs +418 -213
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -7500,7 +7500,13 @@ async function runToolLoop(options) {
|
|
|
7500
7500
|
);
|
|
7501
7501
|
const extra = results.flatMap((r) => Array.isArray(r) ? r : []);
|
|
7502
7502
|
if (extra.length > 0) {
|
|
7503
|
-
|
|
7503
|
+
let userIndex = messages.length - 1;
|
|
7504
|
+
while (userIndex > 0 && messages[userIndex].role !== "user") userIndex--;
|
|
7505
|
+
messages = [
|
|
7506
|
+
...messages.slice(0, userIndex),
|
|
7507
|
+
...await redactBatch(extra),
|
|
7508
|
+
...messages.slice(userIndex)
|
|
7509
|
+
];
|
|
7504
7510
|
}
|
|
7505
7511
|
}
|
|
7506
7512
|
} catch (err) {
|
|
@@ -11576,6 +11582,51 @@ async function updateVaultMemoryOp(ctx, id, opts) {
|
|
|
11576
11582
|
return null;
|
|
11577
11583
|
}
|
|
11578
11584
|
}
|
|
11585
|
+
async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
11586
|
+
const entityCtx = ctx.entityCtx;
|
|
11587
|
+
if (!entityCtx) {
|
|
11588
|
+
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
11589
|
+
}
|
|
11590
|
+
let record;
|
|
11591
|
+
try {
|
|
11592
|
+
record = await ctx.vaultMemoryCollection.find(memoryId);
|
|
11593
|
+
} catch {
|
|
11594
|
+
return null;
|
|
11595
|
+
}
|
|
11596
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
|
|
11597
|
+
let stale = false;
|
|
11598
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
11599
|
+
await ctx.database.write(async (writer) => {
|
|
11600
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
|
|
11601
|
+
stale = true;
|
|
11602
|
+
return;
|
|
11603
|
+
}
|
|
11604
|
+
await record.update((r) => {
|
|
11605
|
+
r._setRaw("topics_user_managed", true);
|
|
11606
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
11607
|
+
});
|
|
11608
|
+
const linked = entities.length > 0 ? await writer.callWriter(
|
|
11609
|
+
() => linkMemoryEntitiesOp(entityCtx, memoryId, entities, { topicsSource: "user" })
|
|
11610
|
+
) : [];
|
|
11611
|
+
const keep = new Set(linked.map((e) => e.uniqueId));
|
|
11612
|
+
const existing = await entityCtx.memoryEntityCollection.query(Q5.where("memory_id", memoryId)).fetch();
|
|
11613
|
+
const staleLinks = existing.filter((l) => !keep.has(String(l.entityId)));
|
|
11614
|
+
if (staleLinks.length === 0 && entities.length > 0) return;
|
|
11615
|
+
const topicsWrite = await resolveMemoryTopicsWrite(
|
|
11616
|
+
entityCtx,
|
|
11617
|
+
memoryId,
|
|
11618
|
+
linked,
|
|
11619
|
+
entities,
|
|
11620
|
+
"user"
|
|
11621
|
+
);
|
|
11622
|
+
await ctx.database.batch(
|
|
11623
|
+
...staleLinks.map((l) => l.prepareDestroyPermanently()),
|
|
11624
|
+
...topicsWrite ? [prepareMemoryTopicsUpdate(topicsWrite)] : []
|
|
11625
|
+
);
|
|
11626
|
+
});
|
|
11627
|
+
if (stale) return null;
|
|
11628
|
+
return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
11629
|
+
}
|
|
11579
11630
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
11580
11631
|
let record;
|
|
11581
11632
|
try {
|
|
@@ -14129,7 +14180,10 @@ async function eagerEmbedContent(content, embeddingOptions, cache, vaultCtx, mem
|
|
|
14129
14180
|
if (memoryId) cacheRowVector(cache, memoryId, Float32Array.from(embedding), updatedAt, content);
|
|
14130
14181
|
if (vaultCtx && memoryId) {
|
|
14131
14182
|
const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
14132
|
-
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel
|
|
14183
|
+
updateVaultMemoryEmbeddingOp(vaultCtx, memoryId, JSON.stringify(embedding), currentModel, {
|
|
14184
|
+
content,
|
|
14185
|
+
...updatedAt !== void 0 && { updatedAt: updatedAt.getTime() }
|
|
14186
|
+
}).catch(
|
|
14133
14187
|
// Silently swallow – SDK must not use console.*; embedding will be retried on next search
|
|
14134
14188
|
() => {
|
|
14135
14189
|
}
|
|
@@ -17650,6 +17704,349 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
17650
17704
|
};
|
|
17651
17705
|
}
|
|
17652
17706
|
|
|
17707
|
+
// src/lib/memory/store/local.ts
|
|
17708
|
+
import { Q as Q7 } from "@nozbe/watermelondb";
|
|
17709
|
+
|
|
17710
|
+
// src/lib/memory/topicExtract.ts
|
|
17711
|
+
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
17712
|
+
var MAX_CHARS_PER_MEMORY = 300;
|
|
17713
|
+
var MAX_VOCABULARY_NAMES = 100;
|
|
17714
|
+
var MAX_COMPLETION_TOKENS = 8192;
|
|
17715
|
+
var SYSTEM_PROMPT5 = `You assign topics to saved memories for a personal memory system.
|
|
17716
|
+
|
|
17717
|
+
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.
|
|
17718
|
+
|
|
17719
|
+
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:
|
|
17720
|
+
- 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.
|
|
17721
|
+
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
17722
|
+
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
17723
|
+
${ENTITY_KIND_GUIDELINES}
|
|
17724
|
+
|
|
17725
|
+
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
17726
|
+
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
17727
|
+
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
17728
|
+
No prose.`;
|
|
17729
|
+
async function extractEntitiesForMemories(memories, options) {
|
|
17730
|
+
const out = /* @__PURE__ */ new Map();
|
|
17731
|
+
if (memories.length === 0) return out;
|
|
17732
|
+
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
17733
|
+
const vocabulary = [];
|
|
17734
|
+
for (const name of (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES)) {
|
|
17735
|
+
vocabulary.push(redactor ? (await redactor.redactTextAsync(name)).text : name);
|
|
17736
|
+
}
|
|
17737
|
+
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
17738
|
+
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".
|
|
17739
|
+
|
|
17740
|
+
` : "";
|
|
17741
|
+
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
17742
|
+
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
17743
|
+
const rows = [];
|
|
17744
|
+
for (const m of batch) {
|
|
17745
|
+
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY).replace(/\s+/g, " ").trim();
|
|
17746
|
+
rows.push(`${m.id}: ${redactor ? (await redactor.redactTextAsync(content)).text : content}`);
|
|
17747
|
+
}
|
|
17748
|
+
const listing = rows.join("\n");
|
|
17749
|
+
const parsed = await callPortalJsonCompletion({
|
|
17750
|
+
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
17751
|
+
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
17752
|
+
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
17753
|
+
taskType: "memory_topic",
|
|
17754
|
+
...options.endpointOverride !== void 0 && {
|
|
17755
|
+
endpointOverride: options.endpointOverride
|
|
17756
|
+
},
|
|
17757
|
+
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
17758
|
+
systemPrompt: SYSTEM_PROMPT5,
|
|
17759
|
+
userMessage: `${vocabularyNote}Memories:
|
|
17760
|
+
${listing}
|
|
17761
|
+
|
|
17762
|
+
List each memory's named entities.`,
|
|
17763
|
+
tag: "memory/topics",
|
|
17764
|
+
extra: { max_completion_tokens: MAX_COMPLETION_TOKENS },
|
|
17765
|
+
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
17766
|
+
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
17767
|
+
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
17768
|
+
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
17769
|
+
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
17770
|
+
});
|
|
17771
|
+
if (parsed === null) {
|
|
17772
|
+
getLogger().warn(
|
|
17773
|
+
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
17774
|
+
);
|
|
17775
|
+
continue;
|
|
17776
|
+
}
|
|
17777
|
+
const validIds = new Set(batch.map((m) => m.id));
|
|
17778
|
+
const byId = parseTopicResponse(parsed, validIds);
|
|
17779
|
+
if (byId === null) {
|
|
17780
|
+
getLogger().warn(
|
|
17781
|
+
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
17782
|
+
);
|
|
17783
|
+
continue;
|
|
17784
|
+
}
|
|
17785
|
+
for (const m of batch) {
|
|
17786
|
+
const entities = byId.get(m.id);
|
|
17787
|
+
if (entities === void 0) {
|
|
17788
|
+
continue;
|
|
17789
|
+
}
|
|
17790
|
+
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
17791
|
+
}
|
|
17792
|
+
}
|
|
17793
|
+
return out;
|
|
17794
|
+
}
|
|
17795
|
+
function restoreEntities(entities, redactor) {
|
|
17796
|
+
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
17797
|
+
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
17798
|
+
);
|
|
17799
|
+
}
|
|
17800
|
+
function parseTopicResponse(parsed, validIds) {
|
|
17801
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
17802
|
+
const list = parsed.memories;
|
|
17803
|
+
if (!Array.isArray(list)) return null;
|
|
17804
|
+
const out = /* @__PURE__ */ new Map();
|
|
17805
|
+
for (const raw of list) {
|
|
17806
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
17807
|
+
const obj = raw;
|
|
17808
|
+
if (typeof obj.id !== "string") continue;
|
|
17809
|
+
const id = obj.id.trim().replace(/:$/, "").replace(/^\[([\s\S]*)\]$/, "$1").trim();
|
|
17810
|
+
if (!validIds.has(id) || out.has(id)) continue;
|
|
17811
|
+
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
17812
|
+
out.set(id, entities);
|
|
17813
|
+
}
|
|
17814
|
+
return out;
|
|
17815
|
+
}
|
|
17816
|
+
var DEGRADED_TOPIC_SKIP = {
|
|
17817
|
+
excluded: false,
|
|
17818
|
+
"link-declined": false,
|
|
17819
|
+
"stamp-declined": false,
|
|
17820
|
+
"llm-unanswered": true,
|
|
17821
|
+
unreadable: true,
|
|
17822
|
+
"not-found": true,
|
|
17823
|
+
"link-failed": true
|
|
17824
|
+
};
|
|
17825
|
+
function isDegradedTopicSkip(reason) {
|
|
17826
|
+
return DEGRADED_TOPIC_SKIP[reason] === true;
|
|
17827
|
+
}
|
|
17828
|
+
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
17829
|
+
const entityCtx = ctx.entityCtx;
|
|
17830
|
+
if (!entityCtx) {
|
|
17831
|
+
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
17832
|
+
}
|
|
17833
|
+
const log = getLogger();
|
|
17834
|
+
const extractedAt = options.now ?? Date.now();
|
|
17835
|
+
const skippedIds = [];
|
|
17836
|
+
const skippedReasons = /* @__PURE__ */ new Map();
|
|
17837
|
+
const skip = (id, reason) => {
|
|
17838
|
+
if (skippedReasons.has(id)) return;
|
|
17839
|
+
skippedIds.push(id);
|
|
17840
|
+
skippedReasons.set(id, reason);
|
|
17841
|
+
};
|
|
17842
|
+
const inputs = [];
|
|
17843
|
+
for (const id of new Set(memoryIds)) {
|
|
17844
|
+
let record;
|
|
17845
|
+
try {
|
|
17846
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
17847
|
+
} catch (err) {
|
|
17848
|
+
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
17849
|
+
skip(id, "not-found");
|
|
17850
|
+
continue;
|
|
17851
|
+
}
|
|
17852
|
+
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
17853
|
+
skip(id, "excluded");
|
|
17854
|
+
continue;
|
|
17855
|
+
}
|
|
17856
|
+
try {
|
|
17857
|
+
const stored = await vaultMemoryToStored(
|
|
17858
|
+
record,
|
|
17859
|
+
ctx.walletAddress,
|
|
17860
|
+
ctx.signMessage,
|
|
17861
|
+
ctx.embeddedWalletSigner
|
|
17862
|
+
);
|
|
17863
|
+
inputs.push({ id, content: stored.content });
|
|
17864
|
+
} catch (err) {
|
|
17865
|
+
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
17866
|
+
skip(id, "unreadable");
|
|
17867
|
+
}
|
|
17868
|
+
}
|
|
17869
|
+
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
17870
|
+
const toStamp = [];
|
|
17871
|
+
for (const input of inputs) {
|
|
17872
|
+
const entities = entitiesByMemory.get(input.id);
|
|
17873
|
+
if (entities === void 0) {
|
|
17874
|
+
skip(input.id, "llm-unanswered");
|
|
17875
|
+
continue;
|
|
17876
|
+
}
|
|
17877
|
+
try {
|
|
17878
|
+
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
17879
|
+
if (linked === null) {
|
|
17880
|
+
skip(input.id, "link-declined");
|
|
17881
|
+
entitiesByMemory.delete(input.id);
|
|
17882
|
+
continue;
|
|
17883
|
+
}
|
|
17884
|
+
} catch (err) {
|
|
17885
|
+
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
17886
|
+
skip(input.id, "link-failed");
|
|
17887
|
+
entitiesByMemory.delete(input.id);
|
|
17888
|
+
continue;
|
|
17889
|
+
}
|
|
17890
|
+
toStamp.push(input.id);
|
|
17891
|
+
}
|
|
17892
|
+
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
17893
|
+
const stampedSet = new Set(stampedIds);
|
|
17894
|
+
for (const id of toStamp) {
|
|
17895
|
+
if (!stampedSet.has(id)) {
|
|
17896
|
+
skip(id, "stamp-declined");
|
|
17897
|
+
entitiesByMemory.delete(id);
|
|
17898
|
+
}
|
|
17899
|
+
}
|
|
17900
|
+
return { entitiesByMemory, stampedIds, skippedIds, skippedReasons };
|
|
17901
|
+
}
|
|
17902
|
+
|
|
17903
|
+
// src/lib/memory/store/local.ts
|
|
17904
|
+
function createLocalMemoryStore(options) {
|
|
17905
|
+
const { database, userId } = options;
|
|
17906
|
+
const entityCtx = {
|
|
17907
|
+
database,
|
|
17908
|
+
entityCollection: database.get("entity"),
|
|
17909
|
+
memoryEntityCollection: database.get("memory_entity"),
|
|
17910
|
+
...userId !== void 0 && { userId },
|
|
17911
|
+
...options.allowUnscopedRows !== void 0 && {
|
|
17912
|
+
allowUnscopedRows: options.allowUnscopedRows
|
|
17913
|
+
}
|
|
17914
|
+
};
|
|
17915
|
+
const vaultCtx = {
|
|
17916
|
+
database,
|
|
17917
|
+
vaultMemoryCollection: database.get("memory_vault"),
|
|
17918
|
+
walletAddress: options.walletAddress,
|
|
17919
|
+
signMessage: options.signMessage,
|
|
17920
|
+
embeddedWalletSigner: options.embeddedWalletSigner,
|
|
17921
|
+
...userId !== void 0 && { userId },
|
|
17922
|
+
...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
|
|
17923
|
+
// Deletes cascade to memory_entity, so the graph lane never serves a
|
|
17924
|
+
// deleted memory's id.
|
|
17925
|
+
entityCtx
|
|
17926
|
+
};
|
|
17927
|
+
const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
|
|
17928
|
+
const ownedBy = userId !== void 0 ? [Q7.where("user_id", userId)] : [];
|
|
17929
|
+
const watchedColumns = [
|
|
17930
|
+
"content",
|
|
17931
|
+
"scope",
|
|
17932
|
+
"updated_at",
|
|
17933
|
+
"fact_type",
|
|
17934
|
+
"event_time_start",
|
|
17935
|
+
"event_time_end",
|
|
17936
|
+
"event_time_kind",
|
|
17937
|
+
"archived_at",
|
|
17938
|
+
"trust_tier",
|
|
17939
|
+
"superseded_by",
|
|
17940
|
+
"visibility",
|
|
17941
|
+
"published_at",
|
|
17942
|
+
"geohash",
|
|
17943
|
+
"topics",
|
|
17944
|
+
"topics_user_managed",
|
|
17945
|
+
"media",
|
|
17946
|
+
"source"
|
|
17947
|
+
];
|
|
17948
|
+
const embedInBackground = (memory) => {
|
|
17949
|
+
eagerEmbedContent(
|
|
17950
|
+
memory.content,
|
|
17951
|
+
options.embeddingOptions,
|
|
17952
|
+
vaultCache,
|
|
17953
|
+
vaultCtx,
|
|
17954
|
+
memory.uniqueId,
|
|
17955
|
+
memory.updatedAt
|
|
17956
|
+
).catch((err) => {
|
|
17957
|
+
getLogger().warn("[memory/store] Failed to embed memory:", err);
|
|
17958
|
+
});
|
|
17959
|
+
};
|
|
17960
|
+
return {
|
|
17961
|
+
list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
|
|
17962
|
+
get: (id) => getVaultMemoryOp(vaultCtx, id),
|
|
17963
|
+
listArchived: async () => {
|
|
17964
|
+
const ids = await vaultCtx.vaultMemoryCollection.query(Q7.where("is_deleted", false), Q7.where("archived_at", Q7.notEq(null)), ...ownedBy).fetchIds();
|
|
17965
|
+
if (ids.length === 0) return [];
|
|
17966
|
+
const rows = await getAllVaultMemoriesOp(vaultCtx, { memoryIds: ids, includeArchived: true });
|
|
17967
|
+
return rows.sort((a, b) => (b.archivedAt ?? 0) - (a.archivedAt ?? 0));
|
|
17968
|
+
},
|
|
17969
|
+
memoriesByTopics: (names) => getMemoriesByEntityNamesOp(entityCtx, names),
|
|
17970
|
+
topicsByMemories: (memoryIds) => getEntitiesByMemoryIdsOp(entityCtx, memoryIds),
|
|
17971
|
+
create: async (input) => {
|
|
17972
|
+
const created = await createVaultMemoryOp(vaultCtx, input);
|
|
17973
|
+
if (input.embedding === void 0) embedInBackground(created);
|
|
17974
|
+
return created;
|
|
17975
|
+
},
|
|
17976
|
+
createMany: async (inputs) => {
|
|
17977
|
+
const created = await createVaultMemoriesBatchOp(vaultCtx, inputs);
|
|
17978
|
+
created.forEach((memory, i) => {
|
|
17979
|
+
if (inputs[i].embedding === void 0) embedInBackground(memory);
|
|
17980
|
+
});
|
|
17981
|
+
return created;
|
|
17982
|
+
},
|
|
17983
|
+
update: async (id, patch) => {
|
|
17984
|
+
const reembed = patch.embedding === void 0;
|
|
17985
|
+
const updated = await updateVaultMemoryOp(
|
|
17986
|
+
vaultCtx,
|
|
17987
|
+
id,
|
|
17988
|
+
reembed ? { ...patch, embedding: null } : patch
|
|
17989
|
+
);
|
|
17990
|
+
if (!updated) return null;
|
|
17991
|
+
vaultCache.delete(id);
|
|
17992
|
+
if (reembed) embedInBackground(updated);
|
|
17993
|
+
return updated;
|
|
17994
|
+
},
|
|
17995
|
+
delete: async (id) => {
|
|
17996
|
+
const deleted = await deleteVaultMemoryOp(vaultCtx, id);
|
|
17997
|
+
if (deleted) vaultCache.delete(id);
|
|
17998
|
+
return deleted;
|
|
17999
|
+
},
|
|
18000
|
+
supersede: (id, supersededById) => supersedeVaultMemoryOp(vaultCtx, id, supersededById),
|
|
18001
|
+
archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
|
|
18002
|
+
restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
|
|
18003
|
+
setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
|
|
18004
|
+
addTopics: (memoryId, topics) => database.write(async (writer) => {
|
|
18005
|
+
const owned = await vaultCtx.vaultMemoryCollection.query(Q7.where("id", memoryId), Q7.where("is_deleted", false), ...ownedBy).fetchCount();
|
|
18006
|
+
return owned > 0 ? writer.callWriter(() => linkMemoryEntitiesOp(entityCtx, memoryId, topics)) : [];
|
|
18007
|
+
}),
|
|
18008
|
+
setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
|
|
18009
|
+
recall: (query, recallOptions) => recall(
|
|
18010
|
+
query,
|
|
18011
|
+
{ vaultCtx, entityCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
18012
|
+
{ ...recallOptions, types: ["fact"] }
|
|
18013
|
+
),
|
|
18014
|
+
retain: (content, retainOptions) => retain(
|
|
18015
|
+
content,
|
|
18016
|
+
{ vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
|
|
18017
|
+
retainOptions
|
|
18018
|
+
),
|
|
18019
|
+
subscribe: (onChange, subscribeOptions) => {
|
|
18020
|
+
const afterFirst = () => {
|
|
18021
|
+
let first = true;
|
|
18022
|
+
return () => {
|
|
18023
|
+
if (first) first = false;
|
|
18024
|
+
else onChange();
|
|
18025
|
+
};
|
|
18026
|
+
};
|
|
18027
|
+
const memories = subscribeOptions?.includeDeleted ? vaultCtx.vaultMemoryCollection.query(...ownedBy).observe() : vaultCtx.vaultMemoryCollection.query(Q7.where("is_deleted", false), ...ownedBy).observeWithColumns(
|
|
18028
|
+
subscribeOptions?.embeddings ? [...watchedColumns, "embedding", "embedding_model"] : watchedColumns
|
|
18029
|
+
);
|
|
18030
|
+
const subscriptions = [memories.subscribe(afterFirst())];
|
|
18031
|
+
if (subscribeOptions?.topics) {
|
|
18032
|
+
const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [Q7.or(Q7.where("user_id", userId), Q7.where("user_id", null))] : [Q7.where("user_id", userId)];
|
|
18033
|
+
subscriptions.push(
|
|
18034
|
+
entityCtx.memoryEntityCollection.query(...linksOwnedBy).observe().subscribe(afterFirst())
|
|
18035
|
+
);
|
|
18036
|
+
}
|
|
18037
|
+
return () => subscriptions.forEach((s) => s.unsubscribe());
|
|
18038
|
+
},
|
|
18039
|
+
maintenance: {
|
|
18040
|
+
createDecaySweeper: (sweeperOptions) => createDecaySweeper({ ...sweeperOptions, vaultCtx }),
|
|
18041
|
+
getTopicBacklog: (backlogOptions) => getMemoriesNeedingTopicExtractionOp(vaultCtx, backlogOptions),
|
|
18042
|
+
extractTopics: (memoryIds, extractOptions) => extractAndLinkEntitiesForMemoriesOp(vaultCtx, memoryIds, extractOptions),
|
|
18043
|
+
stampTopicsExtracted: (memoryIds, extractedAt, version) => stampTopicsExtractedAtOp(vaultCtx, memoryIds, extractedAt, version),
|
|
18044
|
+
relinkTopics: (memoryIds) => relinkMemoryTopicsOp(vaultCtx, memoryIds),
|
|
18045
|
+
backfillTopics: (memoryIds) => backfillMemoryTopicsOp(vaultCtx, memoryIds)
|
|
18046
|
+
}
|
|
18047
|
+
};
|
|
18048
|
+
}
|
|
18049
|
+
|
|
17653
18050
|
// src/lib/memory/synthesizeProfile.ts
|
|
17654
18051
|
var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
|
|
17655
18052
|
var DEFAULT_FACET_RECALL_LIMIT = 20;
|
|
@@ -18177,199 +18574,6 @@ function normalizeInterests(values) {
|
|
|
18177
18574
|
return out.length > 0 ? out : void 0;
|
|
18178
18575
|
}
|
|
18179
18576
|
|
|
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
18577
|
// src/lib/memory/verifySupport.ts
|
|
18374
18578
|
var DEFAULT_MODEL5 = "inclusionai/ling-2.6-flash";
|
|
18375
18579
|
var DEFAULT_ATTEMPTS3 = 2;
|
|
@@ -18760,7 +18964,7 @@ async function assembleMemoryContext(options) {
|
|
|
18760
18964
|
}
|
|
18761
18965
|
|
|
18762
18966
|
// src/lib/memory/durableExtraction.ts
|
|
18763
|
-
import { Q as
|
|
18967
|
+
import { Q as Q8 } from "@nozbe/watermelondb";
|
|
18764
18968
|
var MAX_JOBS_PER_PASS = 3;
|
|
18765
18969
|
var MAX_ATTEMPTS = 3;
|
|
18766
18970
|
var MAX_FAILED_SESSIONS = 3;
|
|
@@ -18907,7 +19111,7 @@ function createDurableAutoExtractor(options) {
|
|
|
18907
19111
|
...options.retainCtx,
|
|
18908
19112
|
vaultCtx: {
|
|
18909
19113
|
...vault,
|
|
18910
|
-
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(
|
|
19114
|
+
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
19115
|
}
|
|
18912
19116
|
},
|
|
18913
19117
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -19049,7 +19253,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19049
19253
|
let scheduleAfterSuccess = false;
|
|
19050
19254
|
try {
|
|
19051
19255
|
await writes;
|
|
19052
|
-
const pending = await jobs.query(
|
|
19256
|
+
const pending = await jobs.query(Q8.where("owner_key", owner), Q8.where("message_ids", Q8.notEq("[]"))).fetch();
|
|
19053
19257
|
storeFailures = 0;
|
|
19054
19258
|
let processed = 0;
|
|
19055
19259
|
for (const job of pending) {
|
|
@@ -19065,7 +19269,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19065
19269
|
let ids = [];
|
|
19066
19270
|
let loaded = [];
|
|
19067
19271
|
try {
|
|
19068
|
-
const conversations = await storage.conversationsCollection.query(
|
|
19272
|
+
const conversations = await storage.conversationsCollection.query(Q8.where("conversation_id", conversationId), Q8.where("is_deleted", false)).fetchCount();
|
|
19069
19273
|
if (!conversations) {
|
|
19070
19274
|
await database.write(() => job.destroyPermanently());
|
|
19071
19275
|
continue;
|
|
@@ -19182,12 +19386,12 @@ function createDurableAutoExtractor(options) {
|
|
|
19182
19386
|
const scope = currentScope();
|
|
19183
19387
|
writes = writes.then(
|
|
19184
19388
|
() => database.write(async () => {
|
|
19185
|
-
const existing = await jobs.query(
|
|
19389
|
+
const existing = await jobs.query(Q8.where("owner_key", owner), Q8.where("conversation_id", conversationId)).fetch();
|
|
19186
19390
|
const job = existing.find(
|
|
19187
19391
|
(candidate) => candidate._getRaw("scope") === scope && (candidate._getRaw("folder_id") ?? null) === folderId
|
|
19188
19392
|
);
|
|
19189
19393
|
const positions = new Map(ids.map((id, index) => [id, index]));
|
|
19190
|
-
const rows = await storage.messagesCollection.query(
|
|
19394
|
+
const rows = await storage.messagesCollection.query(Q8.where("id", Q8.oneOf(ids))).fetch();
|
|
19191
19395
|
const sequences = /* @__PURE__ */ new Map();
|
|
19192
19396
|
for (const row of rows) {
|
|
19193
19397
|
const sequence = Number(row._getRaw("message_id"));
|
|
@@ -23340,7 +23544,7 @@ var DatabaseManager = class {
|
|
|
23340
23544
|
};
|
|
23341
23545
|
|
|
23342
23546
|
// src/lib/db/conversationMemory/operations.ts
|
|
23343
|
-
import { Q as
|
|
23547
|
+
import { Q as Q9 } from "@nozbe/watermelondb";
|
|
23344
23548
|
var MAX_PER_CONVERSATION = 200;
|
|
23345
23549
|
function conversationMemoryToStored(row) {
|
|
23346
23550
|
return {
|
|
@@ -23355,7 +23559,7 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
|
|
|
23355
23559
|
if (!conversationId || items.length === 0) return;
|
|
23356
23560
|
const now = Date.now();
|
|
23357
23561
|
await ctx.database.write(async () => {
|
|
23358
|
-
const existing = await ctx.conversationMemoryCollection.query(
|
|
23562
|
+
const existing = await ctx.conversationMemoryCollection.query(Q9.where("conversation_id", conversationId), Q9.sortBy("created_at", Q9.asc)).fetch();
|
|
23359
23563
|
const seen = new Set(existing.map((r) => r.memoryId));
|
|
23360
23564
|
const batchSeen = /* @__PURE__ */ new Set();
|
|
23361
23565
|
const deduped = [];
|
|
@@ -23390,20 +23594,20 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
|
|
|
23390
23594
|
}
|
|
23391
23595
|
async function getConversationMemoriesOp(ctx, conversationId) {
|
|
23392
23596
|
if (!conversationId) return [];
|
|
23393
|
-
const rows = await ctx.conversationMemoryCollection.query(
|
|
23597
|
+
const rows = await ctx.conversationMemoryCollection.query(Q9.where("conversation_id", conversationId), Q9.sortBy("created_at", Q9.asc)).fetch();
|
|
23394
23598
|
return rows.map(conversationMemoryToStored);
|
|
23395
23599
|
}
|
|
23396
23600
|
async function clearConversationMemoriesOp(ctx, conversationId) {
|
|
23397
23601
|
if (!conversationId) return;
|
|
23398
23602
|
await ctx.database.write(async () => {
|
|
23399
|
-
const rows = await ctx.conversationMemoryCollection.query(
|
|
23603
|
+
const rows = await ctx.conversationMemoryCollection.query(Q9.where("conversation_id", conversationId)).fetch();
|
|
23400
23604
|
if (rows.length === 0) return;
|
|
23401
23605
|
await ctx.database.batch(...rows.map((r) => r.prepareDestroyPermanently()));
|
|
23402
23606
|
});
|
|
23403
23607
|
}
|
|
23404
23608
|
|
|
23405
23609
|
// src/lib/db/vaultFolders/operations.ts
|
|
23406
|
-
import { Q as
|
|
23610
|
+
import { Q as Q10 } from "@nozbe/watermelondb";
|
|
23407
23611
|
function folderToStored(folder) {
|
|
23408
23612
|
return {
|
|
23409
23613
|
uniqueId: folder.id,
|
|
@@ -23428,7 +23632,7 @@ async function createVaultFolderOp(ctx, opts) {
|
|
|
23428
23632
|
return folderToStored(created);
|
|
23429
23633
|
}
|
|
23430
23634
|
async function getAllVaultFoldersOp(ctx) {
|
|
23431
|
-
const results = await ctx.vaultFolderCollection.query(
|
|
23635
|
+
const results = await ctx.vaultFolderCollection.query(Q10.where("is_deleted", false), Q10.sortBy("created_at", Q10.desc)).fetch();
|
|
23432
23636
|
return results.map(folderToStored);
|
|
23433
23637
|
}
|
|
23434
23638
|
async function updateVaultFolderOp(ctx, id, opts) {
|
|
@@ -23437,7 +23641,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
|
|
|
23437
23641
|
if (record.isDeleted) return null;
|
|
23438
23642
|
const scopeChanged = opts.scope !== void 0 && opts.scope !== record.scope;
|
|
23439
23643
|
const updated = await ctx.database.write(async () => {
|
|
23440
|
-
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(
|
|
23644
|
+
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(Q10.where("folder_id", id), Q10.where("is_deleted", false)).fetch() : [];
|
|
23441
23645
|
const updates = [];
|
|
23442
23646
|
updates.push(
|
|
23443
23647
|
record.prepareUpdate((r) => {
|
|
@@ -23465,7 +23669,7 @@ async function deleteVaultFolderOp(ctx, id) {
|
|
|
23465
23669
|
const record = await ctx.vaultFolderCollection.find(id);
|
|
23466
23670
|
if (record.isDeleted) return false;
|
|
23467
23671
|
await ctx.database.write(async () => {
|
|
23468
|
-
const memories = await ctx.vaultMemoryCollection.query(
|
|
23672
|
+
const memories = await ctx.vaultMemoryCollection.query(Q10.where("folder_id", id), Q10.where("is_deleted", false)).fetch();
|
|
23469
23673
|
const preparedMemories = memories.map(
|
|
23470
23674
|
(memory) => memory.prepareUpdate((r) => {
|
|
23471
23675
|
r._setRaw("folder_id", null);
|
|
@@ -23534,7 +23738,7 @@ async function updateVaultFolderContextOp(ctx, id, context) {
|
|
|
23534
23738
|
}
|
|
23535
23739
|
}
|
|
23536
23740
|
async function getVaultFolderMemoryCountOp(ctx, folderId) {
|
|
23537
|
-
return await ctx.vaultMemoryCollection.query(
|
|
23741
|
+
return await ctx.vaultMemoryCollection.query(Q10.where("folder_id", folderId), Q10.where("is_deleted", false)).fetchCount();
|
|
23538
23742
|
}
|
|
23539
23743
|
|
|
23540
23744
|
// src/lib/db/vaultFolders/defaults.ts
|
|
@@ -24567,6 +24771,7 @@ export {
|
|
|
24567
24771
|
createDurableAutoExtractor,
|
|
24568
24772
|
createLlmDecayClassifier,
|
|
24569
24773
|
createLlmNeighborRefiner,
|
|
24774
|
+
createLocalMemoryStore,
|
|
24570
24775
|
createMemoryEngineTool,
|
|
24571
24776
|
createMemoryVaultSearchTool,
|
|
24572
24777
|
createMemoryVaultTool,
|