@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.mjs
CHANGED
|
@@ -214,25 +214,25 @@ var TRUNCATION_MARKER_HEAD = "... (tool output truncated, ";
|
|
|
214
214
|
var TRUNCATION_MARKER_TAIL = " characters omitted)";
|
|
215
215
|
var MAX_PERSISTED_TOOL_RESULT_CHARS = 1e5;
|
|
216
216
|
function buildToolResultContent(results) {
|
|
217
|
-
const
|
|
217
|
+
const entries2 = results.map(
|
|
218
218
|
(r) => `Tool "${r.name}" returned: ${JSON.stringify(r.result)}`.replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029")
|
|
219
219
|
);
|
|
220
|
-
const framing = HEADER.length + FOOTER.length + ENTRY_SEPARATOR.length * Math.max(0,
|
|
221
|
-
const summary = capEntries(
|
|
220
|
+
const framing = HEADER.length + FOOTER.length + ENTRY_SEPARATOR.length * Math.max(0, entries2.length - 1);
|
|
221
|
+
const summary = capEntries(entries2, MAX_PERSISTED_TOOL_RESULT_CHARS - framing).join(
|
|
222
222
|
ENTRY_SEPARATOR
|
|
223
223
|
);
|
|
224
224
|
return `${HEADER}${summary}${FOOTER}`;
|
|
225
225
|
}
|
|
226
|
-
function capToolResultEntries(
|
|
227
|
-
return capEntries(
|
|
226
|
+
function capToolResultEntries(entries2, budget) {
|
|
227
|
+
return capEntries(entries2, budget);
|
|
228
228
|
}
|
|
229
|
-
function capEntries(
|
|
230
|
-
const smallestFirst =
|
|
231
|
-
const capped = [...
|
|
229
|
+
function capEntries(entries2, budget) {
|
|
230
|
+
const smallestFirst = entries2.map((_, index) => index).sort((a, b) => entries2[a].length - entries2[b].length);
|
|
231
|
+
const capped = [...entries2];
|
|
232
232
|
let remaining = budget;
|
|
233
|
-
let unassigned =
|
|
233
|
+
let unassigned = entries2.length;
|
|
234
234
|
for (const index of smallestFirst) {
|
|
235
|
-
capped[index] = truncateEntry(
|
|
235
|
+
capped[index] = truncateEntry(entries2[index], Math.floor(remaining / unassigned));
|
|
236
236
|
remaining -= capped[index].length;
|
|
237
237
|
unassigned--;
|
|
238
238
|
}
|
|
@@ -934,9 +934,9 @@ async function refreshEncryptionKeyIfMatches(walletAddress, probeCiphertext, sig
|
|
|
934
934
|
return false;
|
|
935
935
|
}
|
|
936
936
|
const startEpoch = sessionEpoch;
|
|
937
|
-
const
|
|
938
|
-
if (
|
|
939
|
-
return tryCommitCandidatesIfProbeMatches(walletAddress, parsed,
|
|
937
|
+
const cached2 = refreshCandidatesByAddress.get(walletAddress);
|
|
938
|
+
if (cached2) {
|
|
939
|
+
return tryCommitCandidatesIfProbeMatches(walletAddress, parsed, cached2, startEpoch);
|
|
940
940
|
}
|
|
941
941
|
let derivePromise = pendingCandidateDerives.get(walletAddress);
|
|
942
942
|
if (!derivePromise) {
|
|
@@ -1901,11 +1901,11 @@ var ToolCallEventIndex = class {
|
|
|
1901
1901
|
this.pending = /* @__PURE__ */ new Map();
|
|
1902
1902
|
this.resetCount = collection.database._resetCount;
|
|
1903
1903
|
collection.experimentalSubscribe((changes) => {
|
|
1904
|
-
for (const { record:
|
|
1904
|
+
for (const { record: record3, type } of changes) {
|
|
1905
1905
|
this.replace(
|
|
1906
|
-
|
|
1907
|
-
type === "destroyed" ? void 0 :
|
|
1908
|
-
type === "destroyed" ? void 0 :
|
|
1906
|
+
record3.id,
|
|
1907
|
+
type === "destroyed" ? void 0 : record3.conversationId,
|
|
1908
|
+
type === "destroyed" ? void 0 : record3._getRaw("tool_call_events")
|
|
1909
1909
|
);
|
|
1910
1910
|
}
|
|
1911
1911
|
});
|
|
@@ -3316,15 +3316,15 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
3316
3316
|
staleSkipped++;
|
|
3317
3317
|
continue;
|
|
3318
3318
|
}
|
|
3319
|
-
const
|
|
3320
|
-
if (!
|
|
3319
|
+
const cached2 = chunkCache?.get(key3.id);
|
|
3320
|
+
if (!cached2 || cached2.version !== key3.version) {
|
|
3321
3321
|
missIds.push(key3.id);
|
|
3322
3322
|
continue;
|
|
3323
3323
|
}
|
|
3324
3324
|
cacheHits++;
|
|
3325
|
-
if (
|
|
3326
|
-
for (let ci = 0; ci <
|
|
3327
|
-
const vec =
|
|
3325
|
+
if (cached2.chunks.length > 0) {
|
|
3326
|
+
for (let ci = 0; ci < cached2.chunks.length; ci++) {
|
|
3327
|
+
const vec = cached2.chunks[ci];
|
|
3328
3328
|
if (vec.length === 0) continue;
|
|
3329
3329
|
const similarity = cosineSimilarity(queryVector, vec);
|
|
3330
3330
|
if (similarity >= minSimilarity) {
|
|
@@ -3337,8 +3337,8 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
3337
3337
|
});
|
|
3338
3338
|
}
|
|
3339
3339
|
}
|
|
3340
|
-
} else if (
|
|
3341
|
-
const similarity = cosineSimilarity(queryVector,
|
|
3340
|
+
} else if (cached2.fallback) {
|
|
3341
|
+
const similarity = cosineSimilarity(queryVector, cached2.fallback);
|
|
3342
3342
|
if (similarity >= minSimilarity) {
|
|
3343
3343
|
candidates.push({
|
|
3344
3344
|
id: key3.id,
|
|
@@ -4151,11 +4151,11 @@ var mergeConfigs = (a, b) => {
|
|
|
4151
4151
|
return config;
|
|
4152
4152
|
};
|
|
4153
4153
|
var headersEntries = (headers) => {
|
|
4154
|
-
const
|
|
4154
|
+
const entries2 = [];
|
|
4155
4155
|
headers.forEach((value, key3) => {
|
|
4156
|
-
|
|
4156
|
+
entries2.push([key3, value]);
|
|
4157
4157
|
});
|
|
4158
|
-
return
|
|
4158
|
+
return entries2;
|
|
4159
4159
|
};
|
|
4160
4160
|
var mergeHeaders = (...headers) => {
|
|
4161
4161
|
const mergedHeaders = new Headers();
|
|
@@ -4583,9 +4583,9 @@ async function embedOne(text16, options, outer) {
|
|
|
4583
4583
|
const { cache } = options;
|
|
4584
4584
|
if (!cache) return Array.from(await requestEmbedding(text16, options, outer));
|
|
4585
4585
|
const model = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
4586
|
-
const
|
|
4587
|
-
const cachedModel =
|
|
4588
|
-
if (
|
|
4586
|
+
const cached2 = cache.get(text16);
|
|
4587
|
+
const cachedModel = cached2 && cachedEmbeddingModels.get(cached2);
|
|
4588
|
+
if (cached2 && (cachedModel === void 0 || cachedModel === model)) return Array.from(cached2);
|
|
4589
4589
|
const inFlight = inFlightByCache.get(cache) ?? /* @__PURE__ */ new Map();
|
|
4590
4590
|
inFlightByCache.set(cache, inFlight);
|
|
4591
4591
|
const requestKey = JSON.stringify([model, text16]);
|
|
@@ -4700,10 +4700,10 @@ async function embedMany(texts, options, outer) {
|
|
|
4700
4700
|
const uncachedTexts = [];
|
|
4701
4701
|
for (let i = 0; i < texts.length; i++) {
|
|
4702
4702
|
if (cache) {
|
|
4703
|
-
const
|
|
4704
|
-
const cachedModel =
|
|
4705
|
-
if (
|
|
4706
|
-
results[i] = Array.from(
|
|
4703
|
+
const cached2 = cache.get(texts[i]);
|
|
4704
|
+
const cachedModel = cached2 && cachedEmbeddingModels.get(cached2);
|
|
4705
|
+
if (cached2 && (cachedModel === void 0 || cachedModel === embeddingModel)) {
|
|
4706
|
+
results[i] = Array.from(cached2);
|
|
4707
4707
|
continue;
|
|
4708
4708
|
}
|
|
4709
4709
|
}
|
|
@@ -5144,58 +5144,337 @@ function parseTopics(value) {
|
|
|
5144
5144
|
return out;
|
|
5145
5145
|
}
|
|
5146
5146
|
|
|
5147
|
+
// src/lib/memory/store/topicCodec.ts
|
|
5148
|
+
var ciphertextPattern = /^enc:v\d+:[0-9a-f]+$/i;
|
|
5149
|
+
var topicHashPattern = /^[0-9a-f]{64}$/;
|
|
5150
|
+
var MAX_SEALED_TOPIC_NAME_BYTES = 1024;
|
|
5151
|
+
function normalizeTopicName(name) {
|
|
5152
|
+
return normalizeEntityName(name).normalize("NFC");
|
|
5153
|
+
}
|
|
5154
|
+
function sealedTopicNamesFit(json5) {
|
|
5155
|
+
return (entries(json5) ?? []).every(
|
|
5156
|
+
(entry) => !hashed(entry) || typeof entry.name !== "string" || entry.name.length <= MAX_SEALED_TOPIC_NAME_BYTES
|
|
5157
|
+
);
|
|
5158
|
+
}
|
|
5159
|
+
function record(value) {
|
|
5160
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5161
|
+
}
|
|
5162
|
+
function hashed(entry) {
|
|
5163
|
+
return record(entry) && typeof entry.name_hash === "string";
|
|
5164
|
+
}
|
|
5165
|
+
function entries(json5) {
|
|
5166
|
+
if (typeof json5 !== "string") return void 0;
|
|
5167
|
+
try {
|
|
5168
|
+
const parsed = JSON.parse(json5);
|
|
5169
|
+
return Array.isArray(parsed) ? parsed : void 0;
|
|
5170
|
+
} catch {
|
|
5171
|
+
return void 0;
|
|
5172
|
+
}
|
|
5173
|
+
}
|
|
5174
|
+
function cached(cache, key3, load) {
|
|
5175
|
+
let pending = cache.get(key3);
|
|
5176
|
+
if (!pending) {
|
|
5177
|
+
const loading = load();
|
|
5178
|
+
pending = loading;
|
|
5179
|
+
cache.set(key3, loading);
|
|
5180
|
+
loading.catch(() => {
|
|
5181
|
+
if (cache.get(key3) === loading) cache.delete(key3);
|
|
5182
|
+
});
|
|
5183
|
+
}
|
|
5184
|
+
return pending;
|
|
5185
|
+
}
|
|
5186
|
+
function createTopicCodec(cipher) {
|
|
5187
|
+
const hashes = /* @__PURE__ */ new Map();
|
|
5188
|
+
const opened = /* @__PURE__ */ new Map();
|
|
5189
|
+
const seals = /* @__PURE__ */ new Map();
|
|
5190
|
+
const legacyNames = /* @__PURE__ */ new Map();
|
|
5191
|
+
const hash = async (name) => {
|
|
5192
|
+
const normalized2 = normalizeTopicName(name);
|
|
5193
|
+
if (!normalized2) return null;
|
|
5194
|
+
return cached(hashes, normalized2, async () => {
|
|
5195
|
+
const digest = await cipher.hashTopic(normalized2);
|
|
5196
|
+
if (!topicHashPattern.test(digest))
|
|
5197
|
+
throw new Error("Topic hashing must return 64 lowercase hex characters");
|
|
5198
|
+
return digest;
|
|
5199
|
+
});
|
|
5200
|
+
};
|
|
5201
|
+
const seal = async (display) => {
|
|
5202
|
+
const nameHash = await hash(display);
|
|
5203
|
+
if (nameHash === null) return null;
|
|
5204
|
+
return cached(seals, display, async () => {
|
|
5205
|
+
const name = await cipher.encrypt(display);
|
|
5206
|
+
if (name === display || !ciphertextPattern.test(name))
|
|
5207
|
+
throw new Error(
|
|
5208
|
+
"Topic encryption must return SDK ciphertext; refusing to upload plaintext"
|
|
5209
|
+
);
|
|
5210
|
+
opened.set(name, Promise.resolve(display));
|
|
5211
|
+
return { name_hash: nameHash, name };
|
|
5212
|
+
});
|
|
5213
|
+
};
|
|
5214
|
+
const plain2 = (name) => {
|
|
5215
|
+
if (!ciphertextPattern.test(name)) return Promise.resolve(name);
|
|
5216
|
+
let pending = legacyNames.get(name);
|
|
5217
|
+
if (!pending) {
|
|
5218
|
+
pending = cipher.decrypt(name).catch(() => name);
|
|
5219
|
+
legacyNames.set(name, pending);
|
|
5220
|
+
}
|
|
5221
|
+
return pending;
|
|
5222
|
+
};
|
|
5223
|
+
const open = async ({ name, name_hash: nameHash }) => {
|
|
5224
|
+
if (nameHash === void 0) return plain2(name);
|
|
5225
|
+
if (typeof name !== "string" || typeof nameHash !== "string" || !topicHashPattern.test(nameHash) || !ciphertextPattern.test(name))
|
|
5226
|
+
throw new Error("Nearby returned a malformed topic name");
|
|
5227
|
+
const plaintext = await cached(opened, name, async () => {
|
|
5228
|
+
const value = await cipher.decrypt(name);
|
|
5229
|
+
if (value === name) throw new Error("Topic decryption failed");
|
|
5230
|
+
return value;
|
|
5231
|
+
});
|
|
5232
|
+
if (await hash(plaintext) !== nameHash) throw new Error("Topic name does not match its hash");
|
|
5233
|
+
if (!seals.has(plaintext)) seals.set(plaintext, Promise.resolve({ name_hash: nameHash, name }));
|
|
5234
|
+
return plaintext;
|
|
5235
|
+
};
|
|
5236
|
+
return {
|
|
5237
|
+
hash,
|
|
5238
|
+
seal,
|
|
5239
|
+
open,
|
|
5240
|
+
encodeTopics: async (json5) => {
|
|
5241
|
+
const list = entries(json5);
|
|
5242
|
+
if (!list) return json5;
|
|
5243
|
+
const sealed2 = await Promise.all(
|
|
5244
|
+
list.map(async (entry) => {
|
|
5245
|
+
if (!record(entry) || typeof entry.name !== "string") return null;
|
|
5246
|
+
const name = await seal(await plain2(entry.name));
|
|
5247
|
+
return name && { ...entry, name: name.name, name_hash: name.name_hash };
|
|
5248
|
+
})
|
|
5249
|
+
);
|
|
5250
|
+
return JSON.stringify(sealed2.filter((entry) => entry !== null));
|
|
5251
|
+
},
|
|
5252
|
+
decodeTopics: async (json5) => {
|
|
5253
|
+
const list = entries(json5);
|
|
5254
|
+
if (!list?.some(
|
|
5255
|
+
(entry) => hashed(entry) || record(entry) && typeof entry.name === "string" && ciphertextPattern.test(entry.name)
|
|
5256
|
+
))
|
|
5257
|
+
return json5;
|
|
5258
|
+
const decoded = await Promise.all(
|
|
5259
|
+
list.map(async (entry) => {
|
|
5260
|
+
if (!hashed(entry))
|
|
5261
|
+
return record(entry) && typeof entry.name === "string" ? { ...entry, name: await plain2(entry.name) } : entry;
|
|
5262
|
+
const { name_hash: nameHash, ...rest } = entry;
|
|
5263
|
+
return { ...rest, name: await open({ name: entry.name, name_hash: nameHash }) };
|
|
5264
|
+
})
|
|
5265
|
+
);
|
|
5266
|
+
return JSON.stringify(decoded);
|
|
5267
|
+
},
|
|
5268
|
+
isLegacy: (json5) => (entries(json5) ?? []).some(
|
|
5269
|
+
(entry) => record(entry) && typeof entry.name === "string" && !hashed(entry)
|
|
5270
|
+
),
|
|
5271
|
+
matchesLegacy: async (json5, names, hashes2) => {
|
|
5272
|
+
const list = typeof json5 === "string" ? entries(json5) ?? [] : [];
|
|
5273
|
+
if (list.some((entry) => hashed(entry) && hashes2.has(entry.name_hash))) return false;
|
|
5274
|
+
const legacy = await Promise.all(
|
|
5275
|
+
list.map(
|
|
5276
|
+
async (entry) => record(entry) && typeof entry.name === "string" && !hashed(entry) ? normalizeTopicName(await plain2(entry.name)) : null
|
|
5277
|
+
)
|
|
5278
|
+
);
|
|
5279
|
+
return legacy.some((name) => name !== null && names.has(name));
|
|
5280
|
+
},
|
|
5281
|
+
encodeCatalog: async (topic2) => {
|
|
5282
|
+
const sealed2 = await seal(normalizeTopicName(await plain2(topic2.name)));
|
|
5283
|
+
return sealed2 && { ...topic2, name: sealed2.name, name_hash: sealed2.name_hash };
|
|
5284
|
+
},
|
|
5285
|
+
decodeCatalog: async (item) => {
|
|
5286
|
+
const { name_hash: nameHash, ...rest } = item;
|
|
5287
|
+
return { ...rest, name: await open({ name: item.name, name_hash: nameHash }) };
|
|
5288
|
+
}
|
|
5289
|
+
};
|
|
5290
|
+
}
|
|
5291
|
+
|
|
5147
5292
|
// src/lib/memory/store/remoteTopics.ts
|
|
5293
|
+
var RETIRE_CONCURRENCY = 8;
|
|
5148
5294
|
function topic(value) {
|
|
5149
5295
|
const t = value;
|
|
5150
|
-
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")
|
|
5296
|
+
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")
|
|
5151
5297
|
throw new Error("Invalid nearby topic");
|
|
5152
5298
|
return t;
|
|
5153
5299
|
}
|
|
5154
|
-
function
|
|
5300
|
+
async function wireTopics(request, signal) {
|
|
5301
|
+
const out = [];
|
|
5302
|
+
let cursor;
|
|
5303
|
+
do {
|
|
5304
|
+
const page = await request(
|
|
5305
|
+
"/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
|
|
5306
|
+
{},
|
|
5307
|
+
signal
|
|
5308
|
+
);
|
|
5309
|
+
if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
|
|
5310
|
+
throw new Error("Invalid nearby topic page");
|
|
5311
|
+
out.push(...page.items.map(topic));
|
|
5312
|
+
cursor = page.next_cursor;
|
|
5313
|
+
} while (cursor);
|
|
5314
|
+
return out;
|
|
5315
|
+
}
|
|
5316
|
+
function hashesOf(items) {
|
|
5317
|
+
return new Set(items.flatMap((t) => t.name_hash === void 0 ? [] : [t.name_hash]));
|
|
5318
|
+
}
|
|
5319
|
+
async function sealedImport(request, codec, topics, signal) {
|
|
5320
|
+
let oversized = 0;
|
|
5321
|
+
for (let i = 0; i < topics.length; i += 50) {
|
|
5322
|
+
signal?.throwIfAborted();
|
|
5323
|
+
const sealed2 = (await Promise.all(topics.slice(i, i + 50).map((t) => codec.encodeCatalog(t)))).filter((t) => {
|
|
5324
|
+
if (t === null) return false;
|
|
5325
|
+
if (t.name.length <= MAX_SEALED_TOPIC_NAME_BYTES) return true;
|
|
5326
|
+
oversized++;
|
|
5327
|
+
return false;
|
|
5328
|
+
});
|
|
5329
|
+
if (sealed2.length)
|
|
5330
|
+
await request(
|
|
5331
|
+
"/topics/import",
|
|
5332
|
+
{ method: "POST", body: JSON.stringify({ topics: sealed2 }) },
|
|
5333
|
+
signal
|
|
5334
|
+
);
|
|
5335
|
+
}
|
|
5336
|
+
signal?.throwIfAborted();
|
|
5337
|
+
if (oversized)
|
|
5338
|
+
getLogger().warn(
|
|
5339
|
+
`[memory/remote] Skipped ${oversized} topic catalog entries whose sealed name exceeds ${MAX_SEALED_TOPIC_NAME_BYTES} bytes`
|
|
5340
|
+
);
|
|
5341
|
+
}
|
|
5342
|
+
function createRemoteTopicPersistence(request, codec) {
|
|
5343
|
+
let legacyOnly = /* @__PURE__ */ new Set();
|
|
5155
5344
|
return {
|
|
5156
5345
|
topics: async () => {
|
|
5157
|
-
const
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5346
|
+
const items = await wireTopics(request);
|
|
5347
|
+
const hashed2 = hashesOf(items);
|
|
5348
|
+
const legacy = /* @__PURE__ */ new Set();
|
|
5349
|
+
const decoded = await Promise.all(
|
|
5350
|
+
items.map(async (item) => {
|
|
5351
|
+
const plain2 = await codec.decodeCatalog(item);
|
|
5352
|
+
const name = normalizeTopicName(plain2.name);
|
|
5353
|
+
if (item.name_hash === void 0) {
|
|
5354
|
+
const hash = await codec.hash(name);
|
|
5355
|
+
if (hash !== null && hashed2.has(hash)) return null;
|
|
5356
|
+
legacy.add(name);
|
|
5357
|
+
}
|
|
5358
|
+
return { ...plain2, name };
|
|
5359
|
+
})
|
|
5360
|
+
);
|
|
5361
|
+
legacyOnly = legacy;
|
|
5362
|
+
return decoded.filter((t) => t !== null);
|
|
5170
5363
|
},
|
|
5171
5364
|
putTopic: async (value, expectedVersion) => {
|
|
5172
5365
|
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
5173
5366
|
throw new Error("Expected topic version must be a nonnegative integer");
|
|
5174
|
-
|
|
5367
|
+
const sealed2 = await codec.encodeCatalog(value);
|
|
5368
|
+
if (!sealed2) throw new Error("Topic name must not be empty");
|
|
5369
|
+
const saved = topic(
|
|
5175
5370
|
await request("/topics", {
|
|
5176
5371
|
method: "PUT",
|
|
5177
|
-
body: JSON.stringify({
|
|
5372
|
+
body: JSON.stringify({
|
|
5373
|
+
topic: sealed2,
|
|
5374
|
+
expected_version: legacyOnly.has(normalizeTopicName(value.name)) ? 0 : expectedVersion
|
|
5375
|
+
})
|
|
5178
5376
|
})
|
|
5179
5377
|
);
|
|
5378
|
+
const decoded = await codec.decodeCatalog(saved);
|
|
5379
|
+
legacyOnly.delete(decoded.name);
|
|
5380
|
+
return decoded;
|
|
5180
5381
|
},
|
|
5181
|
-
importTopics:
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5382
|
+
importTopics: (topics, signal) => sealedImport(
|
|
5383
|
+
request,
|
|
5384
|
+
codec,
|
|
5385
|
+
topics.map(({ name, kind }) => ({ name, ...kind !== void 0 && { kind } })),
|
|
5386
|
+
signal
|
|
5387
|
+
)
|
|
5388
|
+
};
|
|
5389
|
+
}
|
|
5390
|
+
async function retireLegacyTopics(request, codec, topics, imported, signal) {
|
|
5391
|
+
const failures = [];
|
|
5392
|
+
const put = async (topic2, expectedVersion) => {
|
|
5393
|
+
try {
|
|
5394
|
+
await request(
|
|
5395
|
+
"/topics",
|
|
5396
|
+
{ method: "PUT", body: JSON.stringify({ topic: topic2, expected_version: expectedVersion }) },
|
|
5397
|
+
signal
|
|
5398
|
+
);
|
|
5399
|
+
return "saved";
|
|
5400
|
+
} catch (error) {
|
|
5401
|
+
if (signal?.aborted) throw error;
|
|
5402
|
+
if (error instanceof RemoteMemoryError && error.status === 409) return "conflict";
|
|
5403
|
+
failures.push(error);
|
|
5404
|
+
return "failed";
|
|
5405
|
+
}
|
|
5406
|
+
};
|
|
5407
|
+
const retire = (item) => put(
|
|
5408
|
+
{ name: item.name, ...item.kind !== void 0 && { kind: item.kind }, is_deleted: true },
|
|
5409
|
+
item.version
|
|
5410
|
+
);
|
|
5411
|
+
const changed = [];
|
|
5412
|
+
let next = 0;
|
|
5413
|
+
const worker = async () => {
|
|
5414
|
+
while (next < topics.length) {
|
|
5193
5415
|
signal?.throwIfAborted();
|
|
5416
|
+
const item = topics[next++];
|
|
5417
|
+
if (await retire(item) === "conflict") changed.push(item);
|
|
5194
5418
|
}
|
|
5195
5419
|
};
|
|
5420
|
+
await Promise.all(
|
|
5421
|
+
Array.from({ length: Math.min(RETIRE_CONCURRENCY, topics.length) }, () => worker())
|
|
5422
|
+
);
|
|
5423
|
+
if (changed.length) {
|
|
5424
|
+
const current = await wireTopics(request, signal);
|
|
5425
|
+
for (const stale of changed) {
|
|
5426
|
+
const legacy = current.find((t) => t.name_hash === void 0 && t.name === stale.name);
|
|
5427
|
+
if (!legacy || legacy.is_deleted) continue;
|
|
5428
|
+
const hash = await codec.hash(await codec.open(legacy));
|
|
5429
|
+
const copy = current.find((t) => t.name_hash !== void 0 && t.name_hash === hash);
|
|
5430
|
+
if (!copy || hash === null) continue;
|
|
5431
|
+
const newer = imported.has(hash) || Date.parse(legacy.server_updated_at) > Date.parse(copy.server_updated_at);
|
|
5432
|
+
if (newer && (copy.is_deleted || legacy.kind !== copy.kind)) {
|
|
5433
|
+
const sealed2 = await codec.encodeCatalog({
|
|
5434
|
+
name: legacy.name,
|
|
5435
|
+
...legacy.kind !== void 0 && { kind: legacy.kind },
|
|
5436
|
+
is_deleted: false
|
|
5437
|
+
});
|
|
5438
|
+
if (!sealed2 || await put(sealed2, copy.version) !== "saved") continue;
|
|
5439
|
+
}
|
|
5440
|
+
await retire(legacy);
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5443
|
+
if (failures.length)
|
|
5444
|
+
getLogger().warn(
|
|
5445
|
+
`[memory/remote] Could not retire ${failures.length} upgraded topic catalog entries:`,
|
|
5446
|
+
failures[0]
|
|
5447
|
+
);
|
|
5448
|
+
}
|
|
5449
|
+
async function upgradeLegacyTopicCatalog(request, codec, signal) {
|
|
5450
|
+
const items = await wireTopics(request, signal);
|
|
5451
|
+
const hashed2 = hashesOf(items);
|
|
5452
|
+
const hashes = await Promise.all(
|
|
5453
|
+
items.map(
|
|
5454
|
+
async (item) => item.name_hash === void 0 ? codec.hash(await codec.open(item)) : null
|
|
5455
|
+
)
|
|
5456
|
+
);
|
|
5457
|
+
const sources = /* @__PURE__ */ new Map();
|
|
5458
|
+
const live2 = [];
|
|
5459
|
+
items.forEach((item, i) => {
|
|
5460
|
+
const hash = hashes[i];
|
|
5461
|
+
if (hash === null) return;
|
|
5462
|
+
if (!item.is_deleted) live2.push(item);
|
|
5463
|
+
if (hashed2.has(hash)) return;
|
|
5464
|
+
const source = sources.get(hash);
|
|
5465
|
+
if (!source || source.is_deleted && !item.is_deleted) sources.set(hash, item);
|
|
5466
|
+
});
|
|
5467
|
+
const legacy = [...sources.values()].map((item) => ({
|
|
5468
|
+
name: item.name,
|
|
5469
|
+
...item.kind !== void 0 && { kind: item.kind },
|
|
5470
|
+
...item.is_deleted && { is_deleted: true }
|
|
5471
|
+
}));
|
|
5472
|
+
await sealedImport(request, codec, legacy, signal);
|
|
5473
|
+
await retireLegacyTopics(request, codec, live2, new Set(sources.keys()), signal);
|
|
5474
|
+
return legacy.length;
|
|
5196
5475
|
}
|
|
5197
5476
|
async function createRemoteTopic(persistence, name) {
|
|
5198
|
-
const canonical =
|
|
5477
|
+
const canonical = normalizeTopicName(name);
|
|
5199
5478
|
if (!canonical) return null;
|
|
5200
5479
|
const existing = (await persistence.topics()).find((t) => t.name === canonical);
|
|
5201
5480
|
if (existing && !existing.is_deleted) return canonical;
|
|
@@ -5283,7 +5562,10 @@ var RemoteMemoryError = class extends Error {
|
|
|
5283
5562
|
this.name = "RemoteMemoryError";
|
|
5284
5563
|
}
|
|
5285
5564
|
};
|
|
5286
|
-
var
|
|
5565
|
+
var TOPIC_UPGRADE_PROCESSOR = "topic-hash-v1";
|
|
5566
|
+
var TOPIC_UPGRADE_PAGE = 50;
|
|
5567
|
+
var LEGACY_TOPIC_CURSOR = "legacy-topics:";
|
|
5568
|
+
var LEGACY_TOPIC_RECHECK_MS = 6e4;
|
|
5287
5569
|
var memoryFields = {
|
|
5288
5570
|
memory_id: true,
|
|
5289
5571
|
content: true,
|
|
@@ -5343,7 +5625,8 @@ var queryFields = [
|
|
|
5343
5625
|
"fact_types",
|
|
5344
5626
|
"visibility",
|
|
5345
5627
|
"memory_ids",
|
|
5346
|
-
"
|
|
5628
|
+
"topic_hashes",
|
|
5629
|
+
"topics_legacy",
|
|
5347
5630
|
"updated_after",
|
|
5348
5631
|
"topics_due",
|
|
5349
5632
|
"topics_extracted",
|
|
@@ -5353,11 +5636,17 @@ var queryFields = [
|
|
|
5353
5636
|
"limit",
|
|
5354
5637
|
"include_embeddings"
|
|
5355
5638
|
];
|
|
5356
|
-
function
|
|
5639
|
+
function isVersionConflict(error) {
|
|
5640
|
+
return error instanceof RemoteMemoryError && error.code === "version_conflict";
|
|
5641
|
+
}
|
|
5642
|
+
function isRejectedRow(error) {
|
|
5643
|
+
return error instanceof RemoteMemoryError && error.status === 400;
|
|
5644
|
+
}
|
|
5645
|
+
function record2(value) {
|
|
5357
5646
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5358
5647
|
}
|
|
5359
5648
|
function memoryRecord(value) {
|
|
5360
|
-
if (!
|
|
5649
|
+
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))) {
|
|
5361
5650
|
throw new Error("Invalid nearby private-memory response");
|
|
5362
5651
|
}
|
|
5363
5652
|
return value;
|
|
@@ -5437,14 +5726,14 @@ function createNearbyRequest(options, apiPath = "/api/private-memories") {
|
|
|
5437
5726
|
const body = await response.json().catch(() => null);
|
|
5438
5727
|
const retryAfter = parseRetryAfterMs(response.headers.get("Retry-After"));
|
|
5439
5728
|
const error = new RemoteMemoryError(
|
|
5440
|
-
|
|
5729
|
+
record2(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
|
|
5441
5730
|
response.status,
|
|
5442
|
-
|
|
5731
|
+
record2(body) && typeof body.code === "string" ? body.code : void 0,
|
|
5443
5732
|
retryAfter ?? void 0,
|
|
5444
|
-
|
|
5733
|
+
record2(body) && typeof body.rate_limit_bucket === "string" ? body.rate_limit_bucket : void 0
|
|
5445
5734
|
);
|
|
5446
5735
|
if (response.status === 429 && retryAfter !== null && retryAfter > 0 && (!error.code || error.code === "rate_limited")) {
|
|
5447
|
-
const bucket = error.rateLimitBucket && budgets.includes(error.rateLimitBucket) ? error.rateLimitBucket :
|
|
5736
|
+
const bucket = error.rateLimitBucket && budgets.includes(error.rateLimitBucket) ? error.rateLimitBucket : record2(body) && (body.limit_scope === "account" || body.limit_scope === "ip") && !error.rateLimitBucket ? "*" : route;
|
|
5448
5737
|
cooldowns.set(bucket, { until: Date.now() + retryAfter, error });
|
|
5449
5738
|
}
|
|
5450
5739
|
throw error;
|
|
@@ -5467,7 +5756,7 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5467
5756
|
throw new Error("A canonical keyId is required");
|
|
5468
5757
|
const request = createNearbyRequest(options);
|
|
5469
5758
|
const account = await request("/account", {}, options.signal);
|
|
5470
|
-
if (!
|
|
5759
|
+
if (!record2(account) || account.state !== "active") {
|
|
5471
5760
|
throw new RemoteMemoryError(
|
|
5472
5761
|
"Complete and verify migration before using remote memories",
|
|
5473
5762
|
409,
|
|
@@ -5481,6 +5770,25 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5481
5770
|
"key_mismatch"
|
|
5482
5771
|
);
|
|
5483
5772
|
}
|
|
5773
|
+
const codec = createTopicCodec(options);
|
|
5774
|
+
let legacyTopicRows = typeof account.legacy_topic_memories === "number" && account.legacy_topic_memories > 0;
|
|
5775
|
+
if (typeof account.legacy_topic_catalog === "number" && account.legacy_topic_catalog > 0)
|
|
5776
|
+
void upgradeLegacyTopicCatalog(request, codec, options.signal).catch((error) => {
|
|
5777
|
+
if (!options.signal?.aborted)
|
|
5778
|
+
getLogger().warn("[memory/remote] Topic catalog upgrade failed:", error);
|
|
5779
|
+
});
|
|
5780
|
+
let legacyCheckedAt = Date.now();
|
|
5781
|
+
let legacyCheck;
|
|
5782
|
+
const recheckLegacyTopicRows = () => {
|
|
5783
|
+
if (legacyCheck || Date.now() - legacyCheckedAt < LEGACY_TOPIC_RECHECK_MS) return;
|
|
5784
|
+
legacyCheckedAt = Date.now();
|
|
5785
|
+
legacyCheck = request("/account", {}, options.signal).then((current) => {
|
|
5786
|
+
if (record2(current) && current.legacy_topic_memories === 0) legacyTopicRows = false;
|
|
5787
|
+
}).catch(() => {
|
|
5788
|
+
}).finally(() => {
|
|
5789
|
+
legacyCheck = void 0;
|
|
5790
|
+
});
|
|
5791
|
+
};
|
|
5484
5792
|
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
5485
5793
|
const decode = async (value) => {
|
|
5486
5794
|
const item = memoryRecord(value);
|
|
@@ -5498,6 +5806,9 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5498
5806
|
content: item.memory.is_deleted && item.memory.content === "" ? "" : await decrypt(item.memory.content),
|
|
5499
5807
|
...item.memory.kind_value !== void 0 && {
|
|
5500
5808
|
kind_value: await decrypt(item.memory.kind_value)
|
|
5809
|
+
},
|
|
5810
|
+
...item.memory.topics !== void 0 && {
|
|
5811
|
+
topics: await codec.decodeTopics(item.memory.topics)
|
|
5501
5812
|
}
|
|
5502
5813
|
}
|
|
5503
5814
|
};
|
|
@@ -5509,8 +5820,10 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5509
5820
|
version: item.version,
|
|
5510
5821
|
content: decoded.memory.content,
|
|
5511
5822
|
kindValue: decoded.memory.kind_value,
|
|
5823
|
+
topics: decoded.memory.topics,
|
|
5512
5824
|
encryptedContent: item.memory.content,
|
|
5513
|
-
encryptedKindValue: item.memory.kind_value
|
|
5825
|
+
encryptedKindValue: item.memory.kind_value,
|
|
5826
|
+
encryptedTopics: item.memory.topics
|
|
5514
5827
|
});
|
|
5515
5828
|
return decoded;
|
|
5516
5829
|
};
|
|
@@ -5532,7 +5845,7 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5532
5845
|
};
|
|
5533
5846
|
const decodeCommitted = async (value, write) => {
|
|
5534
5847
|
const item = memoryRecord(value);
|
|
5535
|
-
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)
|
|
5848
|
+
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)
|
|
5536
5849
|
return decode(item);
|
|
5537
5850
|
return remember(
|
|
5538
5851
|
{
|
|
@@ -5540,7 +5853,8 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5540
5853
|
memory: {
|
|
5541
5854
|
...item.memory,
|
|
5542
5855
|
content: write.content,
|
|
5543
|
-
...write.kindValue !== void 0 && { kind_value: write.kindValue }
|
|
5856
|
+
...write.kindValue !== void 0 && { kind_value: write.kindValue },
|
|
5857
|
+
...write.topics !== void 0 && { topics: write.topics }
|
|
5544
5858
|
}
|
|
5545
5859
|
},
|
|
5546
5860
|
item
|
|
@@ -5592,13 +5906,21 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5592
5906
|
const reusableContent = snapshot?.encryptedContent ?? existing?.memory.content;
|
|
5593
5907
|
const content = reusableContent && (snapshot?.content ?? decoded?.memory.content) === memory.content ? reusableContent : await encryptField2(memory.content);
|
|
5594
5908
|
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);
|
|
5909
|
+
const wireTopics2 = snapshot ? snapshot.encryptedTopics : existing?.memory.topics;
|
|
5910
|
+
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);
|
|
5595
5911
|
return {
|
|
5596
5912
|
body: {
|
|
5597
5913
|
expected_version: expectedVersion,
|
|
5598
|
-
memory: {
|
|
5914
|
+
memory: {
|
|
5915
|
+
...memory,
|
|
5916
|
+
content,
|
|
5917
|
+
...kindValue !== void 0 && { kind_value: kindValue },
|
|
5918
|
+
...topics !== void 0 && { topics }
|
|
5919
|
+
}
|
|
5599
5920
|
},
|
|
5600
5921
|
content: memory.content,
|
|
5601
|
-
kindValue: memory.kind_value
|
|
5922
|
+
kindValue: memory.kind_value,
|
|
5923
|
+
topics: memory.topics
|
|
5602
5924
|
};
|
|
5603
5925
|
};
|
|
5604
5926
|
const fetchCandidates = async (embedding2, candidateOptions, withCounts) => {
|
|
@@ -5647,32 +5969,72 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5647
5969
|
},
|
|
5648
5970
|
candidateOptions.signal
|
|
5649
5971
|
);
|
|
5650
|
-
if (!
|
|
5972
|
+
if (!record2(result) || !Array.isArray(result.items))
|
|
5651
5973
|
throw new Error("Invalid nearby candidate response");
|
|
5652
5974
|
return result;
|
|
5653
5975
|
};
|
|
5654
5976
|
const fetchQueryPage = async (queryOptions) => {
|
|
5655
|
-
const { signal, ...
|
|
5656
|
-
if (
|
|
5977
|
+
const { signal, topics: names, ...wire2 } = queryOptions;
|
|
5978
|
+
if (wire2.limit !== void 0 && (!Number.isInteger(wire2.limit) || wire2.limit < 1 || wire2.limit > 200))
|
|
5657
5979
|
throw new Error("Page limit must be 1\u2013200");
|
|
5658
5980
|
for (const [key3, max] of queryListLimits) {
|
|
5659
|
-
const values =
|
|
5981
|
+
const values = queryOptions[key3];
|
|
5660
5982
|
if (values && values.length > max)
|
|
5661
5983
|
throw new Error(`Query ${key3} accepts at most ${max} entries (got ${values.length})`);
|
|
5662
5984
|
}
|
|
5985
|
+
const body = wire2;
|
|
5986
|
+
if (names === void 0) return postQuery(body, signal);
|
|
5987
|
+
const hashes = [
|
|
5988
|
+
...new Set(
|
|
5989
|
+
(await Promise.all(names.map((name) => codec.hash(name)))).filter((h) => h !== null)
|
|
5990
|
+
)
|
|
5991
|
+
];
|
|
5992
|
+
if (names.length > 0 && hashes.length === 0) return { items: [] };
|
|
5993
|
+
if (hashes.length > 0 && wire2.cursor?.startsWith(LEGACY_TOPIC_CURSOR)) {
|
|
5994
|
+
const page2 = await postQuery(
|
|
5995
|
+
{
|
|
5996
|
+
...wire2,
|
|
5997
|
+
cursor: wire2.cursor.slice(LEGACY_TOPIC_CURSOR.length) || void 0,
|
|
5998
|
+
topics_legacy: true
|
|
5999
|
+
},
|
|
6000
|
+
signal
|
|
6001
|
+
);
|
|
6002
|
+
const wanted = new Set(names.map(normalizeTopicName));
|
|
6003
|
+
const hashed2 = new Set(hashes);
|
|
6004
|
+
const matches = await Promise.all(
|
|
6005
|
+
page2.items.map(
|
|
6006
|
+
(item) => codec.matchesLegacy(
|
|
6007
|
+
record2(item) && record2(item.memory) ? item.memory.topics : void 0,
|
|
6008
|
+
wanted,
|
|
6009
|
+
hashed2
|
|
6010
|
+
)
|
|
6011
|
+
)
|
|
6012
|
+
);
|
|
6013
|
+
return {
|
|
6014
|
+
...page2,
|
|
6015
|
+
items: page2.items.filter((_, i) => matches[i]),
|
|
6016
|
+
next_cursor: page2.next_cursor === void 0 ? void 0 : LEGACY_TOPIC_CURSOR + page2.next_cursor
|
|
6017
|
+
};
|
|
6018
|
+
}
|
|
6019
|
+
const page = await postQuery({ ...body, topic_hashes: hashes }, signal);
|
|
6020
|
+
if (hashes.length === 0 || page.next_cursor !== void 0 || !legacyTopicRows) return page;
|
|
6021
|
+
recheckLegacyTopicRows();
|
|
6022
|
+
return { ...page, next_cursor: LEGACY_TOPIC_CURSOR };
|
|
6023
|
+
};
|
|
6024
|
+
const postQuery = async (body, signal) => {
|
|
5663
6025
|
const page = await request(
|
|
5664
6026
|
"/memories/query",
|
|
5665
6027
|
{
|
|
5666
6028
|
method: "POST",
|
|
5667
6029
|
body: JSON.stringify(
|
|
5668
6030
|
Object.fromEntries(
|
|
5669
|
-
queryFields.filter((key3) =>
|
|
6031
|
+
queryFields.filter((key3) => body[key3] !== void 0).map((key3) => [key3, body[key3]])
|
|
5670
6032
|
)
|
|
5671
6033
|
)
|
|
5672
6034
|
},
|
|
5673
6035
|
signal
|
|
5674
6036
|
);
|
|
5675
|
-
if (!
|
|
6037
|
+
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")
|
|
5676
6038
|
throw new Error("Invalid nearby private-memory page");
|
|
5677
6039
|
return page;
|
|
5678
6040
|
};
|
|
@@ -5686,13 +6048,13 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5686
6048
|
unavailable_count: result.unavailable_count
|
|
5687
6049
|
};
|
|
5688
6050
|
};
|
|
5689
|
-
|
|
5690
|
-
...createRemoteTopicPersistence(request),
|
|
6051
|
+
const persistence = {
|
|
6052
|
+
...createRemoteTopicPersistence(request, codec),
|
|
5691
6053
|
...createRemoteWorkPersistence(request),
|
|
5692
6054
|
supportsRealtimeChanges: account.realtime_changes === true,
|
|
5693
6055
|
counts: async () => {
|
|
5694
6056
|
const result = await request("/counts", {});
|
|
5695
|
-
if (!
|
|
6057
|
+
if (!record2(result) || ["live", "archived", "quarantined"].some(
|
|
5696
6058
|
(key3) => !Number.isSafeInteger(result[key3]) || result[key3] < 0
|
|
5697
6059
|
))
|
|
5698
6060
|
throw new Error("Invalid nearby memory counts");
|
|
@@ -5709,8 +6071,8 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5709
6071
|
method: "POST",
|
|
5710
6072
|
body: JSON.stringify({ ...window2, limit })
|
|
5711
6073
|
});
|
|
5712
|
-
if (!
|
|
5713
|
-
(item) => !
|
|
6074
|
+
if (!record2(result) || !Array.isArray(result.items) || result.items.some(
|
|
6075
|
+
(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
|
|
5714
6076
|
))
|
|
5715
6077
|
throw new Error("Invalid nearby temporal candidates");
|
|
5716
6078
|
return result.items.map((item) => item.memory_id);
|
|
@@ -5741,7 +6103,7 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5741
6103
|
if (query[key3] !== void 0) params.set(key3, String(query[key3]));
|
|
5742
6104
|
}
|
|
5743
6105
|
const page = await request("/memories?" + params.toString(), {}, signal);
|
|
5744
|
-
if (!
|
|
6106
|
+
if (!record2(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string") {
|
|
5745
6107
|
throw new Error("Invalid nearby private-memory page");
|
|
5746
6108
|
}
|
|
5747
6109
|
return {
|
|
@@ -5781,7 +6143,7 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5781
6143
|
},
|
|
5782
6144
|
signal
|
|
5783
6145
|
);
|
|
5784
|
-
if (!
|
|
6146
|
+
if (!record2(result) || !Array.isArray(result.items) || result.items.length !== prepared.length)
|
|
5785
6147
|
throw new Error("Invalid nearby batch response");
|
|
5786
6148
|
return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
|
|
5787
6149
|
},
|
|
@@ -5796,20 +6158,87 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
5796
6158
|
queryMetadata: async (queryOptions = {}) => {
|
|
5797
6159
|
const page = await fetchQueryPage(queryOptions);
|
|
5798
6160
|
return {
|
|
5799
|
-
items:
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
6161
|
+
items: await Promise.all(
|
|
6162
|
+
page.items.map(async (item) => {
|
|
6163
|
+
const {
|
|
6164
|
+
memory: { content: _content, kind_value: _kindValue, topics, ...memory },
|
|
6165
|
+
version,
|
|
6166
|
+
server_updated_at
|
|
6167
|
+
} = memoryRecord(item);
|
|
6168
|
+
const plain2 = topics === void 0 ? void 0 : await codec.decodeTopics(topics).catch(() => null);
|
|
6169
|
+
return {
|
|
6170
|
+
memory: { ...memory, ...typeof plain2 === "string" && { topics: plain2 } },
|
|
6171
|
+
version,
|
|
6172
|
+
server_updated_at
|
|
6173
|
+
};
|
|
6174
|
+
})
|
|
6175
|
+
),
|
|
5807
6176
|
...page.next_cursor !== void 0 && { next_cursor: page.next_cursor }
|
|
5808
6177
|
};
|
|
5809
6178
|
},
|
|
5810
6179
|
candidateSet,
|
|
5811
6180
|
candidates: async (embedding2, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding2, candidateOptions, false)).items)
|
|
5812
6181
|
};
|
|
6182
|
+
let rejectedRows = 0;
|
|
6183
|
+
const rewriteLegacyTopics = async (records, token) => {
|
|
6184
|
+
const write = (batch) => persistence.putMany(
|
|
6185
|
+
batch.map((item) => ({ memory: item.memory, expectedVersion: item })),
|
|
6186
|
+
options.signal,
|
|
6187
|
+
token
|
|
6188
|
+
);
|
|
6189
|
+
try {
|
|
6190
|
+
await write(records);
|
|
6191
|
+
return true;
|
|
6192
|
+
} catch (error) {
|
|
6193
|
+
if (!isVersionConflict(error) && !isRejectedRow(error)) throw error;
|
|
6194
|
+
if (records.length === 1) {
|
|
6195
|
+
if (isRejectedRow(error)) rejectedRows++;
|
|
6196
|
+
return false;
|
|
6197
|
+
}
|
|
6198
|
+
let complete = true;
|
|
6199
|
+
for (const item of records)
|
|
6200
|
+
await write([item]).catch((rowError) => {
|
|
6201
|
+
if (isRejectedRow(rowError)) rejectedRows++;
|
|
6202
|
+
else if (!isVersionConflict(rowError)) throw rowError;
|
|
6203
|
+
complete = false;
|
|
6204
|
+
});
|
|
6205
|
+
return complete;
|
|
6206
|
+
}
|
|
6207
|
+
};
|
|
6208
|
+
const upgradeLegacyTopics = () => withRemoteWorkLease(persistence, "topics", TOPIC_UPGRADE_PROCESSOR, async (token, lease) => {
|
|
6209
|
+
let cursor;
|
|
6210
|
+
let complete = true;
|
|
6211
|
+
do {
|
|
6212
|
+
options.signal?.throwIfAborted();
|
|
6213
|
+
if (lease.aborted) return false;
|
|
6214
|
+
const page = await fetchQueryPage({
|
|
6215
|
+
topics_legacy: true,
|
|
6216
|
+
include_archived: true,
|
|
6217
|
+
include_quarantined: true,
|
|
6218
|
+
include_superseded: true,
|
|
6219
|
+
limit: TOPIC_UPGRADE_PAGE,
|
|
6220
|
+
...cursor !== void 0 && { cursor },
|
|
6221
|
+
signal: options.signal
|
|
6222
|
+
});
|
|
6223
|
+
const { items } = await decodeAll(page.items);
|
|
6224
|
+
const legacy = items.filter((item) => codec.isLegacy(snapshots.get(item)?.encryptedTopics));
|
|
6225
|
+
if (legacy.length && !await rewriteLegacyTopics(legacy, token)) complete = false;
|
|
6226
|
+
cursor = page.next_cursor;
|
|
6227
|
+
} while (cursor);
|
|
6228
|
+
if (rejectedRows)
|
|
6229
|
+
getLogger().warn(
|
|
6230
|
+
`[memory/remote] Nearby rejected ${rejectedRows} rows during the topic upgrade; they keep legacy topics`
|
|
6231
|
+
);
|
|
6232
|
+
return complete;
|
|
6233
|
+
});
|
|
6234
|
+
if (legacyTopicRows)
|
|
6235
|
+
void upgradeLegacyTopics().then((complete) => {
|
|
6236
|
+
if (complete) legacyTopicRows = false;
|
|
6237
|
+
}).catch((error) => {
|
|
6238
|
+
if (!options.signal?.aborted)
|
|
6239
|
+
getLogger().warn("[memory/remote] Topic upgrade failed:", error);
|
|
6240
|
+
});
|
|
6241
|
+
return persistence;
|
|
5813
6242
|
}
|
|
5814
6243
|
|
|
5815
6244
|
// src/lib/chat/inbox.ts
|
|
@@ -6283,9 +6712,9 @@ function toResponsesFormat(tool) {
|
|
|
6283
6712
|
function getCachedServerTools() {
|
|
6284
6713
|
if (typeof localStorage === "undefined") return null;
|
|
6285
6714
|
try {
|
|
6286
|
-
const
|
|
6287
|
-
if (!
|
|
6288
|
-
const parsed = JSON.parse(
|
|
6715
|
+
const cached2 = localStorage.getItem(SERVER_TOOLS_CACHE_KEY);
|
|
6716
|
+
if (!cached2) return null;
|
|
6717
|
+
const parsed = JSON.parse(cached2);
|
|
6289
6718
|
if (parsed.version !== CACHE_VERSION) {
|
|
6290
6719
|
removeLocalStorageCache();
|
|
6291
6720
|
return null;
|
|
@@ -6329,8 +6758,8 @@ function clearServerToolsCache(cache = localStorageToolsCache) {
|
|
|
6329
6758
|
return cache.clear?.();
|
|
6330
6759
|
}
|
|
6331
6760
|
function getToolsChecksum2(cache = localStorageToolsCache) {
|
|
6332
|
-
const
|
|
6333
|
-
return
|
|
6761
|
+
const cached2 = cache.get();
|
|
6762
|
+
return cached2 instanceof Promise ? cached2.then((c) => c?.checksum) : cached2?.checksum;
|
|
6334
6763
|
}
|
|
6335
6764
|
function shouldRefreshTools(responseChecksum, cache = localStorageToolsCache) {
|
|
6336
6765
|
if (!responseChecksum) {
|
|
@@ -6393,33 +6822,33 @@ async function getServerTools(options) {
|
|
|
6393
6822
|
} catch (error) {
|
|
6394
6823
|
getLogger().warn("[serverTools] Cache read failed; falling through to server fetch:", error);
|
|
6395
6824
|
}
|
|
6396
|
-
const
|
|
6397
|
-
const cacheValid = !isCacheExpired(
|
|
6398
|
-
if (
|
|
6399
|
-
return
|
|
6825
|
+
const cached2 = rawCached && rawCached.version === CACHE_VERSION ? rawCached : null;
|
|
6826
|
+
const cacheValid = !isCacheExpired(cached2, cacheExpirationMs);
|
|
6827
|
+
if (cached2 && cacheValid && !forceRefresh) {
|
|
6828
|
+
return cached2.tools;
|
|
6400
6829
|
}
|
|
6401
6830
|
try {
|
|
6402
6831
|
const { BASE_URL: BASE_URL2 } = await import("./clientConfig-VPOGQRNP.mjs");
|
|
6403
6832
|
const effectiveBaseUrl = baseUrl ?? BASE_URL2;
|
|
6404
|
-
const validator =
|
|
6833
|
+
const validator = cached2 && !forceRefresh ? cached2.etag : void 0;
|
|
6405
6834
|
let authHeaders;
|
|
6406
6835
|
if (apiKey) {
|
|
6407
6836
|
authHeaders = { "X-API-Key": apiKey };
|
|
6408
6837
|
} else {
|
|
6409
6838
|
if (!getToken) {
|
|
6410
6839
|
getLogger().warn("[serverTools] No auth method available for fetching tools");
|
|
6411
|
-
return
|
|
6840
|
+
return cached2?.tools ?? [];
|
|
6412
6841
|
}
|
|
6413
6842
|
const token = await getToken();
|
|
6414
6843
|
if (!token) {
|
|
6415
6844
|
getLogger().warn("[serverTools] No auth token available for fetching tools");
|
|
6416
|
-
return
|
|
6845
|
+
return cached2?.tools ?? [];
|
|
6417
6846
|
}
|
|
6418
6847
|
authHeaders = { Authorization: `Bearer ${token}` };
|
|
6419
6848
|
}
|
|
6420
6849
|
const result = await fetchServerToolsFromApi(effectiveBaseUrl, authHeaders, validator);
|
|
6421
6850
|
if (result.notModified) {
|
|
6422
|
-
const confirmed =
|
|
6851
|
+
const confirmed = cached2;
|
|
6423
6852
|
await persistCache({ ...confirmed, timestamp: Date.now() });
|
|
6424
6853
|
return confirmed.tools;
|
|
6425
6854
|
}
|
|
@@ -6427,9 +6856,9 @@ async function getServerTools(options) {
|
|
|
6427
6856
|
return result.tools;
|
|
6428
6857
|
} catch (error) {
|
|
6429
6858
|
getLogger().error("[serverTools] Failed to fetch server tools:", error);
|
|
6430
|
-
if (
|
|
6859
|
+
if (cached2?.tools) {
|
|
6431
6860
|
getLogger().warn("[serverTools] Using stale cached tools due to fetch error");
|
|
6432
|
-
return
|
|
6861
|
+
return cached2.tools;
|
|
6433
6862
|
}
|
|
6434
6863
|
return [];
|
|
6435
6864
|
}
|
|
@@ -7515,13 +7944,13 @@ function extractParamGroups(content) {
|
|
|
7515
7944
|
}
|
|
7516
7945
|
function mergeXaiInlineParameterTags(content, toolCalls) {
|
|
7517
7946
|
if (!content || !content.includes(PARAM_MARKER)) return content;
|
|
7518
|
-
const
|
|
7519
|
-
if (
|
|
7947
|
+
const entries2 = Array.from(toolCalls.values());
|
|
7948
|
+
if (entries2.length === 0) return content;
|
|
7520
7949
|
const groups = extractParamGroups(content);
|
|
7521
7950
|
if (groups.length === 0) return content;
|
|
7522
|
-
const pairCount = Math.min(groups.length,
|
|
7951
|
+
const pairCount = Math.min(groups.length, entries2.length);
|
|
7523
7952
|
for (let i = 0; i < pairCount; i++) {
|
|
7524
|
-
const target =
|
|
7953
|
+
const target = entries2[i];
|
|
7525
7954
|
const params = groups[i];
|
|
7526
7955
|
if (!target || !params) continue;
|
|
7527
7956
|
let args = {};
|
|
@@ -10985,21 +11414,21 @@ function contextFields(context) {
|
|
|
10985
11414
|
);
|
|
10986
11415
|
}
|
|
10987
11416
|
function conversationContext(data) {
|
|
10988
|
-
const
|
|
10989
|
-
return
|
|
11417
|
+
const entries2 = Object.entries(data).filter(([field10]) => field10.startsWith(CONTEXT_FIELD_PREFIX)).map(([field10, value]) => [field10.slice(CONTEXT_FIELD_PREFIX.length), value]);
|
|
11418
|
+
return entries2.length > 0 ? plain(Object.fromEntries(entries2)) : void 0;
|
|
10990
11419
|
}
|
|
10991
|
-
function toConversation(
|
|
10992
|
-
const pinnedAt = number(
|
|
10993
|
-
const projectId = text3(
|
|
10994
|
-
const context = conversationContext(
|
|
11420
|
+
function toConversation(record3) {
|
|
11421
|
+
const pinnedAt = number(record3.data.pinnedAt);
|
|
11422
|
+
const projectId = text3(record3.data.projectId);
|
|
11423
|
+
const context = conversationContext(record3.data);
|
|
10995
11424
|
return {
|
|
10996
|
-
uniqueId:
|
|
10997
|
-
conversationId:
|
|
10998
|
-
title: text3(
|
|
11425
|
+
uniqueId: record3.id,
|
|
11426
|
+
conversationId: record3.id,
|
|
11427
|
+
title: text3(record3.data.title) ?? "",
|
|
10999
11428
|
...projectId ? { projectId } : {},
|
|
11000
|
-
createdAt: new Date(
|
|
11001
|
-
updatedAt: new Date(
|
|
11002
|
-
isDeleted:
|
|
11429
|
+
createdAt: new Date(record3.createdAt),
|
|
11430
|
+
updatedAt: new Date(record3.updatedAt),
|
|
11431
|
+
isDeleted: record3.isDeleted,
|
|
11003
11432
|
pinnedAt: pinnedAt ? new Date(pinnedAt) : null,
|
|
11004
11433
|
...context ? { context } : {}
|
|
11005
11434
|
};
|
|
@@ -11021,21 +11450,21 @@ function messageData(options) {
|
|
|
11021
11450
|
...anuma ? { anuma } : {}
|
|
11022
11451
|
});
|
|
11023
11452
|
}
|
|
11024
|
-
function toMessage(
|
|
11025
|
-
const { chunkOffsets: _offsets, truncated: _truncated, anuma: rawAnuma, ...fields } =
|
|
11453
|
+
function toMessage(record3) {
|
|
11454
|
+
const { chunkOffsets: _offsets, truncated: _truncated, anuma: rawAnuma, ...fields } = record3.data;
|
|
11026
11455
|
const anuma = readAnumaTurn(rawAnuma);
|
|
11027
11456
|
return {
|
|
11028
11457
|
...anuma ? { anuma } : {},
|
|
11029
11458
|
...fields,
|
|
11030
|
-
uniqueId:
|
|
11031
|
-
messageId:
|
|
11032
|
-
conversationId:
|
|
11033
|
-
createdAt: new Date(
|
|
11034
|
-
updatedAt: new Date(
|
|
11459
|
+
uniqueId: record3.id,
|
|
11460
|
+
messageId: record3.sortKey,
|
|
11461
|
+
conversationId: record3.conversationId,
|
|
11462
|
+
createdAt: new Date(record3.createdAt),
|
|
11463
|
+
updatedAt: new Date(record3.updatedAt)
|
|
11035
11464
|
};
|
|
11036
11465
|
}
|
|
11037
|
-
function chunkOffsets(
|
|
11038
|
-
const offsets =
|
|
11466
|
+
function chunkOffsets(record3) {
|
|
11467
|
+
const offsets = record3.data.chunkOffsets;
|
|
11039
11468
|
return Array.isArray(offsets) ? offsets : void 0;
|
|
11040
11469
|
}
|
|
11041
11470
|
function toSkeletons(records) {
|
|
@@ -11056,15 +11485,15 @@ function toSkeletons(records) {
|
|
|
11056
11485
|
};
|
|
11057
11486
|
});
|
|
11058
11487
|
}
|
|
11059
|
-
function toSummary(
|
|
11488
|
+
function toSummary(record3) {
|
|
11060
11489
|
return {
|
|
11061
|
-
uniqueId:
|
|
11062
|
-
conversationId:
|
|
11063
|
-
summary: text3(
|
|
11064
|
-
summarizedUpTo: text3(
|
|
11065
|
-
tokenCount: number(
|
|
11066
|
-
createdAt: new Date(
|
|
11067
|
-
updatedAt: new Date(
|
|
11490
|
+
uniqueId: record3.id,
|
|
11491
|
+
conversationId: record3.id,
|
|
11492
|
+
summary: text3(record3.data.summary) ?? "",
|
|
11493
|
+
summarizedUpTo: text3(record3.data.summarizedUpTo) ?? "",
|
|
11494
|
+
tokenCount: number(record3.data.tokenCount) ?? 0,
|
|
11495
|
+
createdAt: new Date(record3.createdAt),
|
|
11496
|
+
updatedAt: new Date(record3.updatedAt)
|
|
11068
11497
|
};
|
|
11069
11498
|
}
|
|
11070
11499
|
function links(data) {
|
|
@@ -11090,10 +11519,10 @@ function applyLinkOps(data, ops) {
|
|
|
11090
11519
|
}
|
|
11091
11520
|
return plain({ links: current });
|
|
11092
11521
|
}
|
|
11093
|
-
function toLinks(
|
|
11094
|
-
return links(
|
|
11095
|
-
uniqueId: `${
|
|
11096
|
-
conversationId:
|
|
11522
|
+
function toLinks(record3) {
|
|
11523
|
+
return links(record3.data).map((l) => ({
|
|
11524
|
+
uniqueId: `${record3.id}:${l.memoryId}`,
|
|
11525
|
+
conversationId: record3.id,
|
|
11097
11526
|
memoryId: l.memoryId,
|
|
11098
11527
|
score: l.score,
|
|
11099
11528
|
createdAt: new Date(l.createdAt)
|
|
@@ -11102,24 +11531,24 @@ function toLinks(record2) {
|
|
|
11102
11531
|
function bytes(value) {
|
|
11103
11532
|
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
11104
11533
|
}
|
|
11105
|
-
function fitRecord(
|
|
11106
|
-
if (
|
|
11107
|
-
const data = { ...
|
|
11534
|
+
function fitRecord(record3) {
|
|
11535
|
+
if (record3.kind !== "message" || bytes(record3) <= recordBudgetBytes) return record3;
|
|
11536
|
+
const data = { ...record3.data };
|
|
11108
11537
|
const truncated = [];
|
|
11109
11538
|
for (const field10 of droppable) {
|
|
11110
|
-
if (bytes({ ...
|
|
11539
|
+
if (bytes({ ...record3, data }) <= recordBudgetBytes) break;
|
|
11111
11540
|
if (data[field10] === void 0) continue;
|
|
11112
11541
|
delete data[field10];
|
|
11113
11542
|
truncated.push(field10);
|
|
11114
11543
|
}
|
|
11115
11544
|
const content = text3(data.content) ?? "";
|
|
11116
|
-
const over = bytes({ ...
|
|
11545
|
+
const over = bytes({ ...record3, data }) - recordBudgetBytes;
|
|
11117
11546
|
if (over > 0) {
|
|
11118
11547
|
const encoded = new TextEncoder().encode(content);
|
|
11119
11548
|
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
11120
11549
|
truncated.push("content");
|
|
11121
11550
|
}
|
|
11122
|
-
return { ...
|
|
11551
|
+
return { ...record3, data: { ...data, truncated } };
|
|
11123
11552
|
}
|
|
11124
11553
|
function acceptedVector(vector2) {
|
|
11125
11554
|
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
@@ -11163,8 +11592,8 @@ function anumaTurnContent(bubbles) {
|
|
|
11163
11592
|
return bubbles.join("\n\n");
|
|
11164
11593
|
}
|
|
11165
11594
|
function anumaLastReadSortKey(conversation) {
|
|
11166
|
-
const
|
|
11167
|
-
const state =
|
|
11595
|
+
const record3 = conversation && "record" in conversation ? conversation.record : conversation;
|
|
11596
|
+
const state = record3?.data.anuma;
|
|
11168
11597
|
if (!isObject(state)) return 0;
|
|
11169
11598
|
const sortKey = state.lastReadSortKey;
|
|
11170
11599
|
return Number.isSafeInteger(sortKey) && sortKey > 0 ? sortKey : 0;
|
|
@@ -11217,19 +11646,19 @@ async function markAnumaRead(store, sortKey, options = {}) {
|
|
|
11217
11646
|
const current = await ensureAnumaConversation(store, options);
|
|
11218
11647
|
const read = anumaLastReadSortKey(current);
|
|
11219
11648
|
if (sortKey <= read) return current;
|
|
11220
|
-
const
|
|
11221
|
-
const state = isObject(
|
|
11222
|
-
const data = plain({ ...
|
|
11649
|
+
const record3 = current.record;
|
|
11650
|
+
const state = isObject(record3.data.anuma) ? record3.data.anuma : {};
|
|
11651
|
+
const data = plain({ ...record3.data, anuma: { ...state, lastReadSortKey: sortKey } });
|
|
11223
11652
|
try {
|
|
11224
11653
|
const [written] = await store.putMany(
|
|
11225
11654
|
[
|
|
11226
11655
|
{
|
|
11227
11656
|
expectedVersion: current.version,
|
|
11228
11657
|
record: {
|
|
11229
|
-
...
|
|
11658
|
+
...record3,
|
|
11230
11659
|
data,
|
|
11231
|
-
sortKey: conversationSortKey(data,
|
|
11232
|
-
updatedAt: Math.max(
|
|
11660
|
+
sortKey: conversationSortKey(data, record3.createdAt),
|
|
11661
|
+
updatedAt: Math.max(record3.updatedAt, now())
|
|
11233
11662
|
}
|
|
11234
11663
|
}
|
|
11235
11664
|
],
|
|
@@ -11264,22 +11693,22 @@ function createSummaryContext(database, encryption = {}) {
|
|
|
11264
11693
|
summariesCollection: database.get("conversation_summaries")
|
|
11265
11694
|
};
|
|
11266
11695
|
}
|
|
11267
|
-
function modelToStored(
|
|
11696
|
+
function modelToStored(record3, summary) {
|
|
11268
11697
|
return {
|
|
11269
|
-
uniqueId:
|
|
11270
|
-
conversationId:
|
|
11698
|
+
uniqueId: record3.id,
|
|
11699
|
+
conversationId: record3.conversationId,
|
|
11271
11700
|
summary,
|
|
11272
|
-
summarizedUpTo:
|
|
11273
|
-
tokenCount:
|
|
11274
|
-
createdAt:
|
|
11275
|
-
updatedAt:
|
|
11701
|
+
summarizedUpTo: record3.summarizedUpTo,
|
|
11702
|
+
tokenCount: record3.tokenCount,
|
|
11703
|
+
createdAt: record3.createdAt,
|
|
11704
|
+
updatedAt: record3.updatedAt
|
|
11276
11705
|
};
|
|
11277
11706
|
}
|
|
11278
11707
|
async function getConversationSummaryOp(ctx, conversationId) {
|
|
11279
11708
|
const results = await ctx.summariesCollection.query(Q4.where("conversation_id", conversationId)).fetch();
|
|
11280
11709
|
if (results.length === 0) return null;
|
|
11281
|
-
const
|
|
11282
|
-
const stored2 = modelToStored(
|
|
11710
|
+
const record3 = results[0];
|
|
11711
|
+
const stored2 = modelToStored(record3, record3.summary);
|
|
11283
11712
|
if (ctx.walletAddress && isEncrypted(stored2.summary)) {
|
|
11284
11713
|
if (ctx.signMessage) {
|
|
11285
11714
|
try {
|
|
@@ -11298,7 +11727,7 @@ async function getConversationSummaryOp(ctx, conversationId) {
|
|
|
11298
11727
|
ctx.embeddedWalletSigner
|
|
11299
11728
|
);
|
|
11300
11729
|
await ctx.database.write(async () => {
|
|
11301
|
-
const current = await ctx.summariesCollection.query(Q4.where("id",
|
|
11730
|
+
const current = await ctx.summariesCollection.query(Q4.where("id", record3.id)).fetch();
|
|
11302
11731
|
if (current[0]?.summary === stored2.summary) {
|
|
11303
11732
|
await current[0].update((rec) => {
|
|
11304
11733
|
rec.summary = encryptedSummary;
|
|
@@ -11313,19 +11742,19 @@ async function getConversationSummaryOp(ctx, conversationId) {
|
|
|
11313
11742
|
}
|
|
11314
11743
|
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
11315
11744
|
const revision2 = getConversationRevision(ctx.database, conversationId);
|
|
11316
|
-
let
|
|
11745
|
+
let record3;
|
|
11317
11746
|
const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
|
|
11318
11747
|
await ctx.database.write(async () => {
|
|
11319
11748
|
assertConversationRevision(ctx.database, conversationId, revision2);
|
|
11320
11749
|
const existing = await ctx.summariesCollection.query(Q4.where("conversation_id", conversationId)).fetch();
|
|
11321
11750
|
if (existing.length > 0) {
|
|
11322
|
-
|
|
11751
|
+
record3 = await existing[0].update((rec) => {
|
|
11323
11752
|
rec.summary = encryptedSummary;
|
|
11324
11753
|
rec.summarizedUpTo = summarizedUpTo;
|
|
11325
11754
|
rec.tokenCount = tokenCount;
|
|
11326
11755
|
});
|
|
11327
11756
|
} else {
|
|
11328
|
-
|
|
11757
|
+
record3 = await ctx.summariesCollection.create((rec) => {
|
|
11329
11758
|
rec.conversationId = conversationId;
|
|
11330
11759
|
rec.summary = encryptedSummary;
|
|
11331
11760
|
rec.summarizedUpTo = summarizedUpTo;
|
|
@@ -11333,13 +11762,13 @@ async function upsertConversationSummaryOp(ctx, conversationId, summary, summari
|
|
|
11333
11762
|
});
|
|
11334
11763
|
}
|
|
11335
11764
|
});
|
|
11336
|
-
return modelToStored(
|
|
11765
|
+
return modelToStored(record3, summary);
|
|
11337
11766
|
}
|
|
11338
11767
|
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
11339
11768
|
await ctx.database.write(async () => {
|
|
11340
11769
|
const existing = await ctx.summariesCollection.query(Q4.where("conversation_id", conversationId)).fetch();
|
|
11341
|
-
for (const
|
|
11342
|
-
await
|
|
11770
|
+
for (const record3 of existing) {
|
|
11771
|
+
await record3.destroyPermanently();
|
|
11343
11772
|
}
|
|
11344
11773
|
});
|
|
11345
11774
|
}
|
|
@@ -11415,7 +11844,7 @@ function messageRecord(message) {
|
|
|
11415
11844
|
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
11416
11845
|
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
11417
11846
|
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
11418
|
-
const
|
|
11847
|
+
const record3 = fitRecord({
|
|
11419
11848
|
kind: "message",
|
|
11420
11849
|
id: message.uniqueId,
|
|
11421
11850
|
conversationId: message.conversationId,
|
|
@@ -11429,7 +11858,7 @@ function messageRecord(message) {
|
|
|
11429
11858
|
}
|
|
11430
11859
|
});
|
|
11431
11860
|
return {
|
|
11432
|
-
record:
|
|
11861
|
+
record: record3,
|
|
11433
11862
|
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
11434
11863
|
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
11435
11864
|
};
|
|
@@ -11577,15 +12006,15 @@ function ref(value) {
|
|
|
11577
12006
|
function sameMetadata(a, b) {
|
|
11578
12007
|
return metadata.every((key3) => a[key3] === b[key3]);
|
|
11579
12008
|
}
|
|
11580
|
-
function wire(
|
|
12009
|
+
function wire(record3, payload) {
|
|
11581
12010
|
return {
|
|
11582
|
-
kind:
|
|
11583
|
-
id:
|
|
11584
|
-
conversation_id:
|
|
11585
|
-
sort_key:
|
|
11586
|
-
created_at:
|
|
11587
|
-
updated_at:
|
|
11588
|
-
is_deleted:
|
|
12011
|
+
kind: record3.kind,
|
|
12012
|
+
id: record3.id,
|
|
12013
|
+
conversation_id: record3.conversationId,
|
|
12014
|
+
sort_key: record3.sortKey,
|
|
12015
|
+
created_at: record3.createdAt,
|
|
12016
|
+
updated_at: record3.updatedAt,
|
|
12017
|
+
is_deleted: record3.isDeleted,
|
|
11589
12018
|
payload
|
|
11590
12019
|
};
|
|
11591
12020
|
}
|
|
@@ -11642,10 +12071,10 @@ async function createRemoteChatStore(options) {
|
|
|
11642
12071
|
serverUpdatedAt: value.server_updated_at
|
|
11643
12072
|
};
|
|
11644
12073
|
};
|
|
11645
|
-
const seal = async (
|
|
11646
|
-
if (
|
|
12074
|
+
const seal = async (record3, signal) => {
|
|
12075
|
+
if (record3.isDeleted) return "";
|
|
11647
12076
|
const payload = await encrypt(
|
|
11648
|
-
JSON.stringify({ schema: 1, account_id: accountId, key_id: keyId, record:
|
|
12077
|
+
JSON.stringify({ schema: 1, account_id: accountId, key_id: keyId, record: record3 })
|
|
11649
12078
|
);
|
|
11650
12079
|
signal?.throwIfAborted();
|
|
11651
12080
|
if (!cipherPattern.test(payload) || payload.length > maxPayload) invalid();
|
|
@@ -12009,8 +12438,8 @@ var emptyMessage = {
|
|
|
12009
12438
|
var maxPasses = 5;
|
|
12010
12439
|
var verifyBatch = 1e3;
|
|
12011
12440
|
var writeBatch = 25;
|
|
12012
|
-
function key(
|
|
12013
|
-
return `${
|
|
12441
|
+
function key(record3) {
|
|
12442
|
+
return `${record3.kind}/${record3.id}`;
|
|
12014
12443
|
}
|
|
12015
12444
|
function sealed(value) {
|
|
12016
12445
|
if (typeof value === "string") return isEncrypted(value);
|
|
@@ -12139,11 +12568,11 @@ async function missing(store, records, signal) {
|
|
|
12139
12568
|
const out = /* @__PURE__ */ new Set();
|
|
12140
12569
|
for (let i = 0; i < records.length; i += verifyBatch) {
|
|
12141
12570
|
const refs = await store.verify(
|
|
12142
|
-
records.slice(i, i + verifyBatch).map(({ record:
|
|
12143
|
-
kind:
|
|
12144
|
-
id:
|
|
12145
|
-
updatedAt:
|
|
12146
|
-
isDeleted:
|
|
12571
|
+
records.slice(i, i + verifyBatch).map(({ record: record3 }) => ({
|
|
12572
|
+
kind: record3.kind,
|
|
12573
|
+
id: record3.id,
|
|
12574
|
+
updatedAt: record3.updatedAt,
|
|
12575
|
+
isDeleted: record3.isDeleted
|
|
12147
12576
|
})),
|
|
12148
12577
|
signal
|
|
12149
12578
|
);
|
|
@@ -12183,14 +12612,14 @@ async function deletedSinceUpload(store, journal, local, signal) {
|
|
|
12183
12612
|
const live2 = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
|
|
12184
12613
|
const tombstoning = new Set(live2.map((s) => key(s.record)));
|
|
12185
12614
|
await journal.drop(gone.filter((k) => !tombstoning.has(k)));
|
|
12186
|
-
return live2.map(({ record:
|
|
12187
|
-
const empty = emptied[
|
|
12615
|
+
return live2.map(({ record: record3, version }) => {
|
|
12616
|
+
const empty = emptied[record3.kind];
|
|
12188
12617
|
return {
|
|
12189
12618
|
record: {
|
|
12190
|
-
...
|
|
12619
|
+
...record3,
|
|
12191
12620
|
isDeleted: !empty,
|
|
12192
12621
|
data: empty ?? {},
|
|
12193
|
-
updatedAt: Math.max(Date.now(),
|
|
12622
|
+
updatedAt: Math.max(Date.now(), record3.updatedAt + 1)
|
|
12194
12623
|
},
|
|
12195
12624
|
expectedVersion: version
|
|
12196
12625
|
};
|
|
@@ -12539,8 +12968,8 @@ function createVaultAttachments(options) {
|
|
|
12539
12968
|
},
|
|
12540
12969
|
async read(attachmentId, signal) {
|
|
12541
12970
|
if (!attachmentIdPattern2.test(attachmentId)) invalidAttachment();
|
|
12542
|
-
const
|
|
12543
|
-
if (
|
|
12971
|
+
const cached2 = await cache?.get(attachmentId).catch(() => null);
|
|
12972
|
+
if (cached2) return cached2;
|
|
12544
12973
|
for (let attempt = 0; ; attempt++) {
|
|
12545
12974
|
const found = await withRetry(() => store.attachments.get(attachmentId, signal), signal);
|
|
12546
12975
|
if (!found?.download) return null;
|
|
@@ -12569,8 +12998,8 @@ function validRef(value) {
|
|
|
12569
12998
|
const ref3 = value;
|
|
12570
12999
|
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;
|
|
12571
13000
|
}
|
|
12572
|
-
function vaultAttachmentRefs(
|
|
12573
|
-
const refs =
|
|
13001
|
+
function vaultAttachmentRefs(record3) {
|
|
13002
|
+
const refs = record3.data.vaultAttachments;
|
|
12574
13003
|
return Array.isArray(refs) ? refs.filter(validRef) : [];
|
|
12575
13004
|
}
|
|
12576
13005
|
function journalKey(messageId, fileId) {
|
|
@@ -12778,14 +13207,14 @@ function sameRecord(a, b) {
|
|
|
12778
13207
|
return a.sortKey === b.sortKey && a.isDeleted === b.isDeleted && sameJson(a.data, b.data);
|
|
12779
13208
|
}
|
|
12780
13209
|
function toWrite(base, patch) {
|
|
12781
|
-
const
|
|
12782
|
-
if (!
|
|
12783
|
-
if (base && patch.embeddings === void 0 && sameRecord(base.record,
|
|
13210
|
+
const record3 = applyPatch(base?.record, patch);
|
|
13211
|
+
if (!record3) return void 0;
|
|
13212
|
+
if (base && patch.embeddings === void 0 && sameRecord(base.record, record3)) return null;
|
|
12784
13213
|
return {
|
|
12785
|
-
record: fitRecord(
|
|
13214
|
+
record: fitRecord(record3),
|
|
12786
13215
|
expectedVersion: base?.version ?? 0,
|
|
12787
|
-
...patch.embeddings !== void 0 && !
|
|
12788
|
-
...patch.embeddingModel !== void 0 && !
|
|
13216
|
+
...patch.embeddings !== void 0 && !record3.isDeleted ? { embeddings: patch.embeddings } : {},
|
|
13217
|
+
...patch.embeddingModel !== void 0 && !record3.isDeleted ? { embeddingModel: patch.embeddingModel } : {}
|
|
12789
13218
|
};
|
|
12790
13219
|
}
|
|
12791
13220
|
var maxWrites = 25;
|
|
@@ -12919,11 +13348,11 @@ function createVaultChatBackend(options) {
|
|
|
12919
13348
|
for (const listener of [...listeners]) listener(event);
|
|
12920
13349
|
};
|
|
12921
13350
|
const view = (k) => {
|
|
12922
|
-
let
|
|
13351
|
+
let record3 = confirmed.get(k)?.record;
|
|
12923
13352
|
for (const patch of [inflight.get(k), pending.get(k)]) {
|
|
12924
|
-
if (patch)
|
|
13353
|
+
if (patch) record3 = applyPatch(record3, patch) ?? record3;
|
|
12925
13354
|
}
|
|
12926
|
-
return
|
|
13355
|
+
return record3;
|
|
12927
13356
|
};
|
|
12928
13357
|
const conversationLive = (conversationId) => {
|
|
12929
13358
|
const conversation2 = view(key2("conversation", conversationId));
|
|
@@ -12934,10 +13363,10 @@ function createVaultChatBackend(options) {
|
|
|
12934
13363
|
const out = [];
|
|
12935
13364
|
for (const k of keys) {
|
|
12936
13365
|
if (!k.startsWith(`${kind}/`)) continue;
|
|
12937
|
-
const
|
|
12938
|
-
if (!
|
|
12939
|
-
if (conversationId !== void 0 &&
|
|
12940
|
-
out.push(
|
|
13366
|
+
const record3 = view(k);
|
|
13367
|
+
if (!record3 || record3.isDeleted && !includeDeleted) continue;
|
|
13368
|
+
if (conversationId !== void 0 && record3.conversationId !== conversationId) continue;
|
|
13369
|
+
out.push(record3);
|
|
12941
13370
|
}
|
|
12942
13371
|
return out;
|
|
12943
13372
|
};
|
|
@@ -12948,7 +13377,7 @@ function createVaultChatBackend(options) {
|
|
|
12948
13377
|
account: cache.account,
|
|
12949
13378
|
cursor: cursor ?? "",
|
|
12950
13379
|
records: [...confirmed.values()].filter(
|
|
12951
|
-
({ record:
|
|
13380
|
+
({ record: record3 }) => record3.kind === "conversation" || record3.kind !== "project" && keep.has(record3.conversationId)
|
|
12952
13381
|
),
|
|
12953
13382
|
threads: kept,
|
|
12954
13383
|
absent: [...checked].filter((k) => {
|
|
@@ -13262,17 +13691,17 @@ function createVaultChatBackend(options) {
|
|
|
13262
13691
|
return loading;
|
|
13263
13692
|
};
|
|
13264
13693
|
const applyRemote = (snapshot) => {
|
|
13265
|
-
const { record:
|
|
13266
|
-
const k = key2(
|
|
13267
|
-
if (
|
|
13694
|
+
const { record: record3 } = snapshot;
|
|
13695
|
+
const k = key2(record3.kind, record3.id);
|
|
13696
|
+
if (record3.kind === "conversation") {
|
|
13268
13697
|
if (!merge(snapshot)) return;
|
|
13269
|
-
if (
|
|
13270
|
-
announce([
|
|
13698
|
+
if (record3.isDeleted) forgetConversation(record3.id);
|
|
13699
|
+
announce([record3]);
|
|
13271
13700
|
return;
|
|
13272
13701
|
}
|
|
13273
|
-
if (
|
|
13274
|
-
const relevant2 = threads.has(
|
|
13275
|
-
if (relevant2 && merge(snapshot)) announce([
|
|
13702
|
+
if (record3.kind === "project") return;
|
|
13703
|
+
const relevant2 = threads.has(record3.conversationId) || confirmed.has(k) || checked.has(k) && record3.kind !== "message";
|
|
13704
|
+
if (relevant2 && merge(snapshot)) announce([record3]);
|
|
13276
13705
|
};
|
|
13277
13706
|
const listIndex = async (source) => {
|
|
13278
13707
|
const index = [];
|
|
@@ -13423,8 +13852,8 @@ function createVaultChatBackend(options) {
|
|
|
13423
13852
|
checked.add(k);
|
|
13424
13853
|
if (found) merge(found);
|
|
13425
13854
|
}
|
|
13426
|
-
const
|
|
13427
|
-
return
|
|
13855
|
+
const record3 = view(k);
|
|
13856
|
+
return record3 && !record3.isDeleted && conversationLive(record3.conversationId) ? record3 : void 0;
|
|
13428
13857
|
};
|
|
13429
13858
|
const child = async (kind, conversationId) => {
|
|
13430
13859
|
await available2();
|
|
@@ -13461,19 +13890,19 @@ function createVaultChatBackend(options) {
|
|
|
13461
13890
|
await backend.deleteSummary(conversationId);
|
|
13462
13891
|
};
|
|
13463
13892
|
const storedMessage = async (uniqueId) => {
|
|
13464
|
-
const
|
|
13465
|
-
return
|
|
13893
|
+
const record3 = await message(uniqueId);
|
|
13894
|
+
return record3 ? toMessage(record3) : null;
|
|
13466
13895
|
};
|
|
13467
13896
|
const patchMessage = async (uniqueId, patch) => {
|
|
13468
|
-
const
|
|
13469
|
-
if (!
|
|
13897
|
+
const record3 = await message(uniqueId);
|
|
13898
|
+
if (!record3) return null;
|
|
13470
13899
|
await enqueue({
|
|
13471
13900
|
kind: "message",
|
|
13472
13901
|
id: uniqueId,
|
|
13473
|
-
conversationId:
|
|
13902
|
+
conversationId: record3.conversationId,
|
|
13474
13903
|
...patch
|
|
13475
13904
|
});
|
|
13476
|
-
emit({ type: "messages", conversationId:
|
|
13905
|
+
emit({ type: "messages", conversationId: record3.conversationId, origin: "local" });
|
|
13477
13906
|
const updated = view(key2("message", uniqueId));
|
|
13478
13907
|
return updated && !updated.isDeleted ? toMessage(updated) : null;
|
|
13479
13908
|
};
|
|
@@ -13498,12 +13927,12 @@ function createVaultChatBackend(options) {
|
|
|
13498
13927
|
});
|
|
13499
13928
|
const backend = {
|
|
13500
13929
|
async getConversation(conversationId) {
|
|
13501
|
-
const
|
|
13502
|
-
return
|
|
13930
|
+
const record3 = await conversation(conversationId);
|
|
13931
|
+
return record3 && !record3.isDeleted ? toConversation(record3) : null;
|
|
13503
13932
|
},
|
|
13504
13933
|
async getConversations(query) {
|
|
13505
13934
|
await available2();
|
|
13506
|
-
return all("conversation").filter((
|
|
13935
|
+
return all("conversation").filter((record3) => record3.id !== ANUMA_CONVERSATION_ID).map(toConversation).filter(
|
|
13507
13936
|
(c) => query?.projectId === void 0 || (query.projectId === null ? !c.projectId : c.projectId === query.projectId)
|
|
13508
13937
|
).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
13509
13938
|
},
|
|
@@ -13542,13 +13971,13 @@ function createVaultChatBackend(options) {
|
|
|
13542
13971
|
async updateConversationContext(conversationId, context) {
|
|
13543
13972
|
const set = contextFields(context);
|
|
13544
13973
|
if (Object.keys(set).length > 0) return updateConversation(conversationId, set);
|
|
13545
|
-
const
|
|
13546
|
-
return !!
|
|
13974
|
+
const record3 = await conversation(conversationId);
|
|
13975
|
+
return !!record3 && !record3.isDeleted;
|
|
13547
13976
|
},
|
|
13548
13977
|
async deleteConversation(conversationId) {
|
|
13549
13978
|
if (conversationId === ANUMA_CONVERSATION_ID) return false;
|
|
13550
|
-
const
|
|
13551
|
-
if (!
|
|
13979
|
+
const record3 = await conversation(conversationId);
|
|
13980
|
+
if (!record3 || record3.isDeleted) return false;
|
|
13552
13981
|
for (const [k, patch] of pending)
|
|
13553
13982
|
if (patch.conversationId === conversationId) pending.delete(k);
|
|
13554
13983
|
await enqueue({ kind: "conversation", id: conversationId, conversationId: "", delete: true });
|
|
@@ -13584,8 +14013,8 @@ function createVaultChatBackend(options) {
|
|
|
13584
14013
|
const unknown = ids.map((id2) => key2("message", id2)).filter((k) => !view(k) && !checked.has(k));
|
|
13585
14014
|
await refresh(unknown);
|
|
13586
14015
|
return ids.flatMap((id2) => {
|
|
13587
|
-
const
|
|
13588
|
-
return
|
|
14016
|
+
const record3 = view(key2("message", id2));
|
|
14017
|
+
return record3 && !record3.isDeleted && conversationLive(record3.conversationId) ? [toMessage(record3)] : [];
|
|
13589
14018
|
});
|
|
13590
14019
|
},
|
|
13591
14020
|
async getMessageCount(conversationId) {
|
|
@@ -13593,8 +14022,8 @@ function createVaultChatBackend(options) {
|
|
|
13593
14022
|
},
|
|
13594
14023
|
async getToolCallEventIds(conversationId) {
|
|
13595
14024
|
const ids = /* @__PURE__ */ new Set();
|
|
13596
|
-
for (const
|
|
13597
|
-
const events =
|
|
14025
|
+
for (const record3 of await thread(conversationId)) {
|
|
14026
|
+
const events = record3.data.toolCallEvents;
|
|
13598
14027
|
if (!Array.isArray(events)) continue;
|
|
13599
14028
|
for (const event of events)
|
|
13600
14029
|
if (event && typeof event === "object" && !Array.isArray(event) && typeof event.id === "string")
|
|
@@ -13687,21 +14116,21 @@ function createVaultChatBackend(options) {
|
|
|
13687
14116
|
},
|
|
13688
14117
|
async clearMessages(conversationId) {
|
|
13689
14118
|
await invalidateSummary(conversationId);
|
|
13690
|
-
for (const
|
|
13691
|
-
await enqueue({ kind: "message", id:
|
|
14119
|
+
for (const record3 of await thread(conversationId))
|
|
14120
|
+
await enqueue({ kind: "message", id: record3.id, conversationId, delete: true });
|
|
13692
14121
|
emit({ type: "messages", conversationId, origin: "local" });
|
|
13693
14122
|
},
|
|
13694
14123
|
async deleteMessage(uniqueId) {
|
|
13695
|
-
const
|
|
13696
|
-
if (!
|
|
13697
|
-
await invalidateSummary(
|
|
14124
|
+
const record3 = await message(uniqueId);
|
|
14125
|
+
if (!record3) return null;
|
|
14126
|
+
await invalidateSummary(record3.conversationId, record3);
|
|
13698
14127
|
await enqueue({
|
|
13699
14128
|
kind: "message",
|
|
13700
14129
|
id: uniqueId,
|
|
13701
|
-
conversationId:
|
|
14130
|
+
conversationId: record3.conversationId,
|
|
13702
14131
|
delete: true
|
|
13703
14132
|
});
|
|
13704
|
-
emit({ type: "messages", conversationId:
|
|
14133
|
+
emit({ type: "messages", conversationId: record3.conversationId, origin: "local" });
|
|
13705
14134
|
return uniqueId;
|
|
13706
14135
|
},
|
|
13707
14136
|
observeMessages(conversationId) {
|
|
@@ -13714,13 +14143,13 @@ function createVaultChatBackend(options) {
|
|
|
13714
14143
|
await available2();
|
|
13715
14144
|
if (query?.conversationId) await loadThread(query.conversationId);
|
|
13716
14145
|
const files = [];
|
|
13717
|
-
for (const
|
|
13718
|
-
if (!conversationLive(
|
|
13719
|
-
const stored2 = toMessage(
|
|
14146
|
+
for (const record3 of all("message", query?.conversationId)) {
|
|
14147
|
+
if (!conversationLive(record3.conversationId)) continue;
|
|
14148
|
+
const stored2 = toMessage(record3);
|
|
13720
14149
|
for (const file of stored2.files ?? [])
|
|
13721
14150
|
files.push({
|
|
13722
14151
|
...file,
|
|
13723
|
-
conversationId:
|
|
14152
|
+
conversationId: record3.conversationId,
|
|
13724
14153
|
createdAt: stored2.createdAt,
|
|
13725
14154
|
messageRole: stored2.role
|
|
13726
14155
|
});
|
|
@@ -13759,8 +14188,8 @@ function createVaultChatBackend(options) {
|
|
|
13759
14188
|
return results;
|
|
13760
14189
|
},
|
|
13761
14190
|
async getSummary(conversationId) {
|
|
13762
|
-
const
|
|
13763
|
-
return
|
|
14191
|
+
const record3 = await child("summary", conversationId);
|
|
14192
|
+
return record3 && !record3.isDeleted && record3.data.summarizedUpTo ? toSummary(record3) : null;
|
|
13764
14193
|
},
|
|
13765
14194
|
async upsertSummary(conversationId, summary, summarizedUpTo, tokenCount) {
|
|
13766
14195
|
await child("summary", conversationId);
|
|
@@ -13776,8 +14205,8 @@ function createVaultChatBackend(options) {
|
|
|
13776
14205
|
return toSummary(view(key2("summary", conversationId)));
|
|
13777
14206
|
},
|
|
13778
14207
|
async deleteSummary(conversationId) {
|
|
13779
|
-
const
|
|
13780
|
-
if (!
|
|
14208
|
+
const record3 = await child("summary", conversationId);
|
|
14209
|
+
if (!record3 || record3.isDeleted) return;
|
|
13781
14210
|
await enqueue({
|
|
13782
14211
|
kind: "summary",
|
|
13783
14212
|
id: conversationId,
|
|
@@ -13787,8 +14216,8 @@ function createVaultChatBackend(options) {
|
|
|
13787
14216
|
emit({ type: "summary", conversationId, origin: "local" });
|
|
13788
14217
|
},
|
|
13789
14218
|
async getMemoryLinks(conversationId) {
|
|
13790
|
-
const
|
|
13791
|
-
return
|
|
14219
|
+
const record3 = await child("memory_links", conversationId);
|
|
14220
|
+
return record3 && !record3.isDeleted ? toLinks(record3) : [];
|
|
13792
14221
|
},
|
|
13793
14222
|
async addMemoryLinks(conversationId, items) {
|
|
13794
14223
|
if (!conversationId || items.length === 0) return;
|
|
@@ -13803,8 +14232,8 @@ function createVaultChatBackend(options) {
|
|
|
13803
14232
|
emit({ type: "links", conversationId, origin: "local" });
|
|
13804
14233
|
},
|
|
13805
14234
|
async clearMemoryLinks(conversationId) {
|
|
13806
|
-
const
|
|
13807
|
-
if (!
|
|
14235
|
+
const record3 = await child("memory_links", conversationId);
|
|
14236
|
+
if (!record3 || record3.isDeleted) return;
|
|
13808
14237
|
await enqueue({
|
|
13809
14238
|
kind: "memory_links",
|
|
13810
14239
|
id: conversationId,
|
|
@@ -13822,8 +14251,8 @@ function createVaultChatBackend(options) {
|
|
|
13822
14251
|
async importChats(chats) {
|
|
13823
14252
|
await ready();
|
|
13824
14253
|
const seen = /* @__PURE__ */ new Set();
|
|
13825
|
-
const unique = (items) => items.filter(({ record:
|
|
13826
|
-
const k = key2(
|
|
14254
|
+
const unique = (items) => items.filter(({ record: record3 }) => {
|
|
14255
|
+
const k = key2(record3.kind, record3.id);
|
|
13827
14256
|
if (seen.has(k)) return false;
|
|
13828
14257
|
seen.add(k);
|
|
13829
14258
|
return true;
|
|
@@ -13847,15 +14276,15 @@ function createVaultChatBackend(options) {
|
|
|
13847
14276
|
for (const batch of batches(messages))
|
|
13848
14277
|
messageCount += await connected.importRecords(batch);
|
|
13849
14278
|
} finally {
|
|
13850
|
-
for (const { record:
|
|
13851
|
-
await refresh(conversations.map(({ record:
|
|
14279
|
+
for (const { record: record3 } of messages) checked.delete(key2("message", record3.id));
|
|
14280
|
+
await refresh(conversations.map(({ record: record3 }) => key2("conversation", record3.id))).catch(
|
|
13852
14281
|
() => void 0
|
|
13853
14282
|
);
|
|
13854
|
-
for (const { record:
|
|
14283
|
+
for (const { record: record3 } of conversations) threads.delete(record3.id);
|
|
13855
14284
|
channel?.postMessage("changed");
|
|
13856
14285
|
emit({ type: "conversations", origin: "local" });
|
|
13857
|
-
for (const { record:
|
|
13858
|
-
emit({ type: "messages", conversationId:
|
|
14286
|
+
for (const { record: record3 } of conversations)
|
|
14287
|
+
emit({ type: "messages", conversationId: record3.id, origin: "local" });
|
|
13859
14288
|
}
|
|
13860
14289
|
return { conversations: conversationCount, messages: messageCount };
|
|
13861
14290
|
},
|
|
@@ -13874,8 +14303,8 @@ function createVaultChatBackend(options) {
|
|
|
13874
14303
|
}
|
|
13875
14304
|
};
|
|
13876
14305
|
const updateConversation = async (conversationId, set) => {
|
|
13877
|
-
const
|
|
13878
|
-
if (!
|
|
14306
|
+
const record3 = await conversation(conversationId);
|
|
14307
|
+
if (!record3 || record3.isDeleted) return false;
|
|
13879
14308
|
await enqueue({ kind: "conversation", id: conversationId, conversationId: "", set });
|
|
13880
14309
|
emit({ type: "conversations", origin: "local" });
|
|
13881
14310
|
return true;
|
|
@@ -13949,10 +14378,10 @@ async function decryptConversationTitle(encryptedTitle, address) {
|
|
|
13949
14378
|
);
|
|
13950
14379
|
}
|
|
13951
14380
|
const cacheKey = buildCacheKey(address, encryptedTitle);
|
|
13952
|
-
const
|
|
13953
|
-
if (
|
|
13954
|
-
touchEntry(cacheKey,
|
|
13955
|
-
return
|
|
14381
|
+
const cached2 = titleCache.get(cacheKey);
|
|
14382
|
+
if (cached2 !== void 0) {
|
|
14383
|
+
touchEntry(cacheKey, cached2);
|
|
14384
|
+
return cached2;
|
|
13956
14385
|
}
|
|
13957
14386
|
const inFlight = pendingDecrypts.get(cacheKey);
|
|
13958
14387
|
if (inFlight) return inFlight;
|
|
@@ -15374,9 +15803,9 @@ var DatabaseManager = class {
|
|
|
15374
15803
|
*/
|
|
15375
15804
|
getDatabase(walletAddress) {
|
|
15376
15805
|
const dbName = this.getDbName(walletAddress);
|
|
15377
|
-
const
|
|
15378
|
-
if (
|
|
15379
|
-
return
|
|
15806
|
+
const cached2 = this.databases.get(dbName);
|
|
15807
|
+
if (cached2) {
|
|
15808
|
+
return cached2;
|
|
15380
15809
|
}
|
|
15381
15810
|
const needsMigration = this.handleSchemaMigration(walletAddress);
|
|
15382
15811
|
if (needsMigration) {
|
|
@@ -15568,25 +15997,25 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
15568
15997
|
const kindBackfills = existing.filter((e) => {
|
|
15569
15998
|
const incoming = kindByName.get(e.canonicalName);
|
|
15570
15999
|
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
15571
|
-
}).map((
|
|
16000
|
+
}).map((record3) => ({ record: record3, kind: kindByName.get(record3.canonicalName) }));
|
|
15572
16001
|
const missing2 = unique.filter((n) => !existingNames.has(n));
|
|
15573
16002
|
const created = missing2.map(
|
|
15574
|
-
(name) => ctx.entityCollection.prepareCreate((
|
|
15575
|
-
|
|
16003
|
+
(name) => ctx.entityCollection.prepareCreate((record3) => {
|
|
16004
|
+
record3._setRaw("canonical_name", name);
|
|
15576
16005
|
const kind = kindByName.get(name);
|
|
15577
|
-
if (kind !== void 0)
|
|
16006
|
+
if (kind !== void 0) record3._setRaw("kind", kind);
|
|
15578
16007
|
})
|
|
15579
16008
|
);
|
|
15580
16009
|
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
15581
|
-
for (const
|
|
15582
|
-
for (const { record:
|
|
15583
|
-
out.set(
|
|
16010
|
+
for (const record3 of created) out.set(record3.canonicalName, entityToStored(record3));
|
|
16011
|
+
for (const { record: record3, kind } of kindBackfills) {
|
|
16012
|
+
out.set(record3.canonicalName, { ...entityToStored(record3), kind });
|
|
15584
16013
|
}
|
|
15585
16014
|
return { entities: out, operations: created, kindBackfills };
|
|
15586
16015
|
}
|
|
15587
16016
|
function prepareKindBackfills(backfills) {
|
|
15588
16017
|
return backfills.map(
|
|
15589
|
-
({ record:
|
|
16018
|
+
({ record: record3, kind }) => record3.prepareUpdate((r) => {
|
|
15590
16019
|
r._setRaw("kind", kind);
|
|
15591
16020
|
})
|
|
15592
16021
|
);
|
|
@@ -15714,10 +16143,10 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
15714
16143
|
return;
|
|
15715
16144
|
}
|
|
15716
16145
|
const linkOps = toCreate.map(
|
|
15717
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
if (userId !== void 0)
|
|
16146
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record3) => {
|
|
16147
|
+
record3._setRaw("memory_id", memoryId);
|
|
16148
|
+
record3._setRaw("entity_id", e.uniqueId);
|
|
16149
|
+
if (userId !== void 0) record3._setRaw("user_id", userId);
|
|
15721
16150
|
})
|
|
15722
16151
|
);
|
|
15723
16152
|
await ctx.database.batch(
|
|
@@ -15787,10 +16216,10 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
15787
16216
|
...entityOps,
|
|
15788
16217
|
...prepareKindBackfills(kindBackfills),
|
|
15789
16218
|
...toCreate.map(
|
|
15790
|
-
(e) => ctx.memoryEntityCollection.prepareCreate((
|
|
15791
|
-
|
|
15792
|
-
|
|
15793
|
-
if (userId !== void 0)
|
|
16219
|
+
(e) => ctx.memoryEntityCollection.prepareCreate((record3) => {
|
|
16220
|
+
record3._setRaw("memory_id", memoryId);
|
|
16221
|
+
record3._setRaw("entity_id", e.uniqueId);
|
|
16222
|
+
if (userId !== void 0) record3._setRaw("user_id", userId);
|
|
15794
16223
|
})
|
|
15795
16224
|
),
|
|
15796
16225
|
...toDestroy.map((l) => l.prepareDestroyPermanently()),
|
|
@@ -15942,8 +16371,8 @@ function visibilityConditions(requested) {
|
|
|
15942
16371
|
if (excluded.length === 0) return [];
|
|
15943
16372
|
return [Q6.or(Q6.where("visibility", null), Q6.where("visibility", Q6.notIn(excluded)))];
|
|
15944
16373
|
}
|
|
15945
|
-
function isKinded(
|
|
15946
|
-
return
|
|
16374
|
+
function isKinded(record3) {
|
|
16375
|
+
return record3.kind !== null && record3.kind !== void 0;
|
|
15947
16376
|
}
|
|
15948
16377
|
async function assertCanWrite2(ctx) {
|
|
15949
16378
|
if (ctx.canWrite && !await ctx.canWrite()) {
|
|
@@ -15997,8 +16426,8 @@ function levelConditions(requested) {
|
|
|
15997
16426
|
}
|
|
15998
16427
|
return [byLevel];
|
|
15999
16428
|
}
|
|
16000
|
-
function isOwnedByCtxUser(ctx,
|
|
16001
|
-
return ctx.userId === void 0 ||
|
|
16429
|
+
function isOwnedByCtxUser(ctx, record3) {
|
|
16430
|
+
return ctx.userId === void 0 || record3.userId === ctx.userId;
|
|
16002
16431
|
}
|
|
16003
16432
|
function baseVaultConditions(ctx, options) {
|
|
16004
16433
|
return [
|
|
@@ -16081,43 +16510,43 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
16081
16510
|
}
|
|
16082
16511
|
return raw;
|
|
16083
16512
|
}
|
|
16084
|
-
function populateNewVaultMemory(
|
|
16513
|
+
function populateNewVaultMemory(record3, ctx, opts, encryptedContent, encryptedKindValue) {
|
|
16085
16514
|
const { level, scope } = resolveCreateLevel(opts);
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
|
|
16092
|
-
|
|
16093
|
-
|
|
16515
|
+
record3._setRaw("content", encryptedContent);
|
|
16516
|
+
record3._setRaw("scope", scope);
|
|
16517
|
+
record3._setRaw("level", level);
|
|
16518
|
+
record3._setRaw("kind", opts.kind ?? null);
|
|
16519
|
+
record3._setRaw("kind_value", encryptedKindValue ?? null);
|
|
16520
|
+
record3._setRaw("folder_id", opts.folderId ?? null);
|
|
16521
|
+
record3._setRaw("user_id", ctx.userId ?? null);
|
|
16522
|
+
record3._setRaw("is_deleted", false);
|
|
16094
16523
|
if (opts.embedding !== void 0) {
|
|
16095
|
-
|
|
16096
|
-
|
|
16524
|
+
record3._setRaw("embedding", opts.embedding);
|
|
16525
|
+
record3._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
16097
16526
|
}
|
|
16098
16527
|
if (opts.sourceChunkIds !== void 0) {
|
|
16099
|
-
|
|
16528
|
+
record3._setRaw("source_chunk_ids", serializeSourceChunkIds(opts.sourceChunkIds));
|
|
16100
16529
|
}
|
|
16101
|
-
|
|
16102
|
-
|
|
16530
|
+
record3._setRaw("proof_count", opts.proofCount ?? 1);
|
|
16531
|
+
record3._setRaw("source", opts.source ?? "manual");
|
|
16103
16532
|
if (opts.eventTime) {
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16533
|
+
record3._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
16534
|
+
record3._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
16535
|
+
record3._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
16107
16536
|
}
|
|
16108
16537
|
if (opts.factType !== void 0) {
|
|
16109
|
-
|
|
16538
|
+
record3._setRaw("fact_type", opts.factType);
|
|
16110
16539
|
}
|
|
16111
16540
|
if (opts.trustTier !== void 0) {
|
|
16112
|
-
|
|
16541
|
+
record3._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
16113
16542
|
}
|
|
16114
|
-
|
|
16115
|
-
|
|
16543
|
+
record3._setRaw("visibility", opts.visibility ?? "private");
|
|
16544
|
+
record3._setRaw(
|
|
16116
16545
|
"published_at",
|
|
16117
16546
|
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
16118
16547
|
);
|
|
16119
16548
|
if (opts.geohash !== void 0) {
|
|
16120
|
-
|
|
16549
|
+
record3._setRaw("geohash", opts.geohash);
|
|
16121
16550
|
}
|
|
16122
16551
|
}
|
|
16123
16552
|
async function createVaultMemoryOp(ctx, opts) {
|
|
@@ -16132,7 +16561,7 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
16132
16561
|
const created = await ctx.database.write(async () => {
|
|
16133
16562
|
await assertCanWrite2(ctx);
|
|
16134
16563
|
return ctx.vaultMemoryCollection.create(
|
|
16135
|
-
(
|
|
16564
|
+
(record3) => populateNewVaultMemory(record3, ctx, opts, encryptedContent, encryptedKindValue)
|
|
16136
16565
|
);
|
|
16137
16566
|
});
|
|
16138
16567
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
@@ -16159,7 +16588,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
16159
16588
|
if (target.isDeleted || target.supersededBy || isKinded(target) || !isOwnedByCtxUser(ctx, target))
|
|
16160
16589
|
return;
|
|
16161
16590
|
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
16162
|
-
(
|
|
16591
|
+
(record3) => populateNewVaultMemory(record3, ctx, opts, encryptedContent, encryptedKindValue)
|
|
16163
16592
|
);
|
|
16164
16593
|
await target.update((r) => {
|
|
16165
16594
|
r._setRaw("superseded_by", createdRecord.id);
|
|
@@ -16244,7 +16673,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
16244
16673
|
await assertCanWrite2(ctx);
|
|
16245
16674
|
const prepared = optionsArray.map(
|
|
16246
16675
|
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
16247
|
-
(
|
|
16676
|
+
(record3) => populateNewVaultMemory(record3, ctx, opts, encryptedContents[i], encryptedKindValues[i])
|
|
16248
16677
|
)
|
|
16249
16678
|
);
|
|
16250
16679
|
await ctx.database.batch(...prepared);
|
|
@@ -16252,16 +16681,16 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
16252
16681
|
});
|
|
16253
16682
|
return Promise.all(
|
|
16254
16683
|
created.map(
|
|
16255
|
-
(
|
|
16684
|
+
(record3) => vaultMemoryToStored(record3, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
16256
16685
|
)
|
|
16257
16686
|
);
|
|
16258
16687
|
}
|
|
16259
16688
|
async function getVaultMemoryOp(ctx, id2) {
|
|
16260
16689
|
try {
|
|
16261
|
-
const
|
|
16262
|
-
if (
|
|
16690
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
16691
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return null;
|
|
16263
16692
|
return vaultMemoryToStored(
|
|
16264
|
-
|
|
16693
|
+
record3,
|
|
16265
16694
|
ctx.walletAddress,
|
|
16266
16695
|
ctx.signMessage,
|
|
16267
16696
|
ctx.embeddedWalletSigner
|
|
@@ -16600,29 +17029,29 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
16600
17029
|
ctx.embeddedWalletSigner
|
|
16601
17030
|
) : opts.content;
|
|
16602
17031
|
let stale = false;
|
|
16603
|
-
const
|
|
17032
|
+
const record3 = probe;
|
|
16604
17033
|
await ctx.database.write(async () => {
|
|
16605
17034
|
await assertCanWrite2(ctx);
|
|
16606
|
-
if (
|
|
17035
|
+
if (record3.isDeleted || record3.supersededBy || !isOwnedByCtxUser(ctx, record3) || opts.freeFormOnly && isKinded(record3) || opts.expectedContent !== void 0 && record3._getRaw("content") !== readStoredContent) {
|
|
16607
17036
|
stale = true;
|
|
16608
17037
|
return;
|
|
16609
17038
|
}
|
|
16610
|
-
const originalUpdatedAt =
|
|
16611
|
-
const nextKind = opts.kind !== void 0 ? opts.kind :
|
|
16612
|
-
const nextLevel = levelAfter(
|
|
17039
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
17040
|
+
const nextKind = opts.kind !== void 0 ? opts.kind : record3.kind;
|
|
17041
|
+
const nextLevel = levelAfter(record3);
|
|
16613
17042
|
assertValidKindLevel(nextKind, nextLevel);
|
|
16614
17043
|
let observedSources = [];
|
|
16615
17044
|
let replayedObservation = false;
|
|
16616
17045
|
if (opts.observationSourceIds?.length) {
|
|
16617
17046
|
try {
|
|
16618
|
-
const parsed = JSON.parse(
|
|
17047
|
+
const parsed = JSON.parse(record3.sourceChunkIds ?? "[]");
|
|
16619
17048
|
if (Array.isArray(parsed))
|
|
16620
17049
|
observedSources = parsed.filter((id3) => typeof id3 === "string");
|
|
16621
17050
|
} catch {
|
|
16622
17051
|
}
|
|
16623
17052
|
replayedObservation = opts.observationSourceIds.every((id3) => observedSources.includes(id3));
|
|
16624
17053
|
}
|
|
16625
|
-
await
|
|
17054
|
+
await record3.update((r) => {
|
|
16626
17055
|
if (encryptedContent !== void 0) r._setRaw("content", encryptedContent);
|
|
16627
17056
|
if (opts.level !== void 0) {
|
|
16628
17057
|
r._setRaw("level", nextLevel);
|
|
@@ -16689,7 +17118,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
16689
17118
|
});
|
|
16690
17119
|
if (stale) return null;
|
|
16691
17120
|
return vaultMemoryToStored(
|
|
16692
|
-
|
|
17121
|
+
record3,
|
|
16693
17122
|
ctx.walletAddress,
|
|
16694
17123
|
ctx.signMessage,
|
|
16695
17124
|
ctx.embeddedWalletSigner
|
|
@@ -16704,22 +17133,22 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
16704
17133
|
if (!entityCtx) {
|
|
16705
17134
|
throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
|
|
16706
17135
|
}
|
|
16707
|
-
let
|
|
17136
|
+
let record3;
|
|
16708
17137
|
try {
|
|
16709
|
-
|
|
17138
|
+
record3 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
16710
17139
|
} catch {
|
|
16711
17140
|
return null;
|
|
16712
17141
|
}
|
|
16713
|
-
if (
|
|
17142
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return null;
|
|
16714
17143
|
let stale = false;
|
|
16715
|
-
const originalUpdatedAt =
|
|
17144
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
16716
17145
|
await ctx.database.write(async (writer) => {
|
|
16717
17146
|
await assertCanWrite2(ctx);
|
|
16718
|
-
if (
|
|
17147
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) {
|
|
16719
17148
|
stale = true;
|
|
16720
17149
|
return;
|
|
16721
17150
|
}
|
|
16722
|
-
await
|
|
17151
|
+
await record3.update((r) => {
|
|
16723
17152
|
r._setRaw("topics_user_managed", true);
|
|
16724
17153
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
16725
17154
|
});
|
|
@@ -16743,26 +17172,26 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
16743
17172
|
);
|
|
16744
17173
|
});
|
|
16745
17174
|
if (stale) return null;
|
|
16746
|
-
return vaultMemoryToStored(
|
|
17175
|
+
return vaultMemoryToStored(record3, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
16747
17176
|
}
|
|
16748
17177
|
async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
16749
|
-
let
|
|
17178
|
+
let record3;
|
|
16750
17179
|
try {
|
|
16751
|
-
|
|
17180
|
+
record3 = await ctx.vaultMemoryCollection.find(memoryId);
|
|
16752
17181
|
} catch {
|
|
16753
17182
|
return false;
|
|
16754
17183
|
}
|
|
16755
|
-
if (
|
|
16756
|
-
const originalUpdatedAt =
|
|
17184
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
17185
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
16757
17186
|
let cleared = false;
|
|
16758
17187
|
await ctx.database.write(async () => {
|
|
16759
17188
|
await assertCanWrite2(ctx);
|
|
16760
|
-
if (options?.unlessTopicsRecorded && parseTopics(
|
|
17189
|
+
if (options?.unlessTopicsRecorded && parseTopics(record3.topics) !== null) return;
|
|
16761
17190
|
cleared = true;
|
|
16762
|
-
await
|
|
17191
|
+
await record3.update((r) => {
|
|
16763
17192
|
r._setRaw("topics_user_managed", false);
|
|
16764
17193
|
r._setRaw("topics_extracted_version", null);
|
|
16765
|
-
if (
|
|
17194
|
+
if (record3.topicsExtractedAt === null) {
|
|
16766
17195
|
r._setRaw("topics_extracted_at", originalUpdatedAt);
|
|
16767
17196
|
}
|
|
16768
17197
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -16771,23 +17200,23 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
|
|
|
16771
17200
|
return cleared;
|
|
16772
17201
|
}
|
|
16773
17202
|
async function setMemoryVisibilityOp(ctx, id2, opts) {
|
|
16774
|
-
let
|
|
17203
|
+
let record3;
|
|
16775
17204
|
try {
|
|
16776
|
-
|
|
17205
|
+
record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
16777
17206
|
} catch {
|
|
16778
17207
|
return null;
|
|
16779
17208
|
}
|
|
16780
|
-
if (
|
|
17209
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return null;
|
|
16781
17210
|
let stale = false;
|
|
16782
17211
|
await ctx.database.write(async () => {
|
|
16783
17212
|
await assertCanWrite2(ctx);
|
|
16784
|
-
if (
|
|
17213
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) {
|
|
16785
17214
|
stale = true;
|
|
16786
17215
|
return;
|
|
16787
17216
|
}
|
|
16788
|
-
const currentUpdatedAt =
|
|
16789
|
-
const currentPublishedAt =
|
|
16790
|
-
await
|
|
17217
|
+
const currentUpdatedAt = record3.updatedAt.getTime();
|
|
17218
|
+
const currentPublishedAt = record3.publishedAt ?? null;
|
|
17219
|
+
await record3.update((r) => {
|
|
16791
17220
|
r._setRaw("visibility", opts.visibility);
|
|
16792
17221
|
if (opts.visibility === "private") {
|
|
16793
17222
|
r._setRaw("published_at", null);
|
|
@@ -16801,20 +17230,20 @@ async function setMemoryVisibilityOp(ctx, id2, opts) {
|
|
|
16801
17230
|
});
|
|
16802
17231
|
});
|
|
16803
17232
|
if (stale) return null;
|
|
16804
|
-
return vaultMemoryToStored(
|
|
17233
|
+
return vaultMemoryToStored(record3, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
16805
17234
|
}
|
|
16806
17235
|
async function deleteVaultMemoryOp(ctx, id2) {
|
|
16807
17236
|
try {
|
|
16808
|
-
const
|
|
16809
|
-
if (
|
|
17237
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
17238
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
16810
17239
|
let stale = false;
|
|
16811
17240
|
await ctx.database.write(async () => {
|
|
16812
17241
|
await assertCanWrite2(ctx);
|
|
16813
|
-
if (
|
|
17242
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) {
|
|
16814
17243
|
stale = true;
|
|
16815
17244
|
return;
|
|
16816
17245
|
}
|
|
16817
|
-
await
|
|
17246
|
+
await record3.update((r) => {
|
|
16818
17247
|
r._setRaw("is_deleted", true);
|
|
16819
17248
|
});
|
|
16820
17249
|
});
|
|
@@ -16833,9 +17262,9 @@ async function deleteVaultMemoryOp(ctx, id2) {
|
|
|
16833
17262
|
async function supersedeVaultMemoryOp(ctx, id2, supersededById) {
|
|
16834
17263
|
if (id2 === supersededById) return false;
|
|
16835
17264
|
try {
|
|
16836
|
-
const
|
|
16837
|
-
if (
|
|
16838
|
-
if (isKinded(
|
|
17265
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
17266
|
+
if (record3.isDeleted || record3.supersededBy || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
17267
|
+
if (isKinded(record3)) return false;
|
|
16839
17268
|
let successor;
|
|
16840
17269
|
try {
|
|
16841
17270
|
successor = await ctx.vaultMemoryCollection.find(supersededById);
|
|
@@ -16848,7 +17277,7 @@ async function supersedeVaultMemoryOp(ctx, id2, supersededById) {
|
|
|
16848
17277
|
let stale = false;
|
|
16849
17278
|
await ctx.database.write(async () => {
|
|
16850
17279
|
await assertCanWrite2(ctx);
|
|
16851
|
-
if (
|
|
17280
|
+
if (record3.isDeleted || record3.supersededBy || !isOwnedByCtxUser(ctx, record3)) {
|
|
16852
17281
|
stale = true;
|
|
16853
17282
|
return;
|
|
16854
17283
|
}
|
|
@@ -16856,7 +17285,7 @@ async function supersedeVaultMemoryOp(ctx, id2, supersededById) {
|
|
|
16856
17285
|
stale = true;
|
|
16857
17286
|
return;
|
|
16858
17287
|
}
|
|
16859
|
-
await
|
|
17288
|
+
await record3.update((r) => {
|
|
16860
17289
|
r._setRaw("superseded_by", supersededById);
|
|
16861
17290
|
r._setRaw("superseded_at", Date.now());
|
|
16862
17291
|
});
|
|
@@ -16875,7 +17304,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
|
|
|
16875
17304
|
const results = await ctx.vaultMemoryCollection.query(...conditions).fetch();
|
|
16876
17305
|
return mapInBatches(
|
|
16877
17306
|
results,
|
|
16878
|
-
(
|
|
17307
|
+
(record3) => vaultMemoryToStored(record3, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
16879
17308
|
);
|
|
16880
17309
|
}
|
|
16881
17310
|
var TOPICS_EXTRACTION_VERSION = 3;
|
|
@@ -17036,17 +17465,17 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
17036
17465
|
}
|
|
17037
17466
|
}
|
|
17038
17467
|
const eligible = records.filter(
|
|
17039
|
-
(
|
|
17468
|
+
(record3) => !record3.isDeleted && isOwnedByCtxUser(ctx, record3) && !record3.topicsUserManaged
|
|
17040
17469
|
);
|
|
17041
|
-
const prepared = eligible.map((
|
|
17042
|
-
const originalUpdatedAt =
|
|
17043
|
-
return
|
|
17470
|
+
const prepared = eligible.map((record3) => {
|
|
17471
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
17472
|
+
return record3.prepareUpdate((r) => {
|
|
17044
17473
|
r._setRaw("topics_extracted_at", extractedAt);
|
|
17045
17474
|
r._setRaw("topics_extracted_version", version);
|
|
17046
17475
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
17047
17476
|
});
|
|
17048
17477
|
});
|
|
17049
|
-
for (const
|
|
17478
|
+
for (const record3 of eligible) stamped.push(record3.id);
|
|
17050
17479
|
if (prepared.length > 0) await ctx.database.batch(...prepared);
|
|
17051
17480
|
});
|
|
17052
17481
|
}
|
|
@@ -17062,14 +17491,14 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
|
17062
17491
|
try {
|
|
17063
17492
|
await ctx.database.write(async (writer) => {
|
|
17064
17493
|
await assertCanWrite2(ctx);
|
|
17065
|
-
let
|
|
17494
|
+
let record3;
|
|
17066
17495
|
try {
|
|
17067
|
-
|
|
17496
|
+
record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
17068
17497
|
} catch {
|
|
17069
17498
|
return;
|
|
17070
17499
|
}
|
|
17071
|
-
if (
|
|
17072
|
-
const topics = parseTopics(
|
|
17500
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return;
|
|
17501
|
+
const topics = parseTopics(record3.topics);
|
|
17073
17502
|
if (topics === null) return;
|
|
17074
17503
|
await writer.callWriter(() => relinkMemoryEntitiesFromTopicsOp(entityCtx, id2, topics));
|
|
17075
17504
|
relinked.push(id2);
|
|
@@ -17095,18 +17524,18 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
17095
17524
|
await assertCanWrite2(ctx);
|
|
17096
17525
|
const records = [];
|
|
17097
17526
|
for (const id2 of chunkIds) {
|
|
17098
|
-
let
|
|
17527
|
+
let record3;
|
|
17099
17528
|
try {
|
|
17100
|
-
|
|
17529
|
+
record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
17101
17530
|
} catch {
|
|
17102
17531
|
continue;
|
|
17103
17532
|
}
|
|
17104
|
-
if (
|
|
17105
|
-
if (parseTopics(
|
|
17106
|
-
records.push(
|
|
17533
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) continue;
|
|
17534
|
+
if (parseTopics(record3.topics) !== null) continue;
|
|
17535
|
+
records.push(record3);
|
|
17107
17536
|
}
|
|
17108
17537
|
if (records.length === 0) return;
|
|
17109
|
-
const links2 = await entityCtx.memoryEntityCollection.query(Q6.where("memory_id", Q6.oneOf(records.map((
|
|
17538
|
+
const links2 = await entityCtx.memoryEntityCollection.query(Q6.where("memory_id", Q6.oneOf(records.map((record3) => record3.id)))).unsafeFetchRaw();
|
|
17110
17539
|
const entityIds = Array.from(new Set(links2.map((link) => String(link.entity_id))));
|
|
17111
17540
|
const entitiesById = /* @__PURE__ */ new Map();
|
|
17112
17541
|
for (let j = 0; j < entityIds.length; j += CHUNK) {
|
|
@@ -17126,13 +17555,13 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
17126
17555
|
entities.add(entity);
|
|
17127
17556
|
}
|
|
17128
17557
|
const writes = [];
|
|
17129
|
-
for (const
|
|
17130
|
-
const entities = entitiesByMemory.get(
|
|
17558
|
+
for (const record3 of records) {
|
|
17559
|
+
const entities = entitiesByMemory.get(record3.id);
|
|
17131
17560
|
if (!entities?.size) continue;
|
|
17132
|
-
const source =
|
|
17561
|
+
const source = record3.topicsUserManaged ? "user" : "auto";
|
|
17133
17562
|
const write = await resolveMemoryTopicsWrite(
|
|
17134
17563
|
entityCtx,
|
|
17135
|
-
|
|
17564
|
+
record3.id,
|
|
17136
17565
|
Array.from(entities),
|
|
17137
17566
|
[],
|
|
17138
17567
|
source
|
|
@@ -17154,7 +17583,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
|
17154
17583
|
await ctx.database.write(async () => {
|
|
17155
17584
|
await assertCanWrite2(ctx);
|
|
17156
17585
|
const prepared = records.map(
|
|
17157
|
-
(
|
|
17586
|
+
(record3) => record3.prepareUpdate((r) => {
|
|
17158
17587
|
r._setRaw("is_deleted", true);
|
|
17159
17588
|
})
|
|
17160
17589
|
);
|
|
@@ -17225,22 +17654,22 @@ async function applyDecayTransitionsOp(ctx, candidates, opts) {
|
|
|
17225
17654
|
Q6.where("id", Q6.oneOf(ids.slice(i, i + CHUNK))),
|
|
17226
17655
|
...ctx.userId !== void 0 ? [Q6.where("user_id", ctx.userId)] : []
|
|
17227
17656
|
).fetch();
|
|
17228
|
-
const eligible = records.filter((
|
|
17229
|
-
if (
|
|
17657
|
+
const eligible = records.filter((record3) => {
|
|
17658
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
17230
17659
|
if (opts.transition === "delete") {
|
|
17231
|
-
return
|
|
17660
|
+
return record3.archivedAt !== null && opts.now - record3.archivedAt > opts.hardDeleteWindowMs;
|
|
17232
17661
|
}
|
|
17233
|
-
const candidate = byId.get(
|
|
17234
|
-
return
|
|
17662
|
+
const candidate = byId.get(record3.id);
|
|
17663
|
+
return record3.archivedAt === null && record3.updatedAt.getTime() === candidate.updatedAt && (record3.lastObservedAt ?? null) === (candidate.lastObservedAt ?? null);
|
|
17235
17664
|
});
|
|
17236
17665
|
const prepared = eligible.map(
|
|
17237
|
-
(
|
|
17666
|
+
(record3) => record3.prepareUpdate((row) => {
|
|
17238
17667
|
if (opts.transition === "archive") row._setRaw("archived_at", opts.now);
|
|
17239
17668
|
else row._setRaw("is_deleted", true);
|
|
17240
17669
|
})
|
|
17241
17670
|
);
|
|
17242
17671
|
if (prepared.length > 0) await ctx.database.batch(prepared);
|
|
17243
|
-
applied = eligible.map((
|
|
17672
|
+
applied = eligible.map((record3) => record3.id);
|
|
17244
17673
|
});
|
|
17245
17674
|
} catch {
|
|
17246
17675
|
continue;
|
|
@@ -17258,21 +17687,21 @@ async function applyDecayTransitionsOp(ctx, candidates, opts) {
|
|
|
17258
17687
|
}
|
|
17259
17688
|
async function archiveVaultMemoryOp(ctx, id2, opts) {
|
|
17260
17689
|
try {
|
|
17261
|
-
const
|
|
17262
|
-
if (
|
|
17690
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
17691
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
17263
17692
|
let stale = false;
|
|
17264
17693
|
const archivedAtValue = opts?.now ?? Date.now();
|
|
17265
17694
|
await ctx.database.write(async () => {
|
|
17266
17695
|
await assertCanWrite2(ctx);
|
|
17267
|
-
if (
|
|
17696
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3) || record3.archivedAt !== null) {
|
|
17268
17697
|
stale = true;
|
|
17269
17698
|
return;
|
|
17270
17699
|
}
|
|
17271
|
-
if (opts?.expectedUpdatedAt !== void 0 &&
|
|
17700
|
+
if (opts?.expectedUpdatedAt !== void 0 && record3.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record3.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
|
|
17272
17701
|
stale = true;
|
|
17273
17702
|
return;
|
|
17274
17703
|
}
|
|
17275
|
-
await
|
|
17704
|
+
await record3.update((r) => {
|
|
17276
17705
|
r._setRaw("archived_at", archivedAtValue);
|
|
17277
17706
|
});
|
|
17278
17707
|
});
|
|
@@ -17283,16 +17712,16 @@ async function archiveVaultMemoryOp(ctx, id2, opts) {
|
|
|
17283
17712
|
}
|
|
17284
17713
|
async function restoreVaultMemoryOp(ctx, id2) {
|
|
17285
17714
|
try {
|
|
17286
|
-
const
|
|
17287
|
-
if (
|
|
17715
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
17716
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
17288
17717
|
let stale = false;
|
|
17289
17718
|
await ctx.database.write(async () => {
|
|
17290
17719
|
await assertCanWrite2(ctx);
|
|
17291
|
-
if (
|
|
17720
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) {
|
|
17292
17721
|
stale = true;
|
|
17293
17722
|
return;
|
|
17294
17723
|
}
|
|
17295
|
-
await
|
|
17724
|
+
await record3.update((r) => {
|
|
17296
17725
|
r._setRaw("archived_at", null);
|
|
17297
17726
|
});
|
|
17298
17727
|
});
|
|
@@ -17303,18 +17732,18 @@ async function restoreVaultMemoryOp(ctx, id2) {
|
|
|
17303
17732
|
}
|
|
17304
17733
|
async function hardDeleteDecayedOp(ctx, id2, opts) {
|
|
17305
17734
|
try {
|
|
17306
|
-
const
|
|
17307
|
-
if (
|
|
17735
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
17736
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
17308
17737
|
const now = opts.now ?? Date.now();
|
|
17309
17738
|
let stale = false;
|
|
17310
17739
|
await ctx.database.write(async () => {
|
|
17311
17740
|
await assertCanWrite2(ctx);
|
|
17312
|
-
const archivedAt =
|
|
17313
|
-
if (
|
|
17741
|
+
const archivedAt = record3.archivedAt;
|
|
17742
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
|
|
17314
17743
|
stale = true;
|
|
17315
17744
|
return;
|
|
17316
17745
|
}
|
|
17317
|
-
await
|
|
17746
|
+
await record3.update((r) => {
|
|
17318
17747
|
r._setRaw("is_deleted", true);
|
|
17319
17748
|
});
|
|
17320
17749
|
});
|
|
@@ -17332,14 +17761,14 @@ async function hardDeleteDecayedOp(ctx, id2, opts) {
|
|
|
17332
17761
|
}
|
|
17333
17762
|
async function updateVaultMemoryEmbeddingOp(ctx, id2, embedding2, embeddingModel, expected) {
|
|
17334
17763
|
try {
|
|
17335
|
-
const
|
|
17336
|
-
if (
|
|
17337
|
-
const readUpdatedAt =
|
|
17338
|
-
const readStoredContent =
|
|
17764
|
+
const record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
17765
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return false;
|
|
17766
|
+
const readUpdatedAt = record3.updatedAt.getTime();
|
|
17767
|
+
const readStoredContent = record3._getRaw("content");
|
|
17339
17768
|
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
17340
17769
|
if (expected?.content !== void 0) {
|
|
17341
17770
|
const current = await vaultMemoryToStored(
|
|
17342
|
-
|
|
17771
|
+
record3,
|
|
17343
17772
|
ctx.walletAddress,
|
|
17344
17773
|
ctx.signMessage,
|
|
17345
17774
|
ctx.embeddedWalletSigner
|
|
@@ -17349,11 +17778,11 @@ async function updateVaultMemoryEmbeddingOp(ctx, id2, embedding2, embeddingModel
|
|
|
17349
17778
|
let written = false;
|
|
17350
17779
|
await ctx.database.write(async () => {
|
|
17351
17780
|
await assertCanWrite2(ctx);
|
|
17352
|
-
if (
|
|
17353
|
-
const originalUpdatedAt =
|
|
17354
|
-
if (originalUpdatedAt !== readUpdatedAt ||
|
|
17781
|
+
if (record3.isDeleted || !isOwnedByCtxUser(ctx, record3)) return;
|
|
17782
|
+
const originalUpdatedAt = record3.updatedAt.getTime();
|
|
17783
|
+
if (originalUpdatedAt !== readUpdatedAt || record3._getRaw("content") !== readStoredContent)
|
|
17355
17784
|
return;
|
|
17356
|
-
await
|
|
17785
|
+
await record3.update((r) => {
|
|
17357
17786
|
r._setRaw("embedding", embedding2);
|
|
17358
17787
|
r._setRaw("embedding_model", embeddingModel);
|
|
17359
17788
|
r._setRaw("updated_at", originalUpdatedAt);
|
|
@@ -17517,26 +17946,26 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
|
|
|
17517
17946
|
inserted = writable.length;
|
|
17518
17947
|
if (writable.length === 0) return;
|
|
17519
17948
|
const prepared = writable.map(
|
|
17520
|
-
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((
|
|
17521
|
-
|
|
17522
|
-
|
|
17523
|
-
|
|
17524
|
-
|
|
17525
|
-
|
|
17526
|
-
|
|
17527
|
-
|
|
17528
|
-
|
|
17529
|
-
|
|
17530
|
-
|
|
17949
|
+
({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record3) => {
|
|
17950
|
+
record3._raw.id = row.memoryId;
|
|
17951
|
+
record3._setRaw("content", content);
|
|
17952
|
+
record3._setRaw("scope", "shared");
|
|
17953
|
+
record3._setRaw("level", "matching");
|
|
17954
|
+
record3._setRaw("folder_id", null);
|
|
17955
|
+
record3._setRaw("user_id", ctx.userId ?? null);
|
|
17956
|
+
record3._setRaw("is_deleted", false);
|
|
17957
|
+
record3._setRaw("proof_count", 1);
|
|
17958
|
+
record3._setRaw("source", SOURCE_PHOTO);
|
|
17959
|
+
record3._setRaw(
|
|
17531
17960
|
"media",
|
|
17532
17961
|
row.media && row.media.length > 0 ? JSON.stringify(row.media) : null
|
|
17533
17962
|
);
|
|
17534
|
-
|
|
17535
|
-
|
|
17963
|
+
record3._setRaw("visibility", "public");
|
|
17964
|
+
record3._setRaw("published_at", now);
|
|
17536
17965
|
if (row.eventTime) {
|
|
17537
|
-
|
|
17538
|
-
|
|
17539
|
-
|
|
17966
|
+
record3._setRaw("event_time_start", row.eventTime.start ?? null);
|
|
17967
|
+
record3._setRaw("event_time_end", row.eventTime.end ?? null);
|
|
17968
|
+
record3._setRaw("event_time_kind", row.eventTime.kind ?? null);
|
|
17540
17969
|
}
|
|
17541
17970
|
})
|
|
17542
17971
|
);
|
|
@@ -17900,11 +18329,11 @@ function folderToStored(folder) {
|
|
|
17900
18329
|
}
|
|
17901
18330
|
async function createVaultFolderOp(ctx, opts) {
|
|
17902
18331
|
const created = await ctx.database.write(async () => {
|
|
17903
|
-
return ctx.vaultFolderCollection.create((
|
|
17904
|
-
|
|
17905
|
-
|
|
17906
|
-
|
|
17907
|
-
|
|
18332
|
+
return ctx.vaultFolderCollection.create((record3) => {
|
|
18333
|
+
record3._setRaw("name", opts.name);
|
|
18334
|
+
record3._setRaw("scope", opts.scope ?? "private");
|
|
18335
|
+
record3._setRaw("is_system", opts.isSystem ?? false);
|
|
18336
|
+
record3._setRaw("is_deleted", false);
|
|
17908
18337
|
});
|
|
17909
18338
|
});
|
|
17910
18339
|
return folderToStored(created);
|
|
@@ -17915,14 +18344,14 @@ async function getAllVaultFoldersOp(ctx) {
|
|
|
17915
18344
|
}
|
|
17916
18345
|
async function updateVaultFolderOp(ctx, id2, opts) {
|
|
17917
18346
|
try {
|
|
17918
|
-
const
|
|
17919
|
-
if (
|
|
17920
|
-
const scopeChanged = opts.scope !== void 0 && opts.scope !==
|
|
18347
|
+
const record3 = await ctx.vaultFolderCollection.find(id2);
|
|
18348
|
+
if (record3.isDeleted) return null;
|
|
18349
|
+
const scopeChanged = opts.scope !== void 0 && opts.scope !== record3.scope;
|
|
17921
18350
|
const updated = await ctx.database.write(async () => {
|
|
17922
18351
|
const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(Q8.where("folder_id", id2), Q8.where("is_deleted", false)).fetch() : [];
|
|
17923
18352
|
const updates = [];
|
|
17924
18353
|
updates.push(
|
|
17925
|
-
|
|
18354
|
+
record3.prepareUpdate((r) => {
|
|
17926
18355
|
if (opts.name !== void 0) r._setRaw("name", opts.name);
|
|
17927
18356
|
if (opts.scope !== void 0) r._setRaw("scope", opts.scope);
|
|
17928
18357
|
})
|
|
@@ -17945,8 +18374,8 @@ async function updateVaultFolderOp(ctx, id2, opts) {
|
|
|
17945
18374
|
}
|
|
17946
18375
|
async function deleteVaultFolderOp(ctx, id2) {
|
|
17947
18376
|
try {
|
|
17948
|
-
const
|
|
17949
|
-
if (
|
|
18377
|
+
const record3 = await ctx.vaultFolderCollection.find(id2);
|
|
18378
|
+
if (record3.isDeleted) return false;
|
|
17950
18379
|
await ctx.database.write(async () => {
|
|
17951
18380
|
const memories = await ctx.vaultMemoryCollection.query(Q8.where("folder_id", id2), Q8.where("is_deleted", false)).fetch();
|
|
17952
18381
|
const preparedMemories = memories.map(
|
|
@@ -17956,7 +18385,7 @@ async function deleteVaultFolderOp(ctx, id2) {
|
|
|
17956
18385
|
r._setRaw("scope", "private");
|
|
17957
18386
|
})
|
|
17958
18387
|
);
|
|
17959
|
-
const preparedFolder =
|
|
18388
|
+
const preparedFolder = record3.prepareUpdate((r) => {
|
|
17960
18389
|
r._setRaw("is_deleted", true);
|
|
17961
18390
|
});
|
|
17962
18391
|
await ctx.database.batch(...preparedMemories, preparedFolder);
|
|
@@ -18003,11 +18432,11 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
|
|
|
18003
18432
|
}
|
|
18004
18433
|
async function updateVaultFolderContextOp(ctx, id2, context) {
|
|
18005
18434
|
try {
|
|
18006
|
-
const
|
|
18007
|
-
if (
|
|
18435
|
+
const record3 = await ctx.vaultFolderCollection.find(id2);
|
|
18436
|
+
if (record3.isDeleted) return null;
|
|
18008
18437
|
const updated = await ctx.database.write(async () => {
|
|
18009
18438
|
await ctx.database.batch(
|
|
18010
|
-
|
|
18439
|
+
record3.prepareUpdate((r) => {
|
|
18011
18440
|
r._setRaw("context", context);
|
|
18012
18441
|
})
|
|
18013
18442
|
);
|
|
@@ -19101,9 +19530,9 @@ function loadVaultCorpus(ctx, options, preparation) {
|
|
|
19101
19530
|
const key3 = JSON.stringify(options ?? {});
|
|
19102
19531
|
let request = pending.get(key3);
|
|
19103
19532
|
if (!request) {
|
|
19104
|
-
const
|
|
19533
|
+
const entries2 = pending;
|
|
19105
19534
|
request = getAllVaultMemoriesOp(ctx, options).catch((error) => {
|
|
19106
|
-
|
|
19535
|
+
entries2.delete(key3);
|
|
19107
19536
|
throw error;
|
|
19108
19537
|
});
|
|
19109
19538
|
pending.set(key3, request);
|
|
@@ -19144,7 +19573,7 @@ function embedVaultRows(ctx, options, rows, preparation) {
|
|
|
19144
19573
|
if (!pending.has(keys[index]) && !prepared?.has(keys[index])) missing2.set(keys[index], row);
|
|
19145
19574
|
});
|
|
19146
19575
|
if (missing2.size > 0) {
|
|
19147
|
-
const
|
|
19576
|
+
const entries2 = pending;
|
|
19148
19577
|
const batch = Promise.resolve().then(
|
|
19149
19578
|
() => generateEmbeddings(
|
|
19150
19579
|
[...missing2.values()].map((row) => row.content),
|
|
@@ -19161,16 +19590,16 @@ function embedVaultRows(ctx, options, rows, preparation) {
|
|
|
19161
19590
|
});
|
|
19162
19591
|
return vector2;
|
|
19163
19592
|
}).finally(() => {
|
|
19164
|
-
|
|
19165
|
-
if (
|
|
19593
|
+
entries2.delete(key3);
|
|
19594
|
+
if (entries2.size === 0) pendingRows.get(ctx)?.delete(options.maskInput);
|
|
19166
19595
|
});
|
|
19167
19596
|
pending.set(key3, request);
|
|
19168
19597
|
});
|
|
19169
19598
|
}
|
|
19170
19599
|
return Promise.all(
|
|
19171
19600
|
keys.map((key3) => {
|
|
19172
|
-
const
|
|
19173
|
-
if (
|
|
19601
|
+
const cached2 = prepared?.get(key3);
|
|
19602
|
+
if (cached2) return cached2;
|
|
19174
19603
|
const request = pending.get(key3);
|
|
19175
19604
|
if (!prepared) return request;
|
|
19176
19605
|
const retained = request.catch((error) => {
|
|
@@ -19870,10 +20299,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
|
|
|
19870
20299
|
const resolvedThisCall = /* @__PURE__ */ new Set();
|
|
19871
20300
|
if (!embeddingsDegraded) {
|
|
19872
20301
|
for (const k2 of keys) {
|
|
19873
|
-
const
|
|
19874
|
-
if (
|
|
20302
|
+
const cached2 = cachedRowVector(cache, k2.uniqueId, k2.updatedAt);
|
|
20303
|
+
if (cached2 && cached2.length === queryEmbedding.length) {
|
|
19875
20304
|
corpusStats.cacheHits++;
|
|
19876
|
-
vectored.push({ uniqueId: k2.uniqueId, embedding:
|
|
20305
|
+
vectored.push({ uniqueId: k2.uniqueId, embedding: cached2, updatedAt: k2.updatedAt });
|
|
19877
20306
|
continue;
|
|
19878
20307
|
}
|
|
19879
20308
|
corpusStats.cacheMisses++;
|
|
@@ -20171,12 +20600,12 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
20171
20600
|
for (let i = 0; queryEmbedding.length > 0 && i < memories.length; i++) {
|
|
20172
20601
|
const content = memories[i].content;
|
|
20173
20602
|
const memoryId = memories[i].uniqueId;
|
|
20174
|
-
const
|
|
20175
|
-
if (
|
|
20176
|
-
resolvedVectors.set(memoryId,
|
|
20603
|
+
const cached2 = cachedRowVector(cache, memoryId, memories[i].updatedAt, content);
|
|
20604
|
+
if (cached2 && cached2.length === queryEmbedding.length) {
|
|
20605
|
+
resolvedVectors.set(memoryId, cached2);
|
|
20177
20606
|
continue;
|
|
20178
20607
|
}
|
|
20179
|
-
if (
|
|
20608
|
+
if (cached2) cache.delete(memoryId);
|
|
20180
20609
|
const storedModel = memories[i].embeddingModel;
|
|
20181
20610
|
const modelCompatible = (storedModel ?? currentModel) === currentModel;
|
|
20182
20611
|
if (memories[i].embedding && modelCompatible) {
|
|
@@ -21860,9 +22289,9 @@ function createDecaySweeperOver(backend, options) {
|
|
|
21860
22289
|
if (ruleVerdict !== "keep") return rule;
|
|
21861
22290
|
if (!classifier || !isBorderline(input)) return rule;
|
|
21862
22291
|
if (input.id) {
|
|
21863
|
-
const
|
|
21864
|
-
if (
|
|
21865
|
-
return { verdict:
|
|
22292
|
+
const cached2 = classifierCache.get(input.id);
|
|
22293
|
+
if (cached2 && cached2.activityAt === lastActivityAt(input))
|
|
22294
|
+
return { verdict: cached2.verdict, source: "classifierDriven" };
|
|
21866
22295
|
}
|
|
21867
22296
|
if (sweep.classifierCalls >= maxClassifierCalls) {
|
|
21868
22297
|
sweep.classifierCapHits++;
|
|
@@ -23685,21 +24114,21 @@ async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
|
|
|
23685
24114
|
};
|
|
23686
24115
|
const inputs = [];
|
|
23687
24116
|
for (const id2 of new Set(memoryIds)) {
|
|
23688
|
-
let
|
|
24117
|
+
let record3;
|
|
23689
24118
|
try {
|
|
23690
|
-
|
|
24119
|
+
record3 = await ctx.vaultMemoryCollection.find(id2);
|
|
23691
24120
|
} catch (err) {
|
|
23692
24121
|
log.warn("[memory/topics] vault lookup failed for extraction", err);
|
|
23693
24122
|
skip(id2, "not-found");
|
|
23694
24123
|
continue;
|
|
23695
24124
|
}
|
|
23696
|
-
if (
|
|
24125
|
+
if (record3.isDeleted || ctx.userId !== void 0 && record3.userId !== ctx.userId || record3.topicsUserManaged) {
|
|
23697
24126
|
skip(id2, "excluded");
|
|
23698
24127
|
continue;
|
|
23699
24128
|
}
|
|
23700
24129
|
try {
|
|
23701
24130
|
const stored2 = await vaultMemoryToStored(
|
|
23702
|
-
|
|
24131
|
+
record3,
|
|
23703
24132
|
ctx.walletAddress,
|
|
23704
24133
|
ctx.signMessage,
|
|
23705
24134
|
ctx.embeddedWalletSigner
|
|
@@ -24006,6 +24435,7 @@ function createLocalMemoryStore(options) {
|
|
|
24006
24435
|
|
|
24007
24436
|
// src/lib/memory/store/memoryKeys.ts
|
|
24008
24437
|
var KEY_ID_DOMAIN = "anuma-private-memory-key-id-v1";
|
|
24438
|
+
var TOPIC_HASH_INFO = "anuma-private-memory-topic-hash-v1";
|
|
24009
24439
|
var MemoryKeyError = class extends Error {
|
|
24010
24440
|
constructor(message) {
|
|
24011
24441
|
super(message);
|
|
@@ -24021,17 +24451,40 @@ async function importAesKey(hex) {
|
|
|
24021
24451
|
["encrypt", "decrypt"]
|
|
24022
24452
|
);
|
|
24023
24453
|
}
|
|
24454
|
+
async function deriveTopicHashKey(hex) {
|
|
24455
|
+
const material = await crypto.subtle.importKey(
|
|
24456
|
+
"raw",
|
|
24457
|
+
hexToBytes(hex).buffer,
|
|
24458
|
+
{ name: "HKDF" },
|
|
24459
|
+
false,
|
|
24460
|
+
["deriveBits"]
|
|
24461
|
+
);
|
|
24462
|
+
const bits = await crypto.subtle.deriveBits(
|
|
24463
|
+
{
|
|
24464
|
+
name: "HKDF",
|
|
24465
|
+
hash: "SHA-256",
|
|
24466
|
+
salt: new Uint8Array(32),
|
|
24467
|
+
info: new TextEncoder().encode(TOPIC_HASH_INFO)
|
|
24468
|
+
},
|
|
24469
|
+
material,
|
|
24470
|
+
256
|
|
24471
|
+
);
|
|
24472
|
+
return crypto.subtle.importKey("raw", bits, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
24473
|
+
}
|
|
24474
|
+
function toHex(bytes4) {
|
|
24475
|
+
return Array.from(new Uint8Array(bytes4), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
24476
|
+
}
|
|
24024
24477
|
async function deriveMemoryKeyRing(signatureHex) {
|
|
24025
24478
|
const v3Hex = await deriveKeyFromSignatureV3(signatureHex);
|
|
24026
24479
|
const digest = await crypto.subtle.digest(
|
|
24027
24480
|
"SHA-256",
|
|
24028
24481
|
new TextEncoder().encode(`${KEY_ID_DOMAIN}:${v3Hex}`)
|
|
24029
24482
|
);
|
|
24030
|
-
const keyId = "v3:" + Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
24031
24483
|
return {
|
|
24032
|
-
keyId,
|
|
24484
|
+
keyId: "v3:" + toHex(digest),
|
|
24033
24485
|
v3: await importAesKey(v3Hex),
|
|
24034
|
-
v2: await importAesKey(await deriveKeyFromSignature(signatureHex))
|
|
24486
|
+
v2: await importAesKey(await deriveKeyFromSignature(signatureHex)),
|
|
24487
|
+
topicHash: await deriveTopicHashKey(v3Hex)
|
|
24035
24488
|
};
|
|
24036
24489
|
}
|
|
24037
24490
|
async function decryptWith(value, rings) {
|
|
@@ -24052,7 +24505,10 @@ function memoryCipher(canonical) {
|
|
|
24052
24505
|
if (!ciphertext.startsWith("enc:v3:") || !isEncrypted(ciphertext))
|
|
24053
24506
|
throw new MemoryKeyError("Remote memory content must be enc:v3 ciphertext");
|
|
24054
24507
|
return decryptWith(ciphertext, [canonical]);
|
|
24055
|
-
}
|
|
24508
|
+
},
|
|
24509
|
+
hashTopic: async (normalized2) => toHex(
|
|
24510
|
+
await crypto.subtle.sign("HMAC", canonical.topicHash, new TextEncoder().encode(normalized2))
|
|
24511
|
+
)
|
|
24056
24512
|
};
|
|
24057
24513
|
}
|
|
24058
24514
|
async function reencryptMemoryField(value, canonical, fallbacks = []) {
|
|
@@ -24484,8 +24940,9 @@ var DEFAULT_RATE_LIMIT_WAIT_MS = 1e4;
|
|
|
24484
24940
|
var MAX_ID_BYTES = 128;
|
|
24485
24941
|
var MAX_CONTENT_BYTES = 32 << 10;
|
|
24486
24942
|
var MAX_TEXT_BYTES = 16 << 10;
|
|
24943
|
+
var MAX_TOPICS_BYTES = 32 << 10;
|
|
24487
24944
|
var MAX_SHORT_BYTES = 256;
|
|
24488
|
-
var TEXT_FIELDS = ["
|
|
24945
|
+
var TEXT_FIELDS = ["media", "source_chunk_ids"];
|
|
24489
24946
|
var SHORT_FIELDS = [
|
|
24490
24947
|
"scope",
|
|
24491
24948
|
"kind",
|
|
@@ -24588,7 +25045,7 @@ function bytes3(value) {
|
|
|
24588
25045
|
return value === void 0 ? 0 : utf82.encode(value).length;
|
|
24589
25046
|
}
|
|
24590
25047
|
function fitsNearby(row) {
|
|
24591
|
-
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);
|
|
25048
|
+
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);
|
|
24592
25049
|
}
|
|
24593
25050
|
function invalid2(raw) {
|
|
24594
25051
|
const id2 = raw.id;
|
|
@@ -24632,7 +25089,7 @@ function defined(value) {
|
|
|
24632
25089
|
Object.entries(value).filter(([, field10]) => field10 !== void 0)
|
|
24633
25090
|
);
|
|
24634
25091
|
}
|
|
24635
|
-
async function prepareRow(raw, canonical, rings, model, updatedAt) {
|
|
25092
|
+
async function prepareRow(raw, canonical, codec, rings, model, updatedAt) {
|
|
24636
25093
|
const deleted = bool(raw.is_deleted) ?? false;
|
|
24637
25094
|
const { encrypt } = memoryCipher(canonical);
|
|
24638
25095
|
const localKindValue = text15(raw.kind_value);
|
|
@@ -24646,10 +25103,12 @@ async function prepareRow(raw, canonical, rings, model, updatedAt) {
|
|
|
24646
25103
|
plaintext = void 0;
|
|
24647
25104
|
kindValue = void 0;
|
|
24648
25105
|
}
|
|
25106
|
+
const fields = metadata2(raw, model);
|
|
24649
25107
|
const row = {
|
|
24650
25108
|
...defined({
|
|
24651
|
-
...
|
|
24652
|
-
kind_value: kindValue === void 0 ? void 0 : await encrypt(kindValue)
|
|
25109
|
+
...fields,
|
|
25110
|
+
kind_value: kindValue === void 0 ? void 0 : await encrypt(kindValue),
|
|
25111
|
+
topics: fields.topics === void 0 ? void 0 : await codec.encodeTopics(fields.topics)
|
|
24653
25112
|
}),
|
|
24654
25113
|
memory_id: raw.id,
|
|
24655
25114
|
content: await encrypt(plaintext ?? ""),
|
|
@@ -24693,6 +25152,8 @@ function sameMetadata2(local, remote, model) {
|
|
|
24693
25152
|
if (field10 === "visibility") return (a ?? "private") === (b ?? "private");
|
|
24694
25153
|
if (field10 === "is_deleted" || field10 === "topics_user_managed" || field10 === "twin_opt_in")
|
|
24695
25154
|
return (a ?? false) === (b ?? false);
|
|
25155
|
+
if (field10 === "topics")
|
|
25156
|
+
return JSON.stringify(parseTopics(a)) === JSON.stringify(parseTopics(b));
|
|
24696
25157
|
return a === b;
|
|
24697
25158
|
});
|
|
24698
25159
|
}
|
|
@@ -24748,7 +25209,7 @@ async function missingIds(request, revisions, signal) {
|
|
|
24748
25209
|
}
|
|
24749
25210
|
return missing2;
|
|
24750
25211
|
}
|
|
24751
|
-
async function remoteMetadata(request, ids, signal) {
|
|
25212
|
+
async function remoteMetadata(request, codec, ids, signal) {
|
|
24752
25213
|
const rows = /* @__PURE__ */ new Map();
|
|
24753
25214
|
for (const batch of chunks(ids, QUERY_IDS)) {
|
|
24754
25215
|
let cursor;
|
|
@@ -24772,7 +25233,12 @@ async function remoteMetadata(request, ids, signal) {
|
|
|
24772
25233
|
if (!Array.isArray(page.items)) throw new Error("Invalid nearby private-memory page");
|
|
24773
25234
|
for (const item of page.items)
|
|
24774
25235
|
if (item.memory && typeof item.memory.memory_id === "string")
|
|
24775
|
-
rows.set(item.memory.memory_id,
|
|
25236
|
+
rows.set(item.memory.memory_id, {
|
|
25237
|
+
...item.memory,
|
|
25238
|
+
...typeof item.memory.topics === "string" && {
|
|
25239
|
+
topics: await codec.decodeTopics(item.memory.topics).catch(() => null)
|
|
25240
|
+
}
|
|
25241
|
+
});
|
|
24776
25242
|
cursor = typeof page.next_cursor === "string" ? page.next_cursor : void 0;
|
|
24777
25243
|
} while (cursor);
|
|
24778
25244
|
}
|
|
@@ -24790,6 +25256,7 @@ async function migrateMemoriesToRemote(options) {
|
|
|
24790
25256
|
const rings = [canonical, ...options.fallbacks ?? []];
|
|
24791
25257
|
const model = options.embeddingOptions?.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
24792
25258
|
const request = createNearbyRequest(options);
|
|
25259
|
+
const codec = createTopicCodec(memoryCipher(canonical));
|
|
24793
25260
|
const account = await request("/account", {}, signal);
|
|
24794
25261
|
if (typeof account.key_id === "string" && account.key_id !== canonical.keyId)
|
|
24795
25262
|
throw new RemoteMemoryError(
|
|
@@ -24806,7 +25273,7 @@ async function migrateMemoriesToRemote(options) {
|
|
|
24806
25273
|
...typeof t.kind === "string" && { kind: t.kind }
|
|
24807
25274
|
})).filter((t) => t.name.length > 0) : []);
|
|
24808
25275
|
if (localTopics.length)
|
|
24809
|
-
await createRemoteTopicPersistence(request).importTopics(localTopics, signal);
|
|
25276
|
+
await createRemoteTopicPersistence(request, codec).importTopics(localTopics, signal);
|
|
24810
25277
|
const skipped = /* @__PURE__ */ new Map();
|
|
24811
25278
|
const reembedded = /* @__PURE__ */ new Set();
|
|
24812
25279
|
const unembedded = /* @__PURE__ */ new Set();
|
|
@@ -24825,6 +25292,7 @@ async function migrateMemoriesToRemote(options) {
|
|
|
24825
25292
|
if (pending.size === 0 && !active) {
|
|
24826
25293
|
const remote = await remoteMetadata(
|
|
24827
25294
|
request,
|
|
25295
|
+
codec,
|
|
24828
25296
|
candidates.map((raw) => raw.id),
|
|
24829
25297
|
signal
|
|
24830
25298
|
);
|
|
@@ -24869,7 +25337,7 @@ async function migrateMemoriesToRemote(options) {
|
|
|
24869
25337
|
const updatedAt = pending.get(raw.id);
|
|
24870
25338
|
if (updatedAt === void 0) continue;
|
|
24871
25339
|
try {
|
|
24872
|
-
prepared.push(await prepareRow(raw, canonical, rings, model, updatedAt));
|
|
25340
|
+
prepared.push(await prepareRow(raw, canonical, codec, rings, model, updatedAt));
|
|
24873
25341
|
} catch (error) {
|
|
24874
25342
|
if (!(error instanceof MemoryKeyError)) throw error;
|
|
24875
25343
|
skipped.set(raw.id, "unreadable");
|
|
@@ -25028,7 +25496,7 @@ function topicInputs(topics, source) {
|
|
|
25028
25496
|
function mergeTopics(existing, added) {
|
|
25029
25497
|
const byName = /* @__PURE__ */ new Map();
|
|
25030
25498
|
for (const topic2 of [...existing, ...added]) {
|
|
25031
|
-
const key3 =
|
|
25499
|
+
const key3 = normalizeTopicName(topic2.name);
|
|
25032
25500
|
const kept = byName.get(key3);
|
|
25033
25501
|
if (!kept) byName.set(key3, topic2);
|
|
25034
25502
|
else if (kept.weight !== void 0 && topic2.weight !== void 0 && topic2.weight > kept.weight)
|
|
@@ -25043,7 +25511,7 @@ function sameTopics(stored2, next) {
|
|
|
25043
25511
|
return next.every((t) => keys.has(key3(t)));
|
|
25044
25512
|
}
|
|
25045
25513
|
function canonicalTopics(row) {
|
|
25046
|
-
return new Set((parseTopics(row.topics) ?? []).map((topic2) =>
|
|
25514
|
+
return new Set((parseTopics(row.topics) ?? []).map((topic2) => normalizeTopicName(topic2.name)));
|
|
25047
25515
|
}
|
|
25048
25516
|
function createRemoteMemoryStore(options) {
|
|
25049
25517
|
const { persistence, embeddingOptions } = options;
|
|
@@ -25090,10 +25558,10 @@ function createRemoteMemoryStore(options) {
|
|
|
25090
25558
|
const notify = (change, records = []) => {
|
|
25091
25559
|
invalidateReads();
|
|
25092
25560
|
if (subscribers.size)
|
|
25093
|
-
for (const
|
|
25094
|
-
const previous = seen.get(
|
|
25095
|
-
if ((previous?.version ?? 0) + 1 ===
|
|
25096
|
-
seen.set(
|
|
25561
|
+
for (const record3 of records) {
|
|
25562
|
+
const previous = seen.get(record3.memory.memory_id);
|
|
25563
|
+
if ((previous?.version ?? 0) + 1 === record3.version)
|
|
25564
|
+
seen.set(record3.memory.memory_id, subscriptionState(record3));
|
|
25097
25565
|
}
|
|
25098
25566
|
for (const subscriber of [...subscribers])
|
|
25099
25567
|
if (relevant(change, subscriber.options)) safely(subscriber.onChange);
|
|
@@ -25146,7 +25614,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25146
25614
|
};
|
|
25147
25615
|
const enumerate = (filters, max = Infinity) => pages(decrypted, filters, max);
|
|
25148
25616
|
const memoriesByTopics = async (names) => {
|
|
25149
|
-
const wanted = new Set(names.map(
|
|
25617
|
+
const wanted = new Set(names.map(normalizeTopicName).filter(Boolean));
|
|
25150
25618
|
const out = /* @__PURE__ */ new Map();
|
|
25151
25619
|
const pages2 = await Promise.all(
|
|
25152
25620
|
chunks2([...wanted], MAX_QUERY_TOPICS).map((topics) => enumerate({ topics }))
|
|
@@ -25158,7 +25626,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25158
25626
|
return out;
|
|
25159
25627
|
};
|
|
25160
25628
|
const topicGraphRanking = async (query, recallOptions = {}) => {
|
|
25161
|
-
const wanted = new Set(extractQueryEntities(query).map(
|
|
25629
|
+
const wanted = new Set(extractQueryEntities(query).map(normalizeTopicName).filter(Boolean));
|
|
25162
25630
|
if (wanted.size === 0 || recallOptions.memoryIds?.length === 0) return [];
|
|
25163
25631
|
const rows = await pages(
|
|
25164
25632
|
metadata3,
|
|
@@ -25216,25 +25684,25 @@ function createRemoteMemoryStore(options) {
|
|
|
25216
25684
|
return run;
|
|
25217
25685
|
};
|
|
25218
25686
|
const live2 = async (id2) => {
|
|
25219
|
-
const
|
|
25220
|
-
return
|
|
25687
|
+
const record3 = await persistence.get(id2);
|
|
25688
|
+
return record3 && !record3.memory.is_deleted ? record3 : null;
|
|
25221
25689
|
};
|
|
25222
25690
|
const mutateLocked = async (id2, change, edit, writeOptions) => {
|
|
25223
25691
|
writeOptions?.signal?.throwIfAborted();
|
|
25224
|
-
const
|
|
25225
|
-
if (!
|
|
25226
|
-
if (
|
|
25692
|
+
const record3 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await live2(id2);
|
|
25693
|
+
if (!record3) return null;
|
|
25694
|
+
if (record3.memory.is_deleted) return null;
|
|
25227
25695
|
if (writeOptions?.canWrite && !await writeOptions.canWrite())
|
|
25228
25696
|
throw new MemorySourceIneligibleError();
|
|
25229
25697
|
writeOptions?.signal?.throwIfAborted();
|
|
25230
|
-
const next = edit(structuredClone(
|
|
25698
|
+
const next = edit(structuredClone(record3.memory));
|
|
25231
25699
|
if (!next) return null;
|
|
25232
25700
|
const saved = writeOptions?.leaseToken ? (await persistence.putMany(
|
|
25233
|
-
[{ memory: next, expectedVersion:
|
|
25701
|
+
[{ memory: next, expectedVersion: record3 }],
|
|
25234
25702
|
writeOptions.signal,
|
|
25235
25703
|
writeOptions.leaseToken
|
|
25236
|
-
))[0] : writeOptions?.signal ? await persistence.put(next,
|
|
25237
|
-
notify(typeof change === "function" ? change(
|
|
25704
|
+
))[0] : writeOptions?.signal ? await persistence.put(next, record3, writeOptions.signal) : await persistence.put(next, record3);
|
|
25705
|
+
notify(typeof change === "function" ? change(record3.memory) : change, [saved]);
|
|
25238
25706
|
return saved;
|
|
25239
25707
|
};
|
|
25240
25708
|
const mutate = (id2, change, edit, writeOptions) => serialized(id2, () => mutateLocked(id2, change, edit, writeOptions));
|
|
@@ -25256,12 +25724,12 @@ function createRemoteMemoryStore(options) {
|
|
|
25256
25724
|
}
|
|
25257
25725
|
const { records, unreadable } = read;
|
|
25258
25726
|
for (const id2 of slice) {
|
|
25259
|
-
const
|
|
25727
|
+
const record3 = records.get(id2);
|
|
25260
25728
|
if (unreadable.has(id2)) failed.set(id2, new Error(`Memory ${id2} could not be decrypted`));
|
|
25261
|
-
else if (!
|
|
25262
|
-
else if (!
|
|
25263
|
-
const memory = edit(structuredClone(
|
|
25264
|
-
if (memory) writes.push({ before:
|
|
25729
|
+
else if (!record3) failed.set(id2, new Error(`Memory ${id2} was not found`));
|
|
25730
|
+
else if (!record3.memory.is_deleted) {
|
|
25731
|
+
const memory = edit(structuredClone(record3.memory));
|
|
25732
|
+
if (memory) writes.push({ before: record3, memory });
|
|
25265
25733
|
}
|
|
25266
25734
|
}
|
|
25267
25735
|
if (writes.length === 0) return;
|
|
@@ -25272,10 +25740,10 @@ function createRemoteMemoryStore(options) {
|
|
|
25272
25740
|
leaseToken
|
|
25273
25741
|
);
|
|
25274
25742
|
const byChange = /* @__PURE__ */ new Map();
|
|
25275
|
-
written.forEach((
|
|
25276
|
-
saved.set(
|
|
25743
|
+
written.forEach((record3, i) => {
|
|
25744
|
+
saved.set(record3.memory.memory_id, record3);
|
|
25277
25745
|
const kind = change(writes[i].before.memory);
|
|
25278
|
-
byChange.set(kind, [...byChange.get(kind) ?? [],
|
|
25746
|
+
byChange.set(kind, [...byChange.get(kind) ?? [], record3]);
|
|
25279
25747
|
});
|
|
25280
25748
|
for (const [kind, changed] of byChange) notify(kind, changed);
|
|
25281
25749
|
} catch (error) {
|
|
@@ -25289,13 +25757,13 @@ function createRemoteMemoryStore(options) {
|
|
|
25289
25757
|
continue;
|
|
25290
25758
|
}
|
|
25291
25759
|
try {
|
|
25292
|
-
const
|
|
25760
|
+
const record3 = await mutateLocked(
|
|
25293
25761
|
id2,
|
|
25294
25762
|
change,
|
|
25295
25763
|
edit,
|
|
25296
25764
|
leaseToken || signal ? { leaseToken, signal } : void 0
|
|
25297
25765
|
);
|
|
25298
|
-
if (
|
|
25766
|
+
if (record3) saved.set(id2, record3);
|
|
25299
25767
|
} catch (rowError) {
|
|
25300
25768
|
signal?.throwIfAborted();
|
|
25301
25769
|
if (isRemoteWorkLeaseExpired(rowError)) throw rowError;
|
|
@@ -25391,12 +25859,12 @@ function createRemoteMemoryStore(options) {
|
|
|
25391
25859
|
const created = (records, inputs) => {
|
|
25392
25860
|
embedInBackground(records.filter((_, i) => inputs[i].embedding === void 0));
|
|
25393
25861
|
notify("membership", records);
|
|
25394
|
-
return records.map((
|
|
25862
|
+
return records.map((record3) => stored(record3.memory));
|
|
25395
25863
|
};
|
|
25396
|
-
const asStored = (
|
|
25864
|
+
const asStored = (record3) => record3 ? stored(record3.memory) : null;
|
|
25397
25865
|
const knownKinds = async (topics, signal) => {
|
|
25398
25866
|
const unkinded = [
|
|
25399
|
-
...new Set(topics.filter((t) => !t.kind).map((t) =>
|
|
25867
|
+
...new Set(topics.filter((t) => !t.kind).map((t) => normalizeTopicName(t.name)))
|
|
25400
25868
|
];
|
|
25401
25869
|
const kinds2 = /* @__PURE__ */ new Map();
|
|
25402
25870
|
for (const names of chunks2(unkinded, MAX_QUERY_TOPICS)) {
|
|
@@ -25408,13 +25876,13 @@ function createRemoteMemoryStore(options) {
|
|
|
25408
25876
|
...signal && { signal }
|
|
25409
25877
|
})) {
|
|
25410
25878
|
for (const topic2 of parseTopics(memory.topics) ?? []) {
|
|
25411
|
-
const name =
|
|
25879
|
+
const name = normalizeTopicName(topic2.name);
|
|
25412
25880
|
if (topic2.kind && !kinds2.has(name)) kinds2.set(name, topic2.kind);
|
|
25413
25881
|
}
|
|
25414
25882
|
}
|
|
25415
25883
|
}
|
|
25416
25884
|
return (topic2) => {
|
|
25417
|
-
const kind = topic2.kind ?? kinds2.get(
|
|
25885
|
+
const kind = topic2.kind ?? kinds2.get(normalizeTopicName(topic2.name));
|
|
25418
25886
|
return kind ? { ...topic2, kind } : topic2;
|
|
25419
25887
|
};
|
|
25420
25888
|
};
|
|
@@ -25437,7 +25905,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25437
25905
|
...cursor2 && { cursor: cursor2 }
|
|
25438
25906
|
});
|
|
25439
25907
|
warnFailed(page.failed);
|
|
25440
|
-
for (const
|
|
25908
|
+
for (const record3 of page.items) records.set(record3.memory.memory_id, record3);
|
|
25441
25909
|
for (const failure of page.failed) unreadable.add(failure.memory_id);
|
|
25442
25910
|
cursor2 = page.next_cursor;
|
|
25443
25911
|
} while (cursor2);
|
|
@@ -25633,8 +26101,8 @@ function createRemoteMemoryStore(options) {
|
|
|
25633
26101
|
const failed = /* @__PURE__ */ new Map();
|
|
25634
26102
|
const collect = (page) => {
|
|
25635
26103
|
warnFailed(page.failed);
|
|
25636
|
-
for (const
|
|
25637
|
-
records.push({ id:
|
|
26104
|
+
for (const record3 of page.items)
|
|
26105
|
+
records.push({ id: record3.memory.memory_id, state: subscriptionState(record3) });
|
|
25638
26106
|
for (const failure of page.failed) failed.set(failure.memory_id, failure.version);
|
|
25639
26107
|
};
|
|
25640
26108
|
let resume = cursor2;
|
|
@@ -25839,7 +26307,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25839
26307
|
result.failed += targets.length;
|
|
25840
26308
|
return finish();
|
|
25841
26309
|
}
|
|
25842
|
-
const writes = targets.flatMap((
|
|
26310
|
+
const writes = targets.flatMap((record3, i) => {
|
|
25843
26311
|
const vector2 = vectors[i];
|
|
25844
26312
|
if (!vector2) {
|
|
25845
26313
|
result.failed++;
|
|
@@ -25849,11 +26317,11 @@ function createRemoteMemoryStore(options) {
|
|
|
25849
26317
|
return [
|
|
25850
26318
|
{
|
|
25851
26319
|
memory: {
|
|
25852
|
-
...
|
|
26320
|
+
...record3.memory,
|
|
25853
26321
|
embedding: storedVector(vector2),
|
|
25854
26322
|
embedding_model: model
|
|
25855
26323
|
},
|
|
25856
|
-
expectedVersion:
|
|
26324
|
+
expectedVersion: record3
|
|
25857
26325
|
}
|
|
25858
26326
|
];
|
|
25859
26327
|
} catch {
|
|
@@ -25868,7 +26336,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25868
26336
|
signal?.throwIfAborted();
|
|
25869
26337
|
const commit = async (slice) => {
|
|
25870
26338
|
const saved = await persistence.putMany(slice, signal, leaseToken);
|
|
25871
|
-
for (const
|
|
26339
|
+
for (const record3 of saved) repaired.add(record3.memory.memory_id);
|
|
25872
26340
|
result.reembedded += saved.length;
|
|
25873
26341
|
notify("embedding", saved);
|
|
25874
26342
|
};
|
|
@@ -25952,7 +26420,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25952
26420
|
if (!topics.length) return;
|
|
25953
26421
|
const existing = new Set((await readTopics()).map((topic2) => topic2.name));
|
|
25954
26422
|
const missing2 = topics.flatMap((topic2) => {
|
|
25955
|
-
const name =
|
|
26423
|
+
const name = normalizeTopicName(topic2.name);
|
|
25956
26424
|
if (existing.has(name)) return [];
|
|
25957
26425
|
existing.add(name);
|
|
25958
26426
|
return [{ ...topic2, name }];
|
|
@@ -25983,7 +26451,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25983
26451
|
include_superseded: true
|
|
25984
26452
|
})) {
|
|
25985
26453
|
for (const topic2 of parseTopics(memory.topics) ?? []) {
|
|
25986
|
-
const name =
|
|
26454
|
+
const name = normalizeTopicName(topic2.name);
|
|
25987
26455
|
if (!name) continue;
|
|
25988
26456
|
const entry = topics.get(name) ?? {
|
|
25989
26457
|
name,
|
|
@@ -26021,7 +26489,7 @@ function createRemoteMemoryStore(options) {
|
|
|
26021
26489
|
},
|
|
26022
26490
|
get: async (id2) => asStored(await live2(id2)),
|
|
26023
26491
|
listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
|
|
26024
|
-
(
|
|
26492
|
+
(record3) => stored(record3.memory)
|
|
26025
26493
|
),
|
|
26026
26494
|
memoriesByTopics,
|
|
26027
26495
|
topicsByMemories: async (memoryIds) => {
|
|
@@ -26037,8 +26505,8 @@ function createRemoteMemoryStore(options) {
|
|
|
26037
26505
|
return out;
|
|
26038
26506
|
},
|
|
26039
26507
|
create: async (input) => {
|
|
26040
|
-
const
|
|
26041
|
-
return created([
|
|
26508
|
+
const record3 = await persistence.put(newRow(input), 0);
|
|
26509
|
+
return created([record3], [input])[0];
|
|
26042
26510
|
},
|
|
26043
26511
|
createMany: async (inputs) => {
|
|
26044
26512
|
const out = [];
|
|
@@ -26125,12 +26593,12 @@ function createRemoteMemoryStore(options) {
|
|
|
26125
26593
|
(memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
|
|
26126
26594
|
),
|
|
26127
26595
|
restore: (id2) => serialized(id2, async () => {
|
|
26128
|
-
const
|
|
26129
|
-
if (!
|
|
26130
|
-
if (
|
|
26596
|
+
const record3 = await live2(id2);
|
|
26597
|
+
if (!record3) return false;
|
|
26598
|
+
if (record3.memory.archived_at === void 0 || record3.memory.archived_at === null)
|
|
26131
26599
|
return true;
|
|
26132
|
-
const { archived_at: _archivedAt, ...memory } =
|
|
26133
|
-
notify("edit", [await persistence.put(memory,
|
|
26600
|
+
const { archived_at: _archivedAt, ...memory } = record3.memory;
|
|
26601
|
+
notify("edit", [await persistence.put(memory, record3)]);
|
|
26134
26602
|
return true;
|
|
26135
26603
|
}),
|
|
26136
26604
|
setTopics: async (memoryId, topics) => {
|
|
@@ -26163,8 +26631,8 @@ function createRemoteMemoryStore(options) {
|
|
|
26163
26631
|
const now = /* @__PURE__ */ new Date();
|
|
26164
26632
|
return mergeTopics([], added).map(
|
|
26165
26633
|
(topic2) => ({
|
|
26166
|
-
uniqueId:
|
|
26167
|
-
canonicalName:
|
|
26634
|
+
uniqueId: normalizeTopicName(topic2.name),
|
|
26635
|
+
canonicalName: normalizeTopicName(topic2.name),
|
|
26168
26636
|
kind: topic2.kind ?? null,
|
|
26169
26637
|
createdAt: now,
|
|
26170
26638
|
updatedAt: now
|
|
@@ -29038,11 +29506,11 @@ async function fetchAllModelPages(baseUrl, provider, headers, previous, signal)
|
|
|
29038
29506
|
return { pages, models, fetchedAt: Date.now() };
|
|
29039
29507
|
}
|
|
29040
29508
|
function loadModels(key3, baseUrl, provider, headers, force, signal) {
|
|
29041
|
-
const
|
|
29042
|
-
if (
|
|
29043
|
-
return Promise.resolve([...
|
|
29509
|
+
const cached2 = modelsCache.get(key3);
|
|
29510
|
+
if (cached2 && !force && Date.now() - cached2.fetchedAt < MODELS_CACHE_TTL_MS) {
|
|
29511
|
+
return Promise.resolve([...cached2.models]);
|
|
29044
29512
|
}
|
|
29045
|
-
const shared = (force ? void 0 : modelsInFlight.get(key3)) ?? startSharedRequest(key3, baseUrl, provider, headers,
|
|
29513
|
+
const shared = (force ? void 0 : modelsInFlight.get(key3)) ?? startSharedRequest(key3, baseUrl, provider, headers, cached2);
|
|
29046
29514
|
return waitForSharedRequest(key3, shared, signal).then((models) => [...models]);
|
|
29047
29515
|
}
|
|
29048
29516
|
function startSharedRequest(key3, baseUrl, provider, headers, previous) {
|
|
@@ -29286,9 +29754,9 @@ async function initializeMCPSession(accessToken) {
|
|
|
29286
29754
|
return sessionId;
|
|
29287
29755
|
}
|
|
29288
29756
|
async function ensureMCPSession(accessToken) {
|
|
29289
|
-
const
|
|
29290
|
-
if (
|
|
29291
|
-
return
|
|
29757
|
+
const cached2 = sessionCache.get(accessToken);
|
|
29758
|
+
if (cached2) {
|
|
29759
|
+
return cached2;
|
|
29292
29760
|
}
|
|
29293
29761
|
return initializeMCPSession(accessToken);
|
|
29294
29762
|
}
|
|
@@ -31262,13 +31730,13 @@ function useConversationRedactors(database, account, storage, secondaryStorage)
|
|
|
31262
31730
|
return useCallback4(
|
|
31263
31731
|
(conversationId, nerDetector) => {
|
|
31264
31732
|
if (!scope.active) return retiredRedactor;
|
|
31265
|
-
const
|
|
31266
|
-
if (
|
|
31733
|
+
const cached2 = scope.redactors.get(conversationId);
|
|
31734
|
+
if (cached2 && cached2.detector === nerDetector) {
|
|
31267
31735
|
scope.redactors.delete(conversationId);
|
|
31268
|
-
scope.redactors.set(conversationId,
|
|
31269
|
-
return
|
|
31736
|
+
scope.redactors.set(conversationId, cached2);
|
|
31737
|
+
return cached2.redactor;
|
|
31270
31738
|
}
|
|
31271
|
-
if (
|
|
31739
|
+
if (cached2) scope.evicted.push(cached2.redactor);
|
|
31272
31740
|
const redactor = new PiiRedactor({ nerDetector });
|
|
31273
31741
|
scope.redactors.set(conversationId, { redactor, detector: nerDetector });
|
|
31274
31742
|
if (scope.redactors.size > REDACTOR_LIMIT) {
|