@anuma/sdk 2.0.1 → 2.2.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/{chunk-N4FEY34G.mjs → chunk-7PAISHUN.mjs} +134 -3
- package/dist/expo/index.cjs +341 -19
- package/dist/expo/index.d.mts +176 -2
- package/dist/expo/index.d.ts +176 -2
- package/dist/expo/index.mjs +208 -19
- package/dist/expo/{recall-DHOR5WWW.mjs → recall-62ZPSDHR.mjs} +1 -1
- package/dist/react/{chunk-63IW5BS5.mjs → chunk-KRNJVLI6.mjs} +135 -3
- package/dist/react/index.cjs +361 -26
- package/dist/react/index.d.mts +216 -6
- package/dist/react/index.d.ts +216 -6
- package/dist/react/index.mjs +226 -26
- package/dist/react/{recall-PUXEQHAP.mjs → recall-ASTJPM5Z.mjs} +1 -1
- package/dist/server/{chunk-45GOZ3AB.mjs → chunk-KEMPJE6C.mjs} +134 -3
- package/dist/server/index.cjs +341 -19
- package/dist/server/index.d.mts +176 -2
- package/dist/server/index.d.ts +176 -2
- package/dist/server/index.mjs +208 -19
- package/dist/server/{recall-RMBNCEG6.mjs → recall-K2YHLBBV.mjs} +1 -1
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -72,6 +72,7 @@ import {
|
|
|
72
72
|
getEncryptionKey,
|
|
73
73
|
getImageModel,
|
|
74
74
|
getMemoriesByEntityNamesOp,
|
|
75
|
+
getMemoriesNeedingTopicExtractionOp,
|
|
75
76
|
getMessageCountOp,
|
|
76
77
|
getMessageSkeletonsOp,
|
|
77
78
|
getMessagesOp,
|
|
@@ -101,6 +102,7 @@ import {
|
|
|
101
102
|
postAuthOauthByProviderRevoke,
|
|
102
103
|
preEmbedVaultMemories,
|
|
103
104
|
recall,
|
|
105
|
+
replaceMemoryEntitiesGuardedOp,
|
|
104
106
|
requestEncryptionKey,
|
|
105
107
|
requestKeyPair,
|
|
106
108
|
resolveStoredUserContent,
|
|
@@ -109,6 +111,7 @@ import {
|
|
|
109
111
|
searchVaultMemories,
|
|
110
112
|
setMemoryEntitiesOp,
|
|
111
113
|
shouldChunkMessage,
|
|
114
|
+
stampTopicsExtractedAtOp,
|
|
112
115
|
stripToolCalls,
|
|
113
116
|
updateConversationPinnedOp,
|
|
114
117
|
updateConversationProjectOp,
|
|
@@ -120,8 +123,9 @@ import {
|
|
|
120
123
|
updateMessageFileIdsOp,
|
|
121
124
|
updateVaultMemoryEmbeddingOp,
|
|
122
125
|
updateVaultMemoryOp,
|
|
123
|
-
useEncryption
|
|
124
|
-
|
|
126
|
+
useEncryption,
|
|
127
|
+
vaultMemoryToStored
|
|
128
|
+
} from "./chunk-KRNJVLI6.mjs";
|
|
125
129
|
import {
|
|
126
130
|
PiiRedactor,
|
|
127
131
|
createStreamingDeAnonymizer,
|
|
@@ -6659,6 +6663,9 @@ __decorateClass([
|
|
|
6659
6663
|
__decorateClass([
|
|
6660
6664
|
field3("topics_user_managed")
|
|
6661
6665
|
], VaultMemory.prototype, "topicsUserManaged", 2);
|
|
6666
|
+
__decorateClass([
|
|
6667
|
+
field3("topics_extracted_at")
|
|
6668
|
+
], VaultMemory.prototype, "topicsExtractedAt", 2);
|
|
6662
6669
|
__decorateClass([
|
|
6663
6670
|
readonly2,
|
|
6664
6671
|
date3("created_at")
|
|
@@ -6875,7 +6882,7 @@ async function isMemoryTopicsUserManaged(ctx, memoryId) {
|
|
|
6875
6882
|
return true;
|
|
6876
6883
|
}
|
|
6877
6884
|
}
|
|
6878
|
-
var
|
|
6885
|
+
var DEFAULT_EXTRACTION_MODEL = "gpt-oss/gpt-oss-120b";
|
|
6879
6886
|
var DEFAULT_MIN_CONFIDENCE = 0.7;
|
|
6880
6887
|
var MAX_CONTENT_LENGTH = 200;
|
|
6881
6888
|
var MIN_CONTENT_LENGTH = 3;
|
|
@@ -6888,6 +6895,16 @@ var FACT_TYPES = [
|
|
|
6888
6895
|
"constraint",
|
|
6889
6896
|
"other"
|
|
6890
6897
|
];
|
|
6898
|
+
var ENTITY_KIND_GUIDELINES = `Choose the MOST SPECIFIC kind:
|
|
6899
|
+
- person: a named individual ("Sara", "Dr. Lee")
|
|
6900
|
+
- organization: a company, team, school, or group ("Google", "the Warriors", "Stanford")
|
|
6901
|
+
- place: a geographic location or venue ("San Francisco", "Blue Bottle on Valencia")
|
|
6902
|
+
- event: a dated or nameable occurrence ("Chicago Marathon", "the Japan trip", "their wedding")
|
|
6903
|
+
- product: a named app, tool, brand, device, book, film, or other media title ("Linear", "iPhone", "Dune", "Ableton")
|
|
6904
|
+
- thing: a concrete physical object that isn't a branded product ("road bike", "sourdough starter")
|
|
6905
|
+
- concept: a topic, skill, field, language, or idea ("machine learning", "Spanish", "async communication")
|
|
6906
|
+
- other: a named entity that genuinely fits none of the above \u2014 use sparingly
|
|
6907
|
+
Prefer organization / product / event / place over the generic "thing"; fall back to "thing" or "other" only when no specific kind fits.`;
|
|
6891
6908
|
var SYSTEM_PROMPT = `You extract durable user facts from conversations for a personal memory system.
|
|
6892
6909
|
|
|
6893
6910
|
A "durable fact" is something the user shared about themselves that should still be true in future conversations. Examples that ARE durable:
|
|
@@ -6916,16 +6933,7 @@ For each durable fact, output:
|
|
|
6916
6933
|
- type: one of identity | preference | relationship | plan | ongoing_context | constraint | other
|
|
6917
6934
|
- confidence: 0.0-1.0; how sure you are this is durable AND true. Only include facts >= 0.7.
|
|
6918
6935
|
- sourceMessageIds: which message IDs from the conversation contained the evidence
|
|
6919
|
-
- entities: named entities mentioned, each as an object { "name": string, "kind": one of "person" | "organization" | "place" | "event" | "product" | "thing" | "concept" | "other" }. Optional \u2014 include only NAMED entities, skip generic/common nouns.
|
|
6920
|
-
- person: a named individual ("Sara", "Dr. Lee")
|
|
6921
|
-
- organization: a company, team, school, or group ("Google", "the Warriors", "Stanford")
|
|
6922
|
-
- place: a geographic location or venue ("San Francisco", "Blue Bottle on Valencia")
|
|
6923
|
-
- event: a dated or nameable occurrence ("Chicago Marathon", "the Japan trip", "their wedding")
|
|
6924
|
-
- product: a named app, tool, brand, device, book, film, or other media title ("Linear", "iPhone", "Dune", "Ableton")
|
|
6925
|
-
- thing: a concrete physical object that isn't a branded product ("road bike", "sourdough starter")
|
|
6926
|
-
- concept: a topic, skill, field, language, or idea ("machine learning", "Spanish", "async communication")
|
|
6927
|
-
- other: a named entity that genuinely fits none of the above \u2014 use sparingly
|
|
6928
|
-
Prefer organization / product / event / place over the generic "thing"; fall back to "thing" or "other" only when no specific kind fits. Examples:
|
|
6936
|
+
- entities: named entities mentioned, each as an object { "name": string, "kind": one of "person" | "organization" | "place" | "event" | "product" | "thing" | "concept" | "other" }. Optional \u2014 include only NAMED entities, skip generic/common nouns. ${ENTITY_KIND_GUIDELINES} Examples:
|
|
6929
6937
|
- "started a new job at Hollowpoint Labs and I'm learning Haskell for it" \u2192 entities: [{ "name": "Hollowpoint Labs", "kind": "organization" }, { "name": "Haskell", "kind": "concept" }]
|
|
6930
6938
|
- "running the Berlin Half in May and I track workouts in Whoop" \u2192 entities: [{ "name": "Berlin Half", "kind": "event" }, { "name": "Whoop", "kind": "product" }]
|
|
6931
6939
|
- eventTime: when the event in this fact occurs/occurred. Resolve relative phrases ("yesterday", "next week") against the current date given in the user message. Output one of:
|
|
@@ -6951,7 +6959,7 @@ async function extractFacts(messages, options) {
|
|
|
6951
6959
|
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
6952
6960
|
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
6953
6961
|
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
6954
|
-
model: options.model ??
|
|
6962
|
+
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
6955
6963
|
systemPrompt: SYSTEM_PROMPT,
|
|
6956
6964
|
userMessage: `Today's date is ${today}. Resolve any relative dates ("yesterday", "next week") against it.
|
|
6957
6965
|
|
|
@@ -7045,7 +7053,9 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
7045
7053
|
if (options.entityCtx && candidate.entities.length > 0) {
|
|
7046
7054
|
try {
|
|
7047
7055
|
if (!await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
|
|
7048
|
-
await linkMemoryEntitiesOp(options.entityCtx, result.memoryId, candidate.entities
|
|
7056
|
+
await linkMemoryEntitiesOp(options.entityCtx, result.memoryId, candidate.entities, {
|
|
7057
|
+
unlessTopicsUserManaged: true
|
|
7058
|
+
});
|
|
7049
7059
|
}
|
|
7050
7060
|
} catch (err) {
|
|
7051
7061
|
log.warn("[memory/extract] linkMemoryEntitiesOp failed", err);
|
|
@@ -7440,7 +7450,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
7440
7450
|
|
|
7441
7451
|
// src/lib/memory/reflect.ts
|
|
7442
7452
|
var DEFAULT_BASE_URL = BASE_URL;
|
|
7443
|
-
var
|
|
7453
|
+
var DEFAULT_MODEL = "anthropic/claude-sonnet-4-6";
|
|
7444
7454
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
7445
7455
|
var REQUEST_TIMEOUT_MS = 6e4;
|
|
7446
7456
|
var DEFAULT_SYSTEM_PROMPT = `You are a personal assistant with access to the user's memory. Answer the user's question using the supplied memories as evidence.
|
|
@@ -7472,7 +7482,7 @@ async function reflect(query, ctx, options) {
|
|
|
7472
7482
|
const evidence = recalled.memories.map((m, i) => `[${i + 1}] (id: ${m.id}, kind: ${m.kind})
|
|
7473
7483
|
${m.content}`).join("\n\n");
|
|
7474
7484
|
const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
|
|
7475
|
-
const model = options.llmModel ??
|
|
7485
|
+
const model = options.llmModel ?? DEFAULT_MODEL;
|
|
7476
7486
|
const wantsStructured = !!options.responseSchema;
|
|
7477
7487
|
const sendResponseFormat = wantsStructured && supportsResponseFormat(model, "json_schema");
|
|
7478
7488
|
const basePrompt = options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
@@ -7582,6 +7592,163 @@ function parseAnswer(body, base, parseSchema) {
|
|
|
7582
7592
|
};
|
|
7583
7593
|
}
|
|
7584
7594
|
|
|
7595
|
+
// src/lib/memory/topicExtract.ts
|
|
7596
|
+
var TOPIC_EXTRACTION_BATCH_SIZE = 10;
|
|
7597
|
+
var MAX_CHARS_PER_MEMORY = 300;
|
|
7598
|
+
var MAX_VOCABULARY_NAMES = 100;
|
|
7599
|
+
var SYSTEM_PROMPT2 = `You assign topics to saved memories for a personal memory system.
|
|
7600
|
+
|
|
7601
|
+
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.
|
|
7602
|
+
|
|
7603
|
+
Include only NAMED entities, skip generic/common nouns. ${ENTITY_KIND_GUIDELINES}
|
|
7604
|
+
|
|
7605
|
+
Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
7606
|
+
- exactly one element per input memory, echoing its id verbatim
|
|
7607
|
+
- "entities" may be empty when a memory mentions no named entities \u2014 most short memories have 0-3
|
|
7608
|
+
No prose.`;
|
|
7609
|
+
async function extractEntitiesForMemories(memories, options) {
|
|
7610
|
+
const out = /* @__PURE__ */ new Map();
|
|
7611
|
+
if (memories.length === 0) return out;
|
|
7612
|
+
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
7613
|
+
const vocabulary = (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES).map((n) => redactor ? redactor.redactText(n).text : n);
|
|
7614
|
+
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
7615
|
+
When a memory refers to one of these, reuse the EXACT existing name (same spelling and casing) instead of a variant.
|
|
7616
|
+
|
|
7617
|
+
` : "";
|
|
7618
|
+
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
|
7619
|
+
const batch = memories.slice(i, i + TOPIC_EXTRACTION_BATCH_SIZE);
|
|
7620
|
+
const listing = batch.map((m) => {
|
|
7621
|
+
const content = m.content.slice(0, MAX_CHARS_PER_MEMORY);
|
|
7622
|
+
return `[${m.id}] ${redactor ? redactor.redactText(content).text : content}`;
|
|
7623
|
+
}).join("\n");
|
|
7624
|
+
const parsed = await callPortalJsonCompletion({
|
|
7625
|
+
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
7626
|
+
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
7627
|
+
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
7628
|
+
model: options.model ?? DEFAULT_EXTRACTION_MODEL,
|
|
7629
|
+
systemPrompt: SYSTEM_PROMPT2,
|
|
7630
|
+
userMessage: `${vocabularyNote}Memories:
|
|
7631
|
+
${listing}
|
|
7632
|
+
|
|
7633
|
+
List each memory's named entities.`,
|
|
7634
|
+
tag: "memory/topics",
|
|
7635
|
+
...options.fetchFn && { fetchFn: options.fetchFn },
|
|
7636
|
+
...options.maxAttempts !== void 0 && { maxAttempts: options.maxAttempts },
|
|
7637
|
+
...options.timeoutMs !== void 0 && { timeoutMs: options.timeoutMs },
|
|
7638
|
+
...options.totalTimeoutMs !== void 0 && { totalTimeoutMs: options.totalTimeoutMs },
|
|
7639
|
+
...options.backoffMs && { backoffMs: options.backoffMs }
|
|
7640
|
+
});
|
|
7641
|
+
if (parsed === null) {
|
|
7642
|
+
getLogger().warn(
|
|
7643
|
+
`[memory/topics] batch of ${batch.length} failed after retries \u2014 will retry next sweep`
|
|
7644
|
+
);
|
|
7645
|
+
continue;
|
|
7646
|
+
}
|
|
7647
|
+
const validIds = new Set(batch.map((m) => m.id));
|
|
7648
|
+
const byId = parseTopicResponse(parsed, validIds);
|
|
7649
|
+
if (byId === null) {
|
|
7650
|
+
getLogger().warn(
|
|
7651
|
+
`[memory/topics] batch of ${batch.length} returned an unrecognized shape \u2014 will retry next sweep`
|
|
7652
|
+
);
|
|
7653
|
+
continue;
|
|
7654
|
+
}
|
|
7655
|
+
for (const m of batch) {
|
|
7656
|
+
const entities = byId.get(m.id);
|
|
7657
|
+
if (entities === void 0) {
|
|
7658
|
+
continue;
|
|
7659
|
+
}
|
|
7660
|
+
out.set(m.id, redactor ? restoreEntities(entities, redactor) : entities);
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7663
|
+
return out;
|
|
7664
|
+
}
|
|
7665
|
+
function restoreEntities(entities, redactor) {
|
|
7666
|
+
return entities.map((e) => ({ kind: e.kind, restored: redactor.restoreForStorage(e.name) })).filter((e) => !e.restored.unresolved).map(
|
|
7667
|
+
(e) => e.kind !== void 0 ? { name: e.restored.text, kind: e.kind } : { name: e.restored.text }
|
|
7668
|
+
);
|
|
7669
|
+
}
|
|
7670
|
+
function parseTopicResponse(parsed, validIds) {
|
|
7671
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
7672
|
+
const list = parsed.memories;
|
|
7673
|
+
if (!Array.isArray(list)) return null;
|
|
7674
|
+
const out = /* @__PURE__ */ new Map();
|
|
7675
|
+
for (const raw of list) {
|
|
7676
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
7677
|
+
const obj = raw;
|
|
7678
|
+
if (typeof obj.id !== "string" || !validIds.has(obj.id) || out.has(obj.id)) continue;
|
|
7679
|
+
const entities = Array.isArray(obj.entities) ? parseEntities(obj.entities) : [];
|
|
7680
|
+
out.set(obj.id, entities);
|
|
7681
|
+
}
|
|
7682
|
+
return out;
|
|
7683
|
+
}
|
|
7684
|
+
async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
7685
|
+
const entityCtx = ctx.entityCtx;
|
|
7686
|
+
if (!entityCtx) {
|
|
7687
|
+
throw new Error("extractAndLinkEntitiesForMemoriesOp requires ctx.entityCtx");
|
|
7688
|
+
}
|
|
7689
|
+
const log = getLogger();
|
|
7690
|
+
const extractedAt = options.now ?? Date.now();
|
|
7691
|
+
const skippedIds = [];
|
|
7692
|
+
const inputs = [];
|
|
7693
|
+
for (const id of memoryIds) {
|
|
7694
|
+
let record;
|
|
7695
|
+
try {
|
|
7696
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
7697
|
+
} catch {
|
|
7698
|
+
skippedIds.push(id);
|
|
7699
|
+
continue;
|
|
7700
|
+
}
|
|
7701
|
+
if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
|
|
7702
|
+
skippedIds.push(id);
|
|
7703
|
+
continue;
|
|
7704
|
+
}
|
|
7705
|
+
try {
|
|
7706
|
+
const stored = await vaultMemoryToStored(
|
|
7707
|
+
record,
|
|
7708
|
+
ctx.walletAddress,
|
|
7709
|
+
ctx.signMessage,
|
|
7710
|
+
ctx.embeddedWalletSigner
|
|
7711
|
+
);
|
|
7712
|
+
inputs.push({ id, content: stored.content });
|
|
7713
|
+
} catch (err) {
|
|
7714
|
+
log.warn("[memory/topics] failed to load memory for extraction", err);
|
|
7715
|
+
skippedIds.push(id);
|
|
7716
|
+
}
|
|
7717
|
+
}
|
|
7718
|
+
const entitiesByMemory = await extractEntitiesForMemories(inputs, options);
|
|
7719
|
+
const toStamp = [];
|
|
7720
|
+
for (const input of inputs) {
|
|
7721
|
+
const entities = entitiesByMemory.get(input.id);
|
|
7722
|
+
if (entities === void 0) {
|
|
7723
|
+
skippedIds.push(input.id);
|
|
7724
|
+
continue;
|
|
7725
|
+
}
|
|
7726
|
+
try {
|
|
7727
|
+
const linked = await replaceMemoryEntitiesGuardedOp(entityCtx, input.id, entities);
|
|
7728
|
+
if (linked === null) {
|
|
7729
|
+
skippedIds.push(input.id);
|
|
7730
|
+
entitiesByMemory.delete(input.id);
|
|
7731
|
+
continue;
|
|
7732
|
+
}
|
|
7733
|
+
} catch (err) {
|
|
7734
|
+
log.warn("[memory/topics] replaceMemoryEntitiesGuardedOp failed", err);
|
|
7735
|
+
skippedIds.push(input.id);
|
|
7736
|
+
entitiesByMemory.delete(input.id);
|
|
7737
|
+
continue;
|
|
7738
|
+
}
|
|
7739
|
+
toStamp.push(input.id);
|
|
7740
|
+
}
|
|
7741
|
+
const stampedIds = await stampTopicsExtractedAtOp(ctx, toStamp, extractedAt);
|
|
7742
|
+
const stampedSet = new Set(stampedIds);
|
|
7743
|
+
for (const id of toStamp) {
|
|
7744
|
+
if (!stampedSet.has(id)) {
|
|
7745
|
+
skippedIds.push(id);
|
|
7746
|
+
entitiesByMemory.delete(id);
|
|
7747
|
+
}
|
|
7748
|
+
}
|
|
7749
|
+
return { entitiesByMemory, stampedIds, skippedIds };
|
|
7750
|
+
}
|
|
7751
|
+
|
|
7585
7752
|
// src/lib/memoryEngine/quantization.ts
|
|
7586
7753
|
var INT8_MAX = 127;
|
|
7587
7754
|
function quantizeEmbedding(v) {
|
|
@@ -11921,7 +12088,7 @@ __decorateClass([
|
|
|
11921
12088
|
], VaultFolder.prototype, "context", 2);
|
|
11922
12089
|
|
|
11923
12090
|
// src/lib/db/schema.ts
|
|
11924
|
-
var SDK_SCHEMA_VERSION =
|
|
12091
|
+
var SDK_SCHEMA_VERSION = 36;
|
|
11925
12092
|
var sdkSchema = appSchema2({
|
|
11926
12093
|
version: SDK_SCHEMA_VERSION,
|
|
11927
12094
|
tables: [
|
|
@@ -12042,7 +12209,11 @@ var sdkSchema = appSchema2({
|
|
|
12042
12209
|
// When true, the user has manually set this memory's topics (entity
|
|
12043
12210
|
// links). Auto-extraction then leaves its links alone — the user owns
|
|
12044
12211
|
// them. Null/false = topics are auto-derived (default).
|
|
12045
|
-
{ name: "topics_user_managed", type: "boolean", isOptional: true }
|
|
12212
|
+
{ name: "topics_user_managed", type: "boolean", isOptional: true },
|
|
12213
|
+
// Unix ms of the last LLM topic-extraction pass over this memory's
|
|
12214
|
+
// content. Null = never extracted standalone (legacy rows with entity
|
|
12215
|
+
// links are grandfathered — see getMemoriesNeedingTopicExtractionOp).
|
|
12216
|
+
{ name: "topics_extracted_at", type: "number", isOptional: true }
|
|
12046
12217
|
]
|
|
12047
12218
|
}),
|
|
12048
12219
|
// Entity table — canonical names extracted from auto-extraction (W5).
|
|
@@ -12640,6 +12811,19 @@ var sdkMigrations = schemaMigrations2({
|
|
|
12640
12811
|
]
|
|
12641
12812
|
})
|
|
12642
12813
|
]
|
|
12814
|
+
},
|
|
12815
|
+
// v35 -> v36: topics_extracted_at watermark on memory_vault. Existing rows
|
|
12816
|
+
// keep it NULL — rows that already have entity links are grandfathered as
|
|
12817
|
+
// extracted (no mass re-extraction on upgrade), rows without links are the
|
|
12818
|
+
// backfill target. See getMemoriesNeedingTopicExtractionOp.
|
|
12819
|
+
{
|
|
12820
|
+
toVersion: 36,
|
|
12821
|
+
steps: [
|
|
12822
|
+
addColumns2({
|
|
12823
|
+
table: "memory_vault",
|
|
12824
|
+
columns: [{ name: "topics_extracted_at", type: "number", isOptional: true }]
|
|
12825
|
+
})
|
|
12826
|
+
]
|
|
12643
12827
|
}
|
|
12644
12828
|
]
|
|
12645
12829
|
});
|
|
@@ -14142,7 +14326,7 @@ function startObserve(entry, walletAddress) {
|
|
|
14142
14326
|
isInitialEmission = false;
|
|
14143
14327
|
}
|
|
14144
14328
|
function subscribeUserSettings(database, walletAddress, listener) {
|
|
14145
|
-
if (!walletAddress) return () => void 0;
|
|
14329
|
+
if (!database || !walletAddress) return () => void 0;
|
|
14146
14330
|
const perDb = getOrCreatePerDb(database);
|
|
14147
14331
|
let entry = perDb.get(walletAddress);
|
|
14148
14332
|
if (!entry) {
|
|
@@ -14172,17 +14356,18 @@ function subscribeUserSettings(database, walletAddress, listener) {
|
|
|
14172
14356
|
};
|
|
14173
14357
|
}
|
|
14174
14358
|
function getUserSettingsSnapshot(database, walletAddress) {
|
|
14175
|
-
if (!walletAddress) return EMPTY_SNAPSHOT;
|
|
14359
|
+
if (!database || !walletAddress) return EMPTY_SNAPSHOT;
|
|
14176
14360
|
return pool.get(database)?.get(walletAddress)?.snapshot ?? EMPTY_SNAPSHOT;
|
|
14177
14361
|
}
|
|
14178
14362
|
function patchUserSettingsSnapshot(database, walletAddress, patch) {
|
|
14179
|
-
if (!walletAddress) return;
|
|
14363
|
+
if (!database || !walletAddress) return;
|
|
14180
14364
|
const entry = pool.get(database)?.get(walletAddress);
|
|
14181
14365
|
if (!entry) return;
|
|
14182
14366
|
patchSnapshot(entry, patch);
|
|
14183
14367
|
}
|
|
14184
14368
|
|
|
14185
14369
|
// src/react/useSettings.ts
|
|
14370
|
+
var DB_NOT_READY = "Database not ready";
|
|
14186
14371
|
function useSettings(options) {
|
|
14187
14372
|
const { database, walletAddress } = options;
|
|
14188
14373
|
const subscribe = useCallback7(
|
|
@@ -14195,24 +14380,25 @@ function useSettings(options) {
|
|
|
14195
14380
|
);
|
|
14196
14381
|
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
14197
14382
|
const storageCtx = useMemo7(
|
|
14198
|
-
() =>
|
|
14383
|
+
() => database ? {
|
|
14199
14384
|
database,
|
|
14200
14385
|
userPreferencesCollection: database.get("userPreferences"),
|
|
14201
14386
|
modelPreferencesCollection: database.get("modelPreferences")
|
|
14202
|
-
}
|
|
14387
|
+
} : null,
|
|
14203
14388
|
[database]
|
|
14204
14389
|
);
|
|
14205
14390
|
const legacyStorageCtx = useMemo7(
|
|
14206
|
-
() =>
|
|
14391
|
+
() => database ? {
|
|
14207
14392
|
database,
|
|
14208
14393
|
modelPreferencesCollection: database.get("modelPreferences")
|
|
14209
|
-
}
|
|
14394
|
+
} : null,
|
|
14210
14395
|
[database]
|
|
14211
14396
|
);
|
|
14212
14397
|
const getModelPreference = useCallback7(
|
|
14213
14398
|
async (address) => {
|
|
14214
14399
|
try {
|
|
14215
14400
|
if (!address) throw new Error("Wallet address is required");
|
|
14401
|
+
if (!legacyStorageCtx) throw new Error(DB_NOT_READY);
|
|
14216
14402
|
const result = await getModelPreferenceOp(legacyStorageCtx, address);
|
|
14217
14403
|
return result;
|
|
14218
14404
|
} catch (error) {
|
|
@@ -14225,6 +14411,7 @@ function useSettings(options) {
|
|
|
14225
14411
|
async (address, models) => {
|
|
14226
14412
|
try {
|
|
14227
14413
|
if (!address) throw new Error("Wallet address is required");
|
|
14414
|
+
if (!legacyStorageCtx) throw new Error(DB_NOT_READY);
|
|
14228
14415
|
const result = await setModelPreferenceOp(legacyStorageCtx, address, models);
|
|
14229
14416
|
if (walletAddress && address === walletAddress) {
|
|
14230
14417
|
patchUserSettingsSnapshot(database, walletAddress, { modelPreference: result });
|
|
@@ -14240,6 +14427,7 @@ function useSettings(options) {
|
|
|
14240
14427
|
async (address) => {
|
|
14241
14428
|
try {
|
|
14242
14429
|
if (!address) throw new Error("Wallet address is required");
|
|
14430
|
+
if (!legacyStorageCtx) throw new Error(DB_NOT_READY);
|
|
14243
14431
|
const deleted = await deleteModelPreferenceOp(legacyStorageCtx, address);
|
|
14244
14432
|
if (deleted && walletAddress && address === walletAddress) {
|
|
14245
14433
|
patchUserSettingsSnapshot(database, walletAddress, { modelPreference: null });
|
|
@@ -14255,6 +14443,7 @@ function useSettings(options) {
|
|
|
14255
14443
|
async (address) => {
|
|
14256
14444
|
try {
|
|
14257
14445
|
if (!address) throw new Error("Wallet address is required");
|
|
14446
|
+
if (!storageCtx) throw new Error(DB_NOT_READY);
|
|
14258
14447
|
const result = await getUserPreferenceOp(storageCtx, address);
|
|
14259
14448
|
return result;
|
|
14260
14449
|
} catch (error) {
|
|
@@ -14267,6 +14456,7 @@ function useSettings(options) {
|
|
|
14267
14456
|
async (address, opts) => {
|
|
14268
14457
|
try {
|
|
14269
14458
|
if (!address) throw new Error("Wallet address is required");
|
|
14459
|
+
if (!storageCtx) throw new Error(DB_NOT_READY);
|
|
14270
14460
|
const result = await setUserPreferenceOp(storageCtx, address, opts);
|
|
14271
14461
|
if (walletAddress && address === walletAddress) {
|
|
14272
14462
|
patchUserSettingsSnapshot(database, walletAddress, { userPreference: result });
|
|
@@ -14282,6 +14472,7 @@ function useSettings(options) {
|
|
|
14282
14472
|
async (address, profile) => {
|
|
14283
14473
|
try {
|
|
14284
14474
|
if (!address) throw new Error("Wallet address is required");
|
|
14475
|
+
if (!storageCtx) throw new Error(DB_NOT_READY);
|
|
14285
14476
|
const result = await updateProfileOp(storageCtx, address, profile);
|
|
14286
14477
|
if (result && walletAddress && address === walletAddress) {
|
|
14287
14478
|
patchUserSettingsSnapshot(database, walletAddress, { userPreference: result });
|
|
@@ -14297,6 +14488,7 @@ function useSettings(options) {
|
|
|
14297
14488
|
async (address, personality) => {
|
|
14298
14489
|
try {
|
|
14299
14490
|
if (!address) throw new Error("Wallet address is required");
|
|
14491
|
+
if (!storageCtx) throw new Error(DB_NOT_READY);
|
|
14300
14492
|
const result = await updatePersonalityOp(storageCtx, address, personality);
|
|
14301
14493
|
if (result && walletAddress && address === walletAddress) {
|
|
14302
14494
|
patchUserSettingsSnapshot(database, walletAddress, { userPreference: result });
|
|
@@ -14312,6 +14504,7 @@ function useSettings(options) {
|
|
|
14312
14504
|
async (address, models) => {
|
|
14313
14505
|
try {
|
|
14314
14506
|
if (!address) throw new Error("Wallet address is required");
|
|
14507
|
+
if (!storageCtx) throw new Error(DB_NOT_READY);
|
|
14315
14508
|
const result = await updateModelsOp(storageCtx, address, models);
|
|
14316
14509
|
if (result && walletAddress && address === walletAddress) {
|
|
14317
14510
|
patchUserSettingsSnapshot(database, walletAddress, { userPreference: result });
|
|
@@ -14327,6 +14520,7 @@ function useSettings(options) {
|
|
|
14327
14520
|
async (address) => {
|
|
14328
14521
|
try {
|
|
14329
14522
|
if (!address) throw new Error("Wallet address is required");
|
|
14523
|
+
if (!storageCtx) throw new Error(DB_NOT_READY);
|
|
14330
14524
|
const deleted = await deleteUserPreferenceOp(storageCtx, address);
|
|
14331
14525
|
if (deleted && walletAddress && address === walletAddress) {
|
|
14332
14526
|
patchUserSettingsSnapshot(database, walletAddress, { userPreference: null });
|
|
@@ -22283,6 +22477,7 @@ export {
|
|
|
22283
22477
|
VaultMemory as StoredVaultMemoryModel,
|
|
22284
22478
|
StreamExpiredError,
|
|
22285
22479
|
THEME_ATTRS,
|
|
22480
|
+
TOPIC_EXTRACTION_BATCH_SIZE,
|
|
22286
22481
|
TextProcessor,
|
|
22287
22482
|
UIInteractionProvider,
|
|
22288
22483
|
WalletPoller,
|
|
@@ -22374,7 +22569,9 @@ export {
|
|
|
22374
22569
|
exportElementToPdf,
|
|
22375
22570
|
exportMarkdownToPdf,
|
|
22376
22571
|
exportPublicKey,
|
|
22572
|
+
extractAndLinkEntitiesForMemoriesOp,
|
|
22377
22573
|
extractAndRetain,
|
|
22574
|
+
extractEntitiesForMemories,
|
|
22378
22575
|
extractFacts,
|
|
22379
22576
|
extractFileIds,
|
|
22380
22577
|
fileExists,
|
|
@@ -22430,6 +22627,7 @@ export {
|
|
|
22430
22627
|
getMediaOp,
|
|
22431
22628
|
getMediaTypeFromMime,
|
|
22432
22629
|
getMemoriesByEntityNamesOp,
|
|
22630
|
+
getMemoriesNeedingTopicExtractionOp,
|
|
22433
22631
|
getNotionAccessToken,
|
|
22434
22632
|
getNotionMCPUrl,
|
|
22435
22633
|
getNumberAttr,
|
|
@@ -22510,6 +22708,7 @@ export {
|
|
|
22510
22708
|
renderAnumaTree,
|
|
22511
22709
|
renderElementToCanvas,
|
|
22512
22710
|
replaceById,
|
|
22711
|
+
replaceMemoryEntitiesGuardedOp,
|
|
22513
22712
|
requestEncryptionKey,
|
|
22514
22713
|
requestKeyPair,
|
|
22515
22714
|
resolveFilePlaceholders,
|
|
@@ -22535,6 +22734,7 @@ export {
|
|
|
22535
22734
|
settingsStorageSchema,
|
|
22536
22735
|
shouldChunkMessage,
|
|
22537
22736
|
shouldRefreshTools,
|
|
22737
|
+
stampTopicsExtractedAtOp,
|
|
22538
22738
|
startGithubAuth,
|
|
22539
22739
|
startNotionAuth,
|
|
22540
22740
|
storeCalendarPendingMessage,
|