@anuma/sdk 10.10.0 → 11.0.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 +1024 -552
- package/dist/expo/index.d.mts +9 -5
- package/dist/expo/index.d.ts +9 -5
- package/dist/expo/index.mjs +1020 -552
- package/dist/react/index.cjs +1204 -661
- package/dist/react/index.d.mts +9 -5
- package/dist/react/index.d.ts +9 -5
- package/dist/react/index.mjs +1200 -661
- package/dist/tools/index.cjs +36 -2
- package/dist/tools/index.mjs +36 -2
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -1863,25 +1863,25 @@ var TRUNCATION_MARKER_HEAD = "... (tool output truncated, ";
|
|
|
1863
1863
|
var TRUNCATION_MARKER_TAIL = " characters omitted)";
|
|
1864
1864
|
var MAX_PERSISTED_TOOL_RESULT_CHARS = 1e5;
|
|
1865
1865
|
function buildToolResultContent(results) {
|
|
1866
|
-
const
|
|
1866
|
+
const entries2 = results.map(
|
|
1867
1867
|
(r) => `Tool "${r.name}" returned: ${JSON.stringify(r.result)}`.replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029")
|
|
1868
1868
|
);
|
|
1869
|
-
const framing = HEADER.length + FOOTER.length + ENTRY_SEPARATOR.length * Math.max(0,
|
|
1870
|
-
const summary = capEntries(
|
|
1869
|
+
const framing = HEADER.length + FOOTER.length + ENTRY_SEPARATOR.length * Math.max(0, entries2.length - 1);
|
|
1870
|
+
const summary = capEntries(entries2, MAX_PERSISTED_TOOL_RESULT_CHARS - framing).join(
|
|
1871
1871
|
ENTRY_SEPARATOR
|
|
1872
1872
|
);
|
|
1873
1873
|
return `${HEADER}${summary}${FOOTER}`;
|
|
1874
1874
|
}
|
|
1875
|
-
function capToolResultEntries(
|
|
1876
|
-
return capEntries(
|
|
1875
|
+
function capToolResultEntries(entries2, budget) {
|
|
1876
|
+
return capEntries(entries2, budget);
|
|
1877
1877
|
}
|
|
1878
|
-
function capEntries(
|
|
1879
|
-
const smallestFirst =
|
|
1880
|
-
const capped = [...
|
|
1878
|
+
function capEntries(entries2, budget) {
|
|
1879
|
+
const smallestFirst = entries2.map((_, index) => index).sort((a, b) => entries2[a].length - entries2[b].length);
|
|
1880
|
+
const capped = [...entries2];
|
|
1881
1881
|
let remaining = budget;
|
|
1882
|
-
let unassigned =
|
|
1882
|
+
let unassigned = entries2.length;
|
|
1883
1883
|
for (const index of smallestFirst) {
|
|
1884
|
-
capped[index] = truncateEntry(
|
|
1884
|
+
capped[index] = truncateEntry(entries2[index], Math.floor(remaining / unassigned));
|
|
1885
1885
|
remaining -= capped[index].length;
|
|
1886
1886
|
unassigned--;
|
|
1887
1887
|
}
|
|
@@ -2584,9 +2584,9 @@ async function refreshEncryptionKeyIfMatches(walletAddress, probeCiphertext, sig
|
|
|
2584
2584
|
return false;
|
|
2585
2585
|
}
|
|
2586
2586
|
const startEpoch = sessionEpoch;
|
|
2587
|
-
const
|
|
2588
|
-
if (
|
|
2589
|
-
return tryCommitCandidatesIfProbeMatches(walletAddress, parsed,
|
|
2587
|
+
const cached2 = refreshCandidatesByAddress.get(walletAddress);
|
|
2588
|
+
if (cached2) {
|
|
2589
|
+
return tryCommitCandidatesIfProbeMatches(walletAddress, parsed, cached2, startEpoch);
|
|
2590
2590
|
}
|
|
2591
2591
|
let derivePromise = pendingCandidateDerives.get(walletAddress);
|
|
2592
2592
|
if (!derivePromise) {
|
|
@@ -3557,11 +3557,11 @@ var ToolCallEventIndex = class {
|
|
|
3557
3557
|
this.pending = /* @__PURE__ */ new Map();
|
|
3558
3558
|
this.resetCount = collection.database._resetCount;
|
|
3559
3559
|
collection.experimentalSubscribe((changes) => {
|
|
3560
|
-
for (const { record:
|
|
3560
|
+
for (const { record: record3, type } of changes) {
|
|
3561
3561
|
this.replace(
|
|
3562
|
-
|
|
3563
|
-
type === "destroyed" ? void 0 :
|
|
3564
|
-
type === "destroyed" ? void 0 :
|
|
3562
|
+
record3.id,
|
|
3563
|
+
type === "destroyed" ? void 0 : record3.conversationId,
|
|
3564
|
+
type === "destroyed" ? void 0 : record3._getRaw("tool_call_events")
|
|
3565
3565
|
);
|
|
3566
3566
|
}
|
|
3567
3567
|
});
|
|
@@ -4972,15 +4972,15 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4972
4972
|
staleSkipped++;
|
|
4973
4973
|
continue;
|
|
4974
4974
|
}
|
|
4975
|
-
const
|
|
4976
|
-
if (!
|
|
4975
|
+
const cached2 = chunkCache?.get(key3.id);
|
|
4976
|
+
if (!cached2 || cached2.version !== key3.version) {
|
|
4977
4977
|
missIds.push(key3.id);
|
|
4978
4978
|
continue;
|
|
4979
4979
|
}
|
|
4980
4980
|
cacheHits++;
|
|
4981
|
-
if (
|
|
4982
|
-
for (let ci = 0; ci <
|
|
4983
|
-
const vec =
|
|
4981
|
+
if (cached2.chunks.length > 0) {
|
|
4982
|
+
for (let ci = 0; ci < cached2.chunks.length; ci++) {
|
|
4983
|
+
const vec = cached2.chunks[ci];
|
|
4984
4984
|
if (vec.length === 0) continue;
|
|
4985
4985
|
const similarity = cosineSimilarity(queryVector, vec);
|
|
4986
4986
|
if (similarity >= minSimilarity) {
|
|
@@ -4993,8 +4993,8 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4993
4993
|
});
|
|
4994
4994
|
}
|
|
4995
4995
|
}
|
|
4996
|
-
} else if (
|
|
4997
|
-
const similarity = cosineSimilarity(queryVector,
|
|
4996
|
+
} else if (cached2.fallback) {
|
|
4997
|
+
const similarity = cosineSimilarity(queryVector, cached2.fallback);
|
|
4998
4998
|
if (similarity >= minSimilarity) {
|
|
4999
4999
|
candidates.push({
|
|
5000
5000
|
id: key3.id,
|
|
@@ -5810,11 +5810,11 @@ var mergeConfigs = (a, b) => {
|
|
|
5810
5810
|
return config;
|
|
5811
5811
|
};
|
|
5812
5812
|
var headersEntries = (headers) => {
|
|
5813
|
-
const
|
|
5813
|
+
const entries2 = [];
|
|
5814
5814
|
headers.forEach((value, key3) => {
|
|
5815
|
-
|
|
5815
|
+
entries2.push([key3, value]);
|
|
5816
5816
|
});
|
|
5817
|
-
return
|
|
5817
|
+
return entries2;
|
|
5818
5818
|
};
|
|
5819
5819
|
var mergeHeaders = (...headers) => {
|
|
5820
5820
|
const mergedHeaders = new Headers();
|
|
@@ -6247,9 +6247,9 @@ async function embedOne(text16, options, outer) {
|
|
|
6247
6247
|
const { cache } = options;
|
|
6248
6248
|
if (!cache) return Array.from(await requestEmbedding(text16, options, outer));
|
|
6249
6249
|
const model = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
6250
|
-
const
|
|
6251
|
-
const cachedModel =
|
|
6252
|
-
if (
|
|
6250
|
+
const cached2 = cache.get(text16);
|
|
6251
|
+
const cachedModel = cached2 && cachedEmbeddingModels.get(cached2);
|
|
6252
|
+
if (cached2 && (cachedModel === void 0 || cachedModel === model)) return Array.from(cached2);
|
|
6253
6253
|
const inFlight = inFlightByCache.get(cache) ?? /* @__PURE__ */ new Map();
|
|
6254
6254
|
inFlightByCache.set(cache, inFlight);
|
|
6255
6255
|
const requestKey = JSON.stringify([model, text16]);
|
|
@@ -6364,10 +6364,10 @@ async function embedMany(texts, options, outer) {
|
|
|
6364
6364
|
const uncachedTexts = [];
|
|
6365
6365
|
for (let i = 0; i < texts.length; i++) {
|
|
6366
6366
|
if (cache) {
|
|
6367
|
-
const
|
|
6368
|
-
const cachedModel =
|
|
6369
|
-
if (
|
|
6370
|
-
results[i] = Array.from(
|
|
6367
|
+
const cached2 = cache.get(texts[i]);
|
|
6368
|
+
const cachedModel = cached2 && cachedEmbeddingModels.get(cached2);
|
|
6369
|
+
if (cached2 && (cachedModel === void 0 || cachedModel === embeddingModel)) {
|
|
6370
|
+
results[i] = Array.from(cached2);
|
|
6371
6371
|
continue;
|
|
6372
6372
|
}
|
|
6373
6373
|
}
|
|
@@ -6753,8 +6753,12 @@ function createCryptoPricePreProcessor(options = {}) {
|
|
|
6753
6753
|
}
|
|
6754
6754
|
|
|
6755
6755
|
// src/lib/memory/store/remotePersistence.ts
|
|
6756
|
+
init_logger();
|
|
6756
6757
|
init_portalLlm();
|
|
6757
6758
|
|
|
6759
|
+
// src/lib/memory/store/remoteTopics.ts
|
|
6760
|
+
init_logger();
|
|
6761
|
+
|
|
6758
6762
|
// src/lib/db/entities/types.ts
|
|
6759
6763
|
var ENTITY_KINDS = [
|
|
6760
6764
|
"person",
|
|
@@ -6811,58 +6815,337 @@ function parseTopics(value) {
|
|
|
6811
6815
|
return out;
|
|
6812
6816
|
}
|
|
6813
6817
|
|
|
6818
|
+
// src/lib/memory/store/topicCodec.ts
|
|
6819
|
+
var ciphertextPattern = /^enc:v\d+:[0-9a-f]+$/i;
|
|
6820
|
+
var topicHashPattern = /^[0-9a-f]{64}$/;
|
|
6821
|
+
var MAX_SEALED_TOPIC_NAME_BYTES = 1024;
|
|
6822
|
+
function normalizeTopicName(name) {
|
|
6823
|
+
return normalizeEntityName(name).normalize("NFC");
|
|
6824
|
+
}
|
|
6825
|
+
function sealedTopicNamesFit(json5) {
|
|
6826
|
+
return (entries(json5) ?? []).every(
|
|
6827
|
+
(entry) => !hashed(entry) || typeof entry.name !== "string" || entry.name.length <= MAX_SEALED_TOPIC_NAME_BYTES
|
|
6828
|
+
);
|
|
6829
|
+
}
|
|
6830
|
+
function record(value) {
|
|
6831
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6832
|
+
}
|
|
6833
|
+
function hashed(entry) {
|
|
6834
|
+
return record(entry) && typeof entry.name_hash === "string";
|
|
6835
|
+
}
|
|
6836
|
+
function entries(json5) {
|
|
6837
|
+
if (typeof json5 !== "string") return void 0;
|
|
6838
|
+
try {
|
|
6839
|
+
const parsed = JSON.parse(json5);
|
|
6840
|
+
return Array.isArray(parsed) ? parsed : void 0;
|
|
6841
|
+
} catch {
|
|
6842
|
+
return void 0;
|
|
6843
|
+
}
|
|
6844
|
+
}
|
|
6845
|
+
function cached(cache, key3, load) {
|
|
6846
|
+
let pending = cache.get(key3);
|
|
6847
|
+
if (!pending) {
|
|
6848
|
+
const loading = load();
|
|
6849
|
+
pending = loading;
|
|
6850
|
+
cache.set(key3, loading);
|
|
6851
|
+
loading.catch(() => {
|
|
6852
|
+
if (cache.get(key3) === loading) cache.delete(key3);
|
|
6853
|
+
});
|
|
6854
|
+
}
|
|
6855
|
+
return pending;
|
|
6856
|
+
}
|
|
6857
|
+
function createTopicCodec(cipher) {
|
|
6858
|
+
const hashes = /* @__PURE__ */ new Map();
|
|
6859
|
+
const opened = /* @__PURE__ */ new Map();
|
|
6860
|
+
const seals = /* @__PURE__ */ new Map();
|
|
6861
|
+
const legacyNames = /* @__PURE__ */ new Map();
|
|
6862
|
+
const hash = async (name) => {
|
|
6863
|
+
const normalized2 = normalizeTopicName(name);
|
|
6864
|
+
if (!normalized2) return null;
|
|
6865
|
+
return cached(hashes, normalized2, async () => {
|
|
6866
|
+
const digest = await cipher.hashTopic(normalized2);
|
|
6867
|
+
if (!topicHashPattern.test(digest))
|
|
6868
|
+
throw new Error("Topic hashing must return 64 lowercase hex characters");
|
|
6869
|
+
return digest;
|
|
6870
|
+
});
|
|
6871
|
+
};
|
|
6872
|
+
const seal = async (display) => {
|
|
6873
|
+
const nameHash = await hash(display);
|
|
6874
|
+
if (nameHash === null) return null;
|
|
6875
|
+
return cached(seals, display, async () => {
|
|
6876
|
+
const name = await cipher.encrypt(display);
|
|
6877
|
+
if (name === display || !ciphertextPattern.test(name))
|
|
6878
|
+
throw new Error(
|
|
6879
|
+
"Topic encryption must return SDK ciphertext; refusing to upload plaintext"
|
|
6880
|
+
);
|
|
6881
|
+
opened.set(name, Promise.resolve(display));
|
|
6882
|
+
return { name_hash: nameHash, name };
|
|
6883
|
+
});
|
|
6884
|
+
};
|
|
6885
|
+
const plain2 = (name) => {
|
|
6886
|
+
if (!ciphertextPattern.test(name)) return Promise.resolve(name);
|
|
6887
|
+
let pending = legacyNames.get(name);
|
|
6888
|
+
if (!pending) {
|
|
6889
|
+
pending = cipher.decrypt(name).catch(() => name);
|
|
6890
|
+
legacyNames.set(name, pending);
|
|
6891
|
+
}
|
|
6892
|
+
return pending;
|
|
6893
|
+
};
|
|
6894
|
+
const open = async ({ name, name_hash: nameHash }) => {
|
|
6895
|
+
if (nameHash === void 0) return plain2(name);
|
|
6896
|
+
if (typeof name !== "string" || typeof nameHash !== "string" || !topicHashPattern.test(nameHash) || !ciphertextPattern.test(name))
|
|
6897
|
+
throw new Error("Nearby returned a malformed topic name");
|
|
6898
|
+
const plaintext = await cached(opened, name, async () => {
|
|
6899
|
+
const value = await cipher.decrypt(name);
|
|
6900
|
+
if (value === name) throw new Error("Topic decryption failed");
|
|
6901
|
+
return value;
|
|
6902
|
+
});
|
|
6903
|
+
if (await hash(plaintext) !== nameHash) throw new Error("Topic name does not match its hash");
|
|
6904
|
+
if (!seals.has(plaintext)) seals.set(plaintext, Promise.resolve({ name_hash: nameHash, name }));
|
|
6905
|
+
return plaintext;
|
|
6906
|
+
};
|
|
6907
|
+
return {
|
|
6908
|
+
hash,
|
|
6909
|
+
seal,
|
|
6910
|
+
open,
|
|
6911
|
+
encodeTopics: async (json5) => {
|
|
6912
|
+
const list = entries(json5);
|
|
6913
|
+
if (!list) return json5;
|
|
6914
|
+
const sealed2 = await Promise.all(
|
|
6915
|
+
list.map(async (entry) => {
|
|
6916
|
+
if (!record(entry) || typeof entry.name !== "string") return null;
|
|
6917
|
+
const name = await seal(await plain2(entry.name));
|
|
6918
|
+
return name && { ...entry, name: name.name, name_hash: name.name_hash };
|
|
6919
|
+
})
|
|
6920
|
+
);
|
|
6921
|
+
return JSON.stringify(sealed2.filter((entry) => entry !== null));
|
|
6922
|
+
},
|
|
6923
|
+
decodeTopics: async (json5) => {
|
|
6924
|
+
const list = entries(json5);
|
|
6925
|
+
if (!list?.some(
|
|
6926
|
+
(entry) => hashed(entry) || record(entry) && typeof entry.name === "string" && ciphertextPattern.test(entry.name)
|
|
6927
|
+
))
|
|
6928
|
+
return json5;
|
|
6929
|
+
const decoded = await Promise.all(
|
|
6930
|
+
list.map(async (entry) => {
|
|
6931
|
+
if (!hashed(entry))
|
|
6932
|
+
return record(entry) && typeof entry.name === "string" ? { ...entry, name: await plain2(entry.name) } : entry;
|
|
6933
|
+
const { name_hash: nameHash, ...rest } = entry;
|
|
6934
|
+
return { ...rest, name: await open({ name: entry.name, name_hash: nameHash }) };
|
|
6935
|
+
})
|
|
6936
|
+
);
|
|
6937
|
+
return JSON.stringify(decoded);
|
|
6938
|
+
},
|
|
6939
|
+
isLegacy: (json5) => (entries(json5) ?? []).some(
|
|
6940
|
+
(entry) => record(entry) && typeof entry.name === "string" && !hashed(entry)
|
|
6941
|
+
),
|
|
6942
|
+
matchesLegacy: async (json5, names, hashes2) => {
|
|
6943
|
+
const list = typeof json5 === "string" ? entries(json5) ?? [] : [];
|
|
6944
|
+
if (list.some((entry) => hashed(entry) && hashes2.has(entry.name_hash))) return false;
|
|
6945
|
+
const legacy = await Promise.all(
|
|
6946
|
+
list.map(
|
|
6947
|
+
async (entry) => record(entry) && typeof entry.name === "string" && !hashed(entry) ? normalizeTopicName(await plain2(entry.name)) : null
|
|
6948
|
+
)
|
|
6949
|
+
);
|
|
6950
|
+
return legacy.some((name) => name !== null && names.has(name));
|
|
6951
|
+
},
|
|
6952
|
+
encodeCatalog: async (topic2) => {
|
|
6953
|
+
const sealed2 = await seal(normalizeTopicName(await plain2(topic2.name)));
|
|
6954
|
+
return sealed2 && { ...topic2, name: sealed2.name, name_hash: sealed2.name_hash };
|
|
6955
|
+
},
|
|
6956
|
+
decodeCatalog: async (item) => {
|
|
6957
|
+
const { name_hash: nameHash, ...rest } = item;
|
|
6958
|
+
return { ...rest, name: await open({ name: item.name, name_hash: nameHash }) };
|
|
6959
|
+
}
|
|
6960
|
+
};
|
|
6961
|
+
}
|
|
6962
|
+
|
|
6814
6963
|
// src/lib/memory/store/remoteTopics.ts
|
|
6964
|
+
var RETIRE_CONCURRENCY = 8;
|
|
6815
6965
|
function topic(value) {
|
|
6816
6966
|
const t = value;
|
|
6817
|
-
if (!t || typeof t.name !== "string" || !t.name || !Number.isSafeInteger(t.version) || t.version < 1 || typeof t.is_deleted !== "boolean" || typeof t.server_updated_at !== "string" || t.kind !== void 0 && typeof t.kind !== "string")
|
|
6967
|
+
if (!t || typeof t.name !== "string" || !t.name || t.name_hash !== void 0 && typeof t.name_hash !== "string" || !Number.isSafeInteger(t.version) || t.version < 1 || typeof t.is_deleted !== "boolean" || typeof t.server_updated_at !== "string" || t.kind !== void 0 && typeof t.kind !== "string")
|
|
6818
6968
|
throw new Error("Invalid nearby topic");
|
|
6819
6969
|
return t;
|
|
6820
6970
|
}
|
|
6821
|
-
function
|
|
6971
|
+
async function wireTopics(request, signal) {
|
|
6972
|
+
const out = [];
|
|
6973
|
+
let cursor;
|
|
6974
|
+
do {
|
|
6975
|
+
const page = await request(
|
|
6976
|
+
"/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
|
|
6977
|
+
{},
|
|
6978
|
+
signal
|
|
6979
|
+
);
|
|
6980
|
+
if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
|
|
6981
|
+
throw new Error("Invalid nearby topic page");
|
|
6982
|
+
out.push(...page.items.map(topic));
|
|
6983
|
+
cursor = page.next_cursor;
|
|
6984
|
+
} while (cursor);
|
|
6985
|
+
return out;
|
|
6986
|
+
}
|
|
6987
|
+
function hashesOf(items) {
|
|
6988
|
+
return new Set(items.flatMap((t) => t.name_hash === void 0 ? [] : [t.name_hash]));
|
|
6989
|
+
}
|
|
6990
|
+
async function sealedImport(request, codec, topics, signal) {
|
|
6991
|
+
let oversized = 0;
|
|
6992
|
+
for (let i = 0; i < topics.length; i += 50) {
|
|
6993
|
+
signal?.throwIfAborted();
|
|
6994
|
+
const sealed2 = (await Promise.all(topics.slice(i, i + 50).map((t) => codec.encodeCatalog(t)))).filter((t) => {
|
|
6995
|
+
if (t === null) return false;
|
|
6996
|
+
if (t.name.length <= MAX_SEALED_TOPIC_NAME_BYTES) return true;
|
|
6997
|
+
oversized++;
|
|
6998
|
+
return false;
|
|
6999
|
+
});
|
|
7000
|
+
if (sealed2.length)
|
|
7001
|
+
await request(
|
|
7002
|
+
"/topics/import",
|
|
7003
|
+
{ method: "POST", body: JSON.stringify({ topics: sealed2 }) },
|
|
7004
|
+
signal
|
|
7005
|
+
);
|
|
7006
|
+
}
|
|
7007
|
+
signal?.throwIfAborted();
|
|
7008
|
+
if (oversized)
|
|
7009
|
+
getLogger().warn(
|
|
7010
|
+
`[memory/remote] Skipped ${oversized} topic catalog entries whose sealed name exceeds ${MAX_SEALED_TOPIC_NAME_BYTES} bytes`
|
|
7011
|
+
);
|
|
7012
|
+
}
|
|
7013
|
+
function createRemoteTopicPersistence(request, codec) {
|
|
7014
|
+
let legacyOnly = /* @__PURE__ */ new Set();
|
|
6822
7015
|
return {
|
|
6823
7016
|
topics: async () => {
|
|
6824
|
-
const
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
7017
|
+
const items = await wireTopics(request);
|
|
7018
|
+
const hashed2 = hashesOf(items);
|
|
7019
|
+
const legacy = /* @__PURE__ */ new Set();
|
|
7020
|
+
const decoded = await Promise.all(
|
|
7021
|
+
items.map(async (item) => {
|
|
7022
|
+
const plain2 = await codec.decodeCatalog(item);
|
|
7023
|
+
const name = normalizeTopicName(plain2.name);
|
|
7024
|
+
if (item.name_hash === void 0) {
|
|
7025
|
+
const hash = await codec.hash(name);
|
|
7026
|
+
if (hash !== null && hashed2.has(hash)) return null;
|
|
7027
|
+
legacy.add(name);
|
|
7028
|
+
}
|
|
7029
|
+
return { ...plain2, name };
|
|
7030
|
+
})
|
|
7031
|
+
);
|
|
7032
|
+
legacyOnly = legacy;
|
|
7033
|
+
return decoded.filter((t) => t !== null);
|
|
6837
7034
|
},
|
|
6838
7035
|
putTopic: async (value, expectedVersion) => {
|
|
6839
7036
|
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
6840
7037
|
throw new Error("Expected topic version must be a nonnegative integer");
|
|
6841
|
-
|
|
7038
|
+
const sealed2 = await codec.encodeCatalog(value);
|
|
7039
|
+
if (!sealed2) throw new Error("Topic name must not be empty");
|
|
7040
|
+
const saved = topic(
|
|
6842
7041
|
await request("/topics", {
|
|
6843
7042
|
method: "PUT",
|
|
6844
|
-
body: JSON.stringify({
|
|
7043
|
+
body: JSON.stringify({
|
|
7044
|
+
topic: sealed2,
|
|
7045
|
+
expected_version: legacyOnly.has(normalizeTopicName(value.name)) ? 0 : expectedVersion
|
|
7046
|
+
})
|
|
6845
7047
|
})
|
|
6846
7048
|
);
|
|
7049
|
+
const decoded = await codec.decodeCatalog(saved);
|
|
7050
|
+
legacyOnly.delete(decoded.name);
|
|
7051
|
+
return decoded;
|
|
6847
7052
|
},
|
|
6848
|
-
importTopics:
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
7053
|
+
importTopics: (topics, signal) => sealedImport(
|
|
7054
|
+
request,
|
|
7055
|
+
codec,
|
|
7056
|
+
topics.map(({ name, kind }) => ({ name, ...kind !== void 0 && { kind } })),
|
|
7057
|
+
signal
|
|
7058
|
+
)
|
|
7059
|
+
};
|
|
7060
|
+
}
|
|
7061
|
+
async function retireLegacyTopics(request, codec, topics, imported, signal) {
|
|
7062
|
+
const failures = [];
|
|
7063
|
+
const put = async (topic2, expectedVersion) => {
|
|
7064
|
+
try {
|
|
7065
|
+
await request(
|
|
7066
|
+
"/topics",
|
|
7067
|
+
{ method: "PUT", body: JSON.stringify({ topic: topic2, expected_version: expectedVersion }) },
|
|
7068
|
+
signal
|
|
7069
|
+
);
|
|
7070
|
+
return "saved";
|
|
7071
|
+
} catch (error) {
|
|
7072
|
+
if (signal?.aborted) throw error;
|
|
7073
|
+
if (error instanceof RemoteMemoryError && error.status === 409) return "conflict";
|
|
7074
|
+
failures.push(error);
|
|
7075
|
+
return "failed";
|
|
7076
|
+
}
|
|
7077
|
+
};
|
|
7078
|
+
const retire = (item) => put(
|
|
7079
|
+
{ name: item.name, ...item.kind !== void 0 && { kind: item.kind }, is_deleted: true },
|
|
7080
|
+
item.version
|
|
7081
|
+
);
|
|
7082
|
+
const changed = [];
|
|
7083
|
+
let next = 0;
|
|
7084
|
+
const worker = async () => {
|
|
7085
|
+
while (next < topics.length) {
|
|
6860
7086
|
signal?.throwIfAborted();
|
|
7087
|
+
const item = topics[next++];
|
|
7088
|
+
if (await retire(item) === "conflict") changed.push(item);
|
|
6861
7089
|
}
|
|
6862
7090
|
};
|
|
7091
|
+
await Promise.all(
|
|
7092
|
+
Array.from({ length: Math.min(RETIRE_CONCURRENCY, topics.length) }, () => worker())
|
|
7093
|
+
);
|
|
7094
|
+
if (changed.length) {
|
|
7095
|
+
const current = await wireTopics(request, signal);
|
|
7096
|
+
for (const stale of changed) {
|
|
7097
|
+
const legacy = current.find((t) => t.name_hash === void 0 && t.name === stale.name);
|
|
7098
|
+
if (!legacy || legacy.is_deleted) continue;
|
|
7099
|
+
const hash = await codec.hash(await codec.open(legacy));
|
|
7100
|
+
const copy = current.find((t) => t.name_hash !== void 0 && t.name_hash === hash);
|
|
7101
|
+
if (!copy || hash === null) continue;
|
|
7102
|
+
const newer = imported.has(hash) || Date.parse(legacy.server_updated_at) > Date.parse(copy.server_updated_at);
|
|
7103
|
+
if (newer && (copy.is_deleted || legacy.kind !== copy.kind)) {
|
|
7104
|
+
const sealed2 = await codec.encodeCatalog({
|
|
7105
|
+
name: legacy.name,
|
|
7106
|
+
...legacy.kind !== void 0 && { kind: legacy.kind },
|
|
7107
|
+
is_deleted: false
|
|
7108
|
+
});
|
|
7109
|
+
if (!sealed2 || await put(sealed2, copy.version) !== "saved") continue;
|
|
7110
|
+
}
|
|
7111
|
+
await retire(legacy);
|
|
7112
|
+
}
|
|
7113
|
+
}
|
|
7114
|
+
if (failures.length)
|
|
7115
|
+
getLogger().warn(
|
|
7116
|
+
`[memory/remote] Could not retire ${failures.length} upgraded topic catalog entries:`,
|
|
7117
|
+
failures[0]
|
|
7118
|
+
);
|
|
7119
|
+
}
|
|
7120
|
+
async function upgradeLegacyTopicCatalog(request, codec, signal) {
|
|
7121
|
+
const items = await wireTopics(request, signal);
|
|
7122
|
+
const hashed2 = hashesOf(items);
|
|
7123
|
+
const hashes = await Promise.all(
|
|
7124
|
+
items.map(
|
|
7125
|
+
async (item) => item.name_hash === void 0 ? codec.hash(await codec.open(item)) : null
|
|
7126
|
+
)
|
|
7127
|
+
);
|
|
7128
|
+
const sources = /* @__PURE__ */ new Map();
|
|
7129
|
+
const live2 = [];
|
|
7130
|
+
items.forEach((item, i) => {
|
|
7131
|
+
const hash = hashes[i];
|
|
7132
|
+
if (hash === null) return;
|
|
7133
|
+
if (!item.is_deleted) live2.push(item);
|
|
7134
|
+
if (hashed2.has(hash)) return;
|
|
7135
|
+
const source = sources.get(hash);
|
|
7136
|
+
if (!source || source.is_deleted && !item.is_deleted) sources.set(hash, item);
|
|
7137
|
+
});
|
|
7138
|
+
const legacy = [...sources.values()].map((item) => ({
|
|
7139
|
+
name: item.name,
|
|
7140
|
+
...item.kind !== void 0 && { kind: item.kind },
|
|
7141
|
+
...item.is_deleted && { is_deleted: true }
|
|
7142
|
+
}));
|
|
7143
|
+
await sealedImport(request, codec, legacy, signal);
|
|
7144
|
+
await retireLegacyTopics(request, codec, live2, new Set(sources.keys()), signal);
|
|
7145
|
+
return legacy.length;
|
|
6863
7146
|
}
|
|
6864
7147
|
async function createRemoteTopic(persistence, name) {
|
|
6865
|
-
const canonical =
|
|
7148
|
+
const canonical = normalizeTopicName(name);
|
|
6866
7149
|
if (!canonical) return null;
|
|
6867
7150
|
const existing = (await persistence.topics()).find((t) => t.name === canonical);
|
|
6868
7151
|
if (existing && !existing.is_deleted) return canonical;
|
|
@@ -6951,7 +7234,10 @@ var RemoteMemoryError = class extends Error {
|
|
|
6951
7234
|
this.name = "RemoteMemoryError";
|
|
6952
7235
|
}
|
|
6953
7236
|
};
|
|
6954
|
-
var
|
|
7237
|
+
var TOPIC_UPGRADE_PROCESSOR = "topic-hash-v1";
|
|
7238
|
+
var TOPIC_UPGRADE_PAGE = 50;
|
|
7239
|
+
var LEGACY_TOPIC_CURSOR = "legacy-topics:";
|
|
7240
|
+
var LEGACY_TOPIC_RECHECK_MS = 6e4;
|
|
6955
7241
|
var memoryFields = {
|
|
6956
7242
|
memory_id: true,
|
|
6957
7243
|
content: true,
|
|
@@ -7011,7 +7297,8 @@ var queryFields = [
|
|
|
7011
7297
|
"fact_types",
|
|
7012
7298
|
"visibility",
|
|
7013
7299
|
"memory_ids",
|
|
7014
|
-
"
|
|
7300
|
+
"topic_hashes",
|
|
7301
|
+
"topics_legacy",
|
|
7015
7302
|
"updated_after",
|
|
7016
7303
|
"topics_due",
|
|
7017
7304
|
"topics_extracted",
|
|
@@ -7021,11 +7308,17 @@ var queryFields = [
|
|
|
7021
7308
|
"limit",
|
|
7022
7309
|
"include_embeddings"
|
|
7023
7310
|
];
|
|
7024
|
-
function
|
|
7311
|
+
function isVersionConflict(error) {
|
|
7312
|
+
return error instanceof RemoteMemoryError && error.code === "version_conflict";
|
|
7313
|
+
}
|
|
7314
|
+
function isRejectedRow(error) {
|
|
7315
|
+
return error instanceof RemoteMemoryError && error.status === 400;
|
|
7316
|
+
}
|
|
7317
|
+
function record2(value) {
|
|
7025
7318
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7026
7319
|
}
|
|
7027
7320
|
function memoryRecord(value) {
|
|
7028
|
-
if (!
|
|
7321
|
+
if (!record2(value) || !record2(value.memory) || typeof value.memory.memory_id !== "string" || typeof value.memory.content !== "string" || typeof value.memory.scope !== "string" || typeof value.memory.created_at !== "number" || typeof value.memory.updated_at !== "number" || typeof value.memory.is_deleted !== "boolean" || !Number.isSafeInteger(value.version) || value.version < 1 || typeof value.server_updated_at !== "string" || value.score !== void 0 && (typeof value.score !== "number" || !Number.isFinite(value.score))) {
|
|
7029
7322
|
throw new Error("Invalid nearby private-memory response");
|
|
7030
7323
|
}
|
|
7031
7324
|
return value;
|
|
@@ -7105,14 +7398,14 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
|
|
|
7105
7398
|
const body = await response.json().catch(() => null);
|
|
7106
7399
|
const retryAfter = parseRetryAfterMs(response.headers.get("Retry-After"));
|
|
7107
7400
|
const error = new RemoteMemoryError(
|
|
7108
|
-
|
|
7401
|
+
record2(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
|
|
7109
7402
|
response.status,
|
|
7110
|
-
|
|
7403
|
+
record2(body) && typeof body.code === "string" ? body.code : void 0,
|
|
7111
7404
|
retryAfter ?? void 0,
|
|
7112
|
-
|
|
7405
|
+
record2(body) && typeof body.rate_limit_bucket === "string" ? body.rate_limit_bucket : void 0
|
|
7113
7406
|
);
|
|
7114
7407
|
if (response.status === 429 && retryAfter !== null && retryAfter > 0 && (!error.code || error.code === "rate_limited")) {
|
|
7115
|
-
const bucket = error.rateLimitBucket && budgets.includes(error.rateLimitBucket) ? error.rateLimitBucket :
|
|
7408
|
+
const bucket = error.rateLimitBucket && budgets.includes(error.rateLimitBucket) ? error.rateLimitBucket : record2(body) && (body.limit_scope === "account" || body.limit_scope === "ip") && !error.rateLimitBucket ? "*" : route;
|
|
7116
7409
|
cooldowns.set(bucket, { until: Date.now() + retryAfter, error });
|
|
7117
7410
|
}
|
|
7118
7411
|
throw error;
|
|
@@ -7135,7 +7428,7 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7135
7428
|
throw new Error("A canonical keyId is required");
|
|
7136
7429
|
const request = createNearbyRequest(options);
|
|
7137
7430
|
const account = await request("/account", {}, options.signal);
|
|
7138
|
-
if (!
|
|
7431
|
+
if (!record2(account) || account.state !== "active") {
|
|
7139
7432
|
throw new RemoteMemoryError(
|
|
7140
7433
|
"Complete and verify migration before using remote memories",
|
|
7141
7434
|
409,
|
|
@@ -7149,6 +7442,25 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7149
7442
|
"key_mismatch"
|
|
7150
7443
|
);
|
|
7151
7444
|
}
|
|
7445
|
+
const codec = createTopicCodec(options);
|
|
7446
|
+
let legacyTopicRows = typeof account.legacy_topic_memories === "number" && account.legacy_topic_memories > 0;
|
|
7447
|
+
if (typeof account.legacy_topic_catalog === "number" && account.legacy_topic_catalog > 0)
|
|
7448
|
+
void upgradeLegacyTopicCatalog(request, codec, options.signal).catch((error) => {
|
|
7449
|
+
if (!options.signal?.aborted)
|
|
7450
|
+
getLogger().warn("[memory/remote] Topic catalog upgrade failed:", error);
|
|
7451
|
+
});
|
|
7452
|
+
let legacyCheckedAt = Date.now();
|
|
7453
|
+
let legacyCheck;
|
|
7454
|
+
const recheckLegacyTopicRows = () => {
|
|
7455
|
+
if (legacyCheck || Date.now() - legacyCheckedAt < LEGACY_TOPIC_RECHECK_MS) return;
|
|
7456
|
+
legacyCheckedAt = Date.now();
|
|
7457
|
+
legacyCheck = request("/account", {}, options.signal).then((current) => {
|
|
7458
|
+
if (record2(current) && current.legacy_topic_memories === 0) legacyTopicRows = false;
|
|
7459
|
+
}).catch(() => {
|
|
7460
|
+
}).finally(() => {
|
|
7461
|
+
legacyCheck = void 0;
|
|
7462
|
+
});
|
|
7463
|
+
};
|
|
7152
7464
|
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
7153
7465
|
const decode = async (value) => {
|
|
7154
7466
|
const item = memoryRecord(value);
|
|
@@ -7166,6 +7478,9 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7166
7478
|
content: item.memory.is_deleted && item.memory.content === "" ? "" : await decrypt(item.memory.content),
|
|
7167
7479
|
...item.memory.kind_value !== void 0 && {
|
|
7168
7480
|
kind_value: await decrypt(item.memory.kind_value)
|
|
7481
|
+
},
|
|
7482
|
+
...item.memory.topics !== void 0 && {
|
|
7483
|
+
topics: await codec.decodeTopics(item.memory.topics)
|
|
7169
7484
|
}
|
|
7170
7485
|
}
|
|
7171
7486
|
};
|
|
@@ -7177,8 +7492,10 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7177
7492
|
version: item.version,
|
|
7178
7493
|
content: decoded.memory.content,
|
|
7179
7494
|
kindValue: decoded.memory.kind_value,
|
|
7495
|
+
topics: decoded.memory.topics,
|
|
7180
7496
|
encryptedContent: item.memory.content,
|
|
7181
|
-
encryptedKindValue: item.memory.kind_value
|
|
7497
|
+
encryptedKindValue: item.memory.kind_value,
|
|
7498
|
+
encryptedTopics: item.memory.topics
|
|
7182
7499
|
});
|
|
7183
7500
|
return decoded;
|
|
7184
7501
|
};
|
|
@@ -7200,7 +7517,7 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7200
7517
|
};
|
|
7201
7518
|
const decodeCommitted = async (value, write) => {
|
|
7202
7519
|
const item = memoryRecord(value);
|
|
7203
|
-
if (item.memory.memory_id !== write.body.memory.memory_id || item.memory.content !== write.body.memory.content || item.memory.kind_value !== write.body.memory.kind_value)
|
|
7520
|
+
if (item.memory.memory_id !== write.body.memory.memory_id || item.memory.content !== write.body.memory.content || item.memory.kind_value !== write.body.memory.kind_value || item.memory.topics !== write.body.memory.topics)
|
|
7204
7521
|
return decode(item);
|
|
7205
7522
|
return remember(
|
|
7206
7523
|
{
|
|
@@ -7208,7 +7525,8 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7208
7525
|
memory: {
|
|
7209
7526
|
...item.memory,
|
|
7210
7527
|
content: write.content,
|
|
7211
|
-
...write.kindValue !== void 0 && { kind_value: write.kindValue }
|
|
7528
|
+
...write.kindValue !== void 0 && { kind_value: write.kindValue },
|
|
7529
|
+
...write.topics !== void 0 && { topics: write.topics }
|
|
7212
7530
|
}
|
|
7213
7531
|
},
|
|
7214
7532
|
item
|
|
@@ -7260,13 +7578,21 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7260
7578
|
const reusableContent = snapshot?.encryptedContent ?? existing?.memory.content;
|
|
7261
7579
|
const content = reusableContent && (snapshot?.content ?? decoded?.memory.content) === memory.content ? reusableContent : await encryptField2(memory.content);
|
|
7262
7580
|
const kindValue = memory.kind_value === void 0 ? void 0 : (snapshot?.kindValue ?? decoded?.memory.kind_value) === memory.kind_value ? snapshot?.encryptedKindValue ?? existing.memory.kind_value : await encryptField2(memory.kind_value);
|
|
7581
|
+
const wireTopics2 = snapshot ? snapshot.encryptedTopics : existing?.memory.topics;
|
|
7582
|
+
const topics = memory.topics === void 0 ? void 0 : (snapshot?.topics ?? decoded?.memory.topics) === memory.topics && wireTopics2 !== void 0 && !codec.isLegacy(wireTopics2) ? wireTopics2 : await codec.encodeTopics(memory.topics);
|
|
7263
7583
|
return {
|
|
7264
7584
|
body: {
|
|
7265
7585
|
expected_version: expectedVersion,
|
|
7266
|
-
memory: {
|
|
7586
|
+
memory: {
|
|
7587
|
+
...memory,
|
|
7588
|
+
content,
|
|
7589
|
+
...kindValue !== void 0 && { kind_value: kindValue },
|
|
7590
|
+
...topics !== void 0 && { topics }
|
|
7591
|
+
}
|
|
7267
7592
|
},
|
|
7268
7593
|
content: memory.content,
|
|
7269
|
-
kindValue: memory.kind_value
|
|
7594
|
+
kindValue: memory.kind_value,
|
|
7595
|
+
topics: memory.topics
|
|
7270
7596
|
};
|
|
7271
7597
|
};
|
|
7272
7598
|
const fetchCandidates = async (embedding2, candidateOptions, withCounts) => {
|
|
@@ -7315,32 +7641,72 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7315
7641
|
},
|
|
7316
7642
|
candidateOptions.signal
|
|
7317
7643
|
);
|
|
7318
|
-
if (!
|
|
7644
|
+
if (!record2(result) || !Array.isArray(result.items))
|
|
7319
7645
|
throw new Error("Invalid nearby candidate response");
|
|
7320
7646
|
return result;
|
|
7321
7647
|
};
|
|
7322
7648
|
const fetchQueryPage = async (queryOptions) => {
|
|
7323
|
-
const { signal, ...
|
|
7324
|
-
if (
|
|
7649
|
+
const { signal, topics: names, ...wire2 } = queryOptions;
|
|
7650
|
+
if (wire2.limit !== void 0 && (!Number.isInteger(wire2.limit) || wire2.limit < 1 || wire2.limit > 200))
|
|
7325
7651
|
throw new Error("Page limit must be 1\u2013200");
|
|
7326
7652
|
for (const [key3, max] of queryListLimits) {
|
|
7327
|
-
const values =
|
|
7653
|
+
const values = queryOptions[key3];
|
|
7328
7654
|
if (values && values.length > max)
|
|
7329
7655
|
throw new Error(`Query ${key3} accepts at most ${max} entries (got ${values.length})`);
|
|
7330
7656
|
}
|
|
7657
|
+
const body = wire2;
|
|
7658
|
+
if (names === void 0) return postQuery(body, signal);
|
|
7659
|
+
const hashes = [
|
|
7660
|
+
...new Set(
|
|
7661
|
+
(await Promise.all(names.map((name) => codec.hash(name)))).filter((h) => h !== null)
|
|
7662
|
+
)
|
|
7663
|
+
];
|
|
7664
|
+
if (names.length > 0 && hashes.length === 0) return { items: [] };
|
|
7665
|
+
if (hashes.length > 0 && wire2.cursor?.startsWith(LEGACY_TOPIC_CURSOR)) {
|
|
7666
|
+
const page2 = await postQuery(
|
|
7667
|
+
{
|
|
7668
|
+
...wire2,
|
|
7669
|
+
cursor: wire2.cursor.slice(LEGACY_TOPIC_CURSOR.length) || void 0,
|
|
7670
|
+
topics_legacy: true
|
|
7671
|
+
},
|
|
7672
|
+
signal
|
|
7673
|
+
);
|
|
7674
|
+
const wanted = new Set(names.map(normalizeTopicName));
|
|
7675
|
+
const hashed2 = new Set(hashes);
|
|
7676
|
+
const matches = await Promise.all(
|
|
7677
|
+
page2.items.map(
|
|
7678
|
+
(item) => codec.matchesLegacy(
|
|
7679
|
+
record2(item) && record2(item.memory) ? item.memory.topics : void 0,
|
|
7680
|
+
wanted,
|
|
7681
|
+
hashed2
|
|
7682
|
+
)
|
|
7683
|
+
)
|
|
7684
|
+
);
|
|
7685
|
+
return {
|
|
7686
|
+
...page2,
|
|
7687
|
+
items: page2.items.filter((_, i) => matches[i]),
|
|
7688
|
+
next_cursor: page2.next_cursor === void 0 ? void 0 : LEGACY_TOPIC_CURSOR + page2.next_cursor
|
|
7689
|
+
};
|
|
7690
|
+
}
|
|
7691
|
+
const page = await postQuery({ ...body, topic_hashes: hashes }, signal);
|
|
7692
|
+
if (hashes.length === 0 || page.next_cursor !== void 0 || !legacyTopicRows) return page;
|
|
7693
|
+
recheckLegacyTopicRows();
|
|
7694
|
+
return { ...page, next_cursor: LEGACY_TOPIC_CURSOR };
|
|
7695
|
+
};
|
|
7696
|
+
const postQuery = async (body, signal) => {
|
|
7331
7697
|
const page = await request(
|
|
7332
7698
|
"/memories/query",
|
|
7333
7699
|
{
|
|
7334
7700
|
method: "POST",
|
|
7335
7701
|
body: JSON.stringify(
|
|
7336
7702
|
Object.fromEntries(
|
|
7337
|
-
queryFields.filter((key3) =>
|
|
7703
|
+
queryFields.filter((key3) => body[key3] !== void 0).map((key3) => [key3, body[key3]])
|
|
7338
7704
|
)
|
|
7339
7705
|
)
|
|
7340
7706
|
},
|
|
7341
7707
|
signal
|
|
7342
7708
|
);
|
|
7343
|
-
if (!
|
|
7709
|
+
if (!record2(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string" || page.changes_cursor !== void 0 && typeof page.changes_cursor !== "string")
|
|
7344
7710
|
throw new Error("Invalid nearby private-memory page");
|
|
7345
7711
|
return page;
|
|
7346
7712
|
};
|
|
@@ -7354,13 +7720,13 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7354
7720
|
unavailable_count: result.unavailable_count
|
|
7355
7721
|
};
|
|
7356
7722
|
};
|
|
7357
|
-
|
|
7358
|
-
...createRemoteTopicPersistence(request),
|
|
7723
|
+
const persistence = {
|
|
7724
|
+
...createRemoteTopicPersistence(request, codec),
|
|
7359
7725
|
...createRemoteWorkPersistence(request),
|
|
7360
7726
|
supportsRealtimeChanges: account.realtime_changes === true,
|
|
7361
7727
|
counts: async () => {
|
|
7362
7728
|
const result = await request("/counts", {});
|
|
7363
|
-
if (!
|
|
7729
|
+
if (!record2(result) || ["live", "archived", "quarantined"].some(
|
|
7364
7730
|
(key3) => !Number.isSafeInteger(result[key3]) || result[key3] < 0
|
|
7365
7731
|
))
|
|
7366
7732
|
throw new Error("Invalid nearby memory counts");
|
|
@@ -7377,8 +7743,8 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7377
7743
|
method: "POST",
|
|
7378
7744
|
body: JSON.stringify({ ...window2, limit })
|
|
7379
7745
|
});
|
|
7380
|
-
if (!
|
|
7381
|
-
(item) => !
|
|
7746
|
+
if (!record2(result) || !Array.isArray(result.items) || result.items.some(
|
|
7747
|
+
(item) => !record2(item) || typeof item.memory_id !== "string" || !item.memory_id || typeof item.score !== "number" || !Number.isFinite(item.score) || item.score <= 0 || item.score > 1
|
|
7382
7748
|
))
|
|
7383
7749
|
throw new Error("Invalid nearby temporal candidates");
|
|
7384
7750
|
return result.items.map((item) => item.memory_id);
|
|
@@ -7409,7 +7775,7 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7409
7775
|
if (query[key3] !== void 0) params.set(key3, String(query[key3]));
|
|
7410
7776
|
}
|
|
7411
7777
|
const page = await request("/memories?" + params.toString(), {}, signal);
|
|
7412
|
-
if (!
|
|
7778
|
+
if (!record2(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string") {
|
|
7413
7779
|
throw new Error("Invalid nearby private-memory page");
|
|
7414
7780
|
}
|
|
7415
7781
|
return {
|
|
@@ -7449,7 +7815,7 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7449
7815
|
},
|
|
7450
7816
|
signal
|
|
7451
7817
|
);
|
|
7452
|
-
if (!
|
|
7818
|
+
if (!record2(result) || !Array.isArray(result.items) || result.items.length !== prepared.length)
|
|
7453
7819
|
throw new Error("Invalid nearby batch response");
|
|
7454
7820
|
return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
|
|
7455
7821
|
},
|
|
@@ -7464,20 +7830,87 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
7464
7830
|
queryMetadata: async (queryOptions = {}) => {
|
|
7465
7831
|
const page = await fetchQueryPage(queryOptions);
|
|
7466
7832
|
return {
|
|
7467
|
-
items:
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7833
|
+
items: await Promise.all(
|
|
7834
|
+
page.items.map(async (item) => {
|
|
7835
|
+
const {
|
|
7836
|
+
memory: { content: _content, kind_value: _kindValue, topics, ...memory },
|
|
7837
|
+
version,
|
|
7838
|
+
server_updated_at
|
|
7839
|
+
} = memoryRecord(item);
|
|
7840
|
+
const plain2 = topics === void 0 ? void 0 : await codec.decodeTopics(topics).catch(() => null);
|
|
7841
|
+
return {
|
|
7842
|
+
memory: { ...memory, ...typeof plain2 === "string" && { topics: plain2 } },
|
|
7843
|
+
version,
|
|
7844
|
+
server_updated_at
|
|
7845
|
+
};
|
|
7846
|
+
})
|
|
7847
|
+
),
|
|
7475
7848
|
...page.next_cursor !== void 0 && { next_cursor: page.next_cursor }
|
|
7476
7849
|
};
|
|
7477
7850
|
},
|
|
7478
7851
|
candidateSet,
|
|
7479
7852
|
candidates: async (embedding2, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding2, candidateOptions, false)).items)
|
|
7480
7853
|
};
|
|
7854
|
+
let rejectedRows = 0;
|
|
7855
|
+
const rewriteLegacyTopics = async (records, token) => {
|
|
7856
|
+
const write = (batch) => persistence.putMany(
|
|
7857
|
+
batch.map((item) => ({ memory: item.memory, expectedVersion: item })),
|
|
7858
|
+
options.signal,
|
|
7859
|
+
token
|
|
7860
|
+
);
|
|
7861
|
+
try {
|
|
7862
|
+
await write(records);
|
|
7863
|
+
return true;
|
|
7864
|
+
} catch (error) {
|
|
7865
|
+
if (!isVersionConflict(error) && !isRejectedRow(error)) throw error;
|
|
7866
|
+
if (records.length === 1) {
|
|
7867
|
+
if (isRejectedRow(error)) rejectedRows++;
|
|
7868
|
+
return false;
|
|
7869
|
+
}
|
|
7870
|
+
let complete = true;
|
|
7871
|
+
for (const item of records)
|
|
7872
|
+
await write([item]).catch((rowError) => {
|
|
7873
|
+
if (isRejectedRow(rowError)) rejectedRows++;
|
|
7874
|
+
else if (!isVersionConflict(rowError)) throw rowError;
|
|
7875
|
+
complete = false;
|
|
7876
|
+
});
|
|
7877
|
+
return complete;
|
|
7878
|
+
}
|
|
7879
|
+
};
|
|
7880
|
+
const upgradeLegacyTopics = () => withRemoteWorkLease(persistence, "topics", TOPIC_UPGRADE_PROCESSOR, async (token, lease) => {
|
|
7881
|
+
let cursor;
|
|
7882
|
+
let complete = true;
|
|
7883
|
+
do {
|
|
7884
|
+
options.signal?.throwIfAborted();
|
|
7885
|
+
if (lease.aborted) return false;
|
|
7886
|
+
const page = await fetchQueryPage({
|
|
7887
|
+
topics_legacy: true,
|
|
7888
|
+
include_archived: true,
|
|
7889
|
+
include_quarantined: true,
|
|
7890
|
+
include_superseded: true,
|
|
7891
|
+
limit: TOPIC_UPGRADE_PAGE,
|
|
7892
|
+
...cursor !== void 0 && { cursor },
|
|
7893
|
+
signal: options.signal
|
|
7894
|
+
});
|
|
7895
|
+
const { items } = await decodeAll(page.items);
|
|
7896
|
+
const legacy = items.filter((item) => codec.isLegacy(snapshots.get(item)?.encryptedTopics));
|
|
7897
|
+
if (legacy.length && !await rewriteLegacyTopics(legacy, token)) complete = false;
|
|
7898
|
+
cursor = page.next_cursor;
|
|
7899
|
+
} while (cursor);
|
|
7900
|
+
if (rejectedRows)
|
|
7901
|
+
getLogger().warn(
|
|
7902
|
+
`[memory/remote] Nearby rejected ${rejectedRows} rows during the topic upgrade; they keep legacy topics`
|
|
7903
|
+
);
|
|
7904
|
+
return complete;
|
|
7905
|
+
});
|
|
7906
|
+
if (legacyTopicRows)
|
|
7907
|
+
void upgradeLegacyTopics().then((complete) => {
|
|
7908
|
+
if (complete) legacyTopicRows = false;
|
|
7909
|
+
}).catch((error) => {
|
|
7910
|
+
if (!options.signal?.aborted)
|
|
7911
|
+
getLogger().warn("[memory/remote] Topic upgrade failed:", error);
|
|
7912
|
+
});
|
|
7913
|
+
return persistence;
|
|
7481
7914
|
}
|
|
7482
7915
|
|
|
7483
7916
|
// src/lib/chat/inbox.ts
|
|
@@ -7962,9 +8395,9 @@ function toResponsesFormat(tool) {
|
|
|
7962
8395
|
function getCachedServerTools() {
|
|
7963
8396
|
if (typeof localStorage === "undefined") return null;
|
|
7964
8397
|
try {
|
|
7965
|
-
const
|
|
7966
|
-
if (!
|
|
7967
|
-
const parsed = JSON.parse(
|
|
8398
|
+
const cached2 = localStorage.getItem(SERVER_TOOLS_CACHE_KEY);
|
|
8399
|
+
if (!cached2) return null;
|
|
8400
|
+
const parsed = JSON.parse(cached2);
|
|
7968
8401
|
if (parsed.version !== CACHE_VERSION) {
|
|
7969
8402
|
removeLocalStorageCache();
|
|
7970
8403
|
return null;
|
|
@@ -8008,8 +8441,8 @@ function clearServerToolsCache(cache = localStorageToolsCache) {
|
|
|
8008
8441
|
return cache.clear?.();
|
|
8009
8442
|
}
|
|
8010
8443
|
function getToolsChecksum2(cache = localStorageToolsCache) {
|
|
8011
|
-
const
|
|
8012
|
-
return
|
|
8444
|
+
const cached2 = cache.get();
|
|
8445
|
+
return cached2 instanceof Promise ? cached2.then((c) => c?.checksum) : cached2?.checksum;
|
|
8013
8446
|
}
|
|
8014
8447
|
function shouldRefreshTools(responseChecksum, cache = localStorageToolsCache) {
|
|
8015
8448
|
if (!responseChecksum) {
|
|
@@ -8072,33 +8505,33 @@ async function getServerTools(options) {
|
|
|
8072
8505
|
} catch (error) {
|
|
8073
8506
|
getLogger().warn("[serverTools] Cache read failed; falling through to server fetch:", error);
|
|
8074
8507
|
}
|
|
8075
|
-
const
|
|
8076
|
-
const cacheValid = !isCacheExpired(
|
|
8077
|
-
if (
|
|
8078
|
-
return
|
|
8508
|
+
const cached2 = rawCached && rawCached.version === CACHE_VERSION ? rawCached : null;
|
|
8509
|
+
const cacheValid = !isCacheExpired(cached2, cacheExpirationMs);
|
|
8510
|
+
if (cached2 && cacheValid && !forceRefresh) {
|
|
8511
|
+
return cached2.tools;
|
|
8079
8512
|
}
|
|
8080
8513
|
try {
|
|
8081
8514
|
const { BASE_URL: BASE_URL2 } = await Promise.resolve().then(() => (init_clientConfig(), clientConfig_exports));
|
|
8082
8515
|
const effectiveBaseUrl = baseUrl ?? BASE_URL2;
|
|
8083
|
-
const validator =
|
|
8516
|
+
const validator = cached2 && !forceRefresh ? cached2.etag : void 0;
|
|
8084
8517
|
let authHeaders;
|
|
8085
8518
|
if (apiKey) {
|
|
8086
8519
|
authHeaders = { "X-API-Key": apiKey };
|
|
8087
8520
|
} else {
|
|
8088
8521
|
if (!getToken) {
|
|
8089
8522
|
getLogger().warn("[serverTools] No auth method available for fetching tools");
|
|
8090
|
-
return
|
|
8523
|
+
return cached2?.tools ?? [];
|
|
8091
8524
|
}
|
|
8092
8525
|
const token = await getToken();
|
|
8093
8526
|
if (!token) {
|
|
8094
8527
|
getLogger().warn("[serverTools] No auth token available for fetching tools");
|
|
8095
|
-
return
|
|
8528
|
+
return cached2?.tools ?? [];
|
|
8096
8529
|
}
|
|
8097
8530
|
authHeaders = { Authorization: `Bearer ${token}` };
|
|
8098
8531
|
}
|
|
8099
8532
|
const result = await fetchServerToolsFromApi(effectiveBaseUrl, authHeaders, validator);
|
|
8100
8533
|
if (result.notModified) {
|
|
8101
|
-
const confirmed =
|
|
8534
|
+
const confirmed = cached2;
|
|
8102
8535
|
await persistCache({ ...confirmed, timestamp: Date.now() });
|
|
8103
8536
|
return confirmed.tools;
|
|
8104
8537
|
}
|
|
@@ -8106,9 +8539,9 @@ async function getServerTools(options) {
|
|
|
8106
8539
|
return result.tools;
|
|
8107
8540
|
} catch (error) {
|
|
8108
8541
|
getLogger().error("[serverTools] Failed to fetch server tools:", error);
|
|
8109
|
-
if (
|
|
8542
|
+
if (cached2?.tools) {
|
|
8110
8543
|
getLogger().warn("[serverTools] Using stale cached tools due to fetch error");
|
|
8111
|
-
return
|
|
8544
|
+
return cached2.tools;
|
|
8112
8545
|
}
|
|
8113
8546
|
return [];
|
|
8114
8547
|
}
|
|
@@ -9198,13 +9631,13 @@ function extractParamGroups(content) {
|
|
|
9198
9631
|
}
|
|
9199
9632
|
function mergeXaiInlineParameterTags(content, toolCalls) {
|
|
9200
9633
|
if (!content || !content.includes(PARAM_MARKER)) return content;
|
|
9201
|
-
const
|
|
9202
|
-
if (
|
|
9634
|
+
const entries2 = Array.from(toolCalls.values());
|
|
9635
|
+
if (entries2.length === 0) return content;
|
|
9203
9636
|
const groups = extractParamGroups(content);
|
|
9204
9637
|
if (groups.length === 0) return content;
|
|
9205
|
-
const pairCount = Math.min(groups.length,
|
|
9638
|
+
const pairCount = Math.min(groups.length, entries2.length);
|
|
9206
9639
|
for (let i = 0; i < pairCount; i++) {
|
|
9207
|
-
const target =
|
|
9640
|
+
const target = entries2[i];
|
|
9208
9641
|
const params = groups[i];
|
|
9209
9642
|
if (!target || !params) continue;
|
|
9210
9643
|
let args = {};
|
|
@@ -12668,21 +13101,21 @@ function contextFields(context) {
|
|
|
12668
13101
|
);
|
|
12669
13102
|
}
|
|
12670
13103
|
function conversationContext(data) {
|
|
12671
|
-
const
|
|
12672
|
-
return
|
|
13104
|
+
const entries2 = Object.entries(data).filter(([field10]) => field10.startsWith(CONTEXT_FIELD_PREFIX)).map(([field10, value]) => [field10.slice(CONTEXT_FIELD_PREFIX.length), value]);
|
|
13105
|
+
return entries2.length > 0 ? plain(Object.fromEntries(entries2)) : void 0;
|
|
12673
13106
|
}
|
|
12674
|
-
function toConversation(
|
|
12675
|
-
const pinnedAt = number(
|
|
12676
|
-
const projectId = text3(
|
|
12677
|
-
const context = conversationContext(
|
|
13107
|
+
function toConversation(record3) {
|
|
13108
|
+
const pinnedAt = number(record3.data.pinnedAt);
|
|
13109
|
+
const projectId = text3(record3.data.projectId);
|
|
13110
|
+
const context = conversationContext(record3.data);
|
|
12678
13111
|
return {
|
|
12679
|
-
uniqueId:
|
|
12680
|
-
conversationId:
|
|
12681
|
-
title: text3(
|
|
13112
|
+
uniqueId: record3.id,
|
|
13113
|
+
conversationId: record3.id,
|
|
13114
|
+
title: text3(record3.data.title) ?? "",
|
|
12682
13115
|
...projectId ? { projectId } : {},
|
|
12683
|
-
createdAt: new Date(
|
|
12684
|
-
updatedAt: new Date(
|
|
12685
|
-
isDeleted:
|
|
13116
|
+
createdAt: new Date(record3.createdAt),
|
|
13117
|
+
updatedAt: new Date(record3.updatedAt),
|
|
13118
|
+
isDeleted: record3.isDeleted,
|
|
12686
13119
|
pinnedAt: pinnedAt ? new Date(pinnedAt) : null,
|
|
12687
13120
|
...context ? { context } : {}
|
|
12688
13121
|
};
|
|
@@ -12704,21 +13137,21 @@ function messageData(options) {
|
|
|
12704
13137
|
...anuma ? { anuma } : {}
|
|
12705
13138
|
});
|
|
12706
13139
|
}
|
|
12707
|
-
function toMessage(
|
|
12708
|
-
const { chunkOffsets: _offsets, truncated: _truncated, anuma: rawAnuma, ...fields } =
|
|
13140
|
+
function toMessage(record3) {
|
|
13141
|
+
const { chunkOffsets: _offsets, truncated: _truncated, anuma: rawAnuma, ...fields } = record3.data;
|
|
12709
13142
|
const anuma = readAnumaTurn(rawAnuma);
|
|
12710
13143
|
return {
|
|
12711
13144
|
...anuma ? { anuma } : {},
|
|
12712
13145
|
...fields,
|
|
12713
|
-
uniqueId:
|
|
12714
|
-
messageId:
|
|
12715
|
-
conversationId:
|
|
12716
|
-
createdAt: new Date(
|
|
12717
|
-
updatedAt: new Date(
|
|
13146
|
+
uniqueId: record3.id,
|
|
13147
|
+
messageId: record3.sortKey,
|
|
13148
|
+
conversationId: record3.conversationId,
|
|
13149
|
+
createdAt: new Date(record3.createdAt),
|
|
13150
|
+
updatedAt: new Date(record3.updatedAt)
|
|
12718
13151
|
};
|
|
12719
13152
|
}
|
|
12720
|
-
function chunkOffsets(
|
|
12721
|
-
const offsets =
|
|
13153
|
+
function chunkOffsets(record3) {
|
|
13154
|
+
const offsets = record3.data.chunkOffsets;
|
|
12722
13155
|
return Array.isArray(offsets) ? offsets : void 0;
|
|
12723
13156
|
}
|
|
12724
13157
|
function toSkeletons(records) {
|
|
@@ -12739,15 +13172,15 @@ function toSkeletons(records) {
|
|
|
12739
13172
|
};
|
|
12740
13173
|
});
|
|
12741
13174
|
}
|
|
12742
|
-
function toSummary(
|
|
13175
|
+
function toSummary(record3) {
|
|
12743
13176
|
return {
|
|
12744
|
-
uniqueId:
|
|
12745
|
-
conversationId:
|
|
12746
|
-
summary: text3(
|
|
12747
|
-
summarizedUpTo: text3(
|
|
12748
|
-
tokenCount: number(
|
|
12749
|
-
createdAt: new Date(
|
|
12750
|
-
updatedAt: new Date(
|
|
13177
|
+
uniqueId: record3.id,
|
|
13178
|
+
conversationId: record3.id,
|
|
13179
|
+
summary: text3(record3.data.summary) ?? "",
|
|
13180
|
+
summarizedUpTo: text3(record3.data.summarizedUpTo) ?? "",
|
|
13181
|
+
tokenCount: number(record3.data.tokenCount) ?? 0,
|
|
13182
|
+
createdAt: new Date(record3.createdAt),
|
|
13183
|
+
updatedAt: new Date(record3.updatedAt)
|
|
12751
13184
|
};
|
|
12752
13185
|
}
|
|
12753
13186
|
function links(data) {
|
|
@@ -12773,10 +13206,10 @@ function applyLinkOps(data, ops) {
|
|
|
12773
13206
|
}
|
|
12774
13207
|
return plain({ links: current });
|
|
12775
13208
|
}
|
|
12776
|
-
function toLinks(
|
|
12777
|
-
return links(
|
|
12778
|
-
uniqueId: `${
|
|
12779
|
-
conversationId:
|
|
13209
|
+
function toLinks(record3) {
|
|
13210
|
+
return links(record3.data).map((l) => ({
|
|
13211
|
+
uniqueId: `${record3.id}:${l.memoryId}`,
|
|
13212
|
+
conversationId: record3.id,
|
|
12780
13213
|
memoryId: l.memoryId,
|
|
12781
13214
|
score: l.score,
|
|
12782
13215
|
createdAt: new Date(l.createdAt)
|
|
@@ -12785,24 +13218,24 @@ function toLinks(record2) {
|
|
|
12785
13218
|
function bytes(value) {
|
|
12786
13219
|
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
12787
13220
|
}
|
|
12788
|
-
function fitRecord(
|
|
12789
|
-
if (
|
|
12790
|
-
const data = { ...
|
|
13221
|
+
function fitRecord(record3) {
|
|
13222
|
+
if (record3.kind !== "message" || bytes(record3) <= recordBudgetBytes) return record3;
|
|
13223
|
+
const data = { ...record3.data };
|
|
12791
13224
|
const truncated = [];
|
|
12792
13225
|
for (const field10 of droppable) {
|
|
12793
|
-
if (bytes({ ...
|
|
13226
|
+
if (bytes({ ...record3, data }) <= recordBudgetBytes) break;
|
|
12794
13227
|
if (data[field10] === void 0) continue;
|
|
12795
13228
|
delete data[field10];
|
|
12796
13229
|
truncated.push(field10);
|
|
12797
13230
|
}
|
|
12798
13231
|
const content = text3(data.content) ?? "";
|
|
12799
|
-
const over = bytes({ ...
|
|
13232
|
+
const over = bytes({ ...record3, data }) - recordBudgetBytes;
|
|
12800
13233
|
if (over > 0) {
|
|
12801
13234
|
const encoded = new TextEncoder().encode(content);
|
|
12802
13235
|
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
12803
13236
|
truncated.push("content");
|
|
12804
13237
|
}
|
|
12805
|
-
return { ...
|
|
13238
|
+
return { ...record3, data: { ...data, truncated } };
|
|
12806
13239
|
}
|
|
12807
13240
|
function acceptedVector(vector2) {
|
|
12808
13241
|
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
@@ -12846,8 +13279,8 @@ function anumaTurnContent(bubbles) {
|
|
|
12846
13279
|
return bubbles.join("\n\n");
|
|
12847
13280
|
}
|
|
12848
13281
|
function anumaLastReadSortKey(conversation) {
|
|
12849
|
-
const
|
|
12850
|
-
const state =
|
|
13282
|
+
const record3 = conversation && "record" in conversation ? conversation.record : conversation;
|
|
13283
|
+
const state = record3?.data.anuma;
|
|
12851
13284
|
if (!isObject(state)) return 0;
|
|
12852
13285
|
const sortKey = state.lastReadSortKey;
|
|
12853
13286
|
return Number.isSafeInteger(sortKey) && sortKey > 0 ? sortKey : 0;
|
|
@@ -12900,19 +13333,19 @@ async function markAnumaRead(store, sortKey, options = {}) {
|
|
|
12900
13333
|
const current = await ensureAnumaConversation(store, options);
|
|
12901
13334
|
const read = anumaLastReadSortKey(current);
|
|
12902
13335
|
if (sortKey <= read) return current;
|
|
12903
|
-
const
|
|
12904
|
-
const state = isObject(
|
|
12905
|
-
const data = plain({ ...
|
|
13336
|
+
const record3 = current.record;
|
|
13337
|
+
const state = isObject(record3.data.anuma) ? record3.data.anuma : {};
|
|
13338
|
+
const data = plain({ ...record3.data, anuma: { ...state, lastReadSortKey: sortKey } });
|
|
12906
13339
|
try {
|
|
12907
13340
|
const [written] = await store.putMany(
|
|
12908
13341
|
[
|
|
12909
13342
|
{
|
|
12910
13343
|
expectedVersion: current.version,
|
|
12911
13344
|
record: {
|
|
12912
|
-
...
|
|
13345
|
+
...record3,
|
|
12913
13346
|
data,
|
|
12914
|
-
sortKey: conversationSortKey(data,
|
|
12915
|
-
updatedAt: Math.max(
|
|
13347
|
+
sortKey: conversationSortKey(data, record3.createdAt),
|
|
13348
|
+
updatedAt: Math.max(record3.updatedAt, now())
|
|
12916
13349
|
}
|
|
12917
13350
|
}
|
|
12918
13351
|
],
|
|
@@ -12948,22 +13381,22 @@ function createSummaryContext(database, encryption = {}) {
|
|
|
12948
13381
|
summariesCollection: database.get("conversation_summaries")
|
|
12949
13382
|
};
|
|
12950
13383
|
}
|
|
12951
|
-
function modelToStored(
|
|
13384
|
+
function modelToStored(record3, summary) {
|
|
12952
13385
|
return {
|
|
12953
|
-
uniqueId:
|
|
12954
|
-
conversationId:
|
|
13386
|
+
uniqueId: record3.id,
|
|
13387
|
+
conversationId: record3.conversationId,
|
|
12955
13388
|
summary,
|
|
12956
|
-
summarizedUpTo:
|
|
12957
|
-
tokenCount:
|
|
12958
|
-
createdAt:
|
|
12959
|
-
updatedAt:
|
|
13389
|
+
summarizedUpTo: record3.summarizedUpTo,
|
|
13390
|
+
tokenCount: record3.tokenCount,
|
|
13391
|
+
createdAt: record3.createdAt,
|
|
13392
|
+
updatedAt: record3.updatedAt
|
|
12960
13393
|
};
|
|
12961
13394
|
}
|
|
12962
13395
|
async function getConversationSummaryOp(ctx, conversationId) {
|
|
12963
13396
|
const results = await ctx.summariesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
|
|
12964
13397
|
if (results.length === 0) return null;
|
|
12965
|
-
const
|
|
12966
|
-
const stored2 = modelToStored(
|
|
13398
|
+
const record3 = results[0];
|
|
13399
|
+
const stored2 = modelToStored(record3, record3.summary);
|
|
12967
13400
|
if (ctx.walletAddress && isEncrypted(stored2.summary)) {
|
|
12968
13401
|
if (ctx.signMessage) {
|
|
12969
13402
|
try {
|
|
@@ -12982,7 +13415,7 @@ async function getConversationSummaryOp(ctx, conversationId) {
|
|
|
12982
13415
|
ctx.embeddedWalletSigner
|
|
12983
13416
|
);
|
|
12984
13417
|
await ctx.database.write(async () => {
|
|
12985
|
-
const current = await ctx.summariesCollection.query(import_watermelondb6.Q.where("id",
|
|
13418
|
+
const current = await ctx.summariesCollection.query(import_watermelondb6.Q.where("id", record3.id)).fetch();
|
|
12986
13419
|
if (current[0]?.summary === stored2.summary) {
|
|
12987
13420
|
await current[0].update((rec) => {
|
|
12988
13421
|
rec.summary = encryptedSummary;
|
|
@@ -12997,19 +13430,19 @@ async function getConversationSummaryOp(ctx, conversationId) {
|
|
|
12997
13430
|
}
|
|
12998
13431
|
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
12999
13432
|
const revision2 = getConversationRevision(ctx.database, conversationId);
|
|
13000
|
-
let
|
|
13433
|
+
let record3;
|
|
13001
13434
|
const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
|
|
13002
13435
|
await ctx.database.write(async () => {
|
|
13003
13436
|
assertConversationRevision(ctx.database, conversationId, revision2);
|
|
13004
13437
|
const existing = await ctx.summariesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
|
|
13005
13438
|
if (existing.length > 0) {
|
|
13006
|
-
|
|
13439
|
+
record3 = await existing[0].update((rec) => {
|
|
13007
13440
|
rec.summary = encryptedSummary;
|
|
13008
13441
|
rec.summarizedUpTo = summarizedUpTo;
|
|
13009
13442
|
rec.tokenCount = tokenCount;
|
|
13010
13443
|
});
|
|
13011
13444
|
} else {
|
|
13012
|
-
|
|
13445
|
+
record3 = await ctx.summariesCollection.create((rec) => {
|
|
13013
13446
|
rec.conversationId = conversationId;
|
|
13014
13447
|
rec.summary = encryptedSummary;
|
|
13015
13448
|
rec.summarizedUpTo = summarizedUpTo;
|
|
@@ -13017,13 +13450,13 @@ async function upsertConversationSummaryOp(ctx, conversationId, summary, summari
|
|
|
13017
13450
|
});
|
|
13018
13451
|
}
|
|
13019
13452
|
});
|
|
13020
|
-
return modelToStored(
|
|
13453
|
+
return modelToStored(record3, summary);
|
|
13021
13454
|
}
|
|
13022
13455
|
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
13023
13456
|
await ctx.database.write(async () => {
|
|
13024
13457
|
const existing = await ctx.summariesCollection.query(import_watermelondb6.Q.where("conversation_id", conversationId)).fetch();
|
|
13025
|
-
for (const
|
|
13026
|
-
await
|
|
13458
|
+
for (const record3 of existing) {
|
|
13459
|
+
await record3.destroyPermanently();
|
|
13027
13460
|
}
|
|
13028
13461
|
});
|
|
13029
13462
|
}
|
|
@@ -13099,7 +13532,7 @@ function messageRecord(message) {
|
|
|
13099
13532
|
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
13100
13533
|
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
13101
13534
|
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
13102
|
-
const
|
|
13535
|
+
const record3 = fitRecord({
|
|
13103
13536
|
kind: "message",
|
|
13104
13537
|
id: message.uniqueId,
|
|
13105
13538
|
conversationId: message.conversationId,
|
|
@@ -13113,7 +13546,7 @@ function messageRecord(message) {
|
|
|
13113
13546
|
}
|
|
13114
13547
|
});
|
|
13115
13548
|
return {
|
|
13116
|
-
record:
|
|
13549
|
+
record: record3,
|
|
13117
13550
|
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
13118
13551
|
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
13119
13552
|
};
|
|
@@ -13261,15 +13694,15 @@ function ref(value) {
|
|
|
13261
13694
|
function sameMetadata(a, b) {
|
|
13262
13695
|
return metadata.every((key3) => a[key3] === b[key3]);
|
|
13263
13696
|
}
|
|
13264
|
-
function wire(
|
|
13697
|
+
function wire(record3, payload) {
|
|
13265
13698
|
return {
|
|
13266
|
-
kind:
|
|
13267
|
-
id:
|
|
13268
|
-
conversation_id:
|
|
13269
|
-
sort_key:
|
|
13270
|
-
created_at:
|
|
13271
|
-
updated_at:
|
|
13272
|
-
is_deleted:
|
|
13699
|
+
kind: record3.kind,
|
|
13700
|
+
id: record3.id,
|
|
13701
|
+
conversation_id: record3.conversationId,
|
|
13702
|
+
sort_key: record3.sortKey,
|
|
13703
|
+
created_at: record3.createdAt,
|
|
13704
|
+
updated_at: record3.updatedAt,
|
|
13705
|
+
is_deleted: record3.isDeleted,
|
|
13273
13706
|
payload
|
|
13274
13707
|
};
|
|
13275
13708
|
}
|
|
@@ -13326,10 +13759,10 @@ async function createRemoteChatStore(options) {
|
|
|
13326
13759
|
serverUpdatedAt: value.server_updated_at
|
|
13327
13760
|
};
|
|
13328
13761
|
};
|
|
13329
|
-
const seal = async (
|
|
13330
|
-
if (
|
|
13762
|
+
const seal = async (record3, signal) => {
|
|
13763
|
+
if (record3.isDeleted) return "";
|
|
13331
13764
|
const payload = await encrypt(
|
|
13332
|
-
JSON.stringify({ schema: 1, account_id: accountId, key_id: keyId, record:
|
|
13765
|
+
JSON.stringify({ schema: 1, account_id: accountId, key_id: keyId, record: record3 })
|
|
13333
13766
|
);
|
|
13334
13767
|
signal?.throwIfAborted();
|
|
13335
13768
|
if (!cipherPattern.test(payload) || payload.length > maxPayload) invalid();
|
|
@@ -13693,8 +14126,8 @@ var emptyMessage = {
|
|
|
13693
14126
|
var maxPasses = 5;
|
|
13694
14127
|
var verifyBatch = 1e3;
|
|
13695
14128
|
var writeBatch = 25;
|
|
13696
|
-
function key(
|
|
13697
|
-
return `${
|
|
14129
|
+
function key(record3) {
|
|
14130
|
+
return `${record3.kind}/${record3.id}`;
|
|
13698
14131
|
}
|
|
13699
14132
|
function sealed(value) {
|
|
13700
14133
|
if (typeof value === "string") return isEncrypted(value);
|
|
@@ -13823,11 +14256,11 @@ async function missing(store, records, signal) {
|
|
|
13823
14256
|
const out = /* @__PURE__ */ new Set();
|
|
13824
14257
|
for (let i = 0; i < records.length; i += verifyBatch) {
|
|
13825
14258
|
const refs = await store.verify(
|
|
13826
|
-
records.slice(i, i + verifyBatch).map(({ record:
|
|
13827
|
-
kind:
|
|
13828
|
-
id:
|
|
13829
|
-
updatedAt:
|
|
13830
|
-
isDeleted:
|
|
14259
|
+
records.slice(i, i + verifyBatch).map(({ record: record3 }) => ({
|
|
14260
|
+
kind: record3.kind,
|
|
14261
|
+
id: record3.id,
|
|
14262
|
+
updatedAt: record3.updatedAt,
|
|
14263
|
+
isDeleted: record3.isDeleted
|
|
13831
14264
|
})),
|
|
13832
14265
|
signal
|
|
13833
14266
|
);
|
|
@@ -13867,14 +14300,14 @@ async function deletedSinceUpload(store, journal, local, signal) {
|
|
|
13867
14300
|
const live2 = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
|
|
13868
14301
|
const tombstoning = new Set(live2.map((s) => key(s.record)));
|
|
13869
14302
|
await journal.drop(gone.filter((k) => !tombstoning.has(k)));
|
|
13870
|
-
return live2.map(({ record:
|
|
13871
|
-
const empty = emptied[
|
|
14303
|
+
return live2.map(({ record: record3, version }) => {
|
|
14304
|
+
const empty = emptied[record3.kind];
|
|
13872
14305
|
return {
|
|
13873
14306
|
record: {
|
|
13874
|
-
...
|
|
14307
|
+
...record3,
|
|
13875
14308
|
isDeleted: !empty,
|
|
13876
14309
|
data: empty ?? {},
|
|
13877
|
-
updatedAt: Math.max(Date.now(),
|
|
14310
|
+
updatedAt: Math.max(Date.now(), record3.updatedAt + 1)
|
|
13878
14311
|
},
|
|
13879
14312
|
expectedVersion: version
|
|
13880
14313
|
};
|
|
@@ -14223,8 +14656,8 @@ function createVaultAttachments(options) {
|
|
|
14223
14656
|
},
|
|
14224
14657
|
async read(attachmentId, signal) {
|
|
14225
14658
|
if (!attachmentIdPattern2.test(attachmentId)) invalidAttachment();
|
|
14226
|
-
const
|
|
14227
|
-
if (
|
|
14659
|
+
const cached2 = await cache?.get(attachmentId).catch(() => null);
|
|
14660
|
+
if (cached2) return cached2;
|
|
14228
14661
|
for (let attempt = 0; ; attempt++) {
|
|
14229
14662
|
const found = await withRetry(() => store.attachments.get(attachmentId, signal), signal);
|
|
14230
14663
|
if (!found?.download) return null;
|
|
@@ -14253,8 +14686,8 @@ function validRef(value) {
|
|
|
14253
14686
|
const ref3 = value;
|
|
14254
14687
|
return typeof ref3.attachmentId === "string" && attachmentIdPattern2.test(ref3.attachmentId) && typeof ref3.fileId === "string" && ref3.fileId.length > 0 && typeof ref3.name === "string" && typeof ref3.type === "string" && Number.isSafeInteger(ref3.size) && ref3.size >= 0;
|
|
14255
14688
|
}
|
|
14256
|
-
function vaultAttachmentRefs(
|
|
14257
|
-
const refs =
|
|
14689
|
+
function vaultAttachmentRefs(record3) {
|
|
14690
|
+
const refs = record3.data.vaultAttachments;
|
|
14258
14691
|
return Array.isArray(refs) ? refs.filter(validRef) : [];
|
|
14259
14692
|
}
|
|
14260
14693
|
function journalKey(messageId, fileId) {
|
|
@@ -14462,14 +14895,14 @@ function sameRecord(a, b) {
|
|
|
14462
14895
|
return a.sortKey === b.sortKey && a.isDeleted === b.isDeleted && sameJson(a.data, b.data);
|
|
14463
14896
|
}
|
|
14464
14897
|
function toWrite(base, patch) {
|
|
14465
|
-
const
|
|
14466
|
-
if (!
|
|
14467
|
-
if (base && patch.embeddings === void 0 && sameRecord(base.record,
|
|
14898
|
+
const record3 = applyPatch(base?.record, patch);
|
|
14899
|
+
if (!record3) return void 0;
|
|
14900
|
+
if (base && patch.embeddings === void 0 && sameRecord(base.record, record3)) return null;
|
|
14468
14901
|
return {
|
|
14469
|
-
record: fitRecord(
|
|
14902
|
+
record: fitRecord(record3),
|
|
14470
14903
|
expectedVersion: base?.version ?? 0,
|
|
14471
|
-
...patch.embeddings !== void 0 && !
|
|
14472
|
-
...patch.embeddingModel !== void 0 && !
|
|
14904
|
+
...patch.embeddings !== void 0 && !record3.isDeleted ? { embeddings: patch.embeddings } : {},
|
|
14905
|
+
...patch.embeddingModel !== void 0 && !record3.isDeleted ? { embeddingModel: patch.embeddingModel } : {}
|
|
14473
14906
|
};
|
|
14474
14907
|
}
|
|
14475
14908
|
var maxWrites = 25;
|
|
@@ -14603,11 +15036,11 @@ function createVaultChatBackend(options) {
|
|
|
14603
15036
|
for (const listener of [...listeners]) listener(event);
|
|
14604
15037
|
};
|
|
14605
15038
|
const view = (k) => {
|
|
14606
|
-
let
|
|
15039
|
+
let record3 = confirmed.get(k)?.record;
|
|
14607
15040
|
for (const patch of [inflight.get(k), pending.get(k)]) {
|
|
14608
|
-
if (patch)
|
|
15041
|
+
if (patch) record3 = applyPatch(record3, patch) ?? record3;
|
|
14609
15042
|
}
|
|
14610
|
-
return
|
|
15043
|
+
return record3;
|
|
14611
15044
|
};
|
|
14612
15045
|
const conversationLive = (conversationId) => {
|
|
14613
15046
|
const conversation2 = view(key2("conversation", conversationId));
|
|
@@ -14618,10 +15051,10 @@ function createVaultChatBackend(options) {
|
|
|
14618
15051
|
const out = [];
|
|
14619
15052
|
for (const k of keys) {
|
|
14620
15053
|
if (!k.startsWith(`${kind}/`)) continue;
|
|
14621
|
-
const
|
|
14622
|
-
if (!
|
|
14623
|
-
if (conversationId !== void 0 &&
|
|
14624
|
-
out.push(
|
|
15054
|
+
const record3 = view(k);
|
|
15055
|
+
if (!record3 || record3.isDeleted && !includeDeleted) continue;
|
|
15056
|
+
if (conversationId !== void 0 && record3.conversationId !== conversationId) continue;
|
|
15057
|
+
out.push(record3);
|
|
14625
15058
|
}
|
|
14626
15059
|
return out;
|
|
14627
15060
|
};
|
|
@@ -14632,7 +15065,7 @@ function createVaultChatBackend(options) {
|
|
|
14632
15065
|
account: cache.account,
|
|
14633
15066
|
cursor: cursor ?? "",
|
|
14634
15067
|
records: [...confirmed.values()].filter(
|
|
14635
|
-
({ record:
|
|
15068
|
+
({ record: record3 }) => record3.kind === "conversation" || record3.kind !== "project" && keep.has(record3.conversationId)
|
|
14636
15069
|
),
|
|
14637
15070
|
threads: kept,
|
|
14638
15071
|
absent: [...checked].filter((k) => {
|
|
@@ -14946,17 +15379,17 @@ function createVaultChatBackend(options) {
|
|
|
14946
15379
|
return loading;
|
|
14947
15380
|
};
|
|
14948
15381
|
const applyRemote = (snapshot) => {
|
|
14949
|
-
const { record:
|
|
14950
|
-
const k = key2(
|
|
14951
|
-
if (
|
|
15382
|
+
const { record: record3 } = snapshot;
|
|
15383
|
+
const k = key2(record3.kind, record3.id);
|
|
15384
|
+
if (record3.kind === "conversation") {
|
|
14952
15385
|
if (!merge(snapshot)) return;
|
|
14953
|
-
if (
|
|
14954
|
-
announce([
|
|
15386
|
+
if (record3.isDeleted) forgetConversation(record3.id);
|
|
15387
|
+
announce([record3]);
|
|
14955
15388
|
return;
|
|
14956
15389
|
}
|
|
14957
|
-
if (
|
|
14958
|
-
const relevant2 = threads.has(
|
|
14959
|
-
if (relevant2 && merge(snapshot)) announce([
|
|
15390
|
+
if (record3.kind === "project") return;
|
|
15391
|
+
const relevant2 = threads.has(record3.conversationId) || confirmed.has(k) || checked.has(k) && record3.kind !== "message";
|
|
15392
|
+
if (relevant2 && merge(snapshot)) announce([record3]);
|
|
14960
15393
|
};
|
|
14961
15394
|
const listIndex = async (source) => {
|
|
14962
15395
|
const index = [];
|
|
@@ -15107,8 +15540,8 @@ function createVaultChatBackend(options) {
|
|
|
15107
15540
|
checked.add(k);
|
|
15108
15541
|
if (found) merge(found);
|
|
15109
15542
|
}
|
|
15110
|
-
const
|
|
15111
|
-
return
|
|
15543
|
+
const record3 = view(k);
|
|
15544
|
+
return record3 && !record3.isDeleted && conversationLive(record3.conversationId) ? record3 : void 0;
|
|
15112
15545
|
};
|
|
15113
15546
|
const child = async (kind, conversationId) => {
|
|
15114
15547
|
await available2();
|
|
@@ -15145,19 +15578,19 @@ function createVaultChatBackend(options) {
|
|
|
15145
15578
|
await backend.deleteSummary(conversationId);
|
|
15146
15579
|
};
|
|
15147
15580
|
const storedMessage = async (uniqueId) => {
|
|
15148
|
-
const
|
|
15149
|
-
return
|
|
15581
|
+
const record3 = await message(uniqueId);
|
|
15582
|
+
return record3 ? toMessage(record3) : null;
|
|
15150
15583
|
};
|
|
15151
15584
|
const patchMessage = async (uniqueId, patch) => {
|
|
15152
|
-
const
|
|
15153
|
-
if (!
|
|
15585
|
+
const record3 = await message(uniqueId);
|
|
15586
|
+
if (!record3) return null;
|
|
15154
15587
|
await enqueue({
|
|
15155
15588
|
kind: "message",
|
|
15156
15589
|
id: uniqueId,
|
|
15157
|
-
conversationId:
|
|
15590
|
+
conversationId: record3.conversationId,
|
|
15158
15591
|
...patch
|
|
15159
15592
|
});
|
|
15160
|
-
emit({ type: "messages", conversationId:
|
|
15593
|
+
emit({ type: "messages", conversationId: record3.conversationId, origin: "local" });
|
|
15161
15594
|
const updated = view(key2("message", uniqueId));
|
|
15162
15595
|
return updated && !updated.isDeleted ? toMessage(updated) : null;
|
|
15163
15596
|
};
|
|
@@ -15182,12 +15615,12 @@ function createVaultChatBackend(options) {
|
|
|
15182
15615
|
});
|
|
15183
15616
|
const backend = {
|
|
15184
15617
|
async getConversation(conversationId) {
|
|
15185
|
-
const
|
|
15186
|
-
return
|
|
15618
|
+
const record3 = await conversation(conversationId);
|
|
15619
|
+
return record3 && !record3.isDeleted ? toConversation(record3) : null;
|
|
15187
15620
|
},
|
|
15188
15621
|
async getConversations(query) {
|
|
15189
15622
|
await available2();
|
|
15190
|
-
return all("conversation").filter((
|
|
15623
|
+
return all("conversation").filter((record3) => record3.id !== ANUMA_CONVERSATION_ID).map(toConversation).filter(
|
|
15191
15624
|
(c) => query?.projectId === void 0 || (query.projectId === null ? !c.projectId : c.projectId === query.projectId)
|
|
15192
15625
|
).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
15193
15626
|
},
|
|
@@ -15226,13 +15659,13 @@ function createVaultChatBackend(options) {
|
|
|
15226
15659
|
async updateConversationContext(conversationId, context) {
|
|
15227
15660
|
const set = contextFields(context);
|
|
15228
15661
|
if (Object.keys(set).length > 0) return updateConversation(conversationId, set);
|
|
15229
|
-
const
|
|
15230
|
-
return !!
|
|
15662
|
+
const record3 = await conversation(conversationId);
|
|
15663
|
+
return !!record3 && !record3.isDeleted;
|
|
15231
15664
|
},
|
|
15232
15665
|
async deleteConversation(conversationId) {
|
|
15233
15666
|
if (conversationId === ANUMA_CONVERSATION_ID) return false;
|
|
15234
|
-
const
|
|
15235
|
-
if (!
|
|
15667
|
+
const record3 = await conversation(conversationId);
|
|
15668
|
+
if (!record3 || record3.isDeleted) return false;
|
|
15236
15669
|
for (const [k, patch] of pending)
|
|
15237
15670
|
if (patch.conversationId === conversationId) pending.delete(k);
|
|
15238
15671
|
await enqueue({ kind: "conversation", id: conversationId, conversationId: "", delete: true });
|
|
@@ -15268,8 +15701,8 @@ function createVaultChatBackend(options) {
|
|
|
15268
15701
|
const unknown = ids.map((id2) => key2("message", id2)).filter((k) => !view(k) && !checked.has(k));
|
|
15269
15702
|
await refresh(unknown);
|
|
15270
15703
|
return ids.flatMap((id2) => {
|
|
15271
|
-
const
|
|
15272
|
-
return
|
|
15704
|
+
const record3 = view(key2("message", id2));
|
|
15705
|
+
return record3 && !record3.isDeleted && conversationLive(record3.conversationId) ? [toMessage(record3)] : [];
|
|
15273
15706
|
});
|
|
15274
15707
|
},
|
|
15275
15708
|
async getMessageCount(conversationId) {
|
|
@@ -15277,8 +15710,8 @@ function createVaultChatBackend(options) {
|
|
|
15277
15710
|
},
|
|
15278
15711
|
async getToolCallEventIds(conversationId) {
|
|
15279
15712
|
const ids = /* @__PURE__ */ new Set();
|
|
15280
|
-
for (const
|
|
15281
|
-
const events =
|
|
15713
|
+
for (const record3 of await thread(conversationId)) {
|
|
15714
|
+
const events = record3.data.toolCallEvents;
|
|
15282
15715
|
if (!Array.isArray(events)) continue;
|
|
15283
15716
|
for (const event of events)
|
|
15284
15717
|
if (event && typeof event === "object" && !Array.isArray(event) && typeof event.id === "string")
|
|
@@ -15371,21 +15804,21 @@ function createVaultChatBackend(options) {
|
|
|
15371
15804
|
},
|
|
15372
15805
|
async clearMessages(conversationId) {
|
|
15373
15806
|
await invalidateSummary(conversationId);
|
|
15374
|
-
for (const
|
|
15375
|
-
await enqueue({ kind: "message", id:
|
|
15807
|
+
for (const record3 of await thread(conversationId))
|
|
15808
|
+
await enqueue({ kind: "message", id: record3.id, conversationId, delete: true });
|
|
15376
15809
|
emit({ type: "messages", conversationId, origin: "local" });
|
|
15377
15810
|
},
|
|
15378
15811
|
async deleteMessage(uniqueId) {
|
|
15379
|
-
const
|
|
15380
|
-
if (!
|
|
15381
|
-
await invalidateSummary(
|
|
15812
|
+
const record3 = await message(uniqueId);
|
|
15813
|
+
if (!record3) return null;
|
|
15814
|
+
await invalidateSummary(record3.conversationId, record3);
|
|
15382
15815
|
await enqueue({
|
|
15383
15816
|
kind: "message",
|
|
15384
15817
|
id: uniqueId,
|
|
15385
|
-
conversationId:
|
|
15818
|
+
conversationId: record3.conversationId,
|
|
15386
15819
|
delete: true
|
|
15387
15820
|
});
|
|
15388
|
-
emit({ type: "messages", conversationId:
|
|
15821
|
+
emit({ type: "messages", conversationId: record3.conversationId, origin: "local" });
|
|
15389
15822
|
return uniqueId;
|
|
15390
15823
|
},
|
|
15391
15824
|
observeMessages(conversationId) {
|
|
@@ -15398,13 +15831,13 @@ function createVaultChatBackend(options) {
|
|
|
15398
15831
|
await available2();
|
|
15399
15832
|
if (query?.conversationId) await loadThread(query.conversationId);
|
|
15400
15833
|
const files = [];
|
|
15401
|
-
for (const
|
|
15402
|
-
if (!conversationLive(
|
|
15403
|
-
const stored2 = toMessage(
|
|
15834
|
+
for (const record3 of all("message", query?.conversationId)) {
|
|
15835
|
+
if (!conversationLive(record3.conversationId)) continue;
|
|
15836
|
+
const stored2 = toMessage(record3);
|
|
15404
15837
|
for (const file of stored2.files ?? [])
|
|
15405
15838
|
files.push({
|
|
15406
15839
|
...file,
|
|
15407
|
-
conversationId:
|
|
15840
|
+
conversationId: record3.conversationId,
|
|
15408
15841
|
createdAt: stored2.createdAt,
|
|
15409
15842
|
messageRole: stored2.role
|
|
15410
15843
|
});
|
|
@@ -15443,8 +15876,8 @@ function createVaultChatBackend(options) {
|
|
|
15443
15876
|
return results;
|
|
15444
15877
|
},
|
|
15445
15878
|
async getSummary(conversationId) {
|
|
15446
|
-
const
|
|
15447
|
-
return
|
|
15879
|
+
const record3 = await child("summary", conversationId);
|
|
15880
|
+
return record3 && !record3.isDeleted && record3.data.summarizedUpTo ? toSummary(record3) : null;
|
|
15448
15881
|
},
|
|
15449
15882
|
async upsertSummary(conversationId, summary, summarizedUpTo, tokenCount) {
|
|
15450
15883
|
await child("summary", conversationId);
|
|
@@ -15460,8 +15893,8 @@ function createVaultChatBackend(options) {
|
|
|
15460
15893
|
return toSummary(view(key2("summary", conversationId)));
|
|
15461
15894
|
},
|
|
15462
15895
|
async deleteSummary(conversationId) {
|
|
15463
|
-
const
|
|
15464
|
-
if (!
|
|
15896
|
+
const record3 = await child("summary", conversationId);
|
|
15897
|
+
if (!record3 || record3.isDeleted) return;
|
|
15465
15898
|
await enqueue({
|
|
15466
15899
|
kind: "summary",
|
|
15467
15900
|
id: conversationId,
|
|
@@ -15471,8 +15904,8 @@ function createVaultChatBackend(options) {
|
|
|
15471
15904
|
emit({ type: "summary", conversationId, origin: "local" });
|
|
15472
15905
|
},
|
|
15473
15906
|
async getMemoryLinks(conversationId) {
|
|
15474
|
-
const
|
|
15475
|
-
return
|
|
15907
|
+
const record3 = await child("memory_links", conversationId);
|
|
15908
|
+
return record3 && !record3.isDeleted ? toLinks(record3) : [];
|
|
15476
15909
|
},
|
|
15477
15910
|
async addMemoryLinks(conversationId, items) {
|
|
15478
15911
|
if (!conversationId || items.length === 0) return;
|
|
@@ -15487,8 +15920,8 @@ function createVaultChatBackend(options) {
|
|
|
15487
15920
|
emit({ type: "links", conversationId, origin: "local" });
|
|
15488
15921
|
},
|
|
15489
15922
|
async clearMemoryLinks(conversationId) {
|
|
15490
|
-
const
|
|
15491
|
-
if (!
|
|
15923
|
+
const record3 = await child("memory_links", conversationId);
|
|
15924
|
+
if (!record3 || record3.isDeleted) return;
|
|
15492
15925
|
await enqueue({
|
|
15493
15926
|
kind: "memory_links",
|
|
15494
15927
|
id: conversationId,
|
|
@@ -15506,8 +15939,8 @@ function createVaultChatBackend(options) {
|
|
|
15506
15939
|
async importChats(chats) {
|
|
15507
15940
|
await ready();
|
|
15508
15941
|
const seen = /* @__PURE__ */ new Set();
|
|
15509
|
-
const unique = (items) => items.filter(({ record:
|
|
15510
|
-
const k = key2(
|
|
15942
|
+
const unique = (items) => items.filter(({ record: record3 }) => {
|
|
15943
|
+
const k = key2(record3.kind, record3.id);
|
|
15511
15944
|
if (seen.has(k)) return false;
|
|
15512
15945
|
seen.add(k);
|
|
15513
15946
|
return true;
|
|
@@ -15531,15 +15964,15 @@ function createVaultChatBackend(options) {
|
|
|
15531
15964
|
for (const batch of batches(messages))
|
|
15532
15965
|
messageCount += await connected.importRecords(batch);
|
|
15533
15966
|
} finally {
|
|
15534
|
-
for (const { record:
|
|
15535
|
-
await refresh(conversations.map(({ record:
|
|
15967
|
+
for (const { record: record3 } of messages) checked.delete(key2("message", record3.id));
|
|
15968
|
+
await refresh(conversations.map(({ record: record3 }) => key2("conversation", record3.id))).catch(
|
|
15536
15969
|
() => void 0
|
|
15537
15970
|
);
|
|
15538
|
-
for (const { record:
|
|
15971
|
+
for (const { record: record3 } of conversations) threads.delete(record3.id);
|
|
15539
15972
|
channel?.postMessage("changed");
|
|
15540
15973
|
emit({ type: "conversations", origin: "local" });
|
|
15541
|
-
for (const { record:
|
|
15542
|
-
emit({ type: "messages", conversationId:
|
|
15974
|
+
for (const { record: record3 } of conversations)
|
|
15975
|
+
emit({ type: "messages", conversationId: record3.id, origin: "local" });
|
|
15543
15976
|
}
|
|
15544
15977
|
return { conversations: conversationCount, messages: messageCount };
|
|
15545
15978
|
},
|
|
@@ -15558,8 +15991,8 @@ function createVaultChatBackend(options) {
|
|
|
15558
15991
|
}
|
|
15559
15992
|
};
|
|
15560
15993
|
const updateConversation = async (conversationId, set) => {
|
|
15561
|
-
const
|
|
15562
|
-
if (!
|
|
15994
|
+
const record3 = await conversation(conversationId);
|
|
15995
|
+
if (!record3 || record3.isDeleted) return false;
|
|
15563
15996
|
await enqueue({ kind: "conversation", id: conversationId, conversationId: "", set });
|
|
15564
15997
|
emit({ type: "conversations", origin: "local" });
|
|
15565
15998
|
return true;
|
|
@@ -15633,10 +16066,10 @@ async function decryptConversationTitle(encryptedTitle, address) {
|
|
|
15633
16066
|
);
|
|
15634
16067
|
}
|
|
15635
16068
|
const cacheKey = buildCacheKey(address, encryptedTitle);
|
|
15636
|
-
const
|
|
15637
|
-
if (
|
|
15638
|
-
touchEntry(cacheKey,
|
|
15639
|
-
return
|
|
16069
|
+
const cached2 = titleCache.get(cacheKey);
|
|
16070
|
+
if (cached2 !== void 0) {
|
|
16071
|
+
touchEntry(cacheKey, cached2);
|
|
16072
|
+
return cached2;
|
|
15640
16073
|
}
|
|
15641
16074
|
const inFlight = pendingDecrypts.get(cacheKey);
|
|
15642
16075
|
if (inFlight) return inFlight;
|
|
@@ -17053,9 +17486,9 @@ var DatabaseManager = class {
|
|
|
17053
17486
|
*/
|
|
17054
17487
|
getDatabase(walletAddress) {
|
|
17055
17488
|
const dbName = this.getDbName(walletAddress);
|
|
17056
|
-
const
|
|
17057
|
-
if (
|
|
17058
|
-
return
|
|
17489
|
+
const cached2 = this.databases.get(dbName);
|
|
17490
|
+
if (cached2) {
|
|
17491
|
+
return cached2;
|
|
17059
17492
|
}
|
|
17060
17493
|
const needsMigration = this.handleSchemaMigration(walletAddress);
|
|
17061
17494
|
if (needsMigration) {
|
|
@@ -17248,25 +17681,25 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
17248
17681
|
const kindBackfills = existing.filter((e) => {
|
|
17249
17682
|
const incoming = kindByName.get(e.canonicalName);
|
|
17250
17683
|
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
17251
|
-
}).map((
|
|
17684
|
+
}).map((record3) => ({ record: record3, kind: kindByName.get(record3.canonicalName) }));
|
|
17252
17685
|
const missing2 = unique.filter((n) => !existingNames.has(n));
|
|
17253
17686
|
const created = missing2.map(
|
|
17254
|
-
(name) => ctx.entityCollection.prepareCreate((
|
|
17255
|
-
|
|
17687
|
+
(name) => ctx.entityCollection.prepareCreate((record3) => {
|
|
17688
|
+
record3._setRaw("canonical_name", name);
|
|
17256
17689
|
const kind = kindByName.get(name);
|
|
17257
|
-
if (kind !== void 0)
|
|
17690
|
+
if (kind !== void 0) record3._setRaw("kind", kind);
|
|
17258
17691
|
})
|
|
17259
17692
|
);
|
|
17260
17693
|
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
17261
|
-
for (const
|
|
17262
|
-
for (const { record:
|
|
17263
|
-
out.set(
|
|
17694
|
+
for (const record3 of created) out.set(record3.canonicalName, entityToStored(record3));
|
|
17695
|
+
for (const { record: record3, kind } of kindBackfills) {
|
|
17696
|
+
out.set(record3.canonicalName, { ...entityToStored(record3), kind });
|
|
17264
17697
|
}
|
|
17265
17698
|
return { entities: out, operations: created, kindBackfills };
|
|
17266
17699
|
}
|
|
17267
17700
|
function prepareKindBackfills(backfills) {
|
|
17268
17701
|
return backfills.map(
|
|
17269
|
-
({ record:
|
|
17702
|
+
({ record: record3, kind }) => record3.prepareUpdate((r) => {
|
|
17270
17703
|
r._setRaw("kind", kind);
|
|
17271
17704
|
})
|
|
17272
17705
|
);
|
|
@@ -17394,10 +17827,10 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
17394
17827
|
return;
|
|
17395
17828
|
}
|
|
17396
17829
|
const linkOps = toCreate.map(
|
|
17397
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
17398
|
-
|
|
17399
|
-
|
|
17400
|
-
if (userId !== void 0)
|
|
17830
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record3) => {
|
|
17831
|
+
record3._setRaw("memory_id", memoryId);
|
|
17832
|
+
record3._setRaw("entity_id", e.uniqueId);
|
|
17833
|
+
if (userId !== void 0) record3._setRaw("user_id", userId);
|
|
17401
17834
|
})
|
|
17402
17835
|
);
|
|
17403
17836
|
await ctx.database.batch(
|
|
@@ -17467,10 +17900,10 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
17467
17900
|
...entityOps,
|
|
17468
17901
|
...prepareKindBackfills(kindBackfills),
|
|
17469
17902
|
...toCreate.map(
|
|
17470
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
17471
|
-
|
|
17472
|
-
|
|
17473
|
-
if (userId !== void 0)
|
|
17903
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record3) => {
|
|
17904
|
+
record3._setRaw("memory_id", memoryId);
|
|
17905
|
+
record3._setRaw("entity_id", e.uniqueId);
|
|
17906
|
+
if (userId !== void 0) record3._setRaw("user_id", userId);
|
|
17474
17907
|
})
|
|
17475
17908
|
),
|
|
17476
17909
|
...toDestroy.map((l) => l.prepareDestroyPermanently()),
|
|
@@ -17623,8 +18056,8 @@ function visibilityConditions(requested) {
|
|
|
17623
18056
|
if (excluded.length === 0) return [];
|
|
17624
18057
|
return [import_watermelondb21.Q.or(import_watermelondb21.Q.where("visibility", null), import_watermelondb21.Q.where("visibility", import_watermelondb21.Q.notIn(excluded)))];
|
|
17625
18058
|
}
|
|
17626
|
-
function isKinded(
|
|
17627
|
-
return
|
|
18059
|
+
function isKinded(record3) {
|
|
18060
|
+
return record3.kind !== null && record3.kind !== void 0;
|
|
17628
18061
|
}
|
|
17629
18062
|
async function assertCanWrite2(ctx) {
|
|
17630
18063
|
if (ctx.canWrite && !await ctx.canWrite()) {
|
|
@@ -17678,8 +18111,8 @@ function levelConditions(requested) {
|
|
|
17678
18111
|
}
|
|
17679
18112
|
return [byLevel];
|
|
17680
18113
|
}
|
|
17681
|
-
function isOwnedByCtxUser(ctx,
|
|
17682
|
-
return ctx.userId === void 0 ||
|
|
18114
|
+
function isOwnedByCtxUser(ctx, record3) {
|
|
18115
|
+
return ctx.userId === void 0 || record3.userId === ctx.userId;
|
|
17683
18116
|
}
|
|
17684
18117
|
function baseVaultConditions(ctx, options) {
|
|
17685
18118
|
return [
|
|
@@ -17762,43 +18195,43 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
17762
18195
|
}
|
|
17763
18196
|
return raw;
|
|
17764
18197
|
}
|
|
17765
|
-
function populateNewVaultMemory(
|
|
18198
|
+
function populateNewVaultMemory(record3, ctx, opts, encryptedContent, encryptedKindValue) {
|
|
17766
18199
|
const { level, scope } = resolveCreateLevel(opts);
|
|
17767
|
-
|
|
17768
|
-
|
|
17769
|
-
|
|
17770
|
-
|
|
17771
|
-
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
18200
|
+
record3._setRaw("content", encryptedContent);
|
|
18201
|
+
record3._setRaw("scope", scope);
|
|
18202
|
+
record3._setRaw("level", level);
|
|
18203
|
+
record3._setRaw("kind", opts.kind ?? null);
|
|
18204
|
+
record3._setRaw("kind_value", encryptedKindValue ?? null);
|
|
18205
|
+
record3._setRaw("folder_id", opts.folderId ?? null);
|
|
18206
|
+
record3._setRaw("user_id", ctx.userId ?? null);
|
|
18207
|
+
record3._setRaw("is_deleted", false);
|
|
17775
18208
|
if (opts.embedding !== void 0) {
|
|
17776
|
-
|
|
17777
|
-
|
|
18209
|
+
record3._setRaw("embedding", opts.embedding);
|
|
18210
|
+
record3._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
17778
18211
|
}
|
|
17779
18212
|
if (opts.sourceChunkIds !== void 0) {
|
|
17780
|
-
|
|
18213
|
+
record3._setRaw("source_chunk_ids", serializeSourceChunkIds(opts.sourceChunkIds));
|
|
17781
18214
|
}
|
|
17782
|
-
|
|
17783
|
-
|
|
18215
|
+
record3._setRaw("proof_count", opts.proofCount ?? 1);
|
|
18216
|
+
record3._setRaw("source", opts.source ?? "manual");
|
|
17784
18217
|
if (opts.eventTime) {
|
|
17785
|
-
|
|
17786
|
-
|
|
17787
|
-
|
|
18218
|
+
record3._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
18219
|
+
record3._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
18220
|
+
record3._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
17788
18221
|
}
|
|
17789
18222
|
if (opts.factType !== void 0) {
|
|
17790
|
-
|
|
18223
|
+
record3._setRaw("fact_type", opts.factType);
|
|
17791
18224
|
}
|
|
17792
18225
|
if (opts.trustTier !== void 0) {
|
|
17793
|
-
|
|
18226
|
+
record3._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
17794
18227
|
}
|
|
17795
|
-
|
|
17796
|
-
|
|
18228
|
+
record3._setRaw("visibility", opts.visibility ?? "private");
|
|
18229
|
+
record3._setRaw(
|
|
17797
18230
|
"published_at",
|
|
17798
18231
|
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
17799
18232
|
);
|
|
17800
18233
|
if (opts.geohash !== void 0) {
|
|
17801
|
-
|
|
18234
|
+
record3._setRaw("geohash", opts.geohash);
|
|
17802
18235
|
}
|
|
17803
18236
|
}
|
|
17804
18237
|
async function createVaultMemoryOp(ctx, opts) {
|
|
@@ -17813,7 +18246,7 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
17813
18246
|
const created = await ctx.database.write(async () => {
|
|
17814
18247
|
await assertCanWrite2(ctx);
|
|
17815
18248
|
return ctx.vaultMemoryCollection.create(
|
|
17816
|
-
(
|
|
18249
|
+
(record3) => populateNewVaultMemory(record3, ctx, opts, encryptedContent, encryptedKindValue)
|
|
17817
18250
|
);
|
|
17818
18251
|
});
|
|
17819
18252
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
@@ -17840,7 +18273,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
17840
18273
|
if (target.isDeleted || target.supersededBy || isKinded(target) || !isOwnedByCtxUser(ctx, target))
|
|
17841
18274
|
return;
|
|
17842
18275
|
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
17843
|
-
(
|
|
18276
|
+
(record3) => populateNewVaultMemory(record3, ctx, opts, encryptedContent, encryptedKindValue)
|
|
17844
18277
|
);
|
|
17845
18278
|
await target.update((r) => {
|
|
17846
18279
|
r._setRaw("superseded_by", createdRecord.id);
|
|
@@ -17925,7 +18358,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
17925
18358
|
await assertCanWrite2(ctx);
|
|
17926
18359
|
const prepared = optionsArray.map(
|
|
17927
18360
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
17928
|
-
(
|
|
18361
|
+
(record3) => populateNewVaultMemory(record3, ctx, opts, encryptedContents[i], encryptedKindValues[i])
|
|
17929
18362
|
)
|
|
17930
18363
|
);
|
|
17931
18364
|
await ctx.database.batch(...prepared);
|
|
@@ -17933,16 +18366,16 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
17933
18366
|
});
|
|
17934
18367
|
return Promise.all(
|
|
17935
18368
|
created.map(
|
|
17936
|
-
(
|
|
18369
|
+
(record3) => vaultMemoryToStored(record3, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
17937
18370
|
)
|
|
17938
18371
|
);
|
|
17939
18372
|
}
|
|
17940
18373
|
async function getVaultMemoryOp(ctx, id2) {
|
|
17941
18374
|
try {
|
|
17942
|
-
const
|
|
17943
|
-
if (
|
|
18375
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
18376
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return null;
|
|
17944
18377
|
return vaultMemoryToStored(
|
|
17945
|
-
|
|
18378
|
+
record3,
|
|
17946
18379
|
ctx.walletAddress,
|
|
17947
18380
|
ctx.signMessage,
|
|
17948
18381
|
ctx.embeddedWalletSigner
|
|
@@ -18281,29 +18714,29 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
18281
18714
|
ctx.embeddedWalletSigner
|
|
18282
18715
|
) : opts.content;
|
|
18283
18716
|
let stale = false;
|
|
18284
|
-
const
|
|
18717
|
+
const record3 = probe;
|
|
18285
18718
|
await ctx.database.write(async () => {
|
|
18286
18719
|
await assertCanWrite2(ctx);
|
|
18287
|
-
if (
|
|
18720
|
+
if (record3.isDeleted || record3.supersededBy || !isOwnedByCtxUser(ctx, record3) || opts.freeFormOnly && isKinded(record3) || opts.expectedContent !== void 0 && record3._getRaw("content") !== readStoredContent) {
|
|
18288
18721
|
stale = true;
|
|
18289
18722
|
return;
|
|
18290
18723
|
}
|
|
18291
|
-
const originalUpdatedAt =
|
|
18292
|
-
const nextKind = opts.kind !== void 0 ? opts.kind :
|
|
18293
|
-
const nextLevel = levelAfter(
|
|
18724
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
18725
|
+
const nextKind = opts.kind !== void 0 ? opts.kind : record3.kind;
|
|
18726
|
+
const nextLevel = levelAfter(record3);
|
|
18294
18727
|
assertValidKindLevel(nextKind, nextLevel);
|
|
18295
18728
|
let observedSources = [];
|
|
18296
18729
|
let replayedObservation = false;
|
|
18297
18730
|
if (opts.observationSourceIds?.length) {
|
|
18298
18731
|
try {
|
|
18299
|
-
const parsed = JSON.parse(
|
|
18732
|
+
const parsed = JSON.parse(record3.sourceChunkIds ?? "[]");
|
|
18300
18733
|
if (Array.isArray(parsed))
|
|
18301
18734
|
observedSources = parsed.filter((id3) => typeof id3 === "string");
|
|
18302
18735
|
} catch {
|
|
18303
18736
|
}
|
|
18304
18737
|
replayedObservation = opts.observationSourceIds.every((id3) => observedSources.includes(id3));
|
|
18305
18738
|
}
|
|
18306
|
-
await
|
|
18739
|
+
await record3.update((r) => {
|
|
18307
18740
|
if (encryptedContent !== void 0) r._setRaw("content", encryptedContent);
|
|
18308
18741
|
if (opts.level !== void 0) {
|
|
18309
18742
|
r._setRaw("level", nextLevel);
|
|
@@ -18370,7 +18803,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
18370
18803
|
});
|
|
18371
18804
|
if (stale) return null;
|
|
18372
18805
|
return vaultMemoryToStored(
|
|
18373
|
-
|
|
18806
|
+
record3,
|
|
18374
18807
|
ctx.walletAddress,
|
|
18375
18808
|
ctx.signMessage,
|
|
18376
18809
|
ctx.embeddedWalletSigner
|
|
@@ -18385,22 +18818,22 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
18385
18818
|
if (!entityCtx) {
|
|
18386
18819
|
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
18387
18820
|
}
|
|
18388
|
-
let
|
|
18821
|
+
let record3;
|
|
18389
18822
|
try {
|
|
18390
|
-
|
|
18823
|
+
record3 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
18391
18824
|
} catch {
|
|
18392
18825
|
return null;
|
|
18393
18826
|
}
|
|
18394
|
-
if (
|
|
18827
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return null;
|
|
18395
18828
|
let stale = false;
|
|
18396
|
-
const originalUpdatedAt =
|
|
18829
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
18397
18830
|
await ctx.database.write(async (writer) => {
|
|
18398
18831
|
await assertCanWrite2(ctx);
|
|
18399
|
-
if (
|
|
18832
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) {
|
|
18400
18833
|
stale = true;
|
|
18401
18834
|
return;
|
|
18402
18835
|
}
|
|
18403
|
-
await
|
|
18836
|
+
await record3.update((r) => {
|
|
18404
18837
|
r._setRaw("topics_user_managed", true);
|
|
18405
18838
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
18406
18839
|
});
|
|
@@ -18424,26 +18857,26 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
18424
18857
|
);
|
|
18425
18858
|
});
|
|
18426
18859
|
if (stale) return null;
|
|
18427
|
-
return vaultMemoryToStored(
|
|
18860
|
+
return vaultMemoryToStored(record3, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
18428
18861
|
}
|
|
18429
18862
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
18430
|
-
let
|
|
18863
|
+
let record3;
|
|
18431
18864
|
try {
|
|
18432
|
-
|
|
18865
|
+
record3 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
18433
18866
|
} catch {
|
|
18434
18867
|
return false;
|
|
18435
18868
|
}
|
|
18436
|
-
if (
|
|
18437
|
-
const originalUpdatedAt =
|
|
18869
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
18870
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
18438
18871
|
let cleared = false;
|
|
18439
18872
|
await ctx.database.write(async () => {
|
|
18440
18873
|
await assertCanWrite2(ctx);
|
|
18441
|
-
if (options?.unlessTopicsRecorded && parseTopics(
|
|
18874
|
+
if (options?.unlessTopicsRecorded && parseTopics(record3.topics) !== null) return;
|
|
18442
18875
|
cleared = true;
|
|
18443
|
-
await
|
|
18876
|
+
await record3.update((r) => {
|
|
18444
18877
|
r._setRaw("topics_user_managed", false);
|
|
18445
18878
|
r._setRaw("topics_extracted_version", null);
|
|
18446
|
-
if (
|
|
18879
|
+
if (record3.topicsExtractedAt === null) {
|
|
18447
18880
|
r._setRaw("topics_extracted_at", originalUpdatedAt);
|
|
18448
18881
|
}
|
|
18449
18882
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -18452,23 +18885,23 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
|
18452
18885
|
return cleared;
|
|
18453
18886
|
}
|
|
18454
18887
|
async function setMemoryVisibilityOp(ctx, id2, opts) {
|
|
18455
|
-
let
|
|
18888
|
+
let record3;
|
|
18456
18889
|
try {
|
|
18457
|
-
|
|
18890
|
+
record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
18458
18891
|
} catch {
|
|
18459
18892
|
return null;
|
|
18460
18893
|
}
|
|
18461
|
-
if (
|
|
18894
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return null;
|
|
18462
18895
|
let stale = false;
|
|
18463
18896
|
await ctx.database.write(async () => {
|
|
18464
18897
|
await assertCanWrite2(ctx);
|
|
18465
|
-
if (
|
|
18898
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) {
|
|
18466
18899
|
stale = true;
|
|
18467
18900
|
return;
|
|
18468
18901
|
}
|
|
18469
|
-
const currentUpdatedAt =
|
|
18470
|
-
const currentPublishedAt =
|
|
18471
|
-
await
|
|
18902
|
+
const currentUpdatedAt = record3.updatedAt.getTime();
|
|
18903
|
+
const currentPublishedAt = record3.publishedAt ?? null;
|
|
18904
|
+
await record3.update((r) => {
|
|
18472
18905
|
r._setRaw("visibility", opts.visibility);
|
|
18473
18906
|
if (opts.visibility === "private") {
|
|
18474
18907
|
r._setRaw("published_at", null);
|
|
@@ -18482,20 +18915,20 @@ async function setMemoryVisibilityOp(ctx, id2, opts) {
|
|
|
18482
18915
|
});
|
|
18483
18916
|
});
|
|
18484
18917
|
if (stale) return null;
|
|
18485
|
-
return vaultMemoryToStored(
|
|
18918
|
+
return vaultMemoryToStored(record3, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
18486
18919
|
}
|
|
18487
18920
|
async function deleteVaultMemoryOp(ctx, id2) {
|
|
18488
18921
|
try {
|
|
18489
|
-
const
|
|
18490
|
-
if (
|
|
18922
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
18923
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
18491
18924
|
let stale = false;
|
|
18492
18925
|
await ctx.database.write(async () => {
|
|
18493
18926
|
await assertCanWrite2(ctx);
|
|
18494
|
-
if (
|
|
18927
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) {
|
|
18495
18928
|
stale = true;
|
|
18496
18929
|
return;
|
|
18497
18930
|
}
|
|
18498
|
-
await
|
|
18931
|
+
await record3.update((r) => {
|
|
18499
18932
|
r._setRaw("is_deleted", true);
|
|
18500
18933
|
});
|
|
18501
18934
|
});
|
|
@@ -18514,9 +18947,9 @@ async function deleteVaultMemoryOp(ctx, id2) {
|
|
|
18514
18947
|
async function supersedeVaultMemoryOp(ctx, id2, supersededById) {
|
|
18515
18948
|
if (id2 === supersededById) return false;
|
|
18516
18949
|
try {
|
|
18517
|
-
const
|
|
18518
|
-
if (
|
|
18519
|
-
if (isKinded(
|
|
18950
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
18951
|
+
if (record3.isDeleted || record3.supersededBy || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
18952
|
+
if (isKinded(record3)) return false;
|
|
18520
18953
|
let successor;
|
|
18521
18954
|
try {
|
|
18522
18955
|
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
@@ -18529,7 +18962,7 @@ async function supersedeVaultMemoryOp(ctx, id2, supersededById) {
|
|
|
18529
18962
|
let stale = false;
|
|
18530
18963
|
await ctx.database.write(async () => {
|
|
18531
18964
|
await assertCanWrite2(ctx);
|
|
18532
|
-
if (
|
|
18965
|
+
if (record3.isDeleted || record3.supersededBy || !isOwnedByCtxUser(ctx, record3)) {
|
|
18533
18966
|
stale = true;
|
|
18534
18967
|
return;
|
|
18535
18968
|
}
|
|
@@ -18537,7 +18970,7 @@ async function supersedeVaultMemoryOp(ctx, id2, supersededById) {
|
|
|
18537
18970
|
stale = true;
|
|
18538
18971
|
return;
|
|
18539
18972
|
}
|
|
18540
|
-
await
|
|
18973
|
+
await record3.update((r) => {
|
|
18541
18974
|
r._setRaw("superseded_by", supersededById);
|
|
18542
18975
|
r._setRaw("superseded_at", Date.now());
|
|
18543
18976
|
});
|
|
@@ -18556,7 +18989,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
|
|
|
18556
18989
|
const results = await ctx.vaultMemoryCollection.query(...conditions).fetch();
|
|
18557
18990
|
return mapInBatches(
|
|
18558
18991
|
results,
|
|
18559
|
-
(
|
|
18992
|
+
(record3) => vaultMemoryToStored(record3, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
18560
18993
|
);
|
|
18561
18994
|
}
|
|
18562
18995
|
var TOPICS_EXTRACTION_VERSION = 3;
|
|
@@ -18717,17 +19150,17 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
18717
19150
|
}
|
|
18718
19151
|
}
|
|
18719
19152
|
const eligible = records.filter(
|
|
18720
|
-
(
|
|
19153
|
+
(record3) => !record3.isDeleted && isOwnedByCtxUser(ctx, record3) && !record3.topicsUserManaged
|
|
18721
19154
|
);
|
|
18722
|
-
const prepared = eligible.map((
|
|
18723
|
-
const originalUpdatedAt =
|
|
18724
|
-
return
|
|
19155
|
+
const prepared = eligible.map((record3) => {
|
|
19156
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
19157
|
+
return record3.prepareUpdate((r) => {
|
|
18725
19158
|
r._setRaw("topics_extracted_at", extractedAt);
|
|
18726
19159
|
r._setRaw("topics_extracted_version", version);
|
|
18727
19160
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
18728
19161
|
});
|
|
18729
19162
|
});
|
|
18730
|
-
for (const
|
|
19163
|
+
for (const record3 of eligible) stamped.push(record3.id);
|
|
18731
19164
|
if (prepared.length > 0) await ctx.database.batch(...prepared);
|
|
18732
19165
|
});
|
|
18733
19166
|
}
|
|
@@ -18743,14 +19176,14 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
|
18743
19176
|
try {
|
|
18744
19177
|
await ctx.database.write(async (writer) => {
|
|
18745
19178
|
await assertCanWrite2(ctx);
|
|
18746
|
-
let
|
|
19179
|
+
let record3;
|
|
18747
19180
|
try {
|
|
18748
|
-
|
|
19181
|
+
record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
18749
19182
|
} catch {
|
|
18750
19183
|
return;
|
|
18751
19184
|
}
|
|
18752
|
-
if (
|
|
18753
|
-
const topics = parseTopics(
|
|
19185
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return;
|
|
19186
|
+
const topics = parseTopics(record3.topics);
|
|
18754
19187
|
if (topics === null) return;
|
|
18755
19188
|
await writer.callWriter(() => relinkMemoryEntitiesFromTopicsOp(entityCtx, id2, topics));
|
|
18756
19189
|
relinked.push(id2);
|
|
@@ -18776,18 +19209,18 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
18776
19209
|
await assertCanWrite2(ctx);
|
|
18777
19210
|
const records = [];
|
|
18778
19211
|
for (const id2 of chunkIds) {
|
|
18779
|
-
let
|
|
19212
|
+
let record3;
|
|
18780
19213
|
try {
|
|
18781
|
-
|
|
19214
|
+
record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
18782
19215
|
} catch {
|
|
18783
19216
|
continue;
|
|
18784
19217
|
}
|
|
18785
|
-
if (
|
|
18786
|
-
if (parseTopics(
|
|
18787
|
-
records.push(
|
|
19218
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) continue;
|
|
19219
|
+
if (parseTopics(record3.topics) !== null) continue;
|
|
19220
|
+
records.push(record3);
|
|
18788
19221
|
}
|
|
18789
19222
|
if (records.length === 0) return;
|
|
18790
|
-
const links2 = await entityCtx.memoryEntityCollection.query(import_watermelondb21.Q.where("memory_id", import_watermelondb21.Q.oneOf(records.map((
|
|
19223
|
+
const links2 = await entityCtx.memoryEntityCollection.query(import_watermelondb21.Q.where("memory_id", import_watermelondb21.Q.oneOf(records.map((record3) => record3.id)))).unsafeFetchRaw();
|
|
18791
19224
|
const entityIds = Array.from(new Set(links2.map((link) => String(link.entity_id))));
|
|
18792
19225
|
const entitiesById = /* @__PURE__ */ new Map();
|
|
18793
19226
|
for (let j = 0; j < entityIds.length; j += CHUNK) {
|
|
@@ -18807,13 +19240,13 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
18807
19240
|
entities.add(entity);
|
|
18808
19241
|
}
|
|
18809
19242
|
const writes = [];
|
|
18810
|
-
for (const
|
|
18811
|
-
const entities = entitiesByMemory.get(
|
|
19243
|
+
for (const record3 of records) {
|
|
19244
|
+
const entities = entitiesByMemory.get(record3.id);
|
|
18812
19245
|
if (!entities?.size) continue;
|
|
18813
|
-
const source =
|
|
19246
|
+
const source = record3.topicsUserManaged ? "user" : "auto";
|
|
18814
19247
|
const write = await resolveMemoryTopicsWrite(
|
|
18815
19248
|
entityCtx,
|
|
18816
|
-
|
|
19249
|
+
record3.id,
|
|
18817
19250
|
Array.from(entities),
|
|
18818
19251
|
[],
|
|
18819
19252
|
source
|
|
@@ -18835,7 +19268,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
|
18835
19268
|
await ctx.database.write(async () => {
|
|
18836
19269
|
await assertCanWrite2(ctx);
|
|
18837
19270
|
const prepared = records.map(
|
|
18838
|
-
(
|
|
19271
|
+
(record3) => record3.prepareUpdate((r) => {
|
|
18839
19272
|
r._setRaw("is_deleted", true);
|
|
18840
19273
|
})
|
|
18841
19274
|
);
|
|
@@ -18906,22 +19339,22 @@ async function applyDecayTransitionsOp(ctx, candidates, opts) {
|
|
|
18906
19339
|
import_watermelondb21.Q.where("id", import_watermelondb21.Q.oneOf(ids.slice(i, i + CHUNK))),
|
|
18907
19340
|
...ctx.userId !== void 0 ? [import_watermelondb21.Q.where("user_id", ctx.userId)] : []
|
|
18908
19341
|
).fetch();
|
|
18909
|
-
const eligible = records.filter((
|
|
18910
|
-
if (
|
|
19342
|
+
const eligible = records.filter((record3) => {
|
|
19343
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
18911
19344
|
if (opts.transition === "delete") {
|
|
18912
|
-
return
|
|
19345
|
+
return record3.archivedAt !== null && opts.now - record3.archivedAt > opts.hardDeleteWindowMs;
|
|
18913
19346
|
}
|
|
18914
|
-
const candidate = byId.get(
|
|
18915
|
-
return
|
|
19347
|
+
const candidate = byId.get(record3.id);
|
|
19348
|
+
return record3.archivedAt === null && record3.updatedAt.getTime() === candidate.updatedAt && (record3.lastObservedAt ?? null) === (candidate.lastObservedAt ?? null);
|
|
18916
19349
|
});
|
|
18917
19350
|
const prepared = eligible.map(
|
|
18918
|
-
(
|
|
19351
|
+
(record3) => record3.prepareUpdate((row) => {
|
|
18919
19352
|
if (opts.transition === "archive") row._setRaw("archived_at", opts.now);
|
|
18920
19353
|
else row._setRaw("is_deleted", true);
|
|
18921
19354
|
})
|
|
18922
19355
|
);
|
|
18923
19356
|
if (prepared.length > 0) await ctx.database.batch(prepared);
|
|
18924
|
-
applied = eligible.map((
|
|
19357
|
+
applied = eligible.map((record3) => record3.id);
|
|
18925
19358
|
});
|
|
18926
19359
|
} catch {
|
|
18927
19360
|
continue;
|
|
@@ -18939,21 +19372,21 @@ async function applyDecayTransitionsOp(ctx, candidates, opts) {
|
|
|
18939
19372
|
}
|
|
18940
19373
|
async function archiveVaultMemoryOp(ctx, id2, opts) {
|
|
18941
19374
|
try {
|
|
18942
|
-
const
|
|
18943
|
-
if (
|
|
19375
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
19376
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
18944
19377
|
let stale = false;
|
|
18945
19378
|
const archivedAtValue = opts?.now ?? Date.now();
|
|
18946
19379
|
await ctx.database.write(async () => {
|
|
18947
19380
|
await assertCanWrite2(ctx);
|
|
18948
|
-
if (
|
|
19381
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3) || record3.archivedAt !== null) {
|
|
18949
19382
|
stale = true;
|
|
18950
19383
|
return;
|
|
18951
19384
|
}
|
|
18952
|
-
if (opts?.expectedUpdatedAt !== void 0 &&
|
|
19385
|
+
if (opts?.expectedUpdatedAt !== void 0 && record3.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record3.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
|
|
18953
19386
|
stale = true;
|
|
18954
19387
|
return;
|
|
18955
19388
|
}
|
|
18956
|
-
await
|
|
19389
|
+
await record3.update((r) => {
|
|
18957
19390
|
r._setRaw("archived_at", archivedAtValue);
|
|
18958
19391
|
});
|
|
18959
19392
|
});
|
|
@@ -18964,16 +19397,16 @@ async function archiveVaultMemoryOp(ctx, id2, opts) {
|
|
|
18964
19397
|
}
|
|
18965
19398
|
async function restoreVaultMemoryOp(ctx, id2) {
|
|
18966
19399
|
try {
|
|
18967
|
-
const
|
|
18968
|
-
if (
|
|
19400
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
19401
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
18969
19402
|
let stale = false;
|
|
18970
19403
|
await ctx.database.write(async () => {
|
|
18971
19404
|
await assertCanWrite2(ctx);
|
|
18972
|
-
if (
|
|
19405
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) {
|
|
18973
19406
|
stale = true;
|
|
18974
19407
|
return;
|
|
18975
19408
|
}
|
|
18976
|
-
await
|
|
19409
|
+
await record3.update((r) => {
|
|
18977
19410
|
r._setRaw("archived_at", null);
|
|
18978
19411
|
});
|
|
18979
19412
|
});
|
|
@@ -18984,18 +19417,18 @@ async function restoreVaultMemoryOp(ctx, id2) {
|
|
|
18984
19417
|
}
|
|
18985
19418
|
async function hardDeleteDecayedOp(ctx, id2, opts) {
|
|
18986
19419
|
try {
|
|
18987
|
-
const
|
|
18988
|
-
if (
|
|
19420
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
19421
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
18989
19422
|
const now = opts.now ?? Date.now();
|
|
18990
19423
|
let stale = false;
|
|
18991
19424
|
await ctx.database.write(async () => {
|
|
18992
19425
|
await assertCanWrite2(ctx);
|
|
18993
|
-
const archivedAt =
|
|
18994
|
-
if (
|
|
19426
|
+
const archivedAt = record3.archivedAt;
|
|
19427
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
|
|
18995
19428
|
stale = true;
|
|
18996
19429
|
return;
|
|
18997
19430
|
}
|
|
18998
|
-
await
|
|
19431
|
+
await record3.update((r) => {
|
|
18999
19432
|
r._setRaw("is_deleted", true);
|
|
19000
19433
|
});
|
|
19001
19434
|
});
|
|
@@ -19013,14 +19446,14 @@ async function hardDeleteDecayedOp(ctx, id2, opts) {
|
|
|
19013
19446
|
}
|
|
19014
19447
|
async function updateVaultMemoryEmbeddingOp(ctx, id2, embedding2, embeddingModel, expected) {
|
|
19015
19448
|
try {
|
|
19016
|
-
const
|
|
19017
|
-
if (
|
|
19018
|
-
const readUpdatedAt =
|
|
19019
|
-
const readStoredContent =
|
|
19449
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
19450
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
19451
|
+
const readUpdatedAt = record3.updatedAt.getTime();
|
|
19452
|
+
const readStoredContent = record3._getRaw("content");
|
|
19020
19453
|
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
19021
19454
|
if (expected?.content !== void 0) {
|
|
19022
19455
|
const current = await vaultMemoryToStored(
|
|
19023
|
-
|
|
19456
|
+
record3,
|
|
19024
19457
|
ctx.walletAddress,
|
|
19025
19458
|
ctx.signMessage,
|
|
19026
19459
|
ctx.embeddedWalletSigner
|
|
@@ -19030,11 +19463,11 @@ async function updateVaultMemoryEmbeddingOp(ctx, id2, embedding2, embeddingModel
|
|
|
19030
19463
|
let written = false;
|
|
19031
19464
|
await ctx.database.write(async () => {
|
|
19032
19465
|
await assertCanWrite2(ctx);
|
|
19033
|
-
if (
|
|
19034
|
-
const originalUpdatedAt =
|
|
19035
|
-
if (originalUpdatedAt !== readUpdatedAt ||
|
|
19466
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return;
|
|
19467
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
19468
|
+
if (originalUpdatedAt !== readUpdatedAt || record3._getRaw("content") !== readStoredContent)
|
|
19036
19469
|
return;
|
|
19037
|
-
await
|
|
19470
|
+
await record3.update((r) => {
|
|
19038
19471
|
r._setRaw("embedding", embedding2);
|
|
19039
19472
|
r._setRaw("embedding_model", embeddingModel);
|
|
19040
19473
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -19199,26 +19632,26 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
|
|
|
19199
19632
|
inserted = writable.length;
|
|
19200
19633
|
if (writable.length === 0) return;
|
|
19201
19634
|
const prepared = writable.map(
|
|
19202
|
-
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((
|
|
19203
|
-
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
|
|
19208
|
-
|
|
19209
|
-
|
|
19210
|
-
|
|
19211
|
-
|
|
19212
|
-
|
|
19635
|
+
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record3) => {
|
|
19636
|
+
record3._raw.id = row.memoryId;
|
|
19637
|
+
record3._setRaw("content", content);
|
|
19638
|
+
record3._setRaw("scope", "shared");
|
|
19639
|
+
record3._setRaw("level", "matching");
|
|
19640
|
+
record3._setRaw("folder_id", null);
|
|
19641
|
+
record3._setRaw("user_id", ctx.userId ?? null);
|
|
19642
|
+
record3._setRaw("is_deleted", false);
|
|
19643
|
+
record3._setRaw("proof_count", 1);
|
|
19644
|
+
record3._setRaw("source", SOURCE_PHOTO);
|
|
19645
|
+
record3._setRaw(
|
|
19213
19646
|
"media",
|
|
19214
19647
|
row.media && row.media.length > 0 ? JSON.stringify(row.media) : null
|
|
19215
19648
|
);
|
|
19216
|
-
|
|
19217
|
-
|
|
19649
|
+
record3._setRaw("visibility", "public");
|
|
19650
|
+
record3._setRaw("published_at", now);
|
|
19218
19651
|
if (row.eventTime) {
|
|
19219
|
-
|
|
19220
|
-
|
|
19221
|
-
|
|
19652
|
+
record3._setRaw("event_time_start", row.eventTime.start ?? null);
|
|
19653
|
+
record3._setRaw("event_time_end", row.eventTime.end ?? null);
|
|
19654
|
+
record3._setRaw("event_time_kind", row.eventTime.kind ?? null);
|
|
19222
19655
|
}
|
|
19223
19656
|
})
|
|
19224
19657
|
);
|
|
@@ -19583,11 +20016,11 @@ function folderToStored(folder) {
|
|
|
19583
20016
|
}
|
|
19584
20017
|
async function createVaultFolderOp(ctx, opts) {
|
|
19585
20018
|
const created = await ctx.database.write(async () => {
|
|
19586
|
-
return ctx.vaultFolderCollection.create((
|
|
19587
|
-
|
|
19588
|
-
|
|
19589
|
-
|
|
19590
|
-
|
|
20019
|
+
return ctx.vaultFolderCollection.create((record3) => {
|
|
20020
|
+
record3._setRaw("name", opts.name);
|
|
20021
|
+
record3._setRaw("scope", opts.scope ?? "private");
|
|
20022
|
+
record3._setRaw("is_system", opts.isSystem ?? false);
|
|
20023
|
+
record3._setRaw("is_deleted", false);
|
|
19591
20024
|
});
|
|
19592
20025
|
});
|
|
19593
20026
|
return folderToStored(created);
|
|
@@ -19598,14 +20031,14 @@ async function getAllVaultFoldersOp(ctx) {
|
|
|
19598
20031
|
}
|
|
19599
20032
|
async function updateVaultFolderOp(ctx, id2, opts) {
|
|
19600
20033
|
try {
|
|
19601
|
-
const
|
|
19602
|
-
if (
|
|
19603
|
-
const scopeChanged = opts.scope !== void 0 && opts.scope !==
|
|
20034
|
+
const record3 = await ctx.vaultFolderCollection.find(id2);
|
|
20035
|
+
if (record3.isDeleted) return null;
|
|
20036
|
+
const scopeChanged = opts.scope !== void 0 && opts.scope !== record3.scope;
|
|
19604
20037
|
const updated = await ctx.database.write(async () => {
|
|
19605
20038
|
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(import_watermelondb23.Q.where("folder_id", id2), import_watermelondb23.Q.where("is_deleted", false)).fetch() : [];
|
|
19606
20039
|
const updates = [];
|
|
19607
20040
|
updates.push(
|
|
19608
|
-
|
|
20041
|
+
record3.prepareUpdate((r) => {
|
|
19609
20042
|
if (opts.name !== void 0) r._setRaw("name", opts.name);
|
|
19610
20043
|
if (opts.scope !== void 0) r._setRaw("scope", opts.scope);
|
|
19611
20044
|
})
|
|
@@ -19628,8 +20061,8 @@ async function updateVaultFolderOp(ctx, id2, opts) {
|
|
|
19628
20061
|
}
|
|
19629
20062
|
async function deleteVaultFolderOp(ctx, id2) {
|
|
19630
20063
|
try {
|
|
19631
|
-
const
|
|
19632
|
-
if (
|
|
20064
|
+
const record3 = await ctx.vaultFolderCollection.find(id2);
|
|
20065
|
+
if (record3.isDeleted) return false;
|
|
19633
20066
|
await ctx.database.write(async () => {
|
|
19634
20067
|
const memories = await ctx.vaultMemoryCollection.query(import_watermelondb23.Q.where("folder_id", id2), import_watermelondb23.Q.where("is_deleted", false)).fetch();
|
|
19635
20068
|
const preparedMemories = memories.map(
|
|
@@ -19639,7 +20072,7 @@ async function deleteVaultFolderOp(ctx, id2) {
|
|
|
19639
20072
|
r._setRaw("scope", "private");
|
|
19640
20073
|
})
|
|
19641
20074
|
);
|
|
19642
|
-
const preparedFolder =
|
|
20075
|
+
const preparedFolder = record3.prepareUpdate((r) => {
|
|
19643
20076
|
r._setRaw("is_deleted", true);
|
|
19644
20077
|
});
|
|
19645
20078
|
await ctx.database.batch(...preparedMemories, preparedFolder);
|
|
@@ -19686,11 +20119,11 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
|
|
|
19686
20119
|
}
|
|
19687
20120
|
async function updateVaultFolderContextOp(ctx, id2, context) {
|
|
19688
20121
|
try {
|
|
19689
|
-
const
|
|
19690
|
-
if (
|
|
20122
|
+
const record3 = await ctx.vaultFolderCollection.find(id2);
|
|
20123
|
+
if (record3.isDeleted) return null;
|
|
19691
20124
|
const updated = await ctx.database.write(async () => {
|
|
19692
20125
|
await ctx.database.batch(
|
|
19693
|
-
|
|
20126
|
+
record3.prepareUpdate((r) => {
|
|
19694
20127
|
r._setRaw("context", context);
|
|
19695
20128
|
})
|
|
19696
20129
|
);
|
|
@@ -20806,9 +21239,9 @@ function loadVaultCorpus(ctx, options, preparation) {
|
|
|
20806
21239
|
const key3 = JSON.stringify(options ?? {});
|
|
20807
21240
|
let request = pending.get(key3);
|
|
20808
21241
|
if (!request) {
|
|
20809
|
-
const
|
|
21242
|
+
const entries2 = pending;
|
|
20810
21243
|
request = getAllVaultMemoriesOp(ctx, options).catch((error) => {
|
|
20811
|
-
|
|
21244
|
+
entries2.delete(key3);
|
|
20812
21245
|
throw error;
|
|
20813
21246
|
});
|
|
20814
21247
|
pending.set(key3, request);
|
|
@@ -20849,7 +21282,7 @@ function embedVaultRows(ctx, options, rows, preparation) {
|
|
|
20849
21282
|
if (!pending.has(keys[index]) && !prepared?.has(keys[index])) missing2.set(keys[index], row);
|
|
20850
21283
|
});
|
|
20851
21284
|
if (missing2.size > 0) {
|
|
20852
|
-
const
|
|
21285
|
+
const entries2 = pending;
|
|
20853
21286
|
const batch = Promise.resolve().then(
|
|
20854
21287
|
() => generateEmbeddings(
|
|
20855
21288
|
[...missing2.values()].map((row) => row.content),
|
|
@@ -20866,16 +21299,16 @@ function embedVaultRows(ctx, options, rows, preparation) {
|
|
|
20866
21299
|
});
|
|
20867
21300
|
return vector2;
|
|
20868
21301
|
}).finally(() => {
|
|
20869
|
-
|
|
20870
|
-
if (
|
|
21302
|
+
entries2.delete(key3);
|
|
21303
|
+
if (entries2.size === 0) pendingRows.get(ctx)?.delete(options.maskInput);
|
|
20871
21304
|
});
|
|
20872
21305
|
pending.set(key3, request);
|
|
20873
21306
|
});
|
|
20874
21307
|
}
|
|
20875
21308
|
return Promise.all(
|
|
20876
21309
|
keys.map((key3) => {
|
|
20877
|
-
const
|
|
20878
|
-
if (
|
|
21310
|
+
const cached2 = prepared?.get(key3);
|
|
21311
|
+
if (cached2) return cached2;
|
|
20879
21312
|
const request = pending.get(key3);
|
|
20880
21313
|
if (!prepared) return request;
|
|
20881
21314
|
const retained = request.catch((error) => {
|
|
@@ -21575,10 +22008,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
|
|
|
21575
22008
|
const resolvedThisCall = /* @__PURE__ */ new Set();
|
|
21576
22009
|
if (!embeddingsDegraded) {
|
|
21577
22010
|
for (const k2 of keys) {
|
|
21578
|
-
const
|
|
21579
|
-
if (
|
|
22011
|
+
const cached2 = cachedRowVector(cache, k2.uniqueId, k2.updatedAt);
|
|
22012
|
+
if (cached2 && cached2.length === queryEmbedding.length) {
|
|
21580
22013
|
corpusStats.cacheHits++;
|
|
21581
|
-
vectored.push({ uniqueId: k2.uniqueId, embedding:
|
|
22014
|
+
vectored.push({ uniqueId: k2.uniqueId, embedding: cached2, updatedAt: k2.updatedAt });
|
|
21582
22015
|
continue;
|
|
21583
22016
|
}
|
|
21584
22017
|
corpusStats.cacheMisses++;
|
|
@@ -21876,12 +22309,12 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
21876
22309
|
for (let i = 0; queryEmbedding.length > 0 && i < memories.length; i++) {
|
|
21877
22310
|
const content = memories[i].content;
|
|
21878
22311
|
const memoryId = memories[i].uniqueId;
|
|
21879
|
-
const
|
|
21880
|
-
if (
|
|
21881
|
-
resolvedVectors.set(memoryId,
|
|
22312
|
+
const cached2 = cachedRowVector(cache, memoryId, memories[i].updatedAt, content);
|
|
22313
|
+
if (cached2 && cached2.length === queryEmbedding.length) {
|
|
22314
|
+
resolvedVectors.set(memoryId, cached2);
|
|
21882
22315
|
continue;
|
|
21883
22316
|
}
|
|
21884
|
-
if (
|
|
22317
|
+
if (cached2) cache.delete(memoryId);
|
|
21885
22318
|
const storedModel = memories[i].embeddingModel;
|
|
21886
22319
|
const modelCompatible = (storedModel ?? currentModel) === currentModel;
|
|
21887
22320
|
if (memories[i].embedding && modelCompatible) {
|
|
@@ -23572,9 +24005,9 @@ function createDecaySweeperOver(backend, options) {
|
|
|
23572
24005
|
if (ruleVerdict !== "keep") return rule;
|
|
23573
24006
|
if (!classifier || !isBorderline(input)) return rule;
|
|
23574
24007
|
if (input.id) {
|
|
23575
|
-
const
|
|
23576
|
-
if (
|
|
23577
|
-
return { verdict:
|
|
24008
|
+
const cached2 = classifierCache.get(input.id);
|
|
24009
|
+
if (cached2 && cached2.activityAt === lastActivityAt(input))
|
|
24010
|
+
return { verdict: cached2.verdict, source: "classifierDriven" };
|
|
23578
24011
|
}
|
|
23579
24012
|
if (sweep.classifierCalls >= maxClassifierCalls) {
|
|
23580
24013
|
sweep.classifierCapHits++;
|
|
@@ -25412,21 +25845,21 @@ async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
|
25412
25845
|
};
|
|
25413
25846
|
const inputs = [];
|
|
25414
25847
|
for (const id2 of new Set(memoryIds)) {
|
|
25415
|
-
let
|
|
25848
|
+
let record3;
|
|
25416
25849
|
try {
|
|
25417
|
-
|
|
25850
|
+
record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
25418
25851
|
} catch (err) {
|
|
25419
25852
|
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
25420
25853
|
skip(id2, "not-found");
|
|
25421
25854
|
continue;
|
|
25422
25855
|
}
|
|
25423
|
-
if (
|
|
25856
|
+
if (record3.isDeleted || ctx.userId !== void 0 && record3.userId !== ctx.userId || record3.topicsUserManaged) {
|
|
25424
25857
|
skip(id2, "excluded");
|
|
25425
25858
|
continue;
|
|
25426
25859
|
}
|
|
25427
25860
|
try {
|
|
25428
25861
|
const stored2 = await vaultMemoryToStored(
|
|
25429
|
-
|
|
25862
|
+
record3,
|
|
25430
25863
|
ctx.walletAddress,
|
|
25431
25864
|
ctx.signMessage,
|
|
25432
25865
|
ctx.embeddedWalletSigner
|
|
@@ -25733,6 +26166,7 @@ function createLocalMemoryStore(options) {
|
|
|
25733
26166
|
|
|
25734
26167
|
// src/lib/memory/store/memoryKeys.ts
|
|
25735
26168
|
var KEY_ID_DOMAIN = "anuma-private-memory-key-id-v1";
|
|
26169
|
+
var TOPIC_HASH_INFO = "anuma-private-memory-topic-hash-v1";
|
|
25736
26170
|
var MemoryKeyError = class extends Error {
|
|
25737
26171
|
constructor(message) {
|
|
25738
26172
|
super(message);
|
|
@@ -25748,17 +26182,40 @@ async function importAesKey(hex) {
|
|
|
25748
26182
|
["encrypt", "decrypt"]
|
|
25749
26183
|
);
|
|
25750
26184
|
}
|
|
26185
|
+
async function deriveTopicHashKey(hex) {
|
|
26186
|
+
const material = await crypto.subtle.importKey(
|
|
26187
|
+
"raw",
|
|
26188
|
+
hexToBytes(hex).buffer,
|
|
26189
|
+
{ name: "HKDF" },
|
|
26190
|
+
false,
|
|
26191
|
+
["deriveBits"]
|
|
26192
|
+
);
|
|
26193
|
+
const bits = await crypto.subtle.deriveBits(
|
|
26194
|
+
{
|
|
26195
|
+
name: "HKDF",
|
|
26196
|
+
hash: "SHA-256",
|
|
26197
|
+
salt: new Uint8Array(32),
|
|
26198
|
+
info: new TextEncoder().encode(TOPIC_HASH_INFO)
|
|
26199
|
+
},
|
|
26200
|
+
material,
|
|
26201
|
+
256
|
|
26202
|
+
);
|
|
26203
|
+
return crypto.subtle.importKey("raw", bits, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
26204
|
+
}
|
|
26205
|
+
function toHex(bytes4) {
|
|
26206
|
+
return Array.from(new Uint8Array(bytes4), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
26207
|
+
}
|
|
25751
26208
|
async function deriveMemoryKeyRing(signatureHex) {
|
|
25752
26209
|
const v3Hex = await deriveKeyFromSignatureV3(signatureHex);
|
|
25753
26210
|
const digest = await crypto.subtle.digest(
|
|
25754
26211
|
"SHA-256",
|
|
25755
26212
|
new TextEncoder().encode(`${KEY_ID_DOMAIN}:${v3Hex}`)
|
|
25756
26213
|
);
|
|
25757
|
-
const keyId = "v3:" + Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
25758
26214
|
return {
|
|
25759
|
-
keyId,
|
|
26215
|
+
keyId: "v3:" + toHex(digest),
|
|
25760
26216
|
v3: await importAesKey(v3Hex),
|
|
25761
|
-
v2: await importAesKey(await deriveKeyFromSignature(signatureHex))
|
|
26217
|
+
v2: await importAesKey(await deriveKeyFromSignature(signatureHex)),
|
|
26218
|
+
topicHash: await deriveTopicHashKey(v3Hex)
|
|
25762
26219
|
};
|
|
25763
26220
|
}
|
|
25764
26221
|
async function decryptWith(value, rings) {
|
|
@@ -25779,7 +26236,10 @@ function memoryCipher(canonical) {
|
|
|
25779
26236
|
if (!ciphertext.startsWith("enc:v3:") || !isEncrypted(ciphertext))
|
|
25780
26237
|
throw new MemoryKeyError("Remote memory content must be enc:v3 ciphertext");
|
|
25781
26238
|
return decryptWith(ciphertext, [canonical]);
|
|
25782
|
-
}
|
|
26239
|
+
},
|
|
26240
|
+
hashTopic: async (normalized2) => toHex(
|
|
26241
|
+
await crypto.subtle.sign("HMAC", canonical.topicHash, new TextEncoder().encode(normalized2))
|
|
26242
|
+
)
|
|
25783
26243
|
};
|
|
25784
26244
|
}
|
|
25785
26245
|
async function reencryptMemoryField(value, canonical, fallbacks = []) {
|
|
@@ -26215,8 +26675,9 @@ var DEFAULT_RATE_LIMIT_WAIT_MS = 1e4;
|
|
|
26215
26675
|
var MAX_ID_BYTES = 128;
|
|
26216
26676
|
var MAX_CONTENT_BYTES = 32 << 10;
|
|
26217
26677
|
var MAX_TEXT_BYTES = 16 << 10;
|
|
26678
|
+
var MAX_TOPICS_BYTES = 32 << 10;
|
|
26218
26679
|
var MAX_SHORT_BYTES = 256;
|
|
26219
|
-
var TEXT_FIELDS = ["
|
|
26680
|
+
var TEXT_FIELDS = ["media", "source_chunk_ids"];
|
|
26220
26681
|
var SHORT_FIELDS = [
|
|
26221
26682
|
"scope",
|
|
26222
26683
|
"kind",
|
|
@@ -26319,7 +26780,7 @@ function bytes3(value) {
|
|
|
26319
26780
|
return value === void 0 ? 0 : utf82.encode(value).length;
|
|
26320
26781
|
}
|
|
26321
26782
|
function fitsNearby(row) {
|
|
26322
|
-
return bytes3(row.memory_id) <= MAX_ID_BYTES && bytes3(row.content) <= MAX_CONTENT_BYTES && bytes3(row.kind_value) <= MAX_CONTENT_BYTES && TEXT_FIELDS.every((field10) => bytes3(row[field10]) <= MAX_TEXT_BYTES) && SHORT_FIELDS.every((field10) => bytes3(row[field10]) <= MAX_SHORT_BYTES);
|
|
26783
|
+
return bytes3(row.memory_id) <= MAX_ID_BYTES && bytes3(row.content) <= MAX_CONTENT_BYTES && bytes3(row.kind_value) <= MAX_CONTENT_BYTES && bytes3(row.topics) <= MAX_TOPICS_BYTES && sealedTopicNamesFit(row.topics) && TEXT_FIELDS.every((field10) => bytes3(row[field10]) <= MAX_TEXT_BYTES) && SHORT_FIELDS.every((field10) => bytes3(row[field10]) <= MAX_SHORT_BYTES);
|
|
26323
26784
|
}
|
|
26324
26785
|
function invalid2(raw) {
|
|
26325
26786
|
const id2 = raw.id;
|
|
@@ -26363,7 +26824,7 @@ function defined(value) {
|
|
|
26363
26824
|
Object.entries(value).filter(([, field10]) => field10 !== void 0)
|
|
26364
26825
|
);
|
|
26365
26826
|
}
|
|
26366
|
-
async function prepareRow(raw, canonical, rings, model, updatedAt) {
|
|
26827
|
+
async function prepareRow(raw, canonical, codec, rings, model, updatedAt) {
|
|
26367
26828
|
const deleted = bool(raw.is_deleted) ?? false;
|
|
26368
26829
|
const { encrypt } = memoryCipher(canonical);
|
|
26369
26830
|
const localKindValue = text15(raw.kind_value);
|
|
@@ -26377,10 +26838,12 @@ async function prepareRow(raw, canonical, rings, model, updatedAt) {
|
|
|
26377
26838
|
plaintext = void 0;
|
|
26378
26839
|
kindValue = void 0;
|
|
26379
26840
|
}
|
|
26841
|
+
const fields = metadata2(raw, model);
|
|
26380
26842
|
const row = {
|
|
26381
26843
|
...defined({
|
|
26382
|
-
...
|
|
26383
|
-
kind_value: kindValue === void 0 ? void 0 : await encrypt(kindValue)
|
|
26844
|
+
...fields,
|
|
26845
|
+
kind_value: kindValue === void 0 ? void 0 : await encrypt(kindValue),
|
|
26846
|
+
topics: fields.topics === void 0 ? void 0 : await codec.encodeTopics(fields.topics)
|
|
26384
26847
|
}),
|
|
26385
26848
|
memory_id: raw.id,
|
|
26386
26849
|
content: await encrypt(plaintext ?? ""),
|
|
@@ -26424,6 +26887,8 @@ function sameMetadata2(local, remote, model) {
|
|
|
26424
26887
|
if (field10 === "visibility") return (a ?? "private") === (b ?? "private");
|
|
26425
26888
|
if (field10 === "is_deleted" || field10 === "topics_user_managed" || field10 === "twin_opt_in")
|
|
26426
26889
|
return (a ?? false) === (b ?? false);
|
|
26890
|
+
if (field10 === "topics")
|
|
26891
|
+
return JSON.stringify(parseTopics(a)) === JSON.stringify(parseTopics(b));
|
|
26427
26892
|
return a === b;
|
|
26428
26893
|
});
|
|
26429
26894
|
}
|
|
@@ -26479,7 +26944,7 @@ async function missingIds(request, revisions, signal) {
|
|
|
26479
26944
|
}
|
|
26480
26945
|
return missing2;
|
|
26481
26946
|
}
|
|
26482
|
-
async function remoteMetadata(request, ids, signal) {
|
|
26947
|
+
async function remoteMetadata(request, codec, ids, signal) {
|
|
26483
26948
|
const rows = /* @__PURE__ */ new Map();
|
|
26484
26949
|
for (const batch of chunks(ids, QUERY_IDS)) {
|
|
26485
26950
|
let cursor;
|
|
@@ -26503,7 +26968,12 @@ async function remoteMetadata(request, ids, signal) {
|
|
|
26503
26968
|
if (!Array.isArray(page.items)) throw new Error("Invalid nearby private-memory page");
|
|
26504
26969
|
for (const item of page.items)
|
|
26505
26970
|
if (item.memory && typeof item.memory.memory_id === "string")
|
|
26506
|
-
rows.set(item.memory.memory_id,
|
|
26971
|
+
rows.set(item.memory.memory_id, {
|
|
26972
|
+
...item.memory,
|
|
26973
|
+
...typeof item.memory.topics === "string" && {
|
|
26974
|
+
topics: await codec.decodeTopics(item.memory.topics).catch(() => null)
|
|
26975
|
+
}
|
|
26976
|
+
});
|
|
26507
26977
|
cursor = typeof page.next_cursor === "string" ? page.next_cursor : void 0;
|
|
26508
26978
|
} while (cursor);
|
|
26509
26979
|
}
|
|
@@ -26521,6 +26991,7 @@ async function migrateMemoriesToRemote(options) {
|
|
|
26521
26991
|
const rings = [canonical, ...options.fallbacks ?? []];
|
|
26522
26992
|
const model = options.embeddingOptions?.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
26523
26993
|
const request = createNearbyRequest(options);
|
|
26994
|
+
const codec = createTopicCodec(memoryCipher(canonical));
|
|
26524
26995
|
const account = await request("/account", {}, signal);
|
|
26525
26996
|
if (typeof account.key_id === "string" && account.key_id !== canonical.keyId)
|
|
26526
26997
|
throw new RemoteMemoryError(
|
|
@@ -26537,7 +27008,7 @@ async function migrateMemoriesToRemote(options) {
|
|
|
26537
27008
|
...typeof t.kind === "string" && { kind: t.kind }
|
|
26538
27009
|
})).filter((t) => t.name.length > 0) : []);
|
|
26539
27010
|
if (localTopics.length)
|
|
26540
|
-
await createRemoteTopicPersistence(request).importTopics(localTopics, signal);
|
|
27011
|
+
await createRemoteTopicPersistence(request, codec).importTopics(localTopics, signal);
|
|
26541
27012
|
const skipped = /* @__PURE__ */ new Map();
|
|
26542
27013
|
const reembedded = /* @__PURE__ */ new Set();
|
|
26543
27014
|
const unembedded = /* @__PURE__ */ new Set();
|
|
@@ -26556,6 +27027,7 @@ async function migrateMemoriesToRemote(options) {
|
|
|
26556
27027
|
if (pending.size === 0 && !active) {
|
|
26557
27028
|
const remote = await remoteMetadata(
|
|
26558
27029
|
request,
|
|
27030
|
+
codec,
|
|
26559
27031
|
candidates.map((raw) => raw.id),
|
|
26560
27032
|
signal
|
|
26561
27033
|
);
|
|
@@ -26600,7 +27072,7 @@ async function migrateMemoriesToRemote(options) {
|
|
|
26600
27072
|
const updatedAt = pending.get(raw.id);
|
|
26601
27073
|
if (updatedAt === void 0) continue;
|
|
26602
27074
|
try {
|
|
26603
|
-
prepared.push(await prepareRow(raw, canonical, rings, model, updatedAt));
|
|
27075
|
+
prepared.push(await prepareRow(raw, canonical, codec, rings, model, updatedAt));
|
|
26604
27076
|
} catch (error) {
|
|
26605
27077
|
if (!(error instanceof MemoryKeyError)) throw error;
|
|
26606
27078
|
skipped.set(raw.id, "unreadable");
|
|
@@ -26760,7 +27232,7 @@ function topicInputs(topics, source) {
|
|
|
26760
27232
|
function mergeTopics(existing, added) {
|
|
26761
27233
|
const byName = /* @__PURE__ */ new Map();
|
|
26762
27234
|
for (const topic2 of [...existing, ...added]) {
|
|
26763
|
-
const key3 =
|
|
27235
|
+
const key3 = normalizeTopicName(topic2.name);
|
|
26764
27236
|
const kept = byName.get(key3);
|
|
26765
27237
|
if (!kept) byName.set(key3, topic2);
|
|
26766
27238
|
else if (kept.weight !== void 0 && topic2.weight !== void 0 && topic2.weight > kept.weight)
|
|
@@ -26775,7 +27247,7 @@ function sameTopics(stored2, next) {
|
|
|
26775
27247
|
return next.every((t) => keys.has(key3(t)));
|
|
26776
27248
|
}
|
|
26777
27249
|
function canonicalTopics(row) {
|
|
26778
|
-
return new Set((parseTopics(row.topics) ?? []).map((topic2) =>
|
|
27250
|
+
return new Set((parseTopics(row.topics) ?? []).map((topic2) => normalizeTopicName(topic2.name)));
|
|
26779
27251
|
}
|
|
26780
27252
|
function createRemoteMemoryStore(options) {
|
|
26781
27253
|
const { persistence, embeddingOptions } = options;
|
|
@@ -26822,10 +27294,10 @@ function createRemoteMemoryStore(options) {
|
|
|
26822
27294
|
const notify = (change, records = []) => {
|
|
26823
27295
|
invalidateReads();
|
|
26824
27296
|
if (subscribers.size)
|
|
26825
|
-
for (const
|
|
26826
|
-
const previous = seen.get(
|
|
26827
|
-
if ((previous?.version ?? 0) + 1 ===
|
|
26828
|
-
seen.set(
|
|
27297
|
+
for (const record3 of records) {
|
|
27298
|
+
const previous = seen.get(record3.memory.memory_id);
|
|
27299
|
+
if ((previous?.version ?? 0) + 1 === record3.version)
|
|
27300
|
+
seen.set(record3.memory.memory_id, subscriptionState(record3));
|
|
26829
27301
|
}
|
|
26830
27302
|
for (const subscriber of [...subscribers])
|
|
26831
27303
|
if (relevant(change, subscriber.options)) safely(subscriber.onChange);
|
|
@@ -26878,7 +27350,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26878
27350
|
};
|
|
26879
27351
|
const enumerate = (filters, max = Infinity) => pages(decrypted, filters, max);
|
|
26880
27352
|
const memoriesByTopics = async (names) => {
|
|
26881
|
-
const wanted = new Set(names.map(
|
|
27353
|
+
const wanted = new Set(names.map(normalizeTopicName).filter(Boolean));
|
|
26882
27354
|
const out = /* @__PURE__ */ new Map();
|
|
26883
27355
|
const pages2 = await Promise.all(
|
|
26884
27356
|
chunks2([...wanted], MAX_QUERY_TOPICS).map((topics) => enumerate({ topics }))
|
|
@@ -26890,7 +27362,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26890
27362
|
return out;
|
|
26891
27363
|
};
|
|
26892
27364
|
const topicGraphRanking = async (query, recallOptions = {}) => {
|
|
26893
|
-
const wanted = new Set(extractQueryEntities(query).map(
|
|
27365
|
+
const wanted = new Set(extractQueryEntities(query).map(normalizeTopicName).filter(Boolean));
|
|
26894
27366
|
if (wanted.size === 0 || recallOptions.memoryIds?.length === 0) return [];
|
|
26895
27367
|
const rows = await pages(
|
|
26896
27368
|
metadata3,
|
|
@@ -26948,25 +27420,25 @@ function createRemoteMemoryStore(options) {
|
|
|
26948
27420
|
return run;
|
|
26949
27421
|
};
|
|
26950
27422
|
const live2 = async (id2) => {
|
|
26951
|
-
const
|
|
26952
|
-
return
|
|
27423
|
+
const record3 = await persistence.get(id2);
|
|
27424
|
+
return record3 && !record3.memory.is_deleted ? record3 : null;
|
|
26953
27425
|
};
|
|
26954
27426
|
const mutateLocked = async (id2, change, edit, writeOptions) => {
|
|
26955
27427
|
writeOptions?.signal?.throwIfAborted();
|
|
26956
|
-
const
|
|
26957
|
-
if (!
|
|
26958
|
-
if (
|
|
27428
|
+
const record3 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await live2(id2);
|
|
27429
|
+
if (!record3) return null;
|
|
27430
|
+
if (record3.memory.is_deleted) return null;
|
|
26959
27431
|
if (writeOptions?.canWrite && !await writeOptions.canWrite())
|
|
26960
27432
|
throw new MemorySourceIneligibleError();
|
|
26961
27433
|
writeOptions?.signal?.throwIfAborted();
|
|
26962
|
-
const next = edit(structuredClone(
|
|
27434
|
+
const next = edit(structuredClone(record3.memory));
|
|
26963
27435
|
if (!next) return null;
|
|
26964
27436
|
const saved = writeOptions?.leaseToken ? (await persistence.putMany(
|
|
26965
|
-
[{ memory: next, expectedVersion:
|
|
27437
|
+
[{ memory: next, expectedVersion: record3 }],
|
|
26966
27438
|
writeOptions.signal,
|
|
26967
27439
|
writeOptions.leaseToken
|
|
26968
|
-
))[0] : writeOptions?.signal ? await persistence.put(next,
|
|
26969
|
-
notify(typeof change === "function" ? change(
|
|
27440
|
+
))[0] : writeOptions?.signal ? await persistence.put(next, record3, writeOptions.signal) : await persistence.put(next, record3);
|
|
27441
|
+
notify(typeof change === "function" ? change(record3.memory) : change, [saved]);
|
|
26970
27442
|
return saved;
|
|
26971
27443
|
};
|
|
26972
27444
|
const mutate = (id2, change, edit, writeOptions) => serialized(id2, () => mutateLocked(id2, change, edit, writeOptions));
|
|
@@ -26988,12 +27460,12 @@ function createRemoteMemoryStore(options) {
|
|
|
26988
27460
|
}
|
|
26989
27461
|
const { records, unreadable } = read;
|
|
26990
27462
|
for (const id2 of slice) {
|
|
26991
|
-
const
|
|
27463
|
+
const record3 = records.get(id2);
|
|
26992
27464
|
if (unreadable.has(id2)) failed.set(id2, new Error(`Memory ${id2} could not be decrypted`));
|
|
26993
|
-
else if (!
|
|
26994
|
-
else if (!
|
|
26995
|
-
const memory = edit(structuredClone(
|
|
26996
|
-
if (memory) writes.push({ before:
|
|
27465
|
+
else if (!record3) failed.set(id2, new Error(`Memory ${id2} was not found`));
|
|
27466
|
+
else if (!record3.memory.is_deleted) {
|
|
27467
|
+
const memory = edit(structuredClone(record3.memory));
|
|
27468
|
+
if (memory) writes.push({ before: record3, memory });
|
|
26997
27469
|
}
|
|
26998
27470
|
}
|
|
26999
27471
|
if (writes.length === 0) return;
|
|
@@ -27004,10 +27476,10 @@ function createRemoteMemoryStore(options) {
|
|
|
27004
27476
|
leaseToken
|
|
27005
27477
|
);
|
|
27006
27478
|
const byChange = /* @__PURE__ */ new Map();
|
|
27007
|
-
written.forEach((
|
|
27008
|
-
saved.set(
|
|
27479
|
+
written.forEach((record3, i) => {
|
|
27480
|
+
saved.set(record3.memory.memory_id, record3);
|
|
27009
27481
|
const kind = change(writes[i].before.memory);
|
|
27010
|
-
byChange.set(kind, [...byChange.get(kind) ?? [],
|
|
27482
|
+
byChange.set(kind, [...byChange.get(kind) ?? [], record3]);
|
|
27011
27483
|
});
|
|
27012
27484
|
for (const [kind, changed] of byChange) notify(kind, changed);
|
|
27013
27485
|
} catch (error) {
|
|
@@ -27021,13 +27493,13 @@ function createRemoteMemoryStore(options) {
|
|
|
27021
27493
|
continue;
|
|
27022
27494
|
}
|
|
27023
27495
|
try {
|
|
27024
|
-
const
|
|
27496
|
+
const record3 = await mutateLocked(
|
|
27025
27497
|
id2,
|
|
27026
27498
|
change,
|
|
27027
27499
|
edit,
|
|
27028
27500
|
leaseToken || signal ? { leaseToken, signal } : void 0
|
|
27029
27501
|
);
|
|
27030
|
-
if (
|
|
27502
|
+
if (record3) saved.set(id2, record3);
|
|
27031
27503
|
} catch (rowError) {
|
|
27032
27504
|
signal?.throwIfAborted();
|
|
27033
27505
|
if (isRemoteWorkLeaseExpired(rowError)) throw rowError;
|
|
@@ -27123,12 +27595,12 @@ function createRemoteMemoryStore(options) {
|
|
|
27123
27595
|
const created = (records, inputs) => {
|
|
27124
27596
|
embedInBackground(records.filter((_, i) => inputs[i].embedding === void 0));
|
|
27125
27597
|
notify("membership", records);
|
|
27126
|
-
return records.map((
|
|
27598
|
+
return records.map((record3) => stored(record3.memory));
|
|
27127
27599
|
};
|
|
27128
|
-
const asStored = (
|
|
27600
|
+
const asStored = (record3) => record3 ? stored(record3.memory) : null;
|
|
27129
27601
|
const knownKinds = async (topics, signal) => {
|
|
27130
27602
|
const unkinded = [
|
|
27131
|
-
...new Set(topics.filter((t) => !t.kind).map((t) =>
|
|
27603
|
+
...new Set(topics.filter((t) => !t.kind).map((t) => normalizeTopicName(t.name)))
|
|
27132
27604
|
];
|
|
27133
27605
|
const kinds2 = /* @__PURE__ */ new Map();
|
|
27134
27606
|
for (const names of chunks2(unkinded, MAX_QUERY_TOPICS)) {
|
|
@@ -27140,13 +27612,13 @@ function createRemoteMemoryStore(options) {
|
|
|
27140
27612
|
...signal && { signal }
|
|
27141
27613
|
})) {
|
|
27142
27614
|
for (const topic2 of parseTopics(memory.topics) ?? []) {
|
|
27143
|
-
const name =
|
|
27615
|
+
const name = normalizeTopicName(topic2.name);
|
|
27144
27616
|
if (topic2.kind && !kinds2.has(name)) kinds2.set(name, topic2.kind);
|
|
27145
27617
|
}
|
|
27146
27618
|
}
|
|
27147
27619
|
}
|
|
27148
27620
|
return (topic2) => {
|
|
27149
|
-
const kind = topic2.kind ?? kinds2.get(
|
|
27621
|
+
const kind = topic2.kind ?? kinds2.get(normalizeTopicName(topic2.name));
|
|
27150
27622
|
return kind ? { ...topic2, kind } : topic2;
|
|
27151
27623
|
};
|
|
27152
27624
|
};
|
|
@@ -27169,7 +27641,7 @@ function createRemoteMemoryStore(options) {
|
|
|
27169
27641
|
...cursor2 && { cursor: cursor2 }
|
|
27170
27642
|
});
|
|
27171
27643
|
warnFailed(page.failed);
|
|
27172
|
-
for (const
|
|
27644
|
+
for (const record3 of page.items) records.set(record3.memory.memory_id, record3);
|
|
27173
27645
|
for (const failure of page.failed) unreadable.add(failure.memory_id);
|
|
27174
27646
|
cursor2 = page.next_cursor;
|
|
27175
27647
|
} while (cursor2);
|
|
@@ -27365,8 +27837,8 @@ function createRemoteMemoryStore(options) {
|
|
|
27365
27837
|
const failed = /* @__PURE__ */ new Map();
|
|
27366
27838
|
const collect = (page) => {
|
|
27367
27839
|
warnFailed(page.failed);
|
|
27368
|
-
for (const
|
|
27369
|
-
records.push({ id:
|
|
27840
|
+
for (const record3 of page.items)
|
|
27841
|
+
records.push({ id: record3.memory.memory_id, state: subscriptionState(record3) });
|
|
27370
27842
|
for (const failure of page.failed) failed.set(failure.memory_id, failure.version);
|
|
27371
27843
|
};
|
|
27372
27844
|
let resume = cursor2;
|
|
@@ -27571,7 +28043,7 @@ function createRemoteMemoryStore(options) {
|
|
|
27571
28043
|
result.failed += targets.length;
|
|
27572
28044
|
return finish();
|
|
27573
28045
|
}
|
|
27574
|
-
const writes = targets.flatMap((
|
|
28046
|
+
const writes = targets.flatMap((record3, i) => {
|
|
27575
28047
|
const vector2 = vectors[i];
|
|
27576
28048
|
if (!vector2) {
|
|
27577
28049
|
result.failed++;
|
|
@@ -27581,11 +28053,11 @@ function createRemoteMemoryStore(options) {
|
|
|
27581
28053
|
return [
|
|
27582
28054
|
{
|
|
27583
28055
|
memory: {
|
|
27584
|
-
...
|
|
28056
|
+
...record3.memory,
|
|
27585
28057
|
embedding: storedVector(vector2),
|
|
27586
28058
|
embedding_model: model
|
|
27587
28059
|
},
|
|
27588
|
-
expectedVersion:
|
|
28060
|
+
expectedVersion: record3
|
|
27589
28061
|
}
|
|
27590
28062
|
];
|
|
27591
28063
|
} catch {
|
|
@@ -27600,7 +28072,7 @@ function createRemoteMemoryStore(options) {
|
|
|
27600
28072
|
signal?.throwIfAborted();
|
|
27601
28073
|
const commit = async (slice) => {
|
|
27602
28074
|
const saved = await persistence.putMany(slice, signal, leaseToken);
|
|
27603
|
-
for (const
|
|
28075
|
+
for (const record3 of saved) repaired.add(record3.memory.memory_id);
|
|
27604
28076
|
result.reembedded += saved.length;
|
|
27605
28077
|
notify("embedding", saved);
|
|
27606
28078
|
};
|
|
@@ -27684,7 +28156,7 @@ function createRemoteMemoryStore(options) {
|
|
|
27684
28156
|
if (!topics.length) return;
|
|
27685
28157
|
const existing = new Set((await readTopics()).map((topic2) => topic2.name));
|
|
27686
28158
|
const missing2 = topics.flatMap((topic2) => {
|
|
27687
|
-
const name =
|
|
28159
|
+
const name = normalizeTopicName(topic2.name);
|
|
27688
28160
|
if (existing.has(name)) return [];
|
|
27689
28161
|
existing.add(name);
|
|
27690
28162
|
return [{ ...topic2, name }];
|
|
@@ -27715,7 +28187,7 @@ function createRemoteMemoryStore(options) {
|
|
|
27715
28187
|
include_superseded: true
|
|
27716
28188
|
})) {
|
|
27717
28189
|
for (const topic2 of parseTopics(memory.topics) ?? []) {
|
|
27718
|
-
const name =
|
|
28190
|
+
const name = normalizeTopicName(topic2.name);
|
|
27719
28191
|
if (!name) continue;
|
|
27720
28192
|
const entry = topics.get(name) ?? {
|
|
27721
28193
|
name,
|
|
@@ -27753,7 +28225,7 @@ function createRemoteMemoryStore(options) {
|
|
|
27753
28225
|
},
|
|
27754
28226
|
get: async (id2) => asStored(await live2(id2)),
|
|
27755
28227
|
listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
|
|
27756
|
-
(
|
|
28228
|
+
(record3) => stored(record3.memory)
|
|
27757
28229
|
),
|
|
27758
28230
|
memoriesByTopics,
|
|
27759
28231
|
topicsByMemories: async (memoryIds) => {
|
|
@@ -27769,8 +28241,8 @@ function createRemoteMemoryStore(options) {
|
|
|
27769
28241
|
return out;
|
|
27770
28242
|
},
|
|
27771
28243
|
create: async (input) => {
|
|
27772
|
-
const
|
|
27773
|
-
return created([
|
|
28244
|
+
const record3 = await persistence.put(newRow(input), 0);
|
|
28245
|
+
return created([record3], [input])[0];
|
|
27774
28246
|
},
|
|
27775
28247
|
createMany: async (inputs) => {
|
|
27776
28248
|
const out = [];
|
|
@@ -27857,12 +28329,12 @@ function createRemoteMemoryStore(options) {
|
|
|
27857
28329
|
(memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
|
|
27858
28330
|
),
|
|
27859
28331
|
restore: (id2) => serialized(id2, async () => {
|
|
27860
|
-
const
|
|
27861
|
-
if (!
|
|
27862
|
-
if (
|
|
28332
|
+
const record3 = await live2(id2);
|
|
28333
|
+
if (!record3) return false;
|
|
28334
|
+
if (record3.memory.archived_at === void 0 || record3.memory.archived_at === null)
|
|
27863
28335
|
return true;
|
|
27864
|
-
const { archived_at: _archivedAt, ...memory } =
|
|
27865
|
-
notify("edit", [await persistence.put(memory,
|
|
28336
|
+
const { archived_at: _archivedAt, ...memory } = record3.memory;
|
|
28337
|
+
notify("edit", [await persistence.put(memory, record3)]);
|
|
27866
28338
|
return true;
|
|
27867
28339
|
}),
|
|
27868
28340
|
setTopics: async (memoryId, topics) => {
|
|
@@ -27895,8 +28367,8 @@ function createRemoteMemoryStore(options) {
|
|
|
27895
28367
|
const now = /* @__PURE__ */ new Date();
|
|
27896
28368
|
return mergeTopics([], added).map(
|
|
27897
28369
|
(topic2) => ({
|
|
27898
|
-
uniqueId:
|
|
27899
|
-
canonicalName:
|
|
28370
|
+
uniqueId: normalizeTopicName(topic2.name),
|
|
28371
|
+
canonicalName: normalizeTopicName(topic2.name),
|
|
27900
28372
|
kind: topic2.kind ?? null,
|
|
27901
28373
|
createdAt: now,
|
|
27902
28374
|
updatedAt: now
|
|
@@ -30782,11 +31254,11 @@ async function fetchAllModelPages(baseUrl, provider, headers, previous, signal)
|
|
|
30782
31254
|
return { pages, models, fetchedAt: Date.now() };
|
|
30783
31255
|
}
|
|
30784
31256
|
function loadModels(key3, baseUrl, provider, headers, force, signal) {
|
|
30785
|
-
const
|
|
30786
|
-
if (
|
|
30787
|
-
return Promise.resolve([...
|
|
31257
|
+
const cached2 = modelsCache.get(key3);
|
|
31258
|
+
if (cached2 && !force && Date.now() - cached2.fetchedAt < MODELS_CACHE_TTL_MS) {
|
|
31259
|
+
return Promise.resolve([...cached2.models]);
|
|
30788
31260
|
}
|
|
30789
|
-
const shared = (force ? void 0 : modelsInFlight.get(key3)) ?? startSharedRequest(key3, baseUrl, provider, headers,
|
|
31261
|
+
const shared = (force ? void 0 : modelsInFlight.get(key3)) ?? startSharedRequest(key3, baseUrl, provider, headers, cached2);
|
|
30790
31262
|
return waitForSharedRequest(key3, shared, signal).then((models) => [...models]);
|
|
30791
31263
|
}
|
|
30792
31264
|
function startSharedRequest(key3, baseUrl, provider, headers, previous) {
|
|
@@ -31030,9 +31502,9 @@ async function initializeMCPSession(accessToken) {
|
|
|
31030
31502
|
return sessionId;
|
|
31031
31503
|
}
|
|
31032
31504
|
async function ensureMCPSession(accessToken) {
|
|
31033
|
-
const
|
|
31034
|
-
if (
|
|
31035
|
-
return
|
|
31505
|
+
const cached2 = sessionCache.get(accessToken);
|
|
31506
|
+
if (cached2) {
|
|
31507
|
+
return cached2;
|
|
31036
31508
|
}
|
|
31037
31509
|
return initializeMCPSession(accessToken);
|
|
31038
31510
|
}
|
|
@@ -33020,13 +33492,13 @@ function useConversationRedactors(database, account, storage, secondaryStorage)
|
|
|
33020
33492
|
return (0, import_react5.useCallback)(
|
|
33021
33493
|
(conversationId, nerDetector) => {
|
|
33022
33494
|
if (!scope.active) return retiredRedactor;
|
|
33023
|
-
const
|
|
33024
|
-
if (
|
|
33495
|
+
const cached2 = scope.redactors.get(conversationId);
|
|
33496
|
+
if (cached2 && cached2.detector === nerDetector) {
|
|
33025
33497
|
scope.redactors.delete(conversationId);
|
|
33026
|
-
scope.redactors.set(conversationId,
|
|
33027
|
-
return
|
|
33498
|
+
scope.redactors.set(conversationId, cached2);
|
|
33499
|
+
return cached2.redactor;
|
|
33028
33500
|
}
|
|
33029
|
-
if (
|
|
33501
|
+
if (cached2) scope.evicted.push(cached2.redactor);
|
|
33030
33502
|
const redactor = new PiiRedactor({ nerDetector });
|
|
33031
33503
|
scope.redactors.set(conversationId, { redactor, detector: nerDetector });
|
|
33032
33504
|
if (scope.redactors.size > REDACTOR_LIMIT) {
|